@inerrata-corporation/errata 2.0.20-dev.3682 → 2.0.20-dev.3704

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.
@@ -16552,6 +16552,11 @@ CREATE INDEX IF NOT EXISTS nodes_live_description ON nodes(description, label) W
16552
16552
  -- Problems by the file their anchor hint names: the harvest upgrades hints for
16553
16553
  -- every edited file of every turn, and a scan parses every Problem's attrs.
16554
16554
  CREATE INDEX IF NOT EXISTS nodes_anchor_hint_path ON nodes(json_extract(attrs_json, '$.anchorHint.path')) WHERE valid_to IS NULL;
16555
+ -- Nodes still waiting on a root-cause ask. The MCP server checks this on EVERY
16556
+ -- tool response (the enrichment piggyback), so it must not parse every
16557
+ -- Solution's and Problem's attrs per call. Not partial: the Problem pull reads
16558
+ -- closed versions too.
16559
+ CREATE INDEX IF NOT EXISTS nodes_enrichment_pending ON nodes(json_extract(attrs_json, '$.enrichmentPending'));
16555
16560
  `;
16556
16561
  function encodeEmbedding(emb) {
16557
16562
  if (!emb || emb.length === 0) return null;
@@ -17209,7 +17214,10 @@ var SqliteGraphStore = class {
17209
17214
  }));
17210
17215
  }
17211
17216
  findAllVersionsByLabel(label, attribute) {
17212
- const rows = attribute ? this.db.prepare("SELECT * FROM nodes WHERE label = ? AND json_extract(attrs_json, ?) = ?").all(label, `$.${attribute.path}`, attribute.value) : this.stmts.findByLabelAll.all(label);
17217
+ if (attribute && !/^[A-Za-z0-9_]+(\.[A-Za-z0-9_]+)*$/.test(attribute.path)) {
17218
+ throw new Error(`invalid attr path: ${attribute.path}`);
17219
+ }
17220
+ const rows = attribute ? this.db.prepare(`SELECT * FROM nodes WHERE json_extract(attrs_json, '$.${attribute.path}') = ? AND label = ?`).all(attribute.value, label) : this.stmts.findByLabelAll.all(label);
17213
17221
  return rows.map(rowToNode);
17214
17222
  }
17215
17223
  searchNodes(opts) {
@@ -17234,6 +17242,21 @@ var SqliteGraphStore = class {
17234
17242
  const rows = this.db.prepare(sql).all(params);
17235
17243
  return rows.map(rowToNode);
17236
17244
  }
17245
+ searchDescriptionTerms(terms, limit) {
17246
+ if (terms.length === 0) return [];
17247
+ const score = terms.map(() => "(description LIKE ?)").join(" + ");
17248
+ const rows = this.db.prepare(
17249
+ `SELECT n.*, h.m AS matched
17250
+ FROM (SELECT rowid AS rid, ${score} AS m
17251
+ FROM nodes INDEXED BY nodes_live_description
17252
+ WHERE valid_to IS NULL) h
17253
+ JOIN nodes n ON n.rowid = h.rid
17254
+ WHERE h.m > 0
17255
+ ORDER BY h.m DESC, n.page_rank DESC, n.last_updated_at DESC
17256
+ LIMIT ?`
17257
+ ).all(...terms.map((t) => `%${t}%`), Math.max(1, limit));
17258
+ return rows.map((r) => ({ node: rowToNode(r), matched: Number(r.matched) }));
17259
+ }
17237
17260
  typedEdgeStmt(sql) {
17238
17261
  let stmt = this.typedEdgeStmts.get(sql);
17239
17262
  if (!stmt) {
@@ -19383,6 +19406,21 @@ function buildSymbolLexicon(store) {
19383
19406
  }
19384
19407
  return lex;
19385
19408
  }
19409
+ var LEXICON_SYMBOL_LABELS = ["Function", "Method", "Class", "Interface", "Const", "Comment"];
19410
+ function codeGraphKey(store) {
19411
+ const files = store.labelFingerprint?.(["File"]);
19412
+ if (files === void 0) return null;
19413
+ return [files, ...LEXICON_SYMBOL_LABELS.map((l) => store.countNodesByLabel(l))].join("|");
19414
+ }
19415
+ var lexiconCache = /* @__PURE__ */ new WeakMap();
19416
+ function lexiconsFor(store) {
19417
+ const key = codeGraphKey(store);
19418
+ const hit = key !== null ? lexiconCache.get(store) : void 0;
19419
+ if (hit && hit.key === key) return hit;
19420
+ const built = { symbols: buildSymbolLexicon(store), files: buildFileLexicon(store) };
19421
+ if (key !== null) lexiconCache.set(store, { key, ...built });
19422
+ return built;
19423
+ }
19386
19424
  var RE_RESERVED = /[.*+?^${}()|[\]\\]/g;
19387
19425
  var escapeRe2 = (s) => s.replace(RE_RESERVED, "\\$&");
19388
19426
  var RE_LEADING_ARTICLE = /^(?:an?|the)\s/i;
@@ -20126,21 +20164,6 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
20126
20164
  }
20127
20165
 
20128
20166
  // src/drain-build.ts
20129
- var LEXICON_SYMBOL_LABELS = ["Function", "Method", "Class", "Interface", "Const", "Comment"];
20130
- function codeGraphKey(store) {
20131
- const files = store.labelFingerprint?.(["File"]);
20132
- if (files === void 0) return null;
20133
- return [files, ...LEXICON_SYMBOL_LABELS.map((l) => store.countNodesByLabel(l))].join("|");
20134
- }
20135
- var lexiconCache = /* @__PURE__ */ new WeakMap();
20136
- function lexiconsFor(store) {
20137
- const key = codeGraphKey(store);
20138
- const hit = key !== null ? lexiconCache.get(store) : void 0;
20139
- if (hit && hit.key === key) return hit;
20140
- const built = { symbols: buildSymbolLexicon(store), files: buildFileLexicon(store) };
20141
- if (key !== null) lexiconCache.set(store, { key, ...built });
20142
- return built;
20143
- }
20144
20167
  function buildDrainContext(store, input) {
20145
20168
  return buildContextIngest(store, input.profile, input.daemonVersion, input.ignorePatterns, {
20146
20169
  ...input.includePackages !== void 0 ? { includePackages: input.includePackages } : {}
package/errata.mjs CHANGED
@@ -18597,6 +18597,11 @@ CREATE INDEX IF NOT EXISTS nodes_live_description ON nodes(description, label) W
18597
18597
  -- Problems by the file their anchor hint names: the harvest upgrades hints for
18598
18598
  -- every edited file of every turn, and a scan parses every Problem's attrs.
18599
18599
  CREATE INDEX IF NOT EXISTS nodes_anchor_hint_path ON nodes(json_extract(attrs_json, '$.anchorHint.path')) WHERE valid_to IS NULL;
18600
+ -- Nodes still waiting on a root-cause ask. The MCP server checks this on EVERY
18601
+ -- tool response (the enrichment piggyback), so it must not parse every
18602
+ -- Solution's and Problem's attrs per call. Not partial: the Problem pull reads
18603
+ -- closed versions too.
18604
+ CREATE INDEX IF NOT EXISTS nodes_enrichment_pending ON nodes(json_extract(attrs_json, '$.enrichmentPending'));
18600
18605
  `;
18601
18606
  FINGERPRINT_INDEXED_LABELS = ["Problem", "Vulnerability", "Solution", "RootCause"];
18602
18607
  NODE_LABELS_CHUNK = 256;
@@ -19197,7 +19202,10 @@ CREATE INDEX IF NOT EXISTS nodes_anchor_hint_path ON nodes(json_extract(attrs_js
19197
19202
  }));
19198
19203
  }
19199
19204
  findAllVersionsByLabel(label, attribute) {
19200
- const rows = attribute ? this.db.prepare("SELECT * FROM nodes WHERE label = ? AND json_extract(attrs_json, ?) = ?").all(label, `$.${attribute.path}`, attribute.value) : this.stmts.findByLabelAll.all(label);
19205
+ if (attribute && !/^[A-Za-z0-9_]+(\.[A-Za-z0-9_]+)*$/.test(attribute.path)) {
19206
+ throw new Error(`invalid attr path: ${attribute.path}`);
19207
+ }
19208
+ const rows = attribute ? this.db.prepare(`SELECT * FROM nodes WHERE json_extract(attrs_json, '$.${attribute.path}') = ? AND label = ?`).all(attribute.value, label) : this.stmts.findByLabelAll.all(label);
19201
19209
  return rows.map(rowToNode);
19202
19210
  }
19203
19211
  searchNodes(opts) {
@@ -19222,6 +19230,21 @@ CREATE INDEX IF NOT EXISTS nodes_anchor_hint_path ON nodes(json_extract(attrs_js
19222
19230
  const rows = this.db.prepare(sql).all(params);
19223
19231
  return rows.map(rowToNode);
19224
19232
  }
19233
+ searchDescriptionTerms(terms, limit) {
19234
+ if (terms.length === 0) return [];
19235
+ const score2 = terms.map(() => "(description LIKE ?)").join(" + ");
19236
+ const rows = this.db.prepare(
19237
+ `SELECT n.*, h.m AS matched
19238
+ FROM (SELECT rowid AS rid, ${score2} AS m
19239
+ FROM nodes INDEXED BY nodes_live_description
19240
+ WHERE valid_to IS NULL) h
19241
+ JOIN nodes n ON n.rowid = h.rid
19242
+ WHERE h.m > 0
19243
+ ORDER BY h.m DESC, n.page_rank DESC, n.last_updated_at DESC
19244
+ LIMIT ?`
19245
+ ).all(...terms.map((t) => `%${t}%`), Math.max(1, limit));
19246
+ return rows.map((r) => ({ node: rowToNode(r), matched: Number(r.matched) }));
19247
+ }
19225
19248
  typedEdgeStmt(sql) {
19226
19249
  let stmt = this.typedEdgeStmts.get(sql);
19227
19250
  if (!stmt) {
@@ -34444,6 +34467,19 @@ function buildSymbolLexicon(store) {
34444
34467
  }
34445
34468
  return lex;
34446
34469
  }
34470
+ function codeGraphKey(store) {
34471
+ const files = store.labelFingerprint?.(["File"]);
34472
+ if (files === void 0) return null;
34473
+ return [files, ...LEXICON_SYMBOL_LABELS.map((l) => store.countNodesByLabel(l))].join("|");
34474
+ }
34475
+ function lexiconsFor(store) {
34476
+ const key = codeGraphKey(store);
34477
+ const hit = key !== null ? lexiconCache.get(store) : void 0;
34478
+ if (hit && hit.key === key) return hit;
34479
+ const built = { symbols: buildSymbolLexicon(store), files: buildFileLexicon(store) };
34480
+ if (key !== null) lexiconCache.set(store, { key, ...built });
34481
+ return built;
34482
+ }
34447
34483
  function replaceWithPhrase(text, before, escapedKey, after, phrase2) {
34448
34484
  if (!RE_LEADING_ARTICLE2.test(phrase2)) {
34449
34485
  return text.replace(new RegExp(`${before}${escapedKey}${after}`, "g"), phrase2);
@@ -34609,7 +34645,7 @@ function registerRenderedContributorLabels(labels) {
34609
34645
  if (trimmed.length >= 3) renderedContributorLabels.add(trimmed);
34610
34646
  }
34611
34647
  }
34612
- var SYMBOL_LABELS2, KIND_PHRASE, BUILTIN_TYPE_NAMES, DOC_COMMENT_KINDS, MAX_DOC_CHARS, RE_RESERVED2, escapeRe4, RE_LEADING_ARTICLE2, CONVENTION_FILENAMES, CONVENTION_BASENAME_MIN_FILES, CONVENTION_STEMS, FILE_TOKEN_RE, STEM_TOKEN_RE, SOURCE_EXTENSIONS, TOKEN_RE3, renderedContributorLabels;
34648
+ var SYMBOL_LABELS2, KIND_PHRASE, BUILTIN_TYPE_NAMES, DOC_COMMENT_KINDS, MAX_DOC_CHARS, LEXICON_SYMBOL_LABELS, lexiconCache, RE_RESERVED2, escapeRe4, RE_LEADING_ARTICLE2, CONVENTION_FILENAMES, CONVENTION_BASENAME_MIN_FILES, CONVENTION_STEMS, FILE_TOKEN_RE, STEM_TOKEN_RE, SOURCE_EXTENSIONS, TOKEN_RE3, renderedContributorLabels;
34613
34649
  var init_generalize_graph = __esm({
34614
34650
  "src/generalize-graph.ts"() {
34615
34651
  "use strict";
@@ -34659,6 +34695,8 @@ var init_generalize_graph = __esm({
34659
34695
  ]);
34660
34696
  DOC_COMMENT_KINDS = /* @__PURE__ */ new Set(["docstring", "explanation"]);
34661
34697
  MAX_DOC_CHARS = 600;
34698
+ LEXICON_SYMBOL_LABELS = ["Function", "Method", "Class", "Interface", "Const", "Comment"];
34699
+ lexiconCache = /* @__PURE__ */ new WeakMap();
34662
34700
  RE_RESERVED2 = /[.*+?^${}()|[\]\\]/g;
34663
34701
  escapeRe4 = (s) => s.replace(RE_RESERVED2, "\\$&");
34664
34702
  RE_LEADING_ARTICLE2 = /^(?:an?|the)\s/i;
@@ -34867,13 +34905,12 @@ async function dualAugment(opts) {
34867
34905
  let seedProvenance = "local";
34868
34906
  const calls = [];
34869
34907
  try {
34870
- const lexicon = buildSymbolLexicon(store);
34871
34908
  const hardIds = [.../* @__PURE__ */ new Set([...seedNode ? [seedNode.id] : [], ...localHits.map((h) => h.id)])].filter((nid) => {
34872
34909
  const n = seedNode && nid === seedNode.id ? seedNode : store.getNode(nid);
34873
34910
  return !!n && isHardBridge(n);
34874
34911
  });
34875
34912
  const softText = queryText ?? (seedNode && BRIDGE_LABELS.has(seedNode.label) ? seedNode.description : void 0);
34876
- const softQ = softText ? generalizeSymbols(softText, lexicon, 1) : void 0;
34913
+ const softQ = softText ? generalizeSymbols(softText, lexiconsFor(store).symbols, 1) : void 0;
34877
34914
  if (seedNode?.label === "Package") {
34878
34915
  calls.push(
34879
34916
  cloud.packages(seedNode.id).then((pn) => {
@@ -43927,7 +43964,7 @@ __export(mcp_exports, {
43927
43964
  import { existsSync as existsSync17, readFileSync as readFileSync16 } from "node:fs";
43928
43965
  import { resolve as resolve4 } from "node:path";
43929
43966
  function collectEnrichmentPulls(store, opts = {}) {
43930
- const pending = store.findNodesByLabel("Solution").filter((s) => s.attrs["enrichmentPending"] === true).filter((s) => !opts.onlyUnsurfaced || s.attrs["enrichmentSurfaced"] !== true);
43967
+ const pending = store.findLiveNodesByAttr("Solution", "enrichmentPending", 1).filter((s) => s.attrs["enrichmentPending"] === true).filter((s) => !opts.onlyUnsurfaced || s.attrs["enrichmentSurfaced"] !== true);
43931
43968
  const byEpisode = /* @__PURE__ */ new Map();
43932
43969
  for (const s of pending) {
43933
43970
  const ep = s.attrs["episodeId"] ?? s.id;
@@ -44044,20 +44081,8 @@ function searchGraph(store, query, limit) {
44044
44081
  const terms = q.split(/\s+/).filter((t) => t.length >= 2);
44045
44082
  const pool = Math.max(limit * 3, 60);
44046
44083
  const raw2 = /* @__PURE__ */ new Map();
44047
- const collect2 = (nodes) => {
44048
- for (const n of nodes) {
44049
- const e = raw2.get(n.id);
44050
- if (e) e.matched++;
44051
- else raw2.set(n.id, { node: n, matched: 1 });
44052
- }
44053
- };
44054
- if (terms.length <= 1) {
44055
- collect2(store.searchNodes({ descriptionLike: q, limit: pool }));
44056
- } else {
44057
- for (const term of terms) {
44058
- collect2(store.searchNodes({ descriptionLike: term, limit: 200 }));
44059
- }
44060
- }
44084
+ const scored = !q ? store.searchNodes({ limit: pool }).map((node2) => ({ node: node2, matched: 1 })) : terms.length <= 1 ? store.searchDescriptionTerms([q], pool) : store.searchDescriptionTerms(terms, Math.max(pool, 600));
44085
+ for (const hit of scored) raw2.set(hit.node.id, hit);
44061
44086
  const merged = /* @__PURE__ */ new Map();
44062
44087
  const add = (node2, matched, via) => {
44063
44088
  const e = merged.get(node2.id);
@@ -82779,7 +82804,7 @@ function createWatchBreaker(deps) {
82779
82804
  }
82780
82805
 
82781
82806
  // src/engine.ts
82782
- var DAEMON_VERSION = true ? "2.0.20-dev.3682" : "2.0.0-alpha.0";
82807
+ var DAEMON_VERSION = true ? "2.0.20-dev.3704" : "2.0.0-alpha.0";
82783
82808
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
82784
82809
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
82785
82810
  var GIT_OP_MUTE_MS = 4e3;
@@ -86810,21 +86835,7 @@ function liveBackoffMs(failures) {
86810
86835
 
86811
86836
  // src/drain-build.ts
86812
86837
  init_generalize_graph();
86813
- var LEXICON_SYMBOL_LABELS = ["Function", "Method", "Class", "Interface", "Const", "Comment"];
86814
- function codeGraphKey(store) {
86815
- const files = store.labelFingerprint?.(["File"]);
86816
- if (files === void 0) return null;
86817
- return [files, ...LEXICON_SYMBOL_LABELS.map((l) => store.countNodesByLabel(l))].join("|");
86818
- }
86819
- var lexiconCache = /* @__PURE__ */ new WeakMap();
86820
- function lexiconsFor(store) {
86821
- const key = codeGraphKey(store);
86822
- const hit = key !== null ? lexiconCache.get(store) : void 0;
86823
- if (hit && hit.key === key) return hit;
86824
- const built = { symbols: buildSymbolLexicon(store), files: buildFileLexicon(store) };
86825
- if (key !== null) lexiconCache.set(store, { key, ...built });
86826
- return built;
86827
- }
86838
+ init_generalize_graph();
86828
86839
  function buildDrainContext(store, input) {
86829
86840
  return buildContextIngest(store, input.profile, input.daemonVersion, input.ignorePatterns, {
86830
86841
  ...input.includePackages !== void 0 ? { includePackages: input.includePackages } : {}
@@ -94177,7 +94188,7 @@ async function cmdInit() {
94177
94188
  }
94178
94189
  console.log("");
94179
94190
  console.log("connecting your cloud account...");
94180
- await cmdLoginOAuth(cfgNow);
94191
+ await cmdLoginOAuth(cfgNow, false, false);
94181
94192
  cfgNow = loadConfig();
94182
94193
  if (!hasCloudCredential(cfgNow)) {
94183
94194
  console.error("init requires login \u2014 re-run `errata init`, or `errata init --no-login` to stay unlinked.");
@@ -94820,7 +94831,7 @@ async function warnIfApprovalUnreachable(url2) {
94820
94831
  } catch {
94821
94832
  }
94822
94833
  }
94823
- async function cmdLoginOAuth(cfg, useBrowserLoopback = false) {
94834
+ async function cmdLoginOAuth(cfg, useBrowserLoopback = false, linkAfterLogin = true) {
94824
94835
  const inspection = await inspectCloudEndpoint(cfg.cloudUrl);
94825
94836
  try {
94826
94837
  assertCloudEndpointAllowed(cfg.cloudUrl, inspection);
@@ -94857,7 +94868,7 @@ async function cmdLoginOAuth(cfg, useBrowserLoopback = false) {
94857
94868
  nextCfg.email = me.handle;
94858
94869
  saveConfig(nextCfg);
94859
94870
  console.log(`logged in as ${me.handle} (${me.tier}) \u2014 tokens stored at ${globalConfigPath()}`);
94860
- await linkRegisteredWorkspaces(nextCfg);
94871
+ if (linkAfterLogin) await linkRegisteredWorkspaces(nextCfg);
94861
94872
  } catch (err2) {
94862
94873
  console.error(`signed in, but identity check failed: ${err2 instanceof Error ? err2.message : err2}`);
94863
94874
  console.error(` credentials were not stored; try again or paste a key: errata login --token <key>`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inerrata-corporation/errata",
3
- "version": "2.0.20-dev.3682",
3
+ "version": "2.0.20-dev.3704",
4
4
  "description": "errata - local-first observation engine for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {
package/pass-worker.mjs CHANGED
@@ -25581,6 +25581,11 @@ CREATE INDEX IF NOT EXISTS nodes_live_description ON nodes(description, label) W
25581
25581
  -- Problems by the file their anchor hint names: the harvest upgrades hints for
25582
25582
  -- every edited file of every turn, and a scan parses every Problem's attrs.
25583
25583
  CREATE INDEX IF NOT EXISTS nodes_anchor_hint_path ON nodes(json_extract(attrs_json, '$.anchorHint.path')) WHERE valid_to IS NULL;
25584
+ -- Nodes still waiting on a root-cause ask. The MCP server checks this on EVERY
25585
+ -- tool response (the enrichment piggyback), so it must not parse every
25586
+ -- Solution's and Problem's attrs per call. Not partial: the Problem pull reads
25587
+ -- closed versions too.
25588
+ CREATE INDEX IF NOT EXISTS nodes_enrichment_pending ON nodes(json_extract(attrs_json, '$.enrichmentPending'));
25584
25589
  `;
25585
25590
  function encodeEmbedding(emb) {
25586
25591
  if (!emb || emb.length === 0) return null;
@@ -26238,7 +26243,10 @@ var SqliteGraphStore = class {
26238
26243
  }));
26239
26244
  }
26240
26245
  findAllVersionsByLabel(label, attribute) {
26241
- const rows = attribute ? this.db.prepare("SELECT * FROM nodes WHERE label = ? AND json_extract(attrs_json, ?) = ?").all(label, `$.${attribute.path}`, attribute.value) : this.stmts.findByLabelAll.all(label);
26246
+ if (attribute && !/^[A-Za-z0-9_]+(\.[A-Za-z0-9_]+)*$/.test(attribute.path)) {
26247
+ throw new Error(`invalid attr path: ${attribute.path}`);
26248
+ }
26249
+ const rows = attribute ? this.db.prepare(`SELECT * FROM nodes WHERE json_extract(attrs_json, '$.${attribute.path}') = ? AND label = ?`).all(attribute.value, label) : this.stmts.findByLabelAll.all(label);
26242
26250
  return rows.map(rowToNode);
26243
26251
  }
26244
26252
  searchNodes(opts) {
@@ -26263,6 +26271,21 @@ var SqliteGraphStore = class {
26263
26271
  const rows = this.db.prepare(sql).all(params);
26264
26272
  return rows.map(rowToNode);
26265
26273
  }
26274
+ searchDescriptionTerms(terms, limit) {
26275
+ if (terms.length === 0) return [];
26276
+ const score2 = terms.map(() => "(description LIKE ?)").join(" + ");
26277
+ const rows = this.db.prepare(
26278
+ `SELECT n.*, h.m AS matched
26279
+ FROM (SELECT rowid AS rid, ${score2} AS m
26280
+ FROM nodes INDEXED BY nodes_live_description
26281
+ WHERE valid_to IS NULL) h
26282
+ JOIN nodes n ON n.rowid = h.rid
26283
+ WHERE h.m > 0
26284
+ ORDER BY h.m DESC, n.page_rank DESC, n.last_updated_at DESC
26285
+ LIMIT ?`
26286
+ ).all(...terms.map((t) => `%${t}%`), Math.max(1, limit));
26287
+ return rows.map((r) => ({ node: rowToNode(r), matched: Number(r.matched) }));
26288
+ }
26266
26289
  typedEdgeStmt(sql) {
26267
26290
  let stmt = this.typedEdgeStmts.get(sql);
26268
26291
  if (!stmt) {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "errata-context",
3
- "version": "2.0.20-dev.3682",
3
+ "version": "2.0.20-dev.3704",
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
- 1a4968f9838a28217386e7d354ba511c588e16739ece36e6bbb7f6feeaa8a4c2 .codex-plugin/plugin.json
1
+ afb5db840916d7c565672ed92c16364144acdada84a9eceaa9ae0b1204277214 .codex-plugin/plugin.json
2
2
  a7bebae9fb01c838d6c75fc784129e28be571233fa66ff5ee8039b574f35ccf7 assets/icon.png
3
3
  fc38b64e4df1e0b72c35764bef6c4c05430d97c9009ad0ecc8a9e75b4deab232 configure-local.mjs
4
4
  73dc6028b3b070257c7c31f252d11e55a9e096f4aed0f187f10cb21716e1e6d7 dist/client.js