@inerrata-corporation/errata 2.0.23-dev.4881 → 2.0.23-dev.4900

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
@@ -58885,7 +58885,14 @@ function buildWebUi(deps) {
58885
58885
  }
58886
58886
  }
58887
58887
  }
58888
- if ((event === "PostToolUse" || event === "PreToolUse") && (recall || refreshed)) {
58888
+ let taskPriors = null;
58889
+ if ((event === "PostToolUse" || event === "PreToolUse") && audience.subagent === null && audience.sessionId && deps.takeTaskPriors) {
58890
+ try {
58891
+ taskPriors = deps.takeTaskPriors(audience.sessionId);
58892
+ } catch {
58893
+ }
58894
+ }
58895
+ if ((event === "PostToolUse" || event === "PreToolUse") && (recall || refreshed || taskPriors)) {
58889
58896
  const showCard = recallCardEnabled();
58890
58897
  const { sessionId, subagent } = audience;
58891
58898
  const raw2 = recall?.card ?? refreshed?.card ?? null;
@@ -58895,7 +58902,7 @@ function buildWebUi(deps) {
58895
58902
  else rememberCard(sessionId, card);
58896
58903
  }
58897
58904
  const line = showCard && recall && card ? renderRecallLine(card) : null;
58898
- const additionalContext = [recall?.context, refreshed?.additionalContext].filter(Boolean).join("\n\n");
58905
+ const additionalContext = [recall?.context, refreshed?.additionalContext, taskPriors].filter(Boolean).join("\n\n");
58899
58906
  return c.json({
58900
58907
  ...line ? { systemMessage: line } : {},
58901
58908
  hookSpecificOutput: { hookEventName: hookEvent, additionalContext }
@@ -59004,6 +59011,15 @@ ${delta}${cue}`;
59004
59011
  const { sessionId: sid, contextKey: contextKey2, subagent, agentId } = hookAudience(body2);
59005
59012
  noteSessionFrom(c.req.header(ORIGIN_HEADER), body2);
59006
59013
  const hookEvent = String(body2["hook_event_name"] ?? "UserPromptSubmit");
59014
+ if (hookEvent === "UserPromptSubmit" && subagent === null && sid && typeof body2["prompt"] === "string" && deps.onTaskPrompt) {
59015
+ const prompt = body2["prompt"];
59016
+ setImmediate(() => {
59017
+ try {
59018
+ deps.onTaskPrompt(sid, prompt);
59019
+ } catch {
59020
+ }
59021
+ });
59022
+ }
59007
59023
  const atPrompt = hookEvent === "UserPromptSubmit" || hookEvent === "SessionStart" || hookEvent === "SubagentStart";
59008
59024
  if (sid && recallCardEnabled() && atPrompt) {
59009
59025
  setImmediate(() => {
@@ -87529,6 +87545,100 @@ function createIntentState(ttlMs = INTENT_TTL_MS) {
87529
87545
  };
87530
87546
  }
87531
87547
 
87548
+ // src/engine.ts
87549
+ init_mcp();
87550
+
87551
+ // src/task-priors.ts
87552
+ function taskPriorsEnabled(env2 = process.env) {
87553
+ return /^(1|on|true|yes)$/i.test((env2["ERRATA_TASK_PRIORS"] ?? "").trim());
87554
+ }
87555
+ var TASK_PRIORS_FLOOR = 0.45;
87556
+ var TASK_PRIORS_BAND = 0.15;
87557
+ var TASK_PRIORS_MAX = 5;
87558
+ var TASK_QUERY_MAX_CHARS = 600;
87559
+ var KNOWLEDGE = /* @__PURE__ */ new Set(["Problem", "RootCause", "Solution", "Pattern", "Comment", "Claim", "Vulnerability"]);
87560
+ var clip2 = (s, n) => s.length > n ? `${s.slice(0, n - 1)}\u2026` : s;
87561
+ var oneLine2 = (s) => String(s ?? "").replace(/\s+/g, " ").trim();
87562
+ function pickTaskHits(result) {
87563
+ const rows = Array.isArray(result) ? result : result?.results;
87564
+ if (!Array.isArray(rows)) return [];
87565
+ const relevanceOf = (r) => Number(r["why"]?.relevance ?? 0);
87566
+ const knowledge = rows.filter((r) => KNOWLEDGE.has(String(r["label"] ?? "")));
87567
+ const best = Math.max(0, ...knowledge.map(relevanceOf));
87568
+ const cut = Math.max(TASK_PRIORS_FLOOR, best - TASK_PRIORS_BAND);
87569
+ const hits = [];
87570
+ for (const r of knowledge) {
87571
+ const label = String(r["label"]);
87572
+ const relevance = relevanceOf(r);
87573
+ if (!(relevance >= cut)) continue;
87574
+ const chain2 = r["chain"];
87575
+ hits.push({
87576
+ id: String(r["cite"] ?? r["id"]),
87577
+ label,
87578
+ text: oneLine2(r["name"] ?? r["description"]),
87579
+ relevance,
87580
+ ...typeof r["lifecycle"] === "string" ? { lifecycle: r["lifecycle"] } : {},
87581
+ ...chain2?.cause?.text ? { cause: oneLine2(chain2.cause.text) } : {},
87582
+ ...chain2?.fix?.text ? { fix: oneLine2(chain2.fix.text) } : {}
87583
+ });
87584
+ if (hits.length >= TASK_PRIORS_MAX) break;
87585
+ }
87586
+ return hits;
87587
+ }
87588
+ function renderTaskPriors(query, hits, addendum) {
87589
+ const lines = [
87590
+ addendum ? "### \u{1F3AF} errata \u2014 more for this task, from the Errata Network" : "### \u{1F3AF} errata \u2014 what the graph already knows about this task",
87591
+ addendum ? "_The Network side of the search on your task finished; these weren't in the earlier list._" : `_errata searched its graph for your task ("${clip2(oneLine2(query), 120)}") \u2014 no need to run that search yourself. Check a prior against the code before relying on it, and cite what you use as ([id])._`
87592
+ ];
87593
+ for (const h of hits) {
87594
+ lines.push(`- **${h.label}:** ${clip2(h.text, 220)} \`[${h.id}]\`${h.lifecycle ? ` \u2014 ${h.lifecycle}` : ""}`);
87595
+ if (h.cause) lines.push(` - cause: ${clip2(h.cause, 220)}`);
87596
+ if (h.fix) lines.push(` - fix: ${clip2(h.fix, 260)}`);
87597
+ }
87598
+ return lines.join("\n");
87599
+ }
87600
+ function createTaskPriors(search, opts) {
87601
+ const sessions = /* @__PURE__ */ new Map();
87602
+ const maxSessions = opts.maxSessions ?? 200;
87603
+ const phase = async (sessionId, state, generation, network) => {
87604
+ let result;
87605
+ try {
87606
+ result = await search(state.query, { network });
87607
+ } catch {
87608
+ return;
87609
+ }
87610
+ if (sessions.get(sessionId) !== state || state.generation !== generation) return;
87611
+ const fresh = pickTaskHits(result).filter((h) => !state.sent.has(h.id));
87612
+ if (fresh.length === 0) return;
87613
+ for (const h of fresh) state.sent.add(h.id);
87614
+ state.ready.push(renderTaskPriors(state.query, fresh, network && state.sent.size > fresh.length));
87615
+ };
87616
+ return {
87617
+ /** The session was handed a task (its prompt) or restated it (an intent fence). */
87618
+ start(sessionId, text) {
87619
+ const query = oneLine2(text).slice(0, TASK_QUERY_MAX_CHARS);
87620
+ if (!sessionId || query.length < 12) return;
87621
+ const prev = sessions.get(sessionId);
87622
+ if (prev?.query === query) return;
87623
+ const state = { query, generation: (prev?.generation ?? 0) + 1, sent: prev?.sent ?? /* @__PURE__ */ new Set(), ready: prev?.ready ?? [] };
87624
+ sessions.delete(sessionId);
87625
+ sessions.set(sessionId, state);
87626
+ if (sessions.size > maxSessions) sessions.delete(sessions.keys().next().value);
87627
+ const generation = state.generation;
87628
+ void phase(sessionId, state, generation, false).then(() => opts.network() ? phase(sessionId, state, generation, true) : void 0);
87629
+ },
87630
+ /** What is ready for this session's next tool hook, once; null when nothing is. */
87631
+ take(sessionId) {
87632
+ const state = sessions.get(sessionId);
87633
+ if (!state || state.ready.length === 0) return null;
87634
+ return state.ready.splice(0).join("\n\n");
87635
+ },
87636
+ end(sessionId) {
87637
+ sessions.delete(sessionId);
87638
+ }
87639
+ };
87640
+ }
87641
+
87532
87642
  // src/working-file-state.ts
87533
87643
  function createWorkingFileState() {
87534
87644
  const bySession = /* @__PURE__ */ new Map();
@@ -88321,7 +88431,7 @@ function createWatchBreaker(deps) {
88321
88431
  }
88322
88432
 
88323
88433
  // src/engine.ts
88324
- var DAEMON_VERSION = true ? "2.0.23-dev.4881" : "2.0.0-alpha.0";
88434
+ var DAEMON_VERSION = true ? "2.0.23-dev.4900" : "2.0.0-alpha.0";
88325
88435
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
88326
88436
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
88327
88437
  var GIT_OP_MUTE_MS = 4e3;
@@ -88756,6 +88866,16 @@ function createWorkspaceEngine(opts) {
88756
88866
  witnessParked: () => witnessQueue.length
88757
88867
  });
88758
88868
  const intents = createIntentState();
88869
+ const taskPriorsOn = taskPriorsEnabled();
88870
+ const taskPriors = createTaskPriors(
88871
+ (query, { network }) => runTool(
88872
+ "errata.search",
88873
+ { query, limit: 10 },
88874
+ store,
88875
+ network ? { cloud, ...opts.generalizeSoft ? { generalizeSoft: opts.generalizeSoft } : {} } : {}
88876
+ ),
88877
+ { network: () => !opts.skipContextWriter && (opts.syncConsent ?? consentNow().sync) && typeof cloud.search === "function" }
88878
+ );
88759
88879
  const subagents = createSubagentState();
88760
88880
  let subagentBase = null;
88761
88881
  let subagentBaseVersion = 0;
@@ -88800,7 +88920,7 @@ function createWorkspaceEngine(opts) {
88800
88920
  }
88801
88921
  }
88802
88922
  };
88803
- const clip2 = (s, n) => s.length > n ? `${s.slice(0, n - 1)}\u2026` : s;
88923
+ const clip3 = (s, n) => s.length > n ? `${s.slice(0, n - 1)}\u2026` : s;
88804
88924
  const pickReviewItems = () => {
88805
88925
  const shared = opts.sharedStore;
88806
88926
  if (!shared) return [];
@@ -88811,12 +88931,12 @@ function createWorkspaceEngine(opts) {
88811
88931
  return [{
88812
88932
  kind: "abstraction",
88813
88933
  candidate: small.candidate,
88814
- members: small.members.map((m) => ({ id: m.id, description: clip2(m.description, 110) }))
88934
+ members: small.members.map((m) => ({ id: m.id, description: clip3(m.description, 110) }))
88815
88935
  }];
88816
88936
  }
88817
88937
  }
88818
88938
  const [d] = pendingDiscriminators(shared, { limit: 1 });
88819
- return d ? [{ kind: "discriminator", route: d.route, presenting: clip2(d.presenting, 140), cause: clip2(d.cause, 140) }] : [];
88939
+ return d ? [{ kind: "discriminator", route: d.route, presenting: clip3(d.presenting, 140), cause: clip3(d.cause, 140) }] : [];
88820
88940
  } catch {
88821
88941
  return [];
88822
88942
  }
@@ -89330,9 +89450,17 @@ function createWorkspaceEngine(opts) {
89330
89450
  delete scoped.supersessionAsks;
89331
89451
  const asks = supersessionAsksFor(sessionId);
89332
89452
  if (asks.length > 0) scoped.supersessionAsks = asks;
89453
+ if (taskPriorsOn) {
89454
+ scoped.recentProblems = [];
89455
+ scoped.recentResolved = [];
89456
+ scoped.regressions = [];
89457
+ scoped.recentConstraints = [];
89458
+ scoped.motifs = [];
89459
+ delete scoped.motifPool;
89460
+ }
89333
89461
  const pendingUpdate = opts.pendingUpdate?.() ?? null;
89334
89462
  const daemonDistress = opts.daemonDistress?.() ?? null;
89335
- const reviewItems = pickReviewItems();
89463
+ const reviewItems = taskPriorsOn ? [] : pickReviewItems();
89336
89464
  const sessionIntent = intent ? statedIntentFor(intent) : null;
89337
89465
  const sessionMotifSignal = motifSignalFor(scoped, sessionIntent);
89338
89466
  const { body: body2, snapshot } = assembleAgentContext({
@@ -89341,7 +89469,7 @@ function createWorkspaceEngine(opts) {
89341
89469
  ...atCommit ? { atCommit } : {},
89342
89470
  reviewCount: pendingCount(paths),
89343
89471
  reviewUiUrl: opts.reviewUrl(),
89344
- remote: remotePriors,
89472
+ remote: taskPriorsOn ? [] : remotePriors,
89345
89473
  snapshot: scoped,
89346
89474
  ...elicit ? { edgeElicitation: { instruction: PRIOR_TAG_INSTRUCTION } } : {},
89347
89475
  ...pendingUpdate ? { pendingUpdate } : {},
@@ -89635,7 +89763,10 @@ function createWorkspaceEngine(opts) {
89635
89763
  const fenceAgent = turn.agentId ?? (sessionId.startsWith("agent-") ? sessionId.slice(6) : void 0);
89636
89764
  for (const fence of parseIntentFences(turn.text)) {
89637
89765
  if (fenceAgent) subagents.setIntent(fenceAgent, fence.intent, t);
89638
- else if (intents.set(sessionId, fence.intent, t)) refreshContextNow();
89766
+ else if (intents.set(sessionId, fence.intent, t)) {
89767
+ refreshContextNow();
89768
+ if (taskPriorsOn) taskPriors.start(sessionId, fence.intent);
89769
+ }
89639
89770
  }
89640
89771
  const plan = harvestInlineTags(store, turn.text, {
89641
89772
  sourceId: sessionLastProblem.get(sessionId),
@@ -90646,6 +90777,7 @@ B: ${b}`,
90646
90777
  return null;
90647
90778
  } : void 0;
90648
90779
  const onSessionEnd = (e) => {
90780
+ taskPriors.end(e.sessionId);
90649
90781
  if (!designRollup) return;
90650
90782
  setImmediate(() => {
90651
90783
  const convo = readConversation(e.transcriptPath);
@@ -90775,6 +90907,10 @@ B: ${b}`,
90775
90907
  onSubagentStop,
90776
90908
  noteSession,
90777
90909
  sessionContext,
90910
+ onTaskPrompt: (sessionId, prompt) => {
90911
+ if (taskPriorsOn) taskPriors.start(sessionId, prompt);
90912
+ },
90913
+ takeTaskPriors: (sessionId) => taskPriorsOn ? taskPriors.take(sessionId) : null,
90778
90914
  onHook: () => telemetry.count("hooks_fired"),
90779
90915
  onToolsObserved: (sessionId, toolNodeIds) => toolRuns.record(sessionId, toolNodeIds),
90780
90916
  onKnowledgeShown: (sessionId, shown) => supersessionAsks.noteShown(sessionId, shown),
@@ -91282,6 +91418,9 @@ async function startDaemon(opts) {
91282
91418
  onSubagentStop: engine.webHooks.onSubagentStop,
91283
91419
  noteSession: engine.webHooks.noteSession,
91284
91420
  sessionContext: engine.webHooks.sessionContext,
91421
+ // Task priors: the task, searched in the background; delivered on the next tool hook.
91422
+ onTaskPrompt: engine.webHooks.onTaskPrompt,
91423
+ takeTaskPriors: engine.webHooks.takeTaskPriors,
91285
91424
  onHook: engine.webHooks.onHook,
91286
91425
  onHookEvent: engine.webHooks.onHookEvent,
91287
91426
  onShellEvent: engine.webHooks.onShellEvent,
@@ -97006,6 +97145,9 @@ async function startMultiDaemon(opts = {}) {
97006
97145
  const engine = createWorkspaceEngine({
97007
97146
  workspaceRoot: entry.path,
97008
97147
  cloud: wsCloud,
97148
+ // The worker's warm lexicon for searches the engine runs itself (task
97149
+ // priors); without it each would build the symbol lexicon inline.
97150
+ ...generalizeWorker ? { generalizeSoft: (text) => generalizeWorker.generalize(workspacePaths(entry.path).castalia, text).catch(() => void 0) } : {},
97009
97151
  apiKey: opts.apiKey,
97010
97152
  reviewUrl: () => `${baseUrl}/ws/${id}/review`,
97011
97153
  sharedStore,
@@ -97031,6 +97173,9 @@ async function startMultiDaemon(opts = {}) {
97031
97173
  // CAP-session-scope: per-session blocks + harness/fixture quarantine.
97032
97174
  noteSession: engine.webHooks.noteSession,
97033
97175
  sessionContext: engine.webHooks.sessionContext,
97176
+ // Task priors: the task, searched in the background; delivered on the next tool hook.
97177
+ onTaskPrompt: engine.webHooks.onTaskPrompt,
97178
+ takeTaskPriors: engine.webHooks.takeTaskPriors,
97034
97179
  onHook: engine.webHooks.onHook,
97035
97180
  onHookEvent: engine.webHooks.onHookEvent,
97036
97181
  onShellEvent: engine.webHooks.onShellEvent,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inerrata-corporation/errata",
3
- "version": "2.0.23-dev.4881",
3
+ "version": "2.0.23-dev.4900",
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.23-dev.4881",
3
+ "version": "2.0.23-dev.4900",
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
- d3a9c0cdb6333538569766d24e122085d18c71a8c767f1b9edd5d73491450f77 .codex-plugin/plugin.json
1
+ 71e234cc465af344aa5e0ba160f5e1a634188138cf1f6285d276185889fa4ad7 .codex-plugin/plugin.json
2
2
  a7bebae9fb01c838d6c75fc784129e28be571233fa66ff5ee8039b574f35ccf7 assets/icon.png
3
3
  fc38b64e4df1e0b72c35764bef6c4c05430d97c9009ad0ecc8a9e75b4deab232 configure-local.mjs
4
4
  73dc6028b3b070257c7c31f252d11e55a9e096f4aed0f187f10cb21716e1e6d7 dist/client.js