@inerrata-corporation/errata 2.0.14-dev.3125 → 2.0.14-dev.3126

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 +65 -27
  2. package/package.json +1 -1
package/errata.mjs CHANGED
@@ -81027,7 +81027,7 @@ function createWatchBreaker(deps) {
81027
81027
  }
81028
81028
 
81029
81029
  // src/engine.ts
81030
- var DAEMON_VERSION = true ? "2.0.14-dev.3125" : "2.0.0-alpha.0";
81030
+ var DAEMON_VERSION = true ? "2.0.14-dev.3126" : "2.0.0-alpha.0";
81031
81031
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
81032
81032
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
81033
81033
  var GIT_OP_MUTE_MS = 4e3;
@@ -84825,12 +84825,12 @@ function startUpdatePoller(opts) {
84825
84825
  const check2 = opts.check ?? (() => checkForUpdate(opts.channel));
84826
84826
  const base = opts.intervalMs ?? POLL_INTERVAL_MS[opts.channel];
84827
84827
  let pending = null;
84828
- let inFlight = false;
84828
+ let inFlight2 = false;
84829
84829
  let timer = null;
84830
84830
  let stopped = false;
84831
84831
  const runOnce = async () => {
84832
- if (inFlight) return;
84833
- inFlight = true;
84832
+ if (inFlight2) return;
84833
+ inFlight2 = true;
84834
84834
  try {
84835
84835
  const status = await check2();
84836
84836
  if (status.latest === null) return;
@@ -84840,7 +84840,7 @@ function startUpdatePoller(opts) {
84840
84840
  if (changed) opts.onChange?.(pending);
84841
84841
  } catch {
84842
84842
  } finally {
84843
- inFlight = false;
84843
+ inFlight2 = false;
84844
84844
  }
84845
84845
  };
84846
84846
  const schedule = () => {
@@ -85409,7 +85409,31 @@ import { extname as extname3 } from "node:path";
85409
85409
  init_profile2();
85410
85410
  var exec = promisify2(execFile4);
85411
85411
  var KINDS = { function: "Function", class: "Class", method: "Method", interface: "Interface", const: "Const", enum: "Enum", typealias: "TypeAlias", namespace: "Namespace", property: "Property" };
85412
+ var inFlight = /* @__PURE__ */ new Map();
85412
85413
  async function syncHistoryRevision(opts) {
85414
+ const current = inFlight.get(opts.root);
85415
+ if (current) return current;
85416
+ const work = (async () => {
85417
+ const started2 = Date.now();
85418
+ let changed = 0, remaining = false;
85419
+ const pages = Math.min(20, Math.max(1, opts.maxPages ?? 10));
85420
+ for (let i2 = 0; i2 < pages; i2++) {
85421
+ const result = await syncHistoryRevisionPage(opts);
85422
+ changed += result.changed;
85423
+ remaining = result.remaining;
85424
+ if (!remaining || Date.now() - started2 >= (opts.budgetMs ?? 45e3)) break;
85425
+ await new Promise((resolve7) => setImmediate(resolve7));
85426
+ }
85427
+ return { changed, remaining };
85428
+ })();
85429
+ inFlight.set(opts.root, work);
85430
+ try {
85431
+ return await work;
85432
+ } finally {
85433
+ if (inFlight.get(opts.root) === work) inFlight.delete(opts.root);
85434
+ }
85435
+ }
85436
+ async function syncHistoryRevisionPage(opts) {
85413
85437
  const { root, profile, store, cloud, salt } = opts;
85414
85438
  if (!profile.projectId) return { changed: 0, remaining: false };
85415
85439
  const projectId = profile.projectId;
@@ -85419,7 +85443,8 @@ async function syncHistoryRevision(opts) {
85419
85443
  const oldCursor = profile.historyRevisionCursor;
85420
85444
  const same = oldCursor?.atCommit === atCommit;
85421
85445
  if (same && oldCursor.complete && Date.now() - oldCursor.updatedAt < 60 * 6e4) return { changed: 0, remaining: false };
85422
- const after = same && !oldCursor.complete ? oldCursor.after : void 0;
85446
+ const after = oldCursor && !oldCursor.complete ? oldCursor.after : void 0;
85447
+ const sweepCommit = after ? oldCursor.atCommit : atCommit;
85423
85448
  const page = await cloud.getHistoryOccurrences(projectId, atCommit, after);
85424
85449
  if (!Array.isArray(page.occurrences) || page.occurrences.length > 50 || page.occurrences.some((o, i2) => o.occurrenceId <= (page.occurrences[i2 - 1]?.occurrenceId ?? after ?? "")) || page.cursor !== null && page.cursor !== page.occurrences.at(-1)?.occurrenceId) throw new Error("invalid history occurrence page");
85425
85450
  const parents = (await git3(["rev-list", "--parents", "--max-count=8192", atCommit])).trim().split("\n").filter(Boolean).map((row) => {
@@ -85475,7 +85500,7 @@ async function syncHistoryRevision(opts) {
85475
85500
  }
85476
85501
  const response = page.occurrences.length ? await cloud.reconcileHistory(projectId, { atCommit, parents, observations }) : { atCommit, receipts: [] };
85477
85502
  if (response.atCommit !== atCommit || response.receipts.length !== page.occurrences.length || new Set(response.receipts.map((r) => r.occurrenceId)).size !== response.receipts.length || response.receipts.some((r) => r.atCommit !== atCommit || !observations.some((o) => o.occurrenceId === r.occurrenceId))) throw new Error("incomplete history reconciliation response");
85478
- if ((await git3(["rev-parse", "--verify", "HEAD"])).trim() !== atCommit) return { changed: 0, remaining: true };
85503
+ const headChanged = (await git3(["rev-parse", "--verify", "HEAD"])).trim() !== atCommit;
85479
85504
  let changed = 0;
85480
85505
  for (const occurrence of page.occurrences) {
85481
85506
  const node2 = store.getNode(occurrence.canonicalId) ?? (occurrence.nodeId ? store.getNode(occurrence.nodeId) : null);
@@ -85491,9 +85516,9 @@ async function syncHistoryRevision(opts) {
85491
85516
  } } });
85492
85517
  changed++;
85493
85518
  }
85494
- profile.historyRevisionCursor = { atCommit, ...page.cursor ? { after: page.cursor } : {}, complete: page.cursor === null, updatedAt: Date.now() };
85519
+ profile.historyRevisionCursor = { atCommit: sweepCommit, ...page.cursor ? { after: page.cursor } : {}, complete: page.cursor === null, updatedAt: Date.now() };
85495
85520
  (opts.save ?? ((p) => saveProfile(root, p)))(profile);
85496
- return { changed, remaining: page.cursor !== null };
85521
+ return { changed, remaining: page.cursor !== null || headChanged || sweepCommit !== atCommit };
85497
85522
  }
85498
85523
 
85499
85524
  // src/project-history.ts
@@ -88054,6 +88079,8 @@ async function startMultiDaemon(opts = {}) {
88054
88079
  // eslint-disable-next-line no-console
88055
88080
  log: (line) => console.log(line)
88056
88081
  });
88082
+ const revisionBacklog = /* @__PURE__ */ new Set();
88083
+ const lastAnchorPull = /* @__PURE__ */ new Map();
88057
88084
  const pullProjectAnchors = async (r, client, salt) => {
88058
88085
  const donePass = markPass(`anchor-pull:${r.engine.profile.name}`);
88059
88086
  const beforeCorrections = r.engine.profile.projectHistoryCorrectionCursor ?? 0;
@@ -88070,6 +88097,8 @@ async function startMultiDaemon(opts = {}) {
88070
88097
  }
88071
88098
  try {
88072
88099
  const revision = await syncHistoryRevision({ root: r.root, profile: r.engine.profile, store: r.engine.store, cloud: client, salt });
88100
+ if (revision.remaining) revisionBacklog.add(r.root);
88101
+ else revisionBacklog.delete(r.root);
88073
88102
  if (revision.changed) r.engine.markContextDirty();
88074
88103
  } catch (err2) {
88075
88104
  console.warn(`[errata] history revision reconciliation failed for ${r.engine.profile.name}: ${err2 instanceof Error ? err2.message : String(err2)}`);
@@ -88086,30 +88115,39 @@ async function startMultiDaemon(opts = {}) {
88086
88115
  }
88087
88116
  };
88088
88117
  const ANCHOR_PULL_INTERVAL_MS = 10 * 60 * 1e3;
88118
+ let anchorPullRunning = false;
88089
88119
  const anchorPullAll = async () => {
88090
- const c = loadConfig();
88091
- if (registryCorrupt()) return;
88092
- for (const r of records) {
88093
- const projectId = r.engine.profile.projectId;
88094
- if (!projectId || !effectiveConsent(c, r.engine.profile).sync) continue;
88095
- const identity = identityFor(liveWorkspaceEntry(r.entry));
88096
- if (identity.invalid) {
88097
- noteIdentityBlock(r.id, r.entry.name, identity);
88098
- continue;
88099
- }
88100
- if (identity.rule !== "workspace-binding" && !hasCloudCredential(c)) continue;
88101
- const client = cloudForIdentity(identity);
88102
- try {
88103
- const { salt } = await resolveProjectSymbolSalt(client, projectId);
88104
- await pullProjectAnchors(r, client, salt);
88105
- } catch (err2) {
88106
- console.warn(`[errata] anchor pull skipped for ${r.engine.profile.name}: ${err2 instanceof Error ? err2.message : String(err2)}`);
88120
+ if (anchorPullRunning) return;
88121
+ anchorPullRunning = true;
88122
+ try {
88123
+ const c = loadConfig();
88124
+ if (registryCorrupt()) return;
88125
+ for (const r of records) {
88126
+ if (!revisionBacklog.has(r.root) && Date.now() - (lastAnchorPull.get(r.root) ?? 0) < ANCHOR_PULL_INTERVAL_MS) continue;
88127
+ const projectId = r.engine.profile.projectId;
88128
+ if (!projectId || !effectiveConsent(c, r.engine.profile).sync) continue;
88129
+ const identity = identityFor(liveWorkspaceEntry(r.entry));
88130
+ if (identity.invalid) {
88131
+ noteIdentityBlock(r.id, r.entry.name, identity);
88132
+ continue;
88133
+ }
88134
+ if (identity.rule !== "workspace-binding" && !hasCloudCredential(c)) continue;
88135
+ const client = cloudForIdentity(identity);
88136
+ try {
88137
+ const { salt } = await resolveProjectSymbolSalt(client, projectId);
88138
+ await pullProjectAnchors(r, client, salt);
88139
+ lastAnchorPull.set(r.root, Date.now());
88140
+ } catch (err2) {
88141
+ console.warn(`[errata] anchor pull skipped for ${r.engine.profile.name}: ${err2 instanceof Error ? err2.message : String(err2)}`);
88142
+ }
88107
88143
  }
88144
+ } finally {
88145
+ anchorPullRunning = false;
88108
88146
  }
88109
88147
  };
88110
88148
  const anchorPull = setInterval(() => {
88111
88149
  void anchorPullAll();
88112
- }, ANCHOR_PULL_INTERVAL_MS);
88150
+ }, 6e4);
88113
88151
  const ambientLinkAll = async () => {
88114
88152
  const c = loadConfig();
88115
88153
  if (registryCorrupt()) return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inerrata-corporation/errata",
3
- "version": "2.0.14-dev.3125",
3
+ "version": "2.0.14-dev.3126",
4
4
  "description": "errata - local-first observation engine for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {