diff --git a/CLAUDE.md b/CLAUDE.md index 56f9319..cc87418 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -67,7 +67,7 @@ If you're tempted to write a new standalone design doc for this project, don't - **`enchiridion save-session` serves both hosts**, detecting the host from which session-id variable is set — Claude Code's `$CLAUDE_CODE_SESSION_ID` (hook-recorded transcript path on disk) or OpenCode's `$OPENCODE_SESSION_ID` (tracker-plugin state, transcript fetched by shelling out to `opencode export`, whose stdout goes to a temp *file* because it truncates on a pipe). Both vars can be set at once (one host run from the other's shell), and env alone can't say which is innermost, so the tie breaks on evidence: OpenCode wins only when its tracker plugin recorded *that* id in *this* project, else Claude Code. Everything downstream of the host-specific fetch — turn filtering, rendering, filename binding — is the one shared seam in `enchiridion-ts/src/transcriptcapture.ts`, so an OpenCode capture inherits its generic "Source: Claude Code session transcript" line. - **`/to-spec` needs a scope-clarifying question first** on this repo — it's wayfinder-mapped (phases charted as child tickets off #1), not "one undiscussed feature per invocation," so expect to ask which phase(s) before drafting. - **Eval strategy:** the hand-authored "golden vault" is shelved in favor of a small synthetic fixture — the irreducible deliverable is the **property list**, not the pages. ~8 pages of deliberately fake content at `wiki-plugin/evals/fixtures/` plus `evals/PROPERTIES.md` (human-owned, agent-drafted, [ADR-0005](docs/adr/0005-tdd-for-scripts-evals-for-agents.md)). Tracked at [#47](https://github.com/dhague/wiki-knowledge/issues/47), still open. The live dogfooding vault stays complementary, never the substrate — it's 100% ingestion output and it moves. The eval **harness** (headless `claude -p` runs, pass-rate, structural assertions, LLM judge for fuzzy questions) is still fog, graduates once #47 lands. -- **Plugin version: `0.11.3`** (`wiki-plugin/.claude-plugin/plugin.json`) — don't assume `main` at any given moment matches any given tag. +- **Plugin version: `0.11.4`** (`wiki-plugin/.claude-plugin/plugin.json`) — don't assume `main` at any given moment matches any given tag. ### The dogfooding vault diff --git a/skills/wiki-ask/scripts/enchiridion.cjs b/skills/wiki-ask/scripts/enchiridion.cjs index 27c44e7..fb50421 100755 --- a/skills/wiki-ask/scripts/enchiridion.cjs +++ b/skills/wiki-ask/scripts/enchiridion.cjs @@ -37154,8 +37154,7 @@ async function captureSession(wikiRoot, slug, cwd, lookupEnv = processLookupEnv, ); } if (openCodeID) { - try { - findOpenCodeSessionID(cwd, lookupEnv); + if (isOpenCodeSessionTracked(cwd, lookupEnv)) { return captureOpenCodeSession( wikiRoot, slug, @@ -37164,7 +37163,6 @@ async function captureSession(wikiRoot, slug, cwd, lookupEnv = processLookupEnv, now, exportSeam ); - } catch { } return captureClaudeCodeSession(wikiRoot, slug, cwd, lookupEnv, now); } @@ -37246,7 +37244,7 @@ function openCodeSessionIsTracked(sessionID, stateDir) { return false; } } -function findOpenCodeSessionID(cwd, lookupEnv = processLookupEnv) { +function openCodeSessionIDFromEnv(lookupEnv = processLookupEnv) { const [sessionIDRaw, ok] = lookupEnv("OPENCODE_SESSION_ID"); const sessionID = sessionIDRaw ?? ""; if (!ok || sessionID === "") { @@ -37254,27 +37252,19 @@ function findOpenCodeSessionID(cwd, lookupEnv = processLookupEnv) { "$OPENCODE_SESSION_ID is not set in this environment. (The session-tracker plugin's shell.env hook injects it; is the plugin installed and loaded in this project?)" ); } + return sessionID; +} +function isOpenCodeSessionTracked(cwd, lookupEnv = processLookupEnv) { + const [sessionIDRaw, ok] = lookupEnv("OPENCODE_SESSION_ID"); + const sessionID = sessionIDRaw ?? ""; + if (!ok || sessionID === "") return false; const stateDir = openCodeSessionsDir(cwd); - let stat4; try { - stat4 = import_node_fs4.default.statSync(stateDir); + if (!import_node_fs4.default.statSync(stateDir).isDirectory()) return false; } catch { - throw openCodeStateNotLocated(cwd, stateDir); - } - if (!stat4.isDirectory()) { - throw openCodeStateNotLocated(cwd, stateDir); - } - if (!openCodeSessionIsTracked(sessionID, stateDir)) { - throw new CaptureError( - "No state recorded for session " + sessionID + " under " + stateDir + ", per the session-tracker plugin. (If this session was started before the plugin was installed, it was never recorded; start a new session and try again.)" - ); + return false; } - return sessionID; -} -function openCodeStateNotLocated(cwd, stateDir) { - return new CaptureError( - "Could not locate OpenCode session-tracker state. Searched " + cwd + " and its ancestors for a '.opencode/' directory, and found no " + stateDir + ". (Has the session-tracker plugin ever run in this project? Start a new session in the project root and try again.)" - ); + return openCodeSessionIsTracked(sessionID, stateDir); } async function exportTranscript(sessionID, command) { let bin = command; @@ -37401,7 +37391,8 @@ function normalizeExport(exportDoc) { return turns; } async function captureOpenCodeSession(wikiRoot, slug, cwd, lookupEnv, now, exportSeam) { - const sessionID = findOpenCodeSessionID(cwd, lookupEnv); + void cwd; + const sessionID = openCodeSessionIDFromEnv(lookupEnv); const timestamp = now.getTime() === 0 ? /* @__PURE__ */ new Date() : now; const fetch = exportSeam ?? ((id) => exportTranscript(id, "opencode")); const document2 = await fetch(sessionID); diff --git a/skills/wiki-ingest/scripts/enchiridion.cjs b/skills/wiki-ingest/scripts/enchiridion.cjs index 27c44e7..fb50421 100755 --- a/skills/wiki-ingest/scripts/enchiridion.cjs +++ b/skills/wiki-ingest/scripts/enchiridion.cjs @@ -37154,8 +37154,7 @@ async function captureSession(wikiRoot, slug, cwd, lookupEnv = processLookupEnv, ); } if (openCodeID) { - try { - findOpenCodeSessionID(cwd, lookupEnv); + if (isOpenCodeSessionTracked(cwd, lookupEnv)) { return captureOpenCodeSession( wikiRoot, slug, @@ -37164,7 +37163,6 @@ async function captureSession(wikiRoot, slug, cwd, lookupEnv = processLookupEnv, now, exportSeam ); - } catch { } return captureClaudeCodeSession(wikiRoot, slug, cwd, lookupEnv, now); } @@ -37246,7 +37244,7 @@ function openCodeSessionIsTracked(sessionID, stateDir) { return false; } } -function findOpenCodeSessionID(cwd, lookupEnv = processLookupEnv) { +function openCodeSessionIDFromEnv(lookupEnv = processLookupEnv) { const [sessionIDRaw, ok] = lookupEnv("OPENCODE_SESSION_ID"); const sessionID = sessionIDRaw ?? ""; if (!ok || sessionID === "") { @@ -37254,27 +37252,19 @@ function findOpenCodeSessionID(cwd, lookupEnv = processLookupEnv) { "$OPENCODE_SESSION_ID is not set in this environment. (The session-tracker plugin's shell.env hook injects it; is the plugin installed and loaded in this project?)" ); } + return sessionID; +} +function isOpenCodeSessionTracked(cwd, lookupEnv = processLookupEnv) { + const [sessionIDRaw, ok] = lookupEnv("OPENCODE_SESSION_ID"); + const sessionID = sessionIDRaw ?? ""; + if (!ok || sessionID === "") return false; const stateDir = openCodeSessionsDir(cwd); - let stat4; try { - stat4 = import_node_fs4.default.statSync(stateDir); + if (!import_node_fs4.default.statSync(stateDir).isDirectory()) return false; } catch { - throw openCodeStateNotLocated(cwd, stateDir); - } - if (!stat4.isDirectory()) { - throw openCodeStateNotLocated(cwd, stateDir); - } - if (!openCodeSessionIsTracked(sessionID, stateDir)) { - throw new CaptureError( - "No state recorded for session " + sessionID + " under " + stateDir + ", per the session-tracker plugin. (If this session was started before the plugin was installed, it was never recorded; start a new session and try again.)" - ); + return false; } - return sessionID; -} -function openCodeStateNotLocated(cwd, stateDir) { - return new CaptureError( - "Could not locate OpenCode session-tracker state. Searched " + cwd + " and its ancestors for a '.opencode/' directory, and found no " + stateDir + ". (Has the session-tracker plugin ever run in this project? Start a new session in the project root and try again.)" - ); + return openCodeSessionIsTracked(sessionID, stateDir); } async function exportTranscript(sessionID, command) { let bin = command; @@ -37401,7 +37391,8 @@ function normalizeExport(exportDoc) { return turns; } async function captureOpenCodeSession(wikiRoot, slug, cwd, lookupEnv, now, exportSeam) { - const sessionID = findOpenCodeSessionID(cwd, lookupEnv); + void cwd; + const sessionID = openCodeSessionIDFromEnv(lookupEnv); const timestamp = now.getTime() === 0 ? /* @__PURE__ */ new Date() : now; const fetch = exportSeam ?? ((id) => exportTranscript(id, "opencode")); const document2 = await fetch(sessionID); diff --git a/wiki-plugin/.claude-plugin/plugin.json b/wiki-plugin/.claude-plugin/plugin.json index 5b4ed64..b2077fb 100644 --- a/wiki-plugin/.claude-plugin/plugin.json +++ b/wiki-plugin/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "wiki-knowledge", - "version": "0.11.3", + "version": "0.11.4", "description": "Clean-room ingestion and retrieval over a git-backed markdown wiki vault, following the Karpathy LLM-wiki pattern.", "author": { "name": "Darren Hague", diff --git a/wiki-plugin/opencode-npm/package.json b/wiki-plugin/opencode-npm/package.json index 4ff071b..43681d9 100644 --- a/wiki-plugin/opencode-npm/package.json +++ b/wiki-plugin/opencode-npm/package.json @@ -1,6 +1,6 @@ { "name": "@dhague/wiki-knowledge", - "version": "0.11.3", + "version": "0.11.4", "description": "Clean-room ingestion and retrieval over a git-backed markdown wiki vault, following the Karpathy LLM-wiki pattern.", "author": { "name": "Darren Hague", diff --git a/wiki-plugin/scripts/cli.cjs b/wiki-plugin/scripts/cli.cjs index 27c44e7..fb50421 100755 --- a/wiki-plugin/scripts/cli.cjs +++ b/wiki-plugin/scripts/cli.cjs @@ -37154,8 +37154,7 @@ async function captureSession(wikiRoot, slug, cwd, lookupEnv = processLookupEnv, ); } if (openCodeID) { - try { - findOpenCodeSessionID(cwd, lookupEnv); + if (isOpenCodeSessionTracked(cwd, lookupEnv)) { return captureOpenCodeSession( wikiRoot, slug, @@ -37164,7 +37163,6 @@ async function captureSession(wikiRoot, slug, cwd, lookupEnv = processLookupEnv, now, exportSeam ); - } catch { } return captureClaudeCodeSession(wikiRoot, slug, cwd, lookupEnv, now); } @@ -37246,7 +37244,7 @@ function openCodeSessionIsTracked(sessionID, stateDir) { return false; } } -function findOpenCodeSessionID(cwd, lookupEnv = processLookupEnv) { +function openCodeSessionIDFromEnv(lookupEnv = processLookupEnv) { const [sessionIDRaw, ok] = lookupEnv("OPENCODE_SESSION_ID"); const sessionID = sessionIDRaw ?? ""; if (!ok || sessionID === "") { @@ -37254,27 +37252,19 @@ function findOpenCodeSessionID(cwd, lookupEnv = processLookupEnv) { "$OPENCODE_SESSION_ID is not set in this environment. (The session-tracker plugin's shell.env hook injects it; is the plugin installed and loaded in this project?)" ); } + return sessionID; +} +function isOpenCodeSessionTracked(cwd, lookupEnv = processLookupEnv) { + const [sessionIDRaw, ok] = lookupEnv("OPENCODE_SESSION_ID"); + const sessionID = sessionIDRaw ?? ""; + if (!ok || sessionID === "") return false; const stateDir = openCodeSessionsDir(cwd); - let stat4; try { - stat4 = import_node_fs4.default.statSync(stateDir); + if (!import_node_fs4.default.statSync(stateDir).isDirectory()) return false; } catch { - throw openCodeStateNotLocated(cwd, stateDir); - } - if (!stat4.isDirectory()) { - throw openCodeStateNotLocated(cwd, stateDir); - } - if (!openCodeSessionIsTracked(sessionID, stateDir)) { - throw new CaptureError( - "No state recorded for session " + sessionID + " under " + stateDir + ", per the session-tracker plugin. (If this session was started before the plugin was installed, it was never recorded; start a new session and try again.)" - ); + return false; } - return sessionID; -} -function openCodeStateNotLocated(cwd, stateDir) { - return new CaptureError( - "Could not locate OpenCode session-tracker state. Searched " + cwd + " and its ancestors for a '.opencode/' directory, and found no " + stateDir + ". (Has the session-tracker plugin ever run in this project? Start a new session in the project root and try again.)" - ); + return openCodeSessionIsTracked(sessionID, stateDir); } async function exportTranscript(sessionID, command) { let bin = command; @@ -37401,7 +37391,8 @@ function normalizeExport(exportDoc) { return turns; } async function captureOpenCodeSession(wikiRoot, slug, cwd, lookupEnv, now, exportSeam) { - const sessionID = findOpenCodeSessionID(cwd, lookupEnv); + void cwd; + const sessionID = openCodeSessionIDFromEnv(lookupEnv); const timestamp = now.getTime() === 0 ? /* @__PURE__ */ new Date() : now; const fetch = exportSeam ?? ((id) => exportTranscript(id, "opencode")); const document2 = await fetch(sessionID);