Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
35 changes: 13 additions & 22 deletions skills/wiki-ask/scripts/enchiridion.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -37164,7 +37163,6 @@ async function captureSession(wikiRoot, slug, cwd, lookupEnv = processLookupEnv,
now,
exportSeam
);
} catch {
}
return captureClaudeCodeSession(wikiRoot, slug, cwd, lookupEnv, now);
}
Expand Down Expand Up @@ -37246,35 +37244,27 @@ 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 === "") {
throw new CaptureError(
"$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;
Expand Down Expand Up @@ -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);
Expand Down
35 changes: 13 additions & 22 deletions skills/wiki-ingest/scripts/enchiridion.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -37164,7 +37163,6 @@ async function captureSession(wikiRoot, slug, cwd, lookupEnv = processLookupEnv,
now,
exportSeam
);
} catch {
}
return captureClaudeCodeSession(wikiRoot, slug, cwd, lookupEnv, now);
}
Expand Down Expand Up @@ -37246,35 +37244,27 @@ 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 === "") {
throw new CaptureError(
"$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;
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion wiki-plugin/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
2 changes: 1 addition & 1 deletion wiki-plugin/opencode-npm/package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
35 changes: 13 additions & 22 deletions wiki-plugin/scripts/cli.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -37164,7 +37163,6 @@ async function captureSession(wikiRoot, slug, cwd, lookupEnv = processLookupEnv,
now,
exportSeam
);
} catch {
}
return captureClaudeCodeSession(wikiRoot, slug, cwd, lookupEnv, now);
}
Expand Down Expand Up @@ -37246,35 +37244,27 @@ 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 === "") {
throw new CaptureError(
"$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;
Expand Down Expand Up @@ -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);
Expand Down
Loading