@inerrata-corporation/errata 2.0.0-dev.47 → 2.0.0-dev.48

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 +139 -44
  2. package/package.json +1 -1
package/errata.mjs CHANGED
@@ -20946,6 +20946,20 @@ var init_client = __esm({
20946
20946
  async createProject(name2) {
20947
20947
  return this.json("POST", "/api/gate/projects/create", { name: name2 });
20948
20948
  }
20949
+ /** Read-only discovery (PJ-attach clone tripwire): the org's claim on a
20950
+ * locator, or null. NEVER creates — 404 means the org hasn't linked it. */
20951
+ async lookupProject(locator) {
20952
+ try {
20953
+ const res = await this.json(
20954
+ "GET",
20955
+ `/api/gate/projects/lookup?locator=${encodeURIComponent(locator)}`
20956
+ );
20957
+ return res.project;
20958
+ } catch (err2) {
20959
+ if (err2 instanceof CloudError && err2.status === 404) return null;
20960
+ throw err2;
20961
+ }
20962
+ }
20949
20963
  // ─── ingest ────────────────────────────────────────────────────────
20950
20964
  /** Upload one outbox batch (projected onto the reconciled wire) and fold
20951
20965
  * the per-decision response into flush accounting.
@@ -38269,8 +38283,8 @@ var init_report_render = __esm({
38269
38283
 
38270
38284
  // src/cli.ts
38271
38285
  init_src5();
38272
- import { closeSync as closeSync2, existsSync as existsSync21, openSync as openSync2, readFileSync as readFileSync20, renameSync as renameSync3, statSync as statSync6 } from "node:fs";
38273
- import { join as join24 } from "node:path";
38286
+ import { closeSync as closeSync2, existsSync as existsSync22, openSync as openSync2, readFileSync as readFileSync20, renameSync as renameSync3, statSync as statSync6 } from "node:fs";
38287
+ import { join as join25 } from "node:path";
38274
38288
  import { spawn as spawn3 } from "node:child_process";
38275
38289
 
38276
38290
  // src/daemon.ts
@@ -39586,9 +39600,9 @@ var NodeFsHandler = class {
39586
39600
  if (this.fsw.closed) {
39587
39601
  return;
39588
39602
  }
39589
- const dirname8 = sysPath.dirname(file2);
39603
+ const dirname9 = sysPath.dirname(file2);
39590
39604
  const basename5 = sysPath.basename(file2);
39591
- const parent = this.fsw._getWatchedDir(dirname8);
39605
+ const parent = this.fsw._getWatchedDir(dirname9);
39592
39606
  let prevStats = stats;
39593
39607
  if (parent.has(basename5))
39594
39608
  return;
@@ -39615,7 +39629,7 @@ var NodeFsHandler = class {
39615
39629
  prevStats = newStats2;
39616
39630
  }
39617
39631
  } catch (error48) {
39618
- this.fsw._remove(dirname8, basename5);
39632
+ this.fsw._remove(dirname9, basename5);
39619
39633
  }
39620
39634
  } else if (parent.has(basename5)) {
39621
39635
  const at = newStats.atimeMs;
@@ -42679,7 +42693,7 @@ function startLoopLagMonitor(thresholdMs = 1e3) {
42679
42693
  }
42680
42694
 
42681
42695
  // src/engine.ts
42682
- var DAEMON_VERSION = true ? "2.0.0-dev.47" : "2.0.0-alpha.0";
42696
+ var DAEMON_VERSION = true ? "2.0.0-dev.48" : "2.0.0-alpha.0";
42683
42697
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
42684
42698
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
42685
42699
  var GIT_OP_MUTE_MS = 4e3;
@@ -44761,6 +44775,48 @@ async function ensureProjectLink(root, profile, client) {
44761
44775
  }
44762
44776
  }
44763
44777
 
44778
+ // src/adopt.ts
44779
+ import { existsSync as existsSync21 } from "node:fs";
44780
+ import { dirname as dirname8, join as join24 } from "node:path";
44781
+ function findGitRoot(absPath) {
44782
+ let dir = absPath;
44783
+ for (let depth = 0; depth < 64; depth++) {
44784
+ if (existsSync21(join24(dir, ".git"))) return dir;
44785
+ const parent = dirname8(dir);
44786
+ if (parent === dir) return null;
44787
+ dir = parent;
44788
+ }
44789
+ return null;
44790
+ }
44791
+ var RETRY_COOLDOWN_MS = 15 * 6e4;
44792
+ function createRootAdopter(deps) {
44793
+ const attempted = /* @__PURE__ */ new Map();
44794
+ let chain = Promise.resolve();
44795
+ const tryAdopt = async (path2) => {
44796
+ if (!deps.linkingAllowed()) return;
44797
+ const root = findGitRoot(path2);
44798
+ if (!root || deps.isKnownRoot(root)) return;
44799
+ const last = attempted.get(root);
44800
+ const now = Date.now();
44801
+ if (last !== void 0 && now - last < RETRY_COOLDOWN_MS) return;
44802
+ attempted.set(root, now);
44803
+ if (!resolveGitDir(root)) return;
44804
+ const locator = detectRepoLocator(root);
44805
+ if (!locator) return;
44806
+ const claimed = await deps.lookup(locator);
44807
+ if (!claimed) return;
44808
+ await deps.adopt(root);
44809
+ deps.log(`[errata] adopted ${root} \u2014 ${locator} is claimed by your org (project ${claimed.id})`);
44810
+ };
44811
+ return {
44812
+ noteMiss(path2) {
44813
+ if (!path2) return;
44814
+ chain = chain.then(() => tryAdopt(path2)).catch(() => void 0);
44815
+ },
44816
+ idle: () => chain
44817
+ };
44818
+ }
44819
+
44764
44820
  // src/multi.ts
44765
44821
  function normPath(p) {
44766
44822
  return p.replace(/\\/g, "/").replace(/\/+$/, "").toLowerCase();
@@ -45023,7 +45079,10 @@ async function startMultiDaemon(opts = {}) {
45023
45079
  return c.json({ error: "bad-json" }, 400);
45024
45080
  }
45025
45081
  const owner = ownerOf(records, pathInBody(body2));
45026
- if (!owner) return c.json({ error: "no-matching-project" }, 404);
45082
+ if (!owner) {
45083
+ rootAdopter.noteMiss(pathInBody(body2));
45084
+ return c.json({ error: "no-matching-project" }, 404);
45085
+ }
45027
45086
  const sub = c.req.path;
45028
45087
  const done = markPass(`${sub}:${owner.entry.name}`);
45029
45088
  try {
@@ -45116,6 +45175,25 @@ async function startMultiDaemon(opts = {}) {
45116
45175
  if (opts.reindexOnStart !== false && records.length > 0) {
45117
45176
  void reindexAll({ skipEmbed: opts.skipEmbed ?? true });
45118
45177
  }
45178
+ const rootAdopter = createRootAdopter({
45179
+ isKnownRoot: (root) => pickOwnerRoot(records.map((r) => r.root), root) !== null,
45180
+ linkingAllowed: () => {
45181
+ const c = loadConfig();
45182
+ return c.consent.sync && hasCloudCredential(c);
45183
+ },
45184
+ lookup: async (locator) => cloudNow().lookupProject(locator),
45185
+ adopt: async (root) => {
45186
+ let profile = loadProfile(root);
45187
+ if (!profile) {
45188
+ profile = autodetectProfile(root);
45189
+ saveProfile(root, profile);
45190
+ }
45191
+ registerWorkspace(profile, root);
45192
+ attachWorkspace(root);
45193
+ },
45194
+ // eslint-disable-next-line no-console
45195
+ log: (line) => console.log(line)
45196
+ });
45119
45197
  const ambientLinkAll = async () => {
45120
45198
  const c = loadConfig();
45121
45199
  if (!c.consent.sync || !hasCloudCredential(c)) return;
@@ -46009,21 +46087,21 @@ async function cmdInit() {
46009
46087
  if (!skipHooks) {
46010
46088
  console.log("");
46011
46089
  console.log("installing harness hooks...");
46012
- const { existsSync: existsSync22 } = await import("node:fs");
46013
- const { join: join25 } = await import("node:path");
46090
+ const { existsSync: existsSync23 } = await import("node:fs");
46091
+ const { join: join26 } = await import("node:path");
46014
46092
  try {
46015
46093
  await installClaudeHooks(port);
46016
46094
  } catch (err2) {
46017
46095
  console.warn(` \u26A0\uFE0F Claude hook install failed: ${err2 instanceof Error ? err2.message : err2}`);
46018
46096
  }
46019
- if (existsSync22(join25(ROOT, ".cursor"))) {
46097
+ if (existsSync23(join26(ROOT, ".cursor"))) {
46020
46098
  try {
46021
46099
  await installCursorMcpConfig();
46022
46100
  } catch (err2) {
46023
46101
  console.warn(` \u26A0\uFE0F Cursor MCP config failed: ${err2 instanceof Error ? err2.message : err2}`);
46024
46102
  }
46025
46103
  }
46026
- if (existsSync22(join25(ROOT, ".codex"))) {
46104
+ if (existsSync23(join26(ROOT, ".codex"))) {
46027
46105
  try {
46028
46106
  await installCodexHooks(port);
46029
46107
  } catch (err2) {
@@ -46097,6 +46175,23 @@ async function cmdNotifyTest() {
46097
46175
  }
46098
46176
  }
46099
46177
  async function cmdStart() {
46178
+ if (!loadProfile(ROOT)) {
46179
+ const cfg = loadConfig();
46180
+ const locator = detectRepoLocator(ROOT);
46181
+ if (locator && cfg.consent.sync && hasCloudCredential(cfg)) {
46182
+ try {
46183
+ const claimed = await authedCloudClient(cfg).lookupProject(locator);
46184
+ if (claimed) {
46185
+ const adopted = autodetectProfile(ROOT);
46186
+ saveProfile(ROOT, adopted);
46187
+ console.log(
46188
+ `adopted: ${locator} is claimed by your org (project ${claimed.id}) \u2014 workspace initialized`
46189
+ );
46190
+ }
46191
+ } catch {
46192
+ }
46193
+ }
46194
+ }
46100
46195
  await ensureProfile();
46101
46196
  const profile = loadProfile(ROOT);
46102
46197
  if (profile) registerWorkspace(profile, ROOT);
@@ -46160,8 +46255,8 @@ async function cmdStatus() {
46160
46255
  console.log(` stack: ${profile.stack.join(", ") || "(none)"}`);
46161
46256
  console.log(` languages: ${profile.languages.join(", ") || "(none)"}`);
46162
46257
  }
46163
- console.log(` graph db: ${existsSync21(paths.castalia) ? "yes" : "no"} (${paths.castalia})`);
46164
- console.log(` event log: ${existsSync21(paths.eventLog) ? "yes" : "no"} (${paths.eventLog})`);
46258
+ console.log(` graph db: ${existsSync22(paths.castalia) ? "yes" : "no"} (${paths.castalia})`);
46259
+ console.log(` event log: ${existsSync22(paths.eventLog) ? "yes" : "no"} (${paths.eventLog})`);
46165
46260
  const lockPath = globalDaemonLock();
46166
46261
  const running = isDaemonAlive(lockPath) ? readDaemonLock(lockPath) : null;
46167
46262
  console.log(
@@ -46576,7 +46671,7 @@ async function cmdUse(args2) {
46576
46671
  }
46577
46672
  async function cmdReview() {
46578
46673
  const paths = workspacePaths(ROOT);
46579
- if (!existsSync21(paths.reviewQueue)) {
46674
+ if (!existsSync22(paths.reviewQueue)) {
46580
46675
  console.log("(review queue empty)");
46581
46676
  return;
46582
46677
  }
@@ -47210,7 +47305,7 @@ async function gatherRepo(store, ws) {
47210
47305
  };
47211
47306
  }
47212
47307
  async function gatherReportData(generatedAt) {
47213
- const { existsSync: existsSync22 } = await import("node:fs");
47308
+ const { existsSync: existsSync23 } = await import("node:fs");
47214
47309
  const { openGraphStore: openGraphStore2 } = await Promise.resolve().then(() => (init_src4(), src_exports2));
47215
47310
  const cfg = loadConfig();
47216
47311
  const outbound = cfg.consent.sync ? "auto" : "off";
@@ -47218,7 +47313,7 @@ async function gatherReportData(generatedAt) {
47218
47313
  for (const ws of listWorkspaces()) {
47219
47314
  if (ws.missing) continue;
47220
47315
  const dbPath = workspacePaths(ws.path).castalia;
47221
- if (!existsSync22(dbPath)) continue;
47316
+ if (!existsSync23(dbPath)) continue;
47222
47317
  let store = null;
47223
47318
  try {
47224
47319
  store = openGraphStore2({ path: dbPath });
@@ -47262,8 +47357,8 @@ async function cmdReport(args2) {
47262
47357
  const outDir = workspacePaths(ROOT).configDir;
47263
47358
  mkdirSync6(outDir, { recursive: true });
47264
47359
  const files = renderReport2(data, { includeFutureVerbs });
47265
- for (const f of files) writeFileSync16(join24(outDir, f.name), f.html, "utf8");
47266
- const indexPath = join24(outDir, "report.html");
47360
+ for (const f of files) writeFileSync16(join25(outDir, f.name), f.html, "utf8");
47361
+ const indexPath = join25(outDir, "report.html");
47267
47362
  console.log(`report \u2192 ${indexPath}`);
47268
47363
  console.log(` ${data.repos.length} repo(s) \xB7 ${files.length} file(s) \xB7 ${data.rollup.nodes.toLocaleString("en-US")} nodes`);
47269
47364
  console.log(` open: file://${indexPath.replace(/\\/g, "/")}`);
@@ -47383,13 +47478,13 @@ function hookRelayCommand(port, path2) {
47383
47478
  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 '{}'`;
47384
47479
  }
47385
47480
  async function installClaudeHooks(port) {
47386
- const { mkdirSync: mkdirSync6, existsSync: existsSync22, readFileSync: readFileSync21, writeFileSync: writeFileSync16 } = await import("node:fs");
47387
- const { join: join25 } = await import("node:path");
47388
- const dir = join25(ROOT, ".claude");
47389
- if (!existsSync22(dir)) mkdirSync6(dir, { recursive: true });
47390
- const file2 = join25(dir, "settings.json");
47481
+ const { mkdirSync: mkdirSync6, existsSync: existsSync23, readFileSync: readFileSync21, writeFileSync: writeFileSync16 } = await import("node:fs");
47482
+ const { join: join26 } = await import("node:path");
47483
+ const dir = join26(ROOT, ".claude");
47484
+ if (!existsSync23(dir)) mkdirSync6(dir, { recursive: true });
47485
+ const file2 = join26(dir, "settings.json");
47391
47486
  let settings = {};
47392
- if (existsSync22(file2)) {
47487
+ if (existsSync23(file2)) {
47393
47488
  try {
47394
47489
  settings = JSON.parse(readFileSync21(file2, "utf8"));
47395
47490
  } catch {
@@ -47440,7 +47535,7 @@ async function installClaudeHooks(port) {
47440
47535
  writeFileSync16(file2, JSON.stringify(settings, null, 2) + "\n", "utf8");
47441
47536
  console.log(`installed Claude Code hooks \u2192 ${file2}`);
47442
47537
  await installClaudeMcpConfig();
47443
- const claudeMd = join25(ROOT, "CLAUDE.md");
47538
+ const claudeMd = join26(ROOT, "CLAUDE.md");
47444
47539
  const recall = writeManagedBlock(claudeMd, { body: RECALL_FIRST_BLOCK });
47445
47540
  if (recall.kind === "collision") {
47446
47541
  console.warn(
@@ -47452,13 +47547,13 @@ async function installClaudeHooks(port) {
47452
47547
  console.log(` endpoint: http://127.0.0.1:${port}/api/hook`);
47453
47548
  }
47454
47549
  async function installClaudeMcpConfig() {
47455
- const { mkdirSync: mkdirSync6, existsSync: existsSync22, readFileSync: readFileSync21, writeFileSync: writeFileSync16 } = await import("node:fs");
47456
- const { join: join25, dirname: dirname8 } = await import("node:path");
47457
- const file2 = join25(ROOT, ".mcp.json");
47458
- const dir = dirname8(file2);
47459
- if (!existsSync22(dir)) mkdirSync6(dir, { recursive: true });
47550
+ const { mkdirSync: mkdirSync6, existsSync: existsSync23, readFileSync: readFileSync21, writeFileSync: writeFileSync16 } = await import("node:fs");
47551
+ const { join: join26, dirname: dirname9 } = await import("node:path");
47552
+ const file2 = join26(ROOT, ".mcp.json");
47553
+ const dir = dirname9(file2);
47554
+ if (!existsSync23(dir)) mkdirSync6(dir, { recursive: true });
47460
47555
  let cfg = {};
47461
- if (existsSync22(file2)) {
47556
+ if (existsSync23(file2)) {
47462
47557
  try {
47463
47558
  cfg = JSON.parse(readFileSync21(file2, "utf8"));
47464
47559
  } catch {
@@ -47474,13 +47569,13 @@ async function installClaudeMcpConfig() {
47474
47569
  console.log(` Tools: errata.search / locate / neighbors / callers_of / what_uses / show / similar`);
47475
47570
  }
47476
47571
  async function installCursorMcpConfig() {
47477
- const { mkdirSync: mkdirSync6, existsSync: existsSync22, readFileSync: readFileSync21, writeFileSync: writeFileSync16 } = await import("node:fs");
47478
- const { join: join25 } = await import("node:path");
47479
- const dir = join25(ROOT, ".cursor");
47480
- if (!existsSync22(dir)) mkdirSync6(dir, { recursive: true });
47481
- const file2 = join25(dir, "mcp.json");
47572
+ const { mkdirSync: mkdirSync6, existsSync: existsSync23, readFileSync: readFileSync21, writeFileSync: writeFileSync16 } = await import("node:fs");
47573
+ const { join: join26 } = await import("node:path");
47574
+ const dir = join26(ROOT, ".cursor");
47575
+ if (!existsSync23(dir)) mkdirSync6(dir, { recursive: true });
47576
+ const file2 = join26(dir, "mcp.json");
47482
47577
  let cfg = {};
47483
- if (existsSync22(file2)) {
47578
+ if (existsSync23(file2)) {
47484
47579
  try {
47485
47580
  cfg = JSON.parse(readFileSync21(file2, "utf8"));
47486
47581
  } catch {
@@ -47498,15 +47593,15 @@ async function installCursorMcpConfig() {
47498
47593
  console.log(` \u26A0\uFE0F reload Cursor (Cmd/Ctrl-Shift-P \u2192 "Reload Window") to pick it up.`);
47499
47594
  }
47500
47595
  async function installCodexHooks(port) {
47501
- const { mkdirSync: mkdirSync6, existsSync: existsSync22, readFileSync: readFileSync21, writeFileSync: writeFileSync16 } = await import("node:fs");
47502
- const { join: join25 } = await import("node:path");
47503
- const dir = join25(ROOT, ".codex");
47504
- if (!existsSync22(dir)) mkdirSync6(dir, { recursive: true });
47505
- const file2 = join25(dir, "config.toml");
47596
+ const { mkdirSync: mkdirSync6, existsSync: existsSync23, readFileSync: readFileSync21, writeFileSync: writeFileSync16 } = await import("node:fs");
47597
+ const { join: join26 } = await import("node:path");
47598
+ const dir = join26(ROOT, ".codex");
47599
+ if (!existsSync23(dir)) mkdirSync6(dir, { recursive: true });
47600
+ const file2 = join26(dir, "config.toml");
47506
47601
  const BEGIN = `# >>> errata hooks (errata-managed)`;
47507
47602
  const END = `# <<< errata hooks`;
47508
47603
  let existing = "";
47509
- if (existsSync22(file2)) {
47604
+ if (existsSync23(file2)) {
47510
47605
  existing = readFileSync21(file2, "utf8");
47511
47606
  const beginIdx = existing.indexOf(BEGIN);
47512
47607
  const endIdx = existing.indexOf(END);
@@ -47799,7 +47894,7 @@ async function cmdDash(args2) {
47799
47894
  await yieldToLoop2();
47800
47895
  try {
47801
47896
  const items = selectDurableMemory(handle2.sharedStore, r.engine.profile);
47802
- const res = bleedRules(join24(r.root, ".claude", "rules"), items);
47897
+ const res = bleedRules(join25(r.root, ".claude", "rules"), items);
47803
47898
  if (res.written || res.pruned) {
47804
47899
  console.log(
47805
47900
  `[rules:${r.entry.name}] ${res.written} collective principle(s) \u2192 .claude/rules` + (res.pruned ? `, ${res.pruned} pruned` : "")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inerrata-corporation/errata",
3
- "version": "2.0.0-dev.47",
3
+ "version": "2.0.0-dev.48",
4
4
  "description": "errata - local-first observation engine for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {