@inerrata-corporation/errata 2.0.2-dev.156 → 2.0.2-dev.161

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 +116 -49
  2. package/package.json +1 -1
package/errata.mjs CHANGED
@@ -25916,6 +25916,33 @@ function federationHint(status) {
25916
25916
  return void 0;
25917
25917
  }
25918
25918
  }
25919
+ function hasCloudNodeShape(id) {
25920
+ return CANONICAL_KNOWLEDGE_ID.test(id) || UUID_ID.test(id) || id.startsWith("pkg:");
25921
+ }
25922
+ async function collectiveDrilldown(cloud, seedId, limit) {
25923
+ try {
25924
+ const res = await cloud.search({ stack: [], domains: [], kinds: [], seed: [seedId], limit });
25925
+ if (res.nodes.length === 0) return null;
25926
+ return {
25927
+ seed: seedId,
25928
+ nodes: res.nodes.map((n) => ({
25929
+ id: n.id,
25930
+ label: n.label,
25931
+ name: n.description,
25932
+ score: Number((n.extractionConfidence ?? 0.5).toFixed(4)),
25933
+ hops: 1,
25934
+ provenance: "collective"
25935
+ })),
25936
+ edges: res.edges.map((e) => ({ from: e.from, to: e.to, type: e.type }))
25937
+ };
25938
+ } catch (err2) {
25939
+ console.error(
25940
+ "[errata] collectiveDrilldown: cloud fallback failed \u2014",
25941
+ err2 instanceof Error ? err2.message : err2
25942
+ );
25943
+ return null;
25944
+ }
25945
+ }
25919
25946
  function formatDualNodes(merged) {
25920
25947
  return merged.nodes.map((n) => ({
25921
25948
  id: n.id,
@@ -25935,7 +25962,7 @@ function formatDualNodes(merged) {
25935
25962
  } : {}
25936
25963
  }));
25937
25964
  }
25938
- var BRIDGE_LABELS;
25965
+ var BRIDGE_LABELS, CANONICAL_KNOWLEDGE_ID, UUID_ID;
25939
25966
  var init_dual_augment = __esm({
25940
25967
  "src/dual-augment.ts"() {
25941
25968
  "use strict";
@@ -25943,6 +25970,8 @@ var init_dual_augment = __esm({
25943
25970
  init_generalize_graph();
25944
25971
  init_dual_burst();
25945
25972
  BRIDGE_LABELS = new Set(SEMANTIC_NODE_LABELS);
25973
+ CANONICAL_KNOWLEDGE_ID = /^[a-z][a-z0-9]*_[0-9a-f]{8,}$/;
25974
+ UUID_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
25946
25975
  }
25947
25976
  });
25948
25977
 
@@ -36858,6 +36887,12 @@ function cosine3(a, b) {
36858
36887
  for (let i2 = 0; i2 < a.length; i2++) dot += a[i2] * b[i2];
36859
36888
  return dot;
36860
36889
  }
36890
+ async function collectiveSeedFallback(args2, ctx, defaultLimit) {
36891
+ const seedId = typeof args2["nodeId"] === "string" ? args2["nodeId"] : null;
36892
+ if (!seedId || !ctx.cloud || !hasCloudNodeShape(seedId)) return null;
36893
+ const limit = Math.max(1, Math.min(100, Number(args2["limit"] ?? defaultLimit)));
36894
+ return collectiveDrilldown(ctx.cloud, seedId, limit);
36895
+ }
36861
36896
  function resolveSymbol2(store, args2) {
36862
36897
  const id = args2["nodeId"];
36863
36898
  if (typeof id === "string" && store.getNode(id)) return id;
@@ -37208,7 +37243,7 @@ var init_mcp = __esm({
37208
37243
  },
37209
37244
  {
37210
37245
  name: "errata.neighbors",
37211
- description: "Return direct in/out edges of a node. Pass either a nodeId or a qname (e.g. ClassName.method) \u2014 resolved like the other nav verbs. Use after errata.search or errata.locate to walk the graph.",
37246
+ description: "Return direct in/out edges of a node. Pass either a nodeId or a qname (e.g. ClassName.method) \u2014 resolved like the other nav verbs. Use after errata.search or errata.locate to walk the graph. A cloud id from search's collective blend (e.g. dprob_\u2026) that isn't in the local graph falls back to its collective neighborhood, tagged provenance:collective.",
37212
37247
  inputSchema: {
37213
37248
  type: "object",
37214
37249
  properties: {
@@ -37217,9 +37252,27 @@ var init_mcp = __esm({
37217
37252
  limit: { type: "number", description: "Max edges per direction (default 30)" }
37218
37253
  }
37219
37254
  },
37220
- handler: (args2, store) => {
37255
+ handler: async (args2, store, ctx) => {
37221
37256
  const id = resolveSymbol2(store, args2);
37222
- if (!id) return unresolved(args2);
37257
+ if (!id) {
37258
+ const cn = await collectiveSeedFallback(args2, ctx, 30);
37259
+ if (cn) {
37260
+ return {
37261
+ found: true,
37262
+ node: { id: cn.seed, provenance: "collective" },
37263
+ collectiveReachable: true,
37264
+ collectiveStatus: "cloud-seed",
37265
+ // Seed-touching edge types aren't on the wire (the server's seed
37266
+ // burst excludes the seed itself, and edges to nodes outside the
37267
+ // result set are dropped), so the collective fallback reports the
37268
+ // 1-hop neighborhood + its internal topology instead of the local
37269
+ // contract's typed out/in lists.
37270
+ nearby: cn.nodes,
37271
+ edges: cn.edges
37272
+ };
37273
+ }
37274
+ return unresolved(args2);
37275
+ }
37223
37276
  const limit = Math.max(1, Math.min(200, Number(args2["limit"] ?? 30)));
37224
37277
  const node2 = store.getNode(id);
37225
37278
  if (!node2) return { found: false, reason: "not-found" };
@@ -37266,32 +37319,17 @@ var init_mcp = __esm({
37266
37319
  handler: async (args2, store, ctx) => {
37267
37320
  const id = resolveSymbol2(store, args2);
37268
37321
  if (!id) {
37269
- const seedId = typeof args2["nodeId"] === "string" ? args2["nodeId"] : null;
37270
- if (seedId && ctx.cloud) {
37271
- const res = await ctx.cloud.search({
37272
- stack: [],
37273
- domains: [],
37274
- kinds: [],
37275
- seed: [seedId],
37276
- limit: args2["limit"] != null ? Number(args2["limit"]) : 20
37277
- }).catch(() => null);
37278
- if (res && res.nodes.length > 0) {
37279
- return {
37280
- seed: seedId,
37281
- seedProvenance: "collective",
37282
- collectiveReachable: true,
37283
- collectiveStatus: "cloud-seed",
37284
- count: res.nodes.length,
37285
- results: res.nodes.map((n) => ({
37286
- id: n.id,
37287
- label: n.label,
37288
- name: n.description,
37289
- score: Number((n.extractionConfidence ?? 0.5).toFixed(4)),
37290
- hops: 1,
37291
- provenance: "collective"
37292
- }))
37293
- };
37294
- }
37322
+ const cn = await collectiveSeedFallback(args2, ctx, 20);
37323
+ if (cn) {
37324
+ return {
37325
+ seed: cn.seed,
37326
+ seedProvenance: "collective",
37327
+ collectiveReachable: true,
37328
+ collectiveStatus: "cloud-seed",
37329
+ count: cn.nodes.length,
37330
+ results: cn.nodes,
37331
+ edges: cn.edges
37332
+ };
37295
37333
  }
37296
37334
  return unresolved(args2);
37297
37335
  }
@@ -37448,7 +37486,7 @@ var init_mcp = __esm({
37448
37486
  },
37449
37487
  {
37450
37488
  name: "errata.why",
37451
- description: "Causal/resolution neighborhood along the causal edge families (CAUSED_BY, MANIFESTS_AS, FIXED_BY, SOLVED_BY, \u2026), walked in both directions. For a Problem this surfaces its root causes AND solutions; for a Solution, the problems it resolves. Merges the machine-wide shared store's triage layer (cause chains from inline `<-` diagnoses land there, keyed by the same content-derived problem id). Ranked by accumulated conductance. Pass nodeId or qname. Returns {seedId, nodes:[{id,label,description,hops,edgeType,relevance}]}.",
37489
+ description: "Causal/resolution neighborhood along the causal edge families (CAUSED_BY, MANIFESTS_AS, FIXED_BY, SOLVED_BY, \u2026), walked in both directions. For a Problem this surfaces its root causes AND solutions; for a Solution, the problems it resolves. Merges the machine-wide shared store's triage layer (cause chains from inline `<-` diagnoses land there, keyed by the same content-derived problem id). Ranked by accumulated conductance. Pass nodeId or qname. Returns {seedId, nodes:[{id,label,description,hops,edgeType,relevance}]}. A cloud id from search's collective blend (e.g. dprob_\u2026) that isn't in the local graph falls back to its collective causal neighborhood, tagged provenance:collective.",
37452
37490
  inputSchema: {
37453
37491
  type: "object",
37454
37492
  properties: {
@@ -37458,9 +37496,30 @@ var init_mcp = __esm({
37458
37496
  limit: { type: "number", description: "Default 30" }
37459
37497
  }
37460
37498
  },
37461
- handler: (args2, store) => {
37499
+ handler: async (args2, store, ctx) => {
37462
37500
  const id = resolveSymbol2(store, args2);
37463
- if (!id) return unresolved(args2);
37501
+ if (!id) {
37502
+ const cn = await collectiveSeedFallback(args2, ctx, 30);
37503
+ if (cn) {
37504
+ return {
37505
+ found: true,
37506
+ seedId: cn.seed,
37507
+ seedProvenance: "collective",
37508
+ collectiveReachable: true,
37509
+ collectiveStatus: "cloud-seed",
37510
+ nodes: cn.nodes.map((n) => ({
37511
+ id: n.id,
37512
+ label: n.label,
37513
+ description: n.name,
37514
+ hops: n.hops,
37515
+ relevance: n.score,
37516
+ provenance: n.provenance
37517
+ })),
37518
+ edges: cn.edges
37519
+ };
37520
+ }
37521
+ return unresolved(args2);
37522
+ }
37464
37523
  const maxHops = Math.max(1, Math.min(8, Number(args2["maxHops"] ?? 4)));
37465
37524
  const limit = Math.max(1, Math.min(100, Number(args2["limit"] ?? 30)));
37466
37525
  const local = causalChain(store, { seedId: id, direction: "both", maxHops, limit });
@@ -50758,14 +50817,16 @@ function generalizePrincipleForSync(principle, level = 2) {
50758
50817
  delete node2.logicalId;
50759
50818
  return node2;
50760
50819
  }
50761
- function buildPrincipleIngest(sharedStore, daemonVersion, ignorePatterns = [], level = 2) {
50820
+ function buildPrincipleIngest(sharedStore, daemonVersion, ignorePatterns = [], level = 2, opts = {}) {
50821
+ const lang = opts.primaryLanguage?.trim().toLowerCase();
50822
+ const claim = lang ? { anchorVisibility: "public", anchor: `lang:${lang}` } : {};
50762
50823
  const selected = sharedStore.findNodesByLabel("Claim").filter((n) => isSyncablePrinciple(n, ignorePatterns));
50763
50824
  for (const n of selected) {
50764
50825
  if (Number(n.attrs["abstractionLevel"] ?? ABSTRACTION_LEVEL.CONCRETE) !== ABSTRACTION_LEVEL.PRINCIPLE || n.attrs["provisional"] !== false) {
50765
50826
  throw new Error(`buildPrincipleIngest: refusing to sync non-canonical-principle ${n.id} \u2014 C7 invariant violated`);
50766
50827
  }
50767
50828
  }
50768
- const nodes = selected.map((n) => generalizePrincipleForSync(n, level));
50829
+ const nodes = selected.map((n) => ({ ...generalizePrincipleForSync(n, level), ...claim }));
50769
50830
  if (nodes.length === 0) return null;
50770
50831
  const base = {
50771
50832
  daemonVersion,
@@ -51936,7 +51997,7 @@ function startLoopLagMonitor(thresholdMs = 1e3) {
51936
51997
  }
51937
51998
 
51938
51999
  // src/engine.ts
51939
- var DAEMON_VERSION = true ? "2.0.2-dev.156" : "2.0.0-alpha.0";
52000
+ var DAEMON_VERSION = true ? "2.0.2-dev.161" : "2.0.0-alpha.0";
51940
52001
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
51941
52002
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
51942
52003
  var GIT_OP_MUTE_MS = 4e3;
@@ -54374,6 +54435,18 @@ async function startMultiDaemon(opts = {}) {
54374
54435
  startLoopLagMonitor();
54375
54436
  let baseUrl = "";
54376
54437
  const records = [];
54438
+ const machineDominantLanguage = () => {
54439
+ const langCounts = /* @__PURE__ */ new Map();
54440
+ for (const r of records) {
54441
+ for (const l of r.engine.profile.languages ?? []) {
54442
+ const k = String(l).trim().toLowerCase();
54443
+ if (k) langCounts.set(k, (langCounts.get(k) ?? 0) + 1);
54444
+ }
54445
+ }
54446
+ return [...langCounts.entries()].sort(
54447
+ (a, b) => b[1] - a[1] || (a[0] < b[0] ? -1 : 1)
54448
+ )[0]?.[0];
54449
+ };
54377
54450
  const updatePoller = opts.updateCheck ? startUpdatePoller({
54378
54451
  channel: loadConfig().updateChannel,
54379
54452
  onChange: (pending) => {
@@ -54936,7 +55009,10 @@ async function startMultiDaemon(opts = {}) {
54936
55009
  async syncPrinciplesPublic() {
54937
55010
  if (!loadConfig().consent.sync) return { uploaded: 0, skipped: "consent-off" };
54938
55011
  const ignore = loadClaimIgnorePatterns(globalDir());
54939
- const payload = buildPrincipleIngest(sharedStore, DAEMON_VERSION, ignore);
55012
+ const primaryLanguage = machineDominantLanguage();
55013
+ const payload = buildPrincipleIngest(sharedStore, DAEMON_VERSION, ignore, 2, {
55014
+ ...primaryLanguage ? { primaryLanguage } : {}
55015
+ });
54940
55016
  if (!payload) return { uploaded: 0 };
54941
55017
  const res = await cloudNow().ingest(payload);
54942
55018
  return { uploaded: res.accepted };
@@ -54944,16 +55020,7 @@ async function startMultiDaemon(opts = {}) {
54944
55020
  async syncTriagePublic() {
54945
55021
  if (!loadConfig().consent.sync) return { uploaded: 0, skipped: "consent-off" };
54946
55022
  const ignore = loadClaimIgnorePatterns(globalDir());
54947
- const langCounts = /* @__PURE__ */ new Map();
54948
- for (const r of records) {
54949
- for (const l of r.engine.profile.languages ?? []) {
54950
- const k = String(l).trim().toLowerCase();
54951
- if (k) langCounts.set(k, (langCounts.get(k) ?? 0) + 1);
54952
- }
54953
- }
54954
- const primaryLanguage = [...langCounts.entries()].sort(
54955
- (a, b) => b[1] - a[1] || (a[0] < b[0] ? -1 : 1)
54956
- )[0]?.[0];
55023
+ const primaryLanguage = machineDominantLanguage();
54957
55024
  const payload = buildTriageIngest(sharedStore, DAEMON_VERSION, ignore, 2, {
54958
55025
  ...primaryLanguage ? { primaryLanguage } : {}
54959
55026
  });
@@ -57373,8 +57440,8 @@ async function cmdSimilar(args2) {
57373
57440
  const limitIdx = args2.indexOf("--limit");
57374
57441
  const limit = limitIdx >= 0 && args2[limitIdx + 1] ? Number(args2[limitIdx + 1]) : 5;
57375
57442
  const { runTool: runTool2 } = await Promise.resolve().then(() => (init_mcp(), mcp_exports));
57376
- await withStore((store) => {
57377
- const r = runTool2("errata.similar", { nodeId: seed, qname: seed, limit }, store);
57443
+ await withStore(async (store) => {
57444
+ const r = await runTool2("errata.similar", { nodeId: seed, qname: seed, limit }, store);
57378
57445
  if (!r.found) {
57379
57446
  console.log("seed not found");
57380
57447
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inerrata-corporation/errata",
3
- "version": "2.0.2-dev.156",
3
+ "version": "2.0.2-dev.161",
4
4
  "description": "errata - local-first observation engine for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {