@inerrata-corporation/errata 2.0.2-dev.1024 → 2.0.2-dev.1097

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.
Files changed (2) hide show
  1. package/errata.mjs +132 -41
  2. package/package.json +1 -1
package/errata.mjs CHANGED
@@ -19166,7 +19166,8 @@ function ingestDesignProblem(store, flag, opts) {
19166
19166
  designProblemId: problemId,
19167
19167
  sources: [opts.source],
19168
19168
  corroborations: 0,
19169
- scope: {}
19169
+ scope: {},
19170
+ ...opts.hostHarness ? { hostHarness: opts.hostHarness } : {}
19170
19171
  })
19171
19172
  );
19172
19173
  }
@@ -53100,7 +53101,64 @@ function readAssistantTurnsFrom(transcriptPath, fromByte, includeThinking = true
53100
53101
  losses: { parseFailures: parsed.parseFailures, ioFailed, bytesUnreachable: 0 }
53101
53102
  };
53102
53103
  }
53104
+ function detectHostHarness(raw2) {
53105
+ const lines = raw2.split(/\r?\n/);
53106
+ let checked = 0;
53107
+ for (const line of lines) {
53108
+ if (!line.trim()) continue;
53109
+ if (checked++ >= 5) break;
53110
+ let obj;
53111
+ try {
53112
+ obj = JSON.parse(line);
53113
+ } catch {
53114
+ continue;
53115
+ }
53116
+ if (obj.type === "response_item" || obj.type === "event_msg" || obj.type === "session_meta" || obj.type === "turn_context" || obj.type === "world_state") {
53117
+ return "codex";
53118
+ }
53119
+ if (obj.type === "user" || obj.type === "assistant" || obj.type === "summary") {
53120
+ return "claude_code";
53121
+ }
53122
+ }
53123
+ return "claude_code";
53124
+ }
53103
53125
  function parseAssistantTurns(raw2, includeThinking, skipFirstLineParseFailure = false) {
53126
+ if (!raw2) return { turns: [], parseFailures: 0 };
53127
+ return detectHostHarness(raw2) === "codex" ? parseCodexAssistantTurns(raw2, skipFirstLineParseFailure) : parseClaudeAssistantTurns(raw2, includeThinking, skipFirstLineParseFailure);
53128
+ }
53129
+ function parseCodexAssistantTurns(raw2, skipFirstLineParseFailure = false) {
53130
+ const turns = [];
53131
+ const lines = raw2.split(/\r?\n/);
53132
+ let parseFailures = 0;
53133
+ for (let i2 = 0; i2 < lines.length; i2++) {
53134
+ const line = lines[i2];
53135
+ if (!line) continue;
53136
+ let obj;
53137
+ try {
53138
+ obj = JSON.parse(line);
53139
+ } catch {
53140
+ if (!(i2 === 0 && skipFirstLineParseFailure)) parseFailures++;
53141
+ continue;
53142
+ }
53143
+ if (obj.type !== "response_item") continue;
53144
+ const payload = obj.payload;
53145
+ if (!payload || payload["type"] !== "message" || payload["role"] !== "assistant") continue;
53146
+ const content = payload["content"];
53147
+ if (!Array.isArray(content)) continue;
53148
+ const parts2 = [];
53149
+ for (const b of content) {
53150
+ if (b["type"] === "output_text" && typeof b["text"] === "string") parts2.push(b["text"]);
53151
+ }
53152
+ if (parts2.length === 0) continue;
53153
+ turns.push({
53154
+ uuid: typeof payload["id"] === "string" ? payload["id"] : `codex-${i2}`,
53155
+ text: parts2.join("\n\n"),
53156
+ hostHarness: "codex"
53157
+ });
53158
+ }
53159
+ return { turns, parseFailures };
53160
+ }
53161
+ function parseClaudeAssistantTurns(raw2, includeThinking, skipFirstLineParseFailure = false) {
53104
53162
  if (!raw2) return { turns: [], parseFailures: 0 };
53105
53163
  const turns = [];
53106
53164
  const lines = raw2.split(/\r?\n/);
@@ -53154,6 +53212,7 @@ function parseAssistantTurns(raw2, includeThinking, skipFirstLineParseFailure =
53154
53212
  turns.push({
53155
53213
  uuid: String(obj.uuid ?? i2),
53156
53214
  text: parts2.join("\n\n"),
53215
+ hostHarness: "claude_code",
53157
53216
  ...lastFile ? { workingFile: lastFile } : {},
53158
53217
  ...provenance ? { workingFileProvenance: provenance } : {},
53159
53218
  ...editedFile && editedFileTurnSeq === turnSeq ? { editedFile } : {},
@@ -56442,7 +56501,7 @@ function createLivenessWatch(deps) {
56442
56501
  }
56443
56502
 
56444
56503
  // src/engine.ts
56445
- var DAEMON_VERSION = true ? "2.0.2-dev.1024" : "2.0.0-alpha.0";
56504
+ var DAEMON_VERSION = true ? "2.0.2-dev.1097" : "2.0.0-alpha.0";
56446
56505
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
56447
56506
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
56448
56507
  var GIT_OP_MUTE_MS = 4e3;
@@ -56948,6 +57007,7 @@ function createWorkspaceEngine(opts) {
56948
57007
  contextDirty = false;
56949
57008
  notifyDigest("recall");
56950
57009
  };
57010
+ const normStackTokens = (xs) => (xs ?? []).map((t) => t.trim().toLowerCase().replace(/(?!^)[@\s].*$/, "")).filter(Boolean);
56951
57011
  const maybeRefreshRemotePriors = () => {
56952
57012
  if (opts.skipContextWriter || remoteInFlight) return;
56953
57013
  const now = Date.now();
@@ -56958,10 +57018,13 @@ function createWorkspaceEngine(opts) {
56958
57018
  remoteInFlight = true;
56959
57019
  lastRemoteAt = now;
56960
57020
  try {
56961
- const norm = (xs) => (xs ?? []).map((t) => t.trim().toLowerCase().replace(/(?!^)[@\s].*$/, "")).filter(Boolean);
57021
+ const norm = normStackTokens;
56962
57022
  const seed = store.findNodesByLabel("Problem").sort((a, b) => b.lastUpdatedAt - a.lastUpdatedAt).slice(0, 6).map((p) => p.id);
56963
57023
  const q = {
56964
- stack: norm(profile.stack),
57024
+ // Languages ride the stack list: the cloud's context-affinity matcher
57025
+ // resolves each token against both the Package and Language
57026
+ // namespaces, and the profile keeps them in separate fields.
57027
+ stack: norm([...profile.stack ?? [], ...profile.languages ?? []]),
56965
57028
  domains: norm(profile.domains),
56966
57029
  kinds: ["Pattern", "Technique", "AntiPattern"],
56967
57030
  ...seed.length ? { seed } : {},
@@ -56990,8 +57053,16 @@ function createWorkspaceEngine(opts) {
56990
57053
  if (typeof cloud.search !== "function") return;
56991
57054
  intentRemoteInFlight = true;
56992
57055
  cloud.search({
56993
- stack: [],
56994
- domains: [],
57056
+ // VS-context-affinity: the intent lane used to send an empty context
57057
+ // while the priming lane sent the profile — opposite postures on the
57058
+ // same method. Under "union derived + stated, canonicalize once"
57059
+ // (VS-intent-fence) the stated intent IS the query and the derived
57060
+ // stack rides along as structured relevanceContext: the cloud no
57061
+ // longer concatenates these tokens into the embedding string, it
57062
+ // re-weights anchored hits with them (stated beats derived — the
57063
+ // intent text drives entry search, the stack only re-ranks).
57064
+ stack: normStackTokens([...profile?.stack ?? [], ...profile?.languages ?? []]),
57065
+ domains: normStackTokens(profile?.domains ?? []),
56995
57066
  kinds: ["Pattern", "Technique", "AntiPattern", "Problem", "Solution"],
56996
57067
  q: liveIntent,
56997
57068
  channel: "intent",
@@ -57296,7 +57367,8 @@ function createWorkspaceEngine(opts) {
57296
57367
  const r = ingestDesignProblem(store, flag, {
57297
57368
  workspaceId: profile.id,
57298
57369
  source: sessionId,
57299
- ts: t
57370
+ ts: t,
57371
+ hostHarness: turn.hostHarness
57300
57372
  });
57301
57373
  if (r.created || r.corroborated) minted++;
57302
57374
  else if (r.rejected) tagsRejected++;
@@ -57415,7 +57487,8 @@ function createWorkspaceEngine(opts) {
57415
57487
  const r = ingestDesignProblem(store, { problem: p.statement, kind: p.kind }, {
57416
57488
  workspaceId: profile.id,
57417
57489
  source: sessionId,
57418
- ts: t
57490
+ ts: t,
57491
+ hostHarness: turn.hostHarness
57419
57492
  });
57420
57493
  if (r.created || r.corroborated) {
57421
57494
  minted++;
@@ -61755,6 +61828,45 @@ function consolidationGapMs(lastPassMs, policy) {
61755
61828
  return Math.max(policy.baseFloorMs, lastPassMs * policy.dutyFactor);
61756
61829
  }
61757
61830
 
61831
+ // src/hook-commands.ts
61832
+ function hookCurlCommand(port, path2 = "/api/hook") {
61833
+ const url2 = `http://127.0.0.1:${port}${path2}`;
61834
+ return process.platform === "win32" ? `cmd //c "curl -s --connect-timeout 1 --max-time 3 -X POST -H \\"Content-Type: application/json\\" --data-binary @- ${url2} >NUL 2>NUL || exit /b 0"` : `curl -s --connect-timeout 1 --max-time 3 -X POST -H 'Content-Type: application/json' --data-binary @- ${url2} >/dev/null 2>&1 || true`;
61835
+ }
61836
+ function hookRelayCommand(port, path2) {
61837
+ const url2 = `http://127.0.0.1:${port}${path2}`;
61838
+ return process.platform === "win32" ? `cmd //c "curl -s --connect-timeout 1 --max-time 2 -X POST -H \\"Content-Type: application/json\\" --data-binary @- ${url2} 2>NUL || echo {}"` : `curl -s --connect-timeout 1 --max-time 2 -X POST -H 'Content-Type: application/json' --data-binary @- ${url2} 2>/dev/null || echo '{}'`;
61839
+ }
61840
+ var CODEX_HOOKS_BEGIN = `# >>> errata hooks (errata-managed)`;
61841
+ var CODEX_HOOKS_END = `# <<< errata hooks`;
61842
+ function buildCodexHooksToml(port) {
61843
+ const cmd2 = hookCurlCommand(port).replace(/"/g, '\\"');
61844
+ const turnCmd = hookCurlCommand(port, "/api/turn").replace(/"/g, '\\"');
61845
+ return `${CODEX_HOOKS_BEGIN}
61846
+ [[hooks.PreToolUse]]
61847
+ matcher = ".*"
61848
+
61849
+ [[hooks.PreToolUse.hooks]]
61850
+ type = "command"
61851
+ command = "${cmd2}"
61852
+ timeout = 10
61853
+
61854
+ [[hooks.PostToolUse]]
61855
+ matcher = ".*"
61856
+
61857
+ [[hooks.PostToolUse.hooks]]
61858
+ type = "command"
61859
+ command = "${cmd2}"
61860
+ timeout = 10
61861
+
61862
+ [[hooks.PostToolUse.hooks]]
61863
+ type = "command"
61864
+ command = "${turnCmd}"
61865
+ timeout = 10
61866
+ ${CODEX_HOOKS_END}
61867
+ `;
61868
+ }
61869
+
61758
61870
  // src/cli.ts
61759
61871
  var exitCleanOnEpipe = (err2) => {
61760
61872
  if (err2.code === "EPIPE") process.exit(0);
@@ -63846,14 +63958,6 @@ function errataMcpInvocation() {
63846
63958
  const { cmd: cmd2, args: args2 } = selfArgv("mcp");
63847
63959
  return { command: cmd2, args: args2 };
63848
63960
  }
63849
- function hookCurlCommand(port, path2 = "/api/hook") {
63850
- const url2 = `http://127.0.0.1:${port}${path2}`;
63851
- return process.platform === "win32" ? `cmd //c "curl -s --connect-timeout 1 --max-time 3 -X POST -H \\"Content-Type: application/json\\" --data-binary @- ${url2} >NUL 2>NUL || exit /b 0"` : `curl -s --connect-timeout 1 --max-time 3 -X POST -H 'Content-Type: application/json' --data-binary @- ${url2} >/dev/null 2>&1 || true`;
63852
- }
63853
- function hookRelayCommand(port, path2) {
63854
- const url2 = `http://127.0.0.1:${port}${path2}`;
63855
- return process.platform === "win32" ? `cmd //c "curl -s --connect-timeout 1 --max-time 2 -X POST -H \\"Content-Type: application/json\\" --data-binary @- ${url2} 2>NUL || echo {}"` : `curl -s --connect-timeout 1 --max-time 2 -X POST -H 'Content-Type: application/json' --data-binary @- ${url2} 2>/dev/null || echo '{}'`;
63856
- }
63857
63961
  async function installClaudeHooks(port) {
63858
63962
  const { mkdirSync: mkdirSync9, existsSync: existsSync31, readFileSync: readFileSync29, writeFileSync: writeFileSync23 } = await import("node:fs");
63859
63963
  const { join: join33 } = await import("node:path");
@@ -63975,45 +64079,32 @@ async function installCodexHooks(port) {
63975
64079
  const dir = join33(ROOT, ".codex");
63976
64080
  if (!existsSync31(dir)) mkdirSync9(dir, { recursive: true });
63977
64081
  const file2 = join33(dir, "config.toml");
63978
- const BEGIN = `# >>> errata hooks (errata-managed)`;
63979
- const END = `# <<< errata hooks`;
63980
64082
  let existing = "";
63981
64083
  if (existsSync31(file2)) {
63982
64084
  existing = readFileSync29(file2, "utf8");
63983
- const beginIdx = existing.indexOf(BEGIN);
63984
- const endIdx = existing.indexOf(END);
64085
+ const beginIdx = existing.indexOf(CODEX_HOOKS_BEGIN);
64086
+ const endIdx = existing.indexOf(CODEX_HOOKS_END);
63985
64087
  if (beginIdx >= 0 && endIdx > beginIdx) {
63986
- existing = existing.slice(0, beginIdx).trimEnd() + existing.slice(endIdx + END.length).trimStart();
64088
+ existing = existing.slice(0, beginIdx).trimEnd() + existing.slice(endIdx + CODEX_HOOKS_END.length).trimStart();
63987
64089
  }
63988
64090
  }
63989
- const cmd2 = hookCurlCommand(port).replace(/"/g, '\\"');
63990
- const block = `${BEGIN}
63991
- [[hooks.PreToolUse]]
63992
- matcher = ".*"
63993
-
63994
- [[hooks.PreToolUse.hooks]]
63995
- type = "command"
63996
- command = "${cmd2}"
63997
- timeout = 10
63998
-
63999
- [[hooks.PostToolUse]]
64000
- matcher = ".*"
64001
-
64002
- [[hooks.PostToolUse.hooks]]
64003
- type = "command"
64004
- command = "${cmd2}"
64005
- timeout = 10
64006
- ${END}
64007
- `;
64091
+ const block = buildCodexHooksToml(port);
64008
64092
  const final = existing.length > 0 && !existing.endsWith("\n") ? `${existing}
64009
64093
 
64010
64094
  ${block}` : existing + (existing.endsWith("\n\n") ? "" : "\n") + block;
64011
64095
  writeFileSync23(file2, final, "utf8");
64012
64096
  console.log(`installed Codex hooks \u2192 ${file2}`);
64013
- console.log(` endpoint: http://127.0.0.1:${port}/api/hook`);
64097
+ console.log(` endpoint: http://127.0.0.1:${port}/api/hook (+ /api/turn on PostToolUse)`);
64014
64098
  console.log("");
64015
64099
  console.log(` Codex reads files via the shell, so the virtual graph surface`);
64016
64100
  console.log(` works by \`cat .errata/g/<verb>/<seed>\` (e.g. cat .errata/g/burst/foo).`);
64101
+ console.log("");
64102
+ console.log(` Codex has no Stop/SessionEnd hook at this installed version, so`);
64103
+ console.log(` [!\u2026]/(fix:[\u2026]) tags are harvested via the PostToolUse-triggered`);
64104
+ console.log(` /api/turn call above instead \u2014 every turn with a tool call is`);
64105
+ console.log(` covered; a tool-less final turn is picked up on this workspace's`);
64106
+ console.log(` next daemon boot replay. Re-run this after a Codex upgrade in`);
64107
+ console.log(` case a newer version adds a real turn-boundary hook.`);
64017
64108
  console.log(` If [features] hooks=false in your config.toml, set it true. Hook`);
64018
64109
  console.log(` schemas evolve \u2014 if hooks stop firing after an update, re-run this.`);
64019
64110
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inerrata-corporation/errata",
3
- "version": "2.0.2-dev.1024",
3
+ "version": "2.0.2-dev.1097",
4
4
  "description": "errata - local-first observation engine for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {