@inerrata-corporation/errata 2.0.8-dev.2896 → 2.0.8-dev.2914

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 +113 -54
  2. package/package.json +1 -1
package/errata.mjs CHANGED
@@ -29131,6 +29131,12 @@ function statuslineText(sessionId, now = Date.now()) {
29131
29131
  if (!hit || now - hit.at > STATUS_CARD_TTL_MS) return IDLE_STATUS;
29132
29132
  return renderStatusCard(hit.card);
29133
29133
  }
29134
+ function statuslineDir(body2) {
29135
+ const ws = body2["workspace"];
29136
+ const current = ws && typeof ws === "object" ? ws["current_dir"] : void 0;
29137
+ if (typeof current === "string" && current) return current;
29138
+ return typeof body2["cwd"] === "string" && body2["cwd"] ? body2["cwd"] : null;
29139
+ }
29134
29140
  function recallCardEnabled(env2 = process.env) {
29135
29141
  const v = (env2["ERRATA_RECALL_CARD"] ?? "").trim().toLowerCase();
29136
29142
  return !(v === "0" || v === "off" || v === "false" || v === "no");
@@ -71393,7 +71399,7 @@ var init_report_render = __esm({
71393
71399
 
71394
71400
  // src/cli.ts
71395
71401
  init_src6();
71396
- import { closeSync as closeSync2, existsSync as existsSync34, openSync as openSync2, readFileSync as readFileSync35, renameSync as renameSync4, statSync as statSync10 } from "node:fs";
71402
+ import { closeSync as closeSync2, existsSync as existsSync35, openSync as openSync2, readFileSync as readFileSync36, renameSync as renameSync4, statSync as statSync10 } from "node:fs";
71397
71403
  import { join as join43, resolve as pathResolve2 } from "node:path";
71398
71404
  import { spawn as spawn5 } from "node:child_process";
71399
71405
 
@@ -72715,9 +72721,9 @@ var NodeFsHandler = class {
72715
72721
  if (this.fsw.closed) {
72716
72722
  return;
72717
72723
  }
72718
- const dirname13 = sysPath.dirname(file2);
72724
+ const dirname14 = sysPath.dirname(file2);
72719
72725
  const basename8 = sysPath.basename(file2);
72720
- const parent = this.fsw._getWatchedDir(dirname13);
72726
+ const parent = this.fsw._getWatchedDir(dirname14);
72721
72727
  let prevStats = stats;
72722
72728
  if (parent.has(basename8))
72723
72729
  return;
@@ -72744,7 +72750,7 @@ var NodeFsHandler = class {
72744
72750
  prevStats = newStats2;
72745
72751
  }
72746
72752
  } catch (error48) {
72747
- this.fsw._remove(dirname13, basename8);
72753
+ this.fsw._remove(dirname14, basename8);
72748
72754
  }
72749
72755
  } else if (parent.has(basename8)) {
72750
72756
  const at = newStats.atimeMs;
@@ -80218,7 +80224,7 @@ function createWatchBreaker(deps) {
80218
80224
  }
80219
80225
 
80220
80226
  // src/engine.ts
80221
- var DAEMON_VERSION = true ? "2.0.8-dev.2896" : "2.0.0-alpha.0";
80227
+ var DAEMON_VERSION = true ? "2.0.8-dev.2914" : "2.0.0-alpha.0";
80222
80228
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
80223
80229
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
80224
80230
  var GIT_OP_MUTE_MS = 4e3;
@@ -86706,6 +86712,15 @@ async function startMultiDaemon(opts = {}) {
86706
86712
  app.post("/api/context-inject", (c) => forward(c, cwdOf, { affinity: "follow" }));
86707
86713
  app.post("/api/statusline", async (c) => {
86708
86714
  const body2 = await c.req.json().catch(() => ({}));
86715
+ const dir = statuslineDir(body2);
86716
+ if (dir !== null) {
86717
+ const d = normPath(dir);
86718
+ const known = listWorkspaceEntries().some((e) => {
86719
+ const root = normPath(e.path);
86720
+ return d === root || d.startsWith(`${root}/`);
86721
+ });
86722
+ if (!known) return c.text("");
86723
+ }
86709
86724
  return c.text(statuslineText(String(body2["session_id"] ?? "")));
86710
86725
  });
86711
86726
  for (const r of records) {
@@ -88566,9 +88581,10 @@ function consolidationGapMs(lastPassMs, policy) {
88566
88581
  }
88567
88582
 
88568
88583
  // src/claude-statusline.ts
88569
- import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync26 } from "node:fs";
88570
- import { join as join42 } from "node:path";
88571
- var STATUSLINE_RELAY_SOURCE = String.raw`// errata-managed: regenerated by errata install-hooks claude
88584
+ import { existsSync as existsSync34, mkdirSync as mkdirSync10, readFileSync as readFileSync35, writeFileSync as writeFileSync26 } from "node:fs";
88585
+ import { homedir as homedir8 } from "node:os";
88586
+ import { dirname as dirname13, join as join42 } from "node:path";
88587
+ var STATUSLINE_RELAY_SOURCE = String.raw`// errata-managed: regenerated by errata init / install-hooks claude
88572
88588
  import { readFileSync } from 'node:fs';
88573
88589
 
88574
88590
  try {
@@ -88594,15 +88610,57 @@ function buildStatusLine(port, nodePath, relayPath) {
88594
88610
  function isErrataStatusLine(value) {
88595
88611
  return !!value && typeof value === "object" && typeof value["command"] === "string" && value["command"].includes(STATUSLINE_RELAY_FILE);
88596
88612
  }
88597
- function installStatusLine(settings, root, port, nodePath = process.execPath) {
88598
- if (settings["statusLine"] !== void 0 && !isErrataStatusLine(settings["statusLine"])) return false;
88599
- const dir = join42(root, ".claude", "hooks");
88600
- const relay = join42(dir, STATUSLINE_RELAY_FILE);
88601
- mkdirSync10(dir, { recursive: true });
88602
- writeFileSync26(relay, STATUSLINE_RELAY_SOURCE, "utf8");
88603
- settings["statusLine"] = buildStatusLine(port, nodePath, relay);
88613
+ function removeProjectStatusLine(settings) {
88614
+ if (!isErrataStatusLine(settings["statusLine"])) return false;
88615
+ delete settings["statusLine"];
88604
88616
  return true;
88605
88617
  }
88618
+ function userClaudeSettingsPath() {
88619
+ const base = process.env["CLAUDE_CONFIG_DIR"] ?? join42(homedir8(), ".claude");
88620
+ return join42(base, "settings.json");
88621
+ }
88622
+ function ensureUserStatusLine(opts) {
88623
+ const env2 = opts.env ?? process.env;
88624
+ const off = (env2["ERRATA_STATUSLINE"] ?? "").trim().toLowerCase();
88625
+ if (off === "0" || off === "off" || off === "false" || off === "no") return "disabled";
88626
+ const settingsPath = opts.userSettingsPath ?? userClaudeSettingsPath();
88627
+ let settings = {};
88628
+ if (existsSync34(settingsPath)) {
88629
+ try {
88630
+ const parsed = JSON.parse(readFileSync35(settingsPath, "utf8"));
88631
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return "unreadable";
88632
+ settings = parsed;
88633
+ } catch {
88634
+ return "unreadable";
88635
+ }
88636
+ }
88637
+ if (settings["statusLine"] !== void 0 && !isErrataStatusLine(settings["statusLine"])) return "kept-own";
88638
+ const relay = join42(opts.relayDir, STATUSLINE_RELAY_FILE);
88639
+ mkdirSync10(opts.relayDir, { recursive: true });
88640
+ if (!existsSync34(relay) || readFileSync35(relay, "utf8") !== STATUSLINE_RELAY_SOURCE) {
88641
+ writeFileSync26(relay, STATUSLINE_RELAY_SOURCE, "utf8");
88642
+ }
88643
+ const next = buildStatusLine(opts.port, opts.nodePath ?? process.execPath, relay);
88644
+ if (JSON.stringify(settings["statusLine"]) === JSON.stringify(next)) return "unchanged";
88645
+ settings["statusLine"] = next;
88646
+ mkdirSync10(dirname13(settingsPath), { recursive: true });
88647
+ writeFileSync26(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf8");
88648
+ return "installed";
88649
+ }
88650
+ function describeStatusLineOutcome(outcome) {
88651
+ switch (outcome) {
88652
+ case "installed":
88653
+ return "status line: errata recall card in colour (user settings; ERRATA_STATUSLINE=off opts out)";
88654
+ case "unchanged":
88655
+ return "status line: errata recall card already set up";
88656
+ case "kept-own":
88657
+ return "status line: kept your own \u2014 errata's recall card shows inline only";
88658
+ case "disabled":
88659
+ return "status line: skipped (ERRATA_STATUSLINE=off)";
88660
+ case "unreadable":
88661
+ return "status line: skipped \u2014 ~/.claude/settings.json is not valid JSON";
88662
+ }
88663
+ }
88606
88664
 
88607
88665
  // src/opencode-plugin.ts
88608
88666
  var OPENCODE_PLUGIN_MARKER = "// @inerrata opencode plugin \u2014 errata-managed (errata install-hooks opencode)";
@@ -89009,14 +89067,14 @@ async function cmdInit() {
89009
89067
  if (!skipHooks) {
89010
89068
  console.log("");
89011
89069
  console.log("installing harness hooks...");
89012
- const { existsSync: existsSync35 } = await import("node:fs");
89070
+ const { existsSync: existsSync36 } = await import("node:fs");
89013
89071
  const { join: join44 } = await import("node:path");
89014
89072
  try {
89015
89073
  await installClaudeHooks(port);
89016
89074
  } catch (err2) {
89017
89075
  console.warn(` \u26A0\uFE0F Claude hook install failed: ${err2 instanceof Error ? err2.message : err2}`);
89018
89076
  }
89019
- if (existsSync35(join44(ROOT, ".cursor"))) {
89077
+ if (existsSync36(join44(ROOT, ".cursor"))) {
89020
89078
  try {
89021
89079
  await installCursorMcpConfig();
89022
89080
  } catch (err2) {
@@ -89118,6 +89176,7 @@ async function cmdStart() {
89118
89176
  await ensureProfile();
89119
89177
  const profile = loadProfile(ROOT);
89120
89178
  if (profile) registerWorkspace(profile, ROOT);
89179
+ if (profile) console.log(`errata: ${ensureStatusLine(resolveHookPort())}`);
89121
89180
  const lockPath = globalDaemonLock();
89122
89181
  const running = isDaemonAlive(lockPath) ? readDaemonLock(lockPath) : null;
89123
89182
  const where = profile ? `${profile.name} (${profile.id})` : ROOT;
@@ -89205,9 +89264,9 @@ async function cmdStatus() {
89205
89264
  console.log(` stack: ${profile.stack.join(", ") || "(none)"}`);
89206
89265
  console.log(` languages: ${profile.languages.join(", ") || "(none)"}`);
89207
89266
  }
89208
- console.log(` graph db: ${existsSync34(paths.castalia) ? "yes" : "no"} (${paths.castalia})`);
89209
- console.log(` event log: ${existsSync34(paths.eventLog) ? "yes" : "no"} (${paths.eventLog})`);
89210
- if (existsSync34(paths.castalia)) {
89267
+ console.log(` graph db: ${existsSync35(paths.castalia) ? "yes" : "no"} (${paths.castalia})`);
89268
+ console.log(` event log: ${existsSync35(paths.eventLog) ? "yes" : "no"} (${paths.eventLog})`);
89269
+ if (existsSync35(paths.castalia)) {
89211
89270
  try {
89212
89271
  const { openGraphStore: openGraphStore2 } = await Promise.resolve().then(() => (init_src5(), src_exports2));
89213
89272
  const store = openGraphStore2({ path: paths.castalia });
@@ -89840,6 +89899,7 @@ async function cmdLink(args2) {
89840
89899
  process.exitCode = 1;
89841
89900
  return;
89842
89901
  }
89902
+ console.log(ensureStatusLine(resolveHookPort()));
89843
89903
  delete profile.projectLinkDisabled;
89844
89904
  const remote = flag("--remote");
89845
89905
  if (remote) {
@@ -90176,11 +90236,11 @@ function cmdInstallationProfile(args2) {
90176
90236
  }
90177
90237
  async function cmdReview() {
90178
90238
  const paths = workspacePaths(ROOT);
90179
- if (!existsSync34(paths.reviewQueue)) {
90239
+ if (!existsSync35(paths.reviewQueue)) {
90180
90240
  console.log("(review queue empty)");
90181
90241
  return;
90182
90242
  }
90183
- const queue = JSON.parse(readFileSync35(paths.reviewQueue, "utf8"));
90243
+ const queue = JSON.parse(readFileSync36(paths.reviewQueue, "utf8"));
90184
90244
  if (queue.length === 0) {
90185
90245
  console.log("(review queue empty)");
90186
90246
  return;
@@ -90851,7 +90911,7 @@ async function gatherRepo(store, ws) {
90851
90911
  };
90852
90912
  }
90853
90913
  async function gatherReportData(generatedAt) {
90854
- const { existsSync: existsSync35 } = await import("node:fs");
90914
+ const { existsSync: existsSync36 } = await import("node:fs");
90855
90915
  const { openGraphStore: openGraphStore2 } = await Promise.resolve().then(() => (init_src5(), src_exports2));
90856
90916
  const cfg = loadConfig();
90857
90917
  const outbound = cfg.consent.sync ? "auto" : "off";
@@ -90859,7 +90919,7 @@ async function gatherReportData(generatedAt) {
90859
90919
  for (const ws of listWorkspaces()) {
90860
90920
  if (ws.missing) continue;
90861
90921
  const dbPath = workspacePaths(ws.path).castalia;
90862
- if (!existsSync35(dbPath)) continue;
90922
+ if (!existsSync36(dbPath)) continue;
90863
90923
  let store = null;
90864
90924
  try {
90865
90925
  store = openGraphStore2({ path: dbPath });
@@ -91024,13 +91084,13 @@ async function cmdInstallHooks(args2) {
91024
91084
  }
91025
91085
  }
91026
91086
  async function installOpencodePlugin(port) {
91027
- const { mkdirSync: mkdirSync11, existsSync: existsSync35, readFileSync: readFileSync36, writeFileSync: writeFileSync27 } = await import("node:fs");
91087
+ const { mkdirSync: mkdirSync11, existsSync: existsSync36, readFileSync: readFileSync37, writeFileSync: writeFileSync27 } = await import("node:fs");
91028
91088
  const { join: join44 } = await import("node:path");
91029
91089
  const dir = join44(ROOT, ".opencode", "plugin");
91030
- if (!existsSync35(dir)) mkdirSync11(dir, { recursive: true });
91090
+ if (!existsSync36(dir)) mkdirSync11(dir, { recursive: true });
91031
91091
  const file2 = join44(dir, "inerrata.js");
91032
- if (existsSync35(file2)) {
91033
- const head2 = readFileSync36(file2, "utf8").split("\n")[0] ?? "";
91092
+ if (existsSync36(file2)) {
91093
+ const head2 = readFileSync37(file2, "utf8").split("\n")[0] ?? "";
91034
91094
  if (head2.trim() !== OPENCODE_PLUGIN_MARKER) {
91035
91095
  console.error(`refusing to overwrite ${file2}: not an errata-managed plugin (line 1 lacks the marker)`);
91036
91096
  process.exit(2);
@@ -91039,9 +91099,9 @@ async function installOpencodePlugin(port) {
91039
91099
  writeFileSync27(file2, buildOpencodePluginSource(port, { version: DAEMON_VERSION }), "utf8");
91040
91100
  const cfgFile = join44(ROOT, "opencode.json");
91041
91101
  let cfg = { $schema: "https://opencode.ai/config.json" };
91042
- if (existsSync35(cfgFile)) {
91102
+ if (existsSync36(cfgFile)) {
91043
91103
  try {
91044
- cfg = JSON.parse(readFileSync36(cfgFile, "utf8"));
91104
+ cfg = JSON.parse(readFileSync37(cfgFile, "utf8"));
91045
91105
  } catch {
91046
91106
  console.error(`refusing to touch invalid JSON at ${cfgFile} \u2014 fix it and re-run`);
91047
91107
  process.exit(2);
@@ -91071,16 +91131,23 @@ function errataMcpInvocation() {
91071
91131
  const { cmd: cmd2, args: args2 } = selfArgv("mcp");
91072
91132
  return { command: cmd2, args: args2 };
91073
91133
  }
91134
+ function ensureStatusLine(port) {
91135
+ try {
91136
+ return describeStatusLineOutcome(ensureUserStatusLine({ port, relayDir: globalDir() }));
91137
+ } catch (err2) {
91138
+ return `status line: not installed (${err2 instanceof Error ? err2.message : err2})`;
91139
+ }
91140
+ }
91074
91141
  async function installClaudeHooks(port) {
91075
- const { mkdirSync: mkdirSync11, existsSync: existsSync35, readFileSync: readFileSync36, writeFileSync: writeFileSync27 } = await import("node:fs");
91142
+ const { mkdirSync: mkdirSync11, existsSync: existsSync36, readFileSync: readFileSync37, writeFileSync: writeFileSync27 } = await import("node:fs");
91076
91143
  const { join: join44 } = await import("node:path");
91077
91144
  const dir = join44(ROOT, ".claude");
91078
- if (!existsSync35(dir)) mkdirSync11(dir, { recursive: true });
91145
+ if (!existsSync36(dir)) mkdirSync11(dir, { recursive: true });
91079
91146
  const file2 = join44(dir, "settings.json");
91080
91147
  let settings = {};
91081
- if (existsSync35(file2)) {
91148
+ if (existsSync36(file2)) {
91082
91149
  try {
91083
- settings = JSON.parse(readFileSync36(file2, "utf8"));
91150
+ settings = JSON.parse(readFileSync37(file2, "utf8"));
91084
91151
  } catch {
91085
91152
  console.error(`refusing to overwrite invalid JSON at ${file2}`);
91086
91153
  process.exit(2);
@@ -91127,18 +91194,10 @@ async function installClaudeHooks(port) {
91127
91194
  dropErrata(list);
91128
91195
  list.push({ hooks: [{ type: "command", command: injectCmd }] });
91129
91196
  }
91130
- const { homedir: homedir8 } = await import("node:os");
91131
- let userStatusLine;
91132
- try {
91133
- userStatusLine = JSON.parse(readFileSync36(join44(homedir8(), ".claude", "settings.json"), "utf8"))["statusLine"];
91134
- } catch {
91135
- }
91136
- const statusLineInstalled = (userStatusLine === void 0 || isErrataStatusLine(userStatusLine)) && installStatusLine(settings, ROOT, port);
91197
+ removeProjectStatusLine(settings);
91137
91198
  writeFileSync27(file2, JSON.stringify(settings, null, 2) + "\n", "utf8");
91138
91199
  console.log(`installed Claude Code hooks \u2192 ${file2}`);
91139
- console.log(
91140
- statusLineInstalled ? " status line: errata recall card in colour (daemon env ERRATA_RECALL_CARD=off hides the cards)" : " status line: kept your own \u2014 errata's recall card shows inline only"
91141
- );
91200
+ console.log(` ${ensureStatusLine(port)}`);
91142
91201
  await installClaudeMcpConfig();
91143
91202
  const claudeMd = join44(ROOT, "CLAUDE.md");
91144
91203
  const recall = writeManagedBlock(claudeMd, { body: RECALL_FIRST_BLOCK });
@@ -91152,15 +91211,15 @@ async function installClaudeHooks(port) {
91152
91211
  console.log(` endpoint: http://127.0.0.1:${port}/api/hook`);
91153
91212
  }
91154
91213
  async function installClaudeMcpConfig() {
91155
- const { mkdirSync: mkdirSync11, existsSync: existsSync35, readFileSync: readFileSync36, writeFileSync: writeFileSync27 } = await import("node:fs");
91156
- const { join: join44, dirname: dirname13 } = await import("node:path");
91214
+ const { mkdirSync: mkdirSync11, existsSync: existsSync36, readFileSync: readFileSync37, writeFileSync: writeFileSync27 } = await import("node:fs");
91215
+ const { join: join44, dirname: dirname14 } = await import("node:path");
91157
91216
  const file2 = join44(ROOT, ".mcp.json");
91158
- const dir = dirname13(file2);
91159
- if (!existsSync35(dir)) mkdirSync11(dir, { recursive: true });
91217
+ const dir = dirname14(file2);
91218
+ if (!existsSync36(dir)) mkdirSync11(dir, { recursive: true });
91160
91219
  let cfg = {};
91161
- if (existsSync35(file2)) {
91220
+ if (existsSync36(file2)) {
91162
91221
  try {
91163
- cfg = JSON.parse(readFileSync36(file2, "utf8"));
91222
+ cfg = JSON.parse(readFileSync37(file2, "utf8"));
91164
91223
  } catch {
91165
91224
  console.error(`refusing to overwrite invalid JSON at ${file2}`);
91166
91225
  process.exit(2);
@@ -91174,15 +91233,15 @@ async function installClaudeMcpConfig() {
91174
91233
  console.log(` Tools: errata.search / locate / neighbors / callers_of / what_uses / show / similar`);
91175
91234
  }
91176
91235
  async function installCursorMcpConfig() {
91177
- const { mkdirSync: mkdirSync11, existsSync: existsSync35, readFileSync: readFileSync36, writeFileSync: writeFileSync27 } = await import("node:fs");
91236
+ const { mkdirSync: mkdirSync11, existsSync: existsSync36, readFileSync: readFileSync37, writeFileSync: writeFileSync27 } = await import("node:fs");
91178
91237
  const { join: join44 } = await import("node:path");
91179
91238
  const dir = join44(ROOT, ".cursor");
91180
- if (!existsSync35(dir)) mkdirSync11(dir, { recursive: true });
91239
+ if (!existsSync36(dir)) mkdirSync11(dir, { recursive: true });
91181
91240
  const file2 = join44(dir, "mcp.json");
91182
91241
  let cfg = {};
91183
- if (existsSync35(file2)) {
91242
+ if (existsSync36(file2)) {
91184
91243
  try {
91185
- cfg = JSON.parse(readFileSync36(file2, "utf8"));
91244
+ cfg = JSON.parse(readFileSync37(file2, "utf8"));
91186
91245
  } catch {
91187
91246
  console.error(`refusing to overwrite invalid JSON at ${file2}`);
91188
91247
  process.exit(2);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inerrata-corporation/errata",
3
- "version": "2.0.8-dev.2896",
3
+ "version": "2.0.8-dev.2914",
4
4
  "description": "errata - local-first observation engine for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {