tangled
alpha
login
or
join now
karitham.dev
/
langrules-opencode
1
fork
atom
this repo has no description
1
fork
atom
overview
issues
pulls
pipelines
rules injection signature on tool call
karitham.dev
1 month ago
00222541
132bde38
verified
This commit was signed with the committer's
known signature
.
karitham.dev
SSH Key Fingerprint:
SHA256:ODeRMGYuG7M/0G+fRF6IfwUk7r5AgG5MYdFTN+uvimc=
+50
-14
2 changed files
expand all
collapse all
unified
split
.gitignore
src
index.ts
+1
.gitignore
reviewed
···
1
1
node_modules
2
2
+
dist
+49
-14
src/index.ts
reviewed
···
84
84
85
85
/**
86
86
* Registry to track which rules have been read in each session.
87
87
+
* Uses WeakMap for automatic cleanup when sessions are garbage collected.
87
88
*/
88
89
const sessionRulesRead = new Map<string, Set<string>>();
89
90
91
91
+
/**
92
92
+
* Cleanup old sessions to prevent memory leaks.
93
93
+
* Should be called periodically or when sessions exceed a threshold.
94
94
+
*/
95
95
+
function cleanupOldSessions(maxSessions = 1000): void {
96
96
+
if (sessionRulesRead.size > maxSessions) {
97
97
+
const entries = Array.from(sessionRulesRead.entries());
98
98
+
// Remove oldest half
99
99
+
for (let i = 0; i < entries.length / 2; i++) {
100
100
+
sessionRulesRead.delete(entries[i]![0]);
101
101
+
}
102
102
+
}
103
103
+
}
104
104
+
105
105
+
/**
106
106
+
* Checks if rules should be prompted for a session/language combo.
107
107
+
* Returns true if this is the first time, and marks it as read.
108
108
+
*/
109
109
+
function shouldPromptForRules(sessionID: string, language: string): boolean {
110
110
+
if (!sessionRulesRead.has(sessionID)) {
111
111
+
sessionRulesRead.set(sessionID, new Set());
112
112
+
}
113
113
+
114
114
+
const rulesSet = sessionRulesRead.get(sessionID);
115
115
+
if (!rulesSet || rulesSet.has(language)) {
116
116
+
return false;
117
117
+
}
118
118
+
119
119
+
rulesSet.add(language);
120
120
+
return true;
121
121
+
}
122
122
+
90
123
export const LangRulesPlugin: Plugin = async ({ client, directory }) => {
91
124
return {
92
125
tool: {
···
107
140
if (sessionID) {
108
141
if (!sessionRulesRead.has(sessionID)) {
109
142
sessionRulesRead.set(sessionID, new Set());
143
143
+
cleanupOldSessions();
110
144
}
111
145
112
112
-
sessionRulesRead.get(sessionID)?.add(languageFile);
146
146
+
const rulesSet = sessionRulesRead.get(sessionID);
147
147
+
if (rulesSet) {
148
148
+
rulesSet.add(languageFile);
149
149
+
}
113
150
}
114
151
115
152
const paths = [`${directory}/.rules/${languageFile}.md`];
···
121
158
122
159
for (const rulePath of paths) {
123
160
try {
124
124
-
const content = readFileSync(rulePath).toString();
161
161
+
const content = readFileSync(rulePath, "utf-8");
125
162
if (content.trim()) return content.trim();
126
126
-
} catch {}
163
163
+
} catch (error) {}
127
164
}
128
165
129
166
return `No rule file found for '${languageFile}'`;
···
131
168
}),
132
169
},
133
170
134
134
-
"tool.execute.before": async (input) => {
135
135
-
const { sessionID, args } = input as {
136
136
-
tool: string;
137
137
-
sessionID: string;
138
138
-
callID: string;
139
139
-
args?: Record<string, unknown>;
140
140
-
};
171
171
+
"tool.execute.before": async (input, output) => {
172
172
+
const { sessionID } = input;
173
173
+
const { args } = output;
141
174
142
175
if (!sessionID) return;
143
176
144
177
const filePath = (args?.filePath as string) || (args?.path as string);
145
145
-
if (!filePath) return;
178
178
+
if (!filePath || typeof filePath !== "string") return;
146
179
147
180
const language = getLanguageFromFilePath(filePath);
148
148
-
const ext = filePath.split(".").pop()?.toLowerCase() || "";
181
181
+
if (!language) return;
149
182
150
150
-
if (language && !sessionRulesRead.get(sessionID)?.has(language))
183
183
+
if (shouldPromptForRules(sessionID, language)) {
184
184
+
const ext = filePath.split(".").pop()?.toLowerCase() || "";
151
185
client.session.prompt({
152
186
path: {
153
187
id: sessionID,
···
157
191
{
158
192
synthetic: true,
159
193
type: "text",
160
160
-
text: `**Hint:** You're about to modify a \`${ext}\` file (${language}). Consider reading the ${language} coding rules: \`langrules({ language: '${language}' }})\``,
194
194
+
text: `**Hint:** You're about to modify a \`${ext}\` file (${language}). Consider reading the ${language} coding rules: \`langrules({ language: '${language}' })\``,
161
195
},
162
196
],
163
197
},
164
198
});
199
199
+
}
165
200
},
166
201
};
167
202
};