@codemem/opencode-plugin 0.29.1 → 0.29.2

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.
@@ -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.29.1";
18
+ const PINNED_BACKEND_VERSION = "0.29.2";
19
19
  const COMPAT_CHECK_DELAY_MS = 1500;
20
20
  const COMPAT_CHECK_CACHE_TTL_MS = 5 * 60 * 1000;
21
21
 
@@ -245,7 +245,6 @@ const applyInjectedContextToOutput = async ({
245
245
  injectEnabled,
246
246
  input,
247
247
  output,
248
- injectedSessions,
249
248
  injectionToastShown,
250
249
  showToast,
251
250
  resolveInjectQuery,
@@ -255,39 +254,33 @@ const applyInjectedContextToOutput = async ({
255
254
  return false;
256
255
  }
257
256
 
257
+ // The previous incarnation cached by sessionID-only, so a follow-up
258
+ // turn whose query happened to match the cache key (e.g. because
259
+ // lastPromptText hadn't yet been captured by the time
260
+ // experimental.chat.system.transform fired) would silently re-serve
261
+ // the first turn's pack. Recompute on every call instead — the chat
262
+ // path tolerates the runCli round trip, and correctness beats the
263
+ // O(1) hit when the cache key isn't tied to the prompt that produced
264
+ // the pack.
258
265
  const query = resolveInjectQuery();
259
- const cached = injectedSessions.get(input.sessionID);
260
- const queryMatchesCache = cached?.query === query;
261
- let contextText = queryMatchesCache ? cached?.text || "" : "";
262
-
263
- if (!contextText || cached?.query !== query) {
264
- const injected = await buildInjectedContext(query);
265
- if (injected?.text) {
266
- injectedSessions.set(input.sessionID, {
267
- query,
268
- text: injected.text,
269
- metrics: injected.metrics || null,
270
- });
271
- contextText = injected.text;
266
+ const injected = await buildInjectedContext(query);
267
+ if (!injected?.text) {
268
+ return false;
269
+ }
272
270
 
273
- if (!injectionToastShown.has(input.sessionID) && showToast) {
274
- injectionToastShown.add(input.sessionID);
275
- try {
276
- await showToast(buildInjectionToastMessage(injected.metrics));
277
- } catch {
278
- // best-effort only
279
- }
280
- }
271
+ if (!injectionToastShown.has(input.sessionID) && showToast) {
272
+ injectionToastShown.add(input.sessionID);
273
+ try {
274
+ await showToast(buildInjectionToastMessage(injected.metrics));
275
+ } catch {
276
+ // best-effort only
281
277
  }
282
278
  }
283
279
 
284
- if (!contextText) {
285
- return false;
286
- }
287
280
  if (!Array.isArray(output.system)) {
288
281
  output.system = [];
289
282
  }
290
- output.system.push(contextText);
283
+ output.system.push(injected.text);
291
284
  return true;
292
285
  };
293
286
 
@@ -749,7 +742,6 @@ export const OpencodeMemPlugin = async ({
749
742
  const injectLimit = injectLimitEnv ? parseNumber(injectLimitEnv, null) : null;
750
743
  const injectTokenBudgetEnv = process.env.CODEMEM_INJECT_TOKEN_BUDGET;
751
744
  const injectTokenBudget = injectTokenBudgetEnv ? parseNumber(injectTokenBudgetEnv, null) : null;
752
- const injectedSessions = new Map();
753
745
  const injectionToastShown = new Set();
754
746
  let sessionStartedAt = null;
755
747
  let activeSessionID = null;
@@ -1537,17 +1529,17 @@ export const OpencodeMemPlugin = async ({
1537
1529
  return "";
1538
1530
  }
1539
1531
  const metrics = parsePackMetrics(result.stdout);
1540
- if (debug) {
1541
- const itemCount = Number.isFinite(Number(metrics?.items))
1542
- ? Number(metrics.items)
1543
- : 0;
1544
- const packTokens = Number.isFinite(Number(metrics?.pack_tokens))
1545
- ? Number(metrics.pack_tokens)
1546
- : 0;
1547
- await logLine(
1548
- `inject.pack.ok query_len=${query ? query.length : 0} items=${itemCount} pack_tokens=${packTokens}`
1549
- );
1550
- }
1532
+ // The pack JSON exposes the item count as `total_items`; `metrics.items`
1533
+ // does not exist on that payload, so reading it would always log 0.
1534
+ const itemCount = Number.isFinite(Number(metrics?.total_items))
1535
+ ? Number(metrics.total_items)
1536
+ : 0;
1537
+ const packTokens = Number.isFinite(Number(metrics?.pack_tokens))
1538
+ ? Number(metrics.pack_tokens)
1539
+ : 0;
1540
+ await logLine(
1541
+ `inject.pack.ok source=opencode items=${itemCount} pack_tokens=${packTokens} query_len=${query ? query.length : 0}`
1542
+ );
1551
1543
  if (metrics) {
1552
1544
  return {
1553
1545
  text: `[codemem context]\n${packText}`,
@@ -1796,25 +1788,35 @@ export const OpencodeMemPlugin = async ({
1796
1788
  } inject_enabled=${injectEnabled} tui_toast=${Boolean(client.tui?.showToast)} query=${JSON.stringify(safeQuery)} first_prompt_len=${firstPromptLen} last_prompt_len=${lastPromptLen} project=${JSON.stringify(projectName)} files_modified=${filesModifiedCount}`
1797
1789
  );
1798
1790
  }
1799
- const applied = await applyInjectedContextToOutput({
1800
- injectEnabled,
1801
- input,
1802
- output,
1803
- injectedSessions,
1804
- injectionToastShown,
1805
- showToast: client.tui?.showToast
1806
- ? async (message) => {
1807
- await client.tui.showToast({
1808
- body: {
1809
- message,
1810
- variant: "info",
1811
- },
1812
- });
1813
- }
1814
- : null,
1815
- resolveInjectQuery,
1816
- buildInjectedContext,
1817
- });
1791
+ // Without the old per-session cache, every transform call shells out
1792
+ // through `runCli`. Swallow rejections here so a single failed pack
1793
+ // build (CLI crash, sqlite locked, network blip on HTTP fallback)
1794
+ // can't take down the chat path.
1795
+ let applied = false;
1796
+ try {
1797
+ applied = await applyInjectedContextToOutput({
1798
+ injectEnabled,
1799
+ input,
1800
+ output,
1801
+ injectionToastShown,
1802
+ showToast: client.tui?.showToast
1803
+ ? async (message) => {
1804
+ await client.tui.showToast({
1805
+ body: {
1806
+ message,
1807
+ variant: "info",
1808
+ },
1809
+ });
1810
+ }
1811
+ : null,
1812
+ resolveInjectQuery,
1813
+ buildInjectedContext,
1814
+ });
1815
+ } catch (err) {
1816
+ await logLine(
1817
+ `inject.transform.error sessionID=${input.sessionID} message=${JSON.stringify(err instanceof Error ? err.message : String(err))}`
1818
+ );
1819
+ }
1818
1820
  if (debug) {
1819
1821
  await logLine(
1820
1822
  `inject.transform.result sessionID=${input.sessionID} applied=${Boolean(applied)} system_entries=${Array.isArray(output.system) ? output.system.length : 0}`
@@ -2000,6 +2002,9 @@ export const OpencodeMemPlugin = async ({
2000
2002
  }
2001
2003
  if (eventType === "session.deleted") {
2002
2004
  activeSessionID = null;
2005
+ if (sessionID) {
2006
+ injectionToastShown.delete(sessionID);
2007
+ }
2003
2008
  await stopViewer();
2004
2009
  }
2005
2010
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codemem/opencode-plugin",
3
- "version": "0.29.1",
3
+ "version": "0.29.2",
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.14.28"
21
+ "@opencode-ai/plugin": "1.14.31"
22
22
  },
23
23
  "repository": {
24
24
  "type": "git",