@inerrata-corporation/errata 2.0.0-dev.43 → 2.0.0-dev.45

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.
@@ -15178,6 +15178,13 @@ var init_wire = __esm({
15178
15178
  }
15179
15179
  });
15180
15180
 
15181
+ // ../../packages/shared/src/repo-locator.ts
15182
+ var init_repo_locator = __esm({
15183
+ "../../packages/shared/src/repo-locator.ts"() {
15184
+ "use strict";
15185
+ }
15186
+ });
15187
+
15181
15188
  // ../../packages/shared/src/nlp/canonicalize.ts
15182
15189
  var init_canonicalize = __esm({
15183
15190
  "../../packages/shared/src/nlp/canonicalize.ts"() {
@@ -15212,6 +15219,7 @@ var init_src = __esm({
15212
15219
  init_wire();
15213
15220
  init_edge_rules();
15214
15221
  init_symbol_intent();
15222
+ init_repo_locator();
15215
15223
  init_hash();
15216
15224
  init_error_signature();
15217
15225
  init_canonicalize();
package/errata.mjs CHANGED
@@ -15481,6 +15481,42 @@ var init_wire = __esm({
15481
15481
  }
15482
15482
  });
15483
15483
 
15484
+ // ../../packages/shared/src/repo-locator.ts
15485
+ function normalizeRepoLocator(remoteUrl) {
15486
+ const raw2 = remoteUrl.trim();
15487
+ if (!raw2) return null;
15488
+ let host;
15489
+ let path2;
15490
+ const schemeMatch = /^(?:git\+)?([a-z][a-z0-9+.-]*):\/\//i.exec(raw2);
15491
+ if (schemeMatch) {
15492
+ const scheme = schemeMatch[1].toLowerCase();
15493
+ if (scheme === "file") return null;
15494
+ let u;
15495
+ try {
15496
+ u = new URL(raw2.replace(/^git\+/i, ""));
15497
+ } catch {
15498
+ return null;
15499
+ }
15500
+ host = u.hostname.toLowerCase() + (u.port ? `:${u.port}` : "");
15501
+ path2 = u.pathname;
15502
+ } else {
15503
+ const scp = SCP_LIKE.exec(raw2);
15504
+ if (!scp) return null;
15505
+ host = scp[2].toLowerCase();
15506
+ path2 = scp[3];
15507
+ }
15508
+ path2 = path2.replace(/^\/+/, "").replace(/\/+$/, "").replace(/\.git$/i, "");
15509
+ if (!host || !path2) return null;
15510
+ return `${host}/${path2}`;
15511
+ }
15512
+ var SCP_LIKE;
15513
+ var init_repo_locator = __esm({
15514
+ "../../packages/shared/src/repo-locator.ts"() {
15515
+ "use strict";
15516
+ SCP_LIKE = /^(?:([^@/]+)@)?([^:/@]+\.[^:/@]+):(.+)$/;
15517
+ }
15518
+ });
15519
+
15484
15520
  // ../../packages/shared/src/nlp/canonicalize.ts
15485
15521
  function canonicalize(value) {
15486
15522
  return value.normalize("NFC").trim().toLowerCase().replace(/\s+/g, " ");
@@ -15587,6 +15623,7 @@ __export(src_exports, {
15587
15623
  languageCanonicalId: () => languageCanonicalId,
15588
15624
  normalizeExtractionSource: () => normalizeExtractionSource,
15589
15625
  normalizePredicate: () => normalizePredicate,
15626
+ normalizeRepoLocator: () => normalizeRepoLocator,
15590
15627
  packageCanonicalId: () => packageCanonicalId,
15591
15628
  pagerankEdgeTypes: () => pagerankEdgeTypes,
15592
15629
  parsePackageRef: () => parsePackageRef,
@@ -15612,6 +15649,7 @@ var init_src = __esm({
15612
15649
  init_wire();
15613
15650
  init_edge_rules();
15614
15651
  init_symbol_intent();
15652
+ init_repo_locator();
15615
15653
  init_hash();
15616
15654
  init_error_signature();
15617
15655
  init_canonicalize();
@@ -20893,6 +20931,11 @@ var init_client = __esm({
20893
20931
  async actAs(handle2) {
20894
20932
  return this.json("POST", "/api/gate/act-as", { handle: handle2 });
20895
20933
  }
20934
+ /** Resolve-or-create the org's project for a repo locator (ambient link,
20935
+ * PJ-entity). Requires user identity on the JWT — login-gated like actAs. */
20936
+ async resolveProject(locator, name2) {
20937
+ return this.json("POST", "/api/gate/projects/resolve", name2 ? { locator, name: name2 } : { locator });
20938
+ }
20896
20939
  // ─── ingest ────────────────────────────────────────────────────────
20897
20940
  /** Upload one outbox batch (projected onto the reconciled wire) and fold
20898
20941
  * the per-decision response into flush accounting.
@@ -28352,13 +28395,13 @@ async function Module2(moduleArg = {}) {
28352
28395
  }
28353
28396
  readAsync = /* @__PURE__ */ __name(async (url2) => {
28354
28397
  if (isFileURI(url2)) {
28355
- return new Promise((resolve5, reject) => {
28398
+ return new Promise((resolve6, reject) => {
28356
28399
  var xhr = new XMLHttpRequest();
28357
28400
  xhr.open("GET", url2, true);
28358
28401
  xhr.responseType = "arraybuffer";
28359
28402
  xhr.onload = () => {
28360
28403
  if (xhr.status == 200 || xhr.status == 0 && xhr.response) {
28361
- resolve5(xhr.response);
28404
+ resolve6(xhr.response);
28362
28405
  return;
28363
28406
  }
28364
28407
  reject(xhr.status);
@@ -28554,9 +28597,9 @@ async function Module2(moduleArg = {}) {
28554
28597
  __name(receiveInstantiationResult, "receiveInstantiationResult");
28555
28598
  var info2 = getWasmImports();
28556
28599
  if (Module["instantiateWasm"]) {
28557
- return new Promise((resolve5, reject) => {
28600
+ return new Promise((resolve6, reject) => {
28558
28601
  Module["instantiateWasm"](info2, (mod, inst) => {
28559
- resolve5(receiveInstance(mod, inst));
28602
+ resolve6(receiveInstance(mod, inst));
28560
28603
  });
28561
28604
  });
28562
28605
  }
@@ -29887,8 +29930,8 @@ async function Module2(moduleArg = {}) {
29887
29930
  if (runtimeInitialized) {
29888
29931
  moduleRtn = Module;
29889
29932
  } else {
29890
- moduleRtn = new Promise((resolve5, reject) => {
29891
- readyPromiseResolve = resolve5;
29933
+ moduleRtn = new Promise((resolve6, reject) => {
29934
+ readyPromiseResolve = resolve6;
29892
29935
  readyPromiseReject = reject;
29893
29936
  });
29894
29937
  }
@@ -38216,12 +38259,12 @@ var init_report_render = __esm({
38216
38259
 
38217
38260
  // src/cli.ts
38218
38261
  init_src5();
38219
- import { closeSync as closeSync2, existsSync as existsSync20, openSync as openSync2, readFileSync as readFileSync19, renameSync as renameSync3, statSync as statSync5 } from "node:fs";
38220
- import { join as join23 } from "node:path";
38262
+ import { closeSync as closeSync2, existsSync as existsSync21, openSync as openSync2, readFileSync as readFileSync20, renameSync as renameSync3, statSync as statSync6 } from "node:fs";
38263
+ import { join as join24 } from "node:path";
38221
38264
  import { spawn as spawn3 } from "node:child_process";
38222
38265
 
38223
38266
  // src/daemon.ts
38224
- import { existsSync as existsSync16, writeFileSync as writeFileSync13 } from "node:fs";
38267
+ import { existsSync as existsSync17, writeFileSync as writeFileSync13 } from "node:fs";
38225
38268
 
38226
38269
  // ../../node_modules/.pnpm/@hono+node-server@1.19.11_hono@4.12.8/node_modules/@hono/node-server/dist/index.mjs
38227
38270
  import { createServer as createServerHTTP } from "http";
@@ -38651,7 +38694,7 @@ var responseViaResponseObject = async (res, outgoing, options = {}) => {
38651
38694
  });
38652
38695
  if (!chunk) {
38653
38696
  if (i2 === 1) {
38654
- await new Promise((resolve5) => setTimeout(resolve5));
38697
+ await new Promise((resolve6) => setTimeout(resolve6));
38655
38698
  maxReadCount = 3;
38656
38699
  continue;
38657
38700
  }
@@ -38801,8 +38844,8 @@ init_config();
38801
38844
 
38802
38845
  // src/engine.ts
38803
38846
  import { execFileSync as execFileSync3 } from "node:child_process";
38804
- import { existsSync as existsSync15, statSync as statSync4, appendFileSync as appendFileSync2, readdirSync as readdirSync7, renameSync as renameSync2, readFileSync as readFileSync14, writeFileSync as writeFileSync12 } from "node:fs";
38805
- import { join as join20, relative as relative6, sep as sep4 } from "node:path";
38847
+ import { existsSync as existsSync16, statSync as statSync5, appendFileSync as appendFileSync2, readdirSync as readdirSync7, renameSync as renameSync2, readFileSync as readFileSync15, writeFileSync as writeFileSync12 } from "node:fs";
38848
+ import { join as join21, relative as relative6, sep as sep4 } from "node:path";
38806
38849
 
38807
38850
  // ../../node_modules/.pnpm/chokidar@4.0.3/node_modules/chokidar/esm/index.js
38808
38851
  import { stat as statcb } from "fs";
@@ -39658,7 +39701,7 @@ var NodeFsHandler = class {
39658
39701
  this._addToNodeFs(path2, initialAdd, wh, depth + 1);
39659
39702
  }
39660
39703
  }).on(EV.ERROR, this._boundHandleError);
39661
- return new Promise((resolve5, reject) => {
39704
+ return new Promise((resolve6, reject) => {
39662
39705
  if (!stream)
39663
39706
  return reject();
39664
39707
  stream.once(STR_END, () => {
@@ -39667,7 +39710,7 @@ var NodeFsHandler = class {
39667
39710
  return;
39668
39711
  }
39669
39712
  const wasThrottled = throttler ? throttler.clear() : false;
39670
- resolve5(void 0);
39713
+ resolve6(void 0);
39671
39714
  previous.getChildren().filter((item) => {
39672
39715
  return item !== directory && !current.has(item);
39673
39716
  }).forEach((item) => {
@@ -41481,8 +41524,8 @@ var PassWorker = class {
41481
41524
  this.ensureWorker();
41482
41525
  const id = this.nextId++;
41483
41526
  return this.ready.then(
41484
- () => new Promise((resolve5, reject) => {
41485
- this.pending.set(id, { resolve: resolve5, reject });
41527
+ () => new Promise((resolve6, reject) => {
41528
+ this.pending.set(id, { resolve: resolve6, reject });
41486
41529
  this.worker.postMessage({ id, kind, ...payload !== void 0 ? { payload } : {} });
41487
41530
  })
41488
41531
  );
@@ -41492,12 +41535,12 @@ var PassWorker = class {
41492
41535
  const workerUrl = new URL("./pass-worker.mjs", import.meta.url);
41493
41536
  const worker = new Worker(workerUrl, { workerData: this.init, execArgv: process.execArgv });
41494
41537
  this.worker = worker;
41495
- this.ready = new Promise((resolve5, reject) => {
41538
+ this.ready = new Promise((resolve6, reject) => {
41496
41539
  const onReady = (m) => {
41497
41540
  if (m?.ready) {
41498
41541
  worker.off("message", onReady);
41499
41542
  worker.off("error", onErr);
41500
- resolve5();
41543
+ resolve6();
41501
41544
  }
41502
41545
  };
41503
41546
  const onErr = (err2) => reject(err2);
@@ -41939,7 +41982,7 @@ function startGitSensor(gitDir, onEvent, opts = {}) {
41939
41982
  // src/git-delta.ts
41940
41983
  import { execFile } from "node:child_process";
41941
41984
  function git(repoDir, args2) {
41942
- return new Promise((resolve5, reject) => {
41985
+ return new Promise((resolve6, reject) => {
41943
41986
  execFile(
41944
41987
  "git",
41945
41988
  ["-C", repoDir, ...args2],
@@ -41950,7 +41993,7 @@ function git(repoDir, args2) {
41950
41993
  // git-sensor runs on every commit/checkout.
41951
41994
  windowsHide: true
41952
41995
  },
41953
- (err2, stdout) => err2 ? reject(err2) : resolve5(stdout)
41996
+ (err2, stdout) => err2 ? reject(err2) : resolve6(stdout)
41954
41997
  );
41955
41998
  });
41956
41999
  }
@@ -42338,16 +42381,77 @@ var CausalBuffer = class {
42338
42381
  // src/profile.ts
42339
42382
  init_src2();
42340
42383
  init_paths();
42341
- import { existsSync as existsSync14, readFileSync as readFileSync13, writeFileSync as writeFileSync11 } from "node:fs";
42384
+ import { existsSync as existsSync15, readFileSync as readFileSync14, writeFileSync as writeFileSync11 } from "node:fs";
42342
42385
  import { createHash as createHash12 } from "node:crypto";
42343
- import { join as join19 } from "node:path";
42386
+ import { join as join20 } from "node:path";
42387
+
42388
+ // src/git-remote.ts
42389
+ init_src();
42390
+ import { existsSync as existsSync14, readFileSync as readFileSync13, statSync as statSync4 } from "node:fs";
42391
+ import { isAbsolute as isAbsolute3, join as join19, resolve as resolve5 } from "node:path";
42392
+ function resolveGitDir(root) {
42393
+ const dotGit = join19(root, ".git");
42394
+ try {
42395
+ const st = statSync4(dotGit);
42396
+ if (st.isDirectory()) return dotGit;
42397
+ const m = /^gitdir:\s*(.+?)\s*$/m.exec(readFileSync13(dotGit, "utf8"));
42398
+ if (!m) return null;
42399
+ const dir = m[1];
42400
+ return isAbsolute3(dir) ? dir : resolve5(root, dir);
42401
+ } catch {
42402
+ return null;
42403
+ }
42404
+ }
42405
+ function gitConfigPath(gitDir) {
42406
+ const commondirFile = join19(gitDir, "commondir");
42407
+ if (existsSync14(commondirFile)) {
42408
+ const common = readFileSync13(commondirFile, "utf8").trim();
42409
+ const commonDir = isAbsolute3(common) ? common : resolve5(gitDir, common);
42410
+ return join19(commonDir, "config");
42411
+ }
42412
+ return join19(gitDir, "config");
42413
+ }
42414
+ function readRemotes(root) {
42415
+ const gitDir = resolveGitDir(root);
42416
+ if (!gitDir) return [];
42417
+ const cfgPath = gitConfigPath(gitDir);
42418
+ if (!existsSync14(cfgPath)) return [];
42419
+ let txt;
42420
+ try {
42421
+ txt = readFileSync13(cfgPath, "utf8");
42422
+ } catch {
42423
+ return [];
42424
+ }
42425
+ const out2 = [];
42426
+ const sectionRe = /^\s*\[remote "([^"]+)"\]\s*$([\s\S]*?)(?=^\s*\[|\s*$(?![\s\S]))/gm;
42427
+ for (const m of txt.matchAll(sectionRe)) {
42428
+ const url2 = /^\s*url\s*=\s*(.+?)\s*$/m.exec(m[2])?.[1];
42429
+ if (url2) out2.push({ name: m[1], url: url2 });
42430
+ }
42431
+ return out2;
42432
+ }
42433
+ function detectRepoLocator(root) {
42434
+ const remotes = readRemotes(root);
42435
+ if (remotes.length === 0) return null;
42436
+ const pick2 = remotes.find((r) => r.name === "origin") ?? (remotes.length === 1 ? remotes[0] : null);
42437
+ return pick2 ? normalizeRepoLocator(pick2.url) : null;
42438
+ }
42439
+
42440
+ // src/profile.ts
42344
42441
  function workspaceId(root) {
42345
42442
  return "wp_" + createHash12("sha256").update(root).digest("hex").slice(0, 12);
42346
42443
  }
42444
+ function refreshRepoLocator(root, profile) {
42445
+ const detected = detectRepoLocator(root);
42446
+ if (!detected || detected === profile.repoLocator) return false;
42447
+ profile.repoLocator = detected;
42448
+ saveProfile(root, profile);
42449
+ return true;
42450
+ }
42347
42451
  function loadProfile(root) {
42348
42452
  const p = workspacePaths(root);
42349
- if (!existsSync14(p.workspaceJson)) return null;
42350
- return JSON.parse(readFileSync13(p.workspaceJson, "utf8"));
42453
+ if (!existsSync15(p.workspaceJson)) return null;
42454
+ return JSON.parse(readFileSync14(p.workspaceJson, "utf8"));
42351
42455
  }
42352
42456
  function saveProfile(root, profile) {
42353
42457
  const p = workspacePaths(root);
@@ -42358,10 +42462,12 @@ function autodetectProfile(root) {
42358
42462
  const id = workspaceId(root);
42359
42463
  const name2 = root.split(/[\\/]/).filter(Boolean).pop() ?? "workspace";
42360
42464
  const p = emptyProfile(id, name2);
42361
- const pkgPath = join19(root, "package.json");
42362
- if (existsSync14(pkgPath)) {
42465
+ const locator = detectRepoLocator(root);
42466
+ if (locator) p.repoLocator = locator;
42467
+ const pkgPath = join20(root, "package.json");
42468
+ if (existsSync15(pkgPath)) {
42363
42469
  try {
42364
- const pkg = JSON.parse(readFileSync13(pkgPath, "utf8"));
42470
+ const pkg = JSON.parse(readFileSync14(pkgPath, "utf8"));
42365
42471
  p.languages.push("typescript", "javascript");
42366
42472
  const nodeVer = pkg.engines?.node ?? "node";
42367
42473
  p.stack.push(`node@${nodeVer}`);
@@ -42382,10 +42488,10 @@ function autodetectProfile(root) {
42382
42488
  } catch {
42383
42489
  }
42384
42490
  }
42385
- const pyproject = join19(root, "pyproject.toml");
42386
- if (existsSync14(pyproject)) {
42491
+ const pyproject = join20(root, "pyproject.toml");
42492
+ if (existsSync15(pyproject)) {
42387
42493
  try {
42388
- const txt = readFileSync13(pyproject, "utf8");
42494
+ const txt = readFileSync14(pyproject, "utf8");
42389
42495
  const py = /python\s*=\s*"([^"]+)"/.exec(txt)?.[1];
42390
42496
  p.languages.push("python");
42391
42497
  p.stack.push(`python@${py ?? "3"}`);
@@ -42396,16 +42502,16 @@ function autodetectProfile(root) {
42396
42502
  } catch {
42397
42503
  }
42398
42504
  }
42399
- const reqs = join19(root, "requirements.txt");
42400
- if (existsSync14(reqs)) {
42505
+ const reqs = join20(root, "requirements.txt");
42506
+ if (existsSync15(reqs)) {
42401
42507
  if (!p.languages.includes("python")) p.languages.push("python");
42402
42508
  if (!p.stack.includes("python@3")) p.stack.push("python@3");
42403
42509
  }
42404
- if (existsSync14(join19(root, "go.mod"))) {
42510
+ if (existsSync15(join20(root, "go.mod"))) {
42405
42511
  p.languages.push("go");
42406
42512
  p.stack.push("go");
42407
42513
  }
42408
- if (existsSync14(join19(root, "Cargo.toml"))) {
42514
+ if (existsSync15(join20(root, "Cargo.toml"))) {
42409
42515
  p.languages.push("rust");
42410
42516
  p.stack.push("rust");
42411
42517
  }
@@ -42563,7 +42669,7 @@ function startLoopLagMonitor(thresholdMs = 1e3) {
42563
42669
  }
42564
42670
 
42565
42671
  // src/engine.ts
42566
- var DAEMON_VERSION = true ? "2.0.0-dev.43" : "2.0.0-alpha.0";
42672
+ var DAEMON_VERSION = true ? "2.0.0-dev.45" : "2.0.0-alpha.0";
42567
42673
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
42568
42674
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
42569
42675
  var GIT_OP_MUTE_MS = 4e3;
@@ -42573,7 +42679,7 @@ var TURN_REPLAY_LOOKBACK_MS = 7 * 24 * 60 * 6e4;
42573
42679
  function appendIdentityAudit(path2, record2, line) {
42574
42680
  if (!record2.accepted && record2.score <= 0) return;
42575
42681
  try {
42576
- if (existsSync15(path2) && statSync4(path2).size >= IDENTITY_AUDIT_MAX_BYTES) {
42682
+ if (existsSync16(path2) && statSync5(path2).size >= IDENTITY_AUDIT_MAX_BYTES) {
42577
42683
  renameSync2(path2, `${path2}.1`);
42578
42684
  }
42579
42685
  appendFileSync2(path2, line);
@@ -42583,7 +42689,7 @@ function appendIdentityAudit(path2, record2, line) {
42583
42689
  var yieldToLoop = () => new Promise((r) => setImmediate(r));
42584
42690
  function loadTurnCursors(path2) {
42585
42691
  try {
42586
- return new Map(Object.entries(JSON.parse(readFileSync14(path2, "utf8"))));
42692
+ return new Map(Object.entries(JSON.parse(readFileSync15(path2, "utf8"))));
42587
42693
  } catch {
42588
42694
  return /* @__PURE__ */ new Map();
42589
42695
  }
@@ -42612,7 +42718,7 @@ function gitSourceWatchTargets(root) {
42612
42718
  ["-C", root, "ls-files", "--others", "--ignored", "--exclude-standard", "--directory", "-z"],
42613
42719
  { encoding: "utf8", maxBuffer: 256 * 1024 * 1024, windowsHide: true, stdio: ["ignore", "pipe", "ignore"] }
42614
42720
  );
42615
- ignoredDirs = igOut.split("\0").filter(Boolean).map((d) => d.replace(/\/+$/, "")).filter((d) => !IGNORED_PATH.test(join20(root, d) + sep4));
42721
+ ignoredDirs = igOut.split("\0").filter(Boolean).map((d) => d.replace(/\/+$/, "")).filter((d) => !IGNORED_PATH.test(join21(root, d) + sep4));
42616
42722
  } catch {
42617
42723
  }
42618
42724
  const hasIgnoredChild = (dir) => ignoredDirs.some((ig) => ig.startsWith(dir + "/"));
@@ -42624,19 +42730,19 @@ function gitSourceWatchTargets(root) {
42624
42730
  if (!f.startsWith(prefix)) continue;
42625
42731
  const rest2 = f.slice(prefix.length);
42626
42732
  if (rest2.includes("/")) children.add(dir === "" ? rest2.slice(0, rest2.indexOf("/")) : dir + "/" + rest2.slice(0, rest2.indexOf("/")));
42627
- else targets.add(join20(root, f));
42733
+ else targets.add(join21(root, f));
42628
42734
  }
42629
42735
  for (const c of children) {
42630
- if (IGNORED_PATH.test(join20(root, c) + sep4)) continue;
42736
+ if (IGNORED_PATH.test(join21(root, c) + sep4)) continue;
42631
42737
  if (hasIgnoredChild(c)) addUnder(c);
42632
- else targets.add(join20(root, c));
42738
+ else targets.add(join21(root, c));
42633
42739
  }
42634
42740
  };
42635
42741
  addUnder("");
42636
42742
  if (targets.size > 0) return [...targets];
42637
42743
  } catch {
42638
42744
  }
42639
- return readdirSync7(root, { withFileTypes: true }).filter((e) => e.isDirectory() && !IGNORED_PATH.test(join20(root, String(e.name)) + sep4)).map((e) => join20(root, String(e.name)));
42745
+ return readdirSync7(root, { withFileTypes: true }).filter((e) => e.isDirectory() && !IGNORED_PATH.test(join21(root, String(e.name)) + sep4)).map((e) => join21(root, String(e.name)));
42640
42746
  }
42641
42747
  function createWorkspaceEngine(opts) {
42642
42748
  const paths = workspacePaths(opts.workspaceRoot);
@@ -42647,6 +42753,8 @@ function createWorkspaceEngine(opts) {
42647
42753
  if (!profile) {
42648
42754
  profile = autodetectProfile(opts.workspaceRoot);
42649
42755
  saveProfile(opts.workspaceRoot, profile);
42756
+ } else {
42757
+ refreshRepoLocator(opts.workspaceRoot, profile);
42650
42758
  }
42651
42759
  const store = openGraphStore({ path: paths.castalia });
42652
42760
  const log = openEventLog({ path: paths.eventLog });
@@ -42675,7 +42783,7 @@ function createWorkspaceEngine(opts) {
42675
42783
  if (IGNORED_PATH.test(path2) || IGNORED_NOISE.test(path2)) return;
42676
42784
  let size = 0;
42677
42785
  try {
42678
- size = statSync4(path2).size;
42786
+ size = statSync5(path2).size;
42679
42787
  } catch {
42680
42788
  }
42681
42789
  const base = { ts: Date.now(), kind, workspaceId: profile.id, path: path2, size };
@@ -42788,7 +42896,7 @@ function createWorkspaceEngine(opts) {
42788
42896
  const srcPaths = diff.changedPaths.filter((p) => /\.(ts|tsx|js|jsx|mjs|cjs|py)$/i.test(p));
42789
42897
  let episodeId2;
42790
42898
  if (srcPaths.length > 0) {
42791
- const abs = srcPaths.map((p) => join20(opts.workspaceRoot, p));
42899
+ const abs = srcPaths.map((p) => join21(opts.workspaceRoot, p));
42792
42900
  try {
42793
42901
  const r = await runReindexPass(
42794
42902
  `git-reindex:${profile.name} (${abs.length} files)`,
@@ -42819,8 +42927,8 @@ function createWorkspaceEngine(opts) {
42819
42927
  `[errata] git: ${ev.kind} ${ev.newSha.slice(0, 7)} by ${meta3.authorName} \u2014 ${diff.changedPaths.length} file(s), ${diff.renames.length} rename(s)`
42820
42928
  );
42821
42929
  };
42822
- const gitDir = join20(opts.workspaceRoot, ".git");
42823
- if (existsSync15(gitDir)) {
42930
+ const gitDir = join21(opts.workspaceRoot, ".git");
42931
+ if (existsSync16(gitDir)) {
42824
42932
  stopGit = startGitSensor(gitDir, (ev) => {
42825
42933
  void handleGitEvent(ev);
42826
42934
  });
@@ -42886,10 +42994,10 @@ function createWorkspaceEngine(opts) {
42886
42994
  ...pendingUpdate ? { pendingUpdate } : {}
42887
42995
  });
42888
42996
  doneRender?.();
42889
- const target = join20(opts.workspaceRoot, "AGENTS.md");
42997
+ const target = join21(opts.workspaceRoot, "AGENTS.md");
42890
42998
  writeManagedBlock(target, { body: body2 });
42891
42999
  if (elicit) {
42892
- writePrimingHandles(join20(paths.configDir, "priming-handles.json"), [
43000
+ writePrimingHandles(join21(paths.configDir, "priming-handles.json"), [
42893
43001
  ...snapshot.recentProblems.map((r) => r.node),
42894
43002
  // Resolved-band handles: the ✓ problem AND its Solution are citable
42895
43003
  // (a fix tag on an already-resolved problem no-ops idempotently; the
@@ -43059,7 +43167,7 @@ function createWorkspaceEngine(opts) {
43059
43167
  resultSummary: { exitCode: e.exitCode ?? 1, errorTokens: e.errorTokens }
43060
43168
  });
43061
43169
  };
43062
- const turnCursorPath = join20(paths.configDir, "turn-cursors.json");
43170
+ const turnCursorPath = join21(paths.configDir, "turn-cursors.json");
43063
43171
  const lastTurnUuid = loadTurnCursors(turnCursorPath);
43064
43172
  const sessionLastProblem = /* @__PURE__ */ new Map();
43065
43173
  const sessionThreads = /* @__PURE__ */ new Map();
@@ -43082,7 +43190,7 @@ function createWorkspaceEngine(opts) {
43082
43190
  const t = Date.now();
43083
43191
  let processedTurns = 0;
43084
43192
  const elicit = isEdgeElicitationEnabled();
43085
- const handleMap = elicit ? readPrimingHandles(join20(paths.configDir, "priming-handles.json")) : {};
43193
+ const handleMap = elicit ? readPrimingHandles(join21(paths.configDir, "priming-handles.json")) : {};
43086
43194
  const wsRoot = (opts.workspaceRoot ?? "").replace(/\\/g, "/");
43087
43195
  const toRel = (abs) => {
43088
43196
  const p = abs.replace(/\\/g, "/");
@@ -43711,7 +43819,7 @@ function createWorkspaceEngine(opts) {
43711
43819
  console.log(
43712
43820
  "[errata] sync skipped \u2014 cloud sync consent is off (enable with `errata consent sync on`)"
43713
43821
  );
43714
- const pending = existsSync15(paths.outbox) ? readdirSync7(paths.outbox).filter((f) => f.endsWith(".json")).length : 0;
43822
+ const pending = existsSync16(paths.outbox) ? readdirSync7(paths.outbox).filter((f) => f.endsWith(".json")).length : 0;
43715
43823
  return { uploaded: 0, failed: 0, remaining: pending };
43716
43824
  }
43717
43825
  try {
@@ -43841,7 +43949,7 @@ async function startDaemon(opts) {
43841
43949
  );
43842
43950
  await engine.stop();
43843
43951
  try {
43844
- if (existsSync16(engine.paths.daemonLock)) {
43952
+ if (existsSync17(engine.paths.daemonLock)) {
43845
43953
  }
43846
43954
  } catch {
43847
43955
  }
@@ -43849,25 +43957,25 @@ async function startDaemon(opts) {
43849
43957
  };
43850
43958
  }
43851
43959
  async function listenServer(fetchFn, port) {
43852
- return new Promise((resolve5) => {
43960
+ return new Promise((resolve6) => {
43853
43961
  const server = serve({ fetch: fetchFn, hostname: "127.0.0.1", port }, (info2) => {
43854
- resolve5({ server, port: info2.port });
43962
+ resolve6({ server, port: info2.port });
43855
43963
  });
43856
43964
  });
43857
43965
  }
43858
43966
 
43859
43967
  // src/registry.ts
43860
43968
  init_paths();
43861
- import { existsSync as existsSync17, readFileSync as readFileSync15, writeFileSync as writeFileSync14 } from "node:fs";
43862
- import { join as join21 } from "node:path";
43969
+ import { existsSync as existsSync18, readFileSync as readFileSync16, writeFileSync as writeFileSync14 } from "node:fs";
43970
+ import { join as join22 } from "node:path";
43863
43971
  function registryPath() {
43864
- return process.env["ERRATA_REGISTRY_PATH"] ?? join21(globalDir(), "workspaces.json");
43972
+ return process.env["ERRATA_REGISTRY_PATH"] ?? join22(globalDir(), "workspaces.json");
43865
43973
  }
43866
43974
  function read() {
43867
43975
  const p = registryPath();
43868
- if (!existsSync17(p)) return { version: 1, workspaces: {} };
43976
+ if (!existsSync18(p)) return { version: 1, workspaces: {} };
43869
43977
  try {
43870
- const parsed = JSON.parse(readFileSync15(p, "utf8"));
43978
+ const parsed = JSON.parse(readFileSync16(p, "utf8"));
43871
43979
  return { version: 1, workspaces: parsed.workspaces ?? {} };
43872
43980
  } catch {
43873
43981
  return { version: 1, workspaces: {} };
@@ -43892,7 +44000,7 @@ function pruneMissingWorkspaces() {
43892
44000
  const reg = read();
43893
44001
  const removed = [];
43894
44002
  for (const [id, entry] of Object.entries(reg.workspaces)) {
43895
- if (!existsSync17(entry.path)) {
44003
+ if (!existsSync18(entry.path)) {
43896
44004
  removed.push(entry);
43897
44005
  delete reg.workspaces[id];
43898
44006
  }
@@ -43901,13 +44009,13 @@ function pruneMissingWorkspaces() {
43901
44009
  return removed;
43902
44010
  }
43903
44011
  function workspaceStatus(entry) {
43904
- const missing = !existsSync17(entry.path);
44012
+ const missing = !existsSync18(entry.path);
43905
44013
  const lockPath = workspacePaths(entry.path).daemonLock;
43906
44014
  let running = false;
43907
44015
  let webUiUrl = null;
43908
- if (existsSync17(lockPath)) {
44016
+ if (existsSync18(lockPath)) {
43909
44017
  try {
43910
- const lock = JSON.parse(readFileSync15(lockPath, "utf8"));
44018
+ const lock = JSON.parse(readFileSync16(lockPath, "utf8"));
43911
44019
  if (lock.pid && lock.webUiUrl && pidAlive(lock.pid)) {
43912
44020
  running = true;
43913
44021
  webUiUrl = lock.webUiUrl;
@@ -43935,7 +44043,7 @@ function pidAlive(pid) {
43935
44043
  // src/multi.ts
43936
44044
  init_dist();
43937
44045
  init_src4();
43938
- import { readFileSync as readFileSync18, unlinkSync as unlinkSync3, writeFileSync as writeFileSync15 } from "node:fs";
44046
+ import { readFileSync as readFileSync19, unlinkSync as unlinkSync3, writeFileSync as writeFileSync15 } from "node:fs";
43939
44047
 
43940
44048
  // src/principle-sync.ts
43941
44049
  init_src4();
@@ -43962,8 +44070,8 @@ async function syncPrinciples(store, cloud, opts) {
43962
44070
  init_reconcile();
43963
44071
 
43964
44072
  // src/lockfile-auto.ts
43965
- import { existsSync as existsSync18, readFileSync as readFileSync16 } from "node:fs";
43966
- import { join as join22 } from "node:path";
44073
+ import { existsSync as existsSync19, readFileSync as readFileSync17 } from "node:fs";
44074
+ import { join as join23 } from "node:path";
43967
44075
 
43968
44076
  // src/package-index.ts
43969
44077
  init_src();
@@ -44227,11 +44335,11 @@ function runLockfilePass(opts) {
44227
44335
  { file: "package-lock.json", parse: parsePackageLockJson }
44228
44336
  ];
44229
44337
  for (const c of candidates) {
44230
- const p = join22(opts.root, c.file);
44231
- if (!existsSync18(p)) continue;
44338
+ const p = join23(opts.root, c.file);
44339
+ if (!existsSync19(p)) continue;
44232
44340
  let sbom;
44233
44341
  try {
44234
- sbom = c.parse(readFileSync16(p, "utf8"));
44342
+ sbom = c.parse(readFileSync17(p, "utf8"));
44235
44343
  } catch {
44236
44344
  continue;
44237
44345
  }
@@ -44449,8 +44557,8 @@ var ConsolidateWorker = class {
44449
44557
  this.ensureWorker();
44450
44558
  const id = this.nextId++;
44451
44559
  return this.ready.then(
44452
- () => new Promise((resolve5, reject) => {
44453
- this.pending.set(id, { resolve: resolve5, reject });
44560
+ () => new Promise((resolve6, reject) => {
44561
+ this.pending.set(id, { resolve: resolve6, reject });
44454
44562
  this.worker.postMessage({ ...req, id });
44455
44563
  })
44456
44564
  );
@@ -44460,12 +44568,12 @@ var ConsolidateWorker = class {
44460
44568
  const workerUrl = new URL("./consolidate-worker.mjs", import.meta.url);
44461
44569
  const worker = new Worker2(workerUrl, { workerData: {}, execArgv: process.execArgv });
44462
44570
  this.worker = worker;
44463
- this.ready = new Promise((resolve5, reject) => {
44571
+ this.ready = new Promise((resolve6, reject) => {
44464
44572
  const onReady = (m) => {
44465
44573
  if (m?.ready) {
44466
44574
  worker.off("message", onReady);
44467
44575
  worker.off("error", onErr);
44468
- resolve5();
44576
+ resolve6();
44469
44577
  }
44470
44578
  };
44471
44579
  const onErr = (err2) => {
@@ -44507,7 +44615,7 @@ var ConsolidateWorker = class {
44507
44615
  init_paths();
44508
44616
 
44509
44617
  // src/lock.ts
44510
- import { existsSync as existsSync19, readFileSync as readFileSync17 } from "node:fs";
44618
+ import { existsSync as existsSync20, readFileSync as readFileSync18 } from "node:fs";
44511
44619
  function isProcessAlive(pid) {
44512
44620
  if (!pid || pid <= 0) return false;
44513
44621
  try {
@@ -44518,9 +44626,9 @@ function isProcessAlive(pid) {
44518
44626
  }
44519
44627
  }
44520
44628
  function readDaemonLock(lockPath) {
44521
- if (!existsSync19(lockPath)) return null;
44629
+ if (!existsSync20(lockPath)) return null;
44522
44630
  try {
44523
- const lock = JSON.parse(readFileSync17(lockPath, "utf8"));
44631
+ const lock = JSON.parse(readFileSync18(lockPath, "utf8"));
44524
44632
  return typeof lock.pid === "number" ? lock : null;
44525
44633
  } catch {
44526
44634
  return null;
@@ -44606,19 +44714,43 @@ function startUpdatePoller(opts) {
44606
44714
  };
44607
44715
  }
44608
44716
  function runNpmInstall(channel) {
44609
- return new Promise((resolve5) => {
44717
+ return new Promise((resolve6) => {
44610
44718
  const child = spawn2("npm", ["install", "-g", `${PACKAGE_NAME}@${channel}`], {
44611
44719
  stdio: "inherit",
44612
44720
  shell: true
44613
44721
  });
44614
- child.on("close", (code) => resolve5(code ?? 1));
44615
- child.on("error", () => resolve5(1));
44722
+ child.on("close", (code) => resolve6(code ?? 1));
44723
+ child.on("error", () => resolve6(1));
44616
44724
  });
44617
44725
  }
44618
44726
 
44619
44727
  // src/multi.ts
44620
44728
  init_cloud_endpoint_policy();
44621
44729
  init_cloud_auth();
44730
+
44731
+ // src/project-link.ts
44732
+ async function ensureProjectLink(root, profile, client) {
44733
+ const locator = profile.repoLocator;
44734
+ if (!locator) return { linked: false, reason: "no-locator" };
44735
+ if (profile.projectId && profile.projectLocator === locator) {
44736
+ return { linked: false, reason: "already-linked" };
44737
+ }
44738
+ try {
44739
+ const res = await client.resolveProject(locator, profile.name);
44740
+ profile.projectId = res.project.id;
44741
+ profile.projectLocator = locator;
44742
+ saveProfile(root, profile);
44743
+ return { linked: true, projectId: res.project.id, created: res.created };
44744
+ } catch (err2) {
44745
+ return {
44746
+ linked: false,
44747
+ reason: "error",
44748
+ detail: err2 instanceof Error ? err2.message : String(err2)
44749
+ };
44750
+ }
44751
+ }
44752
+
44753
+ // src/multi.ts
44622
44754
  function normPath(p) {
44623
44755
  return p.replace(/\\/g, "/").replace(/\/+$/, "").toLowerCase();
44624
44756
  }
@@ -44766,6 +44898,7 @@ async function startMultiDaemon(opts = {}) {
44766
44898
  return { attached: false, id: null, reason: err2 instanceof Error ? err2.message : "build-failed" };
44767
44899
  }
44768
44900
  records.push(rec);
44901
+ void ambientLinkAll();
44769
44902
  app.route(`/ws/${rec.id}`, rec.webApp);
44770
44903
  try {
44771
44904
  writeFileSync15(
@@ -44972,10 +45105,24 @@ async function startMultiDaemon(opts = {}) {
44972
45105
  if (opts.reindexOnStart !== false && records.length > 0) {
44973
45106
  void reindexAll({ skipEmbed: opts.skipEmbed ?? true });
44974
45107
  }
45108
+ const ambientLinkAll = async () => {
45109
+ const c = loadConfig();
45110
+ if (!c.consent.sync || !hasCloudCredential(c)) return;
45111
+ const client = cloudNow();
45112
+ for (const r of records) {
45113
+ const out2 = await ensureProjectLink(r.root, r.engine.profile, client);
45114
+ if (out2.linked) {
45115
+ console.log(
45116
+ `[errata] linked ${r.engine.profile.name} \u2192 project ${out2.projectId}${out2.created ? " (created)" : ""}`
45117
+ );
45118
+ }
45119
+ }
45120
+ };
45121
+ void ambientLinkAll();
44975
45122
  const packageAutoAll = async () => {
44976
45123
  const out2 = /* @__PURE__ */ new Map();
44977
45124
  for (const r of records) {
44978
- await new Promise((resolve5) => setImmediate(resolve5));
45125
+ await new Promise((resolve6) => setImmediate(resolve6));
44979
45126
  const done = markPass(`package-index:${r.entry.name}`);
44980
45127
  try {
44981
45128
  out2.set(
@@ -45045,7 +45192,10 @@ async function startMultiDaemon(opts = {}) {
45045
45192
  ts,
45046
45193
  workspaces: fileBacked.map((r) => ({
45047
45194
  recordId: r.id,
45048
- workspaceId: r.engine.profile.id,
45195
+ // Repo-keyed when linked: two checkouts of one repo are ONE
45196
+ // project in observedInProjects, not two independent
45197
+ // observations (PJ-local — the Q9 independence gate).
45198
+ workspaceId: r.engine.profile.repoLocator ?? r.engine.profile.id,
45049
45199
  castaliaPath: r.engine.paths.castalia
45050
45200
  }))
45051
45201
  });
@@ -45059,7 +45209,13 @@ async function startMultiDaemon(opts = {}) {
45059
45209
  for (const r of inlineRecords) {
45060
45210
  const done = markPass(`percolate-inline:${r.entry.name}`);
45061
45211
  try {
45062
- out2.set(r.id, percolate(r.engine.store, sharedStore, { workspaceId: r.engine.profile.id, ts }));
45212
+ out2.set(
45213
+ r.id,
45214
+ percolate(r.engine.store, sharedStore, {
45215
+ workspaceId: r.engine.profile.repoLocator ?? r.engine.profile.id,
45216
+ ts
45217
+ })
45218
+ );
45063
45219
  } catch (err2) {
45064
45220
  console.warn(
45065
45221
  `[errata] percolate failed for ${r.entry.name}: ${err2 instanceof Error ? err2.message : err2}`
@@ -45263,7 +45419,7 @@ async function startMultiDaemon(opts = {}) {
45263
45419
  },
45264
45420
  async stop() {
45265
45421
  try {
45266
- const cur = readFileSync18(lockPath, "utf8");
45422
+ const cur = readFileSync19(lockPath, "utf8");
45267
45423
  if (JSON.parse(cur).pid === process.pid) unlinkSync3(lockPath);
45268
45424
  } catch {
45269
45425
  }
@@ -45461,7 +45617,7 @@ async function loginOAuthLoopback(opts) {
45461
45617
  const state = randomState();
45462
45618
  const scope = opts.scope ?? DEFAULT_OAUTH_SCOPE;
45463
45619
  const { code, redirectUri, clientId } = await new Promise(
45464
- (resolve5, reject) => {
45620
+ (resolve6, reject) => {
45465
45621
  const server = createServer((req, res) => {
45466
45622
  const u = new URL(req.url ?? "/", "http://127.0.0.1");
45467
45623
  if (u.pathname !== "/callback") {
@@ -45484,7 +45640,7 @@ async function loginOAuthLoopback(opts) {
45484
45640
  res.writeHead(200, { "content-type": "text/html" });
45485
45641
  res.end("<html><body>inErrata: you're logged in. You can close this tab.</body></html>");
45486
45642
  server.close();
45487
- resolve5({ code: code2, redirectUri: `http://127.0.0.1:${port}/callback`, clientId: activeClientId });
45643
+ resolve6({ code: code2, redirectUri: `http://127.0.0.1:${port}/callback`, clientId: activeClientId });
45488
45644
  });
45489
45645
  let activeClientId = oauthClientId();
45490
45646
  server.on("error", reject);
@@ -45824,27 +45980,28 @@ async function cmdInit() {
45824
45980
  console.log(`initialized errata workspace:`);
45825
45981
  console.log(` id: ${profile.id}`);
45826
45982
  console.log(` name: ${profile.name}`);
45983
+ console.log(` repo: ${profile.repoLocator ?? "(no git remote detected)"}`);
45827
45984
  console.log(` stack: ${profile.stack.join(", ") || "(none)"}`);
45828
45985
  console.log(` languages: ${profile.languages.join(", ") || "(none)"}`);
45829
45986
  }
45830
45987
  if (!skipHooks) {
45831
45988
  console.log("");
45832
45989
  console.log("installing harness hooks...");
45833
- const { existsSync: existsSync21 } = await import("node:fs");
45834
- const { join: join24 } = await import("node:path");
45990
+ const { existsSync: existsSync22 } = await import("node:fs");
45991
+ const { join: join25 } = await import("node:path");
45835
45992
  try {
45836
45993
  await installClaudeHooks(port);
45837
45994
  } catch (err2) {
45838
45995
  console.warn(` \u26A0\uFE0F Claude hook install failed: ${err2 instanceof Error ? err2.message : err2}`);
45839
45996
  }
45840
- if (existsSync21(join24(ROOT, ".cursor"))) {
45997
+ if (existsSync22(join25(ROOT, ".cursor"))) {
45841
45998
  try {
45842
45999
  await installCursorMcpConfig();
45843
46000
  } catch (err2) {
45844
46001
  console.warn(` \u26A0\uFE0F Cursor MCP config failed: ${err2 instanceof Error ? err2.message : err2}`);
45845
46002
  }
45846
46003
  }
45847
- if (existsSync21(join24(ROOT, ".codex"))) {
46004
+ if (existsSync22(join25(ROOT, ".codex"))) {
45848
46005
  try {
45849
46006
  await installCodexHooks(port);
45850
46007
  } catch (err2) {
@@ -45958,11 +46115,13 @@ async function cmdStatus() {
45958
46115
  console.log(` version: ${DAEMON_VERSION} (update channel: ${cfg.updateChannel})`);
45959
46116
  console.log(` workspace: ${profile ? `${profile.name} (${profile.id})` : "(not initialized)"}`);
45960
46117
  if (profile) {
46118
+ const link = profile.projectId ? ` \u2192 project ${profile.projectId.slice(0, 8)}` : " (unlinked)";
46119
+ console.log(` repo: ${profile.repoLocator ? `${profile.repoLocator}${link}` : "(no git remote \u2014 unlinked)"}`);
45961
46120
  console.log(` stack: ${profile.stack.join(", ") || "(none)"}`);
45962
46121
  console.log(` languages: ${profile.languages.join(", ") || "(none)"}`);
45963
46122
  }
45964
- console.log(` graph db: ${existsSync20(paths.castalia) ? "yes" : "no"} (${paths.castalia})`);
45965
- console.log(` event log: ${existsSync20(paths.eventLog) ? "yes" : "no"} (${paths.eventLog})`);
46123
+ console.log(` graph db: ${existsSync21(paths.castalia) ? "yes" : "no"} (${paths.castalia})`);
46124
+ console.log(` event log: ${existsSync21(paths.eventLog) ? "yes" : "no"} (${paths.eventLog})`);
45966
46125
  const lockPath = globalDaemonLock();
45967
46126
  const running = isDaemonAlive(lockPath) ? readDaemonLock(lockPath) : null;
45968
46127
  console.log(
@@ -46161,12 +46320,31 @@ async function cmdLoginOAuth(cfg) {
46161
46320
  nextCfg.email = me.handle;
46162
46321
  saveConfig(nextCfg);
46163
46322
  console.log(`logged in as ${me.handle} (${me.tier}) \u2014 tokens stored at ${globalConfigPath()}`);
46323
+ await linkRegisteredWorkspaces(nextCfg);
46164
46324
  } catch (err2) {
46165
46325
  console.error(`signed in, but identity check failed: ${err2 instanceof Error ? err2.message : err2}`);
46166
46326
  console.error(` credentials were not stored; try again or paste a key: errata login --token <key>`);
46167
46327
  process.exitCode = 1;
46168
46328
  }
46169
46329
  }
46330
+ async function linkRegisteredWorkspaces(cfg) {
46331
+ if (!cfg.consent.sync) return;
46332
+ const client = authedCloudClient(cfg);
46333
+ for (const w of listWorkspaces()) {
46334
+ try {
46335
+ const profile = loadProfile(w.path);
46336
+ if (!profile) continue;
46337
+ refreshRepoLocator(w.path, profile);
46338
+ const out2 = await ensureProjectLink(w.path, profile, client);
46339
+ if (out2.linked) {
46340
+ console.log(
46341
+ ` linked ${profile.name} \u2192 project ${out2.projectId}${out2.created ? " (created)" : ""}`
46342
+ );
46343
+ }
46344
+ } catch {
46345
+ }
46346
+ }
46347
+ }
46170
46348
  async function cmdLogin() {
46171
46349
  const cfg = loadConfig();
46172
46350
  const flags2 = parseFlags(rest);
@@ -46280,11 +46458,11 @@ async function cmdUse(args2) {
46280
46458
  }
46281
46459
  async function cmdReview() {
46282
46460
  const paths = workspacePaths(ROOT);
46283
- if (!existsSync20(paths.reviewQueue)) {
46461
+ if (!existsSync21(paths.reviewQueue)) {
46284
46462
  console.log("(review queue empty)");
46285
46463
  return;
46286
46464
  }
46287
- const queue = JSON.parse(readFileSync19(paths.reviewQueue, "utf8"));
46465
+ const queue = JSON.parse(readFileSync20(paths.reviewQueue, "utf8"));
46288
46466
  if (queue.length === 0) {
46289
46467
  console.log("(review queue empty)");
46290
46468
  return;
@@ -46914,7 +47092,7 @@ async function gatherRepo(store, ws) {
46914
47092
  };
46915
47093
  }
46916
47094
  async function gatherReportData(generatedAt) {
46917
- const { existsSync: existsSync21 } = await import("node:fs");
47095
+ const { existsSync: existsSync22 } = await import("node:fs");
46918
47096
  const { openGraphStore: openGraphStore2 } = await Promise.resolve().then(() => (init_src4(), src_exports2));
46919
47097
  const cfg = loadConfig();
46920
47098
  const outbound = cfg.consent.sync ? "auto" : "off";
@@ -46922,7 +47100,7 @@ async function gatherReportData(generatedAt) {
46922
47100
  for (const ws of listWorkspaces()) {
46923
47101
  if (ws.missing) continue;
46924
47102
  const dbPath = workspacePaths(ws.path).castalia;
46925
- if (!existsSync21(dbPath)) continue;
47103
+ if (!existsSync22(dbPath)) continue;
46926
47104
  let store = null;
46927
47105
  try {
46928
47106
  store = openGraphStore2({ path: dbPath });
@@ -46966,8 +47144,8 @@ async function cmdReport(args2) {
46966
47144
  const outDir = workspacePaths(ROOT).configDir;
46967
47145
  mkdirSync6(outDir, { recursive: true });
46968
47146
  const files = renderReport2(data, { includeFutureVerbs });
46969
- for (const f of files) writeFileSync16(join23(outDir, f.name), f.html, "utf8");
46970
- const indexPath = join23(outDir, "report.html");
47147
+ for (const f of files) writeFileSync16(join24(outDir, f.name), f.html, "utf8");
47148
+ const indexPath = join24(outDir, "report.html");
46971
47149
  console.log(`report \u2192 ${indexPath}`);
46972
47150
  console.log(` ${data.repos.length} repo(s) \xB7 ${files.length} file(s) \xB7 ${data.rollup.nodes.toLocaleString("en-US")} nodes`);
46973
47151
  console.log(` open: file://${indexPath.replace(/\\/g, "/")}`);
@@ -47019,7 +47197,7 @@ function spawnDaemonDetached() {
47019
47197
  try {
47020
47198
  const logPath = daemonLogPath();
47021
47199
  try {
47022
- if (statSync5(logPath).size > 5 * 1024 * 1024) renameSync3(logPath, `${logPath}.1`);
47200
+ if (statSync6(logPath).size > 5 * 1024 * 1024) renameSync3(logPath, `${logPath}.1`);
47023
47201
  } catch {
47024
47202
  }
47025
47203
  out2 = openSync2(logPath, "a");
@@ -47087,15 +47265,15 @@ function hookRelayCommand(port, path2) {
47087
47265
  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 '{}'`;
47088
47266
  }
47089
47267
  async function installClaudeHooks(port) {
47090
- const { mkdirSync: mkdirSync6, existsSync: existsSync21, readFileSync: readFileSync20, writeFileSync: writeFileSync16 } = await import("node:fs");
47091
- const { join: join24 } = await import("node:path");
47092
- const dir = join24(ROOT, ".claude");
47093
- if (!existsSync21(dir)) mkdirSync6(dir, { recursive: true });
47094
- const file2 = join24(dir, "settings.json");
47268
+ const { mkdirSync: mkdirSync6, existsSync: existsSync22, readFileSync: readFileSync21, writeFileSync: writeFileSync16 } = await import("node:fs");
47269
+ const { join: join25 } = await import("node:path");
47270
+ const dir = join25(ROOT, ".claude");
47271
+ if (!existsSync22(dir)) mkdirSync6(dir, { recursive: true });
47272
+ const file2 = join25(dir, "settings.json");
47095
47273
  let settings = {};
47096
- if (existsSync21(file2)) {
47274
+ if (existsSync22(file2)) {
47097
47275
  try {
47098
- settings = JSON.parse(readFileSync20(file2, "utf8"));
47276
+ settings = JSON.parse(readFileSync21(file2, "utf8"));
47099
47277
  } catch {
47100
47278
  console.error(`refusing to overwrite invalid JSON at ${file2}`);
47101
47279
  process.exit(2);
@@ -47144,7 +47322,7 @@ async function installClaudeHooks(port) {
47144
47322
  writeFileSync16(file2, JSON.stringify(settings, null, 2) + "\n", "utf8");
47145
47323
  console.log(`installed Claude Code hooks \u2192 ${file2}`);
47146
47324
  await installClaudeMcpConfig();
47147
- const claudeMd = join24(ROOT, "CLAUDE.md");
47325
+ const claudeMd = join25(ROOT, "CLAUDE.md");
47148
47326
  const recall = writeManagedBlock(claudeMd, { body: RECALL_FIRST_BLOCK });
47149
47327
  if (recall.kind === "collision") {
47150
47328
  console.warn(
@@ -47156,15 +47334,15 @@ async function installClaudeHooks(port) {
47156
47334
  console.log(` endpoint: http://127.0.0.1:${port}/api/hook`);
47157
47335
  }
47158
47336
  async function installClaudeMcpConfig() {
47159
- const { mkdirSync: mkdirSync6, existsSync: existsSync21, readFileSync: readFileSync20, writeFileSync: writeFileSync16 } = await import("node:fs");
47160
- const { join: join24, dirname: dirname8 } = await import("node:path");
47161
- const file2 = join24(ROOT, ".mcp.json");
47337
+ const { mkdirSync: mkdirSync6, existsSync: existsSync22, readFileSync: readFileSync21, writeFileSync: writeFileSync16 } = await import("node:fs");
47338
+ const { join: join25, dirname: dirname8 } = await import("node:path");
47339
+ const file2 = join25(ROOT, ".mcp.json");
47162
47340
  const dir = dirname8(file2);
47163
- if (!existsSync21(dir)) mkdirSync6(dir, { recursive: true });
47341
+ if (!existsSync22(dir)) mkdirSync6(dir, { recursive: true });
47164
47342
  let cfg = {};
47165
- if (existsSync21(file2)) {
47343
+ if (existsSync22(file2)) {
47166
47344
  try {
47167
- cfg = JSON.parse(readFileSync20(file2, "utf8"));
47345
+ cfg = JSON.parse(readFileSync21(file2, "utf8"));
47168
47346
  } catch {
47169
47347
  console.error(`refusing to overwrite invalid JSON at ${file2}`);
47170
47348
  process.exit(2);
@@ -47178,15 +47356,15 @@ async function installClaudeMcpConfig() {
47178
47356
  console.log(` Tools: errata.search / locate / neighbors / callers_of / what_uses / show / similar`);
47179
47357
  }
47180
47358
  async function installCursorMcpConfig() {
47181
- const { mkdirSync: mkdirSync6, existsSync: existsSync21, readFileSync: readFileSync20, writeFileSync: writeFileSync16 } = await import("node:fs");
47182
- const { join: join24 } = await import("node:path");
47183
- const dir = join24(ROOT, ".cursor");
47184
- if (!existsSync21(dir)) mkdirSync6(dir, { recursive: true });
47185
- const file2 = join24(dir, "mcp.json");
47359
+ const { mkdirSync: mkdirSync6, existsSync: existsSync22, readFileSync: readFileSync21, writeFileSync: writeFileSync16 } = await import("node:fs");
47360
+ const { join: join25 } = await import("node:path");
47361
+ const dir = join25(ROOT, ".cursor");
47362
+ if (!existsSync22(dir)) mkdirSync6(dir, { recursive: true });
47363
+ const file2 = join25(dir, "mcp.json");
47186
47364
  let cfg = {};
47187
- if (existsSync21(file2)) {
47365
+ if (existsSync22(file2)) {
47188
47366
  try {
47189
- cfg = JSON.parse(readFileSync20(file2, "utf8"));
47367
+ cfg = JSON.parse(readFileSync21(file2, "utf8"));
47190
47368
  } catch {
47191
47369
  console.error(`refusing to overwrite invalid JSON at ${file2}`);
47192
47370
  process.exit(2);
@@ -47202,16 +47380,16 @@ async function installCursorMcpConfig() {
47202
47380
  console.log(` \u26A0\uFE0F reload Cursor (Cmd/Ctrl-Shift-P \u2192 "Reload Window") to pick it up.`);
47203
47381
  }
47204
47382
  async function installCodexHooks(port) {
47205
- const { mkdirSync: mkdirSync6, existsSync: existsSync21, readFileSync: readFileSync20, writeFileSync: writeFileSync16 } = await import("node:fs");
47206
- const { join: join24 } = await import("node:path");
47207
- const dir = join24(ROOT, ".codex");
47208
- if (!existsSync21(dir)) mkdirSync6(dir, { recursive: true });
47209
- const file2 = join24(dir, "config.toml");
47383
+ const { mkdirSync: mkdirSync6, existsSync: existsSync22, readFileSync: readFileSync21, writeFileSync: writeFileSync16 } = await import("node:fs");
47384
+ const { join: join25 } = await import("node:path");
47385
+ const dir = join25(ROOT, ".codex");
47386
+ if (!existsSync22(dir)) mkdirSync6(dir, { recursive: true });
47387
+ const file2 = join25(dir, "config.toml");
47210
47388
  const BEGIN = `# >>> errata hooks (errata-managed)`;
47211
47389
  const END = `# <<< errata hooks`;
47212
47390
  let existing = "";
47213
- if (existsSync21(file2)) {
47214
- existing = readFileSync20(file2, "utf8");
47391
+ if (existsSync22(file2)) {
47392
+ existing = readFileSync21(file2, "utf8");
47215
47393
  const beginIdx = existing.indexOf(BEGIN);
47216
47394
  const endIdx = existing.indexOf(END);
47217
47395
  if (beginIdx >= 0 && endIdx > beginIdx) {
@@ -47428,7 +47606,7 @@ async function cmdDash(args2) {
47428
47606
  const hotspotScanMark = /* @__PURE__ */ new Map();
47429
47607
  const HOTSPOT_FANIN = 20;
47430
47608
  const runNightlyPass = async () => {
47431
- const yieldToLoop2 = () => new Promise((resolve5) => setImmediate(resolve5));
47609
+ const yieldToLoop2 = () => new Promise((resolve6) => setImmediate(resolve6));
47432
47610
  const fullReclusterPass = nightlyCount++ % FULL_RECLUSTER_EVERY === 0;
47433
47611
  const m = await handle2.nightlyAll();
47434
47612
  let skillsLearned = 0;
@@ -47503,7 +47681,7 @@ async function cmdDash(args2) {
47503
47681
  await yieldToLoop2();
47504
47682
  try {
47505
47683
  const items = selectDurableMemory(handle2.sharedStore, r.engine.profile);
47506
- const res = bleedRules(join23(r.root, ".claude", "rules"), items);
47684
+ const res = bleedRules(join24(r.root, ".claude", "rules"), items);
47507
47685
  if (res.written || res.pruned) {
47508
47686
  console.log(
47509
47687
  `[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.43",
3
+ "version": "2.0.0-dev.45",
4
4
  "description": "errata - local-first observation engine for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {
package/pass-worker.mjs CHANGED
@@ -15024,6 +15024,13 @@ var init_wire = __esm({
15024
15024
  }
15025
15025
  });
15026
15026
 
15027
+ // ../../packages/shared/src/repo-locator.ts
15028
+ var init_repo_locator = __esm({
15029
+ "../../packages/shared/src/repo-locator.ts"() {
15030
+ "use strict";
15031
+ }
15032
+ });
15033
+
15027
15034
  // ../../packages/shared/src/nlp/canonicalize.ts
15028
15035
  var init_canonicalize = __esm({
15029
15036
  "../../packages/shared/src/nlp/canonicalize.ts"() {
@@ -15048,6 +15055,7 @@ var init_src = __esm({
15048
15055
  init_wire();
15049
15056
  init_edge_rules();
15050
15057
  init_symbol_intent();
15058
+ init_repo_locator();
15051
15059
  init_hash();
15052
15060
  init_error_signature();
15053
15061
  init_canonicalize();