@inerrata-corporation/errata 2.0.21-dev.3863 → 2.0.21-dev.3896

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
@@ -27416,7 +27416,8 @@ var init_client = __esm({
27416
27416
  nodes,
27417
27417
  edges,
27418
27418
  generatedAt: res.generatedAt,
27419
- ...res.voidSignal ? { voidSignal: res.voidSignal } : {}
27419
+ ...res.voidSignal ? { voidSignal: res.voidSignal } : {},
27420
+ ...res.seeds ? { seeds: res.seeds } : {}
27420
27421
  };
27421
27422
  }
27422
27423
  /**
@@ -27561,6 +27562,15 @@ var init_client = __esm({
27561
27562
  throw err2;
27562
27563
  }
27563
27564
  }
27565
+ /** One graph node's detail — label, full description, evidence counters,
27566
+ * §5.4 posterior and causal neighbours in both directions — via the
27567
+ * inspector read of `GET /v2/nodes` (keys on the graph node id, not the
27568
+ * canonicalId). Null when the node is absent or outside the caller's scope. */
27569
+ async getNode(nodeId) {
27570
+ const qs = new URLSearchParams({ ids: nodeId, withRelated: "true", limit: "1" });
27571
+ const res = await this.json("GET", `/v2/nodes?${qs.toString()}`);
27572
+ return res.rows.find((r) => r.id === nodeId) ?? null;
27573
+ }
27564
27574
  async sendTelemetry(batch) {
27565
27575
  return this.json("POST", "/v2/telemetry", batch);
27566
27576
  }
@@ -35107,28 +35117,97 @@ function hasCloudNodeShape(id) {
35107
35117
  return CANONICAL_KNOWLEDGE_ID.test(id) || UUID_ID.test(id) || id.startsWith("pkg:");
35108
35118
  }
35109
35119
  async function collectiveDrilldown(cloud, seedId, limit) {
35120
+ let res;
35110
35121
  try {
35111
- const res = await cloud.search({ stack: [], domains: [], kinds: [], seed: [seedId], limit });
35112
- if (res.nodes.length === 0) return null;
35113
- return {
35114
- seed: seedId,
35115
- nodes: res.nodes.map((n) => ({
35116
- id: n.id,
35117
- label: n.label,
35118
- name: n.description,
35119
- score: Number((n.extractionConfidence ?? 0.5).toFixed(4)),
35120
- hops: 1,
35121
- provenance: "collective"
35122
- })),
35123
- edges: res.edges.map((e) => ({ from: e.from, to: e.to, type: e.type }))
35124
- };
35122
+ res = await cloud.search({ stack: [], domains: [], kinds: [], seed: [seedId], limit });
35125
35123
  } catch (err2) {
35124
+ if (isQuotaError(err2)) {
35125
+ console.warn("[errata] collectiveDrilldown: collective read QUOTA EXCEEDED \u2014 the id's existence is unknown, not refuted.");
35126
+ return { status: "quota" };
35127
+ }
35126
35128
  console.error(
35127
35129
  "[errata] collectiveDrilldown: cloud fallback failed \u2014",
35128
35130
  err2 instanceof Error ? err2.message : err2
35129
35131
  );
35130
- return null;
35132
+ return { status: "offline" };
35133
+ }
35134
+ const seedEntry = res.seeds?.find((s) => s.seed === seedId);
35135
+ const resolution = seedEntry?.status;
35136
+ if (resolution === "unresolved") return { status: "no-twin" };
35137
+ if (resolution === "error") return { status: "seed-error" };
35138
+ if (res.nodes.length === 0 && resolution !== "resolved") return { status: "no-twin" };
35139
+ return {
35140
+ status: "resolved",
35141
+ neighborhood: {
35142
+ seed: seedId,
35143
+ ...seedEntry?.nodeId ? { nodeId: seedEntry.nodeId } : {},
35144
+ nodes: res.nodes.map((n) => {
35145
+ const score2 = n.attrs["score"];
35146
+ const uncertainty = n.attrs["uncertainty"];
35147
+ return {
35148
+ id: n.id,
35149
+ label: n.label,
35150
+ name: n.description,
35151
+ ...typeof score2 === "number" ? { score: Number(score2.toFixed(4)) } : {},
35152
+ ...typeof uncertainty === "number" ? { uncertainty: Number(uncertainty.toFixed(4)) } : {},
35153
+ hops: 1,
35154
+ provenance: "collective"
35155
+ };
35156
+ }),
35157
+ edges: res.edges.map((e) => ({ from: e.from, to: e.to, type: e.type }))
35158
+ }
35159
+ };
35160
+ }
35161
+ async function collectiveNodeDetail(cloud, id) {
35162
+ const read2 = async (nodeId) => {
35163
+ try {
35164
+ return await cloud.getNode(nodeId);
35165
+ } catch (err2) {
35166
+ if (isQuotaError(err2)) return "quota";
35167
+ console.error("[errata] collectiveNodeDetail: node read failed \u2014", err2 instanceof Error ? err2.message : err2);
35168
+ return "offline";
35169
+ }
35170
+ };
35171
+ let row = await read2(id);
35172
+ if (row === "quota" || row === "offline") return { status: row };
35173
+ if (!row) {
35174
+ const drill = await collectiveDrilldown(cloud, id, 1);
35175
+ if (drill.status !== "resolved") return drill;
35176
+ const nodeId = drill.neighborhood.nodeId;
35177
+ if (nodeId && nodeId !== id) {
35178
+ row = await read2(nodeId);
35179
+ if (row === "quota" || row === "offline") return { status: row };
35180
+ }
35181
+ if (!row) return { status: "found", node: null };
35131
35182
  }
35183
+ return {
35184
+ status: "found",
35185
+ node: {
35186
+ id,
35187
+ nodeId: row.id,
35188
+ label: row.label,
35189
+ description: row.description,
35190
+ evidence: {
35191
+ validated: row.validated,
35192
+ acceptedCount: row.accepted,
35193
+ corroborationCount: row.corroborations,
35194
+ failureReportCount: row.refutes,
35195
+ effectivenessScore: row.effectivenessScore ?? null,
35196
+ uncertainty: row.uncertainty?.value ?? null,
35197
+ priorStrength: row.uncertainty?.priorStrength ?? null,
35198
+ trustTier: row.trustTier ?? null
35199
+ },
35200
+ memoryTier: row.memoryTier,
35201
+ reinforcementCount: row.reinforced,
35202
+ hits: row.hits,
35203
+ createdAtMs: row.createdAtMs,
35204
+ lastValidatedAtMs: row.lastValidatedAtMs,
35205
+ visibility: row.visibility,
35206
+ resolvedBy: row.resolvedBy,
35207
+ causalChain: row.causalChain ?? [],
35208
+ related: row.related
35209
+ }
35210
+ };
35132
35211
  }
35133
35212
  function formatDualNodes(merged) {
35134
35213
  return merged.nodes.map((n) => ({
@@ -44420,6 +44499,22 @@ async function collectiveSeedFallback(args2, ctx, defaultLimit) {
44420
44499
  const limit = Math.max(1, Math.min(100, Number(args2["limit"] ?? defaultLimit)));
44421
44500
  return collectiveDrilldown(ctx.cloud, seedId, limit);
44422
44501
  }
44502
+ function collectiveSeedStatus(cn) {
44503
+ return cn.nodes.length > 0 ? "cloud-seed" : "cloud-seed-empty";
44504
+ }
44505
+ function collectiveSeedMiss(args2, outcome) {
44506
+ if (!outcome || outcome.status === "no-twin" || outcome.status === "resolved") return unresolved(args2);
44507
+ const { query } = unresolved(args2);
44508
+ const hint = outcome.status === "seed-error" ? "collective reached, but this id's lookup failed server-side \u2014 its existence is unknown; retry" : federationHint(outcome.status);
44509
+ return {
44510
+ found: false,
44511
+ reason: "collective-unreachable",
44512
+ query,
44513
+ collectiveReachable: outcome.status === "seed-error",
44514
+ collectiveStatus: outcome.status === "seed-error" ? "cloud-seed-error" : outcome.status,
44515
+ ...hint ? { collectiveHint: hint } : {}
44516
+ };
44517
+ }
44423
44518
  function resolveSymbol2(store, args2) {
44424
44519
  const id = args2["nodeId"];
44425
44520
  if (typeof id === "string" && store.getNode(id)) return id;
@@ -44770,13 +44865,14 @@ var init_mcp = __esm({
44770
44865
  handler: async (args2, store, ctx) => {
44771
44866
  const id = resolveSymbol2(store, args2);
44772
44867
  if (!id) {
44773
- const cn = await collectiveSeedFallback(args2, ctx, 30);
44774
- if (cn) {
44868
+ const cs = await collectiveSeedFallback(args2, ctx, 30);
44869
+ if (cs?.status === "resolved") {
44870
+ const cn = cs.neighborhood;
44775
44871
  return {
44776
44872
  found: true,
44777
44873
  node: { id: cn.seed, provenance: "collective" },
44778
44874
  collectiveReachable: true,
44779
- collectiveStatus: "cloud-seed",
44875
+ collectiveStatus: collectiveSeedStatus(cn),
44780
44876
  // Seed-touching edge types aren't on the wire (the server's seed
44781
44877
  // burst excludes the seed itself, and edges to nodes outside the
44782
44878
  // result set are dropped), so the collective fallback reports the
@@ -44786,7 +44882,7 @@ var init_mcp = __esm({
44786
44882
  edges: cn.edges
44787
44883
  };
44788
44884
  }
44789
- return unresolved(args2);
44885
+ return collectiveSeedMiss(args2, cs);
44790
44886
  }
44791
44887
  const limit = Math.max(1, Math.min(200, Number(args2["limit"] ?? 30)));
44792
44888
  const node2 = store.getNode(id);
@@ -44834,19 +44930,21 @@ var init_mcp = __esm({
44834
44930
  handler: async (args2, store, ctx) => {
44835
44931
  const id = resolveSymbol2(store, args2);
44836
44932
  if (!id) {
44837
- const cn = await collectiveSeedFallback(args2, ctx, 20);
44838
- if (cn) {
44933
+ const cs = await collectiveSeedFallback(args2, ctx, 20);
44934
+ if (cs?.status === "resolved") {
44935
+ const cn = cs.neighborhood;
44839
44936
  return {
44937
+ found: true,
44840
44938
  seed: cn.seed,
44841
44939
  seedProvenance: "collective",
44842
44940
  collectiveReachable: true,
44843
- collectiveStatus: "cloud-seed",
44941
+ collectiveStatus: collectiveSeedStatus(cn),
44844
44942
  count: cn.nodes.length,
44845
44943
  results: cn.nodes,
44846
44944
  edges: cn.edges
44847
44945
  };
44848
44946
  }
44849
- return unresolved(args2);
44947
+ return collectiveSeedMiss(args2, cs);
44850
44948
  }
44851
44949
  const seedForBurst = store.getNode(id);
44852
44950
  if (seedForBurst && seedForBurst.embedding.length === 0) {
@@ -45016,14 +45114,15 @@ var init_mcp = __esm({
45016
45114
  handler: async (args2, store, ctx) => {
45017
45115
  const id = resolveSymbol2(store, args2);
45018
45116
  if (!id) {
45019
- const cn = await collectiveSeedFallback(args2, ctx, 30);
45020
- if (cn) {
45117
+ const cs = await collectiveSeedFallback(args2, ctx, 30);
45118
+ if (cs?.status === "resolved") {
45119
+ const cn = cs.neighborhood;
45021
45120
  return {
45022
45121
  found: true,
45023
45122
  seedId: cn.seed,
45024
45123
  seedProvenance: "collective",
45025
45124
  collectiveReachable: true,
45026
- collectiveStatus: "cloud-seed",
45125
+ collectiveStatus: collectiveSeedStatus(cn),
45027
45126
  nodes: cn.nodes.map((n) => ({
45028
45127
  id: n.id,
45029
45128
  label: n.label,
@@ -45035,7 +45134,7 @@ var init_mcp = __esm({
45035
45134
  edges: cn.edges
45036
45135
  };
45037
45136
  }
45038
- return unresolved(args2);
45137
+ return collectiveSeedMiss(args2, cs);
45039
45138
  }
45040
45139
  const maxHops = Math.max(1, Math.min(8, Number(args2["maxHops"] ?? 4)));
45041
45140
  const limit = Math.max(1, Math.min(100, Number(args2["limit"] ?? 30)));
@@ -45399,7 +45498,7 @@ var init_mcp = __esm({
45399
45498
  },
45400
45499
  {
45401
45500
  name: "errata.show",
45402
- description: "Print the source code for a node. Uses bodyStartByte/endByte if the node has them (Function/Method/Class), else falls back to startByte/endByte (Const/Comment). File nodes return the whole file content. Returns {found, path, signature, calls (in source order), startLine, endLine, source}.",
45501
+ description: "Print the source code for a node. Uses bodyStartByte/endByte if the node has them (Function/Method/Class), else falls back to startByte/endByte (Const/Comment). File nodes return the whole file content. Returns {found, path, signature, calls (in source order), startLine, endLine, source}. A cloud id from search's collective blend (e.g. projn_\u2026, dprob_\u2026) that isn't in the local graph returns the collective node's own record instead: {found, provenance:'collective', node:{label, description, evidence:{validated, acceptedCount, corroborationCount, failureReportCount, effectivenessScore, uncertainty, priorStrength, trustTier}, causalChain, related (causal neighbours, both directions)}}.",
45403
45502
  inputSchema: {
45404
45503
  type: "object",
45405
45504
  properties: {
@@ -45409,9 +45508,21 @@ var init_mcp = __esm({
45409
45508
  maxLines: { type: "number" }
45410
45509
  }
45411
45510
  },
45412
- handler: (args2, store) => {
45511
+ handler: async (args2, store, ctx) => {
45413
45512
  const id = resolveSymbol2(store, args2);
45414
- if (!id) return unresolved(args2);
45513
+ if (!id) {
45514
+ const seedId = typeof args2["nodeId"] === "string" ? args2["nodeId"] : null;
45515
+ if (!seedId || !ctx.cloud || !hasCloudNodeShape(seedId)) return unresolved(args2);
45516
+ const shown = await collectiveNodeDetail(ctx.cloud, seedId);
45517
+ if (shown.status !== "found") return collectiveSeedMiss(args2, shown);
45518
+ return {
45519
+ found: true,
45520
+ provenance: "collective",
45521
+ collectiveReachable: true,
45522
+ collectiveStatus: shown.node ? "cloud-node" : "cloud-node-no-detail",
45523
+ ...shown.node ? { node: shown.node } : { node: { id: seedId } }
45524
+ };
45525
+ }
45415
45526
  const node2 = store.getNode(id);
45416
45527
  if (!node2) return { found: false, reason: "not-found" };
45417
45528
  const maxLines = Math.max(10, Math.min(2e3, Number(args2["maxLines"] ?? 200)));
@@ -83013,7 +83124,7 @@ function createWatchBreaker(deps) {
83013
83124
  }
83014
83125
 
83015
83126
  // src/engine.ts
83016
- var DAEMON_VERSION = true ? "2.0.21-dev.3863" : "2.0.0-alpha.0";
83127
+ var DAEMON_VERSION = true ? "2.0.21-dev.3896" : "2.0.0-alpha.0";
83017
83128
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
83018
83129
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
83019
83130
  var GIT_OP_MUTE_MS = 4e3;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inerrata-corporation/errata",
3
- "version": "2.0.21-dev.3863",
3
+ "version": "2.0.21-dev.3896",
4
4
  "description": "errata - local-first observation engine for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "errata-context",
3
- "version": "2.0.21-dev.3863",
3
+ "version": "2.0.21-dev.3896",
4
4
  "description": "A minimal 3D view of loaded Errata priors and recent graph bursts.",
5
5
  "author": {
6
6
  "name": "inErrata"
@@ -1,4 +1,4 @@
1
- d2b8238acf66ab6c4bb1cfb326376ef90018fc2e3ebe8c4a3dabdfff67135669 .codex-plugin/plugin.json
1
+ 318e19fc332a3ee22b8c6f8318ee7c7c82b37b03b0624fee47dcabbdee5ddaa9 .codex-plugin/plugin.json
2
2
  a7bebae9fb01c838d6c75fc784129e28be571233fa66ff5ee8039b574f35ccf7 assets/icon.png
3
3
  fc38b64e4df1e0b72c35764bef6c4c05430d97c9009ad0ecc8a9e75b4deab232 configure-local.mjs
4
4
  73dc6028b3b070257c7c31f252d11e55a9e096f4aed0f187f10cb21716e1e6d7 dist/client.js