@inerrata-corporation/errata 2.0.2-dev.226 → 2.0.2-dev.245
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 +462 -207
- 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";
|
|
@@ -21631,6 +21643,7 @@ var init_oauth = __esm({
|
|
|
21631
21643
|
|
|
21632
21644
|
// ../../packages/cloud-client/src/client.ts
|
|
21633
21645
|
import { randomUUID } from "node:crypto";
|
|
21646
|
+
import { gzipSync } from "node:zlib";
|
|
21634
21647
|
function wirePerContext(value) {
|
|
21635
21648
|
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
21636
21649
|
const out2 = {};
|
|
@@ -21828,6 +21841,11 @@ function normalizeSolution(input) {
|
|
|
21828
21841
|
validationSource: input.validationSource
|
|
21829
21842
|
};
|
|
21830
21843
|
}
|
|
21844
|
+
function isIntermediaryRejection(err2) {
|
|
21845
|
+
if (!(err2 instanceof CloudError)) return false;
|
|
21846
|
+
if (err2.status < 400 || err2.status >= 500) return false;
|
|
21847
|
+
return /<!DOCTYPE html|<html/i.test(err2.message);
|
|
21848
|
+
}
|
|
21831
21849
|
function chunkArray(items, size) {
|
|
21832
21850
|
if (items.length <= size) return items.length ? [[...items]] : [];
|
|
21833
21851
|
const out2 = [];
|
|
@@ -21845,7 +21863,7 @@ function provenanceHeaders(provenance) {
|
|
|
21845
21863
|
...provenance.agentModel ? { "x-inerrata-agent-model": provenance.agentModel } : {}
|
|
21846
21864
|
};
|
|
21847
21865
|
}
|
|
21848
|
-
var asWireCount, INGEST_NODE_CHUNK, CloudClient, CloudError;
|
|
21866
|
+
var asWireCount, INGEST_NODE_CHUNK, COMPRESS_MIN_BYTES, CloudClient, CloudError;
|
|
21849
21867
|
var init_client = __esm({
|
|
21850
21868
|
"../../packages/cloud-client/src/client.ts"() {
|
|
21851
21869
|
"use strict";
|
|
@@ -21853,6 +21871,7 @@ var init_client = __esm({
|
|
|
21853
21871
|
init_src();
|
|
21854
21872
|
asWireCount = (n) => typeof n === "number" && Number.isFinite(n) && n >= 0 ? Math.floor(n) : null;
|
|
21855
21873
|
INGEST_NODE_CHUNK = 8;
|
|
21874
|
+
COMPRESS_MIN_BYTES = 4096;
|
|
21856
21875
|
CloudClient = class {
|
|
21857
21876
|
baseUrl;
|
|
21858
21877
|
apiKey;
|
|
@@ -21867,6 +21886,8 @@ var init_client = __esm({
|
|
|
21867
21886
|
daemonVersion;
|
|
21868
21887
|
daemonChannel;
|
|
21869
21888
|
provenance;
|
|
21889
|
+
/** Cleared for the process once a server proves it cannot inflate (see `json`). */
|
|
21890
|
+
compressRequests;
|
|
21870
21891
|
constructor(opts) {
|
|
21871
21892
|
this.baseUrl = opts.baseUrl.replace(/\/+$/, "");
|
|
21872
21893
|
if (opts.apiKey !== void 0) this.apiKey = opts.apiKey;
|
|
@@ -21880,6 +21901,7 @@ var init_client = __esm({
|
|
|
21880
21901
|
this.timeoutMs = opts.timeoutMs ?? 15e3;
|
|
21881
21902
|
this.daemonVersion = opts.daemonVersion;
|
|
21882
21903
|
this.daemonChannel = opts.daemonChannel;
|
|
21904
|
+
this.compressRequests = opts.compressRequests ?? true;
|
|
21883
21905
|
this.provenance = opts.provenance ?? {
|
|
21884
21906
|
clientProduct: "inerrata_cloud_client",
|
|
21885
21907
|
clientKind: "sdk",
|
|
@@ -22017,18 +22039,24 @@ var init_client = __esm({
|
|
|
22017
22039
|
const startedAt = Date.now();
|
|
22018
22040
|
const totalChunks = Math.max(1, Math.ceil(batch.nodes.length / INGEST_NODE_CHUNK)) + Math.ceil(Math.max(0, batch.edges.length - MAX_EDGES_PER_PAYLOAD) / MAX_EDGES_PER_PAYLOAD);
|
|
22019
22041
|
let chunkIndex = 0;
|
|
22042
|
+
const blocked = [];
|
|
22020
22043
|
const emit = (nodeIds, accepted) => {
|
|
22021
22044
|
chunkIndex++;
|
|
22045
|
+
const refused = blocked.splice(0, blocked.length);
|
|
22046
|
+
const refusedSet = new Set(refused);
|
|
22022
22047
|
opts.onChunk?.({
|
|
22023
22048
|
chunkIndex,
|
|
22024
22049
|
totalChunks,
|
|
22025
|
-
|
|
22050
|
+
// Watermark only what actually landed — a blocked node never reached the
|
|
22051
|
+
// door, and marking it contributed would lose it permanently and silently.
|
|
22052
|
+
nodeIds: refusedSet.size ? nodeIds.filter((id) => !refusedSet.has(id)) : nodeIds,
|
|
22026
22053
|
accepted,
|
|
22027
|
-
elapsedMs: Date.now() - startedAt
|
|
22054
|
+
elapsedMs: Date.now() - startedAt,
|
|
22055
|
+
...refused.length ? { blockedNodeIds: refused } : {}
|
|
22028
22056
|
});
|
|
22029
22057
|
};
|
|
22030
22058
|
if (batch.nodes.length <= INGEST_NODE_CHUNK && batch.edges.length <= MAX_EDGES_PER_PAYLOAD) {
|
|
22031
|
-
const result = await this.ingestWithSplit(batch, batch.nodes, batch.edges);
|
|
22059
|
+
const result = await this.ingestWithSplit(batch, batch.nodes, batch.edges, blocked);
|
|
22032
22060
|
const summary = summarizeIngestResult(result);
|
|
22033
22061
|
emit(batch.nodes.map((n) => n.id), summary.accepted);
|
|
22034
22062
|
return { ...summary, result };
|
|
@@ -22043,7 +22071,7 @@ var init_client = __esm({
|
|
|
22043
22071
|
const shipped = new Set(inChunk);
|
|
22044
22072
|
pendingEdges = pendingEdges.filter((e) => !shipped.has(e));
|
|
22045
22073
|
}
|
|
22046
|
-
const r = await this.ingestWithSplit(batch, nodeChunk, inChunk);
|
|
22074
|
+
const r = await this.ingestWithSplit(batch, nodeChunk, inChunk, blocked);
|
|
22047
22075
|
emit(nodeChunk.map((n) => n.id), summarizeIngestResult(r).accepted);
|
|
22048
22076
|
merged.nodes.push(...r.nodes);
|
|
22049
22077
|
merged.edges.push(...r.edges);
|
|
@@ -22086,16 +22114,21 @@ var init_client = __esm({
|
|
|
22086
22114
|
* a verdict about the payload — splitting it would just re-send a rejected batch
|
|
22087
22115
|
* N more times — and a 409/413 has its own handling upstream.
|
|
22088
22116
|
*/
|
|
22089
|
-
async ingestWithSplit(batch, nodes, edges) {
|
|
22117
|
+
async ingestWithSplit(batch, nodes, edges, blocked) {
|
|
22090
22118
|
try {
|
|
22091
22119
|
return await this.ingestWire(toWirePayload({ ...batch, nodes, edges }, randomUUID()));
|
|
22092
22120
|
} catch (err2) {
|
|
22093
22121
|
const status = err2 instanceof CloudError ? err2.status : 0;
|
|
22094
22122
|
const timedOut = status === 502 || status === 504 || status === 408 || status === 0;
|
|
22095
|
-
|
|
22123
|
+
const refusedAtEdge = blocked !== void 0 && isIntermediaryRejection(err2);
|
|
22124
|
+
if (refusedAtEdge && nodes.length === 1 && nodes[0]) {
|
|
22125
|
+
blocked.push(nodes[0].id);
|
|
22126
|
+
return { runId: randomUUID(), nodes: [], edges: [] };
|
|
22127
|
+
}
|
|
22128
|
+
if (!timedOut && !refusedAtEdge || nodes.length <= 1) throw err2;
|
|
22096
22129
|
const mid = Math.ceil(nodes.length / 2);
|
|
22097
|
-
const a = await this.ingestWithSplit(batch, nodes.slice(0, mid), edges);
|
|
22098
|
-
const b = await this.ingestWithSplit(batch, nodes.slice(mid), []);
|
|
22130
|
+
const a = await this.ingestWithSplit(batch, nodes.slice(0, mid), edges, blocked);
|
|
22131
|
+
const b = await this.ingestWithSplit(batch, nodes.slice(mid), [], blocked);
|
|
22099
22132
|
return {
|
|
22100
22133
|
runId: a.runId,
|
|
22101
22134
|
nodes: [...a.nodes, ...b.nodes],
|
|
@@ -22397,15 +22430,43 @@ var init_client = __esm({
|
|
|
22397
22430
|
const token = opts?.bearerToken ?? await this.authToken();
|
|
22398
22431
|
if (token) headers["authorization"] = `Bearer ${token}`;
|
|
22399
22432
|
}
|
|
22433
|
+
let payload;
|
|
22434
|
+
if (body2 !== void 0) {
|
|
22435
|
+
const raw2 = JSON.stringify(body2);
|
|
22436
|
+
if (this.compressRequests && Buffer.byteLength(raw2) >= COMPRESS_MIN_BYTES) {
|
|
22437
|
+
payload = gzipSync(Buffer.from(raw2));
|
|
22438
|
+
headers["content-encoding"] = "gzip";
|
|
22439
|
+
} else {
|
|
22440
|
+
payload = raw2;
|
|
22441
|
+
}
|
|
22442
|
+
}
|
|
22400
22443
|
const ac = new AbortController();
|
|
22401
22444
|
const tid = setTimeout(() => ac.abort(), this.timeoutMs);
|
|
22402
22445
|
try {
|
|
22403
22446
|
const res = await this.fetchFn(url2, {
|
|
22404
22447
|
method,
|
|
22405
22448
|
headers,
|
|
22406
|
-
body:
|
|
22449
|
+
body: payload,
|
|
22407
22450
|
signal: ac.signal
|
|
22408
22451
|
});
|
|
22452
|
+
if (res.status === 400 && headers["content-encoding"] === "gzip") {
|
|
22453
|
+
delete headers["content-encoding"];
|
|
22454
|
+
const retry = await this.fetchFn(url2, {
|
|
22455
|
+
method,
|
|
22456
|
+
headers,
|
|
22457
|
+
body: JSON.stringify(body2),
|
|
22458
|
+
signal: ac.signal
|
|
22459
|
+
});
|
|
22460
|
+
if (!retry.ok) {
|
|
22461
|
+
const text = await retry.text();
|
|
22462
|
+
throw new CloudError(
|
|
22463
|
+
`${method} ${path2} failed: HTTP ${retry.status} ${text.slice(0, 200)}`,
|
|
22464
|
+
retry.status
|
|
22465
|
+
);
|
|
22466
|
+
}
|
|
22467
|
+
this.compressRequests = false;
|
|
22468
|
+
return await retry.json();
|
|
22469
|
+
}
|
|
22409
22470
|
if (!res.ok) {
|
|
22410
22471
|
const text = await res.text();
|
|
22411
22472
|
throw new CloudError(
|
|
@@ -47250,12 +47311,12 @@ var init_report_render = __esm({
|
|
|
47250
47311
|
|
|
47251
47312
|
// src/cli.ts
|
|
47252
47313
|
init_src5();
|
|
47253
|
-
import { closeSync as closeSync2, existsSync as existsSync25, openSync as openSync2, readFileSync as
|
|
47254
|
-
import { join as
|
|
47314
|
+
import { closeSync as closeSync2, existsSync as existsSync25, openSync as openSync2, readFileSync as readFileSync24, renameSync as renameSync4, statSync as statSync6 } from "node:fs";
|
|
47315
|
+
import { join as join28 } from "node:path";
|
|
47255
47316
|
import { spawn as spawn3 } from "node:child_process";
|
|
47256
47317
|
|
|
47257
47318
|
// src/daemon.ts
|
|
47258
|
-
import { existsSync as existsSync20, writeFileSync as
|
|
47319
|
+
import { existsSync as existsSync20, writeFileSync as writeFileSync17 } from "node:fs";
|
|
47259
47320
|
|
|
47260
47321
|
// ../../node_modules/.pnpm/@hono+node-server@1.19.11_hono@4.12.8/node_modules/@hono/node-server/dist/index.mjs
|
|
47261
47322
|
import { createServer as createServerHTTP } from "http";
|
|
@@ -47835,8 +47896,8 @@ init_config();
|
|
|
47835
47896
|
|
|
47836
47897
|
// src/engine.ts
|
|
47837
47898
|
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
|
|
47899
|
+
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";
|
|
47900
|
+
import { join as join24, relative as relative6, sep as sep4 } from "node:path";
|
|
47840
47901
|
|
|
47841
47902
|
// ../../node_modules/.pnpm/chokidar@4.0.3/node_modules/chokidar/esm/index.js
|
|
47842
47903
|
import { stat as statcb } from "fs";
|
|
@@ -48567,9 +48628,9 @@ var NodeFsHandler = class {
|
|
|
48567
48628
|
if (this.fsw.closed) {
|
|
48568
48629
|
return;
|
|
48569
48630
|
}
|
|
48570
|
-
const
|
|
48631
|
+
const dirname11 = sysPath.dirname(file2);
|
|
48571
48632
|
const basename5 = sysPath.basename(file2);
|
|
48572
|
-
const parent = this.fsw._getWatchedDir(
|
|
48633
|
+
const parent = this.fsw._getWatchedDir(dirname11);
|
|
48573
48634
|
let prevStats = stats;
|
|
48574
48635
|
if (parent.has(basename5))
|
|
48575
48636
|
return;
|
|
@@ -48596,7 +48657,7 @@ var NodeFsHandler = class {
|
|
|
48596
48657
|
prevStats = newStats2;
|
|
48597
48658
|
}
|
|
48598
48659
|
} catch (error48) {
|
|
48599
|
-
this.fsw._remove(
|
|
48660
|
+
this.fsw._remove(dirname11, basename5);
|
|
48600
48661
|
}
|
|
48601
48662
|
} else if (parent.has(basename5)) {
|
|
48602
48663
|
const at = newStats.atimeMs;
|
|
@@ -51997,109 +52058,6 @@ function createToolRunState() {
|
|
|
51997
52058
|
// src/engine.ts
|
|
51998
52059
|
init_paths();
|
|
51999
52060
|
|
|
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
52061
|
// src/profile.ts
|
|
52104
52062
|
init_src2();
|
|
52105
52063
|
init_paths();
|
|
@@ -52163,6 +52121,10 @@ function detectRepoLocator(root, remote) {
|
|
|
52163
52121
|
function workspaceId(root) {
|
|
52164
52122
|
return "wp_" + createHash12("sha256").update(root).digest("hex").slice(0, 12);
|
|
52165
52123
|
}
|
|
52124
|
+
function sessionOriginKey(sessionId) {
|
|
52125
|
+
if (!sessionId) return void 0;
|
|
52126
|
+
return "ws_" + createHash12("sha256").update(sessionId).digest("hex").slice(0, 12);
|
|
52127
|
+
}
|
|
52166
52128
|
function refreshRepoLocator(root, profile) {
|
|
52167
52129
|
const detected = detectRepoLocator(root, profile.repoRemote);
|
|
52168
52130
|
if (!detected || detected === profile.repoLocator) return false;
|
|
@@ -52242,6 +52204,160 @@ function autodetectProfile(root) {
|
|
|
52242
52204
|
return p;
|
|
52243
52205
|
}
|
|
52244
52206
|
|
|
52207
|
+
// src/witness-queue.ts
|
|
52208
|
+
import { readFileSync as readFileSync18, renameSync as renameSync2, writeFileSync as writeFileSync15 } from "node:fs";
|
|
52209
|
+
import { dirname as dirname9, join as join23 } from "node:path";
|
|
52210
|
+
var WITNESS_QUEUE_CAP = 500;
|
|
52211
|
+
var WITNESS_TTL_MS = 14 * 24 * 60 * 60 * 1e3;
|
|
52212
|
+
var WITNESS_MAX_ATTEMPTS = 5;
|
|
52213
|
+
function witnessQueuePath(workspaceConfigDir) {
|
|
52214
|
+
return join23(workspaceConfigDir, "witness-queue.json");
|
|
52215
|
+
}
|
|
52216
|
+
function loadWitnessQueue(path2) {
|
|
52217
|
+
try {
|
|
52218
|
+
const raw2 = JSON.parse(readFileSync18(path2, "utf8"));
|
|
52219
|
+
if (!Array.isArray(raw2)) return [];
|
|
52220
|
+
return raw2.filter(
|
|
52221
|
+
(w) => !!w && typeof w === "object" && typeof w.nodeId === "string" && typeof w.witnessKey === "string"
|
|
52222
|
+
);
|
|
52223
|
+
} catch {
|
|
52224
|
+
return [];
|
|
52225
|
+
}
|
|
52226
|
+
}
|
|
52227
|
+
function saveWitnessQueue(path2, queue) {
|
|
52228
|
+
try {
|
|
52229
|
+
const tmp = join23(dirname9(path2), `.${Date.now()}.witness-queue.tmp`);
|
|
52230
|
+
writeFileSync15(tmp, JSON.stringify(queue), "utf8");
|
|
52231
|
+
renameSync2(tmp, path2);
|
|
52232
|
+
} catch {
|
|
52233
|
+
}
|
|
52234
|
+
}
|
|
52235
|
+
function pruneWitnessQueue(queue, now) {
|
|
52236
|
+
const live = queue.filter(
|
|
52237
|
+
(w) => now - w.ts < WITNESS_TTL_MS && w.attempts < WITNESS_MAX_ATTEMPTS
|
|
52238
|
+
);
|
|
52239
|
+
return live.length > WITNESS_QUEUE_CAP ? live.slice(live.length - WITNESS_QUEUE_CAP) : live;
|
|
52240
|
+
}
|
|
52241
|
+
function enqueueWitnesses(queue, fresh, now) {
|
|
52242
|
+
const byKey = new Map(queue.map((w) => [`${w.channel}:${w.witnessKey}`, w]));
|
|
52243
|
+
for (const f of fresh) {
|
|
52244
|
+
const k = `${f.channel}:${f.witnessKey}`;
|
|
52245
|
+
const existing = byKey.get(k);
|
|
52246
|
+
if (existing) existing.attempts += 1;
|
|
52247
|
+
else byKey.set(k, { ...f, ts: now, attempts: 1 });
|
|
52248
|
+
}
|
|
52249
|
+
return pruneWitnessQueue([...byKey.values()], now);
|
|
52250
|
+
}
|
|
52251
|
+
function pendingFor(queue, channel) {
|
|
52252
|
+
return queue.filter((w) => w.channel === channel);
|
|
52253
|
+
}
|
|
52254
|
+
function retireWitnesses(queue, channel, settledKeys) {
|
|
52255
|
+
return queue.filter((w) => !(w.channel === channel && settledKeys.has(w.witnessKey)));
|
|
52256
|
+
}
|
|
52257
|
+
|
|
52258
|
+
// src/causal.ts
|
|
52259
|
+
var SUPPRESSORS = [
|
|
52260
|
+
{ kind: "ts-nocheck", re: /@ts-nocheck\b/g },
|
|
52261
|
+
{ kind: "ts-ignore", re: /@ts-(?:ignore|expect-error)\b/g },
|
|
52262
|
+
{ kind: "eslint-disable", re: /eslint-disable(?:-next-line|-line)?\b/g },
|
|
52263
|
+
{ kind: "py-ignore", re: /#\s*(?:noqa|type:\s*ignore|pyright:\s*ignore|mypy:\s*ignore|nosec|pragma:\s*no\s*cover)\b/gi },
|
|
52264
|
+
{ kind: "test-skip", re: /\bx(?:it|describe|test)\s*\(|\.(?:skip|todo)\s*\(|@(?:pytest\.mark\.skip|unittest\.skip)|\bxfail\b|\bt\.Skip\s*\(/g },
|
|
52265
|
+
{ kind: "lint-allow", re: /\/\/\s*nolint\b|#\[allow\(|istanbul\s+ignore|c8\s+ignore/g },
|
|
52266
|
+
{ kind: "config-loosen", re: /"strict"\s*:\s*false|"skipLibCheck"\s*:\s*true|ignore_errors\s*=\s*True/gi }
|
|
52267
|
+
];
|
|
52268
|
+
function detectSuppression(oldStr, newStr) {
|
|
52269
|
+
if (!newStr) return null;
|
|
52270
|
+
const old = oldStr ?? "";
|
|
52271
|
+
for (const { kind, re } of SUPPRESSORS) {
|
|
52272
|
+
const inNew = (newStr.match(re) ?? []).length;
|
|
52273
|
+
const inOld = (old.match(re) ?? []).length;
|
|
52274
|
+
if (inNew > inOld) return kind;
|
|
52275
|
+
}
|
|
52276
|
+
return null;
|
|
52277
|
+
}
|
|
52278
|
+
var DECL_RE = /\b(?:function|class|const|let|var|def|interface|type|enum)\s+([A-Za-z_$][\w$]*)/g;
|
|
52279
|
+
function deriveIntentHints(tool, oldStr, newStr) {
|
|
52280
|
+
const hints = /* @__PURE__ */ new Set();
|
|
52281
|
+
if (tool === "Write" && (oldStr == null || oldStr === "")) hints.add("add");
|
|
52282
|
+
if (detectSuppression(oldStr, newStr)) hints.add("suppress");
|
|
52283
|
+
if (oldStr != null && newStr != null) {
|
|
52284
|
+
const oldNames = new Set([...oldStr.matchAll(DECL_RE)].map((m) => m[1]));
|
|
52285
|
+
const newNames = new Set([...newStr.matchAll(DECL_RE)].map((m) => m[1]));
|
|
52286
|
+
const removed = [...oldNames].filter((n) => !newNames.has(n));
|
|
52287
|
+
const added = [...newNames].filter((n) => !oldNames.has(n));
|
|
52288
|
+
if (removed.length > 0 && added.length > 0) hints.add("rename");
|
|
52289
|
+
else if (added.length > 0) hints.add("add");
|
|
52290
|
+
else if (removed.length > 0) hints.add("delete");
|
|
52291
|
+
}
|
|
52292
|
+
return [...hints];
|
|
52293
|
+
}
|
|
52294
|
+
function deriveDeclaredRenames(oldStr, newStr) {
|
|
52295
|
+
if (oldStr == null || newStr == null) return [];
|
|
52296
|
+
const oldNames = [...oldStr.matchAll(DECL_RE)].map((m) => m[1]);
|
|
52297
|
+
const newNames = [...newStr.matchAll(DECL_RE)].map((m) => m[1]);
|
|
52298
|
+
const oldSet = new Set(oldNames);
|
|
52299
|
+
const newSet = new Set(newNames);
|
|
52300
|
+
const removed = [...new Set(oldNames.filter((n) => !newSet.has(n)))];
|
|
52301
|
+
const added = [...new Set(newNames.filter((n) => !oldSet.has(n)))];
|
|
52302
|
+
if (removed.length === 1 && added.length === 1) {
|
|
52303
|
+
return [{ from: removed[0], to: added[0] }];
|
|
52304
|
+
}
|
|
52305
|
+
return [];
|
|
52306
|
+
}
|
|
52307
|
+
var CausalBuffer = class {
|
|
52308
|
+
constructor(windowMs = 5e3, maxAgeMs = 3e4) {
|
|
52309
|
+
this.windowMs = windowMs;
|
|
52310
|
+
this.maxAgeMs = maxAgeMs;
|
|
52311
|
+
}
|
|
52312
|
+
events = [];
|
|
52313
|
+
record(e) {
|
|
52314
|
+
this.events.push(e);
|
|
52315
|
+
this.prune(e.ts);
|
|
52316
|
+
}
|
|
52317
|
+
prune(now) {
|
|
52318
|
+
const cutoff = now - this.maxAgeMs;
|
|
52319
|
+
if (this.events.length > 0 && this.events[0].ts < cutoff) {
|
|
52320
|
+
this.events = this.events.filter((e) => e.ts >= cutoff);
|
|
52321
|
+
}
|
|
52322
|
+
}
|
|
52323
|
+
/**
|
|
52324
|
+
* Correlate a reindex flush (the changed relPaths at instant `t`) to a causal
|
|
52325
|
+
* context, if any buffered tool event touched one of those paths within the
|
|
52326
|
+
* window. The most recent match wins for session/tool; hints are unioned.
|
|
52327
|
+
*/
|
|
52328
|
+
correlate(relPaths, t) {
|
|
52329
|
+
const set2 = new Set(relPaths);
|
|
52330
|
+
const matches = this.events.filter(
|
|
52331
|
+
(e) => set2.has(e.relPath) && Math.abs(e.ts - t) <= this.windowMs
|
|
52332
|
+
);
|
|
52333
|
+
if (matches.length === 0) return null;
|
|
52334
|
+
matches.sort((a, b) => b.ts - a.ts);
|
|
52335
|
+
const top = matches[0];
|
|
52336
|
+
const hints = /* @__PURE__ */ new Set();
|
|
52337
|
+
const renames = [];
|
|
52338
|
+
const seen = /* @__PURE__ */ new Set();
|
|
52339
|
+
for (const m of matches) {
|
|
52340
|
+
for (const h of m.intentHints) hints.add(h);
|
|
52341
|
+
for (const r of m.declaredRenames) {
|
|
52342
|
+
const key = `${r.from}->${r.to}`;
|
|
52343
|
+
if (!seen.has(key)) {
|
|
52344
|
+
seen.add(key);
|
|
52345
|
+
renames.push(r);
|
|
52346
|
+
}
|
|
52347
|
+
}
|
|
52348
|
+
}
|
|
52349
|
+
return {
|
|
52350
|
+
sessionId: top.sessionId,
|
|
52351
|
+
tool: top.tool,
|
|
52352
|
+
intentHints: [...hints],
|
|
52353
|
+
declaredRenames: renames
|
|
52354
|
+
};
|
|
52355
|
+
}
|
|
52356
|
+
size() {
|
|
52357
|
+
return this.events.length;
|
|
52358
|
+
}
|
|
52359
|
+
};
|
|
52360
|
+
|
|
52245
52361
|
// src/engine.ts
|
|
52246
52362
|
init_config();
|
|
52247
52363
|
init_cloud_auth();
|
|
@@ -52391,7 +52507,7 @@ function startLoopLagMonitor(thresholdMs = 1e3) {
|
|
|
52391
52507
|
}
|
|
52392
52508
|
|
|
52393
52509
|
// src/engine.ts
|
|
52394
|
-
var DAEMON_VERSION = true ? "2.0.2-dev.
|
|
52510
|
+
var DAEMON_VERSION = true ? "2.0.2-dev.245" : "2.0.0-alpha.0";
|
|
52395
52511
|
var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
|
|
52396
52512
|
var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
|
|
52397
52513
|
var GIT_OP_MUTE_MS = 4e3;
|
|
@@ -52402,7 +52518,7 @@ function appendIdentityAudit(path2, record2, line) {
|
|
|
52402
52518
|
if (!record2.accepted && record2.score <= 0) return;
|
|
52403
52519
|
try {
|
|
52404
52520
|
if (existsSync19(path2) && statSync5(path2).size >= IDENTITY_AUDIT_MAX_BYTES) {
|
|
52405
|
-
|
|
52521
|
+
renameSync3(path2, `${path2}.1`);
|
|
52406
52522
|
}
|
|
52407
52523
|
appendFileSync2(path2, line);
|
|
52408
52524
|
} catch {
|
|
@@ -52411,7 +52527,7 @@ function appendIdentityAudit(path2, record2, line) {
|
|
|
52411
52527
|
var yieldToLoop = () => new Promise((r) => setImmediate(r));
|
|
52412
52528
|
function loadTurnCursors(path2) {
|
|
52413
52529
|
try {
|
|
52414
|
-
const raw2 = JSON.parse(
|
|
52530
|
+
const raw2 = JSON.parse(readFileSync19(path2, "utf8"));
|
|
52415
52531
|
return new Map(
|
|
52416
52532
|
Object.entries(raw2).map(([k, v]) => [k, typeof v === "string" ? v : String(v?.uuid ?? "")])
|
|
52417
52533
|
);
|
|
@@ -52421,7 +52537,7 @@ function loadTurnCursors(path2) {
|
|
|
52421
52537
|
}
|
|
52422
52538
|
function loadTurnOffsets(path2) {
|
|
52423
52539
|
try {
|
|
52424
|
-
const raw2 = JSON.parse(
|
|
52540
|
+
const raw2 = JSON.parse(readFileSync19(path2, "utf8"));
|
|
52425
52541
|
const out2 = /* @__PURE__ */ new Map();
|
|
52426
52542
|
for (const [k, v] of Object.entries(raw2)) {
|
|
52427
52543
|
const off = typeof v === "object" && v !== null ? v.offset : void 0;
|
|
@@ -52437,7 +52553,7 @@ function saveTurnCursors(path2, cursors, offsets) {
|
|
|
52437
52553
|
const merged = {};
|
|
52438
52554
|
for (const [k, uuid3] of cursors) merged[k] = { uuid: uuid3, offset: offsets.get(k) ?? 0 };
|
|
52439
52555
|
for (const [k, offset] of offsets) if (!merged[k]) merged[k] = { uuid: "", offset };
|
|
52440
|
-
|
|
52556
|
+
writeFileSync16(path2, JSON.stringify(merged), "utf8");
|
|
52441
52557
|
} catch {
|
|
52442
52558
|
}
|
|
52443
52559
|
}
|
|
@@ -52459,7 +52575,7 @@ function gitSourceWatchTargets(root) {
|
|
|
52459
52575
|
["-C", root, "ls-files", "--others", "--ignored", "--exclude-standard", "--directory", "-z"],
|
|
52460
52576
|
{ encoding: "utf8", maxBuffer: 256 * 1024 * 1024, windowsHide: true, stdio: ["ignore", "pipe", "ignore"] }
|
|
52461
52577
|
);
|
|
52462
|
-
ignoredDirs = igOut.split("\0").filter(Boolean).map((d) => d.replace(/\/+$/, "")).filter((d) => !IGNORED_PATH.test(
|
|
52578
|
+
ignoredDirs = igOut.split("\0").filter(Boolean).map((d) => d.replace(/\/+$/, "")).filter((d) => !IGNORED_PATH.test(join24(root, d) + sep4));
|
|
52463
52579
|
} catch {
|
|
52464
52580
|
}
|
|
52465
52581
|
const hasIgnoredChild = (dir) => ignoredDirs.some((ig) => ig.startsWith(dir + "/"));
|
|
@@ -52471,19 +52587,19 @@ function gitSourceWatchTargets(root) {
|
|
|
52471
52587
|
if (!f.startsWith(prefix)) continue;
|
|
52472
52588
|
const rest2 = f.slice(prefix.length);
|
|
52473
52589
|
if (rest2.includes("/")) children.add(dir === "" ? rest2.slice(0, rest2.indexOf("/")) : dir + "/" + rest2.slice(0, rest2.indexOf("/")));
|
|
52474
|
-
else targets.add(
|
|
52590
|
+
else targets.add(join24(root, f));
|
|
52475
52591
|
}
|
|
52476
52592
|
for (const c of children) {
|
|
52477
|
-
if (IGNORED_PATH.test(
|
|
52593
|
+
if (IGNORED_PATH.test(join24(root, c) + sep4)) continue;
|
|
52478
52594
|
if (hasIgnoredChild(c)) addUnder(c);
|
|
52479
|
-
else targets.add(
|
|
52595
|
+
else targets.add(join24(root, c));
|
|
52480
52596
|
}
|
|
52481
52597
|
};
|
|
52482
52598
|
addUnder("");
|
|
52483
52599
|
if (targets.size > 0) return [...targets];
|
|
52484
52600
|
} catch {
|
|
52485
52601
|
}
|
|
52486
|
-
return readdirSync9(root, { withFileTypes: true }).filter((e) => e.isDirectory() && !IGNORED_PATH.test(
|
|
52602
|
+
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
52603
|
}
|
|
52488
52604
|
function createWorkspaceEngine(opts) {
|
|
52489
52605
|
const paths = workspacePaths(opts.workspaceRoot);
|
|
@@ -52498,6 +52614,10 @@ function createWorkspaceEngine(opts) {
|
|
|
52498
52614
|
refreshRepoLocator(opts.workspaceRoot, profile);
|
|
52499
52615
|
}
|
|
52500
52616
|
const store = openGraphStore({ path: paths.castalia });
|
|
52617
|
+
let witnessQueue = pruneWitnessQueue(
|
|
52618
|
+
loadWitnessQueue(witnessQueuePath(paths.configDir)),
|
|
52619
|
+
Date.now()
|
|
52620
|
+
);
|
|
52501
52621
|
const log = openEventLog({ path: paths.eventLog });
|
|
52502
52622
|
const bundled = import.meta.url.endsWith(".mjs");
|
|
52503
52623
|
const passWorker = bundled && paths.castalia !== ":memory:" ? new PassWorker({
|
|
@@ -52637,7 +52757,7 @@ function createWorkspaceEngine(opts) {
|
|
|
52637
52757
|
const srcPaths = diff.changedPaths.filter((p) => /\.(ts|tsx|js|jsx|mjs|cjs|py)$/i.test(p));
|
|
52638
52758
|
let episodeId2;
|
|
52639
52759
|
if (srcPaths.length > 0) {
|
|
52640
|
-
const abs = srcPaths.map((p) =>
|
|
52760
|
+
const abs = srcPaths.map((p) => join24(opts.workspaceRoot, p));
|
|
52641
52761
|
try {
|
|
52642
52762
|
const r = await runReindexPass(
|
|
52643
52763
|
`git-reindex:${profile.name} (${abs.length} files)`,
|
|
@@ -52673,7 +52793,7 @@ function createWorkspaceEngine(opts) {
|
|
|
52673
52793
|
`[errata] git: ${ev.kind} ${ev.newSha.slice(0, 7)} by ${meta3.authorName} \u2014 ${diff.changedPaths.length} file(s), ${diff.renames.length} rename(s)`
|
|
52674
52794
|
);
|
|
52675
52795
|
};
|
|
52676
|
-
const gitDir =
|
|
52796
|
+
const gitDir = join24(opts.workspaceRoot, ".git");
|
|
52677
52797
|
if (existsSync19(gitDir)) {
|
|
52678
52798
|
stopGit = startGitSensor(gitDir, (ev) => {
|
|
52679
52799
|
void handleGitEvent(ev).catch((err2) => {
|
|
@@ -52744,10 +52864,10 @@ function createWorkspaceEngine(opts) {
|
|
|
52744
52864
|
});
|
|
52745
52865
|
doneRender?.();
|
|
52746
52866
|
writeContextFile(opts.workspaceRoot, body2);
|
|
52747
|
-
const target =
|
|
52867
|
+
const target = join24(opts.workspaceRoot, "AGENTS.md");
|
|
52748
52868
|
writeManagedBlock(target, { body: AGENTS_POINTER_BODY, stable: true, force: true });
|
|
52749
52869
|
if (elicit) {
|
|
52750
|
-
writePrimingHandles(
|
|
52870
|
+
writePrimingHandles(join24(paths.configDir, "priming-handles.json"), [
|
|
52751
52871
|
...snapshot.recentProblems.map((r) => r.node),
|
|
52752
52872
|
// Resolved-band handles: the ✓ problem AND its Solution are citable
|
|
52753
52873
|
// (a fix tag on an already-resolved problem no-ops idempotently; the
|
|
@@ -52952,7 +53072,7 @@ function createWorkspaceEngine(opts) {
|
|
|
52952
53072
|
resultSummary: { exitCode: e.exitCode ?? 1, errorTokens: e.errorTokens }
|
|
52953
53073
|
});
|
|
52954
53074
|
};
|
|
52955
|
-
const turnCursorPath =
|
|
53075
|
+
const turnCursorPath = join24(paths.configDir, "turn-cursors.json");
|
|
52956
53076
|
const lastTurnUuid = loadTurnCursors(turnCursorPath);
|
|
52957
53077
|
const turnOffset = loadTurnOffsets(turnCursorPath);
|
|
52958
53078
|
const sessionLastProblem = /* @__PURE__ */ new Map();
|
|
@@ -52976,7 +53096,7 @@ function createWorkspaceEngine(opts) {
|
|
|
52976
53096
|
const t = Date.now();
|
|
52977
53097
|
let processedTurns = 0;
|
|
52978
53098
|
const elicit = isEdgeElicitationEnabled();
|
|
52979
|
-
const handleMap = elicit ? readPrimingHandles(
|
|
53099
|
+
const handleMap = elicit ? readPrimingHandles(join24(paths.configDir, "priming-handles.json")) : {};
|
|
52980
53100
|
const wsRoot = (opts.workspaceRoot ?? "").replace(/\\/g, "/");
|
|
52981
53101
|
const toRel = (abs) => {
|
|
52982
53102
|
const p = abs.replace(/\\/g, "/");
|
|
@@ -53318,18 +53438,83 @@ function createWorkspaceEngine(opts) {
|
|
|
53318
53438
|
mintCiteEdge(solId, targetId, sl.relation, 0.4, { solutionStructure: true, hypothesis: true });
|
|
53319
53439
|
}
|
|
53320
53440
|
}
|
|
53321
|
-
|
|
53322
|
-
|
|
53323
|
-
|
|
53324
|
-
|
|
53325
|
-
|
|
53441
|
+
const citingSession = sessionOriginKey(sessionId);
|
|
53442
|
+
const mintedHere = (nodeId) => store.getNode(nodeId)?.attrs["sources"]?.[0] === sessionId;
|
|
53443
|
+
const sendWitnesses = async (channel, fresh, send) => {
|
|
53444
|
+
const queued = pendingFor(witnessQueue, channel);
|
|
53445
|
+
if (fresh.length === 0 && queued.length === 0) return;
|
|
53446
|
+
const groups = /* @__PURE__ */ new Map();
|
|
53447
|
+
for (const q of queued) {
|
|
53448
|
+
const g = groups.get(q.sessionKey) ?? [];
|
|
53449
|
+
g.push({ nodeId: q.nodeId, witnessKey: q.witnessKey });
|
|
53450
|
+
groups.set(q.sessionKey, g);
|
|
53451
|
+
}
|
|
53452
|
+
const freshGroup = groups.get(citingSession) ?? [];
|
|
53453
|
+
for (const f of fresh) {
|
|
53454
|
+
if (freshGroup.some((x) => x.witnessKey === f.witnessKey)) continue;
|
|
53455
|
+
freshGroup.push(f);
|
|
53456
|
+
}
|
|
53457
|
+
groups.set(citingSession, freshGroup);
|
|
53458
|
+
const settled = /* @__PURE__ */ new Set();
|
|
53459
|
+
const stillUnmatched = [];
|
|
53460
|
+
let recorded = 0, unmatched = 0, duplicate = 0, selfGated = 0;
|
|
53461
|
+
for (const [session, items2] of groups) {
|
|
53462
|
+
if (items2.length === 0) continue;
|
|
53463
|
+
try {
|
|
53464
|
+
const raw2 = await send(items2, session);
|
|
53465
|
+
const d = {
|
|
53466
|
+
recorded: raw2?.recorded ?? 0,
|
|
53467
|
+
unmatched: raw2?.unmatched ?? 0,
|
|
53468
|
+
duplicate: raw2?.duplicate ?? 0,
|
|
53469
|
+
selfGated: raw2?.selfGated ?? 0,
|
|
53470
|
+
unmatchedIds: raw2?.unmatchedIds ?? []
|
|
53471
|
+
};
|
|
53472
|
+
recorded += d.recorded;
|
|
53473
|
+
unmatched += d.unmatched;
|
|
53474
|
+
duplicate += d.duplicate;
|
|
53475
|
+
selfGated += d.selfGated;
|
|
53476
|
+
const missing = new Set(d.unmatchedIds);
|
|
53477
|
+
for (const it of items2) {
|
|
53478
|
+
if (missing.has(it.nodeId)) stillUnmatched.push({ channel, ...it, sessionKey: session });
|
|
53479
|
+
else settled.add(it.witnessKey);
|
|
53480
|
+
}
|
|
53481
|
+
} catch (err2) {
|
|
53482
|
+
console.warn(`[errata] ${channel} transport failed (witnesses kept for retry):`, err2 instanceof Error ? err2.message : err2);
|
|
53483
|
+
for (const it of items2) stillUnmatched.push({ channel, ...it, sessionKey: session });
|
|
53484
|
+
}
|
|
53485
|
+
}
|
|
53486
|
+
witnessQueue = retireWitnesses(witnessQueue, channel, settled);
|
|
53487
|
+
witnessQueue = enqueueWitnesses(witnessQueue, stillUnmatched, Date.now());
|
|
53488
|
+
saveWitnessQueue(witnessQueuePath(paths.configDir), witnessQueue);
|
|
53489
|
+
console.log(
|
|
53490
|
+
`[errata] ${channel}: ${formatDisposition({ recorded, unmatched, duplicate, selfGated })}` + (queued.length > 0 ? ` (incl. ${queued.length} replayed)` : "")
|
|
53491
|
+
);
|
|
53492
|
+
};
|
|
53493
|
+
if (typeof cloud.reportContradictions === "function") {
|
|
53494
|
+
await sendWitnesses(
|
|
53495
|
+
"contradict",
|
|
53496
|
+
plan.refutes,
|
|
53497
|
+
(items2, session) => cloud.reportContradictions({
|
|
53498
|
+
daemonVersion: DAEMON_VERSION,
|
|
53499
|
+
projectId: profile.id,
|
|
53500
|
+
...session ? { sessionId: session } : {},
|
|
53501
|
+
items: stampWitnessOrigin(items2, profile.id)
|
|
53502
|
+
})
|
|
53326
53503
|
);
|
|
53327
53504
|
}
|
|
53328
|
-
if (
|
|
53329
|
-
|
|
53330
|
-
|
|
53331
|
-
|
|
53332
|
-
|
|
53505
|
+
if (typeof cloud.reportCorroborations === "function") {
|
|
53506
|
+
const emit = plan.corroborations.filter((c) => !mintedHere(c.nodeId));
|
|
53507
|
+
const skipped = plan.corroborations.length - emit.length;
|
|
53508
|
+
if (skipped > 0) console.log(`[errata] corroborate: ${skipped} skipped (this session authored the node)`);
|
|
53509
|
+
await sendWitnesses(
|
|
53510
|
+
"corroborate",
|
|
53511
|
+
emit,
|
|
53512
|
+
(items2, session) => cloud.reportCorroborations({
|
|
53513
|
+
daemonVersion: DAEMON_VERSION,
|
|
53514
|
+
projectId: profile.id,
|
|
53515
|
+
...session ? { sessionId: session } : {},
|
|
53516
|
+
items: stampWitnessOrigin(items2, profile.id)
|
|
53517
|
+
})
|
|
53333
53518
|
);
|
|
53334
53519
|
}
|
|
53335
53520
|
} catch (err2) {
|
|
@@ -53522,7 +53707,7 @@ function createWorkspaceEngine(opts) {
|
|
|
53522
53707
|
try {
|
|
53523
53708
|
const inputs = emitInputsFromManifest(paths.configDir, paths.skillsManifest);
|
|
53524
53709
|
emitAndProjectSkills(opts.workspaceRoot, inputs);
|
|
53525
|
-
writePrimingHandles(
|
|
53710
|
+
writePrimingHandles(join24(paths.configDir, "priming-handles.json"), skillHandleNodes(inputs));
|
|
53526
53711
|
} catch (err2) {
|
|
53527
53712
|
console.warn("[skills] agent-skills projection failed (non-fatal):", err2 instanceof Error ? err2.message : err2);
|
|
53528
53713
|
}
|
|
@@ -53796,7 +53981,7 @@ async function startDaemon(opts) {
|
|
|
53796
53981
|
reviewUrl: () => webUiUrl + "/review"
|
|
53797
53982
|
});
|
|
53798
53983
|
const writeLockFile = (url2) => {
|
|
53799
|
-
|
|
53984
|
+
writeFileSync17(
|
|
53800
53985
|
engine.paths.daemonLock,
|
|
53801
53986
|
JSON.stringify({ pid: process.pid, webUiUrl: url2, startedAt: Date.now() }),
|
|
53802
53987
|
"utf8"
|
|
@@ -53856,16 +54041,16 @@ async function listenServer(fetchFn, port) {
|
|
|
53856
54041
|
|
|
53857
54042
|
// src/registry.ts
|
|
53858
54043
|
init_paths();
|
|
53859
|
-
import { existsSync as existsSync21, readFileSync as
|
|
53860
|
-
import { join as
|
|
54044
|
+
import { existsSync as existsSync21, readFileSync as readFileSync20, writeFileSync as writeFileSync18 } from "node:fs";
|
|
54045
|
+
import { join as join25 } from "node:path";
|
|
53861
54046
|
function registryPath() {
|
|
53862
|
-
return process.env["ERRATA_REGISTRY_PATH"] ??
|
|
54047
|
+
return process.env["ERRATA_REGISTRY_PATH"] ?? join25(globalDir(), "workspaces.json");
|
|
53863
54048
|
}
|
|
53864
54049
|
function read() {
|
|
53865
54050
|
const p = registryPath();
|
|
53866
54051
|
if (!existsSync21(p)) return { version: 1, workspaces: {} };
|
|
53867
54052
|
try {
|
|
53868
|
-
const parsed = JSON.parse(
|
|
54053
|
+
const parsed = JSON.parse(readFileSync20(p, "utf8"));
|
|
53869
54054
|
return { version: 1, workspaces: parsed.workspaces ?? {} };
|
|
53870
54055
|
} catch {
|
|
53871
54056
|
return { version: 1, workspaces: {} };
|
|
@@ -53873,7 +54058,7 @@ function read() {
|
|
|
53873
54058
|
}
|
|
53874
54059
|
function write(reg) {
|
|
53875
54060
|
ensureDir(globalDir());
|
|
53876
|
-
|
|
54061
|
+
writeFileSync18(registryPath(), JSON.stringify(reg, null, 2), "utf8");
|
|
53877
54062
|
}
|
|
53878
54063
|
function registerWorkspace(profile, root, now = Date.now()) {
|
|
53879
54064
|
const reg = read();
|
|
@@ -53905,7 +54090,7 @@ function workspaceStatus(entry) {
|
|
|
53905
54090
|
let webUiUrl = null;
|
|
53906
54091
|
if (existsSync21(lockPath)) {
|
|
53907
54092
|
try {
|
|
53908
|
-
const lock = JSON.parse(
|
|
54093
|
+
const lock = JSON.parse(readFileSync20(lockPath, "utf8"));
|
|
53909
54094
|
if (lock.pid && lock.webUiUrl && pidAlive(lock.pid)) {
|
|
53910
54095
|
running = true;
|
|
53911
54096
|
webUiUrl = lock.webUiUrl;
|
|
@@ -53933,7 +54118,7 @@ function pidAlive(pid) {
|
|
|
53933
54118
|
// src/multi.ts
|
|
53934
54119
|
init_dist();
|
|
53935
54120
|
init_src4();
|
|
53936
|
-
import { readFileSync as
|
|
54121
|
+
import { readFileSync as readFileSync23, unlinkSync as unlinkSync3, writeFileSync as writeFileSync19 } from "node:fs";
|
|
53937
54122
|
|
|
53938
54123
|
// src/principle-sync.ts
|
|
53939
54124
|
init_src4();
|
|
@@ -53961,8 +54146,8 @@ init_reconcile();
|
|
|
53961
54146
|
|
|
53962
54147
|
// src/lockfile-auto.ts
|
|
53963
54148
|
init_src();
|
|
53964
|
-
import { existsSync as existsSync22, readFileSync as
|
|
53965
|
-
import { join as
|
|
54149
|
+
import { existsSync as existsSync22, readFileSync as readFileSync21 } from "node:fs";
|
|
54150
|
+
import { join as join26 } from "node:path";
|
|
53966
54151
|
|
|
53967
54152
|
// src/package-index.ts
|
|
53968
54153
|
init_src();
|
|
@@ -54111,11 +54296,11 @@ function runLockfilePass(opts) {
|
|
|
54111
54296
|
{ file: "package-lock.json", parse: parsePackageLockJson }
|
|
54112
54297
|
];
|
|
54113
54298
|
for (const c of candidates) {
|
|
54114
|
-
const p =
|
|
54299
|
+
const p = join26(opts.root, c.file);
|
|
54115
54300
|
if (!existsSync22(p)) continue;
|
|
54116
54301
|
let sbom;
|
|
54117
54302
|
try {
|
|
54118
|
-
sbom = c.parse(
|
|
54303
|
+
sbom = c.parse(readFileSync21(p, "utf8"));
|
|
54119
54304
|
} catch {
|
|
54120
54305
|
continue;
|
|
54121
54306
|
}
|
|
@@ -54225,10 +54410,15 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
|
|
|
54225
54410
|
const level = opts.level ?? 1;
|
|
54226
54411
|
const noveltyOpts = opts.dedupCosine != null ? { dedupCosine: opts.dedupCosine } : {};
|
|
54227
54412
|
const ignored = (text) => ignorePatterns.length > 0 && ignorePatterns.some((p) => text.toLowerCase().includes(p));
|
|
54413
|
+
const originSessionOf = (n) => {
|
|
54414
|
+
const key = sessionOriginKey(n.attrs["sources"]?.[0]);
|
|
54415
|
+
return key ? { originSession: key } : {};
|
|
54416
|
+
};
|
|
54228
54417
|
const shareable = (n) => ({
|
|
54229
54418
|
...n,
|
|
54230
54419
|
description: generalize(n.description, { level }).text,
|
|
54231
54420
|
embedding: [],
|
|
54421
|
+
...originSessionOf(n),
|
|
54232
54422
|
attrs: {
|
|
54233
54423
|
scope: stripCodebaseScope(n.attrs["scope"]),
|
|
54234
54424
|
...n.attrs["kind"] ? { kind: n.attrs["kind"] } : {},
|
|
@@ -54558,7 +54748,7 @@ var ConsolidateWorker = class {
|
|
|
54558
54748
|
init_paths();
|
|
54559
54749
|
|
|
54560
54750
|
// src/lock.ts
|
|
54561
|
-
import { existsSync as existsSync23, readFileSync as
|
|
54751
|
+
import { existsSync as existsSync23, readFileSync as readFileSync22 } from "node:fs";
|
|
54562
54752
|
function isProcessAlive(pid) {
|
|
54563
54753
|
if (!pid || pid <= 0) return false;
|
|
54564
54754
|
try {
|
|
@@ -54571,7 +54761,7 @@ function isProcessAlive(pid) {
|
|
|
54571
54761
|
function readDaemonLock(lockPath) {
|
|
54572
54762
|
if (!existsSync23(lockPath)) return null;
|
|
54573
54763
|
try {
|
|
54574
|
-
const lock = JSON.parse(
|
|
54764
|
+
const lock = JSON.parse(readFileSync22(lockPath, "utf8"));
|
|
54575
54765
|
return typeof lock.pid === "number" ? lock : null;
|
|
54576
54766
|
} catch {
|
|
54577
54767
|
return null;
|
|
@@ -54588,6 +54778,39 @@ init_config();
|
|
|
54588
54778
|
// src/update.ts
|
|
54589
54779
|
import { spawn as spawn2 } from "node:child_process";
|
|
54590
54780
|
var PACKAGE_NAME = "@inerrata-corporation/errata";
|
|
54781
|
+
function parse3(v) {
|
|
54782
|
+
const m = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z][0-9A-Za-z.-]*))?/.exec(v.trim());
|
|
54783
|
+
if (!m) return null;
|
|
54784
|
+
return {
|
|
54785
|
+
base: [Number(m[1]), Number(m[2]), Number(m[3])],
|
|
54786
|
+
pre: m[4] === void 0 ? null : m[4].split(/[.-]/).map((p) => /^\d+$/.test(p) ? Number(p) : p)
|
|
54787
|
+
};
|
|
54788
|
+
}
|
|
54789
|
+
function compareVersions(a, b) {
|
|
54790
|
+
const pa = parse3(a);
|
|
54791
|
+
const pb = parse3(b);
|
|
54792
|
+
if (!pa || !pb) return 0;
|
|
54793
|
+
const [aMaj, aMin, aPatch] = pa.base;
|
|
54794
|
+
const [bMaj, bMin, bPatch] = pb.base;
|
|
54795
|
+
if (aMaj !== bMaj) return aMaj - bMaj;
|
|
54796
|
+
if (aMin !== bMin) return aMin - bMin;
|
|
54797
|
+
if (aPatch !== bPatch) return aPatch - bPatch;
|
|
54798
|
+
if (pa.pre === null && pb.pre === null) return 0;
|
|
54799
|
+
if (pa.pre === null) return 1;
|
|
54800
|
+
if (pb.pre === null) return -1;
|
|
54801
|
+
for (let i2 = 0; i2 < Math.max(pa.pre.length, pb.pre.length); i2++) {
|
|
54802
|
+
const x = pa.pre[i2];
|
|
54803
|
+
const y = pb.pre[i2];
|
|
54804
|
+
if (x === void 0) return -1;
|
|
54805
|
+
if (y === void 0) return 1;
|
|
54806
|
+
if (x === y) continue;
|
|
54807
|
+
if (typeof x === "number" && typeof y === "number") return x - y;
|
|
54808
|
+
if (typeof x === "number") return -1;
|
|
54809
|
+
if (typeof y === "number") return 1;
|
|
54810
|
+
return x < y ? -1 : 1;
|
|
54811
|
+
}
|
|
54812
|
+
return 0;
|
|
54813
|
+
}
|
|
54591
54814
|
async function latestPublished(channel, timeoutMs = 4e3) {
|
|
54592
54815
|
const ctrl = new AbortController();
|
|
54593
54816
|
const timer = setTimeout(() => ctrl.abort(), timeoutMs);
|
|
@@ -54607,10 +54830,14 @@ async function latestPublished(channel, timeoutMs = 4e3) {
|
|
|
54607
54830
|
}
|
|
54608
54831
|
async function checkForUpdate(channel) {
|
|
54609
54832
|
const latest = await latestPublished(channel);
|
|
54833
|
+
const direction = latest === null ? 0 : compareVersions(latest, DAEMON_VERSION);
|
|
54610
54834
|
return {
|
|
54611
54835
|
current: DAEMON_VERSION,
|
|
54612
54836
|
latest,
|
|
54613
|
-
|
|
54837
|
+
// `compareVersions` returns 0 for unparseable input, so an unrecognizable tag
|
|
54838
|
+
// is treated as "nothing to do" rather than gambling on a direction.
|
|
54839
|
+
updateAvailable: latest !== null && direction > 0,
|
|
54840
|
+
downgradeAvailable: latest !== null && direction < 0
|
|
54614
54841
|
};
|
|
54615
54842
|
}
|
|
54616
54843
|
var POLL_INTERVAL_MS = {
|
|
@@ -54814,12 +55041,12 @@ async function reanchorProject(opts) {
|
|
|
54814
55041
|
|
|
54815
55042
|
// src/adopt.ts
|
|
54816
55043
|
import { existsSync as existsSync24 } from "node:fs";
|
|
54817
|
-
import { dirname as
|
|
55044
|
+
import { dirname as dirname10, join as join27 } from "node:path";
|
|
54818
55045
|
function findGitRoot(absPath) {
|
|
54819
55046
|
let dir = absPath;
|
|
54820
55047
|
for (let depth = 0; depth < 64; depth++) {
|
|
54821
|
-
if (existsSync24(
|
|
54822
|
-
const parent =
|
|
55048
|
+
if (existsSync24(join27(dir, ".git"))) return dir;
|
|
55049
|
+
const parent = dirname10(dir);
|
|
54823
55050
|
if (parent === dir) return null;
|
|
54824
55051
|
dir = parent;
|
|
54825
55052
|
}
|
|
@@ -55067,7 +55294,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
55067
55294
|
void ambientLinkAll();
|
|
55068
55295
|
app.route(`/ws/${rec.id}`, rec.webApp);
|
|
55069
55296
|
try {
|
|
55070
|
-
|
|
55297
|
+
writeFileSync19(
|
|
55071
55298
|
rec.engine.paths.daemonLock,
|
|
55072
55299
|
JSON.stringify({ pid: process.pid, webUiUrl: `${baseUrl}/ws/${rec.id}`, startedAt: Date.now() }),
|
|
55073
55300
|
"utf8"
|
|
@@ -55256,7 +55483,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
55256
55483
|
baseUrl = `http://127.0.0.1:${port}`;
|
|
55257
55484
|
try {
|
|
55258
55485
|
ensureDir(globalDir());
|
|
55259
|
-
|
|
55486
|
+
writeFileSync19(
|
|
55260
55487
|
lockPath,
|
|
55261
55488
|
JSON.stringify({ pid: process.pid, webUiUrl: baseUrl, startedAt: Date.now() }),
|
|
55262
55489
|
"utf8"
|
|
@@ -55265,7 +55492,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
55265
55492
|
}
|
|
55266
55493
|
for (const r of records) {
|
|
55267
55494
|
try {
|
|
55268
|
-
|
|
55495
|
+
writeFileSync19(
|
|
55269
55496
|
r.engine.paths.daemonLock,
|
|
55270
55497
|
JSON.stringify({ pid: process.pid, webUiUrl: `${baseUrl}/ws/${r.id}`, startedAt: Date.now() }),
|
|
55271
55498
|
"utf8"
|
|
@@ -55592,6 +55819,11 @@ async function startMultiDaemon(opts = {}) {
|
|
|
55592
55819
|
if (!local) continue;
|
|
55593
55820
|
store.updateNode(localId, { attrs: { ...local.attrs, contributedAtSeq: seq } });
|
|
55594
55821
|
}
|
|
55822
|
+
if (p.blockedNodeIds?.length) {
|
|
55823
|
+
console.log(
|
|
55824
|
+
`[sync\u2192cloud] [${projectName}] context: ${p.blockedNodeIds.length} node(s) refused by an edge/CDN filter on content \u2014 left pending, will retry`
|
|
55825
|
+
);
|
|
55826
|
+
}
|
|
55595
55827
|
noteFlushProgress(p.accepted, p.nodeIds.length, `context ${p.chunkIndex}/${p.totalChunks}`);
|
|
55596
55828
|
}
|
|
55597
55829
|
});
|
|
@@ -55621,9 +55853,18 @@ async function startMultiDaemon(opts = {}) {
|
|
|
55621
55853
|
if (instances) {
|
|
55622
55854
|
if (project) instances.projectId = project.projectId;
|
|
55623
55855
|
await lane("instances", projectName, async () => {
|
|
55856
|
+
const blocked = /* @__PURE__ */ new Set();
|
|
55624
55857
|
const res = await client.ingest(instances, {
|
|
55625
|
-
onChunk: (p) =>
|
|
55858
|
+
onChunk: (p) => {
|
|
55859
|
+
for (const id of p.blockedNodeIds ?? []) blocked.add(id);
|
|
55860
|
+
noteFlushProgress(p.accepted, p.nodeIds.length, `instances ${p.chunkIndex}/${p.totalChunks}`);
|
|
55861
|
+
}
|
|
55626
55862
|
});
|
|
55863
|
+
if (blocked.size > 0) {
|
|
55864
|
+
console.log(
|
|
55865
|
+
`[sync\u2192cloud] [${projectName}] instances: ${blocked.size} node(s) refused by an edge/CDN filter on content \u2014 left pending, will retry. First: ${store.getNode([...blocked][0])?.description.slice(0, 120) ?? [...blocked][0]}`
|
|
55866
|
+
);
|
|
55867
|
+
}
|
|
55627
55868
|
uploaded += res.accepted;
|
|
55628
55869
|
const seq = store.currentIngestSeq();
|
|
55629
55870
|
const cloudIdByLocal = new Map(
|
|
@@ -55632,6 +55873,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
55632
55873
|
for (const n of instances.nodes) {
|
|
55633
55874
|
const local = store.getNode(n.id);
|
|
55634
55875
|
if (!local || !["Problem", "Solution", "RootCause"].includes(local.label)) continue;
|
|
55876
|
+
if (blocked.has(n.id)) continue;
|
|
55635
55877
|
const cloudNodeId = cloudIdByLocal.get(n.id);
|
|
55636
55878
|
store.updateNode(n.id, {
|
|
55637
55879
|
attrs: {
|
|
@@ -55748,7 +55990,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
55748
55990
|
},
|
|
55749
55991
|
async stop() {
|
|
55750
55992
|
try {
|
|
55751
|
-
const cur =
|
|
55993
|
+
const cur = readFileSync23(lockPath, "utf8");
|
|
55752
55994
|
if (JSON.parse(cur).pid === process.pid) unlinkSync3(lockPath);
|
|
55753
55995
|
} catch {
|
|
55754
55996
|
}
|
|
@@ -56766,20 +57008,20 @@ async function cmdInit() {
|
|
|
56766
57008
|
console.log("");
|
|
56767
57009
|
console.log("installing harness hooks...");
|
|
56768
57010
|
const { existsSync: existsSync26 } = await import("node:fs");
|
|
56769
|
-
const { join:
|
|
57011
|
+
const { join: join29 } = await import("node:path");
|
|
56770
57012
|
try {
|
|
56771
57013
|
await installClaudeHooks(port);
|
|
56772
57014
|
} catch (err2) {
|
|
56773
57015
|
console.warn(` \u26A0\uFE0F Claude hook install failed: ${err2 instanceof Error ? err2.message : err2}`);
|
|
56774
57016
|
}
|
|
56775
|
-
if (existsSync26(
|
|
57017
|
+
if (existsSync26(join29(ROOT, ".cursor"))) {
|
|
56776
57018
|
try {
|
|
56777
57019
|
await installCursorMcpConfig();
|
|
56778
57020
|
} catch (err2) {
|
|
56779
57021
|
console.warn(` \u26A0\uFE0F Cursor MCP config failed: ${err2 instanceof Error ? err2.message : err2}`);
|
|
56780
57022
|
}
|
|
56781
57023
|
}
|
|
56782
|
-
if (existsSync26(
|
|
57024
|
+
if (existsSync26(join29(ROOT, ".codex"))) {
|
|
56783
57025
|
try {
|
|
56784
57026
|
await installCodexHooks(port);
|
|
56785
57027
|
} catch (err2) {
|
|
@@ -57073,9 +57315,11 @@ async function cmdUpdate(args2) {
|
|
|
57073
57315
|
const cfg = loadConfig();
|
|
57074
57316
|
let channel = cfg.updateChannel;
|
|
57075
57317
|
let checkOnly = false;
|
|
57318
|
+
let allowDowngrade = false;
|
|
57076
57319
|
for (let i2 = 0; i2 < args2.length; i2++) {
|
|
57077
57320
|
const a = args2[i2];
|
|
57078
57321
|
if (a === "--check") checkOnly = true;
|
|
57322
|
+
else if (a === "--allow-downgrade") allowDowngrade = true;
|
|
57079
57323
|
else if (a === "--channel") {
|
|
57080
57324
|
const v = args2[++i2];
|
|
57081
57325
|
if (v === "dev" || v === "latest") channel = v;
|
|
@@ -57096,8 +57340,19 @@ async function cmdUpdate(args2) {
|
|
|
57096
57340
|
return;
|
|
57097
57341
|
}
|
|
57098
57342
|
if (!status.updateAvailable) {
|
|
57099
|
-
|
|
57100
|
-
|
|
57343
|
+
if (status.downgradeAvailable) {
|
|
57344
|
+
console.log(
|
|
57345
|
+
`channel '${channel}' points at ${status.latest}, which is OLDER than the running ${status.current}.`
|
|
57346
|
+
);
|
|
57347
|
+
console.log(` not installing \u2014 a downgrade past a store migration cannot open its own graph.`);
|
|
57348
|
+
console.log(` if this is a deliberate rollback: errata update --allow-downgrade`);
|
|
57349
|
+
if (!allowDowngrade) return;
|
|
57350
|
+
console.log(`
|
|
57351
|
+
--allow-downgrade given; proceeding.`);
|
|
57352
|
+
} else {
|
|
57353
|
+
console.log(`errata is up to date \u2014 ${status.current} (channel: ${channel})`);
|
|
57354
|
+
return;
|
|
57355
|
+
}
|
|
57101
57356
|
}
|
|
57102
57357
|
console.log(`update available: ${status.current} \u2192 ${status.latest} (channel: ${channel})`);
|
|
57103
57358
|
if (checkOnly) {
|
|
@@ -57593,7 +57848,7 @@ async function cmdReview() {
|
|
|
57593
57848
|
console.log("(review queue empty)");
|
|
57594
57849
|
return;
|
|
57595
57850
|
}
|
|
57596
|
-
const queue = JSON.parse(
|
|
57851
|
+
const queue = JSON.parse(readFileSync24(paths.reviewQueue, "utf8"));
|
|
57597
57852
|
if (queue.length === 0) {
|
|
57598
57853
|
console.log("(review queue empty)");
|
|
57599
57854
|
return;
|
|
@@ -58303,7 +58558,7 @@ async function gatherReportData(generatedAt) {
|
|
|
58303
58558
|
};
|
|
58304
58559
|
}
|
|
58305
58560
|
async function cmdReport(args2) {
|
|
58306
|
-
const { mkdirSync: mkdirSync8, writeFileSync:
|
|
58561
|
+
const { mkdirSync: mkdirSync8, writeFileSync: writeFileSync20 } = await import("node:fs");
|
|
58307
58562
|
const { renderReport: renderReport2 } = await Promise.resolve().then(() => (init_report_render(), report_render_exports));
|
|
58308
58563
|
const includeFutureVerbs = args2.includes("--future-verbs");
|
|
58309
58564
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -58316,8 +58571,8 @@ async function cmdReport(args2) {
|
|
|
58316
58571
|
const outDir = workspacePaths(ROOT).configDir;
|
|
58317
58572
|
mkdirSync8(outDir, { recursive: true });
|
|
58318
58573
|
const files = renderReport2(data, { includeFutureVerbs });
|
|
58319
|
-
for (const f of files)
|
|
58320
|
-
const indexPath =
|
|
58574
|
+
for (const f of files) writeFileSync20(join28(outDir, f.name), f.html, "utf8");
|
|
58575
|
+
const indexPath = join28(outDir, "report.html");
|
|
58321
58576
|
console.log(`report \u2192 ${indexPath}`);
|
|
58322
58577
|
console.log(
|
|
58323
58578
|
` ${data.repos.length} repo(s) \xB7 ${files.length} file(s) \xB7 ${data.rollup.nodes.toLocaleString("en-US")} nodes`
|
|
@@ -58369,7 +58624,7 @@ function spawnDaemonDetached() {
|
|
|
58369
58624
|
try {
|
|
58370
58625
|
const logPath = daemonLogPath();
|
|
58371
58626
|
try {
|
|
58372
|
-
if (statSync6(logPath).size > 5 * 1024 * 1024)
|
|
58627
|
+
if (statSync6(logPath).size > 5 * 1024 * 1024) renameSync4(logPath, `${logPath}.1`);
|
|
58373
58628
|
} catch {
|
|
58374
58629
|
}
|
|
58375
58630
|
out2 = openSync2(logPath, "a");
|
|
@@ -58435,15 +58690,15 @@ function hookRelayCommand(port, path2) {
|
|
|
58435
58690
|
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
58691
|
}
|
|
58437
58692
|
async function installClaudeHooks(port) {
|
|
58438
|
-
const { mkdirSync: mkdirSync8, existsSync: existsSync26, readFileSync:
|
|
58439
|
-
const { join:
|
|
58440
|
-
const dir =
|
|
58693
|
+
const { mkdirSync: mkdirSync8, existsSync: existsSync26, readFileSync: readFileSync25, writeFileSync: writeFileSync20 } = await import("node:fs");
|
|
58694
|
+
const { join: join29 } = await import("node:path");
|
|
58695
|
+
const dir = join29(ROOT, ".claude");
|
|
58441
58696
|
if (!existsSync26(dir)) mkdirSync8(dir, { recursive: true });
|
|
58442
|
-
const file2 =
|
|
58697
|
+
const file2 = join29(dir, "settings.json");
|
|
58443
58698
|
let settings = {};
|
|
58444
58699
|
if (existsSync26(file2)) {
|
|
58445
58700
|
try {
|
|
58446
|
-
settings = JSON.parse(
|
|
58701
|
+
settings = JSON.parse(readFileSync25(file2, "utf8"));
|
|
58447
58702
|
} catch {
|
|
58448
58703
|
console.error(`refusing to overwrite invalid JSON at ${file2}`);
|
|
58449
58704
|
process.exit(2);
|
|
@@ -58489,10 +58744,10 @@ async function installClaudeHooks(port) {
|
|
|
58489
58744
|
dropErrata(list);
|
|
58490
58745
|
list.push({ hooks: [{ type: "command", command: injectCmd }] });
|
|
58491
58746
|
}
|
|
58492
|
-
|
|
58747
|
+
writeFileSync20(file2, JSON.stringify(settings, null, 2) + "\n", "utf8");
|
|
58493
58748
|
console.log(`installed Claude Code hooks \u2192 ${file2}`);
|
|
58494
58749
|
await installClaudeMcpConfig();
|
|
58495
|
-
const claudeMd =
|
|
58750
|
+
const claudeMd = join29(ROOT, "CLAUDE.md");
|
|
58496
58751
|
const recall = writeManagedBlock(claudeMd, { body: RECALL_FIRST_BLOCK });
|
|
58497
58752
|
if (recall.kind === "collision") {
|
|
58498
58753
|
console.warn(
|
|
@@ -58504,15 +58759,15 @@ async function installClaudeHooks(port) {
|
|
|
58504
58759
|
console.log(` endpoint: http://127.0.0.1:${port}/api/hook`);
|
|
58505
58760
|
}
|
|
58506
58761
|
async function installClaudeMcpConfig() {
|
|
58507
|
-
const { mkdirSync: mkdirSync8, existsSync: existsSync26, readFileSync:
|
|
58508
|
-
const { join:
|
|
58509
|
-
const file2 =
|
|
58510
|
-
const dir =
|
|
58762
|
+
const { mkdirSync: mkdirSync8, existsSync: existsSync26, readFileSync: readFileSync25, writeFileSync: writeFileSync20 } = await import("node:fs");
|
|
58763
|
+
const { join: join29, dirname: dirname11 } = await import("node:path");
|
|
58764
|
+
const file2 = join29(ROOT, ".mcp.json");
|
|
58765
|
+
const dir = dirname11(file2);
|
|
58511
58766
|
if (!existsSync26(dir)) mkdirSync8(dir, { recursive: true });
|
|
58512
58767
|
let cfg = {};
|
|
58513
58768
|
if (existsSync26(file2)) {
|
|
58514
58769
|
try {
|
|
58515
|
-
cfg = JSON.parse(
|
|
58770
|
+
cfg = JSON.parse(readFileSync25(file2, "utf8"));
|
|
58516
58771
|
} catch {
|
|
58517
58772
|
console.error(`refusing to overwrite invalid JSON at ${file2}`);
|
|
58518
58773
|
process.exit(2);
|
|
@@ -58520,21 +58775,21 @@ async function installClaudeMcpConfig() {
|
|
|
58520
58775
|
}
|
|
58521
58776
|
cfg.mcpServers ??= {};
|
|
58522
58777
|
cfg.mcpServers["errata"] = errataMcpInvocation();
|
|
58523
|
-
|
|
58778
|
+
writeFileSync20(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
|
|
58524
58779
|
console.log(`installed Claude Code MCP server config \u2192 ${file2}`);
|
|
58525
58780
|
console.log(` Claude Code will spawn \`errata mcp\` on workspace open.`);
|
|
58526
58781
|
console.log(` Tools: errata.search / locate / neighbors / callers_of / what_uses / show / similar`);
|
|
58527
58782
|
}
|
|
58528
58783
|
async function installCursorMcpConfig() {
|
|
58529
|
-
const { mkdirSync: mkdirSync8, existsSync: existsSync26, readFileSync:
|
|
58530
|
-
const { join:
|
|
58531
|
-
const dir =
|
|
58784
|
+
const { mkdirSync: mkdirSync8, existsSync: existsSync26, readFileSync: readFileSync25, writeFileSync: writeFileSync20 } = await import("node:fs");
|
|
58785
|
+
const { join: join29 } = await import("node:path");
|
|
58786
|
+
const dir = join29(ROOT, ".cursor");
|
|
58532
58787
|
if (!existsSync26(dir)) mkdirSync8(dir, { recursive: true });
|
|
58533
|
-
const file2 =
|
|
58788
|
+
const file2 = join29(dir, "mcp.json");
|
|
58534
58789
|
let cfg = {};
|
|
58535
58790
|
if (existsSync26(file2)) {
|
|
58536
58791
|
try {
|
|
58537
|
-
cfg = JSON.parse(
|
|
58792
|
+
cfg = JSON.parse(readFileSync25(file2, "utf8"));
|
|
58538
58793
|
} catch {
|
|
58539
58794
|
console.error(`refusing to overwrite invalid JSON at ${file2}`);
|
|
58540
58795
|
process.exit(2);
|
|
@@ -58542,7 +58797,7 @@ async function installCursorMcpConfig() {
|
|
|
58542
58797
|
}
|
|
58543
58798
|
cfg.mcpServers ??= {};
|
|
58544
58799
|
cfg.mcpServers["errata"] = errataMcpInvocation();
|
|
58545
|
-
|
|
58800
|
+
writeFileSync20(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
|
|
58546
58801
|
console.log(`installed Cursor MCP server config \u2192 ${file2}`);
|
|
58547
58802
|
console.log(` Cursor will spawn \`errata mcp\` on workspace open.`);
|
|
58548
58803
|
console.log(` Tools: errata.search / locate / neighbors / callers_of / what_uses`);
|
|
@@ -58550,16 +58805,16 @@ async function installCursorMcpConfig() {
|
|
|
58550
58805
|
console.log(` \u26A0\uFE0F reload Cursor (Cmd/Ctrl-Shift-P \u2192 "Reload Window") to pick it up.`);
|
|
58551
58806
|
}
|
|
58552
58807
|
async function installCodexHooks(port) {
|
|
58553
|
-
const { mkdirSync: mkdirSync8, existsSync: existsSync26, readFileSync:
|
|
58554
|
-
const { join:
|
|
58555
|
-
const dir =
|
|
58808
|
+
const { mkdirSync: mkdirSync8, existsSync: existsSync26, readFileSync: readFileSync25, writeFileSync: writeFileSync20 } = await import("node:fs");
|
|
58809
|
+
const { join: join29 } = await import("node:path");
|
|
58810
|
+
const dir = join29(ROOT, ".codex");
|
|
58556
58811
|
if (!existsSync26(dir)) mkdirSync8(dir, { recursive: true });
|
|
58557
|
-
const file2 =
|
|
58812
|
+
const file2 = join29(dir, "config.toml");
|
|
58558
58813
|
const BEGIN = `# >>> errata hooks (errata-managed)`;
|
|
58559
58814
|
const END = `# <<< errata hooks`;
|
|
58560
58815
|
let existing = "";
|
|
58561
58816
|
if (existsSync26(file2)) {
|
|
58562
|
-
existing =
|
|
58817
|
+
existing = readFileSync25(file2, "utf8");
|
|
58563
58818
|
const beginIdx = existing.indexOf(BEGIN);
|
|
58564
58819
|
const endIdx = existing.indexOf(END);
|
|
58565
58820
|
if (beginIdx >= 0 && endIdx > beginIdx) {
|
|
@@ -58588,7 +58843,7 @@ ${END}
|
|
|
58588
58843
|
const final = existing.length > 0 && !existing.endsWith("\n") ? `${existing}
|
|
58589
58844
|
|
|
58590
58845
|
${block}` : existing + (existing.endsWith("\n\n") ? "" : "\n") + block;
|
|
58591
|
-
|
|
58846
|
+
writeFileSync20(file2, final, "utf8");
|
|
58592
58847
|
console.log(`installed Codex hooks \u2192 ${file2}`);
|
|
58593
58848
|
console.log(` endpoint: http://127.0.0.1:${port}/api/hook`);
|
|
58594
58849
|
console.log("");
|
|
@@ -58902,7 +59157,7 @@ async function cmdDash(args2) {
|
|
|
58902
59157
|
await yieldToLoop2();
|
|
58903
59158
|
try {
|
|
58904
59159
|
const items = selectDurableMemory(handle2.sharedStore, r.engine.profile);
|
|
58905
|
-
const res = bleedRules(
|
|
59160
|
+
const res = bleedRules(join28(r.root, ".claude", "rules"), items);
|
|
58906
59161
|
if (res.written || res.pruned) {
|
|
58907
59162
|
console.log(
|
|
58908
59163
|
`[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
|