opencode-self-improvement 0.6.3 → 0.6.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-self-improvement",
3
- "version": "0.6.3",
3
+ "version": "0.6.5",
4
4
  "description": "Durable memory for opencode: remember facts, decisions, and commands across sessions, plus a one-command per-repo setup (/repo-init).",
5
5
  "main": "index.ts",
6
6
  "exports": {
@@ -29,6 +29,7 @@
29
29
  "files": [
30
30
  "index.ts",
31
31
  "tui.ts",
32
+ "tsconfig.json",
32
33
  "src",
33
34
  "command",
34
35
  "vendor",
package/src/index.ts CHANGED
@@ -204,6 +204,36 @@ const impl = {
204
204
  hasEngagement: hasEngagement(getCurrent().sid),
205
205
  });
206
206
 
207
+ // Identity-event race backstop: a resumed session's FIRST turn can write
208
+ // before the subscription has delivered its execution.started, and the
209
+ // module-scope fallback is the last setup instance — possibly another
210
+ // workspace. The session context API is synchronous and its messages
211
+ // carry location.directory, so bind once from them for unmapped sids.
212
+ // One-shot: never overwrites an event-bound entry.
213
+ const bindingSids = new Set<string>();
214
+ async function bindSessionFromMessages(sid: string | undefined): Promise<void> {
215
+ if (!sid || sid === "?" || sessionDir(sid) || bindingSids.has(sid)) return;
216
+ bindingSids.add(sid);
217
+ try {
218
+ const msgs = await ctx.session?.context?.({ sessionID: sid });
219
+ if (Array.isArray(msgs)) {
220
+ for (const m of msgs) {
221
+ if (!m || typeof m !== "object") continue;
222
+ const r = m as Record<string, any>;
223
+ const dir = r.location?.directory ?? r.info?.location?.directory;
224
+ if (typeof dir === "string" && dir) {
225
+ rememberSessionDir(sid, dir);
226
+ break;
227
+ }
228
+ }
229
+ }
230
+ } catch {
231
+ // no context access or host error: the event stream still binds later
232
+ } finally {
233
+ bindingSids.delete(sid);
234
+ }
235
+ }
236
+
207
237
  // ---- tools --------------------------------------------------------------
208
238
  await ctx.tool?.transform((editor) => {
209
239
  const direct = { codemode: false } as const;
@@ -223,6 +253,7 @@ const impl = {
223
253
  status: args.status,
224
254
  repo: args.global ? "global" : undefined,
225
255
  };
256
+ await bindSessionFromMessages(getCurrent().sid);
226
257
  const outcome = await runWriteGate(candidate, gateContext());
227
258
  if (outcome.action === "promoted") return { content: `Remembered: ${args.type} in ${args.scope}` };
228
259
  if (outcome.action === "collapsed") return { content: `Duplicate ignored: ${args.type}/${args.scope}` };
@@ -240,6 +271,7 @@ const impl = {
240
271
  "Initialize repository memory and knowledge graph. Ensures the codebase-memory graph for this repo is indexed (one-shot `cli` spawn; no session MCP needed) and re-derives build/lint/test/typecheck command memories through the write gate, then stores an init stamp keyed on git HEAD. Idempotent: a no-op when the stamp matches HEAD, unless force=true (refresh after a refactor).",
241
272
  options: direct,
242
273
  async execute(args): Promise<{ content: string }> {
274
+ await bindSessionFromMessages(getCurrent().sid);
243
275
  const summary = await runInit({ liveRoot: gateContext().liveRoot, force: args.force, mode: args.mode });
244
276
  return { content: formatInit(summary) };
245
277
  },
@@ -286,6 +318,7 @@ const impl = {
286
318
  "Update an existing memory (gated like remember; the prior entry is superseded, not erased). `query` selects which row to update: its exact id (ts), a clock fragment (e.g. HH:MM:SS.mmm), or a unique substring of its content. Omitting `query` targets the most recent active row of scope+type. An unmatched or ambiguous `query` fails closed and writes nothing.",
287
319
  options: direct,
288
320
  async execute(args): Promise<{ content: string }> {
321
+ await bindSessionFromMessages(getCurrent().sid);
289
322
  const prior = (await loadAll()).filter(
290
323
  (m) => m.scope === args.scope && m.type === args.type && isActive(m) && isVisibleHere(m),
291
324
  );
@@ -684,6 +717,7 @@ const impl = {
684
717
  if (typeof sid === "string") {
685
718
  markTurn(sid);
686
719
  await checkNewSession(sid);
720
+ await bindSessionFromMessages(sid);
687
721
  const version = await storeVersion();
688
722
  const cached = epoch.get(sid);
689
723
  if (!cached || cached.version !== version) {
package/src/tui.tsx CHANGED
@@ -1,3 +1,4 @@
1
+ /** @jsxImportSource @opentui/solid */
1
2
  // Terminal surface for opencode-self-improvement (the CLI/TUI half of the
2
3
  // plugin). Runs in the terminal process, beside the host's OpenTUI renderer:
3
4
  // a one-line footer badge (what is in my context + is the cache healthy), a
package/tsconfig.json ADDED
@@ -0,0 +1,17 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ESNext",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "types": ["bun", "node"],
7
+ "skipLibCheck": true,
8
+ "strict": true,
9
+ "noEmit": true,
10
+ "allowImportingTsExtensions": true,
11
+ "erasableSyntaxOnly": true,
12
+ "verbatimModuleSyntax": true,
13
+ "jsx": "preserve",
14
+ "jsxImportSource": "@opentui/solid"
15
+ },
16
+ "include": ["index.ts", "src", "test", "bench"]
17
+ }