@inerrata-corporation/errata 2.0.2-dev.227 → 2.0.2-dev.247
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 +112 -16
- package/errata.mjs +528 -210
- package/package.json +1 -1
- package/pass-worker.mjs +112 -16
package/errata.mjs
CHANGED
|
@@ -16410,6 +16410,21 @@ var init_src2 = __esm({
|
|
|
16410
16410
|
});
|
|
16411
16411
|
|
|
16412
16412
|
// ../../packages/local-graph/src/store.ts
|
|
16413
|
+
function localEdgeViolation(fromLabel, type, toLabel) {
|
|
16414
|
+
if (type in LOCAL_RULE_OVERRIDES) {
|
|
16415
|
+
const rule = LOCAL_RULE_OVERRIDES[type];
|
|
16416
|
+
if (!rule) return null;
|
|
16417
|
+
if (fromLabel && rule.from && !rule.from.includes(fromLabel)) {
|
|
16418
|
+
return `${type} cannot originate from ${fromLabel} locally (allowed: ${rule.from.join(", ")})`;
|
|
16419
|
+
}
|
|
16420
|
+
if (toLabel && rule.to && !rule.to.includes(toLabel)) {
|
|
16421
|
+
return `${type} cannot target ${toLabel} locally (allowed: ${rule.to.join(", ")})`;
|
|
16422
|
+
}
|
|
16423
|
+
return null;
|
|
16424
|
+
}
|
|
16425
|
+
const verdict = isValidEdge(fromLabel, type, toLabel);
|
|
16426
|
+
return verdict.ok ? null : verdict.reason ?? "edge rule violation";
|
|
16427
|
+
}
|
|
16413
16428
|
function encodeEmbedding(emb) {
|
|
16414
16429
|
if (!emb || emb.length === 0) return null;
|
|
16415
16430
|
const f = Float32Array.from(emb);
|
|
@@ -16484,7 +16499,7 @@ var init_store = __esm({
|
|
|
16484
16499
|
REVEALED_BY: null,
|
|
16485
16500
|
PRODUCED: null
|
|
16486
16501
|
};
|
|
16487
|
-
SCHEMA_VERSION =
|
|
16502
|
+
SCHEMA_VERSION = 6;
|
|
16488
16503
|
SCHEMA_SQL = `
|
|
16489
16504
|
CREATE TABLE IF NOT EXISTS schema_version (
|
|
16490
16505
|
version INTEGER PRIMARY KEY
|
|
@@ -16499,6 +16514,21 @@ CREATE TABLE IF NOT EXISTS store_meta (
|
|
|
16499
16514
|
value TEXT NOT NULL
|
|
16500
16515
|
);
|
|
16501
16516
|
|
|
16517
|
+
-- Durable ledger of edges the ontology gate REFUSED, keyed by edge type.
|
|
16518
|
+
-- Durable rather than in-memory for one specific reason: the status command runs
|
|
16519
|
+
-- in a SEPARATE process and opens its own store handle, so a counter living on
|
|
16520
|
+
-- the instance reads 0 there forever. That is exactly how a producer rejecting
|
|
16521
|
+
-- 100% of its output stayed invisible for 17 days. Persisting it also survives
|
|
16522
|
+
-- the daemon restart that would otherwise erase the evidence.
|
|
16523
|
+
-- Keyed by type because a systematic producer bug shows up as ONE type
|
|
16524
|
+
-- dominating; sample keeps the latest reason so the count is actionable.
|
|
16525
|
+
CREATE TABLE IF NOT EXISTS edge_rejections (
|
|
16526
|
+
type TEXT PRIMARY KEY,
|
|
16527
|
+
count INTEGER NOT NULL DEFAULT 0,
|
|
16528
|
+
last_at INTEGER NOT NULL,
|
|
16529
|
+
sample TEXT
|
|
16530
|
+
);
|
|
16531
|
+
|
|
16502
16532
|
CREATE TABLE IF NOT EXISTS nodes (
|
|
16503
16533
|
id TEXT PRIMARY KEY,
|
|
16504
16534
|
label TEXT NOT NULL,
|
|
@@ -16818,6 +16848,16 @@ CREATE INDEX IF NOT EXISTS nodes_relpath ON nodes(json_extract(attrs_json, '$.re
|
|
|
16818
16848
|
if (!cols.has(name2)) this.db.exec(ddl);
|
|
16819
16849
|
}
|
|
16820
16850
|
}
|
|
16851
|
+
if (from < 6) {
|
|
16852
|
+
this.db.exec(`
|
|
16853
|
+
CREATE TABLE IF NOT EXISTS edge_rejections (
|
|
16854
|
+
type TEXT PRIMARY KEY,
|
|
16855
|
+
count INTEGER NOT NULL DEFAULT 0,
|
|
16856
|
+
last_at INTEGER NOT NULL,
|
|
16857
|
+
sample TEXT
|
|
16858
|
+
)
|
|
16859
|
+
`);
|
|
16860
|
+
}
|
|
16821
16861
|
this.db.prepare("UPDATE schema_version SET version = ?").run(SCHEMA_VERSION);
|
|
16822
16862
|
});
|
|
16823
16863
|
}
|
|
@@ -16899,6 +16939,7 @@ CREATE INDEX IF NOT EXISTS nodes_relpath ON nodes(json_extract(attrs_json, '$.re
|
|
|
16899
16939
|
const violation = this.edgeRuleViolation(edge2);
|
|
16900
16940
|
if (violation) {
|
|
16901
16941
|
this.rejectedEdgeCount++;
|
|
16942
|
+
this.recordEdgeRejection(edge2.type, violation, edge2.lastSeenAt || edge2.createdAt || 0);
|
|
16902
16943
|
console.warn(`[local-graph] rejected edge ${edge2.from}-[:${edge2.type}]->${edge2.to}: ${violation}`);
|
|
16903
16944
|
return;
|
|
16904
16945
|
}
|
|
@@ -16923,22 +16964,51 @@ CREATE INDEX IF NOT EXISTS nodes_relpath ON nodes(json_extract(attrs_json, '$.re
|
|
|
16923
16964
|
* overlay consulted first. Returns the reason string on a documented-
|
|
16924
16965
|
* forbidden combination, else null. Point lookups on the id PK — negligible
|
|
16925
16966
|
* next to the insert itself. */
|
|
16926
|
-
|
|
16927
|
-
|
|
16928
|
-
|
|
16929
|
-
|
|
16930
|
-
|
|
16931
|
-
|
|
16932
|
-
|
|
16933
|
-
|
|
16934
|
-
|
|
16935
|
-
|
|
16936
|
-
|
|
16937
|
-
|
|
16938
|
-
|
|
16967
|
+
/** Upsert one refusal into the durable ledger. Best-effort: a bookkeeping
|
|
16968
|
+
* failure must never turn a refused edge into a thrown write. */
|
|
16969
|
+
recordEdgeRejection(type, reason, at) {
|
|
16970
|
+
try {
|
|
16971
|
+
this.db.prepare(
|
|
16972
|
+
`INSERT INTO edge_rejections (type, count, last_at, sample) VALUES (?, 1, ?, ?)
|
|
16973
|
+
ON CONFLICT(type) DO UPDATE SET
|
|
16974
|
+
count = count + 1, last_at = excluded.last_at, sample = excluded.sample`
|
|
16975
|
+
).run(type, at, reason.slice(0, 200));
|
|
16976
|
+
} catch {
|
|
16977
|
+
}
|
|
16978
|
+
}
|
|
16979
|
+
/** Refusals recorded by the ontology gate, per edge type, newest activity first.
|
|
16980
|
+
* Durable across restarts and readable from any process (see the table note). */
|
|
16981
|
+
edgeRejections() {
|
|
16982
|
+
try {
|
|
16983
|
+
return this.db.prepare(
|
|
16984
|
+
"SELECT type, count, last_at AS lastAt, sample FROM edge_rejections ORDER BY count DESC, last_at DESC"
|
|
16985
|
+
).all();
|
|
16986
|
+
} catch {
|
|
16987
|
+
return [];
|
|
16988
|
+
}
|
|
16989
|
+
}
|
|
16990
|
+
/** Drop ledger entries whose last refusal predates `cutoff`. A still-misbehaving
|
|
16991
|
+
* producer keeps refreshing `last_at` and survives; a fixed one fades out. */
|
|
16992
|
+
pruneEdgeRejections(cutoff) {
|
|
16993
|
+
try {
|
|
16994
|
+
this.db.prepare("DELETE FROM edge_rejections WHERE last_at < ?").run(cutoff);
|
|
16995
|
+
} catch {
|
|
16996
|
+
}
|
|
16997
|
+
}
|
|
16998
|
+
/** Clear the ledger outright, whole or per type — operator escape hatch. */
|
|
16999
|
+
clearEdgeRejections(type) {
|
|
17000
|
+
try {
|
|
17001
|
+
if (type) this.db.prepare("DELETE FROM edge_rejections WHERE type = ?").run(type);
|
|
17002
|
+
else this.db.exec("DELETE FROM edge_rejections");
|
|
17003
|
+
} catch {
|
|
16939
17004
|
}
|
|
16940
|
-
|
|
16941
|
-
|
|
17005
|
+
}
|
|
17006
|
+
edgeRuleViolation(edge2) {
|
|
17007
|
+
return localEdgeViolation(
|
|
17008
|
+
this.getNode(edge2.from)?.label,
|
|
17009
|
+
edge2.type,
|
|
17010
|
+
this.getNode(edge2.to)?.label
|
|
17011
|
+
);
|
|
16942
17012
|
}
|
|
16943
17013
|
updateEdge(id, patch) {
|
|
16944
17014
|
this.stmts.updateEdge.run({
|
|
@@ -17075,6 +17145,32 @@ CREATE INDEX IF NOT EXISTS nodes_relpath ON nodes(json_extract(attrs_json, '$.re
|
|
|
17075
17145
|
const rows = this.db.prepare("SELECT from_id, to_id, type FROM edges WHERE valid_to IS NULL").all();
|
|
17076
17146
|
return rows.map((r) => ({ from: r.from_id, to: r.to_id, type: r.type }));
|
|
17077
17147
|
}
|
|
17148
|
+
/**
|
|
17149
|
+
* Live edges WITH their endpoint labels and ids, resolved in ONE join.
|
|
17150
|
+
*
|
|
17151
|
+
* The ontology sweep needs (id, type, fromLabel, toLabel) for every live edge.
|
|
17152
|
+
* Doing that as `scanLiveEdges()` + two `getNode()` calls is 2N node reads —
|
|
17153
|
+
* 550,000 on this store — and each one deserializes the node's embedding blob.
|
|
17154
|
+
* Measured: the sweep did not finish in 10 minutes. As a single join it is one
|
|
17155
|
+
* query over an index-covered scan. Labels only; nothing here touches embeddings.
|
|
17156
|
+
*/
|
|
17157
|
+
scanLiveEdgeRows() {
|
|
17158
|
+
const rows = this.db.prepare(
|
|
17159
|
+
`SELECT e.id, e.from_id, e.to_id, e.type, a.label AS from_label, b.label AS to_label
|
|
17160
|
+
FROM edges e
|
|
17161
|
+
LEFT JOIN nodes a ON a.id = e.from_id AND a.valid_to IS NULL
|
|
17162
|
+
LEFT JOIN nodes b ON b.id = e.to_id AND b.valid_to IS NULL
|
|
17163
|
+
WHERE e.valid_to IS NULL`
|
|
17164
|
+
).all();
|
|
17165
|
+
return rows.map((r) => ({
|
|
17166
|
+
id: r.id,
|
|
17167
|
+
from: r.from_id,
|
|
17168
|
+
to: r.to_id,
|
|
17169
|
+
type: r.type,
|
|
17170
|
+
fromLabel: r.from_label ?? void 0,
|
|
17171
|
+
toLabel: r.to_label ?? void 0
|
|
17172
|
+
}));
|
|
17173
|
+
}
|
|
17078
17174
|
/** Live nodes whose attrs.relPath is one of `relPaths`. Uses the nodes_relpath
|
|
17079
17175
|
* expression index so the incremental reindex fetches only the changed files'
|
|
17080
17176
|
* symbols instead of scanning every versioned node. */
|
|
@@ -20879,6 +20975,7 @@ __export(src_exports2, {
|
|
|
20879
20975
|
linkProblemToPackages: () => linkProblemToPackages,
|
|
20880
20976
|
linkProblemToSymbols: () => linkProblemToSymbols,
|
|
20881
20977
|
listNeedsRevisit: () => listNeedsRevisit,
|
|
20978
|
+
localEdgeViolation: () => localEdgeViolation,
|
|
20882
20979
|
markRevisit: () => markRevisit,
|
|
20883
20980
|
matchLanguagesInText: () => matchLanguagesInText,
|
|
20884
20981
|
matchPackagesInText: () => matchPackagesInText,
|
|
@@ -21643,6 +21740,7 @@ var init_oauth = __esm({
|
|
|
21643
21740
|
|
|
21644
21741
|
// ../../packages/cloud-client/src/client.ts
|
|
21645
21742
|
import { randomUUID } from "node:crypto";
|
|
21743
|
+
import { gzipSync } from "node:zlib";
|
|
21646
21744
|
function wirePerContext(value) {
|
|
21647
21745
|
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
21648
21746
|
const out2 = {};
|
|
@@ -21840,6 +21938,11 @@ function normalizeSolution(input) {
|
|
|
21840
21938
|
validationSource: input.validationSource
|
|
21841
21939
|
};
|
|
21842
21940
|
}
|
|
21941
|
+
function isIntermediaryRejection(err2) {
|
|
21942
|
+
if (!(err2 instanceof CloudError)) return false;
|
|
21943
|
+
if (err2.status < 400 || err2.status >= 500) return false;
|
|
21944
|
+
return /<!DOCTYPE html|<html/i.test(err2.message);
|
|
21945
|
+
}
|
|
21843
21946
|
function chunkArray(items, size) {
|
|
21844
21947
|
if (items.length <= size) return items.length ? [[...items]] : [];
|
|
21845
21948
|
const out2 = [];
|
|
@@ -21857,7 +21960,7 @@ function provenanceHeaders(provenance) {
|
|
|
21857
21960
|
...provenance.agentModel ? { "x-inerrata-agent-model": provenance.agentModel } : {}
|
|
21858
21961
|
};
|
|
21859
21962
|
}
|
|
21860
|
-
var asWireCount, INGEST_NODE_CHUNK, CloudClient, CloudError;
|
|
21963
|
+
var asWireCount, INGEST_NODE_CHUNK, COMPRESS_MIN_BYTES, CloudClient, CloudError;
|
|
21861
21964
|
var init_client = __esm({
|
|
21862
21965
|
"../../packages/cloud-client/src/client.ts"() {
|
|
21863
21966
|
"use strict";
|
|
@@ -21865,6 +21968,7 @@ var init_client = __esm({
|
|
|
21865
21968
|
init_src();
|
|
21866
21969
|
asWireCount = (n) => typeof n === "number" && Number.isFinite(n) && n >= 0 ? Math.floor(n) : null;
|
|
21867
21970
|
INGEST_NODE_CHUNK = 8;
|
|
21971
|
+
COMPRESS_MIN_BYTES = 4096;
|
|
21868
21972
|
CloudClient = class {
|
|
21869
21973
|
baseUrl;
|
|
21870
21974
|
apiKey;
|
|
@@ -21879,6 +21983,8 @@ var init_client = __esm({
|
|
|
21879
21983
|
daemonVersion;
|
|
21880
21984
|
daemonChannel;
|
|
21881
21985
|
provenance;
|
|
21986
|
+
/** Cleared for the process once a server proves it cannot inflate (see `json`). */
|
|
21987
|
+
compressRequests;
|
|
21882
21988
|
constructor(opts) {
|
|
21883
21989
|
this.baseUrl = opts.baseUrl.replace(/\/+$/, "");
|
|
21884
21990
|
if (opts.apiKey !== void 0) this.apiKey = opts.apiKey;
|
|
@@ -21892,6 +21998,7 @@ var init_client = __esm({
|
|
|
21892
21998
|
this.timeoutMs = opts.timeoutMs ?? 15e3;
|
|
21893
21999
|
this.daemonVersion = opts.daemonVersion;
|
|
21894
22000
|
this.daemonChannel = opts.daemonChannel;
|
|
22001
|
+
this.compressRequests = opts.compressRequests ?? true;
|
|
21895
22002
|
this.provenance = opts.provenance ?? {
|
|
21896
22003
|
clientProduct: "inerrata_cloud_client",
|
|
21897
22004
|
clientKind: "sdk",
|
|
@@ -22029,18 +22136,24 @@ var init_client = __esm({
|
|
|
22029
22136
|
const startedAt = Date.now();
|
|
22030
22137
|
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);
|
|
22031
22138
|
let chunkIndex = 0;
|
|
22139
|
+
const blocked = [];
|
|
22032
22140
|
const emit = (nodeIds, accepted) => {
|
|
22033
22141
|
chunkIndex++;
|
|
22142
|
+
const refused = blocked.splice(0, blocked.length);
|
|
22143
|
+
const refusedSet = new Set(refused);
|
|
22034
22144
|
opts.onChunk?.({
|
|
22035
22145
|
chunkIndex,
|
|
22036
22146
|
totalChunks,
|
|
22037
|
-
|
|
22147
|
+
// Watermark only what actually landed — a blocked node never reached the
|
|
22148
|
+
// door, and marking it contributed would lose it permanently and silently.
|
|
22149
|
+
nodeIds: refusedSet.size ? nodeIds.filter((id) => !refusedSet.has(id)) : nodeIds,
|
|
22038
22150
|
accepted,
|
|
22039
|
-
elapsedMs: Date.now() - startedAt
|
|
22151
|
+
elapsedMs: Date.now() - startedAt,
|
|
22152
|
+
...refused.length ? { blockedNodeIds: refused } : {}
|
|
22040
22153
|
});
|
|
22041
22154
|
};
|
|
22042
22155
|
if (batch.nodes.length <= INGEST_NODE_CHUNK && batch.edges.length <= MAX_EDGES_PER_PAYLOAD) {
|
|
22043
|
-
const result = await this.ingestWithSplit(batch, batch.nodes, batch.edges);
|
|
22156
|
+
const result = await this.ingestWithSplit(batch, batch.nodes, batch.edges, blocked);
|
|
22044
22157
|
const summary = summarizeIngestResult(result);
|
|
22045
22158
|
emit(batch.nodes.map((n) => n.id), summary.accepted);
|
|
22046
22159
|
return { ...summary, result };
|
|
@@ -22055,7 +22168,7 @@ var init_client = __esm({
|
|
|
22055
22168
|
const shipped = new Set(inChunk);
|
|
22056
22169
|
pendingEdges = pendingEdges.filter((e) => !shipped.has(e));
|
|
22057
22170
|
}
|
|
22058
|
-
const r = await this.ingestWithSplit(batch, nodeChunk, inChunk);
|
|
22171
|
+
const r = await this.ingestWithSplit(batch, nodeChunk, inChunk, blocked);
|
|
22059
22172
|
emit(nodeChunk.map((n) => n.id), summarizeIngestResult(r).accepted);
|
|
22060
22173
|
merged.nodes.push(...r.nodes);
|
|
22061
22174
|
merged.edges.push(...r.edges);
|
|
@@ -22098,16 +22211,21 @@ var init_client = __esm({
|
|
|
22098
22211
|
* a verdict about the payload — splitting it would just re-send a rejected batch
|
|
22099
22212
|
* N more times — and a 409/413 has its own handling upstream.
|
|
22100
22213
|
*/
|
|
22101
|
-
async ingestWithSplit(batch, nodes, edges) {
|
|
22214
|
+
async ingestWithSplit(batch, nodes, edges, blocked) {
|
|
22102
22215
|
try {
|
|
22103
22216
|
return await this.ingestWire(toWirePayload({ ...batch, nodes, edges }, randomUUID()));
|
|
22104
22217
|
} catch (err2) {
|
|
22105
22218
|
const status = err2 instanceof CloudError ? err2.status : 0;
|
|
22106
22219
|
const timedOut = status === 502 || status === 504 || status === 408 || status === 0;
|
|
22107
|
-
|
|
22220
|
+
const refusedAtEdge = blocked !== void 0 && isIntermediaryRejection(err2);
|
|
22221
|
+
if (refusedAtEdge && nodes.length === 1 && nodes[0]) {
|
|
22222
|
+
blocked.push(nodes[0].id);
|
|
22223
|
+
return { runId: randomUUID(), nodes: [], edges: [] };
|
|
22224
|
+
}
|
|
22225
|
+
if (!timedOut && !refusedAtEdge || nodes.length <= 1) throw err2;
|
|
22108
22226
|
const mid = Math.ceil(nodes.length / 2);
|
|
22109
|
-
const a = await this.ingestWithSplit(batch, nodes.slice(0, mid), edges);
|
|
22110
|
-
const b = await this.ingestWithSplit(batch, nodes.slice(mid), []);
|
|
22227
|
+
const a = await this.ingestWithSplit(batch, nodes.slice(0, mid), edges, blocked);
|
|
22228
|
+
const b = await this.ingestWithSplit(batch, nodes.slice(mid), [], blocked);
|
|
22111
22229
|
return {
|
|
22112
22230
|
runId: a.runId,
|
|
22113
22231
|
nodes: [...a.nodes, ...b.nodes],
|
|
@@ -22409,15 +22527,43 @@ var init_client = __esm({
|
|
|
22409
22527
|
const token = opts?.bearerToken ?? await this.authToken();
|
|
22410
22528
|
if (token) headers["authorization"] = `Bearer ${token}`;
|
|
22411
22529
|
}
|
|
22530
|
+
let payload;
|
|
22531
|
+
if (body2 !== void 0) {
|
|
22532
|
+
const raw2 = JSON.stringify(body2);
|
|
22533
|
+
if (this.compressRequests && Buffer.byteLength(raw2) >= COMPRESS_MIN_BYTES) {
|
|
22534
|
+
payload = gzipSync(Buffer.from(raw2));
|
|
22535
|
+
headers["content-encoding"] = "gzip";
|
|
22536
|
+
} else {
|
|
22537
|
+
payload = raw2;
|
|
22538
|
+
}
|
|
22539
|
+
}
|
|
22412
22540
|
const ac = new AbortController();
|
|
22413
22541
|
const tid = setTimeout(() => ac.abort(), this.timeoutMs);
|
|
22414
22542
|
try {
|
|
22415
22543
|
const res = await this.fetchFn(url2, {
|
|
22416
22544
|
method,
|
|
22417
22545
|
headers,
|
|
22418
|
-
body:
|
|
22546
|
+
body: payload,
|
|
22419
22547
|
signal: ac.signal
|
|
22420
22548
|
});
|
|
22549
|
+
if (res.status === 400 && headers["content-encoding"] === "gzip") {
|
|
22550
|
+
delete headers["content-encoding"];
|
|
22551
|
+
const retry = await this.fetchFn(url2, {
|
|
22552
|
+
method,
|
|
22553
|
+
headers,
|
|
22554
|
+
body: JSON.stringify(body2),
|
|
22555
|
+
signal: ac.signal
|
|
22556
|
+
});
|
|
22557
|
+
if (!retry.ok) {
|
|
22558
|
+
const text = await retry.text();
|
|
22559
|
+
throw new CloudError(
|
|
22560
|
+
`${method} ${path2} failed: HTTP ${retry.status} ${text.slice(0, 200)}`,
|
|
22561
|
+
retry.status
|
|
22562
|
+
);
|
|
22563
|
+
}
|
|
22564
|
+
this.compressRequests = false;
|
|
22565
|
+
return await retry.json();
|
|
22566
|
+
}
|
|
22421
22567
|
if (!res.ok) {
|
|
22422
22568
|
const text = await res.text();
|
|
22423
22569
|
throw new CloudError(
|
|
@@ -47262,12 +47408,12 @@ var init_report_render = __esm({
|
|
|
47262
47408
|
|
|
47263
47409
|
// src/cli.ts
|
|
47264
47410
|
init_src5();
|
|
47265
|
-
import { closeSync as closeSync2, existsSync as
|
|
47266
|
-
import { join as
|
|
47411
|
+
import { closeSync as closeSync2, existsSync as existsSync26, openSync as openSync2, readFileSync as readFileSync25, renameSync as renameSync4, statSync as statSync6 } from "node:fs";
|
|
47412
|
+
import { join as join29 } from "node:path";
|
|
47267
47413
|
import { spawn as spawn3 } from "node:child_process";
|
|
47268
47414
|
|
|
47269
47415
|
// src/daemon.ts
|
|
47270
|
-
import { existsSync as
|
|
47416
|
+
import { existsSync as existsSync21, writeFileSync as writeFileSync18 } from "node:fs";
|
|
47271
47417
|
|
|
47272
47418
|
// ../../node_modules/.pnpm/@hono+node-server@1.19.11_hono@4.12.8/node_modules/@hono/node-server/dist/index.mjs
|
|
47273
47419
|
import { createServer as createServerHTTP } from "http";
|
|
@@ -47847,8 +47993,8 @@ init_config();
|
|
|
47847
47993
|
|
|
47848
47994
|
// src/engine.ts
|
|
47849
47995
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
47850
|
-
import { existsSync as
|
|
47851
|
-
import { join as
|
|
47996
|
+
import { existsSync as existsSync20, statSync as statSync5, appendFileSync as appendFileSync2, readdirSync as readdirSync9, renameSync as renameSync3, readFileSync as readFileSync20, writeFileSync as writeFileSync17 } from "node:fs";
|
|
47997
|
+
import { join as join25, relative as relative6, sep as sep4 } from "node:path";
|
|
47852
47998
|
|
|
47853
47999
|
// ../../node_modules/.pnpm/chokidar@4.0.3/node_modules/chokidar/esm/index.js
|
|
47854
48000
|
import { stat as statcb } from "fs";
|
|
@@ -50292,6 +50438,10 @@ function tagEdgeCorroborated(targetAnchorIds, sessionTouchedNodeIds, independent
|
|
|
50292
50438
|
for (const a of targetAnchorIds) if (sessionTouchedNodeIds.has(a)) return true;
|
|
50293
50439
|
return false;
|
|
50294
50440
|
}
|
|
50441
|
+
function citeEdgeType(targetLabel2) {
|
|
50442
|
+
const t = typePriorEdge("Problem", targetLabel2);
|
|
50443
|
+
return t === "SUPERSEDES" ? "RELATES_TO" : t;
|
|
50444
|
+
}
|
|
50295
50445
|
function typePriorEdge(sourceLabel, targetLabel2, sentence = "") {
|
|
50296
50446
|
const direct = LABEL_PAIR[`${sourceLabel}>${targetLabel2}`];
|
|
50297
50447
|
if (direct) return direct;
|
|
@@ -50838,6 +50988,90 @@ function backfillConstraintKind(store, opts) {
|
|
|
50838
50988
|
return report;
|
|
50839
50989
|
}
|
|
50840
50990
|
|
|
50991
|
+
// src/edge-repair.ts
|
|
50992
|
+
init_src();
|
|
50993
|
+
init_src4();
|
|
50994
|
+
import { existsSync as existsSync14, readFileSync as readFileSync12, writeFileSync as writeFileSync12 } from "node:fs";
|
|
50995
|
+
import { join as join17 } from "node:path";
|
|
50996
|
+
function citeEdgeId(from, type, to) {
|
|
50997
|
+
return `edge_${digest({ from, type, to })}`.slice(0, 24);
|
|
50998
|
+
}
|
|
50999
|
+
var EDGE_REPAIR_VERSION = 1;
|
|
51000
|
+
var REJECTION_RETENTION_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
51001
|
+
var EMPTY2 = {
|
|
51002
|
+
skipped: true,
|
|
51003
|
+
scanned: 0,
|
|
51004
|
+
invalid: 0,
|
|
51005
|
+
retyped: 0,
|
|
51006
|
+
closed: 0,
|
|
51007
|
+
byType: {}
|
|
51008
|
+
};
|
|
51009
|
+
function markerPath2(configDir) {
|
|
51010
|
+
return join17(configDir, "edge-repair.json");
|
|
51011
|
+
}
|
|
51012
|
+
function alreadyDone2(configDir) {
|
|
51013
|
+
const p = markerPath2(configDir);
|
|
51014
|
+
if (!existsSync14(p)) return false;
|
|
51015
|
+
try {
|
|
51016
|
+
return JSON.parse(readFileSync12(p, "utf8"))?.version === EDGE_REPAIR_VERSION;
|
|
51017
|
+
} catch {
|
|
51018
|
+
return false;
|
|
51019
|
+
}
|
|
51020
|
+
}
|
|
51021
|
+
function repairInvalidEdges(store, opts) {
|
|
51022
|
+
if (!opts.force && !opts.dryRun && alreadyDone2(opts.configDir)) return EMPTY2;
|
|
51023
|
+
const report = {
|
|
51024
|
+
skipped: false,
|
|
51025
|
+
scanned: 0,
|
|
51026
|
+
invalid: 0,
|
|
51027
|
+
retyped: 0,
|
|
51028
|
+
closed: 0,
|
|
51029
|
+
byType: {}
|
|
51030
|
+
};
|
|
51031
|
+
const work = [];
|
|
51032
|
+
for (const e of store.scanLiveEdgeRows()) {
|
|
51033
|
+
report.scanned++;
|
|
51034
|
+
if (!localEdgeViolation(e.fromLabel, e.type, e.toLabel)) continue;
|
|
51035
|
+
report.invalid++;
|
|
51036
|
+
const candidate = e.toLabel ? citeEdgeType(e.toLabel) : null;
|
|
51037
|
+
const retype = candidate && candidate !== e.type && !localEdgeViolation(e.fromLabel, candidate, e.toLabel) ? candidate : null;
|
|
51038
|
+
work.push({ edge: { id: e.id, from: e.from, to: e.to, type: e.type }, retype });
|
|
51039
|
+
report.byType[e.type] = (report.byType[e.type] ?? 0) + 1;
|
|
51040
|
+
if (retype) report.retyped++;
|
|
51041
|
+
else report.closed++;
|
|
51042
|
+
}
|
|
51043
|
+
if (opts.dryRun) return report;
|
|
51044
|
+
store.transaction(() => {
|
|
51045
|
+
for (const w of work) {
|
|
51046
|
+
const prior = store.getEdge(w.edge.id);
|
|
51047
|
+
store.closeEdge(w.edge.id, opts.now);
|
|
51048
|
+
if (!w.retype || !prior) continue;
|
|
51049
|
+
store.mergeEdge({
|
|
51050
|
+
...prior,
|
|
51051
|
+
id: citeEdgeId(w.edge.from, w.retype, w.edge.to),
|
|
51052
|
+
type: w.retype,
|
|
51053
|
+
validFrom: opts.now,
|
|
51054
|
+
validTo: null,
|
|
51055
|
+
lastSeenAt: opts.now,
|
|
51056
|
+
// Mark the provenance of the rewrite so a later audit can tell a repaired
|
|
51057
|
+
// edge from one captured natively — without which this sweep would be
|
|
51058
|
+
// indistinguishable from the agent having witnessed it post-fix.
|
|
51059
|
+
attrs: { ...prior.attrs ?? {}, retypedFrom: w.edge.type, retypedBy: `edge-repair:v${EDGE_REPAIR_VERSION}` }
|
|
51060
|
+
});
|
|
51061
|
+
}
|
|
51062
|
+
});
|
|
51063
|
+
store.pruneEdgeRejections(opts.now - REJECTION_RETENTION_MS);
|
|
51064
|
+
try {
|
|
51065
|
+
writeFileSync12(
|
|
51066
|
+
markerPath2(opts.configDir),
|
|
51067
|
+
JSON.stringify({ version: EDGE_REPAIR_VERSION, at: opts.now, ...report }, null, 2),
|
|
51068
|
+
"utf8"
|
|
51069
|
+
);
|
|
51070
|
+
} catch {
|
|
51071
|
+
}
|
|
51072
|
+
return report;
|
|
51073
|
+
}
|
|
51074
|
+
|
|
50841
51075
|
// src/engine.ts
|
|
50842
51076
|
init_symbol_summaries();
|
|
50843
51077
|
init_reconcile();
|
|
@@ -51036,11 +51270,11 @@ init_outbox();
|
|
|
51036
51270
|
init_src8();
|
|
51037
51271
|
init_src();
|
|
51038
51272
|
init_src2();
|
|
51039
|
-
import { readFileSync as
|
|
51040
|
-
import { join as
|
|
51273
|
+
import { readFileSync as readFileSync13 } from "node:fs";
|
|
51274
|
+
import { join as join18 } from "node:path";
|
|
51041
51275
|
function loadClaimIgnorePatterns(workspaceRoot) {
|
|
51042
51276
|
try {
|
|
51043
|
-
return
|
|
51277
|
+
return readFileSync13(join18(workspaceRoot, ".errataignore"), "utf8").split(/\r?\n/).map((l) => l.trim()).filter((l) => l.length > 0 && !l.startsWith("#")).map((l) => l.toLowerCase());
|
|
51044
51278
|
} catch {
|
|
51045
51279
|
return [];
|
|
51046
51280
|
}
|
|
@@ -51401,22 +51635,22 @@ async function pullCloudTriage(shared, cloud, profile, limit = 50) {
|
|
|
51401
51635
|
}
|
|
51402
51636
|
|
|
51403
51637
|
// src/git-sensor.ts
|
|
51404
|
-
import { existsSync as
|
|
51405
|
-
import { join as
|
|
51638
|
+
import { existsSync as existsSync15, readFileSync as readFileSync14, watch as fsWatch } from "node:fs";
|
|
51639
|
+
import { join as join19 } from "node:path";
|
|
51406
51640
|
function readFirstLine(path2) {
|
|
51407
51641
|
try {
|
|
51408
|
-
return
|
|
51642
|
+
return readFileSync14(path2, "utf8").split(/\r?\n/, 1)[0].trim();
|
|
51409
51643
|
} catch {
|
|
51410
51644
|
return null;
|
|
51411
51645
|
}
|
|
51412
51646
|
}
|
|
51413
51647
|
function readGitRefState(gitDir) {
|
|
51414
|
-
const head2 = readFirstLine(
|
|
51648
|
+
const head2 = readFirstLine(join19(gitDir, "HEAD"));
|
|
51415
51649
|
const m = head2 ? /^ref:\s*refs\/heads\/(.+)$/.exec(head2) : null;
|
|
51416
51650
|
const branch = m ? m[1] : null;
|
|
51417
51651
|
let sha2 = null;
|
|
51418
51652
|
if (branch) {
|
|
51419
|
-
sha2 = readFirstLine(
|
|
51653
|
+
sha2 = readFirstLine(join19(gitDir, "refs", "heads", branch));
|
|
51420
51654
|
if (!sha2) sha2 = shaFromPackedRefs(gitDir, `refs/heads/${branch}`);
|
|
51421
51655
|
} else if (head2 && /^[0-9a-f]{7,40}$/i.test(head2)) {
|
|
51422
51656
|
sha2 = head2;
|
|
@@ -51424,13 +51658,13 @@ function readGitRefState(gitDir) {
|
|
|
51424
51658
|
return {
|
|
51425
51659
|
branch,
|
|
51426
51660
|
sha: sha2,
|
|
51427
|
-
mergeHeadExists:
|
|
51428
|
-
origHeadExists:
|
|
51661
|
+
mergeHeadExists: existsSync15(join19(gitDir, "MERGE_HEAD")),
|
|
51662
|
+
origHeadExists: existsSync15(join19(gitDir, "ORIG_HEAD"))
|
|
51429
51663
|
};
|
|
51430
51664
|
}
|
|
51431
51665
|
function shaFromPackedRefs(gitDir, ref) {
|
|
51432
51666
|
try {
|
|
51433
|
-
for (const line of
|
|
51667
|
+
for (const line of readFileSync14(join19(gitDir, "packed-refs"), "utf8").split(/\r?\n/)) {
|
|
51434
51668
|
const [sha2, name2] = line.split(/\s+/);
|
|
51435
51669
|
if (name2 === ref && sha2) return sha2;
|
|
51436
51670
|
}
|
|
@@ -51464,7 +51698,7 @@ function startGitSensor(gitDir, onEvent, opts = {}) {
|
|
|
51464
51698
|
const settle = () => {
|
|
51465
51699
|
if (timer) clearTimeout(timer);
|
|
51466
51700
|
timer = setTimeout(() => {
|
|
51467
|
-
if (
|
|
51701
|
+
if (existsSync15(join19(gitDir, "index.lock"))) {
|
|
51468
51702
|
settle();
|
|
51469
51703
|
return;
|
|
51470
51704
|
}
|
|
@@ -51475,7 +51709,7 @@ function startGitSensor(gitDir, onEvent, opts = {}) {
|
|
|
51475
51709
|
}, debounceMs);
|
|
51476
51710
|
};
|
|
51477
51711
|
for (const sub of ["HEAD", "logs/HEAD", "MERGE_HEAD", "ORIG_HEAD"]) {
|
|
51478
|
-
const p =
|
|
51712
|
+
const p = join19(gitDir, sub);
|
|
51479
51713
|
try {
|
|
51480
51714
|
watchers.push(fsWatch(p, settle));
|
|
51481
51715
|
} catch {
|
|
@@ -51700,21 +51934,21 @@ var TelemetryRecorder = class {
|
|
|
51700
51934
|
|
|
51701
51935
|
// src/skills.ts
|
|
51702
51936
|
import {
|
|
51703
|
-
existsSync as
|
|
51937
|
+
existsSync as existsSync16,
|
|
51704
51938
|
mkdirSync as mkdirSync6,
|
|
51705
|
-
readFileSync as
|
|
51939
|
+
readFileSync as readFileSync15,
|
|
51706
51940
|
readdirSync as readdirSync7,
|
|
51707
51941
|
unlinkSync as unlinkSync2,
|
|
51708
|
-
writeFileSync as
|
|
51942
|
+
writeFileSync as writeFileSync13
|
|
51709
51943
|
} from "node:fs";
|
|
51710
|
-
import { basename as basename4, join as
|
|
51944
|
+
import { basename as basename4, join as join20 } from "node:path";
|
|
51711
51945
|
function skillFileName(id) {
|
|
51712
51946
|
return `${id.replace(/[^A-Za-z0-9_.-]/g, "_")}.md`;
|
|
51713
51947
|
}
|
|
51714
51948
|
function readSkillManifest(manifestPath) {
|
|
51715
|
-
if (!
|
|
51949
|
+
if (!existsSync16(manifestPath)) return [];
|
|
51716
51950
|
try {
|
|
51717
|
-
const parsed = JSON.parse(
|
|
51951
|
+
const parsed = JSON.parse(readFileSync15(manifestPath, "utf8"));
|
|
51718
51952
|
return (parsed.skills ?? []).map((s) => ({
|
|
51719
51953
|
title: s.title ?? "",
|
|
51720
51954
|
layer: s.layer ?? "technique",
|
|
@@ -51738,7 +51972,7 @@ async function syncSkills(paths, client, seed, pins = [], techSeed) {
|
|
|
51738
51972
|
for (const s of res.skills) {
|
|
51739
51973
|
const fileName = skillFileName(s.id);
|
|
51740
51974
|
keep.add(fileName);
|
|
51741
|
-
|
|
51975
|
+
writeFileSync13(join20(paths.skillsDir, fileName), s.markdown, "utf8");
|
|
51742
51976
|
rows.push({
|
|
51743
51977
|
id: s.id,
|
|
51744
51978
|
title: s.title,
|
|
@@ -51751,7 +51985,7 @@ async function syncSkills(paths, client, seed, pins = [], techSeed) {
|
|
|
51751
51985
|
const fileName = skillFileName(p.id);
|
|
51752
51986
|
if (keep.has(fileName)) continue;
|
|
51753
51987
|
keep.add(fileName);
|
|
51754
|
-
|
|
51988
|
+
writeFileSync13(join20(paths.skillsDir, fileName), p.markdown, "utf8");
|
|
51755
51989
|
rows.push({
|
|
51756
51990
|
id: p.id,
|
|
51757
51991
|
title: p.title,
|
|
@@ -51765,13 +51999,13 @@ async function syncSkills(paths, client, seed, pins = [], techSeed) {
|
|
|
51765
51999
|
if (!f.endsWith(".md")) continue;
|
|
51766
52000
|
if (keep.has(basename4(f))) continue;
|
|
51767
52001
|
try {
|
|
51768
|
-
unlinkSync2(
|
|
52002
|
+
unlinkSync2(join20(paths.skillsDir, f));
|
|
51769
52003
|
pruned++;
|
|
51770
52004
|
} catch {
|
|
51771
52005
|
}
|
|
51772
52006
|
}
|
|
51773
52007
|
rows.sort((a, b) => a.id.localeCompare(b.id));
|
|
51774
|
-
|
|
52008
|
+
writeFileSync13(
|
|
51775
52009
|
paths.skillsManifest,
|
|
51776
52010
|
JSON.stringify({ generatedAt: Date.now(), skills: rows }, null, 2),
|
|
51777
52011
|
"utf8"
|
|
@@ -51783,22 +52017,22 @@ async function syncSkills(paths, client, seed, pins = [], techSeed) {
|
|
|
51783
52017
|
init_src2();
|
|
51784
52018
|
import {
|
|
51785
52019
|
cpSync,
|
|
51786
|
-
existsSync as
|
|
52020
|
+
existsSync as existsSync17,
|
|
51787
52021
|
lstatSync,
|
|
51788
52022
|
mkdirSync as mkdirSync7,
|
|
51789
|
-
readFileSync as
|
|
52023
|
+
readFileSync as readFileSync16,
|
|
51790
52024
|
readdirSync as readdirSync8,
|
|
51791
52025
|
rmSync as rmSync2,
|
|
51792
52026
|
symlinkSync,
|
|
51793
|
-
writeFileSync as
|
|
52027
|
+
writeFileSync as writeFileSync14
|
|
51794
52028
|
} from "node:fs";
|
|
51795
|
-
import { join as
|
|
52029
|
+
import { join as join21 } from "node:path";
|
|
51796
52030
|
var SKILL_NS = "errata-";
|
|
51797
52031
|
var HARNESS_SKILL_DIRS = [
|
|
51798
|
-
{ configDir: ".claude", skillsDir:
|
|
52032
|
+
{ configDir: ".claude", skillsDir: join21(".claude", "skills") },
|
|
51799
52033
|
// Cursor adopted the standard; its exact project dir is still moving — kept
|
|
51800
52034
|
// best-effort and gated on `.cursor/` presence so we never create it blind.
|
|
51801
|
-
{ configDir: ".cursor", skillsDir:
|
|
52035
|
+
{ configDir: ".cursor", skillsDir: join21(".cursor", "skills") }
|
|
51802
52036
|
];
|
|
51803
52037
|
function skillSlug(title, id) {
|
|
51804
52038
|
const base = title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || id.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "skill";
|
|
@@ -51843,12 +52077,12 @@ function skillCiteHandle(s) {
|
|
|
51843
52077
|
return priorHandle({ id: s.id, description: s.title });
|
|
51844
52078
|
}
|
|
51845
52079
|
function reconcileNamespaced(dir, keep) {
|
|
51846
|
-
if (!
|
|
52080
|
+
if (!existsSync17(dir)) return 0;
|
|
51847
52081
|
let pruned = 0;
|
|
51848
52082
|
for (const name2 of readdirSync8(dir)) {
|
|
51849
52083
|
if (!name2.startsWith(SKILL_NS) || keep.has(name2)) continue;
|
|
51850
52084
|
try {
|
|
51851
|
-
rmSync2(
|
|
52085
|
+
rmSync2(join21(dir, name2), { recursive: true, force: true });
|
|
51852
52086
|
pruned++;
|
|
51853
52087
|
} catch {
|
|
51854
52088
|
}
|
|
@@ -51857,7 +52091,7 @@ function reconcileNamespaced(dir, keep) {
|
|
|
51857
52091
|
}
|
|
51858
52092
|
function linkOrCopy(linkPath, target) {
|
|
51859
52093
|
try {
|
|
51860
|
-
if (
|
|
52094
|
+
if (existsSync17(linkPath) || safeLstat(linkPath)) rmSync2(linkPath, { recursive: true, force: true });
|
|
51861
52095
|
} catch {
|
|
51862
52096
|
}
|
|
51863
52097
|
try {
|
|
@@ -51878,7 +52112,7 @@ function safeLstat(p) {
|
|
|
51878
52112
|
}
|
|
51879
52113
|
}
|
|
51880
52114
|
function emitAndProjectSkills(root, skills) {
|
|
51881
|
-
const agentsSkillsDir =
|
|
52115
|
+
const agentsSkillsDir = join21(root, ".agents", "skills");
|
|
51882
52116
|
mkdirSync7(agentsSkillsDir, { recursive: true });
|
|
51883
52117
|
const slugs = [];
|
|
51884
52118
|
const keep = /* @__PURE__ */ new Set();
|
|
@@ -51886,7 +52120,7 @@ function emitAndProjectSkills(root, skills) {
|
|
|
51886
52120
|
for (const s of skills) {
|
|
51887
52121
|
let body2;
|
|
51888
52122
|
try {
|
|
51889
|
-
body2 =
|
|
52123
|
+
body2 = readFileSync16(s.bodyPath, "utf8");
|
|
51890
52124
|
} catch {
|
|
51891
52125
|
continue;
|
|
51892
52126
|
}
|
|
@@ -51895,9 +52129,9 @@ function emitAndProjectSkills(root, skills) {
|
|
|
51895
52129
|
keep.add(slug2);
|
|
51896
52130
|
slugs.push(slug2);
|
|
51897
52131
|
const description = deriveDescription(s.title, s.layer, body2);
|
|
51898
|
-
mkdirSync7(
|
|
51899
|
-
|
|
51900
|
-
|
|
52132
|
+
mkdirSync7(join21(agentsSkillsDir, slug2), { recursive: true });
|
|
52133
|
+
writeFileSync14(
|
|
52134
|
+
join21(agentsSkillsDir, slug2, "SKILL.md"),
|
|
51901
52135
|
renderSkillMd(slug2, description, body2, skillCiteHandle(s)),
|
|
51902
52136
|
"utf8"
|
|
51903
52137
|
);
|
|
@@ -51906,11 +52140,11 @@ function emitAndProjectSkills(root, skills) {
|
|
|
51906
52140
|
reconcileNamespaced(agentsSkillsDir, keep);
|
|
51907
52141
|
let projected = 0;
|
|
51908
52142
|
for (const h of HARNESS_SKILL_DIRS) {
|
|
51909
|
-
if (!
|
|
51910
|
-
const dir =
|
|
52143
|
+
if (!existsSync17(join21(root, h.configDir))) continue;
|
|
52144
|
+
const dir = join21(root, h.skillsDir);
|
|
51911
52145
|
mkdirSync7(dir, { recursive: true });
|
|
51912
52146
|
for (const slug2 of slugs) {
|
|
51913
|
-
linkOrCopy(
|
|
52147
|
+
linkOrCopy(join21(dir, slug2), join21(agentsSkillsDir, slug2));
|
|
51914
52148
|
projected++;
|
|
51915
52149
|
}
|
|
51916
52150
|
reconcileNamespaced(dir, keep);
|
|
@@ -51919,15 +52153,15 @@ function emitAndProjectSkills(root, skills) {
|
|
|
51919
52153
|
return { slugs, emitted, projected };
|
|
51920
52154
|
}
|
|
51921
52155
|
function emitInputsFromManifest(erretaDir, manifestPath) {
|
|
51922
|
-
if (!
|
|
52156
|
+
if (!existsSync17(manifestPath)) return [];
|
|
51923
52157
|
try {
|
|
51924
|
-
const parsed = JSON.parse(
|
|
52158
|
+
const parsed = JSON.parse(readFileSync16(manifestPath, "utf8"));
|
|
51925
52159
|
return (parsed.skills ?? []).filter((s) => Boolean(s.id && s.file)).map((s) => ({
|
|
51926
52160
|
id: s.id,
|
|
51927
52161
|
title: s.title ?? s.id,
|
|
51928
52162
|
layer: s.layer ?? "technique",
|
|
51929
52163
|
confidence: s.confidence ?? 0,
|
|
51930
|
-
bodyPath:
|
|
52164
|
+
bodyPath: join21(erretaDir, s.file)
|
|
51931
52165
|
}));
|
|
51932
52166
|
} catch {
|
|
51933
52167
|
return [];
|
|
@@ -51941,17 +52175,17 @@ var GITIGNORE_LINES = [
|
|
|
51941
52175
|
".cursor/skills/errata-*/"
|
|
51942
52176
|
];
|
|
51943
52177
|
function ensureSkillGitignore(root) {
|
|
51944
|
-
const path2 =
|
|
52178
|
+
const path2 = join21(root, ".gitignore");
|
|
51945
52179
|
let current = "";
|
|
51946
52180
|
try {
|
|
51947
|
-
current =
|
|
52181
|
+
current = existsSync17(path2) ? readFileSync16(path2, "utf8") : "";
|
|
51948
52182
|
} catch {
|
|
51949
52183
|
return;
|
|
51950
52184
|
}
|
|
51951
52185
|
if (current.includes(GITIGNORE_MARK)) return;
|
|
51952
52186
|
const prefix = current.length > 0 && !current.endsWith("\n") ? "\n" : "";
|
|
51953
52187
|
try {
|
|
51954
|
-
|
|
52188
|
+
writeFileSync14(path2, `${current}${prefix}
|
|
51955
52189
|
${GITIGNORE_LINES.join("\n")}
|
|
51956
52190
|
`, "utf8");
|
|
51957
52191
|
} catch {
|
|
@@ -52012,20 +52246,20 @@ init_paths();
|
|
|
52012
52246
|
// src/profile.ts
|
|
52013
52247
|
init_src2();
|
|
52014
52248
|
init_paths();
|
|
52015
|
-
import { existsSync as
|
|
52249
|
+
import { existsSync as existsSync19, readFileSync as readFileSync18, writeFileSync as writeFileSync15 } from "node:fs";
|
|
52016
52250
|
import { createHash as createHash12 } from "node:crypto";
|
|
52017
|
-
import { join as
|
|
52251
|
+
import { join as join23 } from "node:path";
|
|
52018
52252
|
|
|
52019
52253
|
// src/git-remote.ts
|
|
52020
52254
|
init_src();
|
|
52021
|
-
import { existsSync as
|
|
52022
|
-
import { isAbsolute as isAbsolute3, join as
|
|
52255
|
+
import { existsSync as existsSync18, readFileSync as readFileSync17, statSync as statSync4 } from "node:fs";
|
|
52256
|
+
import { isAbsolute as isAbsolute3, join as join22, resolve as resolve5 } from "node:path";
|
|
52023
52257
|
function resolveGitDir(root) {
|
|
52024
|
-
const dotGit =
|
|
52258
|
+
const dotGit = join22(root, ".git");
|
|
52025
52259
|
try {
|
|
52026
52260
|
const st = statSync4(dotGit);
|
|
52027
52261
|
if (st.isDirectory()) return dotGit;
|
|
52028
|
-
const m = /^gitdir:\s*(.+?)\s*$/m.exec(
|
|
52262
|
+
const m = /^gitdir:\s*(.+?)\s*$/m.exec(readFileSync17(dotGit, "utf8"));
|
|
52029
52263
|
if (!m) return null;
|
|
52030
52264
|
const dir = m[1];
|
|
52031
52265
|
return isAbsolute3(dir) ? dir : resolve5(root, dir);
|
|
@@ -52034,22 +52268,22 @@ function resolveGitDir(root) {
|
|
|
52034
52268
|
}
|
|
52035
52269
|
}
|
|
52036
52270
|
function gitConfigPath(gitDir) {
|
|
52037
|
-
const commondirFile =
|
|
52038
|
-
if (
|
|
52039
|
-
const common =
|
|
52271
|
+
const commondirFile = join22(gitDir, "commondir");
|
|
52272
|
+
if (existsSync18(commondirFile)) {
|
|
52273
|
+
const common = readFileSync17(commondirFile, "utf8").trim();
|
|
52040
52274
|
const commonDir = isAbsolute3(common) ? common : resolve5(gitDir, common);
|
|
52041
|
-
return
|
|
52275
|
+
return join22(commonDir, "config");
|
|
52042
52276
|
}
|
|
52043
|
-
return
|
|
52277
|
+
return join22(gitDir, "config");
|
|
52044
52278
|
}
|
|
52045
52279
|
function readRemotes(root) {
|
|
52046
52280
|
const gitDir = resolveGitDir(root);
|
|
52047
52281
|
if (!gitDir) return [];
|
|
52048
52282
|
const cfgPath = gitConfigPath(gitDir);
|
|
52049
|
-
if (!
|
|
52283
|
+
if (!existsSync18(cfgPath)) return [];
|
|
52050
52284
|
let txt;
|
|
52051
52285
|
try {
|
|
52052
|
-
txt =
|
|
52286
|
+
txt = readFileSync17(cfgPath, "utf8");
|
|
52053
52287
|
} catch {
|
|
52054
52288
|
return [];
|
|
52055
52289
|
}
|
|
@@ -52085,13 +52319,13 @@ function refreshRepoLocator(root, profile) {
|
|
|
52085
52319
|
}
|
|
52086
52320
|
function loadProfile(root) {
|
|
52087
52321
|
const p = workspacePaths(root);
|
|
52088
|
-
if (!
|
|
52089
|
-
return JSON.parse(
|
|
52322
|
+
if (!existsSync19(p.workspaceJson)) return null;
|
|
52323
|
+
return JSON.parse(readFileSync18(p.workspaceJson, "utf8"));
|
|
52090
52324
|
}
|
|
52091
52325
|
function saveProfile(root, profile) {
|
|
52092
52326
|
const p = workspacePaths(root);
|
|
52093
52327
|
ensureDir(p.configDir);
|
|
52094
|
-
|
|
52328
|
+
writeFileSync15(p.workspaceJson, JSON.stringify(profile, null, 2), "utf8");
|
|
52095
52329
|
}
|
|
52096
52330
|
function autodetectProfile(root) {
|
|
52097
52331
|
const id = workspaceId(root);
|
|
@@ -52099,10 +52333,10 @@ function autodetectProfile(root) {
|
|
|
52099
52333
|
const p = emptyProfile(id, name2);
|
|
52100
52334
|
const locator = detectRepoLocator(root);
|
|
52101
52335
|
if (locator) p.repoLocator = locator;
|
|
52102
|
-
const pkgPath =
|
|
52103
|
-
if (
|
|
52336
|
+
const pkgPath = join23(root, "package.json");
|
|
52337
|
+
if (existsSync19(pkgPath)) {
|
|
52104
52338
|
try {
|
|
52105
|
-
const pkg = JSON.parse(
|
|
52339
|
+
const pkg = JSON.parse(readFileSync18(pkgPath, "utf8"));
|
|
52106
52340
|
p.languages.push("typescript", "javascript");
|
|
52107
52341
|
const nodeVer = pkg.engines?.node ?? "node";
|
|
52108
52342
|
p.stack.push(`node@${nodeVer}`);
|
|
@@ -52123,10 +52357,10 @@ function autodetectProfile(root) {
|
|
|
52123
52357
|
} catch {
|
|
52124
52358
|
}
|
|
52125
52359
|
}
|
|
52126
|
-
const pyproject =
|
|
52127
|
-
if (
|
|
52360
|
+
const pyproject = join23(root, "pyproject.toml");
|
|
52361
|
+
if (existsSync19(pyproject)) {
|
|
52128
52362
|
try {
|
|
52129
|
-
const txt =
|
|
52363
|
+
const txt = readFileSync18(pyproject, "utf8");
|
|
52130
52364
|
const py = /python\s*=\s*"([^"]+)"/.exec(txt)?.[1];
|
|
52131
52365
|
p.languages.push("python");
|
|
52132
52366
|
p.stack.push(`python@${py ?? "3"}`);
|
|
@@ -52137,16 +52371,16 @@ function autodetectProfile(root) {
|
|
|
52137
52371
|
} catch {
|
|
52138
52372
|
}
|
|
52139
52373
|
}
|
|
52140
|
-
const reqs =
|
|
52141
|
-
if (
|
|
52374
|
+
const reqs = join23(root, "requirements.txt");
|
|
52375
|
+
if (existsSync19(reqs)) {
|
|
52142
52376
|
if (!p.languages.includes("python")) p.languages.push("python");
|
|
52143
52377
|
if (!p.stack.includes("python@3")) p.stack.push("python@3");
|
|
52144
52378
|
}
|
|
52145
|
-
if (
|
|
52379
|
+
if (existsSync19(join23(root, "go.mod"))) {
|
|
52146
52380
|
p.languages.push("go");
|
|
52147
52381
|
p.stack.push("go");
|
|
52148
52382
|
}
|
|
52149
|
-
if (
|
|
52383
|
+
if (existsSync19(join23(root, "Cargo.toml"))) {
|
|
52150
52384
|
p.languages.push("rust");
|
|
52151
52385
|
p.stack.push("rust");
|
|
52152
52386
|
}
|
|
@@ -52156,17 +52390,17 @@ function autodetectProfile(root) {
|
|
|
52156
52390
|
}
|
|
52157
52391
|
|
|
52158
52392
|
// src/witness-queue.ts
|
|
52159
|
-
import { readFileSync as
|
|
52160
|
-
import { dirname as dirname9, join as
|
|
52393
|
+
import { readFileSync as readFileSync19, renameSync as renameSync2, writeFileSync as writeFileSync16 } from "node:fs";
|
|
52394
|
+
import { dirname as dirname9, join as join24 } from "node:path";
|
|
52161
52395
|
var WITNESS_QUEUE_CAP = 500;
|
|
52162
52396
|
var WITNESS_TTL_MS = 14 * 24 * 60 * 60 * 1e3;
|
|
52163
52397
|
var WITNESS_MAX_ATTEMPTS = 5;
|
|
52164
52398
|
function witnessQueuePath(workspaceConfigDir) {
|
|
52165
|
-
return
|
|
52399
|
+
return join24(workspaceConfigDir, "witness-queue.json");
|
|
52166
52400
|
}
|
|
52167
52401
|
function loadWitnessQueue(path2) {
|
|
52168
52402
|
try {
|
|
52169
|
-
const raw2 = JSON.parse(
|
|
52403
|
+
const raw2 = JSON.parse(readFileSync19(path2, "utf8"));
|
|
52170
52404
|
if (!Array.isArray(raw2)) return [];
|
|
52171
52405
|
return raw2.filter(
|
|
52172
52406
|
(w) => !!w && typeof w === "object" && typeof w.nodeId === "string" && typeof w.witnessKey === "string"
|
|
@@ -52177,8 +52411,8 @@ function loadWitnessQueue(path2) {
|
|
|
52177
52411
|
}
|
|
52178
52412
|
function saveWitnessQueue(path2, queue) {
|
|
52179
52413
|
try {
|
|
52180
|
-
const tmp =
|
|
52181
|
-
|
|
52414
|
+
const tmp = join24(dirname9(path2), `.${Date.now()}.witness-queue.tmp`);
|
|
52415
|
+
writeFileSync16(tmp, JSON.stringify(queue), "utf8");
|
|
52182
52416
|
renameSync2(tmp, path2);
|
|
52183
52417
|
} catch {
|
|
52184
52418
|
}
|
|
@@ -52458,7 +52692,7 @@ function startLoopLagMonitor(thresholdMs = 1e3) {
|
|
|
52458
52692
|
}
|
|
52459
52693
|
|
|
52460
52694
|
// src/engine.ts
|
|
52461
|
-
var DAEMON_VERSION = true ? "2.0.2-dev.
|
|
52695
|
+
var DAEMON_VERSION = true ? "2.0.2-dev.247" : "2.0.0-alpha.0";
|
|
52462
52696
|
var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
|
|
52463
52697
|
var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
|
|
52464
52698
|
var GIT_OP_MUTE_MS = 4e3;
|
|
@@ -52468,7 +52702,7 @@ var TURN_REPLAY_LOOKBACK_MS = 7 * 24 * 60 * 6e4;
|
|
|
52468
52702
|
function appendIdentityAudit(path2, record2, line) {
|
|
52469
52703
|
if (!record2.accepted && record2.score <= 0) return;
|
|
52470
52704
|
try {
|
|
52471
|
-
if (
|
|
52705
|
+
if (existsSync20(path2) && statSync5(path2).size >= IDENTITY_AUDIT_MAX_BYTES) {
|
|
52472
52706
|
renameSync3(path2, `${path2}.1`);
|
|
52473
52707
|
}
|
|
52474
52708
|
appendFileSync2(path2, line);
|
|
@@ -52478,7 +52712,7 @@ function appendIdentityAudit(path2, record2, line) {
|
|
|
52478
52712
|
var yieldToLoop = () => new Promise((r) => setImmediate(r));
|
|
52479
52713
|
function loadTurnCursors(path2) {
|
|
52480
52714
|
try {
|
|
52481
|
-
const raw2 = JSON.parse(
|
|
52715
|
+
const raw2 = JSON.parse(readFileSync20(path2, "utf8"));
|
|
52482
52716
|
return new Map(
|
|
52483
52717
|
Object.entries(raw2).map(([k, v]) => [k, typeof v === "string" ? v : String(v?.uuid ?? "")])
|
|
52484
52718
|
);
|
|
@@ -52488,7 +52722,7 @@ function loadTurnCursors(path2) {
|
|
|
52488
52722
|
}
|
|
52489
52723
|
function loadTurnOffsets(path2) {
|
|
52490
52724
|
try {
|
|
52491
|
-
const raw2 = JSON.parse(
|
|
52725
|
+
const raw2 = JSON.parse(readFileSync20(path2, "utf8"));
|
|
52492
52726
|
const out2 = /* @__PURE__ */ new Map();
|
|
52493
52727
|
for (const [k, v] of Object.entries(raw2)) {
|
|
52494
52728
|
const off = typeof v === "object" && v !== null ? v.offset : void 0;
|
|
@@ -52504,7 +52738,7 @@ function saveTurnCursors(path2, cursors, offsets) {
|
|
|
52504
52738
|
const merged = {};
|
|
52505
52739
|
for (const [k, uuid3] of cursors) merged[k] = { uuid: uuid3, offset: offsets.get(k) ?? 0 };
|
|
52506
52740
|
for (const [k, offset] of offsets) if (!merged[k]) merged[k] = { uuid: "", offset };
|
|
52507
|
-
|
|
52741
|
+
writeFileSync17(path2, JSON.stringify(merged), "utf8");
|
|
52508
52742
|
} catch {
|
|
52509
52743
|
}
|
|
52510
52744
|
}
|
|
@@ -52526,7 +52760,7 @@ function gitSourceWatchTargets(root) {
|
|
|
52526
52760
|
["-C", root, "ls-files", "--others", "--ignored", "--exclude-standard", "--directory", "-z"],
|
|
52527
52761
|
{ encoding: "utf8", maxBuffer: 256 * 1024 * 1024, windowsHide: true, stdio: ["ignore", "pipe", "ignore"] }
|
|
52528
52762
|
);
|
|
52529
|
-
ignoredDirs = igOut.split("\0").filter(Boolean).map((d) => d.replace(/\/+$/, "")).filter((d) => !IGNORED_PATH.test(
|
|
52763
|
+
ignoredDirs = igOut.split("\0").filter(Boolean).map((d) => d.replace(/\/+$/, "")).filter((d) => !IGNORED_PATH.test(join25(root, d) + sep4));
|
|
52530
52764
|
} catch {
|
|
52531
52765
|
}
|
|
52532
52766
|
const hasIgnoredChild = (dir) => ignoredDirs.some((ig) => ig.startsWith(dir + "/"));
|
|
@@ -52538,19 +52772,19 @@ function gitSourceWatchTargets(root) {
|
|
|
52538
52772
|
if (!f.startsWith(prefix)) continue;
|
|
52539
52773
|
const rest2 = f.slice(prefix.length);
|
|
52540
52774
|
if (rest2.includes("/")) children.add(dir === "" ? rest2.slice(0, rest2.indexOf("/")) : dir + "/" + rest2.slice(0, rest2.indexOf("/")));
|
|
52541
|
-
else targets.add(
|
|
52775
|
+
else targets.add(join25(root, f));
|
|
52542
52776
|
}
|
|
52543
52777
|
for (const c of children) {
|
|
52544
|
-
if (IGNORED_PATH.test(
|
|
52778
|
+
if (IGNORED_PATH.test(join25(root, c) + sep4)) continue;
|
|
52545
52779
|
if (hasIgnoredChild(c)) addUnder(c);
|
|
52546
|
-
else targets.add(
|
|
52780
|
+
else targets.add(join25(root, c));
|
|
52547
52781
|
}
|
|
52548
52782
|
};
|
|
52549
52783
|
addUnder("");
|
|
52550
52784
|
if (targets.size > 0) return [...targets];
|
|
52551
52785
|
} catch {
|
|
52552
52786
|
}
|
|
52553
|
-
return readdirSync9(root, { withFileTypes: true }).filter((e) => e.isDirectory() && !IGNORED_PATH.test(
|
|
52787
|
+
return readdirSync9(root, { withFileTypes: true }).filter((e) => e.isDirectory() && !IGNORED_PATH.test(join25(root, String(e.name)) + sep4)).map((e) => join25(root, String(e.name)));
|
|
52554
52788
|
}
|
|
52555
52789
|
function createWorkspaceEngine(opts) {
|
|
52556
52790
|
const paths = workspacePaths(opts.workspaceRoot);
|
|
@@ -52708,7 +52942,7 @@ function createWorkspaceEngine(opts) {
|
|
|
52708
52942
|
const srcPaths = diff.changedPaths.filter((p) => /\.(ts|tsx|js|jsx|mjs|cjs|py)$/i.test(p));
|
|
52709
52943
|
let episodeId2;
|
|
52710
52944
|
if (srcPaths.length > 0) {
|
|
52711
|
-
const abs = srcPaths.map((p) =>
|
|
52945
|
+
const abs = srcPaths.map((p) => join25(opts.workspaceRoot, p));
|
|
52712
52946
|
try {
|
|
52713
52947
|
const r = await runReindexPass(
|
|
52714
52948
|
`git-reindex:${profile.name} (${abs.length} files)`,
|
|
@@ -52744,8 +52978,8 @@ function createWorkspaceEngine(opts) {
|
|
|
52744
52978
|
`[errata] git: ${ev.kind} ${ev.newSha.slice(0, 7)} by ${meta3.authorName} \u2014 ${diff.changedPaths.length} file(s), ${diff.renames.length} rename(s)`
|
|
52745
52979
|
);
|
|
52746
52980
|
};
|
|
52747
|
-
const gitDir =
|
|
52748
|
-
if (
|
|
52981
|
+
const gitDir = join25(opts.workspaceRoot, ".git");
|
|
52982
|
+
if (existsSync20(gitDir)) {
|
|
52749
52983
|
stopGit = startGitSensor(gitDir, (ev) => {
|
|
52750
52984
|
void handleGitEvent(ev).catch((err2) => {
|
|
52751
52985
|
console.warn("[errata] git event handler failed:", err2);
|
|
@@ -52815,10 +53049,10 @@ function createWorkspaceEngine(opts) {
|
|
|
52815
53049
|
});
|
|
52816
53050
|
doneRender?.();
|
|
52817
53051
|
writeContextFile(opts.workspaceRoot, body2);
|
|
52818
|
-
const target =
|
|
53052
|
+
const target = join25(opts.workspaceRoot, "AGENTS.md");
|
|
52819
53053
|
writeManagedBlock(target, { body: AGENTS_POINTER_BODY, stable: true, force: true });
|
|
52820
53054
|
if (elicit) {
|
|
52821
|
-
writePrimingHandles(
|
|
53055
|
+
writePrimingHandles(join25(paths.configDir, "priming-handles.json"), [
|
|
52822
53056
|
...snapshot.recentProblems.map((r) => r.node),
|
|
52823
53057
|
// Resolved-band handles: the ✓ problem AND its Solution are citable
|
|
52824
53058
|
// (a fix tag on an already-resolved problem no-ops idempotently; the
|
|
@@ -52909,6 +53143,17 @@ function createWorkspaceEngine(opts) {
|
|
|
52909
53143
|
} catch (err2) {
|
|
52910
53144
|
console.warn("[errata] anchor backfill failed:", err2);
|
|
52911
53145
|
}
|
|
53146
|
+
try {
|
|
53147
|
+
const r = repairInvalidEdges(store, { configDir: paths.configDir, now: Date.now() });
|
|
53148
|
+
if (!r.skipped && r.invalid > 0) {
|
|
53149
|
+
console.log(
|
|
53150
|
+
`[errata] edge repair: ${r.retyped} edge(s) retyped, ${r.closed} closed (${Object.entries(r.byType).map(([t, n]) => `${t}x${n}`).join(", ")})`
|
|
53151
|
+
);
|
|
53152
|
+
refreshContextNow();
|
|
53153
|
+
}
|
|
53154
|
+
} catch (err2) {
|
|
53155
|
+
console.warn("[errata] edge repair failed:", err2);
|
|
53156
|
+
}
|
|
52912
53157
|
try {
|
|
52913
53158
|
const c = backfillConstraintKind(store, {
|
|
52914
53159
|
root: opts.workspaceRoot,
|
|
@@ -53023,7 +53268,7 @@ function createWorkspaceEngine(opts) {
|
|
|
53023
53268
|
resultSummary: { exitCode: e.exitCode ?? 1, errorTokens: e.errorTokens }
|
|
53024
53269
|
});
|
|
53025
53270
|
};
|
|
53026
|
-
const turnCursorPath =
|
|
53271
|
+
const turnCursorPath = join25(paths.configDir, "turn-cursors.json");
|
|
53027
53272
|
const lastTurnUuid = loadTurnCursors(turnCursorPath);
|
|
53028
53273
|
const turnOffset = loadTurnOffsets(turnCursorPath);
|
|
53029
53274
|
const sessionLastProblem = /* @__PURE__ */ new Map();
|
|
@@ -53047,7 +53292,7 @@ function createWorkspaceEngine(opts) {
|
|
|
53047
53292
|
const t = Date.now();
|
|
53048
53293
|
let processedTurns = 0;
|
|
53049
53294
|
const elicit = isEdgeElicitationEnabled();
|
|
53050
|
-
const handleMap = elicit ? readPrimingHandles(
|
|
53295
|
+
const handleMap = elicit ? readPrimingHandles(join25(paths.configDir, "priming-handles.json")) : {};
|
|
53051
53296
|
const wsRoot = (opts.workspaceRoot ?? "").replace(/\\/g, "/");
|
|
53052
53297
|
const toRel = (abs) => {
|
|
53053
53298
|
const p = abs.replace(/\\/g, "/");
|
|
@@ -53356,9 +53601,7 @@ function createWorkspaceEngine(opts) {
|
|
|
53356
53601
|
if (targetId === pid) continue;
|
|
53357
53602
|
const target = store.getNode(targetId);
|
|
53358
53603
|
if (!target) continue;
|
|
53359
|
-
|
|
53360
|
-
const type = target.label === "Pattern" ? "INSTANCE_OF" : target.label === "Problem" ? "MATCHES" : fallback === "SUPERSEDES" ? "RELATES_TO" : fallback;
|
|
53361
|
-
mintCiteEdge(pid, targetId, type, inst.evidence === "witnessed" ? 0.4 : 0.3, { instanceCite: true, evidence: inst.evidence });
|
|
53604
|
+
mintCiteEdge(pid, targetId, citeEdgeType(target.label), inst.evidence === "witnessed" ? 0.4 : 0.3, { instanceCite: true, evidence: inst.evidence });
|
|
53362
53605
|
}
|
|
53363
53606
|
}
|
|
53364
53607
|
for (const tf of plan.transfers) {
|
|
@@ -53658,7 +53901,7 @@ function createWorkspaceEngine(opts) {
|
|
|
53658
53901
|
try {
|
|
53659
53902
|
const inputs = emitInputsFromManifest(paths.configDir, paths.skillsManifest);
|
|
53660
53903
|
emitAndProjectSkills(opts.workspaceRoot, inputs);
|
|
53661
|
-
writePrimingHandles(
|
|
53904
|
+
writePrimingHandles(join25(paths.configDir, "priming-handles.json"), skillHandleNodes(inputs));
|
|
53662
53905
|
} catch (err2) {
|
|
53663
53906
|
console.warn("[skills] agent-skills projection failed (non-fatal):", err2 instanceof Error ? err2.message : err2);
|
|
53664
53907
|
}
|
|
@@ -53845,7 +54088,7 @@ function createWorkspaceEngine(opts) {
|
|
|
53845
54088
|
console.log(
|
|
53846
54089
|
"[errata] sync skipped \u2014 cloud sync consent is off (enable with `errata consent sync on`)"
|
|
53847
54090
|
);
|
|
53848
|
-
const pending =
|
|
54091
|
+
const pending = existsSync20(paths.outbox) ? readdirSync9(paths.outbox).filter((f) => f.endsWith(".json")).length : 0;
|
|
53849
54092
|
return { uploaded: 0, failed: 0, remaining: pending };
|
|
53850
54093
|
}
|
|
53851
54094
|
try {
|
|
@@ -53932,7 +54175,7 @@ async function startDaemon(opts) {
|
|
|
53932
54175
|
reviewUrl: () => webUiUrl + "/review"
|
|
53933
54176
|
});
|
|
53934
54177
|
const writeLockFile = (url2) => {
|
|
53935
|
-
|
|
54178
|
+
writeFileSync18(
|
|
53936
54179
|
engine.paths.daemonLock,
|
|
53937
54180
|
JSON.stringify({ pid: process.pid, webUiUrl: url2, startedAt: Date.now() }),
|
|
53938
54181
|
"utf8"
|
|
@@ -53975,7 +54218,7 @@ async function startDaemon(opts) {
|
|
|
53975
54218
|
);
|
|
53976
54219
|
await engine.stop();
|
|
53977
54220
|
try {
|
|
53978
|
-
if (
|
|
54221
|
+
if (existsSync21(engine.paths.daemonLock)) {
|
|
53979
54222
|
}
|
|
53980
54223
|
} catch {
|
|
53981
54224
|
}
|
|
@@ -53992,16 +54235,16 @@ async function listenServer(fetchFn, port) {
|
|
|
53992
54235
|
|
|
53993
54236
|
// src/registry.ts
|
|
53994
54237
|
init_paths();
|
|
53995
|
-
import { existsSync as
|
|
53996
|
-
import { join as
|
|
54238
|
+
import { existsSync as existsSync22, readFileSync as readFileSync21, writeFileSync as writeFileSync19 } from "node:fs";
|
|
54239
|
+
import { join as join26 } from "node:path";
|
|
53997
54240
|
function registryPath() {
|
|
53998
|
-
return process.env["ERRATA_REGISTRY_PATH"] ??
|
|
54241
|
+
return process.env["ERRATA_REGISTRY_PATH"] ?? join26(globalDir(), "workspaces.json");
|
|
53999
54242
|
}
|
|
54000
54243
|
function read() {
|
|
54001
54244
|
const p = registryPath();
|
|
54002
|
-
if (!
|
|
54245
|
+
if (!existsSync22(p)) return { version: 1, workspaces: {} };
|
|
54003
54246
|
try {
|
|
54004
|
-
const parsed = JSON.parse(
|
|
54247
|
+
const parsed = JSON.parse(readFileSync21(p, "utf8"));
|
|
54005
54248
|
return { version: 1, workspaces: parsed.workspaces ?? {} };
|
|
54006
54249
|
} catch {
|
|
54007
54250
|
return { version: 1, workspaces: {} };
|
|
@@ -54009,7 +54252,7 @@ function read() {
|
|
|
54009
54252
|
}
|
|
54010
54253
|
function write(reg) {
|
|
54011
54254
|
ensureDir(globalDir());
|
|
54012
|
-
|
|
54255
|
+
writeFileSync19(registryPath(), JSON.stringify(reg, null, 2), "utf8");
|
|
54013
54256
|
}
|
|
54014
54257
|
function registerWorkspace(profile, root, now = Date.now()) {
|
|
54015
54258
|
const reg = read();
|
|
@@ -54026,7 +54269,7 @@ function pruneMissingWorkspaces() {
|
|
|
54026
54269
|
const reg = read();
|
|
54027
54270
|
const removed = [];
|
|
54028
54271
|
for (const [id, entry] of Object.entries(reg.workspaces)) {
|
|
54029
|
-
if (!
|
|
54272
|
+
if (!existsSync22(entry.path)) {
|
|
54030
54273
|
removed.push(entry);
|
|
54031
54274
|
delete reg.workspaces[id];
|
|
54032
54275
|
}
|
|
@@ -54035,13 +54278,13 @@ function pruneMissingWorkspaces() {
|
|
|
54035
54278
|
return removed;
|
|
54036
54279
|
}
|
|
54037
54280
|
function workspaceStatus(entry) {
|
|
54038
|
-
const missing = !
|
|
54281
|
+
const missing = !existsSync22(entry.path);
|
|
54039
54282
|
const lockPath = workspacePaths(entry.path).daemonLock;
|
|
54040
54283
|
let running = false;
|
|
54041
54284
|
let webUiUrl = null;
|
|
54042
|
-
if (
|
|
54285
|
+
if (existsSync22(lockPath)) {
|
|
54043
54286
|
try {
|
|
54044
|
-
const lock = JSON.parse(
|
|
54287
|
+
const lock = JSON.parse(readFileSync21(lockPath, "utf8"));
|
|
54045
54288
|
if (lock.pid && lock.webUiUrl && pidAlive(lock.pid)) {
|
|
54046
54289
|
running = true;
|
|
54047
54290
|
webUiUrl = lock.webUiUrl;
|
|
@@ -54069,7 +54312,7 @@ function pidAlive(pid) {
|
|
|
54069
54312
|
// src/multi.ts
|
|
54070
54313
|
init_dist();
|
|
54071
54314
|
init_src4();
|
|
54072
|
-
import { readFileSync as
|
|
54315
|
+
import { readFileSync as readFileSync24, unlinkSync as unlinkSync3, writeFileSync as writeFileSync20 } from "node:fs";
|
|
54073
54316
|
|
|
54074
54317
|
// src/principle-sync.ts
|
|
54075
54318
|
init_src4();
|
|
@@ -54097,8 +54340,8 @@ init_reconcile();
|
|
|
54097
54340
|
|
|
54098
54341
|
// src/lockfile-auto.ts
|
|
54099
54342
|
init_src();
|
|
54100
|
-
import { existsSync as
|
|
54101
|
-
import { join as
|
|
54343
|
+
import { existsSync as existsSync23, readFileSync as readFileSync22 } from "node:fs";
|
|
54344
|
+
import { join as join27 } from "node:path";
|
|
54102
54345
|
|
|
54103
54346
|
// src/package-index.ts
|
|
54104
54347
|
init_src();
|
|
@@ -54247,11 +54490,11 @@ function runLockfilePass(opts) {
|
|
|
54247
54490
|
{ file: "package-lock.json", parse: parsePackageLockJson }
|
|
54248
54491
|
];
|
|
54249
54492
|
for (const c of candidates) {
|
|
54250
|
-
const p =
|
|
54251
|
-
if (!
|
|
54493
|
+
const p = join27(opts.root, c.file);
|
|
54494
|
+
if (!existsSync23(p)) continue;
|
|
54252
54495
|
let sbom;
|
|
54253
54496
|
try {
|
|
54254
|
-
sbom = c.parse(
|
|
54497
|
+
sbom = c.parse(readFileSync22(p, "utf8"));
|
|
54255
54498
|
} catch {
|
|
54256
54499
|
continue;
|
|
54257
54500
|
}
|
|
@@ -54699,7 +54942,7 @@ var ConsolidateWorker = class {
|
|
|
54699
54942
|
init_paths();
|
|
54700
54943
|
|
|
54701
54944
|
// src/lock.ts
|
|
54702
|
-
import { existsSync as
|
|
54945
|
+
import { existsSync as existsSync24, readFileSync as readFileSync23 } from "node:fs";
|
|
54703
54946
|
function isProcessAlive(pid) {
|
|
54704
54947
|
if (!pid || pid <= 0) return false;
|
|
54705
54948
|
try {
|
|
@@ -54710,9 +54953,9 @@ function isProcessAlive(pid) {
|
|
|
54710
54953
|
}
|
|
54711
54954
|
}
|
|
54712
54955
|
function readDaemonLock(lockPath) {
|
|
54713
|
-
if (!
|
|
54956
|
+
if (!existsSync24(lockPath)) return null;
|
|
54714
54957
|
try {
|
|
54715
|
-
const lock = JSON.parse(
|
|
54958
|
+
const lock = JSON.parse(readFileSync23(lockPath, "utf8"));
|
|
54716
54959
|
return typeof lock.pid === "number" ? lock : null;
|
|
54717
54960
|
} catch {
|
|
54718
54961
|
return null;
|
|
@@ -54729,6 +54972,39 @@ init_config();
|
|
|
54729
54972
|
// src/update.ts
|
|
54730
54973
|
import { spawn as spawn2 } from "node:child_process";
|
|
54731
54974
|
var PACKAGE_NAME = "@inerrata-corporation/errata";
|
|
54975
|
+
function parse3(v) {
|
|
54976
|
+
const m = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z][0-9A-Za-z.-]*))?/.exec(v.trim());
|
|
54977
|
+
if (!m) return null;
|
|
54978
|
+
return {
|
|
54979
|
+
base: [Number(m[1]), Number(m[2]), Number(m[3])],
|
|
54980
|
+
pre: m[4] === void 0 ? null : m[4].split(/[.-]/).map((p) => /^\d+$/.test(p) ? Number(p) : p)
|
|
54981
|
+
};
|
|
54982
|
+
}
|
|
54983
|
+
function compareVersions(a, b) {
|
|
54984
|
+
const pa = parse3(a);
|
|
54985
|
+
const pb = parse3(b);
|
|
54986
|
+
if (!pa || !pb) return 0;
|
|
54987
|
+
const [aMaj, aMin, aPatch] = pa.base;
|
|
54988
|
+
const [bMaj, bMin, bPatch] = pb.base;
|
|
54989
|
+
if (aMaj !== bMaj) return aMaj - bMaj;
|
|
54990
|
+
if (aMin !== bMin) return aMin - bMin;
|
|
54991
|
+
if (aPatch !== bPatch) return aPatch - bPatch;
|
|
54992
|
+
if (pa.pre === null && pb.pre === null) return 0;
|
|
54993
|
+
if (pa.pre === null) return 1;
|
|
54994
|
+
if (pb.pre === null) return -1;
|
|
54995
|
+
for (let i2 = 0; i2 < Math.max(pa.pre.length, pb.pre.length); i2++) {
|
|
54996
|
+
const x = pa.pre[i2];
|
|
54997
|
+
const y = pb.pre[i2];
|
|
54998
|
+
if (x === void 0) return -1;
|
|
54999
|
+
if (y === void 0) return 1;
|
|
55000
|
+
if (x === y) continue;
|
|
55001
|
+
if (typeof x === "number" && typeof y === "number") return x - y;
|
|
55002
|
+
if (typeof x === "number") return -1;
|
|
55003
|
+
if (typeof y === "number") return 1;
|
|
55004
|
+
return x < y ? -1 : 1;
|
|
55005
|
+
}
|
|
55006
|
+
return 0;
|
|
55007
|
+
}
|
|
54732
55008
|
async function latestPublished(channel, timeoutMs = 4e3) {
|
|
54733
55009
|
const ctrl = new AbortController();
|
|
54734
55010
|
const timer = setTimeout(() => ctrl.abort(), timeoutMs);
|
|
@@ -54748,10 +55024,14 @@ async function latestPublished(channel, timeoutMs = 4e3) {
|
|
|
54748
55024
|
}
|
|
54749
55025
|
async function checkForUpdate(channel) {
|
|
54750
55026
|
const latest = await latestPublished(channel);
|
|
55027
|
+
const direction = latest === null ? 0 : compareVersions(latest, DAEMON_VERSION);
|
|
54751
55028
|
return {
|
|
54752
55029
|
current: DAEMON_VERSION,
|
|
54753
55030
|
latest,
|
|
54754
|
-
|
|
55031
|
+
// `compareVersions` returns 0 for unparseable input, so an unrecognizable tag
|
|
55032
|
+
// is treated as "nothing to do" rather than gambling on a direction.
|
|
55033
|
+
updateAvailable: latest !== null && direction > 0,
|
|
55034
|
+
downgradeAvailable: latest !== null && direction < 0
|
|
54755
55035
|
};
|
|
54756
55036
|
}
|
|
54757
55037
|
var POLL_INTERVAL_MS = {
|
|
@@ -54954,12 +55234,12 @@ async function reanchorProject(opts) {
|
|
|
54954
55234
|
}
|
|
54955
55235
|
|
|
54956
55236
|
// src/adopt.ts
|
|
54957
|
-
import { existsSync as
|
|
54958
|
-
import { dirname as dirname10, join as
|
|
55237
|
+
import { existsSync as existsSync25 } from "node:fs";
|
|
55238
|
+
import { dirname as dirname10, join as join28 } from "node:path";
|
|
54959
55239
|
function findGitRoot(absPath) {
|
|
54960
55240
|
let dir = absPath;
|
|
54961
55241
|
for (let depth = 0; depth < 64; depth++) {
|
|
54962
|
-
if (
|
|
55242
|
+
if (existsSync25(join28(dir, ".git"))) return dir;
|
|
54963
55243
|
const parent = dirname10(dir);
|
|
54964
55244
|
if (parent === dir) return null;
|
|
54965
55245
|
dir = parent;
|
|
@@ -55208,7 +55488,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
55208
55488
|
void ambientLinkAll();
|
|
55209
55489
|
app.route(`/ws/${rec.id}`, rec.webApp);
|
|
55210
55490
|
try {
|
|
55211
|
-
|
|
55491
|
+
writeFileSync20(
|
|
55212
55492
|
rec.engine.paths.daemonLock,
|
|
55213
55493
|
JSON.stringify({ pid: process.pid, webUiUrl: `${baseUrl}/ws/${rec.id}`, startedAt: Date.now() }),
|
|
55214
55494
|
"utf8"
|
|
@@ -55397,7 +55677,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
55397
55677
|
baseUrl = `http://127.0.0.1:${port}`;
|
|
55398
55678
|
try {
|
|
55399
55679
|
ensureDir(globalDir());
|
|
55400
|
-
|
|
55680
|
+
writeFileSync20(
|
|
55401
55681
|
lockPath,
|
|
55402
55682
|
JSON.stringify({ pid: process.pid, webUiUrl: baseUrl, startedAt: Date.now() }),
|
|
55403
55683
|
"utf8"
|
|
@@ -55406,7 +55686,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
55406
55686
|
}
|
|
55407
55687
|
for (const r of records) {
|
|
55408
55688
|
try {
|
|
55409
|
-
|
|
55689
|
+
writeFileSync20(
|
|
55410
55690
|
r.engine.paths.daemonLock,
|
|
55411
55691
|
JSON.stringify({ pid: process.pid, webUiUrl: `${baseUrl}/ws/${r.id}`, startedAt: Date.now() }),
|
|
55412
55692
|
"utf8"
|
|
@@ -55733,6 +56013,11 @@ async function startMultiDaemon(opts = {}) {
|
|
|
55733
56013
|
if (!local) continue;
|
|
55734
56014
|
store.updateNode(localId, { attrs: { ...local.attrs, contributedAtSeq: seq } });
|
|
55735
56015
|
}
|
|
56016
|
+
if (p.blockedNodeIds?.length) {
|
|
56017
|
+
console.log(
|
|
56018
|
+
`[sync\u2192cloud] [${projectName}] context: ${p.blockedNodeIds.length} node(s) refused by an edge/CDN filter on content \u2014 left pending, will retry`
|
|
56019
|
+
);
|
|
56020
|
+
}
|
|
55736
56021
|
noteFlushProgress(p.accepted, p.nodeIds.length, `context ${p.chunkIndex}/${p.totalChunks}`);
|
|
55737
56022
|
}
|
|
55738
56023
|
});
|
|
@@ -55762,9 +56047,18 @@ async function startMultiDaemon(opts = {}) {
|
|
|
55762
56047
|
if (instances) {
|
|
55763
56048
|
if (project) instances.projectId = project.projectId;
|
|
55764
56049
|
await lane("instances", projectName, async () => {
|
|
56050
|
+
const blocked = /* @__PURE__ */ new Set();
|
|
55765
56051
|
const res = await client.ingest(instances, {
|
|
55766
|
-
onChunk: (p) =>
|
|
56052
|
+
onChunk: (p) => {
|
|
56053
|
+
for (const id of p.blockedNodeIds ?? []) blocked.add(id);
|
|
56054
|
+
noteFlushProgress(p.accepted, p.nodeIds.length, `instances ${p.chunkIndex}/${p.totalChunks}`);
|
|
56055
|
+
}
|
|
55767
56056
|
});
|
|
56057
|
+
if (blocked.size > 0) {
|
|
56058
|
+
console.log(
|
|
56059
|
+
`[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]}`
|
|
56060
|
+
);
|
|
56061
|
+
}
|
|
55768
56062
|
uploaded += res.accepted;
|
|
55769
56063
|
const seq = store.currentIngestSeq();
|
|
55770
56064
|
const cloudIdByLocal = new Map(
|
|
@@ -55773,6 +56067,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
55773
56067
|
for (const n of instances.nodes) {
|
|
55774
56068
|
const local = store.getNode(n.id);
|
|
55775
56069
|
if (!local || !["Problem", "Solution", "RootCause"].includes(local.label)) continue;
|
|
56070
|
+
if (blocked.has(n.id)) continue;
|
|
55776
56071
|
const cloudNodeId = cloudIdByLocal.get(n.id);
|
|
55777
56072
|
store.updateNode(n.id, {
|
|
55778
56073
|
attrs: {
|
|
@@ -55889,7 +56184,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
55889
56184
|
},
|
|
55890
56185
|
async stop() {
|
|
55891
56186
|
try {
|
|
55892
|
-
const cur =
|
|
56187
|
+
const cur = readFileSync24(lockPath, "utf8");
|
|
55893
56188
|
if (JSON.parse(cur).pid === process.pid) unlinkSync3(lockPath);
|
|
55894
56189
|
} catch {
|
|
55895
56190
|
}
|
|
@@ -56906,21 +57201,21 @@ async function cmdInit() {
|
|
|
56906
57201
|
if (!skipHooks) {
|
|
56907
57202
|
console.log("");
|
|
56908
57203
|
console.log("installing harness hooks...");
|
|
56909
|
-
const { existsSync:
|
|
56910
|
-
const { join:
|
|
57204
|
+
const { existsSync: existsSync27 } = await import("node:fs");
|
|
57205
|
+
const { join: join30 } = await import("node:path");
|
|
56911
57206
|
try {
|
|
56912
57207
|
await installClaudeHooks(port);
|
|
56913
57208
|
} catch (err2) {
|
|
56914
57209
|
console.warn(` \u26A0\uFE0F Claude hook install failed: ${err2 instanceof Error ? err2.message : err2}`);
|
|
56915
57210
|
}
|
|
56916
|
-
if (
|
|
57211
|
+
if (existsSync27(join30(ROOT, ".cursor"))) {
|
|
56917
57212
|
try {
|
|
56918
57213
|
await installCursorMcpConfig();
|
|
56919
57214
|
} catch (err2) {
|
|
56920
57215
|
console.warn(` \u26A0\uFE0F Cursor MCP config failed: ${err2 instanceof Error ? err2.message : err2}`);
|
|
56921
57216
|
}
|
|
56922
57217
|
}
|
|
56923
|
-
if (
|
|
57218
|
+
if (existsSync27(join30(ROOT, ".codex"))) {
|
|
56924
57219
|
try {
|
|
56925
57220
|
await installCodexHooks(port);
|
|
56926
57221
|
} catch (err2) {
|
|
@@ -57077,9 +57372,9 @@ async function cmdStatus() {
|
|
|
57077
57372
|
console.log(` stack: ${profile.stack.join(", ") || "(none)"}`);
|
|
57078
57373
|
console.log(` languages: ${profile.languages.join(", ") || "(none)"}`);
|
|
57079
57374
|
}
|
|
57080
|
-
console.log(` graph db: ${
|
|
57081
|
-
console.log(` event log: ${
|
|
57082
|
-
if (
|
|
57375
|
+
console.log(` graph db: ${existsSync26(paths.castalia) ? "yes" : "no"} (${paths.castalia})`);
|
|
57376
|
+
console.log(` event log: ${existsSync26(paths.eventLog) ? "yes" : "no"} (${paths.eventLog})`);
|
|
57377
|
+
if (existsSync26(paths.castalia)) {
|
|
57083
57378
|
try {
|
|
57084
57379
|
const { openGraphStore: openGraphStore2 } = await Promise.resolve().then(() => (init_src4(), src_exports2));
|
|
57085
57380
|
const store = openGraphStore2({ path: paths.castalia });
|
|
@@ -57095,6 +57390,16 @@ async function cmdStatus() {
|
|
|
57095
57390
|
}
|
|
57096
57391
|
}
|
|
57097
57392
|
console.log(` contribute: ${pending} pending of ${total} instance node(s)`);
|
|
57393
|
+
const rejections = store.edgeRejections();
|
|
57394
|
+
if (rejections.length > 0) {
|
|
57395
|
+
const refused = rejections.reduce((n, r) => n + r.count, 0);
|
|
57396
|
+
console.log(` edges: ${refused} refused by the ontology gate \u2014 a producer is emitting invalid edges`);
|
|
57397
|
+
for (const r of rejections.slice(0, 3)) {
|
|
57398
|
+
const mins = Math.max(0, Math.round((Date.now() - r.lastAt) / 6e4));
|
|
57399
|
+
const age = mins < 60 ? `${mins}m ago` : mins < 1440 ? `${Math.round(mins / 60)}h ago` : `${Math.round(mins / 1440)}d ago`;
|
|
57400
|
+
console.log(` ${r.count}x ${r.type} (last ${age})${r.sample ? ` \u2014 ${r.sample}` : ""}`);
|
|
57401
|
+
}
|
|
57402
|
+
}
|
|
57098
57403
|
} finally {
|
|
57099
57404
|
store.close();
|
|
57100
57405
|
}
|
|
@@ -57214,9 +57519,11 @@ async function cmdUpdate(args2) {
|
|
|
57214
57519
|
const cfg = loadConfig();
|
|
57215
57520
|
let channel = cfg.updateChannel;
|
|
57216
57521
|
let checkOnly = false;
|
|
57522
|
+
let allowDowngrade = false;
|
|
57217
57523
|
for (let i2 = 0; i2 < args2.length; i2++) {
|
|
57218
57524
|
const a = args2[i2];
|
|
57219
57525
|
if (a === "--check") checkOnly = true;
|
|
57526
|
+
else if (a === "--allow-downgrade") allowDowngrade = true;
|
|
57220
57527
|
else if (a === "--channel") {
|
|
57221
57528
|
const v = args2[++i2];
|
|
57222
57529
|
if (v === "dev" || v === "latest") channel = v;
|
|
@@ -57237,8 +57544,19 @@ async function cmdUpdate(args2) {
|
|
|
57237
57544
|
return;
|
|
57238
57545
|
}
|
|
57239
57546
|
if (!status.updateAvailable) {
|
|
57240
|
-
|
|
57241
|
-
|
|
57547
|
+
if (status.downgradeAvailable) {
|
|
57548
|
+
console.log(
|
|
57549
|
+
`channel '${channel}' points at ${status.latest}, which is OLDER than the running ${status.current}.`
|
|
57550
|
+
);
|
|
57551
|
+
console.log(` not installing \u2014 a downgrade past a store migration cannot open its own graph.`);
|
|
57552
|
+
console.log(` if this is a deliberate rollback: errata update --allow-downgrade`);
|
|
57553
|
+
if (!allowDowngrade) return;
|
|
57554
|
+
console.log(`
|
|
57555
|
+
--allow-downgrade given; proceeding.`);
|
|
57556
|
+
} else {
|
|
57557
|
+
console.log(`errata is up to date \u2014 ${status.current} (channel: ${channel})`);
|
|
57558
|
+
return;
|
|
57559
|
+
}
|
|
57242
57560
|
}
|
|
57243
57561
|
console.log(`update available: ${status.current} \u2192 ${status.latest} (channel: ${channel})`);
|
|
57244
57562
|
if (checkOnly) {
|
|
@@ -57730,11 +58048,11 @@ function cmdInstallationProfile(args2) {
|
|
|
57730
58048
|
}
|
|
57731
58049
|
async function cmdReview() {
|
|
57732
58050
|
const paths = workspacePaths(ROOT);
|
|
57733
|
-
if (!
|
|
58051
|
+
if (!existsSync26(paths.reviewQueue)) {
|
|
57734
58052
|
console.log("(review queue empty)");
|
|
57735
58053
|
return;
|
|
57736
58054
|
}
|
|
57737
|
-
const queue = JSON.parse(
|
|
58055
|
+
const queue = JSON.parse(readFileSync25(paths.reviewQueue, "utf8"));
|
|
57738
58056
|
if (queue.length === 0) {
|
|
57739
58057
|
console.log("(review queue empty)");
|
|
57740
58058
|
return;
|
|
@@ -58405,7 +58723,7 @@ async function gatherRepo(store, ws) {
|
|
|
58405
58723
|
};
|
|
58406
58724
|
}
|
|
58407
58725
|
async function gatherReportData(generatedAt) {
|
|
58408
|
-
const { existsSync:
|
|
58726
|
+
const { existsSync: existsSync27 } = await import("node:fs");
|
|
58409
58727
|
const { openGraphStore: openGraphStore2 } = await Promise.resolve().then(() => (init_src4(), src_exports2));
|
|
58410
58728
|
const cfg = loadConfig();
|
|
58411
58729
|
const outbound = cfg.consent.sync ? "auto" : "off";
|
|
@@ -58413,7 +58731,7 @@ async function gatherReportData(generatedAt) {
|
|
|
58413
58731
|
for (const ws of listWorkspaces()) {
|
|
58414
58732
|
if (ws.missing) continue;
|
|
58415
58733
|
const dbPath = workspacePaths(ws.path).castalia;
|
|
58416
|
-
if (!
|
|
58734
|
+
if (!existsSync27(dbPath)) continue;
|
|
58417
58735
|
let store = null;
|
|
58418
58736
|
try {
|
|
58419
58737
|
store = openGraphStore2({ path: dbPath });
|
|
@@ -58444,7 +58762,7 @@ async function gatherReportData(generatedAt) {
|
|
|
58444
58762
|
};
|
|
58445
58763
|
}
|
|
58446
58764
|
async function cmdReport(args2) {
|
|
58447
|
-
const { mkdirSync: mkdirSync8, writeFileSync:
|
|
58765
|
+
const { mkdirSync: mkdirSync8, writeFileSync: writeFileSync21 } = await import("node:fs");
|
|
58448
58766
|
const { renderReport: renderReport2 } = await Promise.resolve().then(() => (init_report_render(), report_render_exports));
|
|
58449
58767
|
const includeFutureVerbs = args2.includes("--future-verbs");
|
|
58450
58768
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -58457,8 +58775,8 @@ async function cmdReport(args2) {
|
|
|
58457
58775
|
const outDir = workspacePaths(ROOT).configDir;
|
|
58458
58776
|
mkdirSync8(outDir, { recursive: true });
|
|
58459
58777
|
const files = renderReport2(data, { includeFutureVerbs });
|
|
58460
|
-
for (const f of files)
|
|
58461
|
-
const indexPath =
|
|
58778
|
+
for (const f of files) writeFileSync21(join29(outDir, f.name), f.html, "utf8");
|
|
58779
|
+
const indexPath = join29(outDir, "report.html");
|
|
58462
58780
|
console.log(`report \u2192 ${indexPath}`);
|
|
58463
58781
|
console.log(
|
|
58464
58782
|
` ${data.repos.length} repo(s) \xB7 ${files.length} file(s) \xB7 ${data.rollup.nodes.toLocaleString("en-US")} nodes`
|
|
@@ -58576,15 +58894,15 @@ function hookRelayCommand(port, path2) {
|
|
|
58576
58894
|
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 '{}'`;
|
|
58577
58895
|
}
|
|
58578
58896
|
async function installClaudeHooks(port) {
|
|
58579
|
-
const { mkdirSync: mkdirSync8, existsSync:
|
|
58580
|
-
const { join:
|
|
58581
|
-
const dir =
|
|
58582
|
-
if (!
|
|
58583
|
-
const file2 =
|
|
58897
|
+
const { mkdirSync: mkdirSync8, existsSync: existsSync27, readFileSync: readFileSync26, writeFileSync: writeFileSync21 } = await import("node:fs");
|
|
58898
|
+
const { join: join30 } = await import("node:path");
|
|
58899
|
+
const dir = join30(ROOT, ".claude");
|
|
58900
|
+
if (!existsSync27(dir)) mkdirSync8(dir, { recursive: true });
|
|
58901
|
+
const file2 = join30(dir, "settings.json");
|
|
58584
58902
|
let settings = {};
|
|
58585
|
-
if (
|
|
58903
|
+
if (existsSync27(file2)) {
|
|
58586
58904
|
try {
|
|
58587
|
-
settings = JSON.parse(
|
|
58905
|
+
settings = JSON.parse(readFileSync26(file2, "utf8"));
|
|
58588
58906
|
} catch {
|
|
58589
58907
|
console.error(`refusing to overwrite invalid JSON at ${file2}`);
|
|
58590
58908
|
process.exit(2);
|
|
@@ -58630,10 +58948,10 @@ async function installClaudeHooks(port) {
|
|
|
58630
58948
|
dropErrata(list);
|
|
58631
58949
|
list.push({ hooks: [{ type: "command", command: injectCmd }] });
|
|
58632
58950
|
}
|
|
58633
|
-
|
|
58951
|
+
writeFileSync21(file2, JSON.stringify(settings, null, 2) + "\n", "utf8");
|
|
58634
58952
|
console.log(`installed Claude Code hooks \u2192 ${file2}`);
|
|
58635
58953
|
await installClaudeMcpConfig();
|
|
58636
|
-
const claudeMd =
|
|
58954
|
+
const claudeMd = join30(ROOT, "CLAUDE.md");
|
|
58637
58955
|
const recall = writeManagedBlock(claudeMd, { body: RECALL_FIRST_BLOCK });
|
|
58638
58956
|
if (recall.kind === "collision") {
|
|
58639
58957
|
console.warn(
|
|
@@ -58645,15 +58963,15 @@ async function installClaudeHooks(port) {
|
|
|
58645
58963
|
console.log(` endpoint: http://127.0.0.1:${port}/api/hook`);
|
|
58646
58964
|
}
|
|
58647
58965
|
async function installClaudeMcpConfig() {
|
|
58648
|
-
const { mkdirSync: mkdirSync8, existsSync:
|
|
58649
|
-
const { join:
|
|
58650
|
-
const file2 =
|
|
58966
|
+
const { mkdirSync: mkdirSync8, existsSync: existsSync27, readFileSync: readFileSync26, writeFileSync: writeFileSync21 } = await import("node:fs");
|
|
58967
|
+
const { join: join30, dirname: dirname11 } = await import("node:path");
|
|
58968
|
+
const file2 = join30(ROOT, ".mcp.json");
|
|
58651
58969
|
const dir = dirname11(file2);
|
|
58652
|
-
if (!
|
|
58970
|
+
if (!existsSync27(dir)) mkdirSync8(dir, { recursive: true });
|
|
58653
58971
|
let cfg = {};
|
|
58654
|
-
if (
|
|
58972
|
+
if (existsSync27(file2)) {
|
|
58655
58973
|
try {
|
|
58656
|
-
cfg = JSON.parse(
|
|
58974
|
+
cfg = JSON.parse(readFileSync26(file2, "utf8"));
|
|
58657
58975
|
} catch {
|
|
58658
58976
|
console.error(`refusing to overwrite invalid JSON at ${file2}`);
|
|
58659
58977
|
process.exit(2);
|
|
@@ -58661,21 +58979,21 @@ async function installClaudeMcpConfig() {
|
|
|
58661
58979
|
}
|
|
58662
58980
|
cfg.mcpServers ??= {};
|
|
58663
58981
|
cfg.mcpServers["errata"] = errataMcpInvocation();
|
|
58664
|
-
|
|
58982
|
+
writeFileSync21(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
|
|
58665
58983
|
console.log(`installed Claude Code MCP server config \u2192 ${file2}`);
|
|
58666
58984
|
console.log(` Claude Code will spawn \`errata mcp\` on workspace open.`);
|
|
58667
58985
|
console.log(` Tools: errata.search / locate / neighbors / callers_of / what_uses / show / similar`);
|
|
58668
58986
|
}
|
|
58669
58987
|
async function installCursorMcpConfig() {
|
|
58670
|
-
const { mkdirSync: mkdirSync8, existsSync:
|
|
58671
|
-
const { join:
|
|
58672
|
-
const dir =
|
|
58673
|
-
if (!
|
|
58674
|
-
const file2 =
|
|
58988
|
+
const { mkdirSync: mkdirSync8, existsSync: existsSync27, readFileSync: readFileSync26, writeFileSync: writeFileSync21 } = await import("node:fs");
|
|
58989
|
+
const { join: join30 } = await import("node:path");
|
|
58990
|
+
const dir = join30(ROOT, ".cursor");
|
|
58991
|
+
if (!existsSync27(dir)) mkdirSync8(dir, { recursive: true });
|
|
58992
|
+
const file2 = join30(dir, "mcp.json");
|
|
58675
58993
|
let cfg = {};
|
|
58676
|
-
if (
|
|
58994
|
+
if (existsSync27(file2)) {
|
|
58677
58995
|
try {
|
|
58678
|
-
cfg = JSON.parse(
|
|
58996
|
+
cfg = JSON.parse(readFileSync26(file2, "utf8"));
|
|
58679
58997
|
} catch {
|
|
58680
58998
|
console.error(`refusing to overwrite invalid JSON at ${file2}`);
|
|
58681
58999
|
process.exit(2);
|
|
@@ -58683,7 +59001,7 @@ async function installCursorMcpConfig() {
|
|
|
58683
59001
|
}
|
|
58684
59002
|
cfg.mcpServers ??= {};
|
|
58685
59003
|
cfg.mcpServers["errata"] = errataMcpInvocation();
|
|
58686
|
-
|
|
59004
|
+
writeFileSync21(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
|
|
58687
59005
|
console.log(`installed Cursor MCP server config \u2192 ${file2}`);
|
|
58688
59006
|
console.log(` Cursor will spawn \`errata mcp\` on workspace open.`);
|
|
58689
59007
|
console.log(` Tools: errata.search / locate / neighbors / callers_of / what_uses`);
|
|
@@ -58691,16 +59009,16 @@ async function installCursorMcpConfig() {
|
|
|
58691
59009
|
console.log(` \u26A0\uFE0F reload Cursor (Cmd/Ctrl-Shift-P \u2192 "Reload Window") to pick it up.`);
|
|
58692
59010
|
}
|
|
58693
59011
|
async function installCodexHooks(port) {
|
|
58694
|
-
const { mkdirSync: mkdirSync8, existsSync:
|
|
58695
|
-
const { join:
|
|
58696
|
-
const dir =
|
|
58697
|
-
if (!
|
|
58698
|
-
const file2 =
|
|
59012
|
+
const { mkdirSync: mkdirSync8, existsSync: existsSync27, readFileSync: readFileSync26, writeFileSync: writeFileSync21 } = await import("node:fs");
|
|
59013
|
+
const { join: join30 } = await import("node:path");
|
|
59014
|
+
const dir = join30(ROOT, ".codex");
|
|
59015
|
+
if (!existsSync27(dir)) mkdirSync8(dir, { recursive: true });
|
|
59016
|
+
const file2 = join30(dir, "config.toml");
|
|
58699
59017
|
const BEGIN = `# >>> errata hooks (errata-managed)`;
|
|
58700
59018
|
const END = `# <<< errata hooks`;
|
|
58701
59019
|
let existing = "";
|
|
58702
|
-
if (
|
|
58703
|
-
existing =
|
|
59020
|
+
if (existsSync27(file2)) {
|
|
59021
|
+
existing = readFileSync26(file2, "utf8");
|
|
58704
59022
|
const beginIdx = existing.indexOf(BEGIN);
|
|
58705
59023
|
const endIdx = existing.indexOf(END);
|
|
58706
59024
|
if (beginIdx >= 0 && endIdx > beginIdx) {
|
|
@@ -58729,7 +59047,7 @@ ${END}
|
|
|
58729
59047
|
const final = existing.length > 0 && !existing.endsWith("\n") ? `${existing}
|
|
58730
59048
|
|
|
58731
59049
|
${block}` : existing + (existing.endsWith("\n\n") ? "" : "\n") + block;
|
|
58732
|
-
|
|
59050
|
+
writeFileSync21(file2, final, "utf8");
|
|
58733
59051
|
console.log(`installed Codex hooks \u2192 ${file2}`);
|
|
58734
59052
|
console.log(` endpoint: http://127.0.0.1:${port}/api/hook`);
|
|
58735
59053
|
console.log("");
|
|
@@ -59043,7 +59361,7 @@ async function cmdDash(args2) {
|
|
|
59043
59361
|
await yieldToLoop2();
|
|
59044
59362
|
try {
|
|
59045
59363
|
const items = selectDurableMemory(handle2.sharedStore, r.engine.profile);
|
|
59046
|
-
const res = bleedRules(
|
|
59364
|
+
const res = bleedRules(join29(r.root, ".claude", "rules"), items);
|
|
59047
59365
|
if (res.written || res.pruned) {
|
|
59048
59366
|
console.log(
|
|
59049
59367
|
`[rules:${r.entry.name}] ${res.written} collective principle(s) \u2192 .claude/rules` + (res.pruned ? `, ${res.pruned} pruned` : "")
|