@inerrata-corporation/errata 2.0.0-dev.23 → 2.0.0-dev.25

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.
package/errata.mjs CHANGED
@@ -15790,6 +15790,7 @@ CREATE INDEX IF NOT EXISTS nodes_relpath ON nodes(json_extract(attrs_json, '$.re
15790
15790
  // cheaper (one bound column, no COALESCE evaluation per row).
15791
15791
  setPageRank: this.db.prepare("UPDATE nodes SET page_rank = :v WHERE id = :id"),
15792
15792
  setLandmark: this.db.prepare("UPDATE nodes SET is_landmark = :v WHERE id = :id"),
15793
+ setCommunity: this.db.prepare("UPDATE nodes SET community = :v WHERE id = :id"),
15793
15794
  updateNode: this.db.prepare(`
15794
15795
  UPDATE nodes SET
15795
15796
  description = COALESCE(:description, description),
@@ -16030,6 +16031,9 @@ CREATE INDEX IF NOT EXISTS nodes_relpath ON nodes(json_extract(attrs_json, '$.re
16030
16031
  setLandmark(id, isLandmark) {
16031
16032
  this.stmts.setLandmark.run({ id, v: isLandmark ? 1 : 0 });
16032
16033
  }
16034
+ setCommunity(id, community) {
16035
+ this.stmts.setCommunity.run({ id, v: community });
16036
+ }
16033
16037
  mergeEdge(edge2) {
16034
16038
  this.mutations++;
16035
16039
  this.stmts.insertEdge.run({
@@ -18721,6 +18725,137 @@ var init_abstraction = __esm({
18721
18725
  }
18722
18726
  });
18723
18727
 
18728
+ // ../../packages/local-graph/src/community.ts
18729
+ function detectLocalCommunities(store, opts = {}) {
18730
+ const minSize = opts.minCommunitySize ?? DEFAULT_MIN_COMMUNITY_SIZE;
18731
+ const report = { candidates: 0, communities: 0, joint: 0, assigned: 0 };
18732
+ const ids = /* @__PURE__ */ new Set();
18733
+ for (const label of JOINT_COMMUNITY_LABELS) {
18734
+ for (const n of store.findNodesByLabel(label)) {
18735
+ if (label === "Problem" && n.attrs["resolvedAs"] === PROBLEM_RESOLUTION.FALSE_POSITIVE) continue;
18736
+ ids.add(n.id);
18737
+ }
18738
+ }
18739
+ report.candidates = ids.size;
18740
+ if (ids.size === 0) return report;
18741
+ const adj = /* @__PURE__ */ new Map();
18742
+ const protect = [];
18743
+ const add = (a, b, w) => {
18744
+ const l = adj.get(a) ?? [];
18745
+ l.push({ to: b, weight: w });
18746
+ adj.set(a, l);
18747
+ };
18748
+ for (const id of ids) {
18749
+ for (const e of store.outEdges(id, [...JOINT_COMMUNITY_EDGES])) {
18750
+ if (!ids.has(e.to)) continue;
18751
+ const conf = e.confidence > 0 ? e.confidence : 0.5;
18752
+ const w = Math.max(EDGE_WEIGHT[e.type] ?? 1, 0.1) * conf;
18753
+ add(id, e.to, w);
18754
+ add(e.to, id, w);
18755
+ if (isCausalProtected(e.type)) protect.push([id, e.to]);
18756
+ }
18757
+ }
18758
+ const comm = detectCommunitiesLeiden({ nodeIds: [...ids], adj }, { protect });
18759
+ const members = /* @__PURE__ */ new Map();
18760
+ for (const [id, c] of comm.community) {
18761
+ const l = members.get(c) ?? [];
18762
+ l.push(id);
18763
+ members.set(c, l);
18764
+ }
18765
+ store.transaction(() => {
18766
+ for (const [cid, mem] of members) {
18767
+ const qualifies = mem.length >= minSize;
18768
+ let hasLocal = false;
18769
+ let hasCloud = false;
18770
+ for (const id of mem) {
18771
+ const n = store.getNode(id);
18772
+ if (!n) continue;
18773
+ const pulled = n.attrs["source"] === "cloud";
18774
+ if (pulled) hasCloud = true;
18775
+ else hasLocal = true;
18776
+ const nextAttrs = { ...n.attrs };
18777
+ if (qualifies) nextAttrs["localCommunity"] = cid;
18778
+ else delete nextAttrs["localCommunity"];
18779
+ store.updateNode(id, { attrs: nextAttrs });
18780
+ if (!pulled) store.setCommunity(id, qualifies ? cid : null);
18781
+ }
18782
+ if (qualifies) {
18783
+ report.communities++;
18784
+ report.assigned += mem.length;
18785
+ if (hasLocal && hasCloud) report.joint++;
18786
+ }
18787
+ }
18788
+ });
18789
+ return report;
18790
+ }
18791
+ function communitySeeds(store, opts = {}) {
18792
+ const maxCommunities = opts.maxCommunities ?? 4;
18793
+ const maxSeeds = opts.maxSeeds ?? 32;
18794
+ const byCommunity = /* @__PURE__ */ new Map();
18795
+ for (const label of JOINT_COMMUNITY_LABELS) {
18796
+ for (const n of store.findNodesByLabel(label)) {
18797
+ const cid = n.attrs["localCommunity"];
18798
+ if (typeof cid !== "string") continue;
18799
+ const cloudId = n.attrs["cloudNodeId"];
18800
+ const l = byCommunity.get(cid) ?? [];
18801
+ l.push({
18802
+ id: n.id,
18803
+ pulled: n.attrs["source"] === "cloud",
18804
+ cloudId: typeof cloudId === "string" && cloudId !== n.id ? cloudId : null,
18805
+ ts: n.lastUpdatedAt
18806
+ });
18807
+ byCommunity.set(cid, l);
18808
+ }
18809
+ }
18810
+ if (byCommunity.size === 0) return [];
18811
+ const ranked = [...byCommunity.entries()].map(([cid, mem]) => ({ cid, mem, fresh: Math.max(...mem.map((m) => m.ts)) })).sort((a, b) => b.fresh - a.fresh).slice(0, maxCommunities);
18812
+ const seeds = [];
18813
+ const seen = /* @__PURE__ */ new Set();
18814
+ const push = (id) => {
18815
+ if (seeds.length >= maxSeeds || seen.has(id)) return;
18816
+ seen.add(id);
18817
+ seeds.push(id);
18818
+ };
18819
+ for (const { mem } of ranked) {
18820
+ const ordered = [...mem].sort(
18821
+ (a, b) => a.pulled === b.pulled ? b.ts - a.ts : a.pulled ? -1 : 1
18822
+ );
18823
+ for (const m of ordered) {
18824
+ push(m.id);
18825
+ if (m.cloudId) push(m.cloudId);
18826
+ }
18827
+ }
18828
+ return seeds;
18829
+ }
18830
+ var JOINT_COMMUNITY_LABELS, JOINT_COMMUNITY_EDGES, DEFAULT_MIN_COMMUNITY_SIZE;
18831
+ var init_community2 = __esm({
18832
+ "../../packages/local-graph/src/community.ts"() {
18833
+ "use strict";
18834
+ init_src2();
18835
+ init_src3();
18836
+ JOINT_COMMUNITY_LABELS = [
18837
+ "Problem",
18838
+ "Solution",
18839
+ "RootCause",
18840
+ "Pattern"
18841
+ ];
18842
+ JOINT_COMMUNITY_EDGES = [
18843
+ "CAUSED_BY",
18844
+ "SOLVED_BY",
18845
+ "FIXED_BY",
18846
+ "CONTRADICTS",
18847
+ "INSTANCE_OF",
18848
+ "MATCHES",
18849
+ "IMPLEMENTS",
18850
+ "TRIAGED_BY",
18851
+ "INDICATES",
18852
+ "CONFIRMS",
18853
+ "RELATES_TO"
18854
+ ];
18855
+ DEFAULT_MIN_COMMUNITY_SIZE = 2;
18856
+ }
18857
+ });
18858
+
18724
18859
  // ../../packages/local-graph/src/triage.ts
18725
18860
  function semNode(id, label, description, ts, attrs) {
18726
18861
  return {
@@ -19339,6 +19474,8 @@ __export(src_exports, {
19339
19474
  CITABLE_PRIOR_LABELS: () => CITABLE_PRIOR_LABELS,
19340
19475
  CODE_REACH_EDGES: () => CODE_REACH_EDGES,
19341
19476
  CREDIT_FAMILY: () => CREDIT_FAMILY,
19477
+ JOINT_COMMUNITY_EDGES: () => JOINT_COMMUNITY_EDGES,
19478
+ JOINT_COMMUNITY_LABELS: () => JOINT_COMMUNITY_LABELS,
19342
19479
  MAX_ANCHOR_FILES: () => MAX_ANCHOR_FILES,
19343
19480
  PERCOLATING_DRIFT_EDGES: () => PERCOLATING_DRIFT_EDGES,
19344
19481
  PERCOLATING_EDGES: () => PERCOLATING_EDGES,
@@ -19359,12 +19496,14 @@ __export(src_exports, {
19359
19496
  causalChain: () => causalChain,
19360
19497
  claimId: () => claimId,
19361
19498
  clearRevisit: () => clearRevisit,
19499
+ communitySeeds: () => communitySeeds,
19362
19500
  compareSemver: () => compareSemver,
19363
19501
  corroborateClaim: () => corroborateClaim,
19364
19502
  creditAssignment: () => creditAssignment,
19365
19503
  crystallize: () => crystallize,
19366
19504
  deriveContextFromAnchors: () => deriveContextFromAnchors,
19367
19505
  designProblemId: () => designProblemId,
19506
+ detectLocalCommunities: () => detectLocalCommunities,
19368
19507
  edgeConductance: () => edgeConductance,
19369
19508
  evaluateDependency: () => evaluateDependency,
19370
19509
  findOrCreatePackage: () => findOrCreatePackage,
@@ -19424,6 +19563,7 @@ var init_src4 = __esm({
19424
19563
  init_design_problem();
19425
19564
  init_percolate();
19426
19565
  init_abstraction();
19566
+ init_community2();
19427
19567
  init_triage2();
19428
19568
  init_problem_dedup();
19429
19569
  init_problem_package_link();
@@ -24982,7 +25122,7 @@ var init_motifs = __esm({
24982
25122
 
24983
25123
  // ../../packages/generalizer/src/nightly.ts
24984
25124
  function runNightlyPipeline(store) {
24985
- const started = Date.now();
25125
+ const started2 = Date.now();
24986
25126
  const allowedTypes = new Set(pagerankEdgeTypes());
24987
25127
  const nodeIds = [];
24988
25128
  const meta3 = /* @__PURE__ */ new Map();
@@ -25063,9 +25203,9 @@ function runNightlyPipeline(store) {
25063
25203
  store.transaction(() => {
25064
25204
  for (const [id, c] of comm.community) store.updateNode(id, { community: c });
25065
25205
  });
25066
- const motifs = promoteMotifs(store, started);
25067
- const designResolved = resolveDesignProblems(store, started);
25068
- const cry = crystallize(store, { ts: started });
25206
+ const motifs = promoteMotifs(store, started2);
25207
+ const designResolved = resolveDesignProblems(store, started2);
25208
+ const cry = crystallize(store, { ts: started2 });
25069
25209
  return {
25070
25210
  scoredNodes: scored,
25071
25211
  iterations: result.iterations,
@@ -25081,7 +25221,7 @@ function runNightlyPipeline(store) {
25081
25221
  designResolved,
25082
25222
  claimsEvaluated: cry.evaluated,
25083
25223
  claimsDerived: cry.derived.length,
25084
- durationMs: Date.now() - started
25224
+ durationMs: Date.now() - started2
25085
25225
  };
25086
25226
  }
25087
25227
  function codeAnchorProjection(store, semanticIds, opts = {}) {
@@ -25124,7 +25264,7 @@ function embedSemanticNodes(store, opts = {}) {
25124
25264
  return embedNodesByLabels(store, SEMANTIC_LABELS, opts);
25125
25265
  }
25126
25266
  async function embedNodesByLabels(store, labels, opts = {}) {
25127
- const started = Date.now();
25267
+ const started2 = Date.now();
25128
25268
  const report = {
25129
25269
  scanned: 0,
25130
25270
  embedded: 0,
@@ -25178,7 +25318,7 @@ async function embedNodesByLabels(store, labels, opts = {}) {
25178
25318
  });
25179
25319
  if (opts.progress) opts.progress(report.embedded, todo.length);
25180
25320
  }
25181
- report.durationMs = Date.now() - started;
25321
+ report.durationMs = Date.now() - started2;
25182
25322
  return report;
25183
25323
  }
25184
25324
  function buildText(store, node2) {
@@ -25898,16 +26038,16 @@ async function incrementalReindex(store, rootPath, workspaceId2, changedAbsPaths
25898
26038
  };
25899
26039
  }
25900
26040
  async function runIndexer(store, opts) {
25901
- const started = Date.now();
26041
+ const started2 = Date.now();
25902
26042
  indexNow = opts.now ?? Date.now();
25903
26043
  const ignores = /* @__PURE__ */ new Set([...DEFAULT_IGNORES, ...opts.ignoreDirs ?? []]);
25904
26044
  const maxBytes = opts.maxFileBytes ?? 1024 * 1024;
25905
- let perfLast = started;
26045
+ let perfLast = started2;
25906
26046
  const perfFile = process.env["ERRATA_PERF"];
25907
26047
  const perf = (label) => {
25908
26048
  if (!perfFile) return;
25909
26049
  const now = Date.now();
25910
- const line = `[perf] ${label}: ${now - perfLast}ms (total ${now - started}ms)
26050
+ const line = `[perf] ${label}: ${now - perfLast}ms (total ${now - started2}ms)
25911
26051
  `;
25912
26052
  perfLast = now;
25913
26053
  try {
@@ -26382,7 +26522,7 @@ async function runIndexer(store, opts) {
26382
26522
  }
26383
26523
  }
26384
26524
  perf("flush cross-file edges");
26385
- report.durationMs = Date.now() - started;
26525
+ report.durationMs = Date.now() - started2;
26386
26526
  indexNow = null;
26387
26527
  return report;
26388
26528
  }
@@ -41091,7 +41231,7 @@ function maybeFlushDigests() {
41091
41231
  }
41092
41232
 
41093
41233
  // src/engine.ts
41094
- var DAEMON_VERSION = true ? "2.0.0-dev.23" : "2.0.0-alpha.0";
41234
+ var DAEMON_VERSION = true ? "2.0.0-dev.25" : "2.0.0-alpha.0";
41095
41235
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
41096
41236
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
41097
41237
  var GIT_OP_MUTE_MS = 4e3;
@@ -41449,6 +41589,14 @@ function createWorkspaceEngine(opts) {
41449
41589
  } catch (err2) {
41450
41590
  console.warn("[errata] problem context derivation failed:", err2);
41451
41591
  }
41592
+ try {
41593
+ const lc = detectLocalCommunities(store);
41594
+ if (lc.communities > 0) {
41595
+ console.log(`[errata] communities: ${lc.communities} detected (${lc.joint} joint local+cloud) across ${lc.assigned}/${lc.candidates} node(s)`);
41596
+ }
41597
+ } catch (err2) {
41598
+ console.warn("[errata] joint community pass failed:", err2);
41599
+ }
41452
41600
  return { report, localSkills: 0 };
41453
41601
  };
41454
41602
  const onWorkingFileChanged = (rel, sessionId) => {
@@ -41889,7 +42037,8 @@ function createWorkspaceEngine(opts) {
41889
42037
  });
41890
42038
  }
41891
42039
  const pullSkills = () => {
41892
- const skillSeed = store.findNodesByLabel("Problem").sort((a, b) => b.lastUpdatedAt - a.lastUpdatedAt).slice(0, 6).flatMap((p) => {
42040
+ const communitySeed = communitySeeds(store);
42041
+ const skillSeed = communitySeed.length > 0 ? communitySeed : store.findNodesByLabel("Problem").sort((a, b) => b.lastUpdatedAt - a.lastUpdatedAt).slice(0, 6).flatMap((p) => {
41893
42042
  const cloudId = p.attrs["cloudNodeId"];
41894
42043
  return typeof cloudId === "string" && cloudId !== p.id ? [p.id, cloudId] : [p.id];
41895
42044
  });
@@ -42803,6 +42952,32 @@ var ConsolidateWorker = class {
42803
42952
  }
42804
42953
  };
42805
42954
 
42955
+ // src/loop-lag.ts
42956
+ var HEARTBEAT_MS = 500;
42957
+ var currentPass = "idle";
42958
+ var started = false;
42959
+ function markPass(name2) {
42960
+ const prev = currentPass;
42961
+ currentPass = name2;
42962
+ return () => {
42963
+ currentPass = prev;
42964
+ };
42965
+ }
42966
+ function startLoopLagMonitor(thresholdMs = 1e3) {
42967
+ if (started) return;
42968
+ started = true;
42969
+ let last = Date.now();
42970
+ const timer = setInterval(() => {
42971
+ const now = Date.now();
42972
+ const lag = now - last - HEARTBEAT_MS;
42973
+ if (lag > thresholdMs) {
42974
+ console.warn(`[loop-lag] event loop held ~${(lag / 1e3).toFixed(1)}s during "${currentPass}"`);
42975
+ }
42976
+ last = now;
42977
+ }, HEARTBEAT_MS);
42978
+ timer.unref();
42979
+ }
42980
+
42806
42981
  // src/multi.ts
42807
42982
  init_paths();
42808
42983
 
@@ -42889,6 +43064,7 @@ async function startMultiDaemon(opts = {}) {
42889
43064
  const sharedStore = openGraphStore({ path: sharedDbPath });
42890
43065
  const bundledRun = import.meta.url.endsWith(".mjs");
42891
43066
  const consolidateWorker = bundledRun && sharedDbPath !== ":memory:" ? new ConsolidateWorker() : null;
43067
+ startLoopLagMonitor();
42892
43068
  let baseUrl = "";
42893
43069
  const records = [];
42894
43070
  const boundaryListeners = [];
@@ -43013,12 +43189,43 @@ async function startMultiDaemon(opts = {}) {
43013
43189
  );
43014
43190
  const STRANDED_TTL_MS = 6e4;
43015
43191
  const strandedCache = /* @__PURE__ */ new Map();
43192
+ const strandedRefreshing = /* @__PURE__ */ new Set();
43016
43193
  const strandedCount = (r) => {
43017
43194
  const hit = strandedCache.get(r.id);
43018
43195
  if (hit && Date.now() - hit.at < STRANDED_TTL_MS) return hit.count;
43019
- const count = findStrandedSymbols(r.engine.store).length;
43020
- strandedCache.set(r.id, { at: Date.now(), count });
43021
- return count;
43196
+ if (!strandedRefreshing.has(r.id)) {
43197
+ strandedRefreshing.add(r.id);
43198
+ const finish = (count) => {
43199
+ strandedCache.set(r.id, { at: Date.now(), count });
43200
+ strandedRefreshing.delete(r.id);
43201
+ };
43202
+ if (consolidateWorker && r.engine.paths.castalia !== ":memory:") {
43203
+ consolidateWorker.run({ kind: "strandedCount", sharedDbPath, castaliaPath: r.engine.paths.castalia }).then((n) => finish(Number(n))).catch(() => {
43204
+ setImmediate(() => {
43205
+ const done = markPass(`stranded-scan:${r.entry.name}`);
43206
+ try {
43207
+ finish(findStrandedSymbols(r.engine.store).length);
43208
+ } catch {
43209
+ strandedRefreshing.delete(r.id);
43210
+ } finally {
43211
+ done();
43212
+ }
43213
+ });
43214
+ });
43215
+ } else {
43216
+ setImmediate(() => {
43217
+ const done = markPass(`stranded-scan:${r.entry.name}`);
43218
+ try {
43219
+ finish(findStrandedSymbols(r.engine.store).length);
43220
+ } catch {
43221
+ strandedRefreshing.delete(r.id);
43222
+ } finally {
43223
+ done();
43224
+ }
43225
+ });
43226
+ }
43227
+ }
43228
+ return hit?.count ?? -1;
43022
43229
  };
43023
43230
  app.get(
43024
43231
  "/health",
@@ -43047,13 +43254,18 @@ async function startMultiDaemon(opts = {}) {
43047
43254
  const owner = ownerOf(records, pathInBody(body2));
43048
43255
  if (!owner) return c.json({ error: "no-matching-project" }, 404);
43049
43256
  const sub = c.req.path;
43050
- return owner.webApp.fetch(
43051
- new Request(`http://local${sub}`, {
43052
- method: "POST",
43053
- headers: { "content-type": "application/json" },
43054
- body: raw2
43055
- })
43056
- );
43257
+ const done = markPass(`${sub}:${owner.entry.name}`);
43258
+ try {
43259
+ return await owner.webApp.fetch(
43260
+ new Request(`http://local${sub}`, {
43261
+ method: "POST",
43262
+ headers: { "content-type": "application/json" },
43263
+ body: raw2
43264
+ })
43265
+ );
43266
+ } finally {
43267
+ done();
43268
+ }
43057
43269
  };
43058
43270
  app.post(
43059
43271
  "/api/hook",
@@ -43071,10 +43283,11 @@ async function startMultiDaemon(opts = {}) {
43071
43283
  return typeof loc === "string" ? fileUriToFsPath(loc) : void 0;
43072
43284
  })
43073
43285
  );
43074
- app.post("/api/turn", (c) => forward(c, (b) => b["cwd"]));
43075
- app.post("/api/message", (c) => forward(c, (b) => b["cwd"]));
43076
- app.post("/api/session-end", (c) => forward(c, (b) => b["cwd"]));
43077
- app.post("/api/context-inject", (c) => forward(c, (b) => b["cwd"]));
43286
+ const cwdOf = (b) => typeof b["cwd"] === "string" ? b["cwd"] : void 0;
43287
+ app.post("/api/turn", (c) => forward(c, cwdOf));
43288
+ app.post("/api/message", (c) => forward(c, cwdOf));
43289
+ app.post("/api/session-end", (c) => forward(c, cwdOf));
43290
+ app.post("/api/context-inject", (c) => forward(c, cwdOf));
43078
43291
  for (const r of records) app.route(`/ws/${r.id}`, r.webApp);
43079
43292
  const reindexAll = async (rOpts) => {
43080
43293
  const out2 = /* @__PURE__ */ new Map();
@@ -43089,6 +43302,7 @@ async function startMultiDaemon(opts = {}) {
43089
43302
  out2.set(r.id, r.engine.store.nodeCount());
43090
43303
  continue;
43091
43304
  }
43305
+ const done = markPass(`reindex:${r.entry.name}`);
43092
43306
  try {
43093
43307
  const idx = await r.engine.reindex({ skipEmbed: rOpts?.skipEmbed ?? true, quiet: true });
43094
43308
  out2.set(r.id, idx.nodes);
@@ -43097,6 +43311,8 @@ async function startMultiDaemon(opts = {}) {
43097
43311
  } catch (err2) {
43098
43312
  console.warn(`[errata] index failed for ${r.entry.name}: ${err2 instanceof Error ? err2.message : err2}`);
43099
43313
  out2.set(r.id, r.engine.store.nodeCount());
43314
+ } finally {
43315
+ done();
43100
43316
  }
43101
43317
  }
43102
43318
  if (toIndex.length > 0) {
@@ -43133,6 +43349,7 @@ async function startMultiDaemon(opts = {}) {
43133
43349
  const out2 = /* @__PURE__ */ new Map();
43134
43350
  for (const r of records) {
43135
43351
  await new Promise((resolve5) => setImmediate(resolve5));
43352
+ const done = markPass(`package-index:${r.entry.name}`);
43136
43353
  try {
43137
43354
  out2.set(
43138
43355
  r.id,
@@ -43146,6 +43363,8 @@ async function startMultiDaemon(opts = {}) {
43146
43363
  );
43147
43364
  } catch (err2) {
43148
43365
  console.warn(`[errata] package index failed for ${r.entry.name}: ${err2 instanceof Error ? err2.message : err2}`);
43366
+ } finally {
43367
+ done();
43149
43368
  }
43150
43369
  }
43151
43370
  return out2;
@@ -43160,10 +43379,13 @@ async function startMultiDaemon(opts = {}) {
43160
43379
  async tickAll() {
43161
43380
  const out2 = /* @__PURE__ */ new Map();
43162
43381
  for (const r of records) {
43382
+ const done = markPass(`tick:${r.entry.name}`);
43163
43383
  try {
43164
43384
  out2.set(r.id, await r.engine.tick());
43165
43385
  } catch (err2) {
43166
43386
  console.warn(`[errata] tick failed for ${r.entry.name}: ${err2 instanceof Error ? err2.message : err2}`);
43387
+ } finally {
43388
+ done();
43167
43389
  }
43168
43390
  }
43169
43391
  return out2;
@@ -43171,10 +43393,13 @@ async function startMultiDaemon(opts = {}) {
43171
43393
  async nightlyAll() {
43172
43394
  const out2 = /* @__PURE__ */ new Map();
43173
43395
  for (const r of records) {
43396
+ const done = markPass(`nightly:${r.entry.name}`);
43174
43397
  try {
43175
43398
  out2.set(r.id, await r.engine.nightly());
43176
43399
  } catch (err2) {
43177
43400
  console.warn(`[errata] nightly failed for ${r.entry.name}: ${err2 instanceof Error ? err2.message : err2}`);
43401
+ } finally {
43402
+ done();
43178
43403
  }
43179
43404
  }
43180
43405
  return out2;
@@ -43205,12 +43430,15 @@ async function startMultiDaemon(opts = {}) {
43205
43430
  }
43206
43431
  }
43207
43432
  for (const r of inlineRecords) {
43433
+ const done = markPass(`percolate-inline:${r.entry.name}`);
43208
43434
  try {
43209
43435
  out2.set(r.id, percolate(r.engine.store, sharedStore, { workspaceId: r.engine.profile.id, ts }));
43210
43436
  } catch (err2) {
43211
43437
  console.warn(
43212
43438
  `[errata] percolate failed for ${r.entry.name}: ${err2 instanceof Error ? err2.message : err2}`
43213
43439
  );
43440
+ } finally {
43441
+ done();
43214
43442
  }
43215
43443
  }
43216
43444
  return out2;
@@ -43547,28 +43775,6 @@ async function loginOAuthLoopback(opts) {
43547
43775
  // src/update.ts
43548
43776
  import { spawn as spawn2 } from "node:child_process";
43549
43777
  var PACKAGE_NAME = "@inerrata-corporation/errata";
43550
- function parse3(v) {
43551
- const m = /^(\d+)\.(\d+)\.(\d+)(?:-dev\.(\d+))?/.exec(v.trim());
43552
- if (!m) return null;
43553
- return {
43554
- base: [Number(m[1]), Number(m[2]), Number(m[3])],
43555
- pre: m[4] === void 0 ? null : Number(m[4])
43556
- };
43557
- }
43558
- function compareVersions(a, b) {
43559
- const pa = parse3(a);
43560
- const pb = parse3(b);
43561
- if (!pa || !pb) return 0;
43562
- const [aMaj, aMin, aPatch] = pa.base;
43563
- const [bMaj, bMin, bPatch] = pb.base;
43564
- if (aMaj !== bMaj) return aMaj - bMaj;
43565
- if (aMin !== bMin) return aMin - bMin;
43566
- if (aPatch !== bPatch) return aPatch - bPatch;
43567
- if (pa.pre === pb.pre) return 0;
43568
- if (pa.pre === null) return 1;
43569
- if (pb.pre === null) return -1;
43570
- return pa.pre - pb.pre;
43571
- }
43572
43778
  async function latestPublished(channel, timeoutMs = 4e3) {
43573
43779
  const ctrl = new AbortController();
43574
43780
  const timer = setTimeout(() => ctrl.abort(), timeoutMs);
@@ -43591,7 +43797,7 @@ async function checkForUpdate(channel) {
43591
43797
  return {
43592
43798
  current: DAEMON_VERSION,
43593
43799
  latest,
43594
- updateAvailable: latest !== null && compareVersions(latest, DAEMON_VERSION) > 0
43800
+ updateAvailable: latest !== null && latest !== DAEMON_VERSION
43595
43801
  };
43596
43802
  }
43597
43803
  function runNpmInstall(channel) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inerrata-corporation/errata",
3
- "version": "2.0.0-dev.23",
3
+ "version": "2.0.0-dev.25",
4
4
  "description": "errata - local-first observation engine for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {
package/pass-worker.mjs CHANGED
@@ -23961,6 +23961,7 @@ var SqliteGraphStore = class {
23961
23961
  // cheaper (one bound column, no COALESCE evaluation per row).
23962
23962
  setPageRank: this.db.prepare("UPDATE nodes SET page_rank = :v WHERE id = :id"),
23963
23963
  setLandmark: this.db.prepare("UPDATE nodes SET is_landmark = :v WHERE id = :id"),
23964
+ setCommunity: this.db.prepare("UPDATE nodes SET community = :v WHERE id = :id"),
23964
23965
  updateNode: this.db.prepare(`
23965
23966
  UPDATE nodes SET
23966
23967
  description = COALESCE(:description, description),
@@ -24201,6 +24202,9 @@ var SqliteGraphStore = class {
24201
24202
  setLandmark(id, isLandmark) {
24202
24203
  this.stmts.setLandmark.run({ id, v: isLandmark ? 1 : 0 });
24203
24204
  }
24205
+ setCommunity(id, community) {
24206
+ this.stmts.setCommunity.run({ id, v: community });
24207
+ }
24204
24208
  mergeEdge(edge) {
24205
24209
  this.mutations++;
24206
24210
  this.stmts.insertEdge.run({
@@ -25167,6 +25171,9 @@ function motifDecision(input) {
25167
25171
  };
25168
25172
  }
25169
25173
 
25174
+ // ../../packages/local-graph/src/community.ts
25175
+ init_src2();
25176
+
25170
25177
  // ../../packages/local-graph/src/triage.ts
25171
25178
  init_src();
25172
25179
  init_src();