@inerrata-corporation/errata 2.0.2-dev.223 → 2.0.2-dev.227
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/consolidate-worker.mjs +9 -0
- package/errata.mjs +346 -193
- package/package.json +1 -1
- package/pass-worker.mjs +9 -0
package/consolidate-worker.mjs
CHANGED
|
@@ -15315,6 +15315,15 @@ var init_wire = __esm({
|
|
|
15315
15315
|
/** Canonical human-readable description (no raw paths — daemon scrubs; server rechecks). */
|
|
15316
15316
|
description: external_exports.string().min(1).max(4e3),
|
|
15317
15317
|
attrs: external_exports.record(external_exports.string(), external_exports.unknown()).default({}),
|
|
15318
|
+
/** One-way origin key of the SESSION that minted this node (`ws_…`, a
|
|
15319
|
+
* truncated digest — never the raw session id). Stamped onto the created
|
|
15320
|
+
* node as `authoringSession`, which is the independence unit for the
|
|
15321
|
+
* evidence channels: the session that authored a claim may not corroborate
|
|
15322
|
+
* or refute it, while a DIFFERENT session on the same checkout may (alyssa,
|
|
15323
|
+
* 2026-07-31 — the workspace key made every witness on a single-checkout
|
|
15324
|
+
* deployment a self-corroboration). Optional + additive: absent leaves the
|
|
15325
|
+
* gate fail-open for that node, exactly today's behaviour. */
|
|
15326
|
+
originSession: external_exports.string().min(3).max(64).optional(),
|
|
15318
15327
|
extractionSource: external_exports.enum(INGEST_EXTRACTION_SOURCES),
|
|
15319
15328
|
validationSource: external_exports.enum(VALIDATION_SOURCES).optional(),
|
|
15320
15329
|
/** Org-membrane (M2): the daemon's anchor tag — it owns the lockfile, so it
|
package/errata.mjs
CHANGED
|
@@ -15616,6 +15616,15 @@ var init_wire = __esm({
|
|
|
15616
15616
|
/** Canonical human-readable description (no raw paths — daemon scrubs; server rechecks). */
|
|
15617
15617
|
description: external_exports.string().min(1).max(4e3),
|
|
15618
15618
|
attrs: external_exports.record(external_exports.string(), external_exports.unknown()).default({}),
|
|
15619
|
+
/** One-way origin key of the SESSION that minted this node (`ws_…`, a
|
|
15620
|
+
* truncated digest — never the raw session id). Stamped onto the created
|
|
15621
|
+
* node as `authoringSession`, which is the independence unit for the
|
|
15622
|
+
* evidence channels: the session that authored a claim may not corroborate
|
|
15623
|
+
* or refute it, while a DIFFERENT session on the same checkout may (alyssa,
|
|
15624
|
+
* 2026-07-31 — the workspace key made every witness on a single-checkout
|
|
15625
|
+
* deployment a self-corroboration). Optional + additive: absent leaves the
|
|
15626
|
+
* gate fail-open for that node, exactly today's behaviour. */
|
|
15627
|
+
originSession: external_exports.string().min(3).max(64).optional(),
|
|
15619
15628
|
extractionSource: external_exports.enum(INGEST_EXTRACTION_SOURCES),
|
|
15620
15629
|
validationSource: external_exports.enum(VALIDATION_SOURCES).optional(),
|
|
15621
15630
|
/** Org-membrane (M2): the daemon's anchor tag — it owns the lockfile, so it
|
|
@@ -16279,6 +16288,9 @@ var init_profile = __esm({
|
|
|
16279
16288
|
});
|
|
16280
16289
|
|
|
16281
16290
|
// ../../packages/local-shared/src/daemon-wire.ts
|
|
16291
|
+
function formatDisposition(d) {
|
|
16292
|
+
return `${d.recorded} recorded \xB7 ${d.unmatched} unmatched (queued) \xB7 ${d.duplicate} dup \xB7 ${d.selfGated} self`;
|
|
16293
|
+
}
|
|
16282
16294
|
var init_daemon_wire = __esm({
|
|
16283
16295
|
"../../packages/local-shared/src/daemon-wire.ts"() {
|
|
16284
16296
|
"use strict";
|
|
@@ -47250,12 +47262,12 @@ var init_report_render = __esm({
|
|
|
47250
47262
|
|
|
47251
47263
|
// src/cli.ts
|
|
47252
47264
|
init_src5();
|
|
47253
|
-
import { closeSync as closeSync2, existsSync as existsSync25, openSync as openSync2, readFileSync as
|
|
47254
|
-
import { join as
|
|
47265
|
+
import { closeSync as closeSync2, existsSync as existsSync25, openSync as openSync2, readFileSync as readFileSync24, renameSync as renameSync4, statSync as statSync6 } from "node:fs";
|
|
47266
|
+
import { join as join28 } from "node:path";
|
|
47255
47267
|
import { spawn as spawn3 } from "node:child_process";
|
|
47256
47268
|
|
|
47257
47269
|
// src/daemon.ts
|
|
47258
|
-
import { existsSync as existsSync20, writeFileSync as
|
|
47270
|
+
import { existsSync as existsSync20, writeFileSync as writeFileSync17 } from "node:fs";
|
|
47259
47271
|
|
|
47260
47272
|
// ../../node_modules/.pnpm/@hono+node-server@1.19.11_hono@4.12.8/node_modules/@hono/node-server/dist/index.mjs
|
|
47261
47273
|
import { createServer as createServerHTTP } from "http";
|
|
@@ -47835,8 +47847,8 @@ init_config();
|
|
|
47835
47847
|
|
|
47836
47848
|
// src/engine.ts
|
|
47837
47849
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
47838
|
-
import { existsSync as existsSync19, statSync as statSync5, appendFileSync as appendFileSync2, readdirSync as readdirSync9, renameSync as
|
|
47839
|
-
import { join as
|
|
47850
|
+
import { existsSync as existsSync19, statSync as statSync5, appendFileSync as appendFileSync2, readdirSync as readdirSync9, renameSync as renameSync3, readFileSync as readFileSync19, writeFileSync as writeFileSync16 } from "node:fs";
|
|
47851
|
+
import { join as join24, relative as relative6, sep as sep4 } from "node:path";
|
|
47840
47852
|
|
|
47841
47853
|
// ../../node_modules/.pnpm/chokidar@4.0.3/node_modules/chokidar/esm/index.js
|
|
47842
47854
|
import { stat as statcb } from "fs";
|
|
@@ -48567,9 +48579,9 @@ var NodeFsHandler = class {
|
|
|
48567
48579
|
if (this.fsw.closed) {
|
|
48568
48580
|
return;
|
|
48569
48581
|
}
|
|
48570
|
-
const
|
|
48582
|
+
const dirname11 = sysPath.dirname(file2);
|
|
48571
48583
|
const basename5 = sysPath.basename(file2);
|
|
48572
|
-
const parent = this.fsw._getWatchedDir(
|
|
48584
|
+
const parent = this.fsw._getWatchedDir(dirname11);
|
|
48573
48585
|
let prevStats = stats;
|
|
48574
48586
|
if (parent.has(basename5))
|
|
48575
48587
|
return;
|
|
@@ -48596,7 +48608,7 @@ var NodeFsHandler = class {
|
|
|
48596
48608
|
prevStats = newStats2;
|
|
48597
48609
|
}
|
|
48598
48610
|
} catch (error48) {
|
|
48599
|
-
this.fsw._remove(
|
|
48611
|
+
this.fsw._remove(dirname11, basename5);
|
|
48600
48612
|
}
|
|
48601
48613
|
} else if (parent.has(basename5)) {
|
|
48602
48614
|
const at = newStats.atimeMs;
|
|
@@ -51997,109 +52009,6 @@ function createToolRunState() {
|
|
|
51997
52009
|
// src/engine.ts
|
|
51998
52010
|
init_paths();
|
|
51999
52011
|
|
|
52000
|
-
// src/causal.ts
|
|
52001
|
-
var SUPPRESSORS = [
|
|
52002
|
-
{ kind: "ts-nocheck", re: /@ts-nocheck\b/g },
|
|
52003
|
-
{ kind: "ts-ignore", re: /@ts-(?:ignore|expect-error)\b/g },
|
|
52004
|
-
{ kind: "eslint-disable", re: /eslint-disable(?:-next-line|-line)?\b/g },
|
|
52005
|
-
{ kind: "py-ignore", re: /#\s*(?:noqa|type:\s*ignore|pyright:\s*ignore|mypy:\s*ignore|nosec|pragma:\s*no\s*cover)\b/gi },
|
|
52006
|
-
{ kind: "test-skip", re: /\bx(?:it|describe|test)\s*\(|\.(?:skip|todo)\s*\(|@(?:pytest\.mark\.skip|unittest\.skip)|\bxfail\b|\bt\.Skip\s*\(/g },
|
|
52007
|
-
{ kind: "lint-allow", re: /\/\/\s*nolint\b|#\[allow\(|istanbul\s+ignore|c8\s+ignore/g },
|
|
52008
|
-
{ kind: "config-loosen", re: /"strict"\s*:\s*false|"skipLibCheck"\s*:\s*true|ignore_errors\s*=\s*True/gi }
|
|
52009
|
-
];
|
|
52010
|
-
function detectSuppression(oldStr, newStr) {
|
|
52011
|
-
if (!newStr) return null;
|
|
52012
|
-
const old = oldStr ?? "";
|
|
52013
|
-
for (const { kind, re } of SUPPRESSORS) {
|
|
52014
|
-
const inNew = (newStr.match(re) ?? []).length;
|
|
52015
|
-
const inOld = (old.match(re) ?? []).length;
|
|
52016
|
-
if (inNew > inOld) return kind;
|
|
52017
|
-
}
|
|
52018
|
-
return null;
|
|
52019
|
-
}
|
|
52020
|
-
var DECL_RE = /\b(?:function|class|const|let|var|def|interface|type|enum)\s+([A-Za-z_$][\w$]*)/g;
|
|
52021
|
-
function deriveIntentHints(tool, oldStr, newStr) {
|
|
52022
|
-
const hints = /* @__PURE__ */ new Set();
|
|
52023
|
-
if (tool === "Write" && (oldStr == null || oldStr === "")) hints.add("add");
|
|
52024
|
-
if (detectSuppression(oldStr, newStr)) hints.add("suppress");
|
|
52025
|
-
if (oldStr != null && newStr != null) {
|
|
52026
|
-
const oldNames = new Set([...oldStr.matchAll(DECL_RE)].map((m) => m[1]));
|
|
52027
|
-
const newNames = new Set([...newStr.matchAll(DECL_RE)].map((m) => m[1]));
|
|
52028
|
-
const removed = [...oldNames].filter((n) => !newNames.has(n));
|
|
52029
|
-
const added = [...newNames].filter((n) => !oldNames.has(n));
|
|
52030
|
-
if (removed.length > 0 && added.length > 0) hints.add("rename");
|
|
52031
|
-
else if (added.length > 0) hints.add("add");
|
|
52032
|
-
else if (removed.length > 0) hints.add("delete");
|
|
52033
|
-
}
|
|
52034
|
-
return [...hints];
|
|
52035
|
-
}
|
|
52036
|
-
function deriveDeclaredRenames(oldStr, newStr) {
|
|
52037
|
-
if (oldStr == null || newStr == null) return [];
|
|
52038
|
-
const oldNames = [...oldStr.matchAll(DECL_RE)].map((m) => m[1]);
|
|
52039
|
-
const newNames = [...newStr.matchAll(DECL_RE)].map((m) => m[1]);
|
|
52040
|
-
const oldSet = new Set(oldNames);
|
|
52041
|
-
const newSet = new Set(newNames);
|
|
52042
|
-
const removed = [...new Set(oldNames.filter((n) => !newSet.has(n)))];
|
|
52043
|
-
const added = [...new Set(newNames.filter((n) => !oldSet.has(n)))];
|
|
52044
|
-
if (removed.length === 1 && added.length === 1) {
|
|
52045
|
-
return [{ from: removed[0], to: added[0] }];
|
|
52046
|
-
}
|
|
52047
|
-
return [];
|
|
52048
|
-
}
|
|
52049
|
-
var CausalBuffer = class {
|
|
52050
|
-
constructor(windowMs = 5e3, maxAgeMs = 3e4) {
|
|
52051
|
-
this.windowMs = windowMs;
|
|
52052
|
-
this.maxAgeMs = maxAgeMs;
|
|
52053
|
-
}
|
|
52054
|
-
events = [];
|
|
52055
|
-
record(e) {
|
|
52056
|
-
this.events.push(e);
|
|
52057
|
-
this.prune(e.ts);
|
|
52058
|
-
}
|
|
52059
|
-
prune(now) {
|
|
52060
|
-
const cutoff = now - this.maxAgeMs;
|
|
52061
|
-
if (this.events.length > 0 && this.events[0].ts < cutoff) {
|
|
52062
|
-
this.events = this.events.filter((e) => e.ts >= cutoff);
|
|
52063
|
-
}
|
|
52064
|
-
}
|
|
52065
|
-
/**
|
|
52066
|
-
* Correlate a reindex flush (the changed relPaths at instant `t`) to a causal
|
|
52067
|
-
* context, if any buffered tool event touched one of those paths within the
|
|
52068
|
-
* window. The most recent match wins for session/tool; hints are unioned.
|
|
52069
|
-
*/
|
|
52070
|
-
correlate(relPaths, t) {
|
|
52071
|
-
const set2 = new Set(relPaths);
|
|
52072
|
-
const matches = this.events.filter(
|
|
52073
|
-
(e) => set2.has(e.relPath) && Math.abs(e.ts - t) <= this.windowMs
|
|
52074
|
-
);
|
|
52075
|
-
if (matches.length === 0) return null;
|
|
52076
|
-
matches.sort((a, b) => b.ts - a.ts);
|
|
52077
|
-
const top = matches[0];
|
|
52078
|
-
const hints = /* @__PURE__ */ new Set();
|
|
52079
|
-
const renames = [];
|
|
52080
|
-
const seen = /* @__PURE__ */ new Set();
|
|
52081
|
-
for (const m of matches) {
|
|
52082
|
-
for (const h of m.intentHints) hints.add(h);
|
|
52083
|
-
for (const r of m.declaredRenames) {
|
|
52084
|
-
const key = `${r.from}->${r.to}`;
|
|
52085
|
-
if (!seen.has(key)) {
|
|
52086
|
-
seen.add(key);
|
|
52087
|
-
renames.push(r);
|
|
52088
|
-
}
|
|
52089
|
-
}
|
|
52090
|
-
}
|
|
52091
|
-
return {
|
|
52092
|
-
sessionId: top.sessionId,
|
|
52093
|
-
tool: top.tool,
|
|
52094
|
-
intentHints: [...hints],
|
|
52095
|
-
declaredRenames: renames
|
|
52096
|
-
};
|
|
52097
|
-
}
|
|
52098
|
-
size() {
|
|
52099
|
-
return this.events.length;
|
|
52100
|
-
}
|
|
52101
|
-
};
|
|
52102
|
-
|
|
52103
52012
|
// src/profile.ts
|
|
52104
52013
|
init_src2();
|
|
52105
52014
|
init_paths();
|
|
@@ -52163,6 +52072,10 @@ function detectRepoLocator(root, remote) {
|
|
|
52163
52072
|
function workspaceId(root) {
|
|
52164
52073
|
return "wp_" + createHash12("sha256").update(root).digest("hex").slice(0, 12);
|
|
52165
52074
|
}
|
|
52075
|
+
function sessionOriginKey(sessionId) {
|
|
52076
|
+
if (!sessionId) return void 0;
|
|
52077
|
+
return "ws_" + createHash12("sha256").update(sessionId).digest("hex").slice(0, 12);
|
|
52078
|
+
}
|
|
52166
52079
|
function refreshRepoLocator(root, profile) {
|
|
52167
52080
|
const detected = detectRepoLocator(root, profile.repoRemote);
|
|
52168
52081
|
if (!detected || detected === profile.repoLocator) return false;
|
|
@@ -52242,6 +52155,160 @@ function autodetectProfile(root) {
|
|
|
52242
52155
|
return p;
|
|
52243
52156
|
}
|
|
52244
52157
|
|
|
52158
|
+
// src/witness-queue.ts
|
|
52159
|
+
import { readFileSync as readFileSync18, renameSync as renameSync2, writeFileSync as writeFileSync15 } from "node:fs";
|
|
52160
|
+
import { dirname as dirname9, join as join23 } from "node:path";
|
|
52161
|
+
var WITNESS_QUEUE_CAP = 500;
|
|
52162
|
+
var WITNESS_TTL_MS = 14 * 24 * 60 * 60 * 1e3;
|
|
52163
|
+
var WITNESS_MAX_ATTEMPTS = 5;
|
|
52164
|
+
function witnessQueuePath(workspaceConfigDir) {
|
|
52165
|
+
return join23(workspaceConfigDir, "witness-queue.json");
|
|
52166
|
+
}
|
|
52167
|
+
function loadWitnessQueue(path2) {
|
|
52168
|
+
try {
|
|
52169
|
+
const raw2 = JSON.parse(readFileSync18(path2, "utf8"));
|
|
52170
|
+
if (!Array.isArray(raw2)) return [];
|
|
52171
|
+
return raw2.filter(
|
|
52172
|
+
(w) => !!w && typeof w === "object" && typeof w.nodeId === "string" && typeof w.witnessKey === "string"
|
|
52173
|
+
);
|
|
52174
|
+
} catch {
|
|
52175
|
+
return [];
|
|
52176
|
+
}
|
|
52177
|
+
}
|
|
52178
|
+
function saveWitnessQueue(path2, queue) {
|
|
52179
|
+
try {
|
|
52180
|
+
const tmp = join23(dirname9(path2), `.${Date.now()}.witness-queue.tmp`);
|
|
52181
|
+
writeFileSync15(tmp, JSON.stringify(queue), "utf8");
|
|
52182
|
+
renameSync2(tmp, path2);
|
|
52183
|
+
} catch {
|
|
52184
|
+
}
|
|
52185
|
+
}
|
|
52186
|
+
function pruneWitnessQueue(queue, now) {
|
|
52187
|
+
const live = queue.filter(
|
|
52188
|
+
(w) => now - w.ts < WITNESS_TTL_MS && w.attempts < WITNESS_MAX_ATTEMPTS
|
|
52189
|
+
);
|
|
52190
|
+
return live.length > WITNESS_QUEUE_CAP ? live.slice(live.length - WITNESS_QUEUE_CAP) : live;
|
|
52191
|
+
}
|
|
52192
|
+
function enqueueWitnesses(queue, fresh, now) {
|
|
52193
|
+
const byKey = new Map(queue.map((w) => [`${w.channel}:${w.witnessKey}`, w]));
|
|
52194
|
+
for (const f of fresh) {
|
|
52195
|
+
const k = `${f.channel}:${f.witnessKey}`;
|
|
52196
|
+
const existing = byKey.get(k);
|
|
52197
|
+
if (existing) existing.attempts += 1;
|
|
52198
|
+
else byKey.set(k, { ...f, ts: now, attempts: 1 });
|
|
52199
|
+
}
|
|
52200
|
+
return pruneWitnessQueue([...byKey.values()], now);
|
|
52201
|
+
}
|
|
52202
|
+
function pendingFor(queue, channel) {
|
|
52203
|
+
return queue.filter((w) => w.channel === channel);
|
|
52204
|
+
}
|
|
52205
|
+
function retireWitnesses(queue, channel, settledKeys) {
|
|
52206
|
+
return queue.filter((w) => !(w.channel === channel && settledKeys.has(w.witnessKey)));
|
|
52207
|
+
}
|
|
52208
|
+
|
|
52209
|
+
// src/causal.ts
|
|
52210
|
+
var SUPPRESSORS = [
|
|
52211
|
+
{ kind: "ts-nocheck", re: /@ts-nocheck\b/g },
|
|
52212
|
+
{ kind: "ts-ignore", re: /@ts-(?:ignore|expect-error)\b/g },
|
|
52213
|
+
{ kind: "eslint-disable", re: /eslint-disable(?:-next-line|-line)?\b/g },
|
|
52214
|
+
{ kind: "py-ignore", re: /#\s*(?:noqa|type:\s*ignore|pyright:\s*ignore|mypy:\s*ignore|nosec|pragma:\s*no\s*cover)\b/gi },
|
|
52215
|
+
{ kind: "test-skip", re: /\bx(?:it|describe|test)\s*\(|\.(?:skip|todo)\s*\(|@(?:pytest\.mark\.skip|unittest\.skip)|\bxfail\b|\bt\.Skip\s*\(/g },
|
|
52216
|
+
{ kind: "lint-allow", re: /\/\/\s*nolint\b|#\[allow\(|istanbul\s+ignore|c8\s+ignore/g },
|
|
52217
|
+
{ kind: "config-loosen", re: /"strict"\s*:\s*false|"skipLibCheck"\s*:\s*true|ignore_errors\s*=\s*True/gi }
|
|
52218
|
+
];
|
|
52219
|
+
function detectSuppression(oldStr, newStr) {
|
|
52220
|
+
if (!newStr) return null;
|
|
52221
|
+
const old = oldStr ?? "";
|
|
52222
|
+
for (const { kind, re } of SUPPRESSORS) {
|
|
52223
|
+
const inNew = (newStr.match(re) ?? []).length;
|
|
52224
|
+
const inOld = (old.match(re) ?? []).length;
|
|
52225
|
+
if (inNew > inOld) return kind;
|
|
52226
|
+
}
|
|
52227
|
+
return null;
|
|
52228
|
+
}
|
|
52229
|
+
var DECL_RE = /\b(?:function|class|const|let|var|def|interface|type|enum)\s+([A-Za-z_$][\w$]*)/g;
|
|
52230
|
+
function deriveIntentHints(tool, oldStr, newStr) {
|
|
52231
|
+
const hints = /* @__PURE__ */ new Set();
|
|
52232
|
+
if (tool === "Write" && (oldStr == null || oldStr === "")) hints.add("add");
|
|
52233
|
+
if (detectSuppression(oldStr, newStr)) hints.add("suppress");
|
|
52234
|
+
if (oldStr != null && newStr != null) {
|
|
52235
|
+
const oldNames = new Set([...oldStr.matchAll(DECL_RE)].map((m) => m[1]));
|
|
52236
|
+
const newNames = new Set([...newStr.matchAll(DECL_RE)].map((m) => m[1]));
|
|
52237
|
+
const removed = [...oldNames].filter((n) => !newNames.has(n));
|
|
52238
|
+
const added = [...newNames].filter((n) => !oldNames.has(n));
|
|
52239
|
+
if (removed.length > 0 && added.length > 0) hints.add("rename");
|
|
52240
|
+
else if (added.length > 0) hints.add("add");
|
|
52241
|
+
else if (removed.length > 0) hints.add("delete");
|
|
52242
|
+
}
|
|
52243
|
+
return [...hints];
|
|
52244
|
+
}
|
|
52245
|
+
function deriveDeclaredRenames(oldStr, newStr) {
|
|
52246
|
+
if (oldStr == null || newStr == null) return [];
|
|
52247
|
+
const oldNames = [...oldStr.matchAll(DECL_RE)].map((m) => m[1]);
|
|
52248
|
+
const newNames = [...newStr.matchAll(DECL_RE)].map((m) => m[1]);
|
|
52249
|
+
const oldSet = new Set(oldNames);
|
|
52250
|
+
const newSet = new Set(newNames);
|
|
52251
|
+
const removed = [...new Set(oldNames.filter((n) => !newSet.has(n)))];
|
|
52252
|
+
const added = [...new Set(newNames.filter((n) => !oldSet.has(n)))];
|
|
52253
|
+
if (removed.length === 1 && added.length === 1) {
|
|
52254
|
+
return [{ from: removed[0], to: added[0] }];
|
|
52255
|
+
}
|
|
52256
|
+
return [];
|
|
52257
|
+
}
|
|
52258
|
+
var CausalBuffer = class {
|
|
52259
|
+
constructor(windowMs = 5e3, maxAgeMs = 3e4) {
|
|
52260
|
+
this.windowMs = windowMs;
|
|
52261
|
+
this.maxAgeMs = maxAgeMs;
|
|
52262
|
+
}
|
|
52263
|
+
events = [];
|
|
52264
|
+
record(e) {
|
|
52265
|
+
this.events.push(e);
|
|
52266
|
+
this.prune(e.ts);
|
|
52267
|
+
}
|
|
52268
|
+
prune(now) {
|
|
52269
|
+
const cutoff = now - this.maxAgeMs;
|
|
52270
|
+
if (this.events.length > 0 && this.events[0].ts < cutoff) {
|
|
52271
|
+
this.events = this.events.filter((e) => e.ts >= cutoff);
|
|
52272
|
+
}
|
|
52273
|
+
}
|
|
52274
|
+
/**
|
|
52275
|
+
* Correlate a reindex flush (the changed relPaths at instant `t`) to a causal
|
|
52276
|
+
* context, if any buffered tool event touched one of those paths within the
|
|
52277
|
+
* window. The most recent match wins for session/tool; hints are unioned.
|
|
52278
|
+
*/
|
|
52279
|
+
correlate(relPaths, t) {
|
|
52280
|
+
const set2 = new Set(relPaths);
|
|
52281
|
+
const matches = this.events.filter(
|
|
52282
|
+
(e) => set2.has(e.relPath) && Math.abs(e.ts - t) <= this.windowMs
|
|
52283
|
+
);
|
|
52284
|
+
if (matches.length === 0) return null;
|
|
52285
|
+
matches.sort((a, b) => b.ts - a.ts);
|
|
52286
|
+
const top = matches[0];
|
|
52287
|
+
const hints = /* @__PURE__ */ new Set();
|
|
52288
|
+
const renames = [];
|
|
52289
|
+
const seen = /* @__PURE__ */ new Set();
|
|
52290
|
+
for (const m of matches) {
|
|
52291
|
+
for (const h of m.intentHints) hints.add(h);
|
|
52292
|
+
for (const r of m.declaredRenames) {
|
|
52293
|
+
const key = `${r.from}->${r.to}`;
|
|
52294
|
+
if (!seen.has(key)) {
|
|
52295
|
+
seen.add(key);
|
|
52296
|
+
renames.push(r);
|
|
52297
|
+
}
|
|
52298
|
+
}
|
|
52299
|
+
}
|
|
52300
|
+
return {
|
|
52301
|
+
sessionId: top.sessionId,
|
|
52302
|
+
tool: top.tool,
|
|
52303
|
+
intentHints: [...hints],
|
|
52304
|
+
declaredRenames: renames
|
|
52305
|
+
};
|
|
52306
|
+
}
|
|
52307
|
+
size() {
|
|
52308
|
+
return this.events.length;
|
|
52309
|
+
}
|
|
52310
|
+
};
|
|
52311
|
+
|
|
52245
52312
|
// src/engine.ts
|
|
52246
52313
|
init_config();
|
|
52247
52314
|
init_cloud_auth();
|
|
@@ -52391,7 +52458,7 @@ function startLoopLagMonitor(thresholdMs = 1e3) {
|
|
|
52391
52458
|
}
|
|
52392
52459
|
|
|
52393
52460
|
// src/engine.ts
|
|
52394
|
-
var DAEMON_VERSION = true ? "2.0.2-dev.
|
|
52461
|
+
var DAEMON_VERSION = true ? "2.0.2-dev.227" : "2.0.0-alpha.0";
|
|
52395
52462
|
var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
|
|
52396
52463
|
var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
|
|
52397
52464
|
var GIT_OP_MUTE_MS = 4e3;
|
|
@@ -52402,7 +52469,7 @@ function appendIdentityAudit(path2, record2, line) {
|
|
|
52402
52469
|
if (!record2.accepted && record2.score <= 0) return;
|
|
52403
52470
|
try {
|
|
52404
52471
|
if (existsSync19(path2) && statSync5(path2).size >= IDENTITY_AUDIT_MAX_BYTES) {
|
|
52405
|
-
|
|
52472
|
+
renameSync3(path2, `${path2}.1`);
|
|
52406
52473
|
}
|
|
52407
52474
|
appendFileSync2(path2, line);
|
|
52408
52475
|
} catch {
|
|
@@ -52411,7 +52478,7 @@ function appendIdentityAudit(path2, record2, line) {
|
|
|
52411
52478
|
var yieldToLoop = () => new Promise((r) => setImmediate(r));
|
|
52412
52479
|
function loadTurnCursors(path2) {
|
|
52413
52480
|
try {
|
|
52414
|
-
const raw2 = JSON.parse(
|
|
52481
|
+
const raw2 = JSON.parse(readFileSync19(path2, "utf8"));
|
|
52415
52482
|
return new Map(
|
|
52416
52483
|
Object.entries(raw2).map(([k, v]) => [k, typeof v === "string" ? v : String(v?.uuid ?? "")])
|
|
52417
52484
|
);
|
|
@@ -52421,7 +52488,7 @@ function loadTurnCursors(path2) {
|
|
|
52421
52488
|
}
|
|
52422
52489
|
function loadTurnOffsets(path2) {
|
|
52423
52490
|
try {
|
|
52424
|
-
const raw2 = JSON.parse(
|
|
52491
|
+
const raw2 = JSON.parse(readFileSync19(path2, "utf8"));
|
|
52425
52492
|
const out2 = /* @__PURE__ */ new Map();
|
|
52426
52493
|
for (const [k, v] of Object.entries(raw2)) {
|
|
52427
52494
|
const off = typeof v === "object" && v !== null ? v.offset : void 0;
|
|
@@ -52437,7 +52504,7 @@ function saveTurnCursors(path2, cursors, offsets) {
|
|
|
52437
52504
|
const merged = {};
|
|
52438
52505
|
for (const [k, uuid3] of cursors) merged[k] = { uuid: uuid3, offset: offsets.get(k) ?? 0 };
|
|
52439
52506
|
for (const [k, offset] of offsets) if (!merged[k]) merged[k] = { uuid: "", offset };
|
|
52440
|
-
|
|
52507
|
+
writeFileSync16(path2, JSON.stringify(merged), "utf8");
|
|
52441
52508
|
} catch {
|
|
52442
52509
|
}
|
|
52443
52510
|
}
|
|
@@ -52459,7 +52526,7 @@ function gitSourceWatchTargets(root) {
|
|
|
52459
52526
|
["-C", root, "ls-files", "--others", "--ignored", "--exclude-standard", "--directory", "-z"],
|
|
52460
52527
|
{ encoding: "utf8", maxBuffer: 256 * 1024 * 1024, windowsHide: true, stdio: ["ignore", "pipe", "ignore"] }
|
|
52461
52528
|
);
|
|
52462
|
-
ignoredDirs = igOut.split("\0").filter(Boolean).map((d) => d.replace(/\/+$/, "")).filter((d) => !IGNORED_PATH.test(
|
|
52529
|
+
ignoredDirs = igOut.split("\0").filter(Boolean).map((d) => d.replace(/\/+$/, "")).filter((d) => !IGNORED_PATH.test(join24(root, d) + sep4));
|
|
52463
52530
|
} catch {
|
|
52464
52531
|
}
|
|
52465
52532
|
const hasIgnoredChild = (dir) => ignoredDirs.some((ig) => ig.startsWith(dir + "/"));
|
|
@@ -52471,19 +52538,19 @@ function gitSourceWatchTargets(root) {
|
|
|
52471
52538
|
if (!f.startsWith(prefix)) continue;
|
|
52472
52539
|
const rest2 = f.slice(prefix.length);
|
|
52473
52540
|
if (rest2.includes("/")) children.add(dir === "" ? rest2.slice(0, rest2.indexOf("/")) : dir + "/" + rest2.slice(0, rest2.indexOf("/")));
|
|
52474
|
-
else targets.add(
|
|
52541
|
+
else targets.add(join24(root, f));
|
|
52475
52542
|
}
|
|
52476
52543
|
for (const c of children) {
|
|
52477
|
-
if (IGNORED_PATH.test(
|
|
52544
|
+
if (IGNORED_PATH.test(join24(root, c) + sep4)) continue;
|
|
52478
52545
|
if (hasIgnoredChild(c)) addUnder(c);
|
|
52479
|
-
else targets.add(
|
|
52546
|
+
else targets.add(join24(root, c));
|
|
52480
52547
|
}
|
|
52481
52548
|
};
|
|
52482
52549
|
addUnder("");
|
|
52483
52550
|
if (targets.size > 0) return [...targets];
|
|
52484
52551
|
} catch {
|
|
52485
52552
|
}
|
|
52486
|
-
return readdirSync9(root, { withFileTypes: true }).filter((e) => e.isDirectory() && !IGNORED_PATH.test(
|
|
52553
|
+
return readdirSync9(root, { withFileTypes: true }).filter((e) => e.isDirectory() && !IGNORED_PATH.test(join24(root, String(e.name)) + sep4)).map((e) => join24(root, String(e.name)));
|
|
52487
52554
|
}
|
|
52488
52555
|
function createWorkspaceEngine(opts) {
|
|
52489
52556
|
const paths = workspacePaths(opts.workspaceRoot);
|
|
@@ -52498,6 +52565,10 @@ function createWorkspaceEngine(opts) {
|
|
|
52498
52565
|
refreshRepoLocator(opts.workspaceRoot, profile);
|
|
52499
52566
|
}
|
|
52500
52567
|
const store = openGraphStore({ path: paths.castalia });
|
|
52568
|
+
let witnessQueue = pruneWitnessQueue(
|
|
52569
|
+
loadWitnessQueue(witnessQueuePath(paths.configDir)),
|
|
52570
|
+
Date.now()
|
|
52571
|
+
);
|
|
52501
52572
|
const log = openEventLog({ path: paths.eventLog });
|
|
52502
52573
|
const bundled = import.meta.url.endsWith(".mjs");
|
|
52503
52574
|
const passWorker = bundled && paths.castalia !== ":memory:" ? new PassWorker({
|
|
@@ -52637,7 +52708,7 @@ function createWorkspaceEngine(opts) {
|
|
|
52637
52708
|
const srcPaths = diff.changedPaths.filter((p) => /\.(ts|tsx|js|jsx|mjs|cjs|py)$/i.test(p));
|
|
52638
52709
|
let episodeId2;
|
|
52639
52710
|
if (srcPaths.length > 0) {
|
|
52640
|
-
const abs = srcPaths.map((p) =>
|
|
52711
|
+
const abs = srcPaths.map((p) => join24(opts.workspaceRoot, p));
|
|
52641
52712
|
try {
|
|
52642
52713
|
const r = await runReindexPass(
|
|
52643
52714
|
`git-reindex:${profile.name} (${abs.length} files)`,
|
|
@@ -52673,7 +52744,7 @@ function createWorkspaceEngine(opts) {
|
|
|
52673
52744
|
`[errata] git: ${ev.kind} ${ev.newSha.slice(0, 7)} by ${meta3.authorName} \u2014 ${diff.changedPaths.length} file(s), ${diff.renames.length} rename(s)`
|
|
52674
52745
|
);
|
|
52675
52746
|
};
|
|
52676
|
-
const gitDir =
|
|
52747
|
+
const gitDir = join24(opts.workspaceRoot, ".git");
|
|
52677
52748
|
if (existsSync19(gitDir)) {
|
|
52678
52749
|
stopGit = startGitSensor(gitDir, (ev) => {
|
|
52679
52750
|
void handleGitEvent(ev).catch((err2) => {
|
|
@@ -52744,10 +52815,10 @@ function createWorkspaceEngine(opts) {
|
|
|
52744
52815
|
});
|
|
52745
52816
|
doneRender?.();
|
|
52746
52817
|
writeContextFile(opts.workspaceRoot, body2);
|
|
52747
|
-
const target =
|
|
52818
|
+
const target = join24(opts.workspaceRoot, "AGENTS.md");
|
|
52748
52819
|
writeManagedBlock(target, { body: AGENTS_POINTER_BODY, stable: true, force: true });
|
|
52749
52820
|
if (elicit) {
|
|
52750
|
-
writePrimingHandles(
|
|
52821
|
+
writePrimingHandles(join24(paths.configDir, "priming-handles.json"), [
|
|
52751
52822
|
...snapshot.recentProblems.map((r) => r.node),
|
|
52752
52823
|
// Resolved-band handles: the ✓ problem AND its Solution are citable
|
|
52753
52824
|
// (a fix tag on an already-resolved problem no-ops idempotently; the
|
|
@@ -52952,7 +53023,7 @@ function createWorkspaceEngine(opts) {
|
|
|
52952
53023
|
resultSummary: { exitCode: e.exitCode ?? 1, errorTokens: e.errorTokens }
|
|
52953
53024
|
});
|
|
52954
53025
|
};
|
|
52955
|
-
const turnCursorPath =
|
|
53026
|
+
const turnCursorPath = join24(paths.configDir, "turn-cursors.json");
|
|
52956
53027
|
const lastTurnUuid = loadTurnCursors(turnCursorPath);
|
|
52957
53028
|
const turnOffset = loadTurnOffsets(turnCursorPath);
|
|
52958
53029
|
const sessionLastProblem = /* @__PURE__ */ new Map();
|
|
@@ -52976,7 +53047,7 @@ function createWorkspaceEngine(opts) {
|
|
|
52976
53047
|
const t = Date.now();
|
|
52977
53048
|
let processedTurns = 0;
|
|
52978
53049
|
const elicit = isEdgeElicitationEnabled();
|
|
52979
|
-
const handleMap = elicit ? readPrimingHandles(
|
|
53050
|
+
const handleMap = elicit ? readPrimingHandles(join24(paths.configDir, "priming-handles.json")) : {};
|
|
52980
53051
|
const wsRoot = (opts.workspaceRoot ?? "").replace(/\\/g, "/");
|
|
52981
53052
|
const toRel = (abs) => {
|
|
52982
53053
|
const p = abs.replace(/\\/g, "/");
|
|
@@ -53318,18 +53389,83 @@ function createWorkspaceEngine(opts) {
|
|
|
53318
53389
|
mintCiteEdge(solId, targetId, sl.relation, 0.4, { solutionStructure: true, hypothesis: true });
|
|
53319
53390
|
}
|
|
53320
53391
|
}
|
|
53321
|
-
|
|
53322
|
-
|
|
53323
|
-
|
|
53324
|
-
|
|
53325
|
-
|
|
53392
|
+
const citingSession = sessionOriginKey(sessionId);
|
|
53393
|
+
const mintedHere = (nodeId) => store.getNode(nodeId)?.attrs["sources"]?.[0] === sessionId;
|
|
53394
|
+
const sendWitnesses = async (channel, fresh, send) => {
|
|
53395
|
+
const queued = pendingFor(witnessQueue, channel);
|
|
53396
|
+
if (fresh.length === 0 && queued.length === 0) return;
|
|
53397
|
+
const groups = /* @__PURE__ */ new Map();
|
|
53398
|
+
for (const q of queued) {
|
|
53399
|
+
const g = groups.get(q.sessionKey) ?? [];
|
|
53400
|
+
g.push({ nodeId: q.nodeId, witnessKey: q.witnessKey });
|
|
53401
|
+
groups.set(q.sessionKey, g);
|
|
53402
|
+
}
|
|
53403
|
+
const freshGroup = groups.get(citingSession) ?? [];
|
|
53404
|
+
for (const f of fresh) {
|
|
53405
|
+
if (freshGroup.some((x) => x.witnessKey === f.witnessKey)) continue;
|
|
53406
|
+
freshGroup.push(f);
|
|
53407
|
+
}
|
|
53408
|
+
groups.set(citingSession, freshGroup);
|
|
53409
|
+
const settled = /* @__PURE__ */ new Set();
|
|
53410
|
+
const stillUnmatched = [];
|
|
53411
|
+
let recorded = 0, unmatched = 0, duplicate = 0, selfGated = 0;
|
|
53412
|
+
for (const [session, items2] of groups) {
|
|
53413
|
+
if (items2.length === 0) continue;
|
|
53414
|
+
try {
|
|
53415
|
+
const raw2 = await send(items2, session);
|
|
53416
|
+
const d = {
|
|
53417
|
+
recorded: raw2?.recorded ?? 0,
|
|
53418
|
+
unmatched: raw2?.unmatched ?? 0,
|
|
53419
|
+
duplicate: raw2?.duplicate ?? 0,
|
|
53420
|
+
selfGated: raw2?.selfGated ?? 0,
|
|
53421
|
+
unmatchedIds: raw2?.unmatchedIds ?? []
|
|
53422
|
+
};
|
|
53423
|
+
recorded += d.recorded;
|
|
53424
|
+
unmatched += d.unmatched;
|
|
53425
|
+
duplicate += d.duplicate;
|
|
53426
|
+
selfGated += d.selfGated;
|
|
53427
|
+
const missing = new Set(d.unmatchedIds);
|
|
53428
|
+
for (const it of items2) {
|
|
53429
|
+
if (missing.has(it.nodeId)) stillUnmatched.push({ channel, ...it, sessionKey: session });
|
|
53430
|
+
else settled.add(it.witnessKey);
|
|
53431
|
+
}
|
|
53432
|
+
} catch (err2) {
|
|
53433
|
+
console.warn(`[errata] ${channel} transport failed (witnesses kept for retry):`, err2 instanceof Error ? err2.message : err2);
|
|
53434
|
+
for (const it of items2) stillUnmatched.push({ channel, ...it, sessionKey: session });
|
|
53435
|
+
}
|
|
53436
|
+
}
|
|
53437
|
+
witnessQueue = retireWitnesses(witnessQueue, channel, settled);
|
|
53438
|
+
witnessQueue = enqueueWitnesses(witnessQueue, stillUnmatched, Date.now());
|
|
53439
|
+
saveWitnessQueue(witnessQueuePath(paths.configDir), witnessQueue);
|
|
53440
|
+
console.log(
|
|
53441
|
+
`[errata] ${channel}: ${formatDisposition({ recorded, unmatched, duplicate, selfGated })}` + (queued.length > 0 ? ` (incl. ${queued.length} replayed)` : "")
|
|
53442
|
+
);
|
|
53443
|
+
};
|
|
53444
|
+
if (typeof cloud.reportContradictions === "function") {
|
|
53445
|
+
await sendWitnesses(
|
|
53446
|
+
"contradict",
|
|
53447
|
+
plan.refutes,
|
|
53448
|
+
(items2, session) => cloud.reportContradictions({
|
|
53449
|
+
daemonVersion: DAEMON_VERSION,
|
|
53450
|
+
projectId: profile.id,
|
|
53451
|
+
...session ? { sessionId: session } : {},
|
|
53452
|
+
items: stampWitnessOrigin(items2, profile.id)
|
|
53453
|
+
})
|
|
53326
53454
|
);
|
|
53327
53455
|
}
|
|
53328
|
-
if (
|
|
53329
|
-
|
|
53330
|
-
|
|
53331
|
-
|
|
53332
|
-
|
|
53456
|
+
if (typeof cloud.reportCorroborations === "function") {
|
|
53457
|
+
const emit = plan.corroborations.filter((c) => !mintedHere(c.nodeId));
|
|
53458
|
+
const skipped = plan.corroborations.length - emit.length;
|
|
53459
|
+
if (skipped > 0) console.log(`[errata] corroborate: ${skipped} skipped (this session authored the node)`);
|
|
53460
|
+
await sendWitnesses(
|
|
53461
|
+
"corroborate",
|
|
53462
|
+
emit,
|
|
53463
|
+
(items2, session) => cloud.reportCorroborations({
|
|
53464
|
+
daemonVersion: DAEMON_VERSION,
|
|
53465
|
+
projectId: profile.id,
|
|
53466
|
+
...session ? { sessionId: session } : {},
|
|
53467
|
+
items: stampWitnessOrigin(items2, profile.id)
|
|
53468
|
+
})
|
|
53333
53469
|
);
|
|
53334
53470
|
}
|
|
53335
53471
|
} catch (err2) {
|
|
@@ -53522,7 +53658,7 @@ function createWorkspaceEngine(opts) {
|
|
|
53522
53658
|
try {
|
|
53523
53659
|
const inputs = emitInputsFromManifest(paths.configDir, paths.skillsManifest);
|
|
53524
53660
|
emitAndProjectSkills(opts.workspaceRoot, inputs);
|
|
53525
|
-
writePrimingHandles(
|
|
53661
|
+
writePrimingHandles(join24(paths.configDir, "priming-handles.json"), skillHandleNodes(inputs));
|
|
53526
53662
|
} catch (err2) {
|
|
53527
53663
|
console.warn("[skills] agent-skills projection failed (non-fatal):", err2 instanceof Error ? err2.message : err2);
|
|
53528
53664
|
}
|
|
@@ -53796,7 +53932,7 @@ async function startDaemon(opts) {
|
|
|
53796
53932
|
reviewUrl: () => webUiUrl + "/review"
|
|
53797
53933
|
});
|
|
53798
53934
|
const writeLockFile = (url2) => {
|
|
53799
|
-
|
|
53935
|
+
writeFileSync17(
|
|
53800
53936
|
engine.paths.daemonLock,
|
|
53801
53937
|
JSON.stringify({ pid: process.pid, webUiUrl: url2, startedAt: Date.now() }),
|
|
53802
53938
|
"utf8"
|
|
@@ -53856,16 +53992,16 @@ async function listenServer(fetchFn, port) {
|
|
|
53856
53992
|
|
|
53857
53993
|
// src/registry.ts
|
|
53858
53994
|
init_paths();
|
|
53859
|
-
import { existsSync as existsSync21, readFileSync as
|
|
53860
|
-
import { join as
|
|
53995
|
+
import { existsSync as existsSync21, readFileSync as readFileSync20, writeFileSync as writeFileSync18 } from "node:fs";
|
|
53996
|
+
import { join as join25 } from "node:path";
|
|
53861
53997
|
function registryPath() {
|
|
53862
|
-
return process.env["ERRATA_REGISTRY_PATH"] ??
|
|
53998
|
+
return process.env["ERRATA_REGISTRY_PATH"] ?? join25(globalDir(), "workspaces.json");
|
|
53863
53999
|
}
|
|
53864
54000
|
function read() {
|
|
53865
54001
|
const p = registryPath();
|
|
53866
54002
|
if (!existsSync21(p)) return { version: 1, workspaces: {} };
|
|
53867
54003
|
try {
|
|
53868
|
-
const parsed = JSON.parse(
|
|
54004
|
+
const parsed = JSON.parse(readFileSync20(p, "utf8"));
|
|
53869
54005
|
return { version: 1, workspaces: parsed.workspaces ?? {} };
|
|
53870
54006
|
} catch {
|
|
53871
54007
|
return { version: 1, workspaces: {} };
|
|
@@ -53873,7 +54009,7 @@ function read() {
|
|
|
53873
54009
|
}
|
|
53874
54010
|
function write(reg) {
|
|
53875
54011
|
ensureDir(globalDir());
|
|
53876
|
-
|
|
54012
|
+
writeFileSync18(registryPath(), JSON.stringify(reg, null, 2), "utf8");
|
|
53877
54013
|
}
|
|
53878
54014
|
function registerWorkspace(profile, root, now = Date.now()) {
|
|
53879
54015
|
const reg = read();
|
|
@@ -53905,7 +54041,7 @@ function workspaceStatus(entry) {
|
|
|
53905
54041
|
let webUiUrl = null;
|
|
53906
54042
|
if (existsSync21(lockPath)) {
|
|
53907
54043
|
try {
|
|
53908
|
-
const lock = JSON.parse(
|
|
54044
|
+
const lock = JSON.parse(readFileSync20(lockPath, "utf8"));
|
|
53909
54045
|
if (lock.pid && lock.webUiUrl && pidAlive(lock.pid)) {
|
|
53910
54046
|
running = true;
|
|
53911
54047
|
webUiUrl = lock.webUiUrl;
|
|
@@ -53933,7 +54069,7 @@ function pidAlive(pid) {
|
|
|
53933
54069
|
// src/multi.ts
|
|
53934
54070
|
init_dist();
|
|
53935
54071
|
init_src4();
|
|
53936
|
-
import { readFileSync as
|
|
54072
|
+
import { readFileSync as readFileSync23, unlinkSync as unlinkSync3, writeFileSync as writeFileSync19 } from "node:fs";
|
|
53937
54073
|
|
|
53938
54074
|
// src/principle-sync.ts
|
|
53939
54075
|
init_src4();
|
|
@@ -53961,8 +54097,8 @@ init_reconcile();
|
|
|
53961
54097
|
|
|
53962
54098
|
// src/lockfile-auto.ts
|
|
53963
54099
|
init_src();
|
|
53964
|
-
import { existsSync as existsSync22, readFileSync as
|
|
53965
|
-
import { join as
|
|
54100
|
+
import { existsSync as existsSync22, readFileSync as readFileSync21 } from "node:fs";
|
|
54101
|
+
import { join as join26 } from "node:path";
|
|
53966
54102
|
|
|
53967
54103
|
// src/package-index.ts
|
|
53968
54104
|
init_src();
|
|
@@ -54111,11 +54247,11 @@ function runLockfilePass(opts) {
|
|
|
54111
54247
|
{ file: "package-lock.json", parse: parsePackageLockJson }
|
|
54112
54248
|
];
|
|
54113
54249
|
for (const c of candidates) {
|
|
54114
|
-
const p =
|
|
54250
|
+
const p = join26(opts.root, c.file);
|
|
54115
54251
|
if (!existsSync22(p)) continue;
|
|
54116
54252
|
let sbom;
|
|
54117
54253
|
try {
|
|
54118
|
-
sbom = c.parse(
|
|
54254
|
+
sbom = c.parse(readFileSync21(p, "utf8"));
|
|
54119
54255
|
} catch {
|
|
54120
54256
|
continue;
|
|
54121
54257
|
}
|
|
@@ -54225,10 +54361,15 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
|
|
|
54225
54361
|
const level = opts.level ?? 1;
|
|
54226
54362
|
const noveltyOpts = opts.dedupCosine != null ? { dedupCosine: opts.dedupCosine } : {};
|
|
54227
54363
|
const ignored = (text) => ignorePatterns.length > 0 && ignorePatterns.some((p) => text.toLowerCase().includes(p));
|
|
54364
|
+
const originSessionOf = (n) => {
|
|
54365
|
+
const key = sessionOriginKey(n.attrs["sources"]?.[0]);
|
|
54366
|
+
return key ? { originSession: key } : {};
|
|
54367
|
+
};
|
|
54228
54368
|
const shareable = (n) => ({
|
|
54229
54369
|
...n,
|
|
54230
54370
|
description: generalize(n.description, { level }).text,
|
|
54231
54371
|
embedding: [],
|
|
54372
|
+
...originSessionOf(n),
|
|
54232
54373
|
attrs: {
|
|
54233
54374
|
scope: stripCodebaseScope(n.attrs["scope"]),
|
|
54234
54375
|
...n.attrs["kind"] ? { kind: n.attrs["kind"] } : {},
|
|
@@ -54558,7 +54699,7 @@ var ConsolidateWorker = class {
|
|
|
54558
54699
|
init_paths();
|
|
54559
54700
|
|
|
54560
54701
|
// src/lock.ts
|
|
54561
|
-
import { existsSync as existsSync23, readFileSync as
|
|
54702
|
+
import { existsSync as existsSync23, readFileSync as readFileSync22 } from "node:fs";
|
|
54562
54703
|
function isProcessAlive(pid) {
|
|
54563
54704
|
if (!pid || pid <= 0) return false;
|
|
54564
54705
|
try {
|
|
@@ -54571,7 +54712,7 @@ function isProcessAlive(pid) {
|
|
|
54571
54712
|
function readDaemonLock(lockPath) {
|
|
54572
54713
|
if (!existsSync23(lockPath)) return null;
|
|
54573
54714
|
try {
|
|
54574
|
-
const lock = JSON.parse(
|
|
54715
|
+
const lock = JSON.parse(readFileSync22(lockPath, "utf8"));
|
|
54575
54716
|
return typeof lock.pid === "number" ? lock : null;
|
|
54576
54717
|
} catch {
|
|
54577
54718
|
return null;
|
|
@@ -54814,12 +54955,12 @@ async function reanchorProject(opts) {
|
|
|
54814
54955
|
|
|
54815
54956
|
// src/adopt.ts
|
|
54816
54957
|
import { existsSync as existsSync24 } from "node:fs";
|
|
54817
|
-
import { dirname as
|
|
54958
|
+
import { dirname as dirname10, join as join27 } from "node:path";
|
|
54818
54959
|
function findGitRoot(absPath) {
|
|
54819
54960
|
let dir = absPath;
|
|
54820
54961
|
for (let depth = 0; depth < 64; depth++) {
|
|
54821
|
-
if (existsSync24(
|
|
54822
|
-
const parent =
|
|
54962
|
+
if (existsSync24(join27(dir, ".git"))) return dir;
|
|
54963
|
+
const parent = dirname10(dir);
|
|
54823
54964
|
if (parent === dir) return null;
|
|
54824
54965
|
dir = parent;
|
|
54825
54966
|
}
|
|
@@ -55067,7 +55208,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
55067
55208
|
void ambientLinkAll();
|
|
55068
55209
|
app.route(`/ws/${rec.id}`, rec.webApp);
|
|
55069
55210
|
try {
|
|
55070
|
-
|
|
55211
|
+
writeFileSync19(
|
|
55071
55212
|
rec.engine.paths.daemonLock,
|
|
55072
55213
|
JSON.stringify({ pid: process.pid, webUiUrl: `${baseUrl}/ws/${rec.id}`, startedAt: Date.now() }),
|
|
55073
55214
|
"utf8"
|
|
@@ -55256,7 +55397,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
55256
55397
|
baseUrl = `http://127.0.0.1:${port}`;
|
|
55257
55398
|
try {
|
|
55258
55399
|
ensureDir(globalDir());
|
|
55259
|
-
|
|
55400
|
+
writeFileSync19(
|
|
55260
55401
|
lockPath,
|
|
55261
55402
|
JSON.stringify({ pid: process.pid, webUiUrl: baseUrl, startedAt: Date.now() }),
|
|
55262
55403
|
"utf8"
|
|
@@ -55265,7 +55406,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
55265
55406
|
}
|
|
55266
55407
|
for (const r of records) {
|
|
55267
55408
|
try {
|
|
55268
|
-
|
|
55409
|
+
writeFileSync19(
|
|
55269
55410
|
r.engine.paths.daemonLock,
|
|
55270
55411
|
JSON.stringify({ pid: process.pid, webUiUrl: `${baseUrl}/ws/${r.id}`, startedAt: Date.now() }),
|
|
55271
55412
|
"utf8"
|
|
@@ -55748,7 +55889,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
55748
55889
|
},
|
|
55749
55890
|
async stop() {
|
|
55750
55891
|
try {
|
|
55751
|
-
const cur =
|
|
55892
|
+
const cur = readFileSync23(lockPath, "utf8");
|
|
55752
55893
|
if (JSON.parse(cur).pid === process.pid) unlinkSync3(lockPath);
|
|
55753
55894
|
} catch {
|
|
55754
55895
|
}
|
|
@@ -56766,20 +56907,20 @@ async function cmdInit() {
|
|
|
56766
56907
|
console.log("");
|
|
56767
56908
|
console.log("installing harness hooks...");
|
|
56768
56909
|
const { existsSync: existsSync26 } = await import("node:fs");
|
|
56769
|
-
const { join:
|
|
56910
|
+
const { join: join29 } = await import("node:path");
|
|
56770
56911
|
try {
|
|
56771
56912
|
await installClaudeHooks(port);
|
|
56772
56913
|
} catch (err2) {
|
|
56773
56914
|
console.warn(` \u26A0\uFE0F Claude hook install failed: ${err2 instanceof Error ? err2.message : err2}`);
|
|
56774
56915
|
}
|
|
56775
|
-
if (existsSync26(
|
|
56916
|
+
if (existsSync26(join29(ROOT, ".cursor"))) {
|
|
56776
56917
|
try {
|
|
56777
56918
|
await installCursorMcpConfig();
|
|
56778
56919
|
} catch (err2) {
|
|
56779
56920
|
console.warn(` \u26A0\uFE0F Cursor MCP config failed: ${err2 instanceof Error ? err2.message : err2}`);
|
|
56780
56921
|
}
|
|
56781
56922
|
}
|
|
56782
|
-
if (existsSync26(
|
|
56923
|
+
if (existsSync26(join29(ROOT, ".codex"))) {
|
|
56783
56924
|
try {
|
|
56784
56925
|
await installCodexHooks(port);
|
|
56785
56926
|
} catch (err2) {
|
|
@@ -57593,7 +57734,7 @@ async function cmdReview() {
|
|
|
57593
57734
|
console.log("(review queue empty)");
|
|
57594
57735
|
return;
|
|
57595
57736
|
}
|
|
57596
|
-
const queue = JSON.parse(
|
|
57737
|
+
const queue = JSON.parse(readFileSync24(paths.reviewQueue, "utf8"));
|
|
57597
57738
|
if (queue.length === 0) {
|
|
57598
57739
|
console.log("(review queue empty)");
|
|
57599
57740
|
return;
|
|
@@ -58303,7 +58444,7 @@ async function gatherReportData(generatedAt) {
|
|
|
58303
58444
|
};
|
|
58304
58445
|
}
|
|
58305
58446
|
async function cmdReport(args2) {
|
|
58306
|
-
const { mkdirSync: mkdirSync8, writeFileSync:
|
|
58447
|
+
const { mkdirSync: mkdirSync8, writeFileSync: writeFileSync20 } = await import("node:fs");
|
|
58307
58448
|
const { renderReport: renderReport2 } = await Promise.resolve().then(() => (init_report_render(), report_render_exports));
|
|
58308
58449
|
const includeFutureVerbs = args2.includes("--future-verbs");
|
|
58309
58450
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -58316,8 +58457,8 @@ async function cmdReport(args2) {
|
|
|
58316
58457
|
const outDir = workspacePaths(ROOT).configDir;
|
|
58317
58458
|
mkdirSync8(outDir, { recursive: true });
|
|
58318
58459
|
const files = renderReport2(data, { includeFutureVerbs });
|
|
58319
|
-
for (const f of files)
|
|
58320
|
-
const indexPath =
|
|
58460
|
+
for (const f of files) writeFileSync20(join28(outDir, f.name), f.html, "utf8");
|
|
58461
|
+
const indexPath = join28(outDir, "report.html");
|
|
58321
58462
|
console.log(`report \u2192 ${indexPath}`);
|
|
58322
58463
|
console.log(
|
|
58323
58464
|
` ${data.repos.length} repo(s) \xB7 ${files.length} file(s) \xB7 ${data.rollup.nodes.toLocaleString("en-US")} nodes`
|
|
@@ -58369,7 +58510,7 @@ function spawnDaemonDetached() {
|
|
|
58369
58510
|
try {
|
|
58370
58511
|
const logPath = daemonLogPath();
|
|
58371
58512
|
try {
|
|
58372
|
-
if (statSync6(logPath).size > 5 * 1024 * 1024)
|
|
58513
|
+
if (statSync6(logPath).size > 5 * 1024 * 1024) renameSync4(logPath, `${logPath}.1`);
|
|
58373
58514
|
} catch {
|
|
58374
58515
|
}
|
|
58375
58516
|
out2 = openSync2(logPath, "a");
|
|
@@ -58435,15 +58576,15 @@ function hookRelayCommand(port, path2) {
|
|
|
58435
58576
|
return process.platform === "win32" ? `cmd //c "curl -s --connect-timeout 1 --max-time 2 -X POST -H \\"Content-Type: application/json\\" --data-binary @- ${url2} 2>NUL || echo {}"` : `curl -s --connect-timeout 1 --max-time 2 -X POST -H 'Content-Type: application/json' --data-binary @- ${url2} 2>/dev/null || echo '{}'`;
|
|
58436
58577
|
}
|
|
58437
58578
|
async function installClaudeHooks(port) {
|
|
58438
|
-
const { mkdirSync: mkdirSync8, existsSync: existsSync26, readFileSync:
|
|
58439
|
-
const { join:
|
|
58440
|
-
const dir =
|
|
58579
|
+
const { mkdirSync: mkdirSync8, existsSync: existsSync26, readFileSync: readFileSync25, writeFileSync: writeFileSync20 } = await import("node:fs");
|
|
58580
|
+
const { join: join29 } = await import("node:path");
|
|
58581
|
+
const dir = join29(ROOT, ".claude");
|
|
58441
58582
|
if (!existsSync26(dir)) mkdirSync8(dir, { recursive: true });
|
|
58442
|
-
const file2 =
|
|
58583
|
+
const file2 = join29(dir, "settings.json");
|
|
58443
58584
|
let settings = {};
|
|
58444
58585
|
if (existsSync26(file2)) {
|
|
58445
58586
|
try {
|
|
58446
|
-
settings = JSON.parse(
|
|
58587
|
+
settings = JSON.parse(readFileSync25(file2, "utf8"));
|
|
58447
58588
|
} catch {
|
|
58448
58589
|
console.error(`refusing to overwrite invalid JSON at ${file2}`);
|
|
58449
58590
|
process.exit(2);
|
|
@@ -58489,10 +58630,10 @@ async function installClaudeHooks(port) {
|
|
|
58489
58630
|
dropErrata(list);
|
|
58490
58631
|
list.push({ hooks: [{ type: "command", command: injectCmd }] });
|
|
58491
58632
|
}
|
|
58492
|
-
|
|
58633
|
+
writeFileSync20(file2, JSON.stringify(settings, null, 2) + "\n", "utf8");
|
|
58493
58634
|
console.log(`installed Claude Code hooks \u2192 ${file2}`);
|
|
58494
58635
|
await installClaudeMcpConfig();
|
|
58495
|
-
const claudeMd =
|
|
58636
|
+
const claudeMd = join29(ROOT, "CLAUDE.md");
|
|
58496
58637
|
const recall = writeManagedBlock(claudeMd, { body: RECALL_FIRST_BLOCK });
|
|
58497
58638
|
if (recall.kind === "collision") {
|
|
58498
58639
|
console.warn(
|
|
@@ -58504,15 +58645,15 @@ async function installClaudeHooks(port) {
|
|
|
58504
58645
|
console.log(` endpoint: http://127.0.0.1:${port}/api/hook`);
|
|
58505
58646
|
}
|
|
58506
58647
|
async function installClaudeMcpConfig() {
|
|
58507
|
-
const { mkdirSync: mkdirSync8, existsSync: existsSync26, readFileSync:
|
|
58508
|
-
const { join:
|
|
58509
|
-
const file2 =
|
|
58510
|
-
const dir =
|
|
58648
|
+
const { mkdirSync: mkdirSync8, existsSync: existsSync26, readFileSync: readFileSync25, writeFileSync: writeFileSync20 } = await import("node:fs");
|
|
58649
|
+
const { join: join29, dirname: dirname11 } = await import("node:path");
|
|
58650
|
+
const file2 = join29(ROOT, ".mcp.json");
|
|
58651
|
+
const dir = dirname11(file2);
|
|
58511
58652
|
if (!existsSync26(dir)) mkdirSync8(dir, { recursive: true });
|
|
58512
58653
|
let cfg = {};
|
|
58513
58654
|
if (existsSync26(file2)) {
|
|
58514
58655
|
try {
|
|
58515
|
-
cfg = JSON.parse(
|
|
58656
|
+
cfg = JSON.parse(readFileSync25(file2, "utf8"));
|
|
58516
58657
|
} catch {
|
|
58517
58658
|
console.error(`refusing to overwrite invalid JSON at ${file2}`);
|
|
58518
58659
|
process.exit(2);
|
|
@@ -58520,21 +58661,21 @@ async function installClaudeMcpConfig() {
|
|
|
58520
58661
|
}
|
|
58521
58662
|
cfg.mcpServers ??= {};
|
|
58522
58663
|
cfg.mcpServers["errata"] = errataMcpInvocation();
|
|
58523
|
-
|
|
58664
|
+
writeFileSync20(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
|
|
58524
58665
|
console.log(`installed Claude Code MCP server config \u2192 ${file2}`);
|
|
58525
58666
|
console.log(` Claude Code will spawn \`errata mcp\` on workspace open.`);
|
|
58526
58667
|
console.log(` Tools: errata.search / locate / neighbors / callers_of / what_uses / show / similar`);
|
|
58527
58668
|
}
|
|
58528
58669
|
async function installCursorMcpConfig() {
|
|
58529
|
-
const { mkdirSync: mkdirSync8, existsSync: existsSync26, readFileSync:
|
|
58530
|
-
const { join:
|
|
58531
|
-
const dir =
|
|
58670
|
+
const { mkdirSync: mkdirSync8, existsSync: existsSync26, readFileSync: readFileSync25, writeFileSync: writeFileSync20 } = await import("node:fs");
|
|
58671
|
+
const { join: join29 } = await import("node:path");
|
|
58672
|
+
const dir = join29(ROOT, ".cursor");
|
|
58532
58673
|
if (!existsSync26(dir)) mkdirSync8(dir, { recursive: true });
|
|
58533
|
-
const file2 =
|
|
58674
|
+
const file2 = join29(dir, "mcp.json");
|
|
58534
58675
|
let cfg = {};
|
|
58535
58676
|
if (existsSync26(file2)) {
|
|
58536
58677
|
try {
|
|
58537
|
-
cfg = JSON.parse(
|
|
58678
|
+
cfg = JSON.parse(readFileSync25(file2, "utf8"));
|
|
58538
58679
|
} catch {
|
|
58539
58680
|
console.error(`refusing to overwrite invalid JSON at ${file2}`);
|
|
58540
58681
|
process.exit(2);
|
|
@@ -58542,7 +58683,7 @@ async function installCursorMcpConfig() {
|
|
|
58542
58683
|
}
|
|
58543
58684
|
cfg.mcpServers ??= {};
|
|
58544
58685
|
cfg.mcpServers["errata"] = errataMcpInvocation();
|
|
58545
|
-
|
|
58686
|
+
writeFileSync20(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
|
|
58546
58687
|
console.log(`installed Cursor MCP server config \u2192 ${file2}`);
|
|
58547
58688
|
console.log(` Cursor will spawn \`errata mcp\` on workspace open.`);
|
|
58548
58689
|
console.log(` Tools: errata.search / locate / neighbors / callers_of / what_uses`);
|
|
@@ -58550,16 +58691,16 @@ async function installCursorMcpConfig() {
|
|
|
58550
58691
|
console.log(` \u26A0\uFE0F reload Cursor (Cmd/Ctrl-Shift-P \u2192 "Reload Window") to pick it up.`);
|
|
58551
58692
|
}
|
|
58552
58693
|
async function installCodexHooks(port) {
|
|
58553
|
-
const { mkdirSync: mkdirSync8, existsSync: existsSync26, readFileSync:
|
|
58554
|
-
const { join:
|
|
58555
|
-
const dir =
|
|
58694
|
+
const { mkdirSync: mkdirSync8, existsSync: existsSync26, readFileSync: readFileSync25, writeFileSync: writeFileSync20 } = await import("node:fs");
|
|
58695
|
+
const { join: join29 } = await import("node:path");
|
|
58696
|
+
const dir = join29(ROOT, ".codex");
|
|
58556
58697
|
if (!existsSync26(dir)) mkdirSync8(dir, { recursive: true });
|
|
58557
|
-
const file2 =
|
|
58698
|
+
const file2 = join29(dir, "config.toml");
|
|
58558
58699
|
const BEGIN = `# >>> errata hooks (errata-managed)`;
|
|
58559
58700
|
const END = `# <<< errata hooks`;
|
|
58560
58701
|
let existing = "";
|
|
58561
58702
|
if (existsSync26(file2)) {
|
|
58562
|
-
existing =
|
|
58703
|
+
existing = readFileSync25(file2, "utf8");
|
|
58563
58704
|
const beginIdx = existing.indexOf(BEGIN);
|
|
58564
58705
|
const endIdx = existing.indexOf(END);
|
|
58565
58706
|
if (beginIdx >= 0 && endIdx > beginIdx) {
|
|
@@ -58588,7 +58729,7 @@ ${END}
|
|
|
58588
58729
|
const final = existing.length > 0 && !existing.endsWith("\n") ? `${existing}
|
|
58589
58730
|
|
|
58590
58731
|
${block}` : existing + (existing.endsWith("\n\n") ? "" : "\n") + block;
|
|
58591
|
-
|
|
58732
|
+
writeFileSync20(file2, final, "utf8");
|
|
58592
58733
|
console.log(`installed Codex hooks \u2192 ${file2}`);
|
|
58593
58734
|
console.log(` endpoint: http://127.0.0.1:${port}/api/hook`);
|
|
58594
58735
|
console.log("");
|
|
@@ -58728,7 +58869,19 @@ async function cmdConsent(args2) {
|
|
|
58728
58869
|
console.log(" note: run `errata login` to actually upload (no cloud credential yet).");
|
|
58729
58870
|
}
|
|
58730
58871
|
}
|
|
58872
|
+
function installLogTimestamps() {
|
|
58873
|
+
const ISO_AT_START = /^\[?\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/;
|
|
58874
|
+
for (const level of ["log", "warn", "error"]) {
|
|
58875
|
+
const original = console[level].bind(console);
|
|
58876
|
+
console[level] = (...args2) => {
|
|
58877
|
+
const first = args2[0];
|
|
58878
|
+
if (typeof first === "string" && ISO_AT_START.test(first)) return original(...args2);
|
|
58879
|
+
original(`[${(/* @__PURE__ */ new Date()).toISOString()}]`, ...args2);
|
|
58880
|
+
};
|
|
58881
|
+
}
|
|
58882
|
+
}
|
|
58731
58883
|
async function cmdDash(args2) {
|
|
58884
|
+
installLogTimestamps();
|
|
58732
58885
|
const portIdx = args2.indexOf("--port");
|
|
58733
58886
|
const port = portIdx >= 0 && args2[portIdx + 1] ? Number(args2[portIdx + 1]) : 7891;
|
|
58734
58887
|
const reindexOnStart = !args2.includes("--no-reindex");
|
|
@@ -58890,7 +59043,7 @@ async function cmdDash(args2) {
|
|
|
58890
59043
|
await yieldToLoop2();
|
|
58891
59044
|
try {
|
|
58892
59045
|
const items = selectDurableMemory(handle2.sharedStore, r.engine.profile);
|
|
58893
|
-
const res = bleedRules(
|
|
59046
|
+
const res = bleedRules(join28(r.root, ".claude", "rules"), items);
|
|
58894
59047
|
if (res.written || res.pruned) {
|
|
58895
59048
|
console.log(
|
|
58896
59049
|
`[rules:${r.entry.name}] ${res.written} collective principle(s) \u2192 .claude/rules` + (res.pruned ? `, ${res.pruned} pruned` : "")
|
package/package.json
CHANGED
package/pass-worker.mjs
CHANGED
|
@@ -15170,6 +15170,15 @@ var init_wire = __esm({
|
|
|
15170
15170
|
/** Canonical human-readable description (no raw paths — daemon scrubs; server rechecks). */
|
|
15171
15171
|
description: external_exports.string().min(1).max(4e3),
|
|
15172
15172
|
attrs: external_exports.record(external_exports.string(), external_exports.unknown()).default({}),
|
|
15173
|
+
/** One-way origin key of the SESSION that minted this node (`ws_…`, a
|
|
15174
|
+
* truncated digest — never the raw session id). Stamped onto the created
|
|
15175
|
+
* node as `authoringSession`, which is the independence unit for the
|
|
15176
|
+
* evidence channels: the session that authored a claim may not corroborate
|
|
15177
|
+
* or refute it, while a DIFFERENT session on the same checkout may (alyssa,
|
|
15178
|
+
* 2026-07-31 — the workspace key made every witness on a single-checkout
|
|
15179
|
+
* deployment a self-corroboration). Optional + additive: absent leaves the
|
|
15180
|
+
* gate fail-open for that node, exactly today's behaviour. */
|
|
15181
|
+
originSession: external_exports.string().min(3).max(64).optional(),
|
|
15173
15182
|
extractionSource: external_exports.enum(INGEST_EXTRACTION_SOURCES),
|
|
15174
15183
|
validationSource: external_exports.enum(VALIDATION_SOURCES).optional(),
|
|
15175
15184
|
/** Org-membrane (M2): the daemon's anchor tag — it owns the lockfile, so it
|