@inerrata-corporation/errata 2.0.2-dev.615 → 2.0.2-dev.629

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 +87 -15
  2. package/package.json +1 -1
package/errata.mjs CHANGED
@@ -48115,6 +48115,48 @@ var init_outbox = __esm({
48115
48115
  }
48116
48116
  });
48117
48117
 
48118
+ // src/message-accumulator.ts
48119
+ function createMessageAccumulator(opts = {}) {
48120
+ const ttlMs = opts.ttlMs ?? MESSAGE_BUFFER_TTL_MS;
48121
+ const buffers = /* @__PURE__ */ new Map();
48122
+ const evictStale = (nowMs) => {
48123
+ for (const [id, b] of buffers) {
48124
+ if (nowMs - b.lastAt > ttlMs) buffers.delete(id);
48125
+ }
48126
+ };
48127
+ return {
48128
+ accumulate(messageId, index, delta, isFinal, nowMs) {
48129
+ if (!messageId) return isFinal ? { text: delta } : null;
48130
+ evictStale(nowMs);
48131
+ let b = buffers.get(messageId);
48132
+ if (!b) {
48133
+ b = { chunks: /* @__PURE__ */ new Map(), lastAt: nowMs };
48134
+ buffers.set(messageId, b);
48135
+ }
48136
+ b.chunks.set(index, delta);
48137
+ if (isFinal) b.finalIndex = index;
48138
+ b.lastAt = nowMs;
48139
+ if (b.finalIndex === void 0) return null;
48140
+ for (let i2 = 0; i2 <= b.finalIndex; i2++) {
48141
+ if (!b.chunks.has(i2)) return null;
48142
+ }
48143
+ const text = [...b.chunks.entries()].sort((a, z2) => a[0] - z2[0]).map(([, d]) => d).join("");
48144
+ buffers.delete(messageId);
48145
+ return { text };
48146
+ },
48147
+ size() {
48148
+ return buffers.size;
48149
+ }
48150
+ };
48151
+ }
48152
+ var MESSAGE_BUFFER_TTL_MS;
48153
+ var init_message_accumulator = __esm({
48154
+ "src/message-accumulator.ts"() {
48155
+ "use strict";
48156
+ MESSAGE_BUFFER_TTL_MS = 5 * 60 * 1e3;
48157
+ }
48158
+ });
48159
+
48118
48160
  // src/webui.ts
48119
48161
  var webui_exports = {};
48120
48162
  __export(webui_exports, {
@@ -48125,6 +48167,9 @@ __export(webui_exports, {
48125
48167
  recallForFile: () => recallForFile,
48126
48168
  recallForTool: () => recallForTool
48127
48169
  });
48170
+ function accumulateMessageDelta(messageId, index, delta, isFinal, nowMs) {
48171
+ return messageAccumulator.accumulate(messageId, index, delta, isFinal, nowMs);
48172
+ }
48128
48173
  function fileUriToFsPath(raw2) {
48129
48174
  let p = raw2.replace(/^file:\/\//, "").replace(/\\/g, "/");
48130
48175
  if (/^\/[A-Za-z]:/.test(p)) p = p.slice(1);
@@ -48512,17 +48557,16 @@ function buildWebUi(deps) {
48512
48557
  } catch {
48513
48558
  return c.json({ error: "bad-json" }, 400);
48514
48559
  }
48515
- const text = String(body2["delta"] ?? "");
48560
+ const delta = String(body2["delta"] ?? "");
48516
48561
  const sessionId = String(body2["session_id"] ?? "");
48517
48562
  const messageId = typeof body2["message_id"] === "string" ? body2["message_id"] : void 0;
48518
- if (body2["final"] === false) return c.json({ ok: true, skipped: "partial" });
48519
- if (typeof body2["index"] === "number" && body2["index"] > 0) {
48520
- console.warn(`[errata] MessageDisplay arrived chunked (index ${body2["index"]}) \u2014 delta accumulation needed, text may be partial`);
48521
- }
48522
- if (text && sessionId && deps.onMessage) {
48523
- deps.onMessage({ sessionId, text, ...messageId ? { messageId } : {} });
48563
+ const index = typeof body2["index"] === "number" ? body2["index"] : 0;
48564
+ const isFinal = body2["final"] !== false;
48565
+ const whole = accumulateMessageDelta(messageId, index, delta, isFinal, Date.now());
48566
+ if (whole !== null && whole.text && sessionId && deps.onMessage) {
48567
+ deps.onMessage({ sessionId, text: whole.text, ...messageId ? { messageId } : {} });
48524
48568
  }
48525
- return c.json({ ok: true });
48569
+ return c.json({ ok: true, ...whole === null ? { buffered: true } : {} });
48526
48570
  });
48527
48571
  app.post("/api/session-end", async (c) => {
48528
48572
  let body2;
@@ -48735,7 +48779,7 @@ function proposalToIngest(p, profile, daemonVersion) {
48735
48779
  payloadDigest: p.id
48736
48780
  };
48737
48781
  }
48738
- var wsPackagesCache, WS_PACKAGES_TTL_MS, loggedToolSessions, META_LABELS;
48782
+ var messageAccumulator, wsPackagesCache, WS_PACKAGES_TTL_MS, loggedToolSessions, META_LABELS;
48739
48783
  var init_webui = __esm({
48740
48784
  "src/webui.ts"() {
48741
48785
  "use strict";
@@ -48747,6 +48791,8 @@ var init_webui = __esm({
48747
48791
  init_vfile();
48748
48792
  init_tool_index();
48749
48793
  init_outbox();
48794
+ init_message_accumulator();
48795
+ messageAccumulator = createMessageAccumulator();
48750
48796
  wsPackagesCache = /* @__PURE__ */ new WeakMap();
48751
48797
  WS_PACKAGES_TTL_MS = 6e4;
48752
48798
  loggedToolSessions = /* @__PURE__ */ new Set();
@@ -54754,7 +54800,7 @@ function startLoopLagMonitor(thresholdMs = 1e3) {
54754
54800
  }
54755
54801
 
54756
54802
  // src/engine.ts
54757
- var DAEMON_VERSION = true ? "2.0.2-dev.615" : "2.0.0-alpha.0";
54803
+ var DAEMON_VERSION = true ? "2.0.2-dev.629" : "2.0.0-alpha.0";
54758
54804
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
54759
54805
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
54760
54806
  var GIT_OP_MUTE_MS = 4e3;
@@ -57285,9 +57331,12 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
57285
57331
  if (outs.length === 0) continue;
57286
57332
  const dg = digest(outs.map(({ e, wireTo }) => `${e.type}>${wireTo}`).sort());
57287
57333
  const owner = store.getNode(sourceId) ?? opts.sharedStore?.getNode(sourceId);
57288
- if (owner?.attrs["semanticEdgesContributedDigest"] === dg) continue;
57289
- semanticEdgeDigests[sourceId] = dg;
57290
- for (const { e, wireTo } of outs) edges.push({ ...e, from: wireFrom, to: wireTo, attrs: {} });
57334
+ const digestSkip = owner?.attrs["semanticEdgesContributedDigest"] === dg;
57335
+ if (!digestSkip) semanticEdgeDigests[sourceId] = dg;
57336
+ for (const { e, wireTo } of outs) {
57337
+ if (digestSkip && !shippedById.has(e.to)) continue;
57338
+ edges.push({ ...e, from: wireFrom, to: wireTo, attrs: {} });
57339
+ }
57291
57340
  }
57292
57341
  if (nodes.length === 0 && anchorEdges.length === 0 && edges.length === 0) return null;
57293
57342
  let symbolSummaries;
@@ -57312,6 +57361,29 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
57312
57361
  if (count > 0) symbolSummaries = sidecar;
57313
57362
  }
57314
57363
  edges.push(...anchorEdges);
57364
+ const bindingEndpoints = /* @__PURE__ */ new Set();
57365
+ for (const e of edges) {
57366
+ if (e.type === "CAUSED_BY" || e.type === "SOLVED_BY") {
57367
+ bindingEndpoints.add(e.from);
57368
+ bindingEndpoints.add(e.to);
57369
+ }
57370
+ }
57371
+ const heldOrphans = /* @__PURE__ */ new Set();
57372
+ for (const wn of nodes) {
57373
+ if (wn.label !== "RootCause" && wn.label !== "Solution") continue;
57374
+ const src = store.getNode(wn.id) ?? opts.sharedStore?.getNode(wn.id);
57375
+ if (typeof src?.attrs["contributedAtSeq"] === "number") continue;
57376
+ if (bindingEndpoints.has(wn.id)) continue;
57377
+ heldOrphans.add(wn.id);
57378
+ }
57379
+ const shippableNodes = heldOrphans.size === 0 ? nodes : nodes.filter((n) => !heldOrphans.has(n.id));
57380
+ const shippableEdges = heldOrphans.size === 0 ? edges : edges.filter((e) => !heldOrphans.has(e.from) && !heldOrphans.has(e.to));
57381
+ if (heldOrphans.size > 0) {
57382
+ console.warn(
57383
+ `[errata] held ${heldOrphans.size} causal-orphan node(s) \u2014 no shippable binding edge this drain (VS-orphan-gate)`
57384
+ );
57385
+ }
57386
+ if (shippableNodes.length === 0 && shippableEdges.length === 0) return null;
57315
57387
  const base = {
57316
57388
  daemonVersion,
57317
57389
  // Origin key (= project, the salted `wp_…`) — the door stamps it onto created
@@ -57323,8 +57395,8 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
57323
57395
  // Context nodes FIRST: a chunked drain (cloud-client, 25-node chunks) then
57324
57396
  // co-locates the few Language/Package stubs with the first instance chunk,
57325
57397
  // maximizing in-payload endpoint resolution.
57326
- nodes: [...contextNodes, ...nodes],
57327
- edges,
57398
+ nodes: [...contextNodes, ...shippableNodes],
57399
+ edges: shippableEdges,
57328
57400
  // Spread-if-present: an absent sidecar keeps `base` — and therefore the
57329
57401
  // payloadDigest — byte-identical to the pre-sidecar batch (backward compat).
57330
57402
  ...symbolSummaries ? { symbolSummaries } : {}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inerrata-corporation/errata",
3
- "version": "2.0.2-dev.615",
3
+ "version": "2.0.2-dev.629",
4
4
  "description": "errata - local-first observation engine for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {