@codemem/opencode-plugin 0.22.3 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.opencode/plugins/codemem.js +140 -95
- package/package.json +5 -2
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
|
|
16
16
|
const TRUTHY_VALUES = ["1", "true", "yes"];
|
|
17
17
|
const DISABLED_VALUES = ["0", "false", "off"];
|
|
18
|
-
const PINNED_BACKEND_VERSION = "0.
|
|
18
|
+
const PINNED_BACKEND_VERSION = "0.23.0";
|
|
19
19
|
const COMPAT_CHECK_DELAY_MS = 1500;
|
|
20
20
|
const COMPAT_CHECK_CACHE_TTL_MS = 5 * 60 * 1000;
|
|
21
21
|
|
|
@@ -161,6 +161,111 @@ const appendWorkingSetFileArgs = (args, workingSetFiles) => {
|
|
|
161
161
|
return args;
|
|
162
162
|
};
|
|
163
163
|
|
|
164
|
+
const buildInjectQuery = ({ firstPrompt, lastPromptText, projectName, filesModified }) => {
|
|
165
|
+
const parts = [];
|
|
166
|
+
|
|
167
|
+
if (firstPrompt && String(firstPrompt).trim()) {
|
|
168
|
+
parts.push(String(firstPrompt).trim());
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (
|
|
172
|
+
lastPromptText
|
|
173
|
+
&& String(lastPromptText).trim()
|
|
174
|
+
&& String(lastPromptText).trim() !== String(firstPrompt || "").trim()
|
|
175
|
+
&& String(lastPromptText).trim().length > 5
|
|
176
|
+
) {
|
|
177
|
+
parts.push(String(lastPromptText).trim());
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (projectName) {
|
|
181
|
+
parts.push(String(projectName));
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const recentFiles = Array.from(filesModified || [])
|
|
185
|
+
.slice(-5)
|
|
186
|
+
.map((filePath) => String(filePath || "").split("/").pop())
|
|
187
|
+
.filter(Boolean)
|
|
188
|
+
.join(" ");
|
|
189
|
+
if (recentFiles) {
|
|
190
|
+
parts.push(recentFiles);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (parts.length === 0) {
|
|
194
|
+
return "recent work";
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const query = parts.join(" ");
|
|
198
|
+
return query.length > 500 ? query.slice(0, 500) : query;
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
const buildPackArgs = ({ query, filesModified, injectLimit, injectTokenBudget }) => {
|
|
202
|
+
const workingSetFiles = Array.from(filesModified || [])
|
|
203
|
+
.slice(-8)
|
|
204
|
+
.map((value) => String(value || "").trim())
|
|
205
|
+
.filter(Boolean);
|
|
206
|
+
const args = ["pack", query];
|
|
207
|
+
if (injectLimit !== null && Number.isFinite(injectLimit) && injectLimit > 0) {
|
|
208
|
+
args.push("--limit", String(injectLimit));
|
|
209
|
+
}
|
|
210
|
+
if (
|
|
211
|
+
injectTokenBudget !== null
|
|
212
|
+
&& Number.isFinite(injectTokenBudget)
|
|
213
|
+
&& injectTokenBudget > 0
|
|
214
|
+
) {
|
|
215
|
+
args.push("--token-budget", String(injectTokenBudget));
|
|
216
|
+
}
|
|
217
|
+
return appendWorkingSetFileArgs(args, workingSetFiles);
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
const applyInjectedContextToOutput = async ({
|
|
221
|
+
injectEnabled,
|
|
222
|
+
input,
|
|
223
|
+
output,
|
|
224
|
+
injectedSessions,
|
|
225
|
+
injectionToastShown,
|
|
226
|
+
showToast,
|
|
227
|
+
resolveInjectQuery,
|
|
228
|
+
buildInjectedContext,
|
|
229
|
+
}) => {
|
|
230
|
+
if (!injectEnabled) {
|
|
231
|
+
return false;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const query = resolveInjectQuery();
|
|
235
|
+
const cached = injectedSessions.get(input.sessionID);
|
|
236
|
+
let contextText = cached?.text || "";
|
|
237
|
+
|
|
238
|
+
if (!contextText || cached?.query !== query) {
|
|
239
|
+
const injected = await buildInjectedContext(query);
|
|
240
|
+
if (injected?.text) {
|
|
241
|
+
injectedSessions.set(input.sessionID, {
|
|
242
|
+
query,
|
|
243
|
+
text: injected.text,
|
|
244
|
+
metrics: injected.metrics || null,
|
|
245
|
+
});
|
|
246
|
+
contextText = injected.text;
|
|
247
|
+
|
|
248
|
+
if (!injectionToastShown.has(input.sessionID) && showToast) {
|
|
249
|
+
injectionToastShown.add(input.sessionID);
|
|
250
|
+
try {
|
|
251
|
+
await showToast(buildInjectionToastMessage(injected.metrics));
|
|
252
|
+
} catch {
|
|
253
|
+
// best-effort only
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
if (!contextText) {
|
|
260
|
+
return false;
|
|
261
|
+
}
|
|
262
|
+
if (!Array.isArray(output.system)) {
|
|
263
|
+
output.system = [];
|
|
264
|
+
}
|
|
265
|
+
output.system.push(contextText);
|
|
266
|
+
return true;
|
|
267
|
+
};
|
|
268
|
+
|
|
164
269
|
const mapOpencodeEventTypeToAdapterType = (eventType) => {
|
|
165
270
|
if (eventType === "user_prompt") {
|
|
166
271
|
return "prompt";
|
|
@@ -1335,63 +1440,13 @@ export const OpencodeMemPlugin = async ({
|
|
|
1335
1440
|
await showToast(`${message}. Suggested action: ${guidance.action}`, "warning");
|
|
1336
1441
|
};
|
|
1337
1442
|
|
|
1338
|
-
const resolveInjectQuery = () =>
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
}
|
|
1345
|
-
|
|
1346
|
-
// Latest prompt adds current focus (skip if same as first, or trivial)
|
|
1347
|
-
if (
|
|
1348
|
-
lastPromptText &&
|
|
1349
|
-
lastPromptText.trim() &&
|
|
1350
|
-
lastPromptText.trim() !== (sessionContext.firstPrompt || "").trim() &&
|
|
1351
|
-
lastPromptText.trim().length > 5
|
|
1352
|
-
) {
|
|
1353
|
-
parts.push(lastPromptText.trim());
|
|
1354
|
-
}
|
|
1355
|
-
|
|
1356
|
-
// Project name for scoping
|
|
1357
|
-
const projectName = resolveProjectName(project, cwd);
|
|
1358
|
-
if (projectName) {
|
|
1359
|
-
parts.push(projectName);
|
|
1360
|
-
}
|
|
1361
|
-
|
|
1362
|
-
// Recently modified files signal what area of the codebase we're in
|
|
1363
|
-
if (sessionContext.filesModified.size > 0) {
|
|
1364
|
-
const recentFiles = Array.from(sessionContext.filesModified)
|
|
1365
|
-
.slice(-5)
|
|
1366
|
-
.map((f) => f.split("/").pop())
|
|
1367
|
-
.join(" ");
|
|
1368
|
-
parts.push(recentFiles);
|
|
1369
|
-
}
|
|
1370
|
-
|
|
1371
|
-
if (parts.length === 0) {
|
|
1372
|
-
return "recent work";
|
|
1373
|
-
}
|
|
1374
|
-
|
|
1375
|
-
// Cap total length to avoid overly long CLI args
|
|
1376
|
-
const query = parts.join(" ");
|
|
1377
|
-
return query.length > 500 ? query.slice(0, 500) : query;
|
|
1378
|
-
};
|
|
1379
|
-
|
|
1380
|
-
const buildPackArgs = (query) => {
|
|
1381
|
-
const workingSetFiles = Array.from(sessionContext.filesModified)
|
|
1382
|
-
.slice(-8)
|
|
1383
|
-
.map((value) => String(value || "").trim())
|
|
1384
|
-
.filter(Boolean);
|
|
1385
|
-
const args = ["pack", query];
|
|
1386
|
-
if (injectLimit !== null && Number.isFinite(injectLimit) && injectLimit > 0) {
|
|
1387
|
-
args.push("--limit", String(injectLimit));
|
|
1388
|
-
}
|
|
1389
|
-
if (injectTokenBudget !== null && Number.isFinite(injectTokenBudget) && injectTokenBudget > 0) {
|
|
1390
|
-
args.push("--token-budget", String(injectTokenBudget));
|
|
1391
|
-
}
|
|
1392
|
-
appendWorkingSetFileArgs(args, workingSetFiles);
|
|
1393
|
-
return args;
|
|
1394
|
-
};
|
|
1443
|
+
const resolveInjectQuery = () =>
|
|
1444
|
+
buildInjectQuery({
|
|
1445
|
+
firstPrompt: sessionContext.firstPrompt,
|
|
1446
|
+
lastPromptText,
|
|
1447
|
+
projectName: resolveProjectName(project, cwd),
|
|
1448
|
+
filesModified: sessionContext.filesModified,
|
|
1449
|
+
});
|
|
1395
1450
|
|
|
1396
1451
|
const parsePackText = (stdout) => {
|
|
1397
1452
|
if (!stdout || !stdout.trim()) {
|
|
@@ -1424,7 +1479,12 @@ export const OpencodeMemPlugin = async ({
|
|
|
1424
1479
|
};
|
|
1425
1480
|
|
|
1426
1481
|
const buildInjectedContext = async (query) => {
|
|
1427
|
-
const packArgs = buildPackArgs(
|
|
1482
|
+
const packArgs = buildPackArgs({
|
|
1483
|
+
query,
|
|
1484
|
+
filesModified: sessionContext.filesModified,
|
|
1485
|
+
injectLimit,
|
|
1486
|
+
injectTokenBudget,
|
|
1487
|
+
});
|
|
1428
1488
|
const result = await runCli(packArgs);
|
|
1429
1489
|
if (!result || result.exitCode !== 0) {
|
|
1430
1490
|
const exitCode = result?.exitCode ?? "unknown";
|
|
@@ -1681,9 +1741,6 @@ export const OpencodeMemPlugin = async ({
|
|
|
1681
1741
|
|
|
1682
1742
|
return {
|
|
1683
1743
|
"experimental.chat.system.transform": async (input, output) => {
|
|
1684
|
-
if (!injectEnabled) {
|
|
1685
|
-
return;
|
|
1686
|
-
}
|
|
1687
1744
|
const query = resolveInjectQuery();
|
|
1688
1745
|
if (debug) {
|
|
1689
1746
|
await logLine(
|
|
@@ -1692,40 +1749,25 @@ export const OpencodeMemPlugin = async ({
|
|
|
1692
1749
|
} tui_toast=${Boolean(client.tui?.showToast)}`
|
|
1693
1750
|
);
|
|
1694
1751
|
}
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
try {
|
|
1710
|
-
await client.tui.showToast({
|
|
1711
|
-
body: {
|
|
1712
|
-
message: buildInjectionToastMessage(injected.metrics),
|
|
1713
|
-
variant: "info",
|
|
1714
|
-
},
|
|
1715
|
-
});
|
|
1716
|
-
} catch (toastErr) {
|
|
1717
|
-
// best-effort only
|
|
1718
|
-
}
|
|
1752
|
+
await applyInjectedContextToOutput({
|
|
1753
|
+
injectEnabled,
|
|
1754
|
+
input,
|
|
1755
|
+
output,
|
|
1756
|
+
injectedSessions,
|
|
1757
|
+
injectionToastShown,
|
|
1758
|
+
showToast: client.tui?.showToast
|
|
1759
|
+
? async (message) => {
|
|
1760
|
+
await client.tui.showToast({
|
|
1761
|
+
body: {
|
|
1762
|
+
message,
|
|
1763
|
+
variant: "info",
|
|
1764
|
+
},
|
|
1765
|
+
});
|
|
1719
1766
|
}
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
}
|
|
1725
|
-
if (!Array.isArray(output.system)) {
|
|
1726
|
-
output.system = [];
|
|
1727
|
-
}
|
|
1728
|
-
output.system.push(contextText);
|
|
1767
|
+
: null,
|
|
1768
|
+
resolveInjectQuery,
|
|
1769
|
+
buildInjectedContext,
|
|
1770
|
+
});
|
|
1729
1771
|
},
|
|
1730
1772
|
event: async ({ event }) => {
|
|
1731
1773
|
const eventType = event?.type || "unknown";
|
|
@@ -2009,6 +2051,9 @@ export const __testUtils = {
|
|
|
2009
2051
|
inferProjectFromCwd,
|
|
2010
2052
|
normalizeProjectLabel,
|
|
2011
2053
|
resolveProjectName,
|
|
2054
|
+
buildInjectQuery,
|
|
2055
|
+
buildPackArgs,
|
|
2056
|
+
applyInjectedContextToOutput,
|
|
2012
2057
|
buildRunnerArgs,
|
|
2013
2058
|
appendWorkingSetFileArgs,
|
|
2014
2059
|
extractApplyPatchPaths,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codemem/opencode-plugin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.23.0",
|
|
4
4
|
"description": "CodeMem plugin for OpenCode",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.js",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
".opencode/lib/"
|
|
19
19
|
],
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@opencode-ai/plugin": "1.3.
|
|
21
|
+
"@opencode-ai/plugin": "1.3.17"
|
|
22
22
|
},
|
|
23
23
|
"repository": {
|
|
24
24
|
"type": "git",
|
|
@@ -29,6 +29,9 @@
|
|
|
29
29
|
"bugs": {
|
|
30
30
|
"url": "https://github.com/kunickiaj/codemem/issues"
|
|
31
31
|
},
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=24"
|
|
34
|
+
},
|
|
32
35
|
"license": "MIT",
|
|
33
36
|
"publishConfig": {
|
|
34
37
|
"access": "public"
|