opencode-codex-memory 0.4.6 → 0.4.7

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/README.md CHANGED
@@ -52,7 +52,7 @@ If you want the mental model before the details, jump to
52
52
 
53
53
  ```json
54
54
  {
55
- "plugin": ["opencode-codex-memory@0.4.6"]
55
+ "plugin": ["opencode-codex-memory@0.4.7"]
56
56
  }
57
57
  ```
58
58
 
@@ -239,7 +239,7 @@ To set options, turn the plugin entry into a `[name, options]` pair:
239
239
  ```json
240
240
  {
241
241
  "plugin": [
242
- ["opencode-codex-memory@0.4.6", { "disable_on_external_context": true, "min_rollout_idle_hours": 2 }]
242
+ ["opencode-codex-memory@0.4.7", { "disable_on_external_context": true, "min_rollout_idle_hours": 2 }]
243
243
  ]
244
244
  }
245
245
  ```
@@ -298,7 +298,7 @@ directions:
298
298
  ```json
299
299
  {
300
300
  "plugin": [
301
- ["opencode-codex-memory@0.4.6", { "codex_interop": { "import": true, "export": true } }]
301
+ ["opencode-codex-memory@0.4.7", { "codex_interop": { "import": true, "export": true } }]
302
302
  ]
303
303
  }
304
304
  ```
@@ -5,17 +5,11 @@ export interface SessionRow {
5
5
  directory: string | null;
6
6
  }
7
7
  /**
8
- * Global session discovery through the official API: opencode's session.list
9
- * is project-scoped, so enumerate projects (project.list) and list each one
10
- * with scope=project (routes the request to that project's instance AND
11
- * widens the filter from the session directory to the whole project).
12
- * Instance contexts created this way are cached by the host for the process
13
- * lifetime, and the whole pass is rate-limited (30s min interval).
14
- *
15
- * Fail-safe at two levels: a failed project.list skips the pass ([]), a
16
- * failed per-project session.list skips that project — neither claims or
17
- * finalizes any job. Transcript loading must NOT be fail-safe — see
18
- * loadTranscript.
8
+ * Global session discovery through the official API:
9
+ * `GET /experimental/session?roots=true` (Session.listGlobal) one call across
10
+ * all projects, sorted by most-recently-updated. Available since opencode
11
+ * 1.17.x. Fail-safe: any error skips the pass ([]); never finalizes a job.
12
+ * Transcript loading must NOT be fail-safe see loadTranscript.
19
13
  */
20
14
  export declare function listRecentSessions(limit?: number): Promise<SessionRow[]>;
21
15
  export interface TranscriptMessage {
@@ -16,64 +16,57 @@ async function withTimeout(promise, ms, label) {
16
16
  }
17
17
  }
18
18
  /**
19
- * Global session discovery through the official API: opencode's session.list
20
- * is project-scoped, so enumerate projects (project.list) and list each one
21
- * with scope=project (routes the request to that project's instance AND
22
- * widens the filter from the session directory to the whole project).
23
- * Instance contexts created this way are cached by the host for the process
24
- * lifetime, and the whole pass is rate-limited (30s min interval).
25
- *
26
- * Fail-safe at two levels: a failed project.list skips the pass ([]), a
27
- * failed per-project session.list skips that project — neither claims or
28
- * finalizes any job. Transcript loading must NOT be fail-safe — see
29
- * loadTranscript.
19
+ * Hey-api transport on PluginInput.client. The V1 SDK has no
20
+ * `experimental.*` namespace, but the host-built client already carries
21
+ * baseUrl + auth headers; `_client.get` is the supported escape hatch for
22
+ * routes the generated surface lags on (same pattern as the scope/roots casts
23
+ * we used to need on session.list).
24
+ */
25
+ function pluginHttp() {
26
+ const http = getPluginInput()?.client?._client;
27
+ if (!http || typeof http.get !== "function")
28
+ return null;
29
+ return http;
30
+ }
31
+ /**
32
+ * Global session discovery through the official API:
33
+ * `GET /experimental/session?roots=true` (Session.listGlobal) — one call across
34
+ * all projects, sorted by most-recently-updated. Available since opencode
35
+ * 1.17.x. Fail-safe: any error skips the pass ([]); never finalizes a job.
36
+ * Transcript loading must NOT be fail-safe — see loadTranscript.
30
37
  */
31
38
  export async function listRecentSessions(limit = SCAN_LIMIT) {
32
- const client = getPluginInput()?.client;
33
- if (!client?.project?.list || !client?.session?.list)
39
+ const http = pluginHttp();
40
+ if (!http)
34
41
  return [];
35
- let projects;
36
42
  try {
37
- const res = await withTimeout(client.project.list(), API_TIMEOUT_MS, "project.list");
38
- if (!res || res.error || !Array.isArray(res.data))
39
- throw new Error(`project.list failed: ${JSON.stringify(res?.error ?? {})}`);
40
- projects = res.data;
43
+ const res = await withTimeout(http.get({
44
+ url: "/experimental/session",
45
+ query: { roots: true, limit },
46
+ }), API_TIMEOUT_MS, "experimental.session.list");
47
+ if (!res || res.error || !Array.isArray(res.data)) {
48
+ throw new Error(`experimental.session.list failed: ${JSON.stringify(res?.error ?? {})}`);
49
+ }
50
+ const all = [];
51
+ for (const s of res.data) {
52
+ // Top-level sessions only: task-tool children are summarized into their
53
+ // parent, and the plugin's own sub-sessions must never be memorized
54
+ // (roots=true drops children server-side; keep both belts).
55
+ if (!s?.id || s.parentID)
56
+ continue;
57
+ if (s.title && s.title.startsWith("codex-memory-"))
58
+ continue;
59
+ all.push({ id: s.id, updated_at: s.time?.updated ?? 0, directory: s.directory ?? null });
60
+ }
61
+ // Server already orders by time_updated DESC; re-sort so a lagging host
62
+ // cannot invert eligibility order.
63
+ all.sort((a, b) => b.updated_at - a.updated_at);
64
+ return all.slice(0, limit);
41
65
  }
42
66
  catch (err) {
43
- console.warn("[opencode-codex-memory] project discovery failed; skipping pass:", err);
67
+ console.warn("[opencode-codex-memory] session discovery failed; skipping pass:", err);
44
68
  return [];
45
69
  }
46
- const all = [];
47
- for (const project of projects) {
48
- if (!project?.worktree)
49
- continue;
50
- try {
51
- const res = await withTimeout(client.session.list({
52
- // scope/roots/limit are in the server's ListQuery (accepted since
53
- // opencode 1.14.30, well under our 1.18 floor); the pinned SDK types
54
- // still omit them (SessionListData.query is just { directory } as of
55
- // 1.18.1), hence the cast at the call site.
56
- query: { directory: project.worktree, scope: "project", roots: true, limit },
57
- }), API_TIMEOUT_MS, "session.list");
58
- if (!res || res.error || !Array.isArray(res.data))
59
- throw new Error(JSON.stringify(res?.error ?? {}));
60
- for (const s of res.data) {
61
- // Top-level sessions only: task-tool children are summarized into
62
- // their parent, and the plugin's own sub-sessions must never be
63
- // memorized (roots=true drops children server-side; keep both belts).
64
- if (!s?.id || s.parentID)
65
- continue;
66
- if (s.title && s.title.startsWith("codex-memory-"))
67
- continue;
68
- all.push({ id: s.id, updated_at: s.time?.updated ?? 0, directory: s.directory ?? null });
69
- }
70
- }
71
- catch (err) {
72
- console.warn(`[opencode-codex-memory] session.list failed for ${project.worktree}; skipping project:`, err);
73
- }
74
- }
75
- all.sort((a, b) => b.updated_at - a.updated_at);
76
- return all.slice(0, limit);
77
70
  }
78
71
  /** Official transcript surface: GET /session/{id}/message via the plugin's authenticated client. */
79
72
  async function fetchMessagesViaApi(sessionId) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-codex-memory",
3
- "version": "0.4.6",
3
+ "version": "0.4.7",
4
4
  "description": "Persistent memory plugin for opencode — ports codex's two-phase memory system (extraction → consolidation → injection → citation feedback)",
5
5
  "type": "module",
6
6
  "main": "./dist/src/index.js",
@@ -31,6 +31,9 @@
31
31
  "dev": "bun --watch src/index.ts",
32
32
  "build": "tsc && rm -rf dist/src/templates && cp -R src/templates dist/src/templates && cp opencode.json dist/opencode.json",
33
33
  "smoke": "bun scripts/smoke.ts",
34
+ "contract": "bun scripts/check-opencode-contract.ts",
35
+ "live:read": "bun scripts/live-readpath.ts",
36
+ "live:e2e": "bun scripts/live-e2e.ts",
34
37
  "prepack": "npm run build && npm run smoke",
35
38
  "test": "bun test",
36
39
  "typecheck": "tsc --noEmit"