@inerrata-corporation/errata 2.0.6-dev.2734 → 2.0.6-dev.2759

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 +129 -16
  2. package/package.json +1 -1
package/errata.mjs CHANGED
@@ -71189,7 +71189,7 @@ var init_report_render = __esm({
71189
71189
  init_src6();
71190
71190
  import { closeSync as closeSync2, existsSync as existsSync34, openSync as openSync2, readFileSync as readFileSync35, renameSync as renameSync4, statSync as statSync8 } from "node:fs";
71191
71191
  import { join as join40, resolve as pathResolve2 } from "node:path";
71192
- import { spawn as spawn4 } from "node:child_process";
71192
+ import { spawn as spawn5 } from "node:child_process";
71193
71193
 
71194
71194
  // src/daemon.ts
71195
71195
  import { existsSync as existsSync26, writeFileSync as writeFileSync22 } from "node:fs";
@@ -74469,10 +74469,12 @@ function fixRationaleBefore(sentence, idx) {
74469
74469
  const ws = masked.slice(start2, idx).search(/\s/);
74470
74470
  start2 = ws < 0 ? idx : start2 + ws;
74471
74471
  }
74472
- const win = masked.slice(start2, idx);
74473
- const m = /[.;!?—][^.;!?—]*$/.exec(win);
74474
- const clause = m ? win.slice(m.index + 1) : win;
74475
- return clause.replace(/\s+/g, " ").trim();
74472
+ const win = masked.slice(start2, idx).replace(/\s+$/, "").replace(/[.!?]$/, "");
74473
+ const scan2 = win.replace(/`[^`]*`/g, (s) => s.replace(/[.;!?—]/g, "_"));
74474
+ const m = /[.;!?—][^.;!?—]*$/.exec(scan2);
74475
+ const clause = (m ? win.slice(m.index + 1) : win).replace(/\*\*|__/g, "").replace(/^\s*(?:[-*+]|\d+[.)])\s+/, "").replace(/\s+([:;,])/g, "$1").replace(/\s+/g, " ").trim();
74476
+ if (clause.endsWith(":")) return "";
74477
+ return clause;
74476
74478
  }
74477
74479
  function fixRationaleAfter(sentence, endIdx) {
74478
74480
  if (/^\s*[)\]}]/.test(sentence.slice(endIdx))) return "";
@@ -74598,7 +74600,7 @@ function parseInlineTagsWithDispositions(text) {
74598
74600
  const dispositions = emptyTagDispositions();
74599
74601
  const deFenced = text.replace(/```[\s\S]*?```/g, " ");
74600
74602
  let seqNo = -1;
74601
- for (const raw2 of deFenced.split(/(?<=[.!?])\s+|\n+/)) {
74603
+ for (const raw2 of deFenced.split(/(?<=[.!?])\s+(?!\(fix:)|\n+/)) {
74602
74604
  seqNo++;
74603
74605
  if (raw2.length > 2e4) {
74604
74606
  dispositions.oversizeSegments++;
@@ -79905,7 +79907,7 @@ function createWatchBreaker(deps) {
79905
79907
  }
79906
79908
 
79907
79909
  // src/engine.ts
79908
- var DAEMON_VERSION = true ? "2.0.6-dev.2734" : "2.0.0-alpha.0";
79910
+ var DAEMON_VERSION = true ? "2.0.6-dev.2759" : "2.0.0-alpha.0";
79909
79911
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
79910
79912
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
79911
79913
  var GIT_OP_MUTE_MS = 4e3;
@@ -85575,6 +85577,7 @@ var SessionAffinity = class {
85575
85577
  };
85576
85578
 
85577
85579
  // src/multi.ts
85580
+ init_checkout_root();
85578
85581
  var PROCESS_STARTED_AT = Date.now();
85579
85582
  var SELF_ENTRY = process.argv[1] ? pathResolve(process.argv[1]) : "";
85580
85583
  var LOCAL_BUILD_ENTRY = SELF_ENTRY && !isInstalledEntry(SELF_ENTRY) ? SELF_ENTRY : void 0;
@@ -86122,6 +86125,19 @@ async function startMultiDaemon(opts = {}) {
86122
86125
  if (owner) break;
86123
86126
  owner = ownerOf(records, p);
86124
86127
  }
86128
+ if (!owner) {
86129
+ for (const p of [primary, ...others]) {
86130
+ if (!p) continue;
86131
+ const gitRoot = nearestGitRoot(p);
86132
+ const main2 = gitRoot ? mainCheckoutOfWorktree(gitRoot) : null;
86133
+ if (!main2) continue;
86134
+ owner = ownerOf(records, main2);
86135
+ if (!owner && listWorkspaceEntries().some((e) => pickOwnerRoot([e.path], main2))) {
86136
+ if (attachWorkspace(main2).attached) owner = ownerOf(records, main2);
86137
+ }
86138
+ if (owner) break;
86139
+ }
86140
+ }
86125
86141
  if (!owner && others.length > 0) {
86126
86142
  const registryRoots = listWorkspaceEntries().map((e) => e.path);
86127
86143
  const registered = others.map((p) => pickOwnerRoot(registryRoots, p)).find((r) => r != null);
@@ -87550,9 +87566,9 @@ function deriveAuthBase(verificationUri) {
87550
87566
  }
87551
87567
  function openInBrowser(url2) {
87552
87568
  try {
87553
- void import("node:child_process").then(({ spawn: spawn5 }) => {
87569
+ void import("node:child_process").then(({ spawn: spawn6 }) => {
87554
87570
  const [cmd2, args2] = process.platform === "win32" ? ["cmd", ["/c", "start", "", url2]] : process.platform === "darwin" ? ["open", [url2]] : ["xdg-open", [url2]];
87555
- spawn5(cmd2, args2, { detached: true, stdio: "ignore" }).unref();
87571
+ spawn6(cmd2, args2, { detached: true, stdio: "ignore" }).unref();
87556
87572
  });
87557
87573
  } catch {
87558
87574
  }
@@ -87632,6 +87648,7 @@ function installedHarnessVersion(bin) {
87632
87648
  }
87633
87649
  async function diagnoseInstallation(cfg, dependencies) {
87634
87650
  const checks = [];
87651
+ if (dependencies.codexHooks) checks.push(...await dependencies.codexHooks());
87635
87652
  const profileName = cfg.activeInstallationProfile;
87636
87653
  const profile = profileName ? cfg.installationProfiles[profileName] : void 0;
87637
87654
  checks.push(
@@ -87725,6 +87742,97 @@ async function diagnoseInstallation(cfg, dependencies) {
87725
87742
  };
87726
87743
  }
87727
87744
 
87745
+ // src/codex-doctor.ts
87746
+ import { spawn as spawn4 } from "node:child_process";
87747
+ import { createInterface } from "node:readline";
87748
+ function readCodexHookState(cwd, options = {}) {
87749
+ return new Promise((resolve7, reject) => {
87750
+ const child = spawn4(options.bin ?? "codex", options.args ?? ["app-server", "--stdio"], {
87751
+ cwd,
87752
+ windowsHide: true,
87753
+ stdio: ["pipe", "pipe", "pipe"]
87754
+ });
87755
+ const lines = createInterface({ input: child.stdout });
87756
+ let settled = false;
87757
+ let size = 0;
87758
+ let hooks;
87759
+ let features;
87760
+ const finish = (error48) => {
87761
+ if (settled) return;
87762
+ settled = true;
87763
+ clearTimeout(timer);
87764
+ lines.close();
87765
+ child.kill();
87766
+ if (error48) reject(error48);
87767
+ else resolve7({ ...hooks, features });
87768
+ };
87769
+ const timer = setTimeout(() => finish(new Error("Codex hook inspection timed out")), options.timeoutMs ?? 1e4);
87770
+ const send = (id, method, params) => {
87771
+ child.stdin.write(JSON.stringify({ id, method, params }) + "\n");
87772
+ };
87773
+ child.on("error", () => finish(new Error("Codex could not be started for hook inspection")));
87774
+ child.on("exit", () => finish(new Error("Codex exited before returning its hook state")));
87775
+ child.stdin.on("error", () => finish(new Error("Codex hook inspection connection closed")));
87776
+ child.stderr.resume();
87777
+ child.stdout.on("data", (chunk) => {
87778
+ size += chunk.length;
87779
+ if (size > 2e6) finish(new Error("Codex hook inspection exceeded its response budget"));
87780
+ });
87781
+ lines.on("line", (line) => {
87782
+ if (settled) return;
87783
+ let message2;
87784
+ try {
87785
+ message2 = JSON.parse(line);
87786
+ } catch {
87787
+ return;
87788
+ }
87789
+ if (![1, 2, 3].includes(message2.id)) return;
87790
+ if (message2.error) return finish(new Error("Codex does not support hook inspection; update Codex and review /hooks"));
87791
+ if (message2.id === 1) {
87792
+ child.stdin.write(JSON.stringify({ method: "initialized" }) + "\n");
87793
+ send(2, "hooks/list", { cwds: [cwd] });
87794
+ send(3, "config/read", { cwd, includeLayers: false });
87795
+ } else if (message2.id === 2) {
87796
+ const entry = message2.result?.data?.[0];
87797
+ if (!Array.isArray(entry?.hooks)) return finish(new Error("Codex returned no hook inspection result"));
87798
+ hooks = { hooks: entry.hooks, errors: entry.errors };
87799
+ } else {
87800
+ if (!message2.result?.config) return finish(new Error("Codex returned no effective configuration"));
87801
+ features = message2.result.config.features ?? {};
87802
+ }
87803
+ if (hooks && features) finish();
87804
+ });
87805
+ send(1, "initialize", {
87806
+ clientInfo: { name: "errata_doctor", version: "1.0.0" },
87807
+ capabilities: { experimentalApi: true }
87808
+ });
87809
+ });
87810
+ }
87811
+ function assessCodexHooks(state) {
87812
+ const check2 = (status, detail) => [{ id: "codex_hooks", status, detail }];
87813
+ if (state.errors?.length) return check2("fail", "Codex could not load hook configuration; inspect /hooks for errors");
87814
+ if ((state.features?.hooks ?? state.features?.codex_hooks) === false) {
87815
+ return check2("fail", "Codex hooks are explicitly disabled; left unchanged");
87816
+ }
87817
+ const hooks = state.hooks.filter((h) => h.command?.includes("errata-relay.mjs"));
87818
+ const required2 = ["sessionStart", "userPromptSubmit", "preToolUse", "postToolUse", "stop"];
87819
+ const missing = required2.filter((event) => !hooks.some((h) => h.eventName === event));
87820
+ const checks = [];
87821
+ if (missing.length) checks.push(...check2("fail", `Errata hooks missing or outdated in this checkout (${missing.join(", ")}); run errata install-hooks codex here`));
87822
+ if (hooks.some((h) => !h.enabled)) checks.push(...check2("fail", "Errata hooks are disabled in Codex; review /hooks; left unchanged"));
87823
+ if (hooks.some((h) => !["trusted", "managed"].includes(h.trustStatus))) {
87824
+ checks.push(...check2("fail", "Errata hooks need review/trust in Codex /hooks before they can run; project trust is separate"));
87825
+ }
87826
+ return checks.length ? checks : check2("pass", "Codex discovers enabled, trusted Errata hooks; verify live context and capture in a session");
87827
+ }
87828
+ async function diagnoseCodexHooks(cwd) {
87829
+ try {
87830
+ return assessCodexHooks(await readCodexHookState(cwd));
87831
+ } catch (error48) {
87832
+ return [{ id: "codex_hooks", status: "fail", detail: error48 instanceof Error ? error48.message : "Cannot verify Codex hooks" }];
87833
+ }
87834
+ }
87835
+
87728
87836
  // src/whoami.ts
87729
87837
  async function resolveWhoami(client, actingHandle) {
87730
87838
  return actingHandle ? client.contextAs(actingHandle) : client.context();
@@ -87817,8 +87925,8 @@ function buildCodexHooksToml(port, options) {
87817
87925
  };
87818
87926
  if (!Number.isInteger(port) || port < 1 || port > 65535) throw new Error("Invalid hook port");
87819
87927
  const command = quote(options.nodePath) + " " + quote(options.relayPath) + " " + port;
87820
- const handlers = ["SessionStart", "UserPromptSubmit", "PreToolUse", "PostToolUse"].map(
87821
- (event) => "[[hooks." + event + "]]\n" + (event === "UserPromptSubmit" ? "" : 'matcher = ".*"\n') + "\n[[hooks." + event + '.hooks]]\ntype = "command"\ncommand = ' + JSON.stringify(command) + "\ntimeout = 10\nadditionalContextLimit = 5000\n"
87928
+ const handlers = ["SessionStart", "UserPromptSubmit", "PreToolUse", "PostToolUse", "Stop"].map(
87929
+ (event) => "[[hooks." + event + "]]\n" + (["UserPromptSubmit", "Stop"].includes(event) ? "" : 'matcher = ".*"\n') + "\n[[hooks." + event + '.hooks]]\ntype = "command"\ncommand = ' + JSON.stringify(command) + "\ntimeout = 10\nadditionalContextLimit = 5000\n"
87822
87930
  );
87823
87931
  return CODEX_HOOKS_BEGIN + "\n" + handlers.join("\n") + CODEX_HOOKS_END + "\n";
87824
87932
  }
@@ -87851,7 +87959,8 @@ try {
87851
87959
  } catch { /* An unavailable daemon must never block the agent. */ }
87852
87960
  };
87853
87961
  if (event === 'PreToolUse' || event === 'PostToolUse') await post('hook', true);
87854
- if (event === 'PostToolUse') await post('turn');
87962
+ // Stop sees the final assistant message, including turns with no tools.
87963
+ if (event === 'PostToolUse' || event === 'Stop') await post('turn');
87855
87964
  if (['SessionStart', 'UserPromptSubmit', 'PostToolUse'].includes(event)) {
87856
87965
  // Run after capture, so changes already rendered by the daemon arrive now.
87857
87966
  // Background extraction finishing later arrives at the next tool boundary.
@@ -88750,6 +88859,7 @@ async function cmdWhoami(args2) {
88750
88859
  async function cmdDoctor(args2) {
88751
88860
  const cfg = loadConfig();
88752
88861
  const report = await diagnoseInstallation(cfg, {
88862
+ ...hasCodexConfig(process.cwd()) ? { codexHooks: () => diagnoseCodexHooks(process.cwd()) } : {},
88753
88863
  inspect: () => inspectCloudEndpoint(cfg.cloudUrl),
88754
88864
  authenticate: async () => {
88755
88865
  const me = await authedCloudClient(cfg).me();
@@ -90195,7 +90305,7 @@ function spawnDaemonDetached(options = {}) {
90195
90305
  out2 = openSync2(logPath, "a");
90196
90306
  } catch {
90197
90307
  }
90198
- spawn4(cmd2, args2, {
90308
+ spawn5(cmd2, args2, {
90199
90309
  detached: true,
90200
90310
  stdio: ["ignore", out2, out2],
90201
90311
  windowsHide: true,
@@ -90417,12 +90527,15 @@ async function installCursorMcpConfig() {
90417
90527
  console.log(` \u26A0\uFE0F reload Cursor (Cmd/Ctrl-Shift-P \u2192 "Reload Window") to pick it up.`);
90418
90528
  }
90419
90529
  async function installCodexHooks(port) {
90420
- const file2 = writeCodexHooks(ROOT, port);
90530
+ const gitRoot = nearestGitRoot(process.cwd());
90531
+ const hookRoot = gitRoot && mainCheckoutOfWorktree(gitRoot) ? gitRoot : ROOT;
90532
+ const file2 = writeCodexHooks(hookRoot, port);
90421
90533
  console.log(`installed Codex hooks \u2192 ${file2}`);
90422
90534
  console.log(" Context loads on SessionStart/UserPromptSubmit and refreshes after tools when changed.");
90423
- console.log(" Tool capture and /api/turn harvesting remain enabled.");
90535
+ console.log(" Tool and final-reply capture are configured; hooks must be trusted before they run.");
90424
90536
  console.log(" Restart/resume Codex to reload config, then review and trust the hooks with /hooks.");
90425
- console.log(" If your Codex version gates hooks, enable [features] codex_hooks = true.");
90537
+ console.log(" Run `errata doctor` here to check hook discovery and trust; installation alone is not activation.");
90538
+ console.log(" Respect an explicit [features] hooks = false setting (older builds use codex_hooks).");
90426
90539
  console.log(" Older Codex versions may not support every event; update if hooks do not fire.");
90427
90540
  }
90428
90541
  async function refreshLinkedCodexHooks(args2) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inerrata-corporation/errata",
3
- "version": "2.0.6-dev.2734",
3
+ "version": "2.0.6-dev.2759",
4
4
  "description": "errata - local-first observation engine for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {