@inerrata-corporation/errata 2.0.22-dev.4122 → 2.0.22-dev.4127

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
@@ -76390,6 +76390,109 @@ init_webui();
76390
76390
  init_config();
76391
76391
  init_lock();
76392
76392
 
76393
+ // src/activity-feed.ts
76394
+ var LABEL_MAX = 120;
76395
+ var DEFAULT_TAIL = 20;
76396
+ function oneLine(text) {
76397
+ const flat = text.replace(/\s+/g, " ").trim();
76398
+ if (flat.length <= LABEL_MAX) return flat;
76399
+ const points = Array.from(flat);
76400
+ return points.length > LABEL_MAX ? `${points.slice(0, LABEL_MAX - 1).join("")}\u2026` : flat;
76401
+ }
76402
+ var ActivityFeed = class {
76403
+ constructor(capacity = 500) {
76404
+ this.capacity = capacity;
76405
+ }
76406
+ events = [];
76407
+ seq = 0;
76408
+ // The engine harvests a turn twice by design (mid-turn + turn-final) and the
76409
+ // sync lanes can re-decide the same node; one tag must flash once.
76410
+ recentKeys = /* @__PURE__ */ new Map();
76411
+ record(input) {
76412
+ const label = oneLine(input.label);
76413
+ if (!label) return null;
76414
+ const key = input.dedupKey ?? `${input.kind}|${input.workspace ?? ""}|${input.tag ?? ""}|${label}`;
76415
+ if (this.recentKeys.has(key)) return null;
76416
+ const event = {
76417
+ seq: ++this.seq,
76418
+ kind: input.kind,
76419
+ at: input.at ?? Date.now(),
76420
+ label,
76421
+ ...input.workspace ? { workspace: input.workspace } : {},
76422
+ ...input.tag ? { tag: input.tag } : {}
76423
+ };
76424
+ this.events.push(event);
76425
+ this.recentKeys.set(key, event.seq);
76426
+ while (this.events.length > this.capacity) this.events.shift();
76427
+ if (this.recentKeys.size > this.capacity * 2) {
76428
+ const floor = this.events[0]?.seq ?? this.seq;
76429
+ for (const [k, s] of this.recentKeys) if (s < floor) this.recentKeys.delete(k);
76430
+ }
76431
+ return event;
76432
+ }
76433
+ since(seq) {
76434
+ const events = seq === void 0 || !Number.isFinite(seq) || seq > this.seq ? this.events.slice(-DEFAULT_TAIL) : this.events.filter((e) => e.seq > seq);
76435
+ return { seq: this.seq, events };
76436
+ }
76437
+ };
76438
+ var activityFeed = new ActivityFeed();
76439
+ function recordHarvest(feed, plan, ctx) {
76440
+ let n = 0;
76441
+ const put = (tag, label) => {
76442
+ if (!label) return;
76443
+ const ok = feed.record({
76444
+ kind: "captured",
76445
+ tag,
76446
+ label,
76447
+ ...ctx.workspace ? { workspace: ctx.workspace } : {},
76448
+ ...ctx.at !== void 0 ? { at: ctx.at } : {},
76449
+ dedupKey: `captured|${ctx.sessionId}|${tag}|${oneLine(label)}`
76450
+ });
76451
+ if (ok) n++;
76452
+ };
76453
+ for (const p of plan.problems) {
76454
+ const tag = p.kind === "vulnerability" ? p.assessment === "suspected" ? "?vuln" : "vuln" : p.kind === "problem" ? "!" : p.kind;
76455
+ put(tag, p.statement);
76456
+ }
76457
+ for (const f of plan.fixes) put("fix", f.fixNote ?? f.boundStatement ?? (f.problemId ? ctx.describe(f.problemId) : void 0));
76458
+ for (const r of plan.refutes) put("refute", ctx.describe(r.nodeId));
76459
+ for (const c of plan.corroborations) put("confirm", ctx.describe(c.nodeId));
76460
+ for (const a of plan.attempts) put(a.outcome, a.note);
76461
+ for (const t of plan.triages) put("cause", t.causeDescription ?? ctx.describe(t.causeId));
76462
+ return n;
76463
+ }
76464
+ var harvestFeedFailed = false;
76465
+ function recordHarvestSafely(...args2) {
76466
+ try {
76467
+ return recordHarvest(...args2);
76468
+ } catch (err2) {
76469
+ if (!harvestFeedFailed) {
76470
+ harvestFeedFailed = true;
76471
+ console.warn("[errata] activity feed record failed (capture unaffected):", err2 instanceof Error ? err2.message : err2);
76472
+ }
76473
+ return 0;
76474
+ }
76475
+ }
76476
+ function mountActivityRoute(app, feed) {
76477
+ app.get("/api/activity", (c) => {
76478
+ const raw2 = c.req.query("since");
76479
+ return c.json(feed.since(raw2 === void 0 || raw2 === "" ? void 0 : Number(raw2)));
76480
+ });
76481
+ }
76482
+ var KNOWLEDGE_LABELS2 = {
76483
+ Problem: "!",
76484
+ Solution: "fix",
76485
+ RootCause: "cause",
76486
+ Pattern: "pattern",
76487
+ Vulnerability: "vuln",
76488
+ Principle: "principle"
76489
+ };
76490
+ function knowledgeTag(label, attrs) {
76491
+ const tag = KNOWLEDGE_LABELS2[label];
76492
+ if (tag === "!" && typeof attrs["kind"] === "string" && attrs["kind"] !== "problem") return attrs["kind"];
76493
+ return tag;
76494
+ }
76495
+
76393
76496
  // src/engine.ts
76394
76497
  import { execFileSync as execFileSync5 } from "node:child_process";
76395
76498
  import { existsSync as existsSync28, statSync as statSync9, appendFileSync as appendFileSync4, readdirSync as readdirSync11, renameSync as renameSync4, readFileSync as readFileSync32, writeFileSync as writeFileSync23 } from "node:fs";
@@ -85062,7 +85165,7 @@ function createWatchBreaker(deps) {
85062
85165
  }
85063
85166
 
85064
85167
  // src/engine.ts
85065
- var DAEMON_VERSION = true ? "2.0.22-dev.4122" : "2.0.0-alpha.0";
85168
+ var DAEMON_VERSION = true ? "2.0.22-dev.4127" : "2.0.0-alpha.0";
85066
85169
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
85067
85170
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
85068
85171
  var GIT_OP_MUTE_MS = 4e3;
@@ -86289,6 +86392,11 @@ function createWorkspaceEngine(opts) {
86289
86392
  sessionId,
86290
86393
  ...touched.size > 0 ? { sessionTouchedIds: touched } : {}
86291
86394
  });
86395
+ recordHarvestSafely(activityFeed, plan, {
86396
+ workspace: profile.name,
86397
+ sessionId,
86398
+ describe: (id) => store.getNode(id)?.description
86399
+ });
86292
86400
  priorEdges += plan.priorEdges;
86293
86401
  corroboratedEdges += plan.corroboratedEdges;
86294
86402
  citeAnchorsAccrued += plan.citeAnchorsAccrued;
@@ -93764,8 +93872,19 @@ async function startMultiDaemon(opts = {}) {
93764
93872
  const localId = instances.contextNodeSources[decision.canonicalId] ?? decision.canonicalId;
93765
93873
  const owner = owningStore(localId);
93766
93874
  if (!sent || !owner || blocked.has(sent.id)) continue;
93767
- const attrs = acceptedInstanceReceipt(owner.n, sent, decision, destinationKey, owner.s === store) ?? withdrawnInstanceReceipt(owner.n, destinationKey, decision, (key) => store.getMeta?.(key) ?? sharedStore.getMeta?.(key), owner.s === store);
93875
+ const accepted = acceptedInstanceReceipt(owner.n, sent, decision, destinationKey, owner.s === store);
93876
+ const attrs = accepted ?? withdrawnInstanceReceipt(owner.n, destinationKey, decision, (key) => store.getMeta?.(key) ?? sharedStore.getMeta?.(key), owner.s === store);
93768
93877
  if (attrs) owner.s.updateNode(localId, { attrs });
93878
+ const tag = accepted ? knowledgeTag(owner.n.label, owner.n.attrs) : void 0;
93879
+ if (tag) {
93880
+ activityFeed.record({
93881
+ kind: "ingested",
93882
+ tag,
93883
+ label: owner.n.description,
93884
+ workspace: projectName,
93885
+ dedupKey: `ingested|${localId}|${owner.n.description}`
93886
+ });
93887
+ }
93769
93888
  }
93770
93889
  noteFlushProgress(p.accepted, p.nodeIds.length, `instances ${p.chunkIndex}/${p.totalChunks}`);
93771
93890
  }
@@ -93836,6 +93955,19 @@ async function startMultiDaemon(opts = {}) {
93836
93955
  };
93837
93956
  for (const id of blocked) noteRefused(id, "blocked-gzip", () => blockedRepeat++);
93838
93957
  for (const [id, why] of rejected) noteRefused(id, why, () => rejectedRepeat++);
93958
+ for (const { id, reason } of nowHeld) {
93959
+ const owner = owningStore(id);
93960
+ const tag = owner ? knowledgeTag(owner.n.label, owner.n.attrs) : void 0;
93961
+ if (owner && tag) {
93962
+ activityFeed.record({
93963
+ kind: "rejected",
93964
+ tag,
93965
+ label: `${owner.n.description} \u2014 ${reason}`,
93966
+ workspace: projectName,
93967
+ dedupKey: `rejected|${id}|${owner.n.description}`
93968
+ });
93969
+ }
93970
+ }
93839
93971
  if (nowHeld.length > 0) {
93840
93972
  console.warn(
93841
93973
  `[sync\u2192cloud] [${projectName}] instances: HOLDING ${nowHeld.length} node(s) \u2014 refused identically ${SHIP_TERMINAL_REFUSALS}\xD7 on unchanged text; not re-sent until the text changes: ` + nowHeld.map(({ id, reason }) => `${id} "${owningStore(id)?.n.description.slice(0, 60) ?? ""}": ${reason}`).join(" | ")
@@ -94097,6 +94229,7 @@ async function startMultiDaemon(opts = {}) {
94097
94229
  return c.json({ error: err2 instanceof Error ? err2.message : String(err2) }, 503);
94098
94230
  }
94099
94231
  });
94232
+ mountActivityRoute(app, activityFeed);
94100
94233
  app.post("/api/tick", async (c) => {
94101
94234
  try {
94102
94235
  return c.json({ reports: Object.fromEntries(await daemon.tickAll()) });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inerrata-corporation/errata",
3
- "version": "2.0.22-dev.4122",
3
+ "version": "2.0.22-dev.4127",
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.22-dev.4122",
3
+ "version": "2.0.22-dev.4127",
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
- 5ba58327da38d3a9b52ab2bc97c6999d2015ca1e410205e55f10e0e24a197693 .codex-plugin/plugin.json
1
+ 78dffda4706af8936449106b69d53de281d602a03d7e3aec97bf85eb19c5ddc5 .codex-plugin/plugin.json
2
2
  a7bebae9fb01c838d6c75fc784129e28be571233fa66ff5ee8039b574f35ccf7 assets/icon.png
3
3
  fc38b64e4df1e0b72c35764bef6c4c05430d97c9009ad0ecc8a9e75b4deab232 configure-local.mjs
4
4
  73dc6028b3b070257c7c31f252d11e55a9e096f4aed0f187f10cb21716e1e6d7 dist/client.js