@inerrata-corporation/errata 2.0.1-dev.99 → 2.0.2-dev.133
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 +46 -4
- package/errata.mjs +1861 -488
- package/package.json +1 -1
- package/pass-worker.mjs +72 -15
package/errata.mjs
CHANGED
|
@@ -183,7 +183,14 @@ var init_castalia = __esm({
|
|
|
183
183
|
"SOLVED_BY",
|
|
184
184
|
"MITIGATES",
|
|
185
185
|
"REPORTED_FAILURE",
|
|
186
|
-
"CONTRADICTS"
|
|
186
|
+
"CONTRADICTS",
|
|
187
|
+
// Motif twin-faces (KN-twin-faces): failure-face motif → remedy-face motif
|
|
188
|
+
// across layers (AntiPattern/Weakness ↔ Technique/Pattern). Same
|
|
189
|
+
// problem→fix direction as FIXED_BY/SOLVED_BY. Minted by the nightly LLM
|
|
190
|
+
// twin-face pass — these are the near-identical cross-layer pairs the
|
|
191
|
+
// polarity gate (finding 5) correctly refuses to FUSE; the link carries
|
|
192
|
+
// what fusion can't.
|
|
193
|
+
"REMEDIED_BY"
|
|
187
194
|
];
|
|
188
195
|
CONCEPTUAL_EDGES = [
|
|
189
196
|
"INSTANCE_OF",
|
|
@@ -313,6 +320,10 @@ var init_castalia = __esm({
|
|
|
313
320
|
CAUSED_BY: 3,
|
|
314
321
|
FIXED_BY: 3,
|
|
315
322
|
SOLVED_BY: 3,
|
|
323
|
+
// Twin-face link (failure motif → remedy motif, KN-twin-faces) — causal-grade
|
|
324
|
+
// but a notch below witnessed FIXED_BY/SOLVED_BY: the pairing is an LLM
|
|
325
|
+
// judgment over descriptions, not an agent-witnessed resolution.
|
|
326
|
+
REMEDIED_BY: 2.5,
|
|
316
327
|
MANIFESTS_AS: 2,
|
|
317
328
|
ESCALATES_TO: 1.5,
|
|
318
329
|
AFFECTS: 1.2,
|
|
@@ -938,6 +949,12 @@ function packageCanonicalId(p) {
|
|
|
938
949
|
const name2 = eco === "npm" ? p.name.toLowerCase() : p.name;
|
|
939
950
|
return `pkg:${eco}/${name2}${p.version ? `@${p.version}` : ""}`;
|
|
940
951
|
}
|
|
952
|
+
function versionlessPurl(purl) {
|
|
953
|
+
if (!purl.startsWith("pkg:")) return null;
|
|
954
|
+
const lastSlash = purl.lastIndexOf("/");
|
|
955
|
+
const lastAt = purl.lastIndexOf("@");
|
|
956
|
+
return lastAt > lastSlash ? purl.slice(0, lastAt) : purl;
|
|
957
|
+
}
|
|
941
958
|
function parsePackageRef(ref) {
|
|
942
959
|
let rest2 = ref.trim();
|
|
943
960
|
if (rest2.startsWith("pkg:")) {
|
|
@@ -15363,7 +15380,10 @@ var init_edge_rules = __esm({
|
|
|
15363
15380
|
// NOT ruled here — the type pre-exists with broader extractor senses, and a
|
|
15364
15381
|
// new rule on an old type would reject legitimate live flows (reject-never-flip
|
|
15365
15382
|
// cuts both ways: only rule types you introduce or senses that are documented).
|
|
15366
|
-
|
|
15383
|
+
// `Component` joined the target set with OM-agent-anchors: an agent-named
|
|
15384
|
+
// component ("React Router") is the same knowledge→named-unit anchor shape as
|
|
15385
|
+
// a Tool — the knowledge is ABOUT it, not dependent on it.
|
|
15386
|
+
CONCERNS: { from: ["Problem", "Solution", "RootCause", "Claim", "Pattern"], to: ["Tool", "Component"] },
|
|
15367
15387
|
OPERATES_ON: { from: ["Algorithm"], to: ["DataStructure"] },
|
|
15368
15388
|
INVOLVES: { from: ["Problem", "Solution"], to: ["DataStructure"] },
|
|
15369
15389
|
// ── Taxonomy (Track 4 Stream C: MITRE CWE `ChildOf` → `Weakness —IS_A→ Weakness`) ──
|
|
@@ -15596,13 +15616,27 @@ var init_wire = __esm({
|
|
|
15596
15616
|
/** Canonical human-readable description (no raw paths — daemon scrubs; server rechecks). */
|
|
15597
15617
|
description: external_exports.string().min(1).max(4e3),
|
|
15598
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(),
|
|
15599
15628
|
extractionSource: external_exports.enum(INGEST_EXTRACTION_SOURCES),
|
|
15600
15629
|
validationSource: external_exports.enum(VALIDATION_SOURCES).optional(),
|
|
15601
15630
|
/** Org-membrane (M2): the daemon's anchor tag — it owns the lockfile, so it
|
|
15602
15631
|
* knows which packages are private. The door does NOT trust a `public` claim
|
|
15603
15632
|
* blindly (it re-confirms on the spine); absent ⇒ unknown ⇒ fail-closed to
|
|
15604
15633
|
* org-private. Accepted-but-ignored until ORG_MEMBRANE_ENABLED flips. */
|
|
15605
|
-
anchorVisibility: external_exports.enum(["public", "private"]).optional()
|
|
15634
|
+
anchorVisibility: external_exports.enum(["public", "private"]).optional(),
|
|
15635
|
+
/** The spine-resolvable anchor id backing a `public` tag (OM-anchor-tag): a
|
|
15636
|
+
* Package purl or `languageCanonicalId`. The door validates THIS on the
|
|
15637
|
+
* public spine (falling back to `canonicalId` when absent — context stubs
|
|
15638
|
+
* are self-anchored). Never trusted without spine confirmation. */
|
|
15639
|
+
anchor: external_exports.string().min(1).max(300).optional()
|
|
15606
15640
|
});
|
|
15607
15641
|
RouteContextCountWireSchema = external_exports.object({
|
|
15608
15642
|
confirmed: external_exports.number().int().min(0),
|
|
@@ -15706,6 +15740,9 @@ function projectSymbolId(projectSalt, projectId, relPath, qname, kind) {
|
|
|
15706
15740
|
const path2 = normalizeSymbolPath(relPath);
|
|
15707
15741
|
return `sym_${createHmac("sha256", projectSalt).update(`${projectId}:${path2}:${qname}:${kind}`).digest("hex").slice(0, 24)}`;
|
|
15708
15742
|
}
|
|
15743
|
+
function isMembraneSaltedId(id) {
|
|
15744
|
+
return typeof id === "string" && /^(orgn_|teamn_|projn_)/.test(id);
|
|
15745
|
+
}
|
|
15709
15746
|
var init_project_symbol = __esm({
|
|
15710
15747
|
"../../packages/shared/src/project-symbol.ts"() {
|
|
15711
15748
|
"use strict";
|
|
@@ -15862,7 +15899,7 @@ var init_canonicalize = __esm({
|
|
|
15862
15899
|
|
|
15863
15900
|
// ../../packages/shared/src/nlp/triage-canon.ts
|
|
15864
15901
|
function canonicalizeToken(t) {
|
|
15865
|
-
const base = t.trim().toLowerCase().replace(/
|
|
15902
|
+
const base = t.trim().toLowerCase().replace(/(?!^)@.*$|\s.*$/, "");
|
|
15866
15903
|
if (!base) return "";
|
|
15867
15904
|
return resolveCanonicalId(base) ?? base;
|
|
15868
15905
|
}
|
|
@@ -15955,6 +15992,7 @@ __export(src_exports, {
|
|
|
15955
15992
|
isCodeLabel: () => isCodeLabel,
|
|
15956
15993
|
isContextLabel: () => isContextLabel,
|
|
15957
15994
|
isInferredSource: () => isInferredSource,
|
|
15995
|
+
isMembraneSaltedId: () => isMembraneSaltedId,
|
|
15958
15996
|
isProjectOnlyEdgeType: () => isProjectOnlyEdgeType,
|
|
15959
15997
|
isProjectOnlyNodeLabel: () => isProjectOnlyNodeLabel,
|
|
15960
15998
|
isQuarantinedExtractionSource: () => isQuarantinedExtractionSource,
|
|
@@ -15993,6 +16031,7 @@ __export(src_exports, {
|
|
|
15993
16031
|
toCloudAttrs: () => toCloudAttrs,
|
|
15994
16032
|
toolCanonicalId: () => toolCanonicalId,
|
|
15995
16033
|
validateCastaliaPayload: () => validateCastaliaPayload,
|
|
16034
|
+
versionlessPurl: () => versionlessPurl,
|
|
15996
16035
|
vetSidecarSummaries: () => vetSidecarSummaries
|
|
15997
16036
|
});
|
|
15998
16037
|
var init_src = __esm({
|
|
@@ -16249,6 +16288,9 @@ var init_profile = __esm({
|
|
|
16249
16288
|
});
|
|
16250
16289
|
|
|
16251
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
|
+
}
|
|
16252
16294
|
var init_daemon_wire = __esm({
|
|
16253
16295
|
"../../packages/local-shared/src/daemon-wire.ts"() {
|
|
16254
16296
|
"use strict";
|
|
@@ -16662,6 +16704,13 @@ CREATE INDEX IF NOT EXISTS nodes_relpath ON nodes(json_extract(attrs_json, '$.re
|
|
|
16662
16704
|
findByLabel: this.db.prepare(
|
|
16663
16705
|
"SELECT * FROM nodes WHERE label = ? AND valid_to IS NULL"
|
|
16664
16706
|
),
|
|
16707
|
+
// Scalar count twin of findByLabel — same live-row semantics, no row
|
|
16708
|
+
// hydration. Exists because status surfaces (daemon `/` + `/health`) used
|
|
16709
|
+
// findNodesByLabel(...).length, materializing every row's attrs JSON and
|
|
16710
|
+
// embedding blob per request — seconds of synchronous loop-hold per poll.
|
|
16711
|
+
countByLabel: this.db.prepare(
|
|
16712
|
+
"SELECT COUNT(*) AS n FROM nodes WHERE label = ? AND valid_to IS NULL"
|
|
16713
|
+
),
|
|
16665
16714
|
// ALL versions of a label — incl frozen/closed (valid_to set). Used by the
|
|
16666
16715
|
// clean-reindex purge so a true wipe removes history too, not just live rows.
|
|
16667
16716
|
findByLabelAll: this.db.prepare("SELECT * FROM nodes WHERE label = ?"),
|
|
@@ -16915,6 +16964,13 @@ CREATE INDEX IF NOT EXISTS nodes_relpath ON nodes(json_extract(attrs_json, '$.re
|
|
|
16915
16964
|
const rows = this.stmts.findByLabel.all(label);
|
|
16916
16965
|
return rows.map(rowToNode);
|
|
16917
16966
|
}
|
|
16967
|
+
/** Live-row count for a label — `findNodesByLabel(label).length` without the
|
|
16968
|
+
* per-row hydration (attrs JSON + embedding blob). Status surfaces poll this
|
|
16969
|
+
* per project per request; the materializing form held the daemon's event
|
|
16970
|
+
* loop for seconds at scale. */
|
|
16971
|
+
countNodesByLabel(label) {
|
|
16972
|
+
return Number(this.stmts.countByLabel.get(label).n);
|
|
16973
|
+
}
|
|
16918
16974
|
findAllVersionsByLabel(label) {
|
|
16919
16975
|
const rows = this.stmts.findByLabelAll.all(label);
|
|
16920
16976
|
return rows.map(rowToNode);
|
|
@@ -18139,6 +18195,9 @@ var init_problem_package_link = __esm({
|
|
|
18139
18195
|
});
|
|
18140
18196
|
|
|
18141
18197
|
// ../../packages/local-graph/src/design-problem.ts
|
|
18198
|
+
function isConstraintProblem(node2) {
|
|
18199
|
+
return node2.attrs["kind"] === "constraint";
|
|
18200
|
+
}
|
|
18142
18201
|
function isPlaceholderStatement(statement) {
|
|
18143
18202
|
const s = statement.trim();
|
|
18144
18203
|
if (s.length < 8) return true;
|
|
@@ -18316,6 +18375,55 @@ function mintDomainNode(store, name2, ts) {
|
|
|
18316
18375
|
}
|
|
18317
18376
|
return id;
|
|
18318
18377
|
}
|
|
18378
|
+
function mintCitedPackageNode(store, ref, ts) {
|
|
18379
|
+
const cleaned = ref.replace(/\s+/g, " ").trim();
|
|
18380
|
+
const slash = /^([a-z0-9-]+)\/(.+)$/i.exec(cleaned);
|
|
18381
|
+
const hasEco = slash != null && !cleaned.startsWith("@");
|
|
18382
|
+
const name2 = (hasEco ? slash[2] : cleaned).trim();
|
|
18383
|
+
const nameLc = name2.toLowerCase();
|
|
18384
|
+
const existing = store.findNodesByLabel("Package").find((n) => String(n.attrs["name"] ?? "").toLowerCase() === nameLc);
|
|
18385
|
+
if (existing) return existing.id;
|
|
18386
|
+
let eco = hasEco ? slash[1].toLowerCase() : "";
|
|
18387
|
+
if (!eco && cleaned.startsWith("@")) eco = "npm";
|
|
18388
|
+
if (!eco) {
|
|
18389
|
+
const counts = /* @__PURE__ */ new Map();
|
|
18390
|
+
for (const p of store.findNodesByLabel("Package")) {
|
|
18391
|
+
const e = String(p.attrs["ecosystem"] ?? "").toLowerCase();
|
|
18392
|
+
if (e) counts.set(e, (counts.get(e) ?? 0) + 1);
|
|
18393
|
+
}
|
|
18394
|
+
eco = [...counts.entries()].sort((a, b) => b[1] - a[1])[0]?.[0] ?? "npm";
|
|
18395
|
+
}
|
|
18396
|
+
const purlName = eco === "npm" ? nameLc : name2;
|
|
18397
|
+
const purl = `pkg:${eco}/${purlName}`;
|
|
18398
|
+
if (!store.getNode(purl)) {
|
|
18399
|
+
store.mergeNode(
|
|
18400
|
+
buildNode(purl, "Package", name2, ts, {
|
|
18401
|
+
purl,
|
|
18402
|
+
name: name2,
|
|
18403
|
+
ecosystem: eco,
|
|
18404
|
+
resolved: false,
|
|
18405
|
+
// agent-cited, no lockfile resolution
|
|
18406
|
+
source: "convo",
|
|
18407
|
+
provisional: true
|
|
18408
|
+
})
|
|
18409
|
+
);
|
|
18410
|
+
}
|
|
18411
|
+
return purl;
|
|
18412
|
+
}
|
|
18413
|
+
function mintComponentNode(store, name2, ts) {
|
|
18414
|
+
const display = name2.replace(/\s+/g, " ").trim();
|
|
18415
|
+
const slug2 = display.toLowerCase();
|
|
18416
|
+
if (!store.getNode(slug2)) {
|
|
18417
|
+
store.mergeNode(
|
|
18418
|
+
buildNode(slug2, "Component", display, ts, {
|
|
18419
|
+
name: display,
|
|
18420
|
+
source: "convo",
|
|
18421
|
+
provisional: true
|
|
18422
|
+
})
|
|
18423
|
+
);
|
|
18424
|
+
}
|
|
18425
|
+
return slug2;
|
|
18426
|
+
}
|
|
18319
18427
|
function resolveFileNode(store, path2, workspaceId2) {
|
|
18320
18428
|
const want = path2.trim().replace(/^\.?\//, "");
|
|
18321
18429
|
for (const n of store.findNodesByLabel("File")) {
|
|
@@ -18339,7 +18447,7 @@ function tokenJaccard(a, b) {
|
|
|
18339
18447
|
for (const t of sa) if (sb.has(t)) inter++;
|
|
18340
18448
|
return inter / (sa.size + sb.size - inter);
|
|
18341
18449
|
}
|
|
18342
|
-
function reinforceSameAnchorProblem(store, relPath, workspaceId2, statement, source, ts) {
|
|
18450
|
+
function reinforceSameAnchorProblem(store, relPath, workspaceId2, statement, source, ts, kind = "problem") {
|
|
18343
18451
|
const stmt = statement.trim();
|
|
18344
18452
|
if (!ANCHORABLE_CODE.test(relPath)) return null;
|
|
18345
18453
|
const file2 = resolveFileNode(store, relPath, workspaceId2);
|
|
@@ -18350,6 +18458,8 @@ function reinforceSameAnchorProblem(store, relPath, workspaceId2, statement, sou
|
|
|
18350
18458
|
const cand = store.getNode(e.from);
|
|
18351
18459
|
if (!cand || cand.label !== "Problem" || cand.attrs["resolvedAt"]) continue;
|
|
18352
18460
|
if (cand.id === selfId) continue;
|
|
18461
|
+
const candKind = cand.attrs["kind"] === "constraint" ? "constraint" : "problem";
|
|
18462
|
+
if (candKind !== (kind === "constraint" ? "constraint" : "problem")) continue;
|
|
18353
18463
|
const score2 = tokenJaccard(stmt, cand.description);
|
|
18354
18464
|
if (score2 >= SAME_ANCHOR_DEDUP_JACCARD && (!best || score2 > best.score)) best = { node: cand, score: score2 };
|
|
18355
18465
|
}
|
|
@@ -18384,6 +18494,7 @@ function priorsForFile(store, relPath) {
|
|
|
18384
18494
|
}
|
|
18385
18495
|
if (!file2) return null;
|
|
18386
18496
|
const openProblems = [];
|
|
18497
|
+
const constraints = [];
|
|
18387
18498
|
const seenProblem = /* @__PURE__ */ new Set();
|
|
18388
18499
|
const related = /* @__PURE__ */ new Map();
|
|
18389
18500
|
for (const e of store.inEdges(file2.id, ["ANCHORED_AT"])) {
|
|
@@ -18392,14 +18503,14 @@ function priorsForFile(store, relPath) {
|
|
|
18392
18503
|
if (n.label === "Problem") {
|
|
18393
18504
|
if (!n.attrs["resolvedAt"] && !seenProblem.has(n.id)) {
|
|
18394
18505
|
seenProblem.add(n.id);
|
|
18395
|
-
openProblems.push(n);
|
|
18506
|
+
(isConstraintProblem(n) ? constraints : openProblems).push(n);
|
|
18396
18507
|
}
|
|
18397
18508
|
} else if (CITABLE_PRIOR_LABELS.has(n.label)) {
|
|
18398
18509
|
related.set(n.id, n);
|
|
18399
18510
|
}
|
|
18400
18511
|
}
|
|
18401
18512
|
const solutionsByProblem = /* @__PURE__ */ new Map();
|
|
18402
|
-
for (const p of openProblems) {
|
|
18513
|
+
for (const p of [...openProblems, ...constraints]) {
|
|
18403
18514
|
for (const e of store.outEdges(p.id, ["SOLVED_BY", "CAUSED_BY", "INSTANCE_OF"])) {
|
|
18404
18515
|
const n = store.getNode(e.to);
|
|
18405
18516
|
if (n && CITABLE_PRIOR_LABELS.has(n.label)) related.set(n.id, n);
|
|
@@ -18410,9 +18521,11 @@ function priorsForFile(store, relPath) {
|
|
|
18410
18521
|
}
|
|
18411
18522
|
}
|
|
18412
18523
|
}
|
|
18413
|
-
if (openProblems.length === 0 && related.size === 0) return null;
|
|
18414
|
-
|
|
18415
|
-
|
|
18524
|
+
if (openProblems.length === 0 && constraints.length === 0 && related.size === 0) return null;
|
|
18525
|
+
const recentFirst = (a, b) => (b.lastUpdatedAt ?? 0) - (a.lastUpdatedAt ?? 0);
|
|
18526
|
+
openProblems.sort(recentFirst);
|
|
18527
|
+
constraints.sort(recentFirst);
|
|
18528
|
+
return { file: file2, openProblems, constraints, related: [...related.values()], solutionsByProblem };
|
|
18416
18529
|
}
|
|
18417
18530
|
function anchorProblemToDiff(store, problemId, changedPaths, workspaceId2, t, opts = {}) {
|
|
18418
18531
|
return anchorNodeToDiff(store, problemId, "Problem", changedPaths, workspaceId2, t, opts);
|
|
@@ -18483,7 +18596,8 @@ function resolveDesignProblemById(store, id, fixNote, t) {
|
|
|
18483
18596
|
}
|
|
18484
18597
|
function closeDesignProblem(store, problemId, fixNote, t) {
|
|
18485
18598
|
const p = store.getNode(problemId);
|
|
18486
|
-
if (!p || p.label !== "Problem"
|
|
18599
|
+
if (!p || p.label !== "Problem") return false;
|
|
18600
|
+
if (p.attrs["resolvedAs"]) return false;
|
|
18487
18601
|
if (fixNote?.trim() && store.outEdges(problemId, ["SOLVED_BY"]).length === 0) {
|
|
18488
18602
|
const solId = `dfix_${digest({ problemId, fix: fixNote })}`.slice(0, 56);
|
|
18489
18603
|
store.mergeNode(
|
|
@@ -18491,6 +18605,7 @@ function closeDesignProblem(store, problemId, fixNote, t) {
|
|
|
18491
18605
|
);
|
|
18492
18606
|
mergeEdge(store, problemId, solId, "SOLVED_BY", t);
|
|
18493
18607
|
}
|
|
18608
|
+
if (p.attrs["resolvedAt"]) return false;
|
|
18494
18609
|
store.updateNode(problemId, {
|
|
18495
18610
|
attrs: { ...p.attrs, provisional: false, resolvedAt: t },
|
|
18496
18611
|
lastUpdatedAt: t
|
|
@@ -18531,6 +18646,7 @@ function resolveDesignProblems(store, t) {
|
|
|
18531
18646
|
for (const p of store.findNodesByLabel("Problem")) {
|
|
18532
18647
|
if (!p.id.startsWith("dprob_")) continue;
|
|
18533
18648
|
if (p.attrs["resolvedAt"]) continue;
|
|
18649
|
+
if (isConstraintProblem(p)) continue;
|
|
18534
18650
|
let symName = "";
|
|
18535
18651
|
let symRelPath;
|
|
18536
18652
|
let edited = false;
|
|
@@ -18548,7 +18664,7 @@ function resolveDesignProblems(store, t) {
|
|
|
18548
18664
|
if (store.outEdges(p.id, ["SOLVED_BY"]).length === 0) {
|
|
18549
18665
|
const solId = `dfix_${digest({ problemId: p.id, edit: t })}`.slice(0, 56);
|
|
18550
18666
|
store.mergeNode(
|
|
18551
|
-
buildNode(solId, "Solution",
|
|
18667
|
+
buildNode(solId, "Solution", `${AUTO_MINT_PREFIX}${symName}`, t, {
|
|
18552
18668
|
source: "convo",
|
|
18553
18669
|
provisional: false,
|
|
18554
18670
|
// AC-resolution-attrs: the resolving symbol/file as STRUCTURED data, not
|
|
@@ -18569,7 +18685,7 @@ function resolveDesignProblems(store, t) {
|
|
|
18569
18685
|
}
|
|
18570
18686
|
return resolved;
|
|
18571
18687
|
}
|
|
18572
|
-
var DESIGN_PROMOTE_AT, DEDUP_STOPWORDS, SAME_ANCHOR_DEDUP_JACCARD, CITABLE_PRIOR_LABELS, ANCHORABLE_CODE, MAX_ANCHOR_FILES;
|
|
18688
|
+
var DESIGN_PROMOTE_AT, DEDUP_STOPWORDS, SAME_ANCHOR_DEDUP_JACCARD, CITABLE_PRIOR_LABELS, ANCHORABLE_CODE, MAX_ANCHOR_FILES, AUTO_MINT_PREFIX;
|
|
18573
18689
|
var init_design_problem = __esm({
|
|
18574
18690
|
"../../packages/local-graph/src/design-problem.ts"() {
|
|
18575
18691
|
"use strict";
|
|
@@ -18611,6 +18727,7 @@ var init_design_problem = __esm({
|
|
|
18611
18727
|
]);
|
|
18612
18728
|
ANCHORABLE_CODE = /\.(ts|tsx|js|mjs|cjs|py|go|rs|java|rb|c|cpp|h)$/;
|
|
18613
18729
|
MAX_ANCHOR_FILES = 5;
|
|
18730
|
+
AUTO_MINT_PREFIX = "addressed by an edit to ";
|
|
18614
18731
|
}
|
|
18615
18732
|
});
|
|
18616
18733
|
|
|
@@ -18675,13 +18792,11 @@ function backfillLegacyAnchors(store, ts) {
|
|
|
18675
18792
|
}
|
|
18676
18793
|
return report;
|
|
18677
18794
|
}
|
|
18678
|
-
var AUTO_MINT_PREFIX;
|
|
18679
18795
|
var init_anchor_backfill = __esm({
|
|
18680
18796
|
"../../packages/local-graph/src/anchor-backfill.ts"() {
|
|
18681
18797
|
"use strict";
|
|
18682
18798
|
init_justification();
|
|
18683
18799
|
init_design_problem();
|
|
18684
|
-
AUTO_MINT_PREFIX = "addressed by an edit to ";
|
|
18685
18800
|
}
|
|
18686
18801
|
});
|
|
18687
18802
|
|
|
@@ -20442,6 +20557,7 @@ function mergeDuplicateProblems(store, opts) {
|
|
|
20442
20557
|
if (consumed.has(b.id)) continue;
|
|
20443
20558
|
const tb = tokens.get(b.id);
|
|
20444
20559
|
if (Math.min(ta.size, tb.size) < minTokens) continue;
|
|
20560
|
+
if (isConstraintProblem(a) !== isConstraintProblem(b)) continue;
|
|
20445
20561
|
if (overlap(ta, tb) >= minOverlap) {
|
|
20446
20562
|
cluster.push(b);
|
|
20447
20563
|
consumed.add(b.id);
|
|
@@ -20498,6 +20614,7 @@ var init_problem_dedup = __esm({
|
|
|
20498
20614
|
"use strict";
|
|
20499
20615
|
init_src();
|
|
20500
20616
|
init_src();
|
|
20617
|
+
init_design_problem();
|
|
20501
20618
|
REDIRECT_EDGES = [
|
|
20502
20619
|
"CAUSED_BY",
|
|
20503
20620
|
"SOLVED_BY",
|
|
@@ -20704,6 +20821,7 @@ var init_principle_sync = __esm({
|
|
|
20704
20821
|
// ../../packages/local-graph/src/index.ts
|
|
20705
20822
|
var src_exports2 = {};
|
|
20706
20823
|
__export(src_exports2, {
|
|
20824
|
+
AUTO_MINT_PREFIX: () => AUTO_MINT_PREFIX,
|
|
20707
20825
|
CAUSAL_FAMILY: () => CAUSAL_FAMILY,
|
|
20708
20826
|
CITABLE_PRIOR_LABELS: () => CITABLE_PRIOR_LABELS,
|
|
20709
20827
|
CODE_REACH_EDGES: () => CODE_REACH_EDGES,
|
|
@@ -20755,6 +20873,7 @@ __export(src_exports2, {
|
|
|
20755
20873
|
induceAbstractions: () => induceAbstractions,
|
|
20756
20874
|
induceTriage: () => induceTriage,
|
|
20757
20875
|
ingestDesignProblem: () => ingestDesignProblem,
|
|
20876
|
+
isConstraintProblem: () => isConstraintProblem,
|
|
20758
20877
|
isPlaceholderStatement: () => isPlaceholderStatement,
|
|
20759
20878
|
linkProblemToLanguages: () => linkProblemToLanguages,
|
|
20760
20879
|
linkProblemToPackages: () => linkProblemToPackages,
|
|
@@ -20766,6 +20885,8 @@ __export(src_exports2, {
|
|
|
20766
20885
|
matchSymbolsInText: () => matchSymbolsInText,
|
|
20767
20886
|
mergeCloudCounts: () => mergeCloudCounts,
|
|
20768
20887
|
mergeDuplicateProblems: () => mergeDuplicateProblems,
|
|
20888
|
+
mintCitedPackageNode: () => mintCitedPackageNode,
|
|
20889
|
+
mintComponentNode: () => mintComponentNode,
|
|
20769
20890
|
mintDomainNode: () => mintDomainNode,
|
|
20770
20891
|
mintPatternNode: () => mintPatternNode,
|
|
20771
20892
|
openGraphStore: () => openGraphStore,
|
|
@@ -20838,12 +20959,14 @@ function isPassiveInjectable(node2) {
|
|
|
20838
20959
|
}
|
|
20839
20960
|
function buildSnapshot(opts) {
|
|
20840
20961
|
const problems = opts.store.findNodesByLabel("Problem").filter((p) => p.attrs["mergedInto"] === void 0);
|
|
20841
|
-
const
|
|
20962
|
+
const stillOpen = problems.filter((p) => p.attrs["resolvedAt"] == null);
|
|
20963
|
+
const allProblems = stillOpen.filter((p) => !isConstraintProblem(p));
|
|
20842
20964
|
allProblems.sort((a, b) => b.lastUpdatedAt - a.lastUpdatedAt);
|
|
20843
20965
|
const recent = allProblems.slice(0, 8).map((p) => ({
|
|
20844
20966
|
node: p,
|
|
20845
20967
|
anchors: opts.store.outEdges(p.id, ["MANIFESTED_IN", "EVIDENCED_BY"])
|
|
20846
20968
|
}));
|
|
20969
|
+
const recentConstraints = stillOpen.filter((p) => isConstraintProblem(p)).sort((a, b) => b.lastUpdatedAt - a.lastUpdatedAt).slice(0, 3);
|
|
20847
20970
|
const recentResolved = problems.filter((p) => p.attrs["resolvedAt"] != null && p.attrs["resolvedAs"] == null).sort((a, b) => Number(b.attrs["resolvedAt"] ?? 0) - Number(a.attrs["resolvedAt"] ?? 0)).slice(0, 4).map((p) => {
|
|
20848
20971
|
const solEdge = opts.store.outEdges(p.id, ["SOLVED_BY"])[0];
|
|
20849
20972
|
const solution = solEdge ? opts.store.getNode(solEdge.to) ?? void 0 : void 0;
|
|
@@ -20871,10 +20994,13 @@ function buildSnapshot(opts) {
|
|
|
20871
20994
|
episodeId: episodeId2,
|
|
20872
20995
|
problems: problems2
|
|
20873
20996
|
}));
|
|
20874
|
-
const
|
|
20875
|
-
|
|
20876
|
-
|
|
20877
|
-
|
|
20997
|
+
const revisitSeen = /* @__PURE__ */ new Set();
|
|
20998
|
+
const needsRevisit = listNeedsRevisit(opts.store, (opts.now ?? /* @__PURE__ */ new Date()).getTime()).filter((r) => {
|
|
20999
|
+
const key = `${r.label}:${r.description.trim().toLowerCase()}`;
|
|
21000
|
+
if (revisitSeen.has(key)) return false;
|
|
21001
|
+
revisitSeen.add(key);
|
|
21002
|
+
return true;
|
|
21003
|
+
}).slice(0, 5);
|
|
20878
21004
|
const norm = (x) => x.toLowerCase().replace(/[^a-z0-9]+/g, "");
|
|
20879
21005
|
const pkgBase = (x) => {
|
|
20880
21006
|
const at = x.lastIndexOf("@");
|
|
@@ -20910,6 +21036,7 @@ function buildSnapshot(opts) {
|
|
|
20910
21036
|
profileContext,
|
|
20911
21037
|
recentProblems: recent,
|
|
20912
21038
|
recentResolved,
|
|
21039
|
+
recentConstraints,
|
|
20913
21040
|
...causalNudge ? { causalNudge } : {},
|
|
20914
21041
|
...domainNudge ? { domainNudge } : {},
|
|
20915
21042
|
motifs,
|
|
@@ -20962,6 +21089,7 @@ function sliceForFile(store, relPath) {
|
|
|
20962
21089
|
const fp = priorsForFile(store, relPath);
|
|
20963
21090
|
const priors = fp ? {
|
|
20964
21091
|
openProblems: fp.openProblems.slice(0, 3).map((p) => ({ id: p.id, description: p.description })),
|
|
21092
|
+
constraints: fp.constraints.slice(0, 2).map((c) => ({ id: c.id, description: c.description })),
|
|
20965
21093
|
related: fp.related.slice(0, 4).map((n) => ({ id: n.id, label: n.label, description: n.description })),
|
|
20966
21094
|
solutionsByProblem: Object.fromEntries(
|
|
20967
21095
|
fp.openProblems.slice(0, 3).map((p) => [
|
|
@@ -21056,7 +21184,7 @@ function renderSnapshot(s) {
|
|
|
21056
21184
|
}
|
|
21057
21185
|
const tagOf = (n) => s.edgeElicitation ? ` \`[${priorHandle(n)}]\`` : "";
|
|
21058
21186
|
lines.push("### Recently observed problems in this workspace");
|
|
21059
|
-
if (s.recentProblems.length === 0 && s.recentResolved.length === 0) {
|
|
21187
|
+
if (s.recentProblems.length === 0 && s.recentResolved.length === 0 && s.recentConstraints.length === 0) {
|
|
21060
21188
|
lines.push("- _none yet \u2014 errata is still building its model_");
|
|
21061
21189
|
} else {
|
|
21062
21190
|
if (s.recentProblems.length > 0) {
|
|
@@ -21078,6 +21206,12 @@ function renderSnapshot(s) {
|
|
|
21078
21206
|
);
|
|
21079
21207
|
}
|
|
21080
21208
|
}
|
|
21209
|
+
if (s.recentConstraints.length > 0) {
|
|
21210
|
+
lines.push("_Design tensions \u2014 constraints this work is shaped around, not defects to fix:_");
|
|
21211
|
+
for (const c of s.recentConstraints) {
|
|
21212
|
+
lines.push(`- \u2696 **${c.description}** \u2014 \`${c.id}\`${tagOf(c)}`);
|
|
21213
|
+
}
|
|
21214
|
+
}
|
|
21081
21215
|
if (s.recentResolved.length > 0) {
|
|
21082
21216
|
lines.push("_Recently resolved \u2014 solved here; jumping-off points, not live defects:_");
|
|
21083
21217
|
for (const r of s.recentResolved) {
|
|
@@ -21145,6 +21279,14 @@ function renderSnapshot(s) {
|
|
|
21145
21279
|
}
|
|
21146
21280
|
}
|
|
21147
21281
|
}
|
|
21282
|
+
if (w.priors?.constraints.length) {
|
|
21283
|
+
lines.push(
|
|
21284
|
+
"- **Design tensions here** \u2014 standing constraints this code is shaped around. They are NOT open work and a change does not resolve one, so there is no `(fix:)` token; cite one you worked within with `([id])`:"
|
|
21285
|
+
);
|
|
21286
|
+
for (const c of w.priors.constraints) {
|
|
21287
|
+
lines.push(` - ${c.description} \u2192 \`([${c.id}])\``);
|
|
21288
|
+
}
|
|
21289
|
+
}
|
|
21148
21290
|
if (w.priors?.related.length) {
|
|
21149
21291
|
lines.push("- **Related priors** (cite with `([id])` where you lean on one):");
|
|
21150
21292
|
for (const n of w.priors.related) {
|
|
@@ -21182,6 +21324,9 @@ function dropLowestUnit(s) {
|
|
|
21182
21324
|
case "pendingEnrichment":
|
|
21183
21325
|
if (s.pendingEnrichment.length) return s.pendingEnrichment.pop(), true;
|
|
21184
21326
|
break;
|
|
21327
|
+
case "recentConstraints":
|
|
21328
|
+
if (s.recentConstraints.length) return s.recentConstraints.pop(), true;
|
|
21329
|
+
break;
|
|
21185
21330
|
case "recentProblems":
|
|
21186
21331
|
if (s.recentProblems.length) return s.recentProblems.pop(), true;
|
|
21187
21332
|
break;
|
|
@@ -21253,8 +21398,19 @@ ${RECALL_FIRST_BODY}`;
|
|
|
21253
21398
|
// budget they drop before anything open/actionable.
|
|
21254
21399
|
"recentResolved",
|
|
21255
21400
|
"pendingEnrichment",
|
|
21256
|
-
|
|
21257
|
-
|
|
21401
|
+
// A standing design tension outranks an enrichment nudge (it prevents a wrong
|
|
21402
|
+
// decision) but yields to a live defect (which is actionable now).
|
|
21403
|
+
"recentConstraints",
|
|
21404
|
+
// `needsRevisit` used to sit LAST — the most protected band in the block. That
|
|
21405
|
+
// inverted the block's whole purpose once the link-elicitation instruction (4,942
|
|
21406
|
+
// chars, 55% of the budget, non-evictable) started competing for room: the
|
|
21407
|
+
// budgeter drained all 8 Problems and all 4 Solutions and kept nine stale
|
|
21408
|
+
// auto-close notices, so the agent was handed an instruction to cite `[handles]`
|
|
21409
|
+
// with zero problem handles left to cite. A revisit flag is a maintenance nudge
|
|
21410
|
+
// about something ALREADY closed; a live prior is the substrate every link verb
|
|
21411
|
+
// needs. Problems outrank it now.
|
|
21412
|
+
"needsRevisit",
|
|
21413
|
+
"recentProblems"
|
|
21258
21414
|
];
|
|
21259
21415
|
DEFAULT_AGENT_CONTEXT_BUDGET = 9e3;
|
|
21260
21416
|
}
|
|
@@ -21487,6 +21643,7 @@ var init_oauth = __esm({
|
|
|
21487
21643
|
|
|
21488
21644
|
// ../../packages/cloud-client/src/client.ts
|
|
21489
21645
|
import { randomUUID } from "node:crypto";
|
|
21646
|
+
import { gzipSync } from "node:zlib";
|
|
21490
21647
|
function wirePerContext(value) {
|
|
21491
21648
|
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
21492
21649
|
const out2 = {};
|
|
@@ -21530,7 +21687,12 @@ function toWirePayload(batch, runId) {
|
|
|
21530
21687
|
// attrs travel; node-level bookkeeping (embedding, momentum counters,
|
|
21531
21688
|
// bi-temporal fields) is local-stratum and never crosses.
|
|
21532
21689
|
attrs: n.attrs ?? {},
|
|
21533
|
-
extractionSource: n.extractionSource
|
|
21690
|
+
extractionSource: n.extractionSource,
|
|
21691
|
+
// Org-membrane anchor tag (OM-anchor-tag): the batch builders set these
|
|
21692
|
+
// on wire-bound projections only; the door re-validates the claim on the
|
|
21693
|
+
// public spine, so lifting them is routing input, not a grant.
|
|
21694
|
+
...n.anchorVisibility ? { anchorVisibility: n.anchorVisibility } : {},
|
|
21695
|
+
...n.anchor ? { anchor: n.anchor } : {}
|
|
21534
21696
|
}));
|
|
21535
21697
|
const edges = batch.edges.filter((e) => !droppedNodeIds.has(e.from) && !droppedNodeIds.has(e.to)).map((e) => {
|
|
21536
21698
|
const perContext = wirePerContext(e.attrs?.["perContext"]);
|
|
@@ -21679,6 +21841,11 @@ function normalizeSolution(input) {
|
|
|
21679
21841
|
validationSource: input.validationSource
|
|
21680
21842
|
};
|
|
21681
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
|
+
}
|
|
21682
21849
|
function chunkArray(items, size) {
|
|
21683
21850
|
if (items.length <= size) return items.length ? [[...items]] : [];
|
|
21684
21851
|
const out2 = [];
|
|
@@ -21696,14 +21863,15 @@ function provenanceHeaders(provenance) {
|
|
|
21696
21863
|
...provenance.agentModel ? { "x-inerrata-agent-model": provenance.agentModel } : {}
|
|
21697
21864
|
};
|
|
21698
21865
|
}
|
|
21699
|
-
var asWireCount, INGEST_NODE_CHUNK, CloudClient, CloudError;
|
|
21866
|
+
var asWireCount, INGEST_NODE_CHUNK, COMPRESS_MIN_BYTES, CloudClient, CloudError;
|
|
21700
21867
|
var init_client = __esm({
|
|
21701
21868
|
"../../packages/cloud-client/src/client.ts"() {
|
|
21702
21869
|
"use strict";
|
|
21703
21870
|
init_oauth();
|
|
21704
21871
|
init_src();
|
|
21705
21872
|
asWireCount = (n) => typeof n === "number" && Number.isFinite(n) && n >= 0 ? Math.floor(n) : null;
|
|
21706
|
-
INGEST_NODE_CHUNK =
|
|
21873
|
+
INGEST_NODE_CHUNK = 8;
|
|
21874
|
+
COMPRESS_MIN_BYTES = 4096;
|
|
21707
21875
|
CloudClient = class {
|
|
21708
21876
|
baseUrl;
|
|
21709
21877
|
apiKey;
|
|
@@ -21718,6 +21886,8 @@ var init_client = __esm({
|
|
|
21718
21886
|
daemonVersion;
|
|
21719
21887
|
daemonChannel;
|
|
21720
21888
|
provenance;
|
|
21889
|
+
/** Cleared for the process once a server proves it cannot inflate (see `json`). */
|
|
21890
|
+
compressRequests;
|
|
21721
21891
|
constructor(opts) {
|
|
21722
21892
|
this.baseUrl = opts.baseUrl.replace(/\/+$/, "");
|
|
21723
21893
|
if (opts.apiKey !== void 0) this.apiKey = opts.apiKey;
|
|
@@ -21731,6 +21901,7 @@ var init_client = __esm({
|
|
|
21731
21901
|
this.timeoutMs = opts.timeoutMs ?? 15e3;
|
|
21732
21902
|
this.daemonVersion = opts.daemonVersion;
|
|
21733
21903
|
this.daemonChannel = opts.daemonChannel;
|
|
21904
|
+
this.compressRequests = opts.compressRequests ?? true;
|
|
21734
21905
|
this.provenance = opts.provenance ?? {
|
|
21735
21906
|
clientProduct: "inerrata_cloud_client",
|
|
21736
21907
|
clientKind: "sdk",
|
|
@@ -21851,20 +22022,48 @@ var init_client = __esm({
|
|
|
21851
22022
|
* the per-decision response into flush accounting.
|
|
21852
22023
|
*
|
|
21853
22024
|
* The v1 door caps a payload at `MAX_NODES_PER_PAYLOAD` / `MAX_EDGES_PER_PAYLOAD`
|
|
21854
|
-
* (413 over). A batch above the cap is split and drained across calls
|
|
21855
|
-
*
|
|
22025
|
+
* (413 over). A batch above the cap is split and drained across calls, every
|
|
22026
|
+
* NODE chunk first (edges empty), then EDGE chunks (nodes empty). Each chunk
|
|
22027
|
+
* gets its OWN runId: the door's durable idempotency claim is keyed on
|
|
22028
|
+
* (agent, org, runId) with the payload digest, so reusing one runId across
|
|
22029
|
+
* different chunk payloads 409s "runId was already used with a different
|
|
22030
|
+
* payload" on the second chunk — exactly how the first real >25-node drain
|
|
22031
|
+
* died (2026-07-22). The runId never grouped anything server-side; it exists
|
|
22032
|
+
* for duplicate-POST protection, which is per-request by nature.
|
|
21856
22033
|
* Recognition resolves an edge's endpoints against nodes already ingested this
|
|
21857
22034
|
* drain (endpoint-label validation is deferred to the service when an endpoint
|
|
21858
22035
|
* isn't in-payload), so the split never orphans an edge. Sub-results concat into
|
|
21859
22036
|
* one. (fix: an un-chunked >200-node backlog 413'd forever and never drained.) */
|
|
21860
|
-
async ingest(batch) {
|
|
22037
|
+
async ingest(batch, opts = {}) {
|
|
21861
22038
|
const runId = randomUUID();
|
|
22039
|
+
const startedAt = Date.now();
|
|
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);
|
|
22041
|
+
let chunkIndex = 0;
|
|
22042
|
+
const blocked = [];
|
|
22043
|
+
const emit = (nodeIds, accepted) => {
|
|
22044
|
+
chunkIndex++;
|
|
22045
|
+
const refused = blocked.splice(0, blocked.length);
|
|
22046
|
+
const refusedSet = new Set(refused);
|
|
22047
|
+
opts.onChunk?.({
|
|
22048
|
+
chunkIndex,
|
|
22049
|
+
totalChunks,
|
|
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,
|
|
22053
|
+
accepted,
|
|
22054
|
+
elapsedMs: Date.now() - startedAt,
|
|
22055
|
+
...refused.length ? { blockedNodeIds: refused } : {}
|
|
22056
|
+
});
|
|
22057
|
+
};
|
|
21862
22058
|
if (batch.nodes.length <= INGEST_NODE_CHUNK && batch.edges.length <= MAX_EDGES_PER_PAYLOAD) {
|
|
21863
|
-
const result = await this.
|
|
21864
|
-
|
|
22059
|
+
const result = await this.ingestWithSplit(batch, batch.nodes, batch.edges, blocked);
|
|
22060
|
+
const summary = summarizeIngestResult(result);
|
|
22061
|
+
emit(batch.nodes.map((n) => n.id), summary.accepted);
|
|
22062
|
+
return { ...summary, result };
|
|
21865
22063
|
}
|
|
21866
22064
|
const merged = { runId, nodes: [], edges: [] };
|
|
21867
22065
|
let pendingEdges = [...batch.edges];
|
|
22066
|
+
const echoedCloudId = /* @__PURE__ */ new Map();
|
|
21868
22067
|
for (const nodeChunk of chunkArray(batch.nodes, INGEST_NODE_CHUNK)) {
|
|
21869
22068
|
const ids = new Set(nodeChunk.map((n) => n.id));
|
|
21870
22069
|
const inChunk = pendingEdges.filter((e) => ids.has(e.from) && ids.has(e.to)).slice(0, MAX_EDGES_PER_PAYLOAD);
|
|
@@ -21872,15 +22071,27 @@ var init_client = __esm({
|
|
|
21872
22071
|
const shipped = new Set(inChunk);
|
|
21873
22072
|
pendingEdges = pendingEdges.filter((e) => !shipped.has(e));
|
|
21874
22073
|
}
|
|
21875
|
-
const r = await this.
|
|
22074
|
+
const r = await this.ingestWithSplit(batch, nodeChunk, inChunk, blocked);
|
|
22075
|
+
emit(nodeChunk.map((n) => n.id), summarizeIngestResult(r).accepted);
|
|
21876
22076
|
merged.nodes.push(...r.nodes);
|
|
21877
22077
|
merged.edges.push(...r.edges);
|
|
22078
|
+
for (const rn of r.nodes) {
|
|
22079
|
+
if (rn.nodeId && rn.nodeId !== rn.canonicalId && isMembraneSaltedId(rn.nodeId)) {
|
|
22080
|
+
echoedCloudId.set(rn.canonicalId, rn.nodeId);
|
|
22081
|
+
}
|
|
22082
|
+
}
|
|
21878
22083
|
if (r.patternReconciliation) {
|
|
21879
22084
|
merged.patternReconciliation = { ...merged.patternReconciliation, ...r.patternReconciliation };
|
|
21880
22085
|
}
|
|
21881
22086
|
}
|
|
21882
22087
|
for (const edgeChunk of chunkArray(pendingEdges, MAX_EDGES_PER_PAYLOAD)) {
|
|
21883
|
-
const
|
|
22088
|
+
const rewritten = edgeChunk.map((e) => ({
|
|
22089
|
+
...e,
|
|
22090
|
+
from: echoedCloudId.get(e.from) ?? e.from,
|
|
22091
|
+
to: echoedCloudId.get(e.to) ?? e.to
|
|
22092
|
+
}));
|
|
22093
|
+
const r = await this.ingestWire(toWirePayload({ ...batch, nodes: [], edges: rewritten }, randomUUID()));
|
|
22094
|
+
emit([], summarizeIngestResult(r).accepted);
|
|
21884
22095
|
merged.edges.push(...r.edges);
|
|
21885
22096
|
}
|
|
21886
22097
|
return { ...summarizeIngestResult(merged), result: merged };
|
|
@@ -21889,6 +22100,43 @@ var init_client = __esm({
|
|
|
21889
22100
|
async ingestWire(payload) {
|
|
21890
22101
|
return this.json("POST", "/v2/ingest", payload);
|
|
21891
22102
|
}
|
|
22103
|
+
/**
|
|
22104
|
+
* Ship a node chunk, and on an EDGE TIMEOUT split it and retry the halves.
|
|
22105
|
+
*
|
|
22106
|
+
* `INGEST_NODE_CHUNK` is a guess about how long the server takes per node, and
|
|
22107
|
+
* that number moves with the size of the graph — so any fixed value eventually
|
|
22108
|
+
* drifts into the proxy's timeout and the lane dies silently (the 2026-07-31
|
|
22109
|
+
* three-day instances-lane outage). This makes the client self-correcting
|
|
22110
|
+
* instead: a chunk that times out is halved and retried, down to a single node,
|
|
22111
|
+
* so the drain degrades to slower rather than to stopped.
|
|
22112
|
+
*
|
|
22113
|
+
* ONLY on timeout-shaped failures (502/504/408, or a transport abort). A 4xx is
|
|
22114
|
+
* a verdict about the payload — splitting it would just re-send a rejected batch
|
|
22115
|
+
* N more times — and a 409/413 has its own handling upstream.
|
|
22116
|
+
*/
|
|
22117
|
+
async ingestWithSplit(batch, nodes, edges, blocked) {
|
|
22118
|
+
try {
|
|
22119
|
+
return await this.ingestWire(toWirePayload({ ...batch, nodes, edges }, randomUUID()));
|
|
22120
|
+
} catch (err2) {
|
|
22121
|
+
const status = err2 instanceof CloudError ? err2.status : 0;
|
|
22122
|
+
const timedOut = status === 502 || status === 504 || status === 408 || status === 0;
|
|
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;
|
|
22129
|
+
const mid = Math.ceil(nodes.length / 2);
|
|
22130
|
+
const a = await this.ingestWithSplit(batch, nodes.slice(0, mid), edges, blocked);
|
|
22131
|
+
const b = await this.ingestWithSplit(batch, nodes.slice(mid), [], blocked);
|
|
22132
|
+
return {
|
|
22133
|
+
runId: a.runId,
|
|
22134
|
+
nodes: [...a.nodes, ...b.nodes],
|
|
22135
|
+
edges: [...a.edges, ...b.edges],
|
|
22136
|
+
...a.patternReconciliation || b.patternReconciliation ? { patternReconciliation: { ...a.patternReconciliation, ...b.patternReconciliation } } : {}
|
|
22137
|
+
};
|
|
22138
|
+
}
|
|
22139
|
+
}
|
|
21892
22140
|
/**
|
|
21893
22141
|
* SDK v2 graph-native write. It remembers a typed diagnostic spine through
|
|
21894
22142
|
* `/v2/ingest` instead of the legacy forum question/answer routes:
|
|
@@ -22090,10 +22338,13 @@ var init_client = __esm({
|
|
|
22090
22338
|
}
|
|
22091
22339
|
/** Pull cloud-induced skills + the session-bootstrap prime payload. `seed` is the
|
|
22092
22340
|
* canonical ids of the agent's recent problems — the cloud ranks the skills whose
|
|
22093
|
-
* motifs those problems match first (the rest are baseline).
|
|
22094
|
-
|
|
22341
|
+
* motifs those problems match first (the rest are baseline). `techSeed`
|
|
22342
|
+
* (CL-tech-bridge) is the workspace's spine tech ids (`lang:<slug>`, purls) —
|
|
22343
|
+
* a secondary relevance signal that also covers the zero-problem cold start. */
|
|
22344
|
+
async getSkills(context = "daemon skill sync", seed, techSeed) {
|
|
22095
22345
|
const qs = new URLSearchParams({ context });
|
|
22096
22346
|
if (seed && seed.length > 0) qs.set("seed", seed.join(","));
|
|
22347
|
+
if (techSeed && techSeed.length > 0) qs.set("techSeed", techSeed.join(","));
|
|
22097
22348
|
if (this.daemonVersion) qs.set("daemonVersion", this.daemonVersion);
|
|
22098
22349
|
if (this.daemonChannel) qs.set("daemonChannel", this.daemonChannel);
|
|
22099
22350
|
return this.json("GET", `/v2/skills?${qs.toString()}`);
|
|
@@ -22179,15 +22430,43 @@ var init_client = __esm({
|
|
|
22179
22430
|
const token = opts?.bearerToken ?? await this.authToken();
|
|
22180
22431
|
if (token) headers["authorization"] = `Bearer ${token}`;
|
|
22181
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
|
+
}
|
|
22182
22443
|
const ac = new AbortController();
|
|
22183
22444
|
const tid = setTimeout(() => ac.abort(), this.timeoutMs);
|
|
22184
22445
|
try {
|
|
22185
22446
|
const res = await this.fetchFn(url2, {
|
|
22186
22447
|
method,
|
|
22187
22448
|
headers,
|
|
22188
|
-
body:
|
|
22449
|
+
body: payload,
|
|
22189
22450
|
signal: ac.signal
|
|
22190
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
|
+
}
|
|
22191
22470
|
if (!res.ok) {
|
|
22192
22471
|
const text = await res.text();
|
|
22193
22472
|
throw new CloudError(
|
|
@@ -25101,15 +25380,22 @@ function triageBullet(ref) {
|
|
|
25101
25380
|
}
|
|
25102
25381
|
function linkBullet(ref) {
|
|
25103
25382
|
return [
|
|
25104
|
-
|
|
25383
|
+
// Lead-in states the trigger without the old "resembles prior knowledge"
|
|
25384
|
+
// conditional (which gated the whole bullet on recognising a prior). Kept to ONE
|
|
25385
|
+
// line on purpose: Cycle 13 measured this instruction at 55% of the 9,000-char
|
|
25386
|
+
// passive-context budget, and every char here is paid for by evicting a prior the
|
|
25387
|
+
// agent could have cited — so unproven framing is a net loss, however good it reads.
|
|
25388
|
+
" \u2022 you flagged a problem \u2014 LINK it, ESPECIALLY when the finding feels novel to here:",
|
|
25105
25389
|
` \xB7 (instance:[${ref}],[another-prior],\u2026) \u2014 the priors this problem is an instance of.`,
|
|
25106
25390
|
" Aim for ~3 DIFFERENT relevant priors; one link is weak, three triangulate it.",
|
|
25107
25391
|
` \xB7 ${TAG_EXAMPLE.pattern()} \u2014 name the general shape it instantiates (e.g. (pattern: unbounded`,
|
|
25108
25392
|
" queue growth under backpressure)) \u2014 this works with NO code anchor, and two agents naming",
|
|
25109
25393
|
" the same pattern converge on one node. Cite a shown Pattern by handle: (pattern:[handle]).",
|
|
25110
|
-
` \xB7 ${TAG_EXAMPLE.
|
|
25111
|
-
"
|
|
25112
|
-
"
|
|
25394
|
+
` \xB7 ${TAG_EXAMPLE.package()} \u2014 the PUBLIC PACKAGE the problem is about, even when this`,
|
|
25395
|
+
" workspace doesn't depend on it (e.g. (package: chokidar), (package: pypi/requests)) \u2014 a",
|
|
25396
|
+
" public-registry anchor lets the knowledge cross to the collective; internal names stay private.",
|
|
25397
|
+
` \xB7 ${TAG_EXAMPLE.component()} \u2014 the framework/product-level UNIT it concerns when it's not a`,
|
|
25398
|
+
" package or a language (e.g. (component: React Router), (component: V8 Isolate)).",
|
|
25113
25399
|
` \xB7 (aids:[${ref}],\u2026) \u2014 your FIX could also help these other, even unrelated, problems.`,
|
|
25114
25400
|
" A hypothesis, not a claim \u2014 it's recorded as may-resolve and checked by whoever tries it.",
|
|
25115
25401
|
` \xB7 when your fix relates to a PRIOR solution you were primed with (a problem's`,
|
|
@@ -25128,9 +25414,9 @@ function attemptBullet() {
|
|
|
25128
25414
|
].join("\n");
|
|
25129
25415
|
}
|
|
25130
25416
|
function buildAgentInstruction(opts = {}) {
|
|
25131
|
-
const signals = opts.signals ?? ["prior", "problem", "fix", "constraint", "triage", "attempt", "link"];
|
|
25417
|
+
const signals = opts.signals ?? ["prior", "problem", "domain", "fix", "constraint", "triage", "attempt", "link"];
|
|
25132
25418
|
const ref = opts.referent ?? "its-handle";
|
|
25133
|
-
const token = (s) => s === "problem" ? TAG_EXAMPLE.problem() : s === "constraint" ? TAG_EXAMPLE.constraint() : s === "attempt" ? TAG_EXAMPLE.tried() : s === "link" ? TAG_EXAMPLE.pattern() : TAG_EXAMPLE[s](ref);
|
|
25419
|
+
const token = (s) => s === "problem" ? TAG_EXAMPLE.problem() : s === "constraint" ? TAG_EXAMPLE.constraint() : s === "attempt" ? TAG_EXAMPLE.tried() : s === "domain" ? TAG_EXAMPLE.domain() : s === "link" ? TAG_EXAMPLE.pattern() : TAG_EXAMPLE[s](ref);
|
|
25134
25420
|
const head2 = `We tag the priors we show you with a short handle like [${opts.handleExample ?? "chokidar-glob"}]. This is a capture protocol, not optional notes: what you DON'T tag is silently lost \u2014 the tag is the ONLY thing recorded. Whenever one of these is true, wrap it inline in your prose (no fences, no extra calls). Tag every one you state; we filter downstream, so don't self-censor or batch:`;
|
|
25135
25421
|
const tail = "Mid-turn text (between tool calls) can be dropped by the harness \u2014 if a tag above appeared only mid-turn, RESTATE it in your final message of the turn; the final message always survives.";
|
|
25136
25422
|
return [
|
|
@@ -25181,6 +25467,12 @@ var init_agent_signals = __esm({
|
|
|
25181
25467
|
// DOMAIN — the abstract area a problem is about; the concept layer an
|
|
25182
25468
|
// anchor-less problem clusters on. Mints/resolves a Domain by name.
|
|
25183
25469
|
domain: () => `(domain: The Area)`,
|
|
25470
|
+
// PACKAGE/COMPONENT — agent-named public anchors (OM-agent-anchors): the
|
|
25471
|
+
// package a problem is ABOUT (even when not a dependency) and the
|
|
25472
|
+
// framework/product-level unit it concerns. Public spine anchors → the
|
|
25473
|
+
// knowledge can cross to the collective.
|
|
25474
|
+
package: () => `(package: the-package-name)`,
|
|
25475
|
+
component: () => `(component: The Component)`,
|
|
25184
25476
|
aids: (ref) => `(aids:[${ref}])`
|
|
25185
25477
|
};
|
|
25186
25478
|
GLOSS = {
|
|
@@ -25190,6 +25482,22 @@ var init_agent_signals = __esm({
|
|
|
25190
25482
|
constraint: "you made a design decision because requirements conflict or something's constrained \u2014 tag the tension, ESPECIALLY when your fix makes it 'only look' contradictory (a clean solution still hides a real trap the next agent needs)",
|
|
25191
25483
|
triage: "you diagnosed a bug \u2014 SPLIT the symptom (what breaks \u2192 [!\u2026]) from the cause (the mechanism you'd change \u2192 (cause:\u2026)); if the line says WHY it breaks, it's a cause, not a problem",
|
|
25192
25484
|
attempt: "you're attempting an approach, or an attempt didn't pan out \u2014 (tried: \u2026) / (failed: \u2026); a failed attempt rules out a path for the next agent",
|
|
25485
|
+
// DOMAIN — promoted to a FIRST-CLASS signal (was nested inside linkBullet, whose
|
|
25486
|
+
// lead-in gates on "a problem you flagged resembles prior knowledge"). Naming the
|
|
25487
|
+
// area a problem is about is unconditional and has nothing to do with recognizing
|
|
25488
|
+
// a prior, so that gate silently suppressed it: field census 2026-07-30 across 387
|
|
25489
|
+
// sessions — `domain` in 10/194 tag-emitting sessions (5%) against `problem` in
|
|
25490
|
+
// 124/194 (64%), and bimodal (the 10 that do emit average ~7 each), i.e. the
|
|
25491
|
+
// syntax is fine and the trigger was never reached.
|
|
25492
|
+
//
|
|
25493
|
+
// The gloss carries the anti-performance framing Cycles 9–11 proved is the actual
|
|
25494
|
+
// lever (the tag alone scored 0 = control; naming the bias and inverting it is
|
|
25495
|
+
// what lifted capture). The bias here is the mirror of the constraint one: an
|
|
25496
|
+
// agent that has just named a problem *precisely* feels the precision IS the
|
|
25497
|
+
// contribution, so stating the general area reads as vague restatement — exactly
|
|
25498
|
+
// when it matters most, because precise wording is what makes a problem
|
|
25499
|
+
// unfindable to anyone who doesn't already share it.
|
|
25500
|
+
domain: "you flagged a problem that isn't about one specific file \u2014 name the AREA it's about. The sharper your wording, the LESS anyone else will search for it; an abstract problem with no area is an invisible island. Title Case",
|
|
25193
25501
|
link: "the problem you flagged is an instance of priors/abstractions you can name \u2014 (instance:[h1],[h2],\u2026) / (pattern: \u2026) / (aids:[h]); rendered whole via linkBullet"
|
|
25194
25502
|
};
|
|
25195
25503
|
}
|
|
@@ -25792,6 +26100,33 @@ function federationHint(status) {
|
|
|
25792
26100
|
return void 0;
|
|
25793
26101
|
}
|
|
25794
26102
|
}
|
|
26103
|
+
function hasCloudNodeShape(id) {
|
|
26104
|
+
return CANONICAL_KNOWLEDGE_ID.test(id) || UUID_ID.test(id) || id.startsWith("pkg:");
|
|
26105
|
+
}
|
|
26106
|
+
async function collectiveDrilldown(cloud, seedId, limit) {
|
|
26107
|
+
try {
|
|
26108
|
+
const res = await cloud.search({ stack: [], domains: [], kinds: [], seed: [seedId], limit });
|
|
26109
|
+
if (res.nodes.length === 0) return null;
|
|
26110
|
+
return {
|
|
26111
|
+
seed: seedId,
|
|
26112
|
+
nodes: res.nodes.map((n) => ({
|
|
26113
|
+
id: n.id,
|
|
26114
|
+
label: n.label,
|
|
26115
|
+
name: n.description,
|
|
26116
|
+
score: Number((n.extractionConfidence ?? 0.5).toFixed(4)),
|
|
26117
|
+
hops: 1,
|
|
26118
|
+
provenance: "collective"
|
|
26119
|
+
})),
|
|
26120
|
+
edges: res.edges.map((e) => ({ from: e.from, to: e.to, type: e.type }))
|
|
26121
|
+
};
|
|
26122
|
+
} catch (err2) {
|
|
26123
|
+
console.error(
|
|
26124
|
+
"[errata] collectiveDrilldown: cloud fallback failed \u2014",
|
|
26125
|
+
err2 instanceof Error ? err2.message : err2
|
|
26126
|
+
);
|
|
26127
|
+
return null;
|
|
26128
|
+
}
|
|
26129
|
+
}
|
|
25795
26130
|
function formatDualNodes(merged) {
|
|
25796
26131
|
return merged.nodes.map((n) => ({
|
|
25797
26132
|
id: n.id,
|
|
@@ -25811,7 +26146,7 @@ function formatDualNodes(merged) {
|
|
|
25811
26146
|
} : {}
|
|
25812
26147
|
}));
|
|
25813
26148
|
}
|
|
25814
|
-
var BRIDGE_LABELS;
|
|
26149
|
+
var BRIDGE_LABELS, CANONICAL_KNOWLEDGE_ID, UUID_ID;
|
|
25815
26150
|
var init_dual_augment = __esm({
|
|
25816
26151
|
"src/dual-augment.ts"() {
|
|
25817
26152
|
"use strict";
|
|
@@ -25819,6 +26154,8 @@ var init_dual_augment = __esm({
|
|
|
25819
26154
|
init_generalize_graph();
|
|
25820
26155
|
init_dual_burst();
|
|
25821
26156
|
BRIDGE_LABELS = new Set(SEMANTIC_NODE_LABELS);
|
|
26157
|
+
CANONICAL_KNOWLEDGE_ID = /^[a-z][a-z0-9]*_[0-9a-f]{8,}$/;
|
|
26158
|
+
UUID_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
25822
26159
|
}
|
|
25823
26160
|
});
|
|
25824
26161
|
|
|
@@ -26313,6 +26650,7 @@ function mergeProblemsByEmbedding(store, opts) {
|
|
|
26313
26650
|
if (b.id === a.id || consumed.has(b.id)) continue;
|
|
26314
26651
|
if (b.embedding.length !== a.embedding.length) continue;
|
|
26315
26652
|
if ((a.attrs["embeddingVersion"] ?? "") !== (b.attrs["embeddingVersion"] ?? "")) continue;
|
|
26653
|
+
if (isConstraintProblem(a) !== isConstraintProblem(b)) continue;
|
|
26316
26654
|
if (cosine(a.embedding, b.embedding) >= minCosine) {
|
|
26317
26655
|
cluster.push(b);
|
|
26318
26656
|
consumed.add(b.id);
|
|
@@ -36734,6 +37072,12 @@ function cosine3(a, b) {
|
|
|
36734
37072
|
for (let i2 = 0; i2 < a.length; i2++) dot += a[i2] * b[i2];
|
|
36735
37073
|
return dot;
|
|
36736
37074
|
}
|
|
37075
|
+
async function collectiveSeedFallback(args2, ctx, defaultLimit) {
|
|
37076
|
+
const seedId = typeof args2["nodeId"] === "string" ? args2["nodeId"] : null;
|
|
37077
|
+
if (!seedId || !ctx.cloud || !hasCloudNodeShape(seedId)) return null;
|
|
37078
|
+
const limit = Math.max(1, Math.min(100, Number(args2["limit"] ?? defaultLimit)));
|
|
37079
|
+
return collectiveDrilldown(ctx.cloud, seedId, limit);
|
|
37080
|
+
}
|
|
36737
37081
|
function resolveSymbol2(store, args2) {
|
|
36738
37082
|
const id = args2["nodeId"];
|
|
36739
37083
|
if (typeof id === "string" && store.getNode(id)) return id;
|
|
@@ -37084,7 +37428,7 @@ var init_mcp = __esm({
|
|
|
37084
37428
|
},
|
|
37085
37429
|
{
|
|
37086
37430
|
name: "errata.neighbors",
|
|
37087
|
-
description: "Return direct in/out edges of a node. Pass either a nodeId or a qname (e.g. ClassName.method) \u2014 resolved like the other nav verbs. Use after errata.search or errata.locate to walk the graph.",
|
|
37431
|
+
description: "Return direct in/out edges of a node. Pass either a nodeId or a qname (e.g. ClassName.method) \u2014 resolved like the other nav verbs. Use after errata.search or errata.locate to walk the graph. A cloud id from search's collective blend (e.g. dprob_\u2026) that isn't in the local graph falls back to its collective neighborhood, tagged provenance:collective.",
|
|
37088
37432
|
inputSchema: {
|
|
37089
37433
|
type: "object",
|
|
37090
37434
|
properties: {
|
|
@@ -37093,9 +37437,27 @@ var init_mcp = __esm({
|
|
|
37093
37437
|
limit: { type: "number", description: "Max edges per direction (default 30)" }
|
|
37094
37438
|
}
|
|
37095
37439
|
},
|
|
37096
|
-
handler: (args2, store) => {
|
|
37440
|
+
handler: async (args2, store, ctx) => {
|
|
37097
37441
|
const id = resolveSymbol2(store, args2);
|
|
37098
|
-
if (!id)
|
|
37442
|
+
if (!id) {
|
|
37443
|
+
const cn = await collectiveSeedFallback(args2, ctx, 30);
|
|
37444
|
+
if (cn) {
|
|
37445
|
+
return {
|
|
37446
|
+
found: true,
|
|
37447
|
+
node: { id: cn.seed, provenance: "collective" },
|
|
37448
|
+
collectiveReachable: true,
|
|
37449
|
+
collectiveStatus: "cloud-seed",
|
|
37450
|
+
// Seed-touching edge types aren't on the wire (the server's seed
|
|
37451
|
+
// burst excludes the seed itself, and edges to nodes outside the
|
|
37452
|
+
// result set are dropped), so the collective fallback reports the
|
|
37453
|
+
// 1-hop neighborhood + its internal topology instead of the local
|
|
37454
|
+
// contract's typed out/in lists.
|
|
37455
|
+
nearby: cn.nodes,
|
|
37456
|
+
edges: cn.edges
|
|
37457
|
+
};
|
|
37458
|
+
}
|
|
37459
|
+
return unresolved(args2);
|
|
37460
|
+
}
|
|
37099
37461
|
const limit = Math.max(1, Math.min(200, Number(args2["limit"] ?? 30)));
|
|
37100
37462
|
const node2 = store.getNode(id);
|
|
37101
37463
|
if (!node2) return { found: false, reason: "not-found" };
|
|
@@ -37142,32 +37504,17 @@ var init_mcp = __esm({
|
|
|
37142
37504
|
handler: async (args2, store, ctx) => {
|
|
37143
37505
|
const id = resolveSymbol2(store, args2);
|
|
37144
37506
|
if (!id) {
|
|
37145
|
-
const
|
|
37146
|
-
if (
|
|
37147
|
-
|
|
37148
|
-
|
|
37149
|
-
|
|
37150
|
-
|
|
37151
|
-
|
|
37152
|
-
|
|
37153
|
-
|
|
37154
|
-
|
|
37155
|
-
|
|
37156
|
-
seed: seedId,
|
|
37157
|
-
seedProvenance: "collective",
|
|
37158
|
-
collectiveReachable: true,
|
|
37159
|
-
collectiveStatus: "cloud-seed",
|
|
37160
|
-
count: res.nodes.length,
|
|
37161
|
-
results: res.nodes.map((n) => ({
|
|
37162
|
-
id: n.id,
|
|
37163
|
-
label: n.label,
|
|
37164
|
-
name: n.description,
|
|
37165
|
-
score: Number((n.extractionConfidence ?? 0.5).toFixed(4)),
|
|
37166
|
-
hops: 1,
|
|
37167
|
-
provenance: "collective"
|
|
37168
|
-
}))
|
|
37169
|
-
};
|
|
37170
|
-
}
|
|
37507
|
+
const cn = await collectiveSeedFallback(args2, ctx, 20);
|
|
37508
|
+
if (cn) {
|
|
37509
|
+
return {
|
|
37510
|
+
seed: cn.seed,
|
|
37511
|
+
seedProvenance: "collective",
|
|
37512
|
+
collectiveReachable: true,
|
|
37513
|
+
collectiveStatus: "cloud-seed",
|
|
37514
|
+
count: cn.nodes.length,
|
|
37515
|
+
results: cn.nodes,
|
|
37516
|
+
edges: cn.edges
|
|
37517
|
+
};
|
|
37171
37518
|
}
|
|
37172
37519
|
return unresolved(args2);
|
|
37173
37520
|
}
|
|
@@ -37324,7 +37671,7 @@ var init_mcp = __esm({
|
|
|
37324
37671
|
},
|
|
37325
37672
|
{
|
|
37326
37673
|
name: "errata.why",
|
|
37327
|
-
description: "Causal/resolution neighborhood along the causal edge families (CAUSED_BY, MANIFESTS_AS, FIXED_BY, SOLVED_BY, \u2026), walked in both directions. For a Problem this surfaces its root causes AND solutions; for a Solution, the problems it resolves. Ranked by accumulated conductance. Pass nodeId or qname. Returns {seedId, nodes:[{id,label,description,hops,edgeType,relevance}]}.",
|
|
37674
|
+
description: "Causal/resolution neighborhood along the causal edge families (CAUSED_BY, MANIFESTS_AS, FIXED_BY, SOLVED_BY, \u2026), walked in both directions. For a Problem this surfaces its root causes AND solutions; for a Solution, the problems it resolves. Merges the machine-wide shared store's triage layer (cause chains from inline `<-` diagnoses land there, keyed by the same content-derived problem id). Ranked by accumulated conductance. Pass nodeId or qname. Returns {seedId, nodes:[{id,label,description,hops,edgeType,relevance}]}. A cloud id from search's collective blend (e.g. dprob_\u2026) that isn't in the local graph falls back to its collective causal neighborhood, tagged provenance:collective.",
|
|
37328
37675
|
inputSchema: {
|
|
37329
37676
|
type: "object",
|
|
37330
37677
|
properties: {
|
|
@@ -37334,12 +37681,52 @@ var init_mcp = __esm({
|
|
|
37334
37681
|
limit: { type: "number", description: "Default 30" }
|
|
37335
37682
|
}
|
|
37336
37683
|
},
|
|
37337
|
-
handler: (args2, store) => {
|
|
37684
|
+
handler: async (args2, store, ctx) => {
|
|
37338
37685
|
const id = resolveSymbol2(store, args2);
|
|
37339
|
-
if (!id)
|
|
37686
|
+
if (!id) {
|
|
37687
|
+
const cn = await collectiveSeedFallback(args2, ctx, 30);
|
|
37688
|
+
if (cn) {
|
|
37689
|
+
return {
|
|
37690
|
+
found: true,
|
|
37691
|
+
seedId: cn.seed,
|
|
37692
|
+
seedProvenance: "collective",
|
|
37693
|
+
collectiveReachable: true,
|
|
37694
|
+
collectiveStatus: "cloud-seed",
|
|
37695
|
+
nodes: cn.nodes.map((n) => ({
|
|
37696
|
+
id: n.id,
|
|
37697
|
+
label: n.label,
|
|
37698
|
+
description: n.name,
|
|
37699
|
+
hops: n.hops,
|
|
37700
|
+
relevance: n.score,
|
|
37701
|
+
provenance: n.provenance
|
|
37702
|
+
})),
|
|
37703
|
+
edges: cn.edges
|
|
37704
|
+
};
|
|
37705
|
+
}
|
|
37706
|
+
return unresolved(args2);
|
|
37707
|
+
}
|
|
37340
37708
|
const maxHops = Math.max(1, Math.min(8, Number(args2["maxHops"] ?? 4)));
|
|
37341
37709
|
const limit = Math.max(1, Math.min(100, Number(args2["limit"] ?? 30)));
|
|
37342
|
-
|
|
37710
|
+
const local = causalChain(store, { seedId: id, direction: "both", maxHops, limit });
|
|
37711
|
+
try {
|
|
37712
|
+
const path2 = sharedStorePath();
|
|
37713
|
+
if (!existsSync10(path2)) return { found: true, ...local };
|
|
37714
|
+
const shared = openGraphStore({ path: path2 });
|
|
37715
|
+
try {
|
|
37716
|
+
if (!shared.getNode(id)) return { found: true, ...local };
|
|
37717
|
+
const l2 = causalChain(shared, { seedId: id, direction: "both", maxHops, limit });
|
|
37718
|
+
const seen = new Set(local.nodes.map((n) => n.id));
|
|
37719
|
+
const merged = [
|
|
37720
|
+
...local.nodes,
|
|
37721
|
+
...l2.nodes.filter((n) => !seen.has(n.id)).map((n) => ({ ...n, store: "shared" }))
|
|
37722
|
+
].sort((a, b) => (b.relevance ?? 0) - (a.relevance ?? 0)).slice(0, limit);
|
|
37723
|
+
return { found: true, seedId: local.seedId, nodes: merged };
|
|
37724
|
+
} finally {
|
|
37725
|
+
shared.close();
|
|
37726
|
+
}
|
|
37727
|
+
} catch {
|
|
37728
|
+
return { found: true, ...local };
|
|
37729
|
+
}
|
|
37343
37730
|
}
|
|
37344
37731
|
},
|
|
37345
37732
|
{
|
|
@@ -37500,11 +37887,11 @@ var init_mcp = __esm({
|
|
|
37500
37887
|
},
|
|
37501
37888
|
{
|
|
37502
37889
|
name: "errata.problems",
|
|
37503
|
-
description: "List the workspace's Problem backlog \u2014 the triage view that search/why/impact can't give because they need a seed. status: 'open' (default) | 'resolved' (a real fix) | 'retracted' (false alarms \u2014 false_positive/dissolution) | 'all'. Also returns a `retracted` breakdown so the false-positive rate stays visible.",
|
|
37890
|
+
description: "List the workspace's Problem backlog \u2014 the triage view that search/why/impact can't give because they need a seed. status: 'open' (default) | 'resolved' (a real fix) | 'retracted' (false alarms \u2014 false_positive/dissolution) | 'constraint' (design TENSIONS captured via `(constraint: \u2026)` \u2014 standing context, not open work, so they're excluded from 'open') | 'all'. Also returns a `retracted` breakdown so the false-positive rate stays visible.",
|
|
37504
37891
|
inputSchema: {
|
|
37505
37892
|
type: "object",
|
|
37506
37893
|
properties: {
|
|
37507
|
-
status: { type: "string", description: "open | resolved | retracted | all (default open)" },
|
|
37894
|
+
status: { type: "string", description: "open | resolved | retracted | constraint | all (default open)" },
|
|
37508
37895
|
limit: { type: "number" }
|
|
37509
37896
|
}
|
|
37510
37897
|
},
|
|
@@ -37514,7 +37901,7 @@ var init_mcp = __esm({
|
|
|
37514
37901
|
const RETRACTIONS = /* @__PURE__ */ new Set(["false_positive", "invalid", "duplicate"]);
|
|
37515
37902
|
const rows = store.findAllVersionsByLabel("Problem").map((p) => {
|
|
37516
37903
|
const ra = p.attrs["resolvedAs"];
|
|
37517
|
-
const status = ra && RETRACTIONS.has(ra) ? ra : p.attrs["resolvedAt"] != null ? "resolved" : "open";
|
|
37904
|
+
const status = ra && RETRACTIONS.has(ra) ? ra : p.attrs["resolvedAt"] != null ? "resolved" : isConstraintProblem(p) ? "constraint" : "open";
|
|
37518
37905
|
const anchorEdge = store.outEdges(p.id, ["ANCHORED_AT"])[0];
|
|
37519
37906
|
const anchor = anchorEdge ? store.getNode(anchorEdge.to)?.description : void 0;
|
|
37520
37907
|
return {
|
|
@@ -37522,17 +37909,21 @@ var init_mcp = __esm({
|
|
|
37522
37909
|
problem: p.description,
|
|
37523
37910
|
status,
|
|
37524
37911
|
createdAt: p.createdAt,
|
|
37912
|
+
// Surfaced even when `status` is resolved/retracted, so a caller can tell
|
|
37913
|
+
// an explicitly-discharged TENSION from a fixed defect.
|
|
37914
|
+
...isConstraintProblem(p) ? { kind: "constraint" } : {},
|
|
37525
37915
|
...p.attrs["provisional"] ? { provisional: true } : {},
|
|
37526
37916
|
...p.attrs["resolvedReason"] ? { reason: String(p.attrs["resolvedReason"]) } : {},
|
|
37527
37917
|
...anchor ? { anchor } : {}
|
|
37528
37918
|
};
|
|
37529
37919
|
});
|
|
37530
|
-
const inScope = (s) => want === "all" ? true : want === "resolved" ? s === "resolved" : want === "retracted" ? RETRACTIONS.has(s) : s === "open";
|
|
37920
|
+
const inScope = (s) => want === "all" ? true : want === "resolved" ? s === "resolved" : want === "retracted" ? RETRACTIONS.has(s) : want === "constraint" ? s === "constraint" : s === "open";
|
|
37531
37921
|
const items = rows.filter((r) => inScope(r.status)).sort((a, b) => b.createdAt - a.createdAt).slice(0, limit);
|
|
37532
37922
|
const countBy = (s) => rows.filter((r) => r.status === s).length;
|
|
37533
37923
|
return {
|
|
37534
37924
|
open: countBy("open"),
|
|
37535
37925
|
resolved: countBy("resolved"),
|
|
37926
|
+
constraints: countBy("constraint"),
|
|
37536
37927
|
retracted: {
|
|
37537
37928
|
falsePositive: countBy("false_positive"),
|
|
37538
37929
|
dissolution: countBy("invalid"),
|
|
@@ -37621,7 +38012,8 @@ var init_mcp = __esm({
|
|
|
37621
38012
|
inputSchema: { type: "object", properties: {} },
|
|
37622
38013
|
handler: (_args, store) => {
|
|
37623
38014
|
const problems = store.findNodesByLabel("Problem");
|
|
37624
|
-
const open2 = problems.filter((p) => p.attrs["resolvedAt"] == null);
|
|
38015
|
+
const open2 = problems.filter((p) => p.attrs["resolvedAt"] == null && !isConstraintProblem(p));
|
|
38016
|
+
const constraints = problems.filter((p) => p.attrs["resolvedAt"] == null && isConstraintProblem(p));
|
|
37625
38017
|
const noFix = open2.filter((p) => store.outEdges(p.id, ["SOLVED_BY"]).length === 0);
|
|
37626
38018
|
const allProblems = store.findAllVersionsByLabel("Problem");
|
|
37627
38019
|
const ungroundedDerived = store.findNodesByLabel("Claim").filter((c) => c.attrs["crystallized"] === "derived" && Number(c.attrs["groundedSupport"] ?? 0) === 0);
|
|
@@ -37631,6 +38023,7 @@ var init_mcp = __esm({
|
|
|
37631
38023
|
strandedSymbols: findStrandedSymbols(store).length,
|
|
37632
38024
|
openProblems: open2.length,
|
|
37633
38025
|
openProblemsWithoutFix: noFix.length,
|
|
38026
|
+
designConstraints: constraints.length,
|
|
37634
38027
|
retractedFalsePositive: allProblems.filter((p) => p.attrs["resolvedAs"] === "false_positive").length,
|
|
37635
38028
|
retractedDissolution: allProblems.filter((p) => p.attrs["resolvedAs"] === "invalid").length,
|
|
37636
38029
|
ungroundedDerivedClaims: ungroundedDerived.length,
|
|
@@ -38202,7 +38595,7 @@ function formatProblemsMd(r) {
|
|
|
38202
38595
|
const lines = [head("problems")];
|
|
38203
38596
|
const ret = r.retracted ?? { falsePositive: 0, dissolution: 0, duplicate: 0 };
|
|
38204
38597
|
lines.push(
|
|
38205
|
-
`open ${r.open} \xB7 resolved ${r.resolved} \xB7 retracted: ${ret.falsePositive} fp / ${ret.dissolution} dissolution / ${ret.duplicate} dup`
|
|
38598
|
+
`open ${r.open} \xB7 resolved ${r.resolved}` + (r.constraints ? ` \xB7 constraints ${r.constraints}` : "") + ` \xB7 retracted: ${ret.falsePositive} fp / ${ret.dissolution} dissolution / ${ret.duplicate} dup`
|
|
38206
38599
|
);
|
|
38207
38600
|
lines.push(`showing ${r.count}`);
|
|
38208
38601
|
lines.push("");
|
|
@@ -45940,10 +46333,13 @@ function recallForFile(store, relPath) {
|
|
|
45940
46333
|
recallLine(p, `${TAG_EXAMPLE.fix(p.id)} if you resolved it \xB7 ${TAG_EXAMPLE.prior(p.id)} to cite${causeCue}`)
|
|
45941
46334
|
);
|
|
45942
46335
|
}
|
|
46336
|
+
for (const c of priors.constraints.slice(0, 2)) {
|
|
46337
|
+
lines.push(recallLine(c, `design tension \u2014 hold it, don't "fix" it \xB7 ${TAG_EXAMPLE.prior(c.id)} to cite`));
|
|
46338
|
+
}
|
|
45943
46339
|
for (const n of priors.related.slice(0, 4)) {
|
|
45944
46340
|
lines.push(recallLine(n, `cite with ${TAG_EXAMPLE.prior(n.id)}`));
|
|
45945
46341
|
}
|
|
45946
|
-
const total = priors.openProblems.length + priors.related.length;
|
|
46342
|
+
const total = priors.openProblems.length + priors.constraints.length + priors.related.length;
|
|
45947
46343
|
return `errata \u2014 ${total} prior(s) recorded on this file (act only if relevant):
|
|
45948
46344
|
${lines.join("\n")}
|
|
45949
46345
|
` + buildFileRecallInstruction();
|
|
@@ -46915,12 +47311,12 @@ var init_report_render = __esm({
|
|
|
46915
47311
|
|
|
46916
47312
|
// src/cli.ts
|
|
46917
47313
|
init_src5();
|
|
46918
|
-
import { closeSync as closeSync2, existsSync as
|
|
46919
|
-
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";
|
|
46920
47316
|
import { spawn as spawn3 } from "node:child_process";
|
|
46921
47317
|
|
|
46922
47318
|
// src/daemon.ts
|
|
46923
|
-
import { existsSync as
|
|
47319
|
+
import { existsSync as existsSync20, writeFileSync as writeFileSync17 } from "node:fs";
|
|
46924
47320
|
|
|
46925
47321
|
// ../../node_modules/.pnpm/@hono+node-server@1.19.11_hono@4.12.8/node_modules/@hono/node-server/dist/index.mjs
|
|
46926
47322
|
import { createServer as createServerHTTP } from "http";
|
|
@@ -47500,8 +47896,8 @@ init_config();
|
|
|
47500
47896
|
|
|
47501
47897
|
// src/engine.ts
|
|
47502
47898
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
47503
|
-
import { existsSync as
|
|
47504
|
-
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";
|
|
47505
47901
|
|
|
47506
47902
|
// ../../node_modules/.pnpm/chokidar@4.0.3/node_modules/chokidar/esm/index.js
|
|
47507
47903
|
import { stat as statcb } from "fs";
|
|
@@ -48232,9 +48628,9 @@ var NodeFsHandler = class {
|
|
|
48232
48628
|
if (this.fsw.closed) {
|
|
48233
48629
|
return;
|
|
48234
48630
|
}
|
|
48235
|
-
const
|
|
48631
|
+
const dirname11 = sysPath.dirname(file2);
|
|
48236
48632
|
const basename5 = sysPath.basename(file2);
|
|
48237
|
-
const parent = this.fsw._getWatchedDir(
|
|
48633
|
+
const parent = this.fsw._getWatchedDir(dirname11);
|
|
48238
48634
|
let prevStats = stats;
|
|
48239
48635
|
if (parent.has(basename5))
|
|
48240
48636
|
return;
|
|
@@ -48261,7 +48657,7 @@ var NodeFsHandler = class {
|
|
|
48261
48657
|
prevStats = newStats2;
|
|
48262
48658
|
}
|
|
48263
48659
|
} catch (error48) {
|
|
48264
|
-
this.fsw._remove(
|
|
48660
|
+
this.fsw._remove(dirname11, basename5);
|
|
48265
48661
|
}
|
|
48266
48662
|
} else if (parent.has(basename5)) {
|
|
48267
48663
|
const at = newStats.atimeMs;
|
|
@@ -49366,6 +49762,39 @@ init_review2();
|
|
|
49366
49762
|
import { closeSync, existsSync as existsSync12, fstatSync, openSync, readdirSync as readdirSync5, readSync, statSync as statSync3 } from "node:fs";
|
|
49367
49763
|
import { basename as basename3, dirname as dirname8, join as join15 } from "node:path";
|
|
49368
49764
|
import { homedir as homedir3 } from "node:os";
|
|
49765
|
+
function readFrom(path2, fromByte) {
|
|
49766
|
+
let fd;
|
|
49767
|
+
try {
|
|
49768
|
+
fd = openSync(path2, "r");
|
|
49769
|
+
} catch {
|
|
49770
|
+
return { text: "", nextOffset: fromByte };
|
|
49771
|
+
}
|
|
49772
|
+
try {
|
|
49773
|
+
const size = fstatSync(fd).size;
|
|
49774
|
+
const start2 = fromByte > 0 && fromByte <= size ? fromByte : 0;
|
|
49775
|
+
const len = size - start2;
|
|
49776
|
+
if (len <= 0) return { text: "", nextOffset: size };
|
|
49777
|
+
const buf = Buffer.allocUnsafe(len);
|
|
49778
|
+
readSync(fd, buf, 0, len, start2);
|
|
49779
|
+
return { text: buf.toString("utf8"), nextOffset: size };
|
|
49780
|
+
} catch {
|
|
49781
|
+
return { text: "", nextOffset: fromByte };
|
|
49782
|
+
} finally {
|
|
49783
|
+
closeSync(fd);
|
|
49784
|
+
}
|
|
49785
|
+
}
|
|
49786
|
+
function transcriptSize(path2) {
|
|
49787
|
+
try {
|
|
49788
|
+
const fd = openSync(path2, "r");
|
|
49789
|
+
try {
|
|
49790
|
+
return fstatSync(fd).size;
|
|
49791
|
+
} finally {
|
|
49792
|
+
closeSync(fd);
|
|
49793
|
+
}
|
|
49794
|
+
} catch {
|
|
49795
|
+
return 0;
|
|
49796
|
+
}
|
|
49797
|
+
}
|
|
49369
49798
|
function readTail(path2, maxBytes) {
|
|
49370
49799
|
let fd;
|
|
49371
49800
|
try {
|
|
@@ -49443,7 +49872,13 @@ function isUserTurnBoundary(obj) {
|
|
|
49443
49872
|
return blocks.some((b) => b["type"] === "text");
|
|
49444
49873
|
}
|
|
49445
49874
|
function readAssistantTurns(transcriptPath, includeThinking = true, maxBytes = 2e6) {
|
|
49446
|
-
|
|
49875
|
+
return parseAssistantTurns(readTail(transcriptPath, maxBytes), includeThinking);
|
|
49876
|
+
}
|
|
49877
|
+
function readAssistantTurnsFrom(transcriptPath, fromByte, includeThinking = true) {
|
|
49878
|
+
const { text, nextOffset } = readFrom(transcriptPath, fromByte);
|
|
49879
|
+
return { turns: parseAssistantTurns(text, includeThinking), nextOffset };
|
|
49880
|
+
}
|
|
49881
|
+
function parseAssistantTurns(raw2, includeThinking) {
|
|
49447
49882
|
if (!raw2) return [];
|
|
49448
49883
|
const turns = [];
|
|
49449
49884
|
const lines = raw2.split(/\r?\n/);
|
|
@@ -49566,10 +50001,13 @@ init_src4();
|
|
|
49566
50001
|
import { readFileSync as readFileSync10, writeFileSync as writeFileSync10 } from "node:fs";
|
|
49567
50002
|
var NEG = /n['']t|\b(?:not|never|no|none|neither|nor|unrelated|irrelevant|would|might|could|if)\b/i;
|
|
49568
50003
|
var CITE_GROUP_RE = /\(((?:[^()\n]|\([^()\n]*\)){1,200})\)/g;
|
|
49569
|
-
var HANDLE_RE = /\[([a-z0-9][\w-]{0,
|
|
50004
|
+
var HANDLE_RE = /\[([a-z0-9][\w-]{0,80})\]|((?:pat|sol|drc|dcause|dfix|dprob|prob|claim|err)_[0-9a-f]{6,})/gi;
|
|
49570
50005
|
var FIX_PREFIX = /^\s*fix:(?:#([a-z][\w-]{0,63}))?\s*/i;
|
|
49571
50006
|
var CONSTRAINT_RE = /\(\s*constraint:\s*([^()\n]{8,}?)\s*\)/gi;
|
|
49572
50007
|
var CAUSE_PREFIX = /^\s*cause:(?:#([a-z][\w-]{0,63}))?\s*/i;
|
|
50008
|
+
var NEST2_UNIT = String.raw`(?:[^()\n]|\((?:[^()\n]|\([^()\n]*\))*\))`;
|
|
50009
|
+
var FIX_LONG_RE = new RegExp(String.raw`\(\s*fix:(?:#([a-z][\w-]{0,63}))?\s*(${NEST2_UNIT}{12,}?)\s*\)`, "gi");
|
|
50010
|
+
var CAUSE_LONG_RE = new RegExp(String.raw`\(\s*cause:(?:#([a-z][\w-]{0,63}))?\s*(${NEST2_UNIT}{8,}?)\s*\)`, "gi");
|
|
49573
50011
|
var CAUSE_ARROW = /\s+(?:<-|←)\s+/;
|
|
49574
50012
|
var ATTEMPT_RE = /\(\s*(tried|failed):(?:#([a-z][\w-]{0,63}))?\s*((?:[^()\n]|\([^()\n]*\)){8,}?)\s*\)/gi;
|
|
49575
50013
|
var AIDS_PREFIX = /^\s*aids:(?:#([a-z][\w-]{0,63}))?\s*/i;
|
|
@@ -49579,8 +50017,10 @@ var ALTERNATIVE_PREFIX = /^\s*alternative:(?:#([a-z][\w-]{0,63}))?\s*/i;
|
|
|
49579
50017
|
var INSTANCE_PREFIX = /^\s*instance:\s*/i;
|
|
49580
50018
|
var PATTERN_RE = /\(\s*pattern:\s*([^()\n]{3,}?)\s*\)/gi;
|
|
49581
50019
|
var DOMAIN_RE = /\(\s*domain:\s*([^()\n]{3,}?)\s*\)/gi;
|
|
50020
|
+
var PACKAGE_RE = /\(\s*package:\s*([^()\n]{2,}?)\s*\)/gi;
|
|
50021
|
+
var COMPONENT_RE = /\(\s*component:\s*([^()\n]{2,}?)\s*\)/gi;
|
|
49582
50022
|
var CAUSE_TEXT_MIN = 8;
|
|
49583
|
-
var FLAG_RE = /\[([!?])(?:#([a-z][\w-]{0,63})\s+)?\s*([^\]\n]{8,}?)\s*(?:@\s*([^\s\]]+?)(?::(\d+))?\s*)?\]/g;
|
|
50023
|
+
var FLAG_RE = /\[([!?])(?:#([a-z][\w-]{0,63})\s+)?\s*((?:\[[^\]\n]*\]|[^\]\n]){8,}?)\s*(?:@\s*([^\s\]]+?)(?::(\d+))?\s*)?\]/g;
|
|
49584
50024
|
var CONSTRAINT_MIN = 8;
|
|
49585
50025
|
function clauseBefore(sentence, idx) {
|
|
49586
50026
|
const win = sentence.slice(Math.max(0, idx - 80), idx);
|
|
@@ -49595,6 +50035,17 @@ function fixRationaleBefore(sentence, idx) {
|
|
|
49595
50035
|
const clause = m ? win.slice(m.index + 1) : win;
|
|
49596
50036
|
return clause.replace(/\s+/g, " ").trim();
|
|
49597
50037
|
}
|
|
50038
|
+
function fixRationaleAfter(sentence, endIdx) {
|
|
50039
|
+
const win = sentence.slice(endIdx, endIdx + FIX_RATIONALE_WINDOW).replace(new RegExp(CITE_GROUP_RE.source, "g"), " ").replace(new RegExp(FLAG_RE.source, "g"), " ");
|
|
50040
|
+
const stripped = win.replace(/^[\s—:–,-]+/, "");
|
|
50041
|
+
const m = /^[^.;!?—]*/.exec(stripped);
|
|
50042
|
+
return (m ? m[0] : stripped).replace(/\s+/g, " ").trim();
|
|
50043
|
+
}
|
|
50044
|
+
function deriveFixRationale(sentence, startIdx, endIdx) {
|
|
50045
|
+
const before = fixRationaleBefore(sentence, startIdx);
|
|
50046
|
+
if (before.length >= FIX_RATIONALE_MIN) return before;
|
|
50047
|
+
return fixRationaleAfter(sentence, endIdx);
|
|
50048
|
+
}
|
|
49598
50049
|
function parseInlineTags(text) {
|
|
49599
50050
|
const out2 = [];
|
|
49600
50051
|
const deFenced = text.replace(/```[\s\S]*?```/g, " ");
|
|
@@ -49608,9 +50059,11 @@ function parseInlineTags(text) {
|
|
|
49608
50059
|
(m) => /\[[!?]|\((?:fix|cause|constraint|tried|failed):|\(\[/.test(m) ? " " : m
|
|
49609
50060
|
);
|
|
49610
50061
|
const sfield = sentence.replace(/\s+/g, " ").trim().slice(0, 160);
|
|
50062
|
+
const citeMatched = /* @__PURE__ */ new Set();
|
|
49611
50063
|
CITE_GROUP_RE.lastIndex = 0;
|
|
49612
50064
|
let g;
|
|
49613
50065
|
while ((g = CITE_GROUP_RE.exec(sentence)) !== null) {
|
|
50066
|
+
citeMatched.add(g.index);
|
|
49614
50067
|
let content = g[1];
|
|
49615
50068
|
if (/^\s*pattern:/i.test(content)) continue;
|
|
49616
50069
|
const fixM = FIX_PREFIX.exec(content);
|
|
@@ -49664,7 +50117,7 @@ function parseInlineTags(text) {
|
|
|
49664
50117
|
if (!isFix && NEG.test(clauseBefore(sentence, g.index))) continue;
|
|
49665
50118
|
let fixRationale;
|
|
49666
50119
|
if (isFix) {
|
|
49667
|
-
const r =
|
|
50120
|
+
const r = deriveFixRationale(sentence, g.index, g.index + g[0].length);
|
|
49668
50121
|
if (r.length >= FIX_RATIONALE_MIN) fixRationale = r;
|
|
49669
50122
|
}
|
|
49670
50123
|
HANDLE_RE.lastIndex = 0;
|
|
@@ -49689,6 +50142,55 @@ function parseInlineTags(text) {
|
|
|
49689
50142
|
out2.push({ kind: "fix", fixRationale: note, sentence: sfield, ...verbThread ? { threadId: verbThread } : {} });
|
|
49690
50143
|
}
|
|
49691
50144
|
}
|
|
50145
|
+
for (const pass of [
|
|
50146
|
+
{ re: FIX_LONG_RE, isFix: true },
|
|
50147
|
+
{ re: CAUSE_LONG_RE, isFix: false }
|
|
50148
|
+
]) {
|
|
50149
|
+
pass.re.lastIndex = 0;
|
|
50150
|
+
let lm;
|
|
50151
|
+
while ((lm = pass.re.exec(sentence)) !== null) {
|
|
50152
|
+
if (citeMatched.has(lm.index)) continue;
|
|
50153
|
+
const verbThread = lm[1] ?? void 0;
|
|
50154
|
+
const content = lm[2];
|
|
50155
|
+
HANDLE_RE.lastIndex = 0;
|
|
50156
|
+
const h = HANDLE_RE.exec(content);
|
|
50157
|
+
const handle2 = h ? h[1] ?? h[2] : void 0;
|
|
50158
|
+
if (!pass.isFix) {
|
|
50159
|
+
if (handle2) {
|
|
50160
|
+
out2.push({ kind: "triage", handle: handle2, sentence: sfield, ...verbThread ? { threadId: verbThread } : {} });
|
|
50161
|
+
} else {
|
|
50162
|
+
const causeText = content.replace(/\s+/g, " ").trim();
|
|
50163
|
+
if (causeText.length >= CAUSE_TEXT_MIN)
|
|
50164
|
+
out2.push({ kind: "triage", causeText, sentence: sfield, ...verbThread ? { threadId: verbThread } : {} });
|
|
50165
|
+
}
|
|
50166
|
+
continue;
|
|
50167
|
+
}
|
|
50168
|
+
if (handle2) {
|
|
50169
|
+
const inGroup = content.replace(new RegExp(HANDLE_RE.source, "gi"), " ").replace(/\s+/g, " ").trim();
|
|
50170
|
+
const r = inGroup.length >= FIX_RATIONALE_MIN ? inGroup : deriveFixRationale(sentence, lm.index, lm.index + lm[0].length);
|
|
50171
|
+
let emitted = false;
|
|
50172
|
+
HANDLE_RE.lastIndex = 0;
|
|
50173
|
+
let hh;
|
|
50174
|
+
while ((hh = HANDLE_RE.exec(content)) !== null) {
|
|
50175
|
+
const hcap = hh[1] ?? hh[2];
|
|
50176
|
+
if (hcap) {
|
|
50177
|
+
emitted = true;
|
|
50178
|
+
out2.push({
|
|
50179
|
+
kind: "fix",
|
|
50180
|
+
handle: hcap,
|
|
50181
|
+
sentence: sfield,
|
|
50182
|
+
...r.length >= FIX_RATIONALE_MIN ? { fixRationale: r } : {},
|
|
50183
|
+
...verbThread ? { threadId: verbThread } : {}
|
|
50184
|
+
});
|
|
50185
|
+
}
|
|
50186
|
+
}
|
|
50187
|
+
if (emitted) continue;
|
|
50188
|
+
}
|
|
50189
|
+
const note = content.replace(/\s+/g, " ").trim();
|
|
50190
|
+
if (note.length >= FIX_RATIONALE_MIN)
|
|
50191
|
+
out2.push({ kind: "fix", fixRationale: note, sentence: sfield, ...verbThread ? { threadId: verbThread } : {} });
|
|
50192
|
+
}
|
|
50193
|
+
}
|
|
49692
50194
|
FLAG_RE.lastIndex = 0;
|
|
49693
50195
|
let f;
|
|
49694
50196
|
while ((f = FLAG_RE.exec(sentence)) !== null) {
|
|
@@ -49774,6 +50276,18 @@ function parseInlineTags(text) {
|
|
|
49774
50276
|
const raw3 = dm[1].replace(/\s+/g, " ").trim();
|
|
49775
50277
|
if (raw3.length >= 3) out2.push({ kind: "domain", domainText: raw3, sentence: sfield });
|
|
49776
50278
|
}
|
|
50279
|
+
PACKAGE_RE.lastIndex = 0;
|
|
50280
|
+
let pk;
|
|
50281
|
+
while ((pk = PACKAGE_RE.exec(sentence)) !== null) {
|
|
50282
|
+
const raw3 = pk[1].replace(/\s+/g, " ").trim();
|
|
50283
|
+
if (raw3.length >= 2) out2.push({ kind: "package", packageText: raw3, sentence: sfield });
|
|
50284
|
+
}
|
|
50285
|
+
COMPONENT_RE.lastIndex = 0;
|
|
50286
|
+
let cm;
|
|
50287
|
+
while ((cm = COMPONENT_RE.exec(sentence)) !== null) {
|
|
50288
|
+
const raw3 = cm[1].replace(/\s+/g, " ").trim();
|
|
50289
|
+
if (raw3.length >= 2) out2.push({ kind: "component", componentText: raw3, sentence: sfield });
|
|
50290
|
+
}
|
|
49777
50291
|
CONSTRAINT_RE.lastIndex = 0;
|
|
49778
50292
|
let c;
|
|
49779
50293
|
while ((c = CONSTRAINT_RE.exec(sentence)) !== null) {
|
|
@@ -49808,7 +50322,12 @@ var LABEL_PAIR = {
|
|
|
49808
50322
|
// EDGE_RULES-clean by construction: CONCERNS allows exactly these sources.
|
|
49809
50323
|
"Problem>Tool": "CONCERNS",
|
|
49810
50324
|
"Solution>Tool": "CONCERNS",
|
|
49811
|
-
"RootCause>Tool": "CONCERNS"
|
|
50325
|
+
"RootCause>Tool": "CONCERNS",
|
|
50326
|
+
// Agent-named component anchors (OM-agent-anchors): a Component is a
|
|
50327
|
+
// framework/product-level unit the knowledge is ABOUT — CONCERNS, like Tool.
|
|
50328
|
+
"Problem>Component": "CONCERNS",
|
|
50329
|
+
"Solution>Component": "CONCERNS",
|
|
50330
|
+
"RootCause>Component": "CONCERNS"
|
|
49812
50331
|
};
|
|
49813
50332
|
var STACK_GROUNDING_EDGES = ["WRITTEN_IN", "DEPENDS_ON", "OCCURS_IN"];
|
|
49814
50333
|
var TIEBREAK = [
|
|
@@ -49907,9 +50426,9 @@ function harvestInlineTags(store, text, opts) {
|
|
|
49907
50426
|
const source = opts.sourceId ? store.getNode(opts.sourceId) : null;
|
|
49908
50427
|
const mintPriors = opts.mintPriors ?? true;
|
|
49909
50428
|
const touched = opts.sessionTouchedIds ?? /* @__PURE__ */ new Set();
|
|
49910
|
-
const plan = { priorEdges: 0, problems: [], fixes: [], triages: [], attempts: [], unresolvedFixes: [], transfers: [], solutionLinks: [], instances: [], patterns: [], domains: [], refutes: [], corroborations: [] };
|
|
50429
|
+
const plan = { priorEdges: 0, problems: [], fixes: [], triages: [], attempts: [], unresolvedFixes: [], transfers: [], solutionLinks: [], instances: [], patterns: [], domains: [], packages: [], components: [], refutes: [], corroborations: [] };
|
|
49911
50430
|
const tags = parseInlineTags(text);
|
|
49912
|
-
const symptomSeqs = tags.filter((t) => (t.kind === "problem" || t.kind === "todo"
|
|
50431
|
+
const symptomSeqs = tags.filter((t) => (t.kind === "problem" || t.kind === "todo") && t.statement).map((t) => ({ seq: t.seq ?? -1, statement: t.statement, threadId: t.threadId })).sort((a, b) => a.seq - b.seq);
|
|
49913
50432
|
const bindSymptom = (seq, threadId) => {
|
|
49914
50433
|
if (threadId) {
|
|
49915
50434
|
const hit = symptomSeqs.find((s) => s.threadId === threadId);
|
|
@@ -49939,7 +50458,7 @@ function harvestInlineTags(store, text, opts) {
|
|
|
49939
50458
|
...tag.threadId ? { threadId: tag.threadId } : {}
|
|
49940
50459
|
});
|
|
49941
50460
|
} else if (tag.kind === "constraint") {
|
|
49942
|
-
plan.problems.push({ statement: tag.statement, kind: "
|
|
50461
|
+
plan.problems.push({ statement: tag.statement, kind: "constraint" });
|
|
49943
50462
|
} else if (tag.kind === "fix") {
|
|
49944
50463
|
if (tag.handle) {
|
|
49945
50464
|
const problemId = resolveHandle(store, tag.handle, opts.handleMap);
|
|
@@ -50047,6 +50566,16 @@ function harvestInlineTags(store, text, opts) {
|
|
|
50047
50566
|
...tag.threadId ? { threadId: tag.threadId } : {},
|
|
50048
50567
|
evidence: b.evidence
|
|
50049
50568
|
});
|
|
50569
|
+
} else if (tag.kind === "package" || tag.kind === "component") {
|
|
50570
|
+
const b = bindSymptom(tag.seq, tag.threadId);
|
|
50571
|
+
const bound = {
|
|
50572
|
+
...b.statement ? { boundStatement: b.statement } : {},
|
|
50573
|
+
...b.problemId ? { problemId: b.problemId } : {},
|
|
50574
|
+
...tag.threadId ? { threadId: tag.threadId } : {},
|
|
50575
|
+
evidence: b.evidence
|
|
50576
|
+
};
|
|
50577
|
+
if (tag.kind === "package") plan.packages.push({ packageText: tag.packageText, ...bound });
|
|
50578
|
+
else plan.components.push({ componentText: tag.componentText, ...bound });
|
|
50050
50579
|
} else if (tag.kind === "attempt" || tag.kind === "failure") {
|
|
50051
50580
|
for (const h of tag.refuteHandles ?? []) {
|
|
50052
50581
|
const nodeId = resolveHandle(store, h, opts.handleMap);
|
|
@@ -50071,6 +50600,17 @@ function harvestInlineTags(store, text, opts) {
|
|
|
50071
50600
|
boundStatement: b.statement
|
|
50072
50601
|
});
|
|
50073
50602
|
}
|
|
50603
|
+
} else if (tag.kind === "prior") {
|
|
50604
|
+
const targetId = resolveHandle(store, tag.handle, opts.handleMap);
|
|
50605
|
+
const target = targetId ? store.getNode(targetId) : null;
|
|
50606
|
+
const citedLabel = target?.label ?? opts.handleMap[tag.handle]?.label;
|
|
50607
|
+
if (targetId && citedLabel && CORROBORATABLE_LABELS.has(citedLabel)) {
|
|
50608
|
+
const witnessKey = `corrob:${targetId}:lean:${digest({ h: tag.handle })}`.slice(0, 72);
|
|
50609
|
+
if (!plan.corroborations.some((c) => c.witnessKey === witnessKey)) {
|
|
50610
|
+
plan.corroborations.push({ nodeId: targetId, witnessKey });
|
|
50611
|
+
}
|
|
50612
|
+
}
|
|
50613
|
+
if (mintPriors && source && target && mintPriorEdge(store, source, target, tag.sentence, touched, opts.ts)) plan.priorEdges++;
|
|
50074
50614
|
} else if (mintPriors && source) {
|
|
50075
50615
|
const targetId = resolveHandle(store, tag.handle, opts.handleMap);
|
|
50076
50616
|
const target = targetId ? store.getNode(targetId) : null;
|
|
@@ -50079,6 +50619,20 @@ function harvestInlineTags(store, text, opts) {
|
|
|
50079
50619
|
}
|
|
50080
50620
|
return plan;
|
|
50081
50621
|
}
|
|
50622
|
+
var CORROBORATABLE_LABELS = /* @__PURE__ */ new Set([
|
|
50623
|
+
"Problem",
|
|
50624
|
+
"Solution",
|
|
50625
|
+
"RootCause",
|
|
50626
|
+
"Pattern",
|
|
50627
|
+
"AntiPattern",
|
|
50628
|
+
"Technique",
|
|
50629
|
+
"Weakness"
|
|
50630
|
+
]);
|
|
50631
|
+
function stampWitnessOrigin(items, origin) {
|
|
50632
|
+
if (!origin) return [...items];
|
|
50633
|
+
const o = digest({ p: origin }).slice(0, 12);
|
|
50634
|
+
return items.map((i2) => ({ ...i2, witnessKey: `${i2.witnessKey}:o:${o}` }));
|
|
50635
|
+
}
|
|
50082
50636
|
|
|
50083
50637
|
// src/rollup.ts
|
|
50084
50638
|
function readConversation(transcriptPath, includeThinking = true, maxChars = 6e4) {
|
|
@@ -50124,7 +50678,10 @@ function parseRollupJson(text) {
|
|
|
50124
50678
|
...str("cause") ? { cause: str("cause") } : {},
|
|
50125
50679
|
...str("fix") ? { fix: str("fix") } : {},
|
|
50126
50680
|
...str("anchor") ? { anchor: str("anchor") } : {},
|
|
50127
|
-
|
|
50681
|
+
// Preserve `constraint` (GH-constraint-kind) — collapsing it to `problem`
|
|
50682
|
+
// here would re-arm the auto-close and the inferred fix-binding on a design
|
|
50683
|
+
// tension that arrived through the rollup path instead of the inline tag.
|
|
50684
|
+
kind: o["kind"] === "todo" ? "todo" : o["kind"] === "constraint" ? "constraint" : "problem"
|
|
50128
50685
|
});
|
|
50129
50686
|
}
|
|
50130
50687
|
return flags2.slice(0, 12);
|
|
@@ -50162,6 +50719,174 @@ ${conversation}` }]
|
|
|
50162
50719
|
};
|
|
50163
50720
|
}
|
|
50164
50721
|
|
|
50722
|
+
// src/constraint-backfill.ts
|
|
50723
|
+
init_src4();
|
|
50724
|
+
init_src2();
|
|
50725
|
+
import { existsSync as existsSync13, readFileSync as readFileSync11, readdirSync as readdirSync6, writeFileSync as writeFileSync11 } from "node:fs";
|
|
50726
|
+
import { join as join16 } from "node:path";
|
|
50727
|
+
import { homedir as homedir4 } from "node:os";
|
|
50728
|
+
var BACKFILL_VERSION = 1;
|
|
50729
|
+
var EMPTY = {
|
|
50730
|
+
skipped: true,
|
|
50731
|
+
stamped: 0,
|
|
50732
|
+
detached: 0,
|
|
50733
|
+
reopened: 0,
|
|
50734
|
+
witnessed: 0,
|
|
50735
|
+
cloudTwins: [],
|
|
50736
|
+
reminted: 0,
|
|
50737
|
+
recoverable: 0
|
|
50738
|
+
};
|
|
50739
|
+
function markerPath(configDir) {
|
|
50740
|
+
return join16(configDir, "constraint-backfill.json");
|
|
50741
|
+
}
|
|
50742
|
+
function alreadyDone(configDir) {
|
|
50743
|
+
const p = markerPath(configDir);
|
|
50744
|
+
if (!existsSync13(p)) return false;
|
|
50745
|
+
try {
|
|
50746
|
+
const raw2 = JSON.parse(readFileSync11(p, "utf8"));
|
|
50747
|
+
return raw2?.version === BACKFILL_VERSION;
|
|
50748
|
+
} catch {
|
|
50749
|
+
return false;
|
|
50750
|
+
}
|
|
50751
|
+
}
|
|
50752
|
+
function replay(root) {
|
|
50753
|
+
const statements = /* @__PURE__ */ new Set();
|
|
50754
|
+
const citedByFix = /* @__PURE__ */ new Set();
|
|
50755
|
+
const dir = claudeProjectDir(root, homedir4());
|
|
50756
|
+
if (!existsSync13(dir)) return { statements, citedByFix };
|
|
50757
|
+
let names;
|
|
50758
|
+
try {
|
|
50759
|
+
names = readdirSync6(dir).filter((n) => n.endsWith(".jsonl"));
|
|
50760
|
+
} catch {
|
|
50761
|
+
return { statements, citedByFix };
|
|
50762
|
+
}
|
|
50763
|
+
for (const f of names) {
|
|
50764
|
+
let lines;
|
|
50765
|
+
try {
|
|
50766
|
+
lines = readFileSync11(join16(dir, f), "utf8").split("\n");
|
|
50767
|
+
} catch {
|
|
50768
|
+
continue;
|
|
50769
|
+
}
|
|
50770
|
+
for (const line of lines) {
|
|
50771
|
+
if (!line.trim()) continue;
|
|
50772
|
+
let rec;
|
|
50773
|
+
try {
|
|
50774
|
+
rec = JSON.parse(line);
|
|
50775
|
+
} catch {
|
|
50776
|
+
continue;
|
|
50777
|
+
}
|
|
50778
|
+
if (rec.type !== "assistant" || !Array.isArray(rec.message?.content)) continue;
|
|
50779
|
+
for (const b of rec.message.content) {
|
|
50780
|
+
if (b?.type !== "text" || typeof b.text !== "string") continue;
|
|
50781
|
+
for (const tag of parseInlineTags(b.text)) {
|
|
50782
|
+
if (tag.kind === "constraint" && tag.statement) statements.add(tag.statement);
|
|
50783
|
+
if (tag.kind === "fix") {
|
|
50784
|
+
const t = tag;
|
|
50785
|
+
if (t.handle) citedByFix.add(t.handle);
|
|
50786
|
+
if (t.threadId) citedByFix.add(t.threadId);
|
|
50787
|
+
}
|
|
50788
|
+
}
|
|
50789
|
+
}
|
|
50790
|
+
}
|
|
50791
|
+
}
|
|
50792
|
+
return { statements, citedByFix };
|
|
50793
|
+
}
|
|
50794
|
+
function backfillConstraintKind(store, opts) {
|
|
50795
|
+
if (!opts.force && !opts.dryRun && alreadyDone(opts.configDir)) return EMPTY;
|
|
50796
|
+
const { statements, citedByFix } = replay(opts.root);
|
|
50797
|
+
const report = {
|
|
50798
|
+
skipped: false,
|
|
50799
|
+
stamped: 0,
|
|
50800
|
+
detached: 0,
|
|
50801
|
+
reopened: 0,
|
|
50802
|
+
witnessed: 0,
|
|
50803
|
+
cloudTwins: [],
|
|
50804
|
+
reminted: 0,
|
|
50805
|
+
recoverable: 0
|
|
50806
|
+
};
|
|
50807
|
+
const missing = [];
|
|
50808
|
+
const seen = /* @__PURE__ */ new Set();
|
|
50809
|
+
const work = [];
|
|
50810
|
+
for (const statement of statements) {
|
|
50811
|
+
const id = designProblemId(statement);
|
|
50812
|
+
if (seen.has(id)) continue;
|
|
50813
|
+
seen.add(id);
|
|
50814
|
+
const node2 = store.getNode(id);
|
|
50815
|
+
if (!node2 || node2.label !== "Problem") {
|
|
50816
|
+
missing.push(statement);
|
|
50817
|
+
continue;
|
|
50818
|
+
}
|
|
50819
|
+
const isWitnessed = citedByFix.has(priorHandle(node2)) || citedByFix.has(id) || [...citedByFix].some((c) => c && id.startsWith(c));
|
|
50820
|
+
const fabricated = [];
|
|
50821
|
+
for (const e of store.outEdges(id, ["SOLVED_BY"])) {
|
|
50822
|
+
const sol = store.getNode(e.to);
|
|
50823
|
+
if (!sol) continue;
|
|
50824
|
+
const auto = sol.description.startsWith(AUTO_MINT_PREFIX);
|
|
50825
|
+
if (!auto && isWitnessed) report.witnessed++;
|
|
50826
|
+
else fabricated.push(sol.id);
|
|
50827
|
+
}
|
|
50828
|
+
const stamp = node2.attrs["kind"] !== "constraint";
|
|
50829
|
+
if (stamp) report.stamped++;
|
|
50830
|
+
if (fabricated.length > 0) {
|
|
50831
|
+
report.detached += fabricated.length;
|
|
50832
|
+
report.reopened++;
|
|
50833
|
+
}
|
|
50834
|
+
const cloudNodeId = node2.attrs["cloudNodeId"];
|
|
50835
|
+
if (typeof cloudNodeId === "string" && (stamp || fabricated.length > 0)) {
|
|
50836
|
+
report.cloudTwins.push(cloudNodeId);
|
|
50837
|
+
}
|
|
50838
|
+
if (stamp || fabricated.length > 0) work.push({ id, fabricated, stamp });
|
|
50839
|
+
}
|
|
50840
|
+
report.recoverable = opts.remint ? 0 : missing.length;
|
|
50841
|
+
if (opts.dryRun) {
|
|
50842
|
+
report.reminted = opts.remint ? missing.length : 0;
|
|
50843
|
+
return report;
|
|
50844
|
+
}
|
|
50845
|
+
if (opts.remint && missing.length > 0) {
|
|
50846
|
+
store.transaction(() => {
|
|
50847
|
+
for (const statement of missing) {
|
|
50848
|
+
try {
|
|
50849
|
+
const r = ingestDesignProblem(
|
|
50850
|
+
store,
|
|
50851
|
+
{ problem: statement, kind: "constraint" },
|
|
50852
|
+
{ workspaceId: "", source: `constraint-remint:v${BACKFILL_VERSION}`, ts: opts.now }
|
|
50853
|
+
);
|
|
50854
|
+
if (r.created) report.reminted++;
|
|
50855
|
+
} catch {
|
|
50856
|
+
}
|
|
50857
|
+
}
|
|
50858
|
+
});
|
|
50859
|
+
}
|
|
50860
|
+
store.transaction(() => {
|
|
50861
|
+
for (const w of work) {
|
|
50862
|
+
const node2 = store.getNode(w.id);
|
|
50863
|
+
if (!node2) continue;
|
|
50864
|
+
const attrs = { ...node2.attrs, kind: "constraint" };
|
|
50865
|
+
if (w.fabricated.length > 0) {
|
|
50866
|
+
delete attrs["resolvedAt"];
|
|
50867
|
+
delete attrs["resolvedReason"];
|
|
50868
|
+
}
|
|
50869
|
+
store.updateNode(w.id, { attrs, lastUpdatedAt: opts.now });
|
|
50870
|
+
for (const solId of w.fabricated) {
|
|
50871
|
+
for (const e of store.outEdges(w.id, ["SOLVED_BY"])) {
|
|
50872
|
+
if (e.to === solId) store.closeEdge(e.id, opts.now);
|
|
50873
|
+
}
|
|
50874
|
+
const sol = store.getNode(solId);
|
|
50875
|
+
if (sol?.description.startsWith(AUTO_MINT_PREFIX)) store.closeNode(solId, opts.now);
|
|
50876
|
+
}
|
|
50877
|
+
}
|
|
50878
|
+
});
|
|
50879
|
+
try {
|
|
50880
|
+
writeFileSync11(
|
|
50881
|
+
markerPath(opts.configDir),
|
|
50882
|
+
JSON.stringify({ version: BACKFILL_VERSION, at: opts.now, ...report, cloudTwins: report.cloudTwins.length }, null, 2),
|
|
50883
|
+
"utf8"
|
|
50884
|
+
);
|
|
50885
|
+
} catch {
|
|
50886
|
+
}
|
|
50887
|
+
return report;
|
|
50888
|
+
}
|
|
50889
|
+
|
|
50165
50890
|
// src/engine.ts
|
|
50166
50891
|
init_symbol_summaries();
|
|
50167
50892
|
init_reconcile();
|
|
@@ -50360,11 +51085,11 @@ init_outbox();
|
|
|
50360
51085
|
init_src8();
|
|
50361
51086
|
init_src();
|
|
50362
51087
|
init_src2();
|
|
50363
|
-
import { readFileSync as
|
|
50364
|
-
import { join as
|
|
51088
|
+
import { readFileSync as readFileSync12 } from "node:fs";
|
|
51089
|
+
import { join as join17 } from "node:path";
|
|
50365
51090
|
function loadClaimIgnorePatterns(workspaceRoot) {
|
|
50366
51091
|
try {
|
|
50367
|
-
return
|
|
51092
|
+
return readFileSync12(join17(workspaceRoot, ".errataignore"), "utf8").split(/\r?\n/).map((l) => l.trim()).filter((l) => l.length > 0 && !l.startsWith("#")).map((l) => l.toLowerCase());
|
|
50368
51093
|
} catch {
|
|
50369
51094
|
return [];
|
|
50370
51095
|
}
|
|
@@ -50496,14 +51221,16 @@ function generalizePrincipleForSync(principle, level = 2) {
|
|
|
50496
51221
|
delete node2.logicalId;
|
|
50497
51222
|
return node2;
|
|
50498
51223
|
}
|
|
50499
|
-
function buildPrincipleIngest(sharedStore, daemonVersion, ignorePatterns = [], level = 2) {
|
|
51224
|
+
function buildPrincipleIngest(sharedStore, daemonVersion, ignorePatterns = [], level = 2, opts = {}) {
|
|
51225
|
+
const lang = opts.primaryLanguage?.trim().toLowerCase();
|
|
51226
|
+
const claim = lang ? { anchorVisibility: "public", anchor: `lang:${lang}` } : {};
|
|
50500
51227
|
const selected = sharedStore.findNodesByLabel("Claim").filter((n) => isSyncablePrinciple(n, ignorePatterns));
|
|
50501
51228
|
for (const n of selected) {
|
|
50502
51229
|
if (Number(n.attrs["abstractionLevel"] ?? ABSTRACTION_LEVEL.CONCRETE) !== ABSTRACTION_LEVEL.PRINCIPLE || n.attrs["provisional"] !== false) {
|
|
50503
51230
|
throw new Error(`buildPrincipleIngest: refusing to sync non-canonical-principle ${n.id} \u2014 C7 invariant violated`);
|
|
50504
51231
|
}
|
|
50505
51232
|
}
|
|
50506
|
-
const nodes = selected.map((n) => generalizePrincipleForSync(n, level));
|
|
51233
|
+
const nodes = selected.map((n) => ({ ...generalizePrincipleForSync(n, level), ...claim }));
|
|
50507
51234
|
if (nodes.length === 0) return null;
|
|
50508
51235
|
const base = {
|
|
50509
51236
|
daemonVersion,
|
|
@@ -50556,11 +51283,17 @@ function isSyncableRoute(edge2, shared, triage, ignorePatterns = []) {
|
|
|
50556
51283
|
].join(" ").toLowerCase();
|
|
50557
51284
|
return !ignorePatterns.some((p) => blob.includes(p));
|
|
50558
51285
|
}
|
|
50559
|
-
|
|
51286
|
+
var isScopedBucket = (bucket) => bucket.startsWith("stack:@");
|
|
51287
|
+
function filterScopedBucketKeys(rec, includeScopedBuckets) {
|
|
51288
|
+
if (includeScopedBuckets) return rec;
|
|
51289
|
+
return Object.fromEntries(Object.entries(rec).filter(([k]) => !isScopedBucket(k)));
|
|
51290
|
+
}
|
|
51291
|
+
function generalizeRouteForSync(edge2, level, includeScopedBuckets = false) {
|
|
50560
51292
|
const disc = edge2.attrs["discriminator"];
|
|
50561
51293
|
const local = edge2.attrs["perContext"] ?? {};
|
|
50562
51294
|
const perContext = {};
|
|
50563
51295
|
for (const [b, c] of Object.entries(local)) {
|
|
51296
|
+
if (!includeScopedBuckets && isScopedBucket(b)) continue;
|
|
50564
51297
|
const independent = c.independent ?? c.contributors?.length;
|
|
50565
51298
|
const inferredIndependent = c.inferredIndependent ?? c.inferredContributors?.length;
|
|
50566
51299
|
perContext[b] = {
|
|
@@ -50581,11 +51314,52 @@ function generalizeRouteForSync(edge2, level) {
|
|
|
50581
51314
|
navFailures: 0
|
|
50582
51315
|
};
|
|
50583
51316
|
}
|
|
50584
|
-
function
|
|
51317
|
+
function buildBucketTokenAnchors(languages, packages = []) {
|
|
51318
|
+
const anchors = {};
|
|
51319
|
+
const langTokens = /* @__PURE__ */ new Set();
|
|
51320
|
+
for (const l of languages) {
|
|
51321
|
+
const t = canonicalizeToken(String(l));
|
|
51322
|
+
if (!t || t.includes(":") && !t.startsWith("lang:")) continue;
|
|
51323
|
+
langTokens.add(t);
|
|
51324
|
+
anchors[t] = t.startsWith("lang:") ? t : `lang:${t}`;
|
|
51325
|
+
}
|
|
51326
|
+
const versionless = (purl) => purl.replace(/@[^/@]+$/, "");
|
|
51327
|
+
const conflicted = /* @__PURE__ */ new Set();
|
|
51328
|
+
for (const p of packages) {
|
|
51329
|
+
const t = canonicalizeToken(p.name);
|
|
51330
|
+
if (!t || !p.purl || langTokens.has(t) || conflicted.has(t)) continue;
|
|
51331
|
+
const existing = anchors[t];
|
|
51332
|
+
if (existing === void 0) {
|
|
51333
|
+
anchors[t] = p.purl;
|
|
51334
|
+
} else if (versionless(existing) !== versionless(p.purl)) {
|
|
51335
|
+
delete anchors[t];
|
|
51336
|
+
conflicted.add(t);
|
|
51337
|
+
}
|
|
51338
|
+
}
|
|
51339
|
+
return anchors;
|
|
51340
|
+
}
|
|
51341
|
+
function witnessedAnchor(routes, tokenAnchors) {
|
|
51342
|
+
const weight = /* @__PURE__ */ new Map();
|
|
51343
|
+
for (const e of routes) {
|
|
51344
|
+
const perContext = e.attrs["perContext"] ?? {};
|
|
51345
|
+
for (const [bucket, c] of Object.entries(perContext)) {
|
|
51346
|
+
if (!bucket.startsWith("stack:") || !c || !(c.confirmed > 0)) continue;
|
|
51347
|
+
const anchor = tokenAnchors[bucket.slice("stack:".length)];
|
|
51348
|
+
if (anchor) weight.set(anchor, (weight.get(anchor) ?? 0) + c.confirmed);
|
|
51349
|
+
}
|
|
51350
|
+
}
|
|
51351
|
+
return [...weight.entries()].sort((a, b) => b[1] - a[1] || (a[0] < b[0] ? -1 : 1))[0]?.[0];
|
|
51352
|
+
}
|
|
51353
|
+
function buildTriageIngest(shared, daemonVersion, ignorePatterns = [], level = 2, opts = {}) {
|
|
51354
|
+
const lang = opts.primaryLanguage?.trim().toLowerCase();
|
|
51355
|
+
const fallbackAnchor = lang ? `lang:${lang}` : void 0;
|
|
51356
|
+
const tokenAnchors = opts.tokenAnchors ?? {};
|
|
51357
|
+
const includeScopedBuckets = opts.includeScopedBuckets === true;
|
|
51358
|
+
const claimOf = (anchor) => anchor ? { anchorVisibility: "public", anchor } : {};
|
|
50585
51359
|
const nodes = [];
|
|
50586
51360
|
const edges = [];
|
|
50587
51361
|
const seenIds = /* @__PURE__ */ new Set();
|
|
50588
|
-
const shareEndpoint = (id) => {
|
|
51362
|
+
const shareEndpoint = (id, anchor) => {
|
|
50589
51363
|
if (seenIds.has(id)) return;
|
|
50590
51364
|
const n = shared.getNode(id);
|
|
50591
51365
|
if (!n) return;
|
|
@@ -50594,12 +51368,14 @@ function buildTriageIngest(shared, daemonVersion, ignorePatterns = [], level = 2
|
|
|
50594
51368
|
...n,
|
|
50595
51369
|
description: generalize(n.description, { level }).text,
|
|
50596
51370
|
embedding: [],
|
|
50597
|
-
attrs: { scope: {} }
|
|
51371
|
+
attrs: { scope: {} },
|
|
51372
|
+
...claimOf(anchor ?? fallbackAnchor)
|
|
50598
51373
|
});
|
|
50599
51374
|
};
|
|
50600
51375
|
for (const tri of shared.findNodesByLabel("Triage")) {
|
|
50601
51376
|
const routes = shared.outEdges(tri.id, ["CONFIRMS", "INDICATES", "ROUTES_TO"]).filter((e) => isSyncableRoute(e, shared, tri, ignorePatterns));
|
|
50602
51377
|
if (routes.length === 0) continue;
|
|
51378
|
+
const triAnchor = witnessedAnchor(routes, tokenAnchors);
|
|
50603
51379
|
if (!seenIds.has(tri.id)) {
|
|
50604
51380
|
seenIds.add(tri.id);
|
|
50605
51381
|
const statement = String(tri.attrs["statement"] ?? "");
|
|
@@ -50609,20 +51385,26 @@ function buildTriageIngest(shared, daemonVersion, ignorePatterns = [], level = 2
|
|
|
50609
51385
|
embedding: [],
|
|
50610
51386
|
attrs: {
|
|
50611
51387
|
...statement ? { statement: generalize(statement, { level }).text } : {},
|
|
50612
|
-
...tri.attrs["perContextSeen"] ? {
|
|
50613
|
-
|
|
51388
|
+
...tri.attrs["perContextSeen"] ? {
|
|
51389
|
+
perContextSeen: filterScopedBucketKeys(
|
|
51390
|
+
tri.attrs["perContextSeen"],
|
|
51391
|
+
includeScopedBuckets
|
|
51392
|
+
)
|
|
51393
|
+
} : {}
|
|
51394
|
+
},
|
|
51395
|
+
...claimOf(triAnchor ?? fallbackAnchor)
|
|
50614
51396
|
});
|
|
50615
51397
|
}
|
|
50616
51398
|
for (const tb of shared.inEdges(tri.id, ["TRIAGED_BY"])) {
|
|
50617
|
-
shareEndpoint(tb.from);
|
|
51399
|
+
shareEndpoint(tb.from, triAnchor);
|
|
50618
51400
|
edges.push({ ...tb, navSuccesses: 0, navFailures: 0 });
|
|
50619
51401
|
}
|
|
50620
51402
|
for (const e of routes) {
|
|
50621
51403
|
if (!(e.type === "CONFIRMS" || e.type === "ROUTES_TO" && e.attrs["provisional"] === false)) {
|
|
50622
51404
|
throw new Error(`buildTriageIngest: refusing to sync non-router route ${e.id} \u2014 C7 invariant violated`);
|
|
50623
51405
|
}
|
|
50624
|
-
shareEndpoint(e.to);
|
|
50625
|
-
edges.push(generalizeRouteForSync(e, level));
|
|
51406
|
+
shareEndpoint(e.to, witnessedAnchor([e], tokenAnchors));
|
|
51407
|
+
edges.push(generalizeRouteForSync(e, level, includeScopedBuckets));
|
|
50626
51408
|
}
|
|
50627
51409
|
}
|
|
50628
51410
|
if (edges.length === 0) return null;
|
|
@@ -50668,22 +51450,22 @@ async function pullCloudTriage(shared, cloud, profile, limit = 50) {
|
|
|
50668
51450
|
}
|
|
50669
51451
|
|
|
50670
51452
|
// src/git-sensor.ts
|
|
50671
|
-
import { existsSync as
|
|
50672
|
-
import { join as
|
|
51453
|
+
import { existsSync as existsSync14, readFileSync as readFileSync13, watch as fsWatch } from "node:fs";
|
|
51454
|
+
import { join as join18 } from "node:path";
|
|
50673
51455
|
function readFirstLine(path2) {
|
|
50674
51456
|
try {
|
|
50675
|
-
return
|
|
51457
|
+
return readFileSync13(path2, "utf8").split(/\r?\n/, 1)[0].trim();
|
|
50676
51458
|
} catch {
|
|
50677
51459
|
return null;
|
|
50678
51460
|
}
|
|
50679
51461
|
}
|
|
50680
51462
|
function readGitRefState(gitDir) {
|
|
50681
|
-
const head2 = readFirstLine(
|
|
51463
|
+
const head2 = readFirstLine(join18(gitDir, "HEAD"));
|
|
50682
51464
|
const m = head2 ? /^ref:\s*refs\/heads\/(.+)$/.exec(head2) : null;
|
|
50683
51465
|
const branch = m ? m[1] : null;
|
|
50684
51466
|
let sha2 = null;
|
|
50685
51467
|
if (branch) {
|
|
50686
|
-
sha2 = readFirstLine(
|
|
51468
|
+
sha2 = readFirstLine(join18(gitDir, "refs", "heads", branch));
|
|
50687
51469
|
if (!sha2) sha2 = shaFromPackedRefs(gitDir, `refs/heads/${branch}`);
|
|
50688
51470
|
} else if (head2 && /^[0-9a-f]{7,40}$/i.test(head2)) {
|
|
50689
51471
|
sha2 = head2;
|
|
@@ -50691,13 +51473,13 @@ function readGitRefState(gitDir) {
|
|
|
50691
51473
|
return {
|
|
50692
51474
|
branch,
|
|
50693
51475
|
sha: sha2,
|
|
50694
|
-
mergeHeadExists:
|
|
50695
|
-
origHeadExists:
|
|
51476
|
+
mergeHeadExists: existsSync14(join18(gitDir, "MERGE_HEAD")),
|
|
51477
|
+
origHeadExists: existsSync14(join18(gitDir, "ORIG_HEAD"))
|
|
50696
51478
|
};
|
|
50697
51479
|
}
|
|
50698
51480
|
function shaFromPackedRefs(gitDir, ref) {
|
|
50699
51481
|
try {
|
|
50700
|
-
for (const line of
|
|
51482
|
+
for (const line of readFileSync13(join18(gitDir, "packed-refs"), "utf8").split(/\r?\n/)) {
|
|
50701
51483
|
const [sha2, name2] = line.split(/\s+/);
|
|
50702
51484
|
if (name2 === ref && sha2) return sha2;
|
|
50703
51485
|
}
|
|
@@ -50731,7 +51513,7 @@ function startGitSensor(gitDir, onEvent, opts = {}) {
|
|
|
50731
51513
|
const settle = () => {
|
|
50732
51514
|
if (timer) clearTimeout(timer);
|
|
50733
51515
|
timer = setTimeout(() => {
|
|
50734
|
-
if (
|
|
51516
|
+
if (existsSync14(join18(gitDir, "index.lock"))) {
|
|
50735
51517
|
settle();
|
|
50736
51518
|
return;
|
|
50737
51519
|
}
|
|
@@ -50742,7 +51524,7 @@ function startGitSensor(gitDir, onEvent, opts = {}) {
|
|
|
50742
51524
|
}, debounceMs);
|
|
50743
51525
|
};
|
|
50744
51526
|
for (const sub of ["HEAD", "logs/HEAD", "MERGE_HEAD", "ORIG_HEAD"]) {
|
|
50745
|
-
const p =
|
|
51527
|
+
const p = join18(gitDir, sub);
|
|
50746
51528
|
try {
|
|
50747
51529
|
watchers.push(fsWatch(p, settle));
|
|
50748
51530
|
} catch {
|
|
@@ -50967,21 +51749,21 @@ var TelemetryRecorder = class {
|
|
|
50967
51749
|
|
|
50968
51750
|
// src/skills.ts
|
|
50969
51751
|
import {
|
|
50970
|
-
existsSync as
|
|
51752
|
+
existsSync as existsSync15,
|
|
50971
51753
|
mkdirSync as mkdirSync6,
|
|
50972
|
-
readFileSync as
|
|
50973
|
-
readdirSync as
|
|
51754
|
+
readFileSync as readFileSync14,
|
|
51755
|
+
readdirSync as readdirSync7,
|
|
50974
51756
|
unlinkSync as unlinkSync2,
|
|
50975
|
-
writeFileSync as
|
|
51757
|
+
writeFileSync as writeFileSync12
|
|
50976
51758
|
} from "node:fs";
|
|
50977
|
-
import { basename as basename4, join as
|
|
51759
|
+
import { basename as basename4, join as join19 } from "node:path";
|
|
50978
51760
|
function skillFileName(id) {
|
|
50979
51761
|
return `${id.replace(/[^A-Za-z0-9_.-]/g, "_")}.md`;
|
|
50980
51762
|
}
|
|
50981
51763
|
function readSkillManifest(manifestPath) {
|
|
50982
|
-
if (!
|
|
51764
|
+
if (!existsSync15(manifestPath)) return [];
|
|
50983
51765
|
try {
|
|
50984
|
-
const parsed = JSON.parse(
|
|
51766
|
+
const parsed = JSON.parse(readFileSync14(manifestPath, "utf8"));
|
|
50985
51767
|
return (parsed.skills ?? []).map((s) => ({
|
|
50986
51768
|
title: s.title ?? "",
|
|
50987
51769
|
layer: s.layer ?? "technique",
|
|
@@ -50992,12 +51774,12 @@ function readSkillManifest(manifestPath) {
|
|
|
50992
51774
|
return [];
|
|
50993
51775
|
}
|
|
50994
51776
|
}
|
|
50995
|
-
async function syncSkills(paths, client, seed, pins = []) {
|
|
50996
|
-
const res = await client.getSkills(void 0, seed);
|
|
51777
|
+
async function syncSkills(paths, client, seed, pins = [], techSeed) {
|
|
51778
|
+
const res = await client.getSkills(void 0, seed, techSeed);
|
|
50997
51779
|
const staleDaemon = res.staleDaemon && res.latestDaemonVersion ? { latest: res.latestDaemonVersion } : void 0;
|
|
50998
51780
|
mkdirSync6(paths.skillsDir, { recursive: true });
|
|
50999
51781
|
if (res.skills.length === 0 && pins.length === 0) {
|
|
51000
|
-
const existing =
|
|
51782
|
+
const existing = readdirSync7(paths.skillsDir).filter((f) => f.endsWith(".md"));
|
|
51001
51783
|
if (existing.length > 0) return { written: 0, pruned: 0, ...staleDaemon ? { staleDaemon } : {} };
|
|
51002
51784
|
}
|
|
51003
51785
|
const rows = [];
|
|
@@ -51005,7 +51787,7 @@ async function syncSkills(paths, client, seed, pins = []) {
|
|
|
51005
51787
|
for (const s of res.skills) {
|
|
51006
51788
|
const fileName = skillFileName(s.id);
|
|
51007
51789
|
keep.add(fileName);
|
|
51008
|
-
|
|
51790
|
+
writeFileSync12(join19(paths.skillsDir, fileName), s.markdown, "utf8");
|
|
51009
51791
|
rows.push({
|
|
51010
51792
|
id: s.id,
|
|
51011
51793
|
title: s.title,
|
|
@@ -51018,7 +51800,7 @@ async function syncSkills(paths, client, seed, pins = []) {
|
|
|
51018
51800
|
const fileName = skillFileName(p.id);
|
|
51019
51801
|
if (keep.has(fileName)) continue;
|
|
51020
51802
|
keep.add(fileName);
|
|
51021
|
-
|
|
51803
|
+
writeFileSync12(join19(paths.skillsDir, fileName), p.markdown, "utf8");
|
|
51022
51804
|
rows.push({
|
|
51023
51805
|
id: p.id,
|
|
51024
51806
|
title: p.title,
|
|
@@ -51028,17 +51810,17 @@ async function syncSkills(paths, client, seed, pins = []) {
|
|
|
51028
51810
|
});
|
|
51029
51811
|
}
|
|
51030
51812
|
let pruned = 0;
|
|
51031
|
-
for (const f of
|
|
51813
|
+
for (const f of readdirSync7(paths.skillsDir)) {
|
|
51032
51814
|
if (!f.endsWith(".md")) continue;
|
|
51033
51815
|
if (keep.has(basename4(f))) continue;
|
|
51034
51816
|
try {
|
|
51035
|
-
unlinkSync2(
|
|
51817
|
+
unlinkSync2(join19(paths.skillsDir, f));
|
|
51036
51818
|
pruned++;
|
|
51037
51819
|
} catch {
|
|
51038
51820
|
}
|
|
51039
51821
|
}
|
|
51040
51822
|
rows.sort((a, b) => a.id.localeCompare(b.id));
|
|
51041
|
-
|
|
51823
|
+
writeFileSync12(
|
|
51042
51824
|
paths.skillsManifest,
|
|
51043
51825
|
JSON.stringify({ generatedAt: Date.now(), skills: rows }, null, 2),
|
|
51044
51826
|
"utf8"
|
|
@@ -51047,24 +51829,25 @@ async function syncSkills(paths, client, seed, pins = []) {
|
|
|
51047
51829
|
}
|
|
51048
51830
|
|
|
51049
51831
|
// src/agent-skills.ts
|
|
51832
|
+
init_src2();
|
|
51050
51833
|
import {
|
|
51051
51834
|
cpSync,
|
|
51052
|
-
existsSync as
|
|
51835
|
+
existsSync as existsSync16,
|
|
51053
51836
|
lstatSync,
|
|
51054
51837
|
mkdirSync as mkdirSync7,
|
|
51055
|
-
readFileSync as
|
|
51056
|
-
readdirSync as
|
|
51838
|
+
readFileSync as readFileSync15,
|
|
51839
|
+
readdirSync as readdirSync8,
|
|
51057
51840
|
rmSync as rmSync2,
|
|
51058
51841
|
symlinkSync,
|
|
51059
|
-
writeFileSync as
|
|
51842
|
+
writeFileSync as writeFileSync13
|
|
51060
51843
|
} from "node:fs";
|
|
51061
|
-
import { join as
|
|
51844
|
+
import { join as join20 } from "node:path";
|
|
51062
51845
|
var SKILL_NS = "errata-";
|
|
51063
51846
|
var HARNESS_SKILL_DIRS = [
|
|
51064
|
-
{ configDir: ".claude", skillsDir:
|
|
51847
|
+
{ configDir: ".claude", skillsDir: join20(".claude", "skills") },
|
|
51065
51848
|
// Cursor adopted the standard; its exact project dir is still moving — kept
|
|
51066
51849
|
// best-effort and gated on `.cursor/` presence so we never create it blind.
|
|
51067
|
-
{ configDir: ".cursor", skillsDir:
|
|
51850
|
+
{ configDir: ".cursor", skillsDir: join20(".cursor", "skills") }
|
|
51068
51851
|
];
|
|
51069
51852
|
function skillSlug(title, id) {
|
|
51070
51853
|
const base = title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || id.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "skill";
|
|
@@ -51079,22 +51862,42 @@ function deriveDescription(title, layer, body2) {
|
|
|
51079
51862
|
const when = ` Apply when working on ${layer === "antipattern" ? "code that risks this pitfall" : "problems in this area"}.`;
|
|
51080
51863
|
return `${lead}${lead.endsWith(".") ? "" : "."}${when}`.slice(0, 1024);
|
|
51081
51864
|
}
|
|
51082
|
-
function renderSkillMd(name2, description, body2) {
|
|
51865
|
+
function renderSkillMd(name2, description, body2, citeHandle) {
|
|
51866
|
+
const footer = citeHandle ? `
|
|
51867
|
+
|
|
51868
|
+
---
|
|
51869
|
+
When this skill actually helps you, witness it inline in your reply: \`([${citeHandle}])\` \u2014 the citation is recorded and feeds this skill's reliability, so it keeps being served. Untagged help is invisible.
|
|
51870
|
+
` : "\n";
|
|
51083
51871
|
return `---
|
|
51084
51872
|
name: ${name2}
|
|
51085
51873
|
description: ${yamlScalar(description)}
|
|
51086
51874
|
---
|
|
51087
51875
|
|
|
51088
|
-
${body2.trimEnd()}
|
|
51089
|
-
|
|
51876
|
+
${body2.trimEnd()}${footer}`;
|
|
51877
|
+
}
|
|
51878
|
+
var LAYER_TO_LABEL = {
|
|
51879
|
+
pattern: "Pattern",
|
|
51880
|
+
antipattern: "AntiPattern",
|
|
51881
|
+
technique: "Technique",
|
|
51882
|
+
weakness: "Weakness"
|
|
51883
|
+
};
|
|
51884
|
+
function skillHandleNodes(skills) {
|
|
51885
|
+
return skills.map((s) => ({
|
|
51886
|
+
id: s.id,
|
|
51887
|
+
label: LAYER_TO_LABEL[s.layer.toLowerCase()] ?? "Pattern",
|
|
51888
|
+
description: s.title
|
|
51889
|
+
}));
|
|
51890
|
+
}
|
|
51891
|
+
function skillCiteHandle(s) {
|
|
51892
|
+
return priorHandle({ id: s.id, description: s.title });
|
|
51090
51893
|
}
|
|
51091
51894
|
function reconcileNamespaced(dir, keep) {
|
|
51092
|
-
if (!
|
|
51895
|
+
if (!existsSync16(dir)) return 0;
|
|
51093
51896
|
let pruned = 0;
|
|
51094
|
-
for (const name2 of
|
|
51897
|
+
for (const name2 of readdirSync8(dir)) {
|
|
51095
51898
|
if (!name2.startsWith(SKILL_NS) || keep.has(name2)) continue;
|
|
51096
51899
|
try {
|
|
51097
|
-
rmSync2(
|
|
51900
|
+
rmSync2(join20(dir, name2), { recursive: true, force: true });
|
|
51098
51901
|
pruned++;
|
|
51099
51902
|
} catch {
|
|
51100
51903
|
}
|
|
@@ -51103,7 +51906,7 @@ function reconcileNamespaced(dir, keep) {
|
|
|
51103
51906
|
}
|
|
51104
51907
|
function linkOrCopy(linkPath, target) {
|
|
51105
51908
|
try {
|
|
51106
|
-
if (
|
|
51909
|
+
if (existsSync16(linkPath) || safeLstat(linkPath)) rmSync2(linkPath, { recursive: true, force: true });
|
|
51107
51910
|
} catch {
|
|
51108
51911
|
}
|
|
51109
51912
|
try {
|
|
@@ -51124,7 +51927,7 @@ function safeLstat(p) {
|
|
|
51124
51927
|
}
|
|
51125
51928
|
}
|
|
51126
51929
|
function emitAndProjectSkills(root, skills) {
|
|
51127
|
-
const agentsSkillsDir =
|
|
51930
|
+
const agentsSkillsDir = join20(root, ".agents", "skills");
|
|
51128
51931
|
mkdirSync7(agentsSkillsDir, { recursive: true });
|
|
51129
51932
|
const slugs = [];
|
|
51130
51933
|
const keep = /* @__PURE__ */ new Set();
|
|
@@ -51132,7 +51935,7 @@ function emitAndProjectSkills(root, skills) {
|
|
|
51132
51935
|
for (const s of skills) {
|
|
51133
51936
|
let body2;
|
|
51134
51937
|
try {
|
|
51135
|
-
body2 =
|
|
51938
|
+
body2 = readFileSync15(s.bodyPath, "utf8");
|
|
51136
51939
|
} catch {
|
|
51137
51940
|
continue;
|
|
51138
51941
|
}
|
|
@@ -51141,10 +51944,10 @@ function emitAndProjectSkills(root, skills) {
|
|
|
51141
51944
|
keep.add(slug2);
|
|
51142
51945
|
slugs.push(slug2);
|
|
51143
51946
|
const description = deriveDescription(s.title, s.layer, body2);
|
|
51144
|
-
mkdirSync7(
|
|
51145
|
-
|
|
51146
|
-
|
|
51147
|
-
renderSkillMd(slug2, description, body2),
|
|
51947
|
+
mkdirSync7(join20(agentsSkillsDir, slug2), { recursive: true });
|
|
51948
|
+
writeFileSync13(
|
|
51949
|
+
join20(agentsSkillsDir, slug2, "SKILL.md"),
|
|
51950
|
+
renderSkillMd(slug2, description, body2, skillCiteHandle(s)),
|
|
51148
51951
|
"utf8"
|
|
51149
51952
|
);
|
|
51150
51953
|
emitted++;
|
|
@@ -51152,11 +51955,11 @@ function emitAndProjectSkills(root, skills) {
|
|
|
51152
51955
|
reconcileNamespaced(agentsSkillsDir, keep);
|
|
51153
51956
|
let projected = 0;
|
|
51154
51957
|
for (const h of HARNESS_SKILL_DIRS) {
|
|
51155
|
-
if (!
|
|
51156
|
-
const dir =
|
|
51958
|
+
if (!existsSync16(join20(root, h.configDir))) continue;
|
|
51959
|
+
const dir = join20(root, h.skillsDir);
|
|
51157
51960
|
mkdirSync7(dir, { recursive: true });
|
|
51158
51961
|
for (const slug2 of slugs) {
|
|
51159
|
-
linkOrCopy(
|
|
51962
|
+
linkOrCopy(join20(dir, slug2), join20(agentsSkillsDir, slug2));
|
|
51160
51963
|
projected++;
|
|
51161
51964
|
}
|
|
51162
51965
|
reconcileNamespaced(dir, keep);
|
|
@@ -51165,15 +51968,15 @@ function emitAndProjectSkills(root, skills) {
|
|
|
51165
51968
|
return { slugs, emitted, projected };
|
|
51166
51969
|
}
|
|
51167
51970
|
function emitInputsFromManifest(erretaDir, manifestPath) {
|
|
51168
|
-
if (!
|
|
51971
|
+
if (!existsSync16(manifestPath)) return [];
|
|
51169
51972
|
try {
|
|
51170
|
-
const parsed = JSON.parse(
|
|
51973
|
+
const parsed = JSON.parse(readFileSync15(manifestPath, "utf8"));
|
|
51171
51974
|
return (parsed.skills ?? []).filter((s) => Boolean(s.id && s.file)).map((s) => ({
|
|
51172
51975
|
id: s.id,
|
|
51173
51976
|
title: s.title ?? s.id,
|
|
51174
51977
|
layer: s.layer ?? "technique",
|
|
51175
51978
|
confidence: s.confidence ?? 0,
|
|
51176
|
-
bodyPath:
|
|
51979
|
+
bodyPath: join20(erretaDir, s.file)
|
|
51177
51980
|
}));
|
|
51178
51981
|
} catch {
|
|
51179
51982
|
return [];
|
|
@@ -51187,17 +51990,17 @@ var GITIGNORE_LINES = [
|
|
|
51187
51990
|
".cursor/skills/errata-*/"
|
|
51188
51991
|
];
|
|
51189
51992
|
function ensureSkillGitignore(root) {
|
|
51190
|
-
const path2 =
|
|
51993
|
+
const path2 = join20(root, ".gitignore");
|
|
51191
51994
|
let current = "";
|
|
51192
51995
|
try {
|
|
51193
|
-
current =
|
|
51996
|
+
current = existsSync16(path2) ? readFileSync15(path2, "utf8") : "";
|
|
51194
51997
|
} catch {
|
|
51195
51998
|
return;
|
|
51196
51999
|
}
|
|
51197
52000
|
if (current.includes(GITIGNORE_MARK)) return;
|
|
51198
52001
|
const prefix = current.length > 0 && !current.endsWith("\n") ? "\n" : "";
|
|
51199
52002
|
try {
|
|
51200
|
-
|
|
52003
|
+
writeFileSync13(path2, `${current}${prefix}
|
|
51201
52004
|
${GITIGNORE_LINES.join("\n")}
|
|
51202
52005
|
`, "utf8");
|
|
51203
52006
|
} catch {
|
|
@@ -51255,6 +52058,203 @@ function createToolRunState() {
|
|
|
51255
52058
|
// src/engine.ts
|
|
51256
52059
|
init_paths();
|
|
51257
52060
|
|
|
52061
|
+
// src/profile.ts
|
|
52062
|
+
init_src2();
|
|
52063
|
+
init_paths();
|
|
52064
|
+
import { existsSync as existsSync18, readFileSync as readFileSync17, writeFileSync as writeFileSync14 } from "node:fs";
|
|
52065
|
+
import { createHash as createHash12 } from "node:crypto";
|
|
52066
|
+
import { join as join22 } from "node:path";
|
|
52067
|
+
|
|
52068
|
+
// src/git-remote.ts
|
|
52069
|
+
init_src();
|
|
52070
|
+
import { existsSync as existsSync17, readFileSync as readFileSync16, statSync as statSync4 } from "node:fs";
|
|
52071
|
+
import { isAbsolute as isAbsolute3, join as join21, resolve as resolve5 } from "node:path";
|
|
52072
|
+
function resolveGitDir(root) {
|
|
52073
|
+
const dotGit = join21(root, ".git");
|
|
52074
|
+
try {
|
|
52075
|
+
const st = statSync4(dotGit);
|
|
52076
|
+
if (st.isDirectory()) return dotGit;
|
|
52077
|
+
const m = /^gitdir:\s*(.+?)\s*$/m.exec(readFileSync16(dotGit, "utf8"));
|
|
52078
|
+
if (!m) return null;
|
|
52079
|
+
const dir = m[1];
|
|
52080
|
+
return isAbsolute3(dir) ? dir : resolve5(root, dir);
|
|
52081
|
+
} catch {
|
|
52082
|
+
return null;
|
|
52083
|
+
}
|
|
52084
|
+
}
|
|
52085
|
+
function gitConfigPath(gitDir) {
|
|
52086
|
+
const commondirFile = join21(gitDir, "commondir");
|
|
52087
|
+
if (existsSync17(commondirFile)) {
|
|
52088
|
+
const common = readFileSync16(commondirFile, "utf8").trim();
|
|
52089
|
+
const commonDir = isAbsolute3(common) ? common : resolve5(gitDir, common);
|
|
52090
|
+
return join21(commonDir, "config");
|
|
52091
|
+
}
|
|
52092
|
+
return join21(gitDir, "config");
|
|
52093
|
+
}
|
|
52094
|
+
function readRemotes(root) {
|
|
52095
|
+
const gitDir = resolveGitDir(root);
|
|
52096
|
+
if (!gitDir) return [];
|
|
52097
|
+
const cfgPath = gitConfigPath(gitDir);
|
|
52098
|
+
if (!existsSync17(cfgPath)) return [];
|
|
52099
|
+
let txt;
|
|
52100
|
+
try {
|
|
52101
|
+
txt = readFileSync16(cfgPath, "utf8");
|
|
52102
|
+
} catch {
|
|
52103
|
+
return [];
|
|
52104
|
+
}
|
|
52105
|
+
const out2 = [];
|
|
52106
|
+
const sectionRe = /^\s*\[remote "([^"]+)"\]\s*$([\s\S]*?)(?=^\s*\[|\s*$(?![\s\S]))/gm;
|
|
52107
|
+
for (const m of txt.matchAll(sectionRe)) {
|
|
52108
|
+
const url2 = /^\s*url\s*=\s*(.+?)\s*$/m.exec(m[2])?.[1];
|
|
52109
|
+
if (url2) out2.push({ name: m[1], url: url2 });
|
|
52110
|
+
}
|
|
52111
|
+
return out2;
|
|
52112
|
+
}
|
|
52113
|
+
function detectRepoLocator(root, remote) {
|
|
52114
|
+
const remotes = readRemotes(root);
|
|
52115
|
+
if (remotes.length === 0) return null;
|
|
52116
|
+
const pick2 = remote ? remotes.find((r) => r.name === remote) ?? null : remotes.find((r) => r.name === "origin") ?? (remotes.length === 1 ? remotes[0] : null);
|
|
52117
|
+
return pick2 ? normalizeRepoLocator(pick2.url) : null;
|
|
52118
|
+
}
|
|
52119
|
+
|
|
52120
|
+
// src/profile.ts
|
|
52121
|
+
function workspaceId(root) {
|
|
52122
|
+
return "wp_" + createHash12("sha256").update(root).digest("hex").slice(0, 12);
|
|
52123
|
+
}
|
|
52124
|
+
function sessionOriginKey(sessionId) {
|
|
52125
|
+
if (!sessionId) return void 0;
|
|
52126
|
+
return "ws_" + createHash12("sha256").update(sessionId).digest("hex").slice(0, 12);
|
|
52127
|
+
}
|
|
52128
|
+
function refreshRepoLocator(root, profile) {
|
|
52129
|
+
const detected = detectRepoLocator(root, profile.repoRemote);
|
|
52130
|
+
if (!detected || detected === profile.repoLocator) return false;
|
|
52131
|
+
profile.repoLocator = detected;
|
|
52132
|
+
saveProfile(root, profile);
|
|
52133
|
+
return true;
|
|
52134
|
+
}
|
|
52135
|
+
function loadProfile(root) {
|
|
52136
|
+
const p = workspacePaths(root);
|
|
52137
|
+
if (!existsSync18(p.workspaceJson)) return null;
|
|
52138
|
+
return JSON.parse(readFileSync17(p.workspaceJson, "utf8"));
|
|
52139
|
+
}
|
|
52140
|
+
function saveProfile(root, profile) {
|
|
52141
|
+
const p = workspacePaths(root);
|
|
52142
|
+
ensureDir(p.configDir);
|
|
52143
|
+
writeFileSync14(p.workspaceJson, JSON.stringify(profile, null, 2), "utf8");
|
|
52144
|
+
}
|
|
52145
|
+
function autodetectProfile(root) {
|
|
52146
|
+
const id = workspaceId(root);
|
|
52147
|
+
const name2 = root.split(/[\\/]/).filter(Boolean).pop() ?? "workspace";
|
|
52148
|
+
const p = emptyProfile(id, name2);
|
|
52149
|
+
const locator = detectRepoLocator(root);
|
|
52150
|
+
if (locator) p.repoLocator = locator;
|
|
52151
|
+
const pkgPath = join22(root, "package.json");
|
|
52152
|
+
if (existsSync18(pkgPath)) {
|
|
52153
|
+
try {
|
|
52154
|
+
const pkg = JSON.parse(readFileSync17(pkgPath, "utf8"));
|
|
52155
|
+
p.languages.push("typescript", "javascript");
|
|
52156
|
+
const nodeVer = pkg.engines?.node ?? "node";
|
|
52157
|
+
p.stack.push(`node@${nodeVer}`);
|
|
52158
|
+
const deps = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
|
|
52159
|
+
const interesting = [
|
|
52160
|
+
"next",
|
|
52161
|
+
"react",
|
|
52162
|
+
"vue",
|
|
52163
|
+
"svelte",
|
|
52164
|
+
"express",
|
|
52165
|
+
"hono",
|
|
52166
|
+
"fastify",
|
|
52167
|
+
"@modelcontextprotocol/sdk"
|
|
52168
|
+
];
|
|
52169
|
+
for (const k of interesting) {
|
|
52170
|
+
if (deps[k]) p.stack.push(k);
|
|
52171
|
+
}
|
|
52172
|
+
} catch {
|
|
52173
|
+
}
|
|
52174
|
+
}
|
|
52175
|
+
const pyproject = join22(root, "pyproject.toml");
|
|
52176
|
+
if (existsSync18(pyproject)) {
|
|
52177
|
+
try {
|
|
52178
|
+
const txt = readFileSync17(pyproject, "utf8");
|
|
52179
|
+
const py = /python\s*=\s*"([^"]+)"/.exec(txt)?.[1];
|
|
52180
|
+
p.languages.push("python");
|
|
52181
|
+
p.stack.push(`python@${py ?? "3"}`);
|
|
52182
|
+
const candidates = ["fastapi", "django", "flask", "mcp", "pytest"];
|
|
52183
|
+
for (const k of candidates) {
|
|
52184
|
+
if (new RegExp(`\\b${k}\\b`, "i").test(txt)) p.stack.push(k);
|
|
52185
|
+
}
|
|
52186
|
+
} catch {
|
|
52187
|
+
}
|
|
52188
|
+
}
|
|
52189
|
+
const reqs = join22(root, "requirements.txt");
|
|
52190
|
+
if (existsSync18(reqs)) {
|
|
52191
|
+
if (!p.languages.includes("python")) p.languages.push("python");
|
|
52192
|
+
if (!p.stack.includes("python@3")) p.stack.push("python@3");
|
|
52193
|
+
}
|
|
52194
|
+
if (existsSync18(join22(root, "go.mod"))) {
|
|
52195
|
+
p.languages.push("go");
|
|
52196
|
+
p.stack.push("go");
|
|
52197
|
+
}
|
|
52198
|
+
if (existsSync18(join22(root, "Cargo.toml"))) {
|
|
52199
|
+
p.languages.push("rust");
|
|
52200
|
+
p.stack.push("rust");
|
|
52201
|
+
}
|
|
52202
|
+
p.languages = [...new Set(p.languages)];
|
|
52203
|
+
p.stack = [...new Set(p.stack)];
|
|
52204
|
+
return p;
|
|
52205
|
+
}
|
|
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
|
+
|
|
51258
52258
|
// src/causal.ts
|
|
51259
52259
|
var SUPPRESSORS = [
|
|
51260
52260
|
{ kind: "ts-nocheck", re: /@ts-nocheck\b/g },
|
|
@@ -51358,148 +52358,6 @@ var CausalBuffer = class {
|
|
|
51358
52358
|
}
|
|
51359
52359
|
};
|
|
51360
52360
|
|
|
51361
|
-
// src/profile.ts
|
|
51362
|
-
init_src2();
|
|
51363
|
-
init_paths();
|
|
51364
|
-
import { existsSync as existsSync17, readFileSync as readFileSync16, writeFileSync as writeFileSync13 } from "node:fs";
|
|
51365
|
-
import { createHash as createHash12 } from "node:crypto";
|
|
51366
|
-
import { join as join21 } from "node:path";
|
|
51367
|
-
|
|
51368
|
-
// src/git-remote.ts
|
|
51369
|
-
init_src();
|
|
51370
|
-
import { existsSync as existsSync16, readFileSync as readFileSync15, statSync as statSync4 } from "node:fs";
|
|
51371
|
-
import { isAbsolute as isAbsolute3, join as join20, resolve as resolve5 } from "node:path";
|
|
51372
|
-
function resolveGitDir(root) {
|
|
51373
|
-
const dotGit = join20(root, ".git");
|
|
51374
|
-
try {
|
|
51375
|
-
const st = statSync4(dotGit);
|
|
51376
|
-
if (st.isDirectory()) return dotGit;
|
|
51377
|
-
const m = /^gitdir:\s*(.+?)\s*$/m.exec(readFileSync15(dotGit, "utf8"));
|
|
51378
|
-
if (!m) return null;
|
|
51379
|
-
const dir = m[1];
|
|
51380
|
-
return isAbsolute3(dir) ? dir : resolve5(root, dir);
|
|
51381
|
-
} catch {
|
|
51382
|
-
return null;
|
|
51383
|
-
}
|
|
51384
|
-
}
|
|
51385
|
-
function gitConfigPath(gitDir) {
|
|
51386
|
-
const commondirFile = join20(gitDir, "commondir");
|
|
51387
|
-
if (existsSync16(commondirFile)) {
|
|
51388
|
-
const common = readFileSync15(commondirFile, "utf8").trim();
|
|
51389
|
-
const commonDir = isAbsolute3(common) ? common : resolve5(gitDir, common);
|
|
51390
|
-
return join20(commonDir, "config");
|
|
51391
|
-
}
|
|
51392
|
-
return join20(gitDir, "config");
|
|
51393
|
-
}
|
|
51394
|
-
function readRemotes(root) {
|
|
51395
|
-
const gitDir = resolveGitDir(root);
|
|
51396
|
-
if (!gitDir) return [];
|
|
51397
|
-
const cfgPath = gitConfigPath(gitDir);
|
|
51398
|
-
if (!existsSync16(cfgPath)) return [];
|
|
51399
|
-
let txt;
|
|
51400
|
-
try {
|
|
51401
|
-
txt = readFileSync15(cfgPath, "utf8");
|
|
51402
|
-
} catch {
|
|
51403
|
-
return [];
|
|
51404
|
-
}
|
|
51405
|
-
const out2 = [];
|
|
51406
|
-
const sectionRe = /^\s*\[remote "([^"]+)"\]\s*$([\s\S]*?)(?=^\s*\[|\s*$(?![\s\S]))/gm;
|
|
51407
|
-
for (const m of txt.matchAll(sectionRe)) {
|
|
51408
|
-
const url2 = /^\s*url\s*=\s*(.+?)\s*$/m.exec(m[2])?.[1];
|
|
51409
|
-
if (url2) out2.push({ name: m[1], url: url2 });
|
|
51410
|
-
}
|
|
51411
|
-
return out2;
|
|
51412
|
-
}
|
|
51413
|
-
function detectRepoLocator(root, remote) {
|
|
51414
|
-
const remotes = readRemotes(root);
|
|
51415
|
-
if (remotes.length === 0) return null;
|
|
51416
|
-
const pick2 = remote ? remotes.find((r) => r.name === remote) ?? null : remotes.find((r) => r.name === "origin") ?? (remotes.length === 1 ? remotes[0] : null);
|
|
51417
|
-
return pick2 ? normalizeRepoLocator(pick2.url) : null;
|
|
51418
|
-
}
|
|
51419
|
-
|
|
51420
|
-
// src/profile.ts
|
|
51421
|
-
function workspaceId(root) {
|
|
51422
|
-
return "wp_" + createHash12("sha256").update(root).digest("hex").slice(0, 12);
|
|
51423
|
-
}
|
|
51424
|
-
function refreshRepoLocator(root, profile) {
|
|
51425
|
-
const detected = detectRepoLocator(root, profile.repoRemote);
|
|
51426
|
-
if (!detected || detected === profile.repoLocator) return false;
|
|
51427
|
-
profile.repoLocator = detected;
|
|
51428
|
-
saveProfile(root, profile);
|
|
51429
|
-
return true;
|
|
51430
|
-
}
|
|
51431
|
-
function loadProfile(root) {
|
|
51432
|
-
const p = workspacePaths(root);
|
|
51433
|
-
if (!existsSync17(p.workspaceJson)) return null;
|
|
51434
|
-
return JSON.parse(readFileSync16(p.workspaceJson, "utf8"));
|
|
51435
|
-
}
|
|
51436
|
-
function saveProfile(root, profile) {
|
|
51437
|
-
const p = workspacePaths(root);
|
|
51438
|
-
ensureDir(p.configDir);
|
|
51439
|
-
writeFileSync13(p.workspaceJson, JSON.stringify(profile, null, 2), "utf8");
|
|
51440
|
-
}
|
|
51441
|
-
function autodetectProfile(root) {
|
|
51442
|
-
const id = workspaceId(root);
|
|
51443
|
-
const name2 = root.split(/[\\/]/).filter(Boolean).pop() ?? "workspace";
|
|
51444
|
-
const p = emptyProfile(id, name2);
|
|
51445
|
-
const locator = detectRepoLocator(root);
|
|
51446
|
-
if (locator) p.repoLocator = locator;
|
|
51447
|
-
const pkgPath = join21(root, "package.json");
|
|
51448
|
-
if (existsSync17(pkgPath)) {
|
|
51449
|
-
try {
|
|
51450
|
-
const pkg = JSON.parse(readFileSync16(pkgPath, "utf8"));
|
|
51451
|
-
p.languages.push("typescript", "javascript");
|
|
51452
|
-
const nodeVer = pkg.engines?.node ?? "node";
|
|
51453
|
-
p.stack.push(`node@${nodeVer}`);
|
|
51454
|
-
const deps = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
|
|
51455
|
-
const interesting = [
|
|
51456
|
-
"next",
|
|
51457
|
-
"react",
|
|
51458
|
-
"vue",
|
|
51459
|
-
"svelte",
|
|
51460
|
-
"express",
|
|
51461
|
-
"hono",
|
|
51462
|
-
"fastify",
|
|
51463
|
-
"@modelcontextprotocol/sdk"
|
|
51464
|
-
];
|
|
51465
|
-
for (const k of interesting) {
|
|
51466
|
-
if (deps[k]) p.stack.push(k);
|
|
51467
|
-
}
|
|
51468
|
-
} catch {
|
|
51469
|
-
}
|
|
51470
|
-
}
|
|
51471
|
-
const pyproject = join21(root, "pyproject.toml");
|
|
51472
|
-
if (existsSync17(pyproject)) {
|
|
51473
|
-
try {
|
|
51474
|
-
const txt = readFileSync16(pyproject, "utf8");
|
|
51475
|
-
const py = /python\s*=\s*"([^"]+)"/.exec(txt)?.[1];
|
|
51476
|
-
p.languages.push("python");
|
|
51477
|
-
p.stack.push(`python@${py ?? "3"}`);
|
|
51478
|
-
const candidates = ["fastapi", "django", "flask", "mcp", "pytest"];
|
|
51479
|
-
for (const k of candidates) {
|
|
51480
|
-
if (new RegExp(`\\b${k}\\b`, "i").test(txt)) p.stack.push(k);
|
|
51481
|
-
}
|
|
51482
|
-
} catch {
|
|
51483
|
-
}
|
|
51484
|
-
}
|
|
51485
|
-
const reqs = join21(root, "requirements.txt");
|
|
51486
|
-
if (existsSync17(reqs)) {
|
|
51487
|
-
if (!p.languages.includes("python")) p.languages.push("python");
|
|
51488
|
-
if (!p.stack.includes("python@3")) p.stack.push("python@3");
|
|
51489
|
-
}
|
|
51490
|
-
if (existsSync17(join21(root, "go.mod"))) {
|
|
51491
|
-
p.languages.push("go");
|
|
51492
|
-
p.stack.push("go");
|
|
51493
|
-
}
|
|
51494
|
-
if (existsSync17(join21(root, "Cargo.toml"))) {
|
|
51495
|
-
p.languages.push("rust");
|
|
51496
|
-
p.stack.push("rust");
|
|
51497
|
-
}
|
|
51498
|
-
p.languages = [...new Set(p.languages)];
|
|
51499
|
-
p.stack = [...new Set(p.stack)];
|
|
51500
|
-
return p;
|
|
51501
|
-
}
|
|
51502
|
-
|
|
51503
52361
|
// src/engine.ts
|
|
51504
52362
|
init_config();
|
|
51505
52363
|
init_cloud_auth();
|
|
@@ -51649,7 +52507,7 @@ function startLoopLagMonitor(thresholdMs = 1e3) {
|
|
|
51649
52507
|
}
|
|
51650
52508
|
|
|
51651
52509
|
// src/engine.ts
|
|
51652
|
-
var DAEMON_VERSION = true ? "2.0.
|
|
52510
|
+
var DAEMON_VERSION = true ? "2.0.2-dev.133" : "2.0.0-alpha.0";
|
|
51653
52511
|
var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
|
|
51654
52512
|
var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
|
|
51655
52513
|
var GIT_OP_MUTE_MS = 4e3;
|
|
@@ -51659,8 +52517,8 @@ var TURN_REPLAY_LOOKBACK_MS = 7 * 24 * 60 * 6e4;
|
|
|
51659
52517
|
function appendIdentityAudit(path2, record2, line) {
|
|
51660
52518
|
if (!record2.accepted && record2.score <= 0) return;
|
|
51661
52519
|
try {
|
|
51662
|
-
if (
|
|
51663
|
-
|
|
52520
|
+
if (existsSync19(path2) && statSync5(path2).size >= IDENTITY_AUDIT_MAX_BYTES) {
|
|
52521
|
+
renameSync3(path2, `${path2}.1`);
|
|
51664
52522
|
}
|
|
51665
52523
|
appendFileSync2(path2, line);
|
|
51666
52524
|
} catch {
|
|
@@ -51669,14 +52527,33 @@ function appendIdentityAudit(path2, record2, line) {
|
|
|
51669
52527
|
var yieldToLoop = () => new Promise((r) => setImmediate(r));
|
|
51670
52528
|
function loadTurnCursors(path2) {
|
|
51671
52529
|
try {
|
|
51672
|
-
|
|
52530
|
+
const raw2 = JSON.parse(readFileSync19(path2, "utf8"));
|
|
52531
|
+
return new Map(
|
|
52532
|
+
Object.entries(raw2).map(([k, v]) => [k, typeof v === "string" ? v : String(v?.uuid ?? "")])
|
|
52533
|
+
);
|
|
52534
|
+
} catch {
|
|
52535
|
+
return /* @__PURE__ */ new Map();
|
|
52536
|
+
}
|
|
52537
|
+
}
|
|
52538
|
+
function loadTurnOffsets(path2) {
|
|
52539
|
+
try {
|
|
52540
|
+
const raw2 = JSON.parse(readFileSync19(path2, "utf8"));
|
|
52541
|
+
const out2 = /* @__PURE__ */ new Map();
|
|
52542
|
+
for (const [k, v] of Object.entries(raw2)) {
|
|
52543
|
+
const off = typeof v === "object" && v !== null ? v.offset : void 0;
|
|
52544
|
+
if (typeof off === "number" && off >= 0) out2.set(k, off);
|
|
52545
|
+
}
|
|
52546
|
+
return out2;
|
|
51673
52547
|
} catch {
|
|
51674
52548
|
return /* @__PURE__ */ new Map();
|
|
51675
52549
|
}
|
|
51676
52550
|
}
|
|
51677
|
-
function saveTurnCursors(path2, cursors) {
|
|
52551
|
+
function saveTurnCursors(path2, cursors, offsets) {
|
|
51678
52552
|
try {
|
|
51679
|
-
|
|
52553
|
+
const merged = {};
|
|
52554
|
+
for (const [k, uuid3] of cursors) merged[k] = { uuid: uuid3, offset: offsets.get(k) ?? 0 };
|
|
52555
|
+
for (const [k, offset] of offsets) if (!merged[k]) merged[k] = { uuid: "", offset };
|
|
52556
|
+
writeFileSync16(path2, JSON.stringify(merged), "utf8");
|
|
51680
52557
|
} catch {
|
|
51681
52558
|
}
|
|
51682
52559
|
}
|
|
@@ -51698,7 +52575,7 @@ function gitSourceWatchTargets(root) {
|
|
|
51698
52575
|
["-C", root, "ls-files", "--others", "--ignored", "--exclude-standard", "--directory", "-z"],
|
|
51699
52576
|
{ encoding: "utf8", maxBuffer: 256 * 1024 * 1024, windowsHide: true, stdio: ["ignore", "pipe", "ignore"] }
|
|
51700
52577
|
);
|
|
51701
|
-
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));
|
|
51702
52579
|
} catch {
|
|
51703
52580
|
}
|
|
51704
52581
|
const hasIgnoredChild = (dir) => ignoredDirs.some((ig) => ig.startsWith(dir + "/"));
|
|
@@ -51710,19 +52587,19 @@ function gitSourceWatchTargets(root) {
|
|
|
51710
52587
|
if (!f.startsWith(prefix)) continue;
|
|
51711
52588
|
const rest2 = f.slice(prefix.length);
|
|
51712
52589
|
if (rest2.includes("/")) children.add(dir === "" ? rest2.slice(0, rest2.indexOf("/")) : dir + "/" + rest2.slice(0, rest2.indexOf("/")));
|
|
51713
|
-
else targets.add(
|
|
52590
|
+
else targets.add(join24(root, f));
|
|
51714
52591
|
}
|
|
51715
52592
|
for (const c of children) {
|
|
51716
|
-
if (IGNORED_PATH.test(
|
|
52593
|
+
if (IGNORED_PATH.test(join24(root, c) + sep4)) continue;
|
|
51717
52594
|
if (hasIgnoredChild(c)) addUnder(c);
|
|
51718
|
-
else targets.add(
|
|
52595
|
+
else targets.add(join24(root, c));
|
|
51719
52596
|
}
|
|
51720
52597
|
};
|
|
51721
52598
|
addUnder("");
|
|
51722
52599
|
if (targets.size > 0) return [...targets];
|
|
51723
52600
|
} catch {
|
|
51724
52601
|
}
|
|
51725
|
-
return
|
|
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)));
|
|
51726
52603
|
}
|
|
51727
52604
|
function createWorkspaceEngine(opts) {
|
|
51728
52605
|
const paths = workspacePaths(opts.workspaceRoot);
|
|
@@ -51737,6 +52614,10 @@ function createWorkspaceEngine(opts) {
|
|
|
51737
52614
|
refreshRepoLocator(opts.workspaceRoot, profile);
|
|
51738
52615
|
}
|
|
51739
52616
|
const store = openGraphStore({ path: paths.castalia });
|
|
52617
|
+
let witnessQueue = pruneWitnessQueue(
|
|
52618
|
+
loadWitnessQueue(witnessQueuePath(paths.configDir)),
|
|
52619
|
+
Date.now()
|
|
52620
|
+
);
|
|
51740
52621
|
const log = openEventLog({ path: paths.eventLog });
|
|
51741
52622
|
const bundled = import.meta.url.endsWith(".mjs");
|
|
51742
52623
|
const passWorker = bundled && paths.castalia !== ":memory:" ? new PassWorker({
|
|
@@ -51876,7 +52757,7 @@ function createWorkspaceEngine(opts) {
|
|
|
51876
52757
|
const srcPaths = diff.changedPaths.filter((p) => /\.(ts|tsx|js|jsx|mjs|cjs|py)$/i.test(p));
|
|
51877
52758
|
let episodeId2;
|
|
51878
52759
|
if (srcPaths.length > 0) {
|
|
51879
|
-
const abs = srcPaths.map((p) =>
|
|
52760
|
+
const abs = srcPaths.map((p) => join24(opts.workspaceRoot, p));
|
|
51880
52761
|
try {
|
|
51881
52762
|
const r = await runReindexPass(
|
|
51882
52763
|
`git-reindex:${profile.name} (${abs.length} files)`,
|
|
@@ -51912,8 +52793,8 @@ function createWorkspaceEngine(opts) {
|
|
|
51912
52793
|
`[errata] git: ${ev.kind} ${ev.newSha.slice(0, 7)} by ${meta3.authorName} \u2014 ${diff.changedPaths.length} file(s), ${diff.renames.length} rename(s)`
|
|
51913
52794
|
);
|
|
51914
52795
|
};
|
|
51915
|
-
const gitDir =
|
|
51916
|
-
if (
|
|
52796
|
+
const gitDir = join24(opts.workspaceRoot, ".git");
|
|
52797
|
+
if (existsSync19(gitDir)) {
|
|
51917
52798
|
stopGit = startGitSensor(gitDir, (ev) => {
|
|
51918
52799
|
void handleGitEvent(ev).catch((err2) => {
|
|
51919
52800
|
console.warn("[errata] git event handler failed:", err2);
|
|
@@ -51983,10 +52864,10 @@ function createWorkspaceEngine(opts) {
|
|
|
51983
52864
|
});
|
|
51984
52865
|
doneRender?.();
|
|
51985
52866
|
writeContextFile(opts.workspaceRoot, body2);
|
|
51986
|
-
const target =
|
|
52867
|
+
const target = join24(opts.workspaceRoot, "AGENTS.md");
|
|
51987
52868
|
writeManagedBlock(target, { body: AGENTS_POINTER_BODY, stable: true, force: true });
|
|
51988
52869
|
if (elicit) {
|
|
51989
|
-
writePrimingHandles(
|
|
52870
|
+
writePrimingHandles(join24(paths.configDir, "priming-handles.json"), [
|
|
51990
52871
|
...snapshot.recentProblems.map((r) => r.node),
|
|
51991
52872
|
// Resolved-band handles: the ✓ problem AND its Solution are citable
|
|
51992
52873
|
// (a fix tag on an already-resolved problem no-ops idempotently; the
|
|
@@ -52077,6 +52958,21 @@ function createWorkspaceEngine(opts) {
|
|
|
52077
52958
|
} catch (err2) {
|
|
52078
52959
|
console.warn("[errata] anchor backfill failed:", err2);
|
|
52079
52960
|
}
|
|
52961
|
+
try {
|
|
52962
|
+
const c = backfillConstraintKind(store, {
|
|
52963
|
+
root: opts.workspaceRoot,
|
|
52964
|
+
configDir: paths.configDir,
|
|
52965
|
+
now: Date.now()
|
|
52966
|
+
});
|
|
52967
|
+
if (!c.skipped && (c.stamped > 0 || c.detached > 0)) {
|
|
52968
|
+
console.log(
|
|
52969
|
+
`[errata] constraint backfill: ${c.stamped} design tension(s) marked` + (c.detached > 0 ? `; ${c.detached} fabricated resolution(s) detached, ${c.reopened} reopened` : "") + (c.witnessed > 0 ? `; ${c.witnessed} cited discharge(s) kept` : "") + (c.cloudTwins.length > 0 ? ` \u2014 ${c.cloudTwins.length} already contributed; run scripts/repair-cloud-constraints.ts to repair the cloud twins` : "")
|
|
52970
|
+
);
|
|
52971
|
+
refreshContextNow();
|
|
52972
|
+
}
|
|
52973
|
+
} catch (err2) {
|
|
52974
|
+
console.warn("[errata] constraint backfill failed:", err2);
|
|
52975
|
+
}
|
|
52080
52976
|
const report = runNightlyPipeline(store);
|
|
52081
52977
|
try {
|
|
52082
52978
|
const m = mergeDuplicateProblems(store, { ts: Date.now() });
|
|
@@ -52176,8 +53072,9 @@ function createWorkspaceEngine(opts) {
|
|
|
52176
53072
|
resultSummary: { exitCode: e.exitCode ?? 1, errorTokens: e.errorTokens }
|
|
52177
53073
|
});
|
|
52178
53074
|
};
|
|
52179
|
-
const turnCursorPath =
|
|
53075
|
+
const turnCursorPath = join24(paths.configDir, "turn-cursors.json");
|
|
52180
53076
|
const lastTurnUuid = loadTurnCursors(turnCursorPath);
|
|
53077
|
+
const turnOffset = loadTurnOffsets(turnCursorPath);
|
|
52181
53078
|
const sessionLastProblem = /* @__PURE__ */ new Map();
|
|
52182
53079
|
const sessionThreads = /* @__PURE__ */ new Map();
|
|
52183
53080
|
const harvestTexts = async (sessionId, items) => {
|
|
@@ -52199,7 +53096,7 @@ function createWorkspaceEngine(opts) {
|
|
|
52199
53096
|
const t = Date.now();
|
|
52200
53097
|
let processedTurns = 0;
|
|
52201
53098
|
const elicit = isEdgeElicitationEnabled();
|
|
52202
|
-
const handleMap = elicit ? readPrimingHandles(
|
|
53099
|
+
const handleMap = elicit ? readPrimingHandles(join24(paths.configDir, "priming-handles.json")) : {};
|
|
52203
53100
|
const wsRoot = (opts.workspaceRoot ?? "").replace(/\\/g, "/");
|
|
52204
53101
|
const toRel = (abs) => {
|
|
52205
53102
|
const p = abs.replace(/\\/g, "/");
|
|
@@ -52241,7 +53138,7 @@ function createWorkspaceEngine(opts) {
|
|
|
52241
53138
|
ts: t
|
|
52242
53139
|
});
|
|
52243
53140
|
if (r.created || r.corroborated) minted++;
|
|
52244
|
-
sessionLastProblem.set(sessionId, designProblemId(flag.problem));
|
|
53141
|
+
if (flag.kind !== "constraint") sessionLastProblem.set(sessionId, designProblemId(flag.problem));
|
|
52245
53142
|
if (r.created || r.corroborated) {
|
|
52246
53143
|
try {
|
|
52247
53144
|
if (editedTurnFile) {
|
|
@@ -52321,11 +53218,13 @@ function createWorkspaceEngine(opts) {
|
|
|
52321
53218
|
const dedupPath = anchorPath ?? hintPath;
|
|
52322
53219
|
if (dedupPath) {
|
|
52323
53220
|
try {
|
|
52324
|
-
const dupId = reinforceSameAnchorProblem(store, dedupPath, profile.id, p.statement, sessionId, t);
|
|
53221
|
+
const dupId = reinforceSameAnchorProblem(store, dedupPath, profile.id, p.statement, sessionId, t, p.kind);
|
|
52325
53222
|
if (dupId) {
|
|
52326
53223
|
minted++;
|
|
52327
|
-
|
|
52328
|
-
|
|
53224
|
+
if (p.kind !== "constraint") {
|
|
53225
|
+
sessionLastProblem.set(sessionId, dupId);
|
|
53226
|
+
inScopeProblemId = dupId;
|
|
53227
|
+
}
|
|
52329
53228
|
if (p.threadId) threads.set(p.threadId, dupId);
|
|
52330
53229
|
continue;
|
|
52331
53230
|
}
|
|
@@ -52339,8 +53238,10 @@ function createWorkspaceEngine(opts) {
|
|
|
52339
53238
|
});
|
|
52340
53239
|
if (r.created || r.corroborated) {
|
|
52341
53240
|
minted++;
|
|
52342
|
-
|
|
52343
|
-
|
|
53241
|
+
if (p.kind !== "constraint") {
|
|
53242
|
+
sessionLastProblem.set(sessionId, designProblemId(p.statement));
|
|
53243
|
+
inScopeProblemId = designProblemId(p.statement);
|
|
53244
|
+
}
|
|
52344
53245
|
if (p.threadId) threads.set(p.threadId, designProblemId(p.statement));
|
|
52345
53246
|
try {
|
|
52346
53247
|
if (anchorPath) {
|
|
@@ -52483,6 +53384,20 @@ function createWorkspaceEngine(opts) {
|
|
|
52483
53384
|
if (domainId === pid) continue;
|
|
52484
53385
|
mintCiteEdge(pid, domainId, "PERTAIN_TO", d.evidence === "witnessed" ? 0.4 : 0.3, { domainCite: true, evidence: d.evidence });
|
|
52485
53386
|
}
|
|
53387
|
+
for (const p of plan.packages) {
|
|
53388
|
+
const pid = bindPid(p);
|
|
53389
|
+
if (!pid) continue;
|
|
53390
|
+
const pkgId = mintCitedPackageNode(store, p.packageText, t);
|
|
53391
|
+
if (pkgId === pid) continue;
|
|
53392
|
+
mintCiteEdge(pid, pkgId, "DEPENDS_ON", p.evidence === "witnessed" ? 0.4 : 0.3, { packageCite: true, evidence: p.evidence });
|
|
53393
|
+
}
|
|
53394
|
+
for (const cpt of plan.components) {
|
|
53395
|
+
const pid = bindPid(cpt);
|
|
53396
|
+
if (!pid) continue;
|
|
53397
|
+
const componentId = mintComponentNode(store, cpt.componentText, t);
|
|
53398
|
+
if (componentId === pid) continue;
|
|
53399
|
+
mintCiteEdge(pid, componentId, "CONCERNS", cpt.evidence === "witnessed" ? 0.4 : 0.3, { componentCite: true, evidence: cpt.evidence });
|
|
53400
|
+
}
|
|
52486
53401
|
for (const inst of plan.instances) {
|
|
52487
53402
|
const pid = bindPid(inst);
|
|
52488
53403
|
if (!pid) continue;
|
|
@@ -52523,18 +53438,83 @@ function createWorkspaceEngine(opts) {
|
|
|
52523
53438
|
mintCiteEdge(solId, targetId, sl.relation, 0.4, { solutionStructure: true, hypothesis: true });
|
|
52524
53439
|
}
|
|
52525
53440
|
}
|
|
52526
|
-
|
|
52527
|
-
|
|
52528
|
-
|
|
52529
|
-
|
|
52530
|
-
|
|
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
|
+
})
|
|
52531
53503
|
);
|
|
52532
53504
|
}
|
|
52533
|
-
if (
|
|
52534
|
-
|
|
52535
|
-
|
|
52536
|
-
|
|
52537
|
-
|
|
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
|
+
})
|
|
52538
53518
|
);
|
|
52539
53519
|
}
|
|
52540
53520
|
} catch (err2) {
|
|
@@ -52563,17 +53543,28 @@ function createWorkspaceEngine(opts) {
|
|
|
52563
53543
|
}
|
|
52564
53544
|
};
|
|
52565
53545
|
const harvestTurns = async (sessionId, transcriptPath) => {
|
|
53546
|
+
const known = turnOffset.get(sessionId);
|
|
52566
53547
|
let turns;
|
|
53548
|
+
let nextOffset;
|
|
52567
53549
|
try {
|
|
52568
|
-
|
|
53550
|
+
if (known === void 0) {
|
|
53551
|
+
turns = readAssistantTurns(transcriptPath);
|
|
53552
|
+
nextOffset = transcriptSize(transcriptPath);
|
|
53553
|
+
} else {
|
|
53554
|
+
({ turns, nextOffset } = readAssistantTurnsFrom(transcriptPath, known));
|
|
53555
|
+
}
|
|
52569
53556
|
} catch {
|
|
52570
53557
|
return;
|
|
52571
53558
|
}
|
|
52572
53559
|
const fresh = turnsSince(turns, lastTurnUuid.get(sessionId));
|
|
52573
|
-
|
|
53560
|
+
turnOffset.set(sessionId, nextOffset);
|
|
53561
|
+
if (fresh.length === 0) {
|
|
53562
|
+
saveTurnCursors(turnCursorPath, lastTurnUuid, turnOffset);
|
|
53563
|
+
return;
|
|
53564
|
+
}
|
|
52574
53565
|
lastTurnUuid.set(sessionId, turns[turns.length - 1].uuid);
|
|
52575
53566
|
await harvestTexts(sessionId, fresh);
|
|
52576
|
-
saveTurnCursors(turnCursorPath, lastTurnUuid);
|
|
53567
|
+
saveTurnCursors(turnCursorPath, lastTurnUuid, turnOffset);
|
|
52577
53568
|
};
|
|
52578
53569
|
const seenMessageIds = /* @__PURE__ */ new Set();
|
|
52579
53570
|
const onMessage = (e) => {
|
|
@@ -52699,9 +53690,24 @@ function createWorkspaceEngine(opts) {
|
|
|
52699
53690
|
return typeof cloudId === "string" && cloudId !== p.id ? [p.id, cloudId] : [p.id];
|
|
52700
53691
|
});
|
|
52701
53692
|
const pins = profile?.projectId ? await cloud.getSkillPins(profile.projectId).then((r) => r.pins).catch(() => []) : [];
|
|
52702
|
-
const
|
|
53693
|
+
const anchorMap = buildBucketTokenAnchors(
|
|
53694
|
+
profile.languages ?? [],
|
|
53695
|
+
loadConfig().consent.contributePackages ? store.findNodesByLabel("Package").map((p) => ({
|
|
53696
|
+
name: String(p.attrs["name"] ?? ""),
|
|
53697
|
+
purl: String(p.attrs["purl"] ?? p.id)
|
|
53698
|
+
})) : []
|
|
53699
|
+
);
|
|
53700
|
+
const stackTokens = new Set((profile.stack ?? []).map((t) => canonicalizeToken(String(t))).filter(Boolean));
|
|
53701
|
+
const techSeed = [
|
|
53702
|
+
...new Set(
|
|
53703
|
+
Object.entries(anchorMap).filter(([tok, a]) => a.startsWith("lang:") || stackTokens.has(tok)).map(([, a]) => a)
|
|
53704
|
+
)
|
|
53705
|
+
].slice(0, 24);
|
|
53706
|
+
const result = await syncSkills(paths, cloud, skillSeed, pins, techSeed);
|
|
52703
53707
|
try {
|
|
52704
|
-
|
|
53708
|
+
const inputs = emitInputsFromManifest(paths.configDir, paths.skillsManifest);
|
|
53709
|
+
emitAndProjectSkills(opts.workspaceRoot, inputs);
|
|
53710
|
+
writePrimingHandles(join24(paths.configDir, "priming-handles.json"), skillHandleNodes(inputs));
|
|
52705
53711
|
} catch (err2) {
|
|
52706
53712
|
console.warn("[skills] agent-skills projection failed (non-fatal):", err2 instanceof Error ? err2.message : err2);
|
|
52707
53713
|
}
|
|
@@ -52888,7 +53894,7 @@ function createWorkspaceEngine(opts) {
|
|
|
52888
53894
|
console.log(
|
|
52889
53895
|
"[errata] sync skipped \u2014 cloud sync consent is off (enable with `errata consent sync on`)"
|
|
52890
53896
|
);
|
|
52891
|
-
const pending =
|
|
53897
|
+
const pending = existsSync19(paths.outbox) ? readdirSync9(paths.outbox).filter((f) => f.endsWith(".json")).length : 0;
|
|
52892
53898
|
return { uploaded: 0, failed: 0, remaining: pending };
|
|
52893
53899
|
}
|
|
52894
53900
|
try {
|
|
@@ -52975,7 +53981,7 @@ async function startDaemon(opts) {
|
|
|
52975
53981
|
reviewUrl: () => webUiUrl + "/review"
|
|
52976
53982
|
});
|
|
52977
53983
|
const writeLockFile = (url2) => {
|
|
52978
|
-
|
|
53984
|
+
writeFileSync17(
|
|
52979
53985
|
engine.paths.daemonLock,
|
|
52980
53986
|
JSON.stringify({ pid: process.pid, webUiUrl: url2, startedAt: Date.now() }),
|
|
52981
53987
|
"utf8"
|
|
@@ -53018,7 +54024,7 @@ async function startDaemon(opts) {
|
|
|
53018
54024
|
);
|
|
53019
54025
|
await engine.stop();
|
|
53020
54026
|
try {
|
|
53021
|
-
if (
|
|
54027
|
+
if (existsSync20(engine.paths.daemonLock)) {
|
|
53022
54028
|
}
|
|
53023
54029
|
} catch {
|
|
53024
54030
|
}
|
|
@@ -53035,16 +54041,16 @@ async function listenServer(fetchFn, port) {
|
|
|
53035
54041
|
|
|
53036
54042
|
// src/registry.ts
|
|
53037
54043
|
init_paths();
|
|
53038
|
-
import { existsSync as
|
|
53039
|
-
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";
|
|
53040
54046
|
function registryPath() {
|
|
53041
|
-
return process.env["ERRATA_REGISTRY_PATH"] ??
|
|
54047
|
+
return process.env["ERRATA_REGISTRY_PATH"] ?? join25(globalDir(), "workspaces.json");
|
|
53042
54048
|
}
|
|
53043
54049
|
function read() {
|
|
53044
54050
|
const p = registryPath();
|
|
53045
|
-
if (!
|
|
54051
|
+
if (!existsSync21(p)) return { version: 1, workspaces: {} };
|
|
53046
54052
|
try {
|
|
53047
|
-
const parsed = JSON.parse(
|
|
54053
|
+
const parsed = JSON.parse(readFileSync20(p, "utf8"));
|
|
53048
54054
|
return { version: 1, workspaces: parsed.workspaces ?? {} };
|
|
53049
54055
|
} catch {
|
|
53050
54056
|
return { version: 1, workspaces: {} };
|
|
@@ -53052,7 +54058,7 @@ function read() {
|
|
|
53052
54058
|
}
|
|
53053
54059
|
function write(reg) {
|
|
53054
54060
|
ensureDir(globalDir());
|
|
53055
|
-
|
|
54061
|
+
writeFileSync18(registryPath(), JSON.stringify(reg, null, 2), "utf8");
|
|
53056
54062
|
}
|
|
53057
54063
|
function registerWorkspace(profile, root, now = Date.now()) {
|
|
53058
54064
|
const reg = read();
|
|
@@ -53069,7 +54075,7 @@ function pruneMissingWorkspaces() {
|
|
|
53069
54075
|
const reg = read();
|
|
53070
54076
|
const removed = [];
|
|
53071
54077
|
for (const [id, entry] of Object.entries(reg.workspaces)) {
|
|
53072
|
-
if (!
|
|
54078
|
+
if (!existsSync21(entry.path)) {
|
|
53073
54079
|
removed.push(entry);
|
|
53074
54080
|
delete reg.workspaces[id];
|
|
53075
54081
|
}
|
|
@@ -53078,13 +54084,13 @@ function pruneMissingWorkspaces() {
|
|
|
53078
54084
|
return removed;
|
|
53079
54085
|
}
|
|
53080
54086
|
function workspaceStatus(entry) {
|
|
53081
|
-
const missing = !
|
|
54087
|
+
const missing = !existsSync21(entry.path);
|
|
53082
54088
|
const lockPath = workspacePaths(entry.path).daemonLock;
|
|
53083
54089
|
let running = false;
|
|
53084
54090
|
let webUiUrl = null;
|
|
53085
|
-
if (
|
|
54091
|
+
if (existsSync21(lockPath)) {
|
|
53086
54092
|
try {
|
|
53087
|
-
const lock = JSON.parse(
|
|
54093
|
+
const lock = JSON.parse(readFileSync20(lockPath, "utf8"));
|
|
53088
54094
|
if (lock.pid && lock.webUiUrl && pidAlive(lock.pid)) {
|
|
53089
54095
|
running = true;
|
|
53090
54096
|
webUiUrl = lock.webUiUrl;
|
|
@@ -53112,7 +54118,7 @@ function pidAlive(pid) {
|
|
|
53112
54118
|
// src/multi.ts
|
|
53113
54119
|
init_dist();
|
|
53114
54120
|
init_src4();
|
|
53115
|
-
import { readFileSync as
|
|
54121
|
+
import { readFileSync as readFileSync23, unlinkSync as unlinkSync3, writeFileSync as writeFileSync19 } from "node:fs";
|
|
53116
54122
|
|
|
53117
54123
|
// src/principle-sync.ts
|
|
53118
54124
|
init_src4();
|
|
@@ -53140,8 +54146,8 @@ init_reconcile();
|
|
|
53140
54146
|
|
|
53141
54147
|
// src/lockfile-auto.ts
|
|
53142
54148
|
init_src();
|
|
53143
|
-
import { existsSync as
|
|
53144
|
-
import { join as
|
|
54149
|
+
import { existsSync as existsSync22, readFileSync as readFileSync21 } from "node:fs";
|
|
54150
|
+
import { join as join26 } from "node:path";
|
|
53145
54151
|
|
|
53146
54152
|
// src/package-index.ts
|
|
53147
54153
|
init_src();
|
|
@@ -53227,10 +54233,12 @@ function buildContextIngest(store, profile, daemonVersion, ignorePatterns = [],
|
|
|
53227
54233
|
const ignored = (s) => ignorePatterns.length > 0 && ignorePatterns.some((p) => s.toLowerCase().includes(p));
|
|
53228
54234
|
const nodes = [];
|
|
53229
54235
|
const seen = /* @__PURE__ */ new Set();
|
|
54236
|
+
const localIdByWireId = {};
|
|
53230
54237
|
for (const label of labels) {
|
|
53231
54238
|
for (const n of store.findNodesByLabel(label)) {
|
|
53232
54239
|
if (n.attrs["source"] === "cloud") continue;
|
|
53233
54240
|
if (ignored(n.description) || ignored(String(n.attrs["name"] ?? ""))) continue;
|
|
54241
|
+
if (typeof n.attrs["contributedAtSeq"] === "number") continue;
|
|
53234
54242
|
nodes.push({
|
|
53235
54243
|
...n,
|
|
53236
54244
|
// Language wire id = the shared `languageCanonicalId` (warming-spine
|
|
@@ -53238,15 +54246,24 @@ function buildContextIngest(store, profile, daemonVersion, ignorePatterns = [],
|
|
|
53238
54246
|
// Package ids are already the purl (= the cross-stratum canonicalId).
|
|
53239
54247
|
id: label === "Language" ? languageCanonicalId(String(n.attrs["name"] ?? "").trim() || n.description) : n.id,
|
|
53240
54248
|
embedding: [],
|
|
54249
|
+
// No `version` attr on the wire: the purl already encodes the resolved
|
|
54250
|
+
// version, and the door's temporal guard rejects ANY `attrs.version` as
|
|
54251
|
+
// bi-temporal bookkeeping (ingest-temporal-guard.ts) — shipping it 422s
|
|
54252
|
+
// the whole batch. `resolved` still travels (range-vs-lockfile signal).
|
|
53241
54253
|
attrs: label === "Package" ? {
|
|
53242
54254
|
purl: n.attrs["purl"],
|
|
53243
54255
|
name: n.attrs["name"],
|
|
53244
|
-
version: n.attrs["version"],
|
|
53245
54256
|
ecosystem: n.attrs["ecosystem"],
|
|
53246
54257
|
resolved: n.attrs["resolved"]
|
|
53247
|
-
} : { name: n.attrs["name"] }
|
|
54258
|
+
} : { name: n.attrs["name"] },
|
|
54259
|
+
// OM-anchor-tag: context stubs are self-anchored — the wire id IS the
|
|
54260
|
+
// spine key (purl / languageCanonicalId). The door re-confirms on the
|
|
54261
|
+
// public spine; a private-registry or workspace package never confirms
|
|
54262
|
+
// and fails closed to org, exactly as an untagged one would.
|
|
54263
|
+
anchorVisibility: "public"
|
|
53248
54264
|
});
|
|
53249
54265
|
seen.add(n.id);
|
|
54266
|
+
localIdByWireId[nodes[nodes.length - 1].id] = n.id;
|
|
53250
54267
|
}
|
|
53251
54268
|
}
|
|
53252
54269
|
if (nodes.length === 0) return null;
|
|
@@ -53258,11 +54275,15 @@ function buildContextIngest(store, profile, daemonVersion, ignorePatterns = [],
|
|
|
53258
54275
|
}
|
|
53259
54276
|
const base = {
|
|
53260
54277
|
daemonVersion,
|
|
54278
|
+
// Origin key (= project, the salted `wp_…`) — the door stamps it onto created
|
|
54279
|
+
// nodes as `authoringProject`, arming the evidence channels' cross-origin gate
|
|
54280
|
+
// (EE-corrob-live: without it every node is fail-open to self-corroboration).
|
|
54281
|
+
...profile.id ? { originProject: profile.id } : {},
|
|
53261
54282
|
profile: { stack: profile.stack, languages: profile.languages, domains: profile.domains },
|
|
53262
54283
|
nodes,
|
|
53263
54284
|
edges
|
|
53264
54285
|
};
|
|
53265
|
-
return { ...base, payloadDigest: digest(base) };
|
|
54286
|
+
return { ...base, payloadDigest: digest(base), localIds: [...seen], localIdByWireId };
|
|
53266
54287
|
}
|
|
53267
54288
|
|
|
53268
54289
|
// src/lockfile-auto.ts
|
|
@@ -53275,11 +54296,11 @@ function runLockfilePass(opts) {
|
|
|
53275
54296
|
{ file: "package-lock.json", parse: parsePackageLockJson }
|
|
53276
54297
|
];
|
|
53277
54298
|
for (const c of candidates) {
|
|
53278
|
-
const p =
|
|
53279
|
-
if (!
|
|
54299
|
+
const p = join26(opts.root, c.file);
|
|
54300
|
+
if (!existsSync22(p)) continue;
|
|
53280
54301
|
let sbom;
|
|
53281
54302
|
try {
|
|
53282
|
-
sbom = c.parse(
|
|
54303
|
+
sbom = c.parse(readFileSync21(p, "utf8"));
|
|
53283
54304
|
} catch {
|
|
53284
54305
|
continue;
|
|
53285
54306
|
}
|
|
@@ -53294,6 +54315,7 @@ function runLockfilePass(opts) {
|
|
|
53294
54315
|
// src/instance-ingest.ts
|
|
53295
54316
|
init_src();
|
|
53296
54317
|
init_src2();
|
|
54318
|
+
init_src4();
|
|
53297
54319
|
init_src8();
|
|
53298
54320
|
init_src();
|
|
53299
54321
|
|
|
@@ -53337,13 +54359,17 @@ function noveltyAgainst(node2, neighbors, opts = {}) {
|
|
|
53337
54359
|
// src/instance-ingest.ts
|
|
53338
54360
|
var INSTANCE_LABELS = ["Problem", "Solution", "RootCause"];
|
|
53339
54361
|
var INSTANCE_EDGES = ["CAUSED_BY", "SOLVED_BY"];
|
|
53340
|
-
var ANCHOR_EDGES = ["OCCURS_IN", "DEPENDS_ON", "PERTAIN_TO"];
|
|
53341
|
-
var ANCHOR_TARGET_LABELS = ["Language", "Package", "Domain"];
|
|
54362
|
+
var ANCHOR_EDGES = ["OCCURS_IN", "DEPENDS_ON", "PERTAIN_TO", "CONCERNS"];
|
|
54363
|
+
var ANCHOR_TARGET_LABELS = ["Language", "Package", "Domain", "Component"];
|
|
53342
54364
|
function stripCodebaseScope(scope) {
|
|
53343
54365
|
const s = { ...scope ?? {} };
|
|
53344
54366
|
delete s["codebase"];
|
|
53345
54367
|
return s;
|
|
53346
54368
|
}
|
|
54369
|
+
function contributedWireId(n) {
|
|
54370
|
+
const cloudId = n.attrs["cloudNodeId"];
|
|
54371
|
+
return isMembraneSaltedId(cloudId) ? cloudId : n.id;
|
|
54372
|
+
}
|
|
53347
54373
|
function wireContextId(n) {
|
|
53348
54374
|
if (n.label === "Language" && n.attrs["source"] !== "cloud") {
|
|
53349
54375
|
const name2 = String(n.attrs["name"] ?? "").trim() || n.description.trim() || n.id.replace(/^lang:/, "");
|
|
@@ -53354,24 +54380,45 @@ function wireContextId(n) {
|
|
|
53354
54380
|
}
|
|
53355
54381
|
return n.id;
|
|
53356
54382
|
}
|
|
54383
|
+
function langAnchor(t) {
|
|
54384
|
+
const name2 = String(t.attrs["name"] ?? "").trim() || t.description.trim() || t.id.replace(/^lang:/, "").trim();
|
|
54385
|
+
return name2 ? `lang:${name2.toLowerCase()}` : void 0;
|
|
54386
|
+
}
|
|
53357
54387
|
function shareableContext(n, wireId) {
|
|
53358
54388
|
const attrs = n.label === "Package" ? {
|
|
54389
|
+
// No `version` attr: the purl encodes it, and the door's temporal
|
|
54390
|
+
// guard 422s any `attrs.version` (mirrors buildContextIngest).
|
|
53359
54391
|
purl: n.attrs["purl"],
|
|
53360
54392
|
name: n.attrs["name"],
|
|
53361
|
-
version: n.attrs["version"],
|
|
53362
54393
|
ecosystem: n.attrs["ecosystem"],
|
|
53363
54394
|
resolved: n.attrs["resolved"]
|
|
53364
54395
|
} : n.label === "Domain" ? { name: n.description, canonicalId: n.attrs["canonicalId"] } : { name: n.attrs["name"] };
|
|
53365
|
-
return {
|
|
54396
|
+
return {
|
|
54397
|
+
...n,
|
|
54398
|
+
id: wireId,
|
|
54399
|
+
embedding: [],
|
|
54400
|
+
attrs,
|
|
54401
|
+
...n.label === "Package" ? { anchorVisibility: "public" } : {},
|
|
54402
|
+
...n.label === "Language" && langAnchor(n) ? { anchorVisibility: "public", anchor: langAnchor(n) } : {},
|
|
54403
|
+
// A Component stub claims itself by slug (OM-agent-anchors) — the door
|
|
54404
|
+
// confirms only against an EXISTING public Component of that slug, so an
|
|
54405
|
+
// org-internal component name never crosses (fails closed to org).
|
|
54406
|
+
...n.label === "Component" ? { anchorVisibility: "public", anchor: `component:${wireId}` } : {}
|
|
54407
|
+
};
|
|
53366
54408
|
}
|
|
53367
54409
|
function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [], opts = {}) {
|
|
53368
54410
|
const level = opts.level ?? 1;
|
|
53369
54411
|
const noveltyOpts = opts.dedupCosine != null ? { dedupCosine: opts.dedupCosine } : {};
|
|
53370
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
|
+
};
|
|
53371
54417
|
const shareable = (n) => ({
|
|
53372
54418
|
...n,
|
|
53373
54419
|
description: generalize(n.description, { level }).text,
|
|
53374
54420
|
embedding: [],
|
|
54421
|
+
...originSessionOf(n),
|
|
53375
54422
|
attrs: {
|
|
53376
54423
|
scope: stripCodebaseScope(n.attrs["scope"]),
|
|
53377
54424
|
...n.attrs["kind"] ? { kind: n.attrs["kind"] } : {},
|
|
@@ -53380,7 +54427,9 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
|
|
|
53380
54427
|
});
|
|
53381
54428
|
const nodes = [];
|
|
53382
54429
|
const seen = /* @__PURE__ */ new Set();
|
|
54430
|
+
const shippedById = /* @__PURE__ */ new Map();
|
|
53383
54431
|
const anchorSources = /* @__PURE__ */ new Set();
|
|
54432
|
+
const semanticEndpoints = /* @__PURE__ */ new Map();
|
|
53384
54433
|
const includedByLabel = /* @__PURE__ */ new Map();
|
|
53385
54434
|
for (const label of INSTANCE_LABELS) {
|
|
53386
54435
|
const ref = [];
|
|
@@ -53393,13 +54442,24 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
|
|
|
53393
54442
|
const contributedAtSeq = n.attrs["contributedAtSeq"];
|
|
53394
54443
|
if (typeof contributedAtSeq === "number" && (n.lastReinforcedAtSeq ?? 0) <= contributedAtSeq) {
|
|
53395
54444
|
anchorSources.add(n.id);
|
|
54445
|
+
semanticEndpoints.set(n.id, contributedWireId(n));
|
|
53396
54446
|
continue;
|
|
53397
54447
|
}
|
|
54448
|
+
if (label === "Solution" && n.description.startsWith(AUTO_MINT_PREFIX)) {
|
|
54449
|
+
const problemShippable = store.inEdges(n.id, ["SOLVED_BY"]).some((e) => {
|
|
54450
|
+
const p = store.getNode(e.from);
|
|
54451
|
+
return p?.label === "Problem" && (seen.has(p.id) || typeof p.attrs["contributedAtSeq"] === "number");
|
|
54452
|
+
});
|
|
54453
|
+
if (!problemShippable) continue;
|
|
54454
|
+
}
|
|
53398
54455
|
if (!noveltyAgainst(n, ref, noveltyOpts).ready) continue;
|
|
53399
54456
|
ref.push(n);
|
|
53400
|
-
|
|
54457
|
+
const wireNode = shareable(n);
|
|
54458
|
+
nodes.push(wireNode);
|
|
54459
|
+
shippedById.set(n.id, wireNode);
|
|
53401
54460
|
seen.add(n.id);
|
|
53402
54461
|
anchorSources.add(n.id);
|
|
54462
|
+
semanticEndpoints.set(n.id, n.id);
|
|
53403
54463
|
}
|
|
53404
54464
|
}
|
|
53405
54465
|
for (const n of nodes) {
|
|
@@ -53419,27 +54479,66 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
|
|
|
53419
54479
|
if (e.type === "OCCURS_IN" && t.label !== "Language") continue;
|
|
53420
54480
|
if (e.type === "DEPENDS_ON" && t.label !== "Package") continue;
|
|
53421
54481
|
if (e.type === "PERTAIN_TO" && t.label !== "Domain") continue;
|
|
53422
|
-
if (
|
|
54482
|
+
if (e.type === "CONCERNS" && t.label !== "Component") continue;
|
|
54483
|
+
if ((t.label === "Package" || t.label === "Component") && opts.includePackages !== true) continue;
|
|
53423
54484
|
if (ignored(t.description) || ignored(String(t.attrs["name"] ?? ""))) continue;
|
|
53424
54485
|
targets.push({ e, t, wireId: wireContextId(t) });
|
|
53425
54486
|
}
|
|
53426
54487
|
if (targets.length === 0) continue;
|
|
54488
|
+
const shipped = shippedById.get(sourceId);
|
|
54489
|
+
if (shipped) {
|
|
54490
|
+
const anchors = (label) => targets.filter((x) => x.t.label === label).map(
|
|
54491
|
+
(x) => label === "Language" ? langAnchor(x.t) : label === "Component" ? `component:${x.wireId}` : x.wireId
|
|
54492
|
+
).filter((a) => a != null).sort();
|
|
54493
|
+
const anchor = anchors("Package")[0] ?? anchors("Component")[0] ?? anchors("Language")[0];
|
|
54494
|
+
if (anchor) {
|
|
54495
|
+
shipped.anchorVisibility = "public";
|
|
54496
|
+
shipped.anchor = anchor;
|
|
54497
|
+
}
|
|
54498
|
+
}
|
|
53427
54499
|
const dg = digest(targets.map(({ e, wireId }) => `${e.type}>${wireId}`).sort());
|
|
53428
|
-
|
|
54500
|
+
const sourceNode = store.getNode(sourceId);
|
|
54501
|
+
if (sourceNode?.attrs["anchorsContributedDigest"] === dg) continue;
|
|
53429
54502
|
anchorDigests[sourceId] = dg;
|
|
54503
|
+
const wireFrom = seen.has(sourceId) || !sourceNode ? sourceId : contributedWireId(sourceNode);
|
|
53430
54504
|
for (const { e, t, wireId } of targets) {
|
|
53431
|
-
anchorEdges.push({ ...e, to: wireId, attrs: {} });
|
|
54505
|
+
anchorEdges.push({ ...e, from: wireFrom, to: wireId, attrs: {} });
|
|
53432
54506
|
if (t.attrs["source"] === "cloud" || contextSeen.has(wireId)) continue;
|
|
53433
54507
|
contextSeen.add(wireId);
|
|
53434
54508
|
contextNodes.push(shareableContext(t, wireId));
|
|
53435
54509
|
}
|
|
53436
54510
|
}
|
|
54511
|
+
const primaryLang = (profile.languages ?? []).map((l) => String(l).trim().toLowerCase()).filter(Boolean)[0];
|
|
54512
|
+
if (primaryLang) {
|
|
54513
|
+
for (const shipped of shippedById.values()) {
|
|
54514
|
+
if (!shipped.anchorVisibility) {
|
|
54515
|
+
shipped.anchorVisibility = "public";
|
|
54516
|
+
shipped.anchor = `lang:${primaryLang}`;
|
|
54517
|
+
}
|
|
54518
|
+
}
|
|
54519
|
+
}
|
|
54520
|
+
for (const [localId, shipped] of shippedById) {
|
|
54521
|
+
const local = store.getNode(localId);
|
|
54522
|
+
if (!local || local.label !== "Solution" || !local.description.startsWith(AUTO_MINT_PREFIX)) continue;
|
|
54523
|
+
const problem = store.inEdges(localId, ["SOLVED_BY"]).map((e) => store.getNode(e.from)).find((p) => p?.label === "Problem");
|
|
54524
|
+
if (!problem) continue;
|
|
54525
|
+
const inBatch = shippedById.get(problem.id);
|
|
54526
|
+
if (inBatch) {
|
|
54527
|
+
if (inBatch.anchorVisibility) shipped.anchorVisibility = inBatch.anchorVisibility;
|
|
54528
|
+
if (inBatch.anchor != null) shipped.anchor = inBatch.anchor;
|
|
54529
|
+
else delete shipped.anchor;
|
|
54530
|
+
} else if (isMembraneSaltedId(problem.attrs["cloudNodeId"])) {
|
|
54531
|
+
shipped.anchorVisibility = "private";
|
|
54532
|
+
delete shipped.anchor;
|
|
54533
|
+
}
|
|
54534
|
+
}
|
|
53437
54535
|
const project = opts.project;
|
|
53438
54536
|
if (project) {
|
|
53439
54537
|
const now = Date.now();
|
|
53440
54538
|
for (const sourceId of anchorSources) {
|
|
53441
54539
|
const source = store.getNode(sourceId);
|
|
53442
54540
|
if (!source) continue;
|
|
54541
|
+
const wireFrom = seen.has(sourceId) ? sourceId : contributedWireId(source);
|
|
53443
54542
|
for (const e of store.outEdges(sourceId, ["ANCHORED_AT"])) {
|
|
53444
54543
|
const target = store.getNode(e.to);
|
|
53445
54544
|
if (!target) continue;
|
|
@@ -53474,11 +54573,21 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
|
|
|
53474
54573
|
stability: "unstable"
|
|
53475
54574
|
});
|
|
53476
54575
|
}
|
|
53477
|
-
anchorEdges.push({ ...e, to: symId, attrs: {} });
|
|
54576
|
+
anchorEdges.push({ ...e, from: wireFrom, to: symId, attrs: {} });
|
|
53478
54577
|
}
|
|
53479
54578
|
}
|
|
53480
54579
|
}
|
|
53481
|
-
|
|
54580
|
+
const edges = [];
|
|
54581
|
+
const semanticEdgeDigests = {};
|
|
54582
|
+
for (const [sourceId, wireFrom] of semanticEndpoints) {
|
|
54583
|
+
const outs = store.outEdges(sourceId, [...INSTANCE_EDGES]).map((e) => ({ e, wireTo: semanticEndpoints.get(e.to) })).filter((x) => x.wireTo != null);
|
|
54584
|
+
if (outs.length === 0) continue;
|
|
54585
|
+
const dg = digest(outs.map(({ e, wireTo }) => `${e.type}>${wireTo}`).sort());
|
|
54586
|
+
if (store.getNode(sourceId)?.attrs["semanticEdgesContributedDigest"] === dg) continue;
|
|
54587
|
+
semanticEdgeDigests[sourceId] = dg;
|
|
54588
|
+
for (const { e, wireTo } of outs) edges.push({ ...e, from: wireFrom, to: wireTo, attrs: {} });
|
|
54589
|
+
}
|
|
54590
|
+
if (nodes.length === 0 && anchorEdges.length === 0 && edges.length === 0) return null;
|
|
53482
54591
|
let symbolSummaries;
|
|
53483
54592
|
if (opts.lexicon && opts.lexicon.size > 0 && nodes.length > 0) {
|
|
53484
54593
|
const lexicon = opts.lexicon;
|
|
@@ -53500,15 +54609,14 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
|
|
|
53500
54609
|
}
|
|
53501
54610
|
if (count > 0) symbolSummaries = sidecar;
|
|
53502
54611
|
}
|
|
53503
|
-
const edges = [];
|
|
53504
|
-
for (const id of seen) {
|
|
53505
|
-
for (const e of store.outEdges(id, [...INSTANCE_EDGES])) {
|
|
53506
|
-
if (seen.has(e.to)) edges.push({ ...e, attrs: {} });
|
|
53507
|
-
}
|
|
53508
|
-
}
|
|
53509
54612
|
edges.push(...anchorEdges);
|
|
53510
54613
|
const base = {
|
|
53511
54614
|
daemonVersion,
|
|
54615
|
+
// Origin key (= project, the salted `wp_…`) — the door stamps it onto created
|
|
54616
|
+
// nodes as `authoringProject`, arming the evidence channels' cross-origin gate
|
|
54617
|
+
// (EE-corrob-live: this is the MAIN semantic drain; without the stamp every
|
|
54618
|
+
// Problem/Solution lands fail-open to self-corroboration).
|
|
54619
|
+
...profile.id ? { originProject: profile.id } : {},
|
|
53512
54620
|
profile: { stack: profile.stack, languages: profile.languages, domains: profile.domains },
|
|
53513
54621
|
// Context nodes FIRST: a chunked drain (cloud-client, 25-node chunks) then
|
|
53514
54622
|
// co-locates the few Language/Package stubs with the first instance chunk,
|
|
@@ -53519,7 +54627,47 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
|
|
|
53519
54627
|
// payloadDigest — byte-identical to the pre-sidecar batch (backward compat).
|
|
53520
54628
|
...symbolSummaries ? { symbolSummaries } : {}
|
|
53521
54629
|
};
|
|
53522
|
-
return { ...base, payloadDigest: digest(base), anchorDigests };
|
|
54630
|
+
return { ...base, payloadDigest: digest(base), anchorDigests, semanticEdgeDigests };
|
|
54631
|
+
}
|
|
54632
|
+
|
|
54633
|
+
// src/backfill-edges.ts
|
|
54634
|
+
init_src();
|
|
54635
|
+
init_src2();
|
|
54636
|
+
var CAUSAL_LABELS = ["Problem", "Solution", "RootCause"];
|
|
54637
|
+
var CAUSAL_EDGES2 = ["SOLVED_BY", "CAUSED_BY", "FIXED_BY"];
|
|
54638
|
+
function cloudWireId(store, id) {
|
|
54639
|
+
const n = store.getNode(id);
|
|
54640
|
+
if (!n || !CAUSAL_LABELS.includes(n.label)) return null;
|
|
54641
|
+
if (n.label === "Problem" && n.attrs["resolvedAs"] === PROBLEM_RESOLUTION.FALSE_POSITIVE) return null;
|
|
54642
|
+
const cloudNodeId = n.attrs["cloudNodeId"];
|
|
54643
|
+
if (typeof cloudNodeId === "string" && cloudNodeId.length > 0) return cloudNodeId;
|
|
54644
|
+
if (n.attrs["source"] === "cloud") return n.id;
|
|
54645
|
+
return typeof n.attrs["contributedAtSeq"] === "number" ? n.id : null;
|
|
54646
|
+
}
|
|
54647
|
+
function buildCausalEdgeBackfill(store, profile, daemonVersion) {
|
|
54648
|
+
const edges = [];
|
|
54649
|
+
const seenEdge = /* @__PURE__ */ new Set();
|
|
54650
|
+
for (const label of CAUSAL_LABELS) {
|
|
54651
|
+
for (const n of store.findNodesByLabel(label)) {
|
|
54652
|
+
for (const e of store.outEdges(n.id, [...CAUSAL_EDGES2])) {
|
|
54653
|
+
if (seenEdge.has(e.id)) continue;
|
|
54654
|
+
seenEdge.add(e.id);
|
|
54655
|
+
const from = cloudWireId(store, e.from);
|
|
54656
|
+
const to = cloudWireId(store, e.to);
|
|
54657
|
+
if (!from || !to) continue;
|
|
54658
|
+
edges.push({ ...e, from, to, attrs: {} });
|
|
54659
|
+
}
|
|
54660
|
+
}
|
|
54661
|
+
}
|
|
54662
|
+
if (edges.length === 0) return null;
|
|
54663
|
+
const base = {
|
|
54664
|
+
daemonVersion,
|
|
54665
|
+
profile: { stack: profile.stack, languages: profile.languages, domains: profile.domains },
|
|
54666
|
+
originProject: profile.id,
|
|
54667
|
+
nodes: [],
|
|
54668
|
+
edges
|
|
54669
|
+
};
|
|
54670
|
+
return { ...base, payloadDigest: digest(base) };
|
|
53523
54671
|
}
|
|
53524
54672
|
|
|
53525
54673
|
// src/multi.ts
|
|
@@ -53600,7 +54748,7 @@ var ConsolidateWorker = class {
|
|
|
53600
54748
|
init_paths();
|
|
53601
54749
|
|
|
53602
54750
|
// src/lock.ts
|
|
53603
|
-
import { existsSync as
|
|
54751
|
+
import { existsSync as existsSync23, readFileSync as readFileSync22 } from "node:fs";
|
|
53604
54752
|
function isProcessAlive(pid) {
|
|
53605
54753
|
if (!pid || pid <= 0) return false;
|
|
53606
54754
|
try {
|
|
@@ -53611,9 +54759,9 @@ function isProcessAlive(pid) {
|
|
|
53611
54759
|
}
|
|
53612
54760
|
}
|
|
53613
54761
|
function readDaemonLock(lockPath) {
|
|
53614
|
-
if (!
|
|
54762
|
+
if (!existsSync23(lockPath)) return null;
|
|
53615
54763
|
try {
|
|
53616
|
-
const lock = JSON.parse(
|
|
54764
|
+
const lock = JSON.parse(readFileSync22(lockPath, "utf8"));
|
|
53617
54765
|
return typeof lock.pid === "number" ? lock : null;
|
|
53618
54766
|
} catch {
|
|
53619
54767
|
return null;
|
|
@@ -53855,13 +55003,13 @@ async function reanchorProject(opts) {
|
|
|
53855
55003
|
}
|
|
53856
55004
|
|
|
53857
55005
|
// src/adopt.ts
|
|
53858
|
-
import { existsSync as
|
|
53859
|
-
import { dirname as
|
|
55006
|
+
import { existsSync as existsSync24 } from "node:fs";
|
|
55007
|
+
import { dirname as dirname10, join as join27 } from "node:path";
|
|
53860
55008
|
function findGitRoot(absPath) {
|
|
53861
55009
|
let dir = absPath;
|
|
53862
55010
|
for (let depth = 0; depth < 64; depth++) {
|
|
53863
|
-
if (
|
|
53864
|
-
const parent =
|
|
55011
|
+
if (existsSync24(join27(dir, ".git"))) return dir;
|
|
55012
|
+
const parent = dirname10(dir);
|
|
53865
55013
|
if (parent === dir) return null;
|
|
53866
55014
|
dir = parent;
|
|
53867
55015
|
}
|
|
@@ -53969,6 +55117,18 @@ async function startMultiDaemon(opts = {}) {
|
|
|
53969
55117
|
startLoopLagMonitor();
|
|
53970
55118
|
let baseUrl = "";
|
|
53971
55119
|
const records = [];
|
|
55120
|
+
const machineDominantLanguage = () => {
|
|
55121
|
+
const langCounts = /* @__PURE__ */ new Map();
|
|
55122
|
+
for (const r of records) {
|
|
55123
|
+
for (const l of r.engine.profile.languages ?? []) {
|
|
55124
|
+
const k = String(l).trim().toLowerCase();
|
|
55125
|
+
if (k) langCounts.set(k, (langCounts.get(k) ?? 0) + 1);
|
|
55126
|
+
}
|
|
55127
|
+
}
|
|
55128
|
+
return [...langCounts.entries()].sort(
|
|
55129
|
+
(a, b) => b[1] - a[1] || (a[0] < b[0] ? -1 : 1)
|
|
55130
|
+
)[0]?.[0];
|
|
55131
|
+
};
|
|
53972
55132
|
const updatePoller = opts.updateCheck ? startUpdatePoller({
|
|
53973
55133
|
channel: loadConfig().updateChannel,
|
|
53974
55134
|
onChange: (pending) => {
|
|
@@ -53981,6 +55141,47 @@ async function startMultiDaemon(opts = {}) {
|
|
|
53981
55141
|
let serverPending = null;
|
|
53982
55142
|
const boundaryListeners = [];
|
|
53983
55143
|
let boundaryFlushing = false;
|
|
55144
|
+
let boundaryFlushStartedAt = 0;
|
|
55145
|
+
let boundaryFlushStage = "";
|
|
55146
|
+
let boundaryFlushUnits = 0;
|
|
55147
|
+
let boundaryFlushLastAdvanceAt = 0;
|
|
55148
|
+
let boundaryFlushBatches = 0;
|
|
55149
|
+
const beginFlush = (stage) => {
|
|
55150
|
+
boundaryFlushing = true;
|
|
55151
|
+
boundaryFlushStartedAt = Date.now();
|
|
55152
|
+
boundaryFlushLastAdvanceAt = Date.now();
|
|
55153
|
+
boundaryFlushUnits = 0;
|
|
55154
|
+
boundaryFlushBatches = 0;
|
|
55155
|
+
boundaryFlushItems = 0;
|
|
55156
|
+
boundaryFlushDetail = "";
|
|
55157
|
+
boundaryFlushStage = stage;
|
|
55158
|
+
};
|
|
55159
|
+
const flushStage = (stage) => {
|
|
55160
|
+
boundaryFlushStage = stage;
|
|
55161
|
+
};
|
|
55162
|
+
let boundaryFlushItems = 0;
|
|
55163
|
+
let boundaryFlushDetail = "";
|
|
55164
|
+
const noteFlushProgress = (units, items = 0, detail = "") => {
|
|
55165
|
+
boundaryFlushBatches++;
|
|
55166
|
+
boundaryFlushUnits += Math.max(0, units);
|
|
55167
|
+
boundaryFlushItems += Math.max(0, items);
|
|
55168
|
+
if (detail) boundaryFlushDetail = detail;
|
|
55169
|
+
if (units > 0 || items > 0) boundaryFlushLastAdvanceAt = Date.now();
|
|
55170
|
+
};
|
|
55171
|
+
const flushSnapshot = () => ({
|
|
55172
|
+
running: boundaryFlushing,
|
|
55173
|
+
stage: boundaryFlushStage,
|
|
55174
|
+
detail: boundaryFlushDetail,
|
|
55175
|
+
ageMs: boundaryFlushStartedAt ? Date.now() - boundaryFlushStartedAt : 0,
|
|
55176
|
+
units: boundaryFlushUnits,
|
|
55177
|
+
items: boundaryFlushItems,
|
|
55178
|
+
chunks: boundaryFlushBatches,
|
|
55179
|
+
stalledMs: boundaryFlushLastAdvanceAt ? Date.now() - boundaryFlushLastAdvanceAt : 0
|
|
55180
|
+
});
|
|
55181
|
+
const endFlush = () => {
|
|
55182
|
+
boundaryFlushing = false;
|
|
55183
|
+
boundaryFlushStage = "";
|
|
55184
|
+
};
|
|
53984
55185
|
const fireBoundary = () => {
|
|
53985
55186
|
for (const l of boundaryListeners) {
|
|
53986
55187
|
try {
|
|
@@ -54056,7 +55257,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
54056
55257
|
void ambientLinkAll();
|
|
54057
55258
|
app.route(`/ws/${rec.id}`, rec.webApp);
|
|
54058
55259
|
try {
|
|
54059
|
-
|
|
55260
|
+
writeFileSync19(
|
|
54060
55261
|
rec.engine.paths.daemonLock,
|
|
54061
55262
|
JSON.stringify({ pid: process.pid, webUiUrl: `${baseUrl}/ws/${rec.id}`, startedAt: Date.now() }),
|
|
54062
55263
|
"utf8"
|
|
@@ -54095,8 +55296,10 @@ async function startMultiDaemon(opts = {}) {
|
|
|
54095
55296
|
path: r.root,
|
|
54096
55297
|
stack: r.entry.stack,
|
|
54097
55298
|
nodes: r.engine.store.nodeCount(),
|
|
54098
|
-
|
|
54099
|
-
|
|
55299
|
+
// COUNT(*) — the materializing findNodesByLabel(...).length form held
|
|
55300
|
+
// the event loop for seconds per poll once stores grew (HZ-index-hydrate).
|
|
55301
|
+
problems: r.engine.store.countNodesByLabel("Problem"),
|
|
55302
|
+
solutions: r.engine.store.countNodesByLabel("Solution"),
|
|
54100
55303
|
endpoints: `/ws/${r.id}/`
|
|
54101
55304
|
})),
|
|
54102
55305
|
humanView: "run `errata report` \u2014 the dashboard was retired (GRAFT 4e)"
|
|
@@ -54152,8 +55355,9 @@ async function startMultiDaemon(opts = {}) {
|
|
|
54152
55355
|
name: r.entry.name,
|
|
54153
55356
|
path: r.root,
|
|
54154
55357
|
nodes: r.engine.store.nodeCount(),
|
|
54155
|
-
|
|
54156
|
-
|
|
55358
|
+
// COUNT(*) — same hydration hazard as `/` (HZ-index-hydrate).
|
|
55359
|
+
problems: r.engine.store.countNodesByLabel("Problem"),
|
|
55360
|
+
solutions: r.engine.store.countNodesByLabel("Solution"),
|
|
54157
55361
|
stranded: strandedCount(r)
|
|
54158
55362
|
}))
|
|
54159
55363
|
})
|
|
@@ -54242,7 +55446,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
54242
55446
|
baseUrl = `http://127.0.0.1:${port}`;
|
|
54243
55447
|
try {
|
|
54244
55448
|
ensureDir(globalDir());
|
|
54245
|
-
|
|
55449
|
+
writeFileSync19(
|
|
54246
55450
|
lockPath,
|
|
54247
55451
|
JSON.stringify({ pid: process.pid, webUiUrl: baseUrl, startedAt: Date.now() }),
|
|
54248
55452
|
"utf8"
|
|
@@ -54251,7 +55455,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
54251
55455
|
}
|
|
54252
55456
|
for (const r of records) {
|
|
54253
55457
|
try {
|
|
54254
|
-
|
|
55458
|
+
writeFileSync19(
|
|
54255
55459
|
r.engine.paths.daemonLock,
|
|
54256
55460
|
JSON.stringify({ pid: process.pid, webUiUrl: `${baseUrl}/ws/${r.id}`, startedAt: Date.now() }),
|
|
54257
55461
|
"utf8"
|
|
@@ -54514,15 +55718,33 @@ async function startMultiDaemon(opts = {}) {
|
|
|
54514
55718
|
async syncPrinciplesPublic() {
|
|
54515
55719
|
if (!loadConfig().consent.sync) return { uploaded: 0, skipped: "consent-off" };
|
|
54516
55720
|
const ignore = loadClaimIgnorePatterns(globalDir());
|
|
54517
|
-
const
|
|
55721
|
+
const primaryLanguage = machineDominantLanguage();
|
|
55722
|
+
const payload = buildPrincipleIngest(sharedStore, DAEMON_VERSION, ignore, 2, {
|
|
55723
|
+
...primaryLanguage ? { primaryLanguage } : {}
|
|
55724
|
+
});
|
|
54518
55725
|
if (!payload) return { uploaded: 0 };
|
|
54519
55726
|
const res = await cloudNow().ingest(payload);
|
|
54520
55727
|
return { uploaded: res.accepted };
|
|
54521
55728
|
},
|
|
54522
55729
|
async syncTriagePublic() {
|
|
54523
|
-
|
|
55730
|
+
const cfg2 = loadConfig();
|
|
55731
|
+
if (!cfg2.consent.sync) return { uploaded: 0, skipped: "consent-off" };
|
|
54524
55732
|
const ignore = loadClaimIgnorePatterns(globalDir());
|
|
54525
|
-
const
|
|
55733
|
+
const primaryLanguage = machineDominantLanguage();
|
|
55734
|
+
const languages = records.flatMap((r) => r.engine.profile.languages ?? []);
|
|
55735
|
+
const packages = cfg2.consent.contributePackages ? records.flatMap(
|
|
55736
|
+
(r) => r.engine.store.findNodesByLabel("Package").map((p) => ({
|
|
55737
|
+
name: String(p.attrs["name"] ?? ""),
|
|
55738
|
+
purl: String(p.attrs["purl"] ?? p.id)
|
|
55739
|
+
}))
|
|
55740
|
+
) : [];
|
|
55741
|
+
const tokenAnchors = buildBucketTokenAnchors(languages, packages);
|
|
55742
|
+
const payload = buildTriageIngest(sharedStore, DAEMON_VERSION, ignore, 2, {
|
|
55743
|
+
...primaryLanguage ? { primaryLanguage } : {},
|
|
55744
|
+
tokenAnchors,
|
|
55745
|
+
// Scoped bucket keys carry package names — same consent as the purls.
|
|
55746
|
+
includeScopedBuckets: cfg2.consent.contributePackages
|
|
55747
|
+
});
|
|
54526
55748
|
if (!payload) return { uploaded: 0 };
|
|
54527
55749
|
const res = await cloudNow().ingest(payload);
|
|
54528
55750
|
return { uploaded: res.accepted };
|
|
@@ -54533,14 +55755,44 @@ async function startMultiDaemon(opts = {}) {
|
|
|
54533
55755
|
const ignore = loadClaimIgnorePatterns(globalDir());
|
|
54534
55756
|
const client = cloudNow();
|
|
54535
55757
|
let uploaded = 0;
|
|
55758
|
+
const errors = [];
|
|
55759
|
+
const lane = async (name2, projectName, run3) => {
|
|
55760
|
+
try {
|
|
55761
|
+
await run3();
|
|
55762
|
+
} catch (err2) {
|
|
55763
|
+
const msg = `[${projectName}] ${name2}: ${err2 instanceof Error ? err2.message : String(err2)}`;
|
|
55764
|
+
errors.push(msg);
|
|
55765
|
+
console.error(`[sync\u2192cloud] ${msg}`);
|
|
55766
|
+
}
|
|
55767
|
+
};
|
|
54536
55768
|
for (const r of records) {
|
|
54537
55769
|
const store = r.engine.store;
|
|
55770
|
+
const projectName = r.engine.profile.name ?? r.engine.profile.id;
|
|
54538
55771
|
const context = buildContextIngest(store, r.engine.profile, DAEMON_VERSION, ignore, {
|
|
54539
55772
|
includePackages: cfg2.consent.contributePackages
|
|
54540
55773
|
});
|
|
54541
55774
|
if (context) {
|
|
54542
|
-
|
|
54543
|
-
|
|
55775
|
+
await lane("context", projectName, async () => {
|
|
55776
|
+
const res = await client.ingest(context, {
|
|
55777
|
+
onChunk: (p) => {
|
|
55778
|
+
const seq = store.currentIngestSeq();
|
|
55779
|
+
for (const wireId of p.nodeIds) {
|
|
55780
|
+
const localId = context.localIdByWireId[wireId] ?? wireId;
|
|
55781
|
+
const local = store.getNode(localId);
|
|
55782
|
+
if (!local) continue;
|
|
55783
|
+
store.updateNode(localId, { attrs: { ...local.attrs, contributedAtSeq: seq } });
|
|
55784
|
+
}
|
|
55785
|
+
if (p.blockedNodeIds?.length) {
|
|
55786
|
+
console.log(
|
|
55787
|
+
`[sync\u2192cloud] [${projectName}] context: ${p.blockedNodeIds.length} node(s) refused by an edge/CDN filter on content \u2014 left pending, will retry`
|
|
55788
|
+
);
|
|
55789
|
+
}
|
|
55790
|
+
noteFlushProgress(p.accepted, p.nodeIds.length, `context ${p.chunkIndex}/${p.totalChunks}`);
|
|
55791
|
+
}
|
|
55792
|
+
});
|
|
55793
|
+
uploaded += res.accepted;
|
|
55794
|
+
return res.accepted;
|
|
55795
|
+
});
|
|
54544
55796
|
}
|
|
54545
55797
|
let lexicon;
|
|
54546
55798
|
try {
|
|
@@ -54563,34 +55815,78 @@ async function startMultiDaemon(opts = {}) {
|
|
|
54563
55815
|
});
|
|
54564
55816
|
if (instances) {
|
|
54565
55817
|
if (project) instances.projectId = project.projectId;
|
|
54566
|
-
|
|
54567
|
-
|
|
54568
|
-
|
|
54569
|
-
|
|
54570
|
-
|
|
54571
|
-
|
|
54572
|
-
for (const n of instances.nodes) {
|
|
54573
|
-
const local = store.getNode(n.id);
|
|
54574
|
-
if (!local || !["Problem", "Solution", "RootCause"].includes(local.label)) continue;
|
|
54575
|
-
const cloudNodeId = cloudIdByLocal.get(n.id);
|
|
54576
|
-
store.updateNode(n.id, {
|
|
54577
|
-
attrs: {
|
|
54578
|
-
...local.attrs,
|
|
54579
|
-
contributedAtSeq: seq,
|
|
54580
|
-
...cloudNodeId && cloudNodeId !== n.id ? { cloudNodeId } : {}
|
|
55818
|
+
await lane("instances", projectName, async () => {
|
|
55819
|
+
const blocked = /* @__PURE__ */ new Set();
|
|
55820
|
+
const res = await client.ingest(instances, {
|
|
55821
|
+
onChunk: (p) => {
|
|
55822
|
+
for (const id of p.blockedNodeIds ?? []) blocked.add(id);
|
|
55823
|
+
noteFlushProgress(p.accepted, p.nodeIds.length, `instances ${p.chunkIndex}/${p.totalChunks}`);
|
|
54581
55824
|
}
|
|
54582
55825
|
});
|
|
54583
|
-
|
|
54584
|
-
|
|
54585
|
-
|
|
54586
|
-
|
|
54587
|
-
|
|
54588
|
-
|
|
54589
|
-
|
|
54590
|
-
|
|
55826
|
+
if (blocked.size > 0) {
|
|
55827
|
+
console.log(
|
|
55828
|
+
`[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]}`
|
|
55829
|
+
);
|
|
55830
|
+
}
|
|
55831
|
+
uploaded += res.accepted;
|
|
55832
|
+
const seq = store.currentIngestSeq();
|
|
55833
|
+
const cloudIdByLocal = new Map(
|
|
55834
|
+
res.result.nodes.filter((rn) => rn.nodeId).map((rn) => [rn.canonicalId, rn.nodeId])
|
|
55835
|
+
);
|
|
55836
|
+
for (const n of instances.nodes) {
|
|
55837
|
+
const local = store.getNode(n.id);
|
|
55838
|
+
if (!local || !["Problem", "Solution", "RootCause"].includes(local.label)) continue;
|
|
55839
|
+
if (blocked.has(n.id)) continue;
|
|
55840
|
+
const cloudNodeId = cloudIdByLocal.get(n.id);
|
|
55841
|
+
store.updateNode(n.id, {
|
|
55842
|
+
attrs: {
|
|
55843
|
+
...local.attrs,
|
|
55844
|
+
contributedAtSeq: seq,
|
|
55845
|
+
...cloudNodeId && cloudNodeId !== n.id ? { cloudNodeId } : {}
|
|
55846
|
+
}
|
|
55847
|
+
});
|
|
55848
|
+
}
|
|
55849
|
+
for (const [localId, dg] of Object.entries(instances.anchorDigests)) {
|
|
55850
|
+
const local = store.getNode(localId);
|
|
55851
|
+
if (!local) continue;
|
|
55852
|
+
store.updateNode(localId, {
|
|
55853
|
+
attrs: { ...local.attrs, anchorsContributedDigest: dg }
|
|
55854
|
+
});
|
|
55855
|
+
}
|
|
55856
|
+
for (const [localId, dg] of Object.entries(instances.semanticEdgeDigests)) {
|
|
55857
|
+
const local = store.getNode(localId);
|
|
55858
|
+
if (!local) continue;
|
|
55859
|
+
store.updateNode(localId, {
|
|
55860
|
+
attrs: { ...local.attrs, semanticEdgesContributedDigest: dg }
|
|
55861
|
+
});
|
|
55862
|
+
}
|
|
55863
|
+
return res.accepted;
|
|
55864
|
+
});
|
|
54591
55865
|
}
|
|
54592
55866
|
}
|
|
54593
|
-
return { uploaded };
|
|
55867
|
+
return { uploaded, ...errors.length > 0 ? { errors } : {} };
|
|
55868
|
+
},
|
|
55869
|
+
async backfillCausalEdges() {
|
|
55870
|
+
if (!loadConfig().consent.sync) return { accepted: 0, rejected: 0, skipped: "consent-off" };
|
|
55871
|
+
const client = cloudNow();
|
|
55872
|
+
let accepted = 0;
|
|
55873
|
+
let rejected = 0;
|
|
55874
|
+
const errors = [];
|
|
55875
|
+
for (const r of records) {
|
|
55876
|
+
const payload = buildCausalEdgeBackfill(r.engine.store, r.engine.profile, DAEMON_VERSION);
|
|
55877
|
+
if (!payload) continue;
|
|
55878
|
+
try {
|
|
55879
|
+
const res = await client.ingest(payload);
|
|
55880
|
+
accepted += res.accepted;
|
|
55881
|
+
rejected += res.rejected;
|
|
55882
|
+
if (res.rejected > 0) errors.push(...res.violations.slice(0, 5));
|
|
55883
|
+
} catch (err2) {
|
|
55884
|
+
errors.push(
|
|
55885
|
+
`[${r.engine.profile.name ?? r.engine.profile.id}] backfill: ${err2 instanceof Error ? err2.message : String(err2)}`
|
|
55886
|
+
);
|
|
55887
|
+
}
|
|
55888
|
+
}
|
|
55889
|
+
return { accepted, rejected, ...errors.length > 0 ? { errors } : {} };
|
|
54594
55890
|
},
|
|
54595
55891
|
async pullTriagePublic() {
|
|
54596
55892
|
if (!loadConfig().consent.sync) return { merged: 0, skipped: "consent-off" };
|
|
@@ -54633,16 +55929,23 @@ async function startMultiDaemon(opts = {}) {
|
|
|
54633
55929
|
},
|
|
54634
55930
|
async sessionBoundaryFlush() {
|
|
54635
55931
|
if (boundaryFlushing) return { uploaded: 0, written: 0, pruned: 0, skipped: "in-flight" };
|
|
54636
|
-
|
|
55932
|
+
beginFlush("embed");
|
|
54637
55933
|
try {
|
|
54638
55934
|
for (const r of records) {
|
|
54639
55935
|
await r.engine.embedSettled();
|
|
54640
55936
|
}
|
|
55937
|
+
flushStage("instances");
|
|
54641
55938
|
const inst = await daemon.syncInstancesPublic();
|
|
55939
|
+
flushStage("skills");
|
|
54642
55940
|
const skills = await daemon.syncSkillsAll();
|
|
54643
|
-
return {
|
|
55941
|
+
return {
|
|
55942
|
+
uploaded: inst.uploaded,
|
|
55943
|
+
written: skills.written,
|
|
55944
|
+
pruned: skills.pruned,
|
|
55945
|
+
...inst.errors ? { errors: inst.errors } : {}
|
|
55946
|
+
};
|
|
54644
55947
|
} finally {
|
|
54645
|
-
|
|
55948
|
+
endFlush();
|
|
54646
55949
|
}
|
|
54647
55950
|
},
|
|
54648
55951
|
onSessionBoundary(cb) {
|
|
@@ -54650,7 +55953,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
54650
55953
|
},
|
|
54651
55954
|
async stop() {
|
|
54652
55955
|
try {
|
|
54653
|
-
const cur =
|
|
55956
|
+
const cur = readFileSync23(lockPath, "utf8");
|
|
54654
55957
|
if (JSON.parse(cur).pid === process.pid) unlinkSync3(lockPath);
|
|
54655
55958
|
} catch {
|
|
54656
55959
|
}
|
|
@@ -54667,15 +55970,24 @@ async function startMultiDaemon(opts = {}) {
|
|
|
54667
55970
|
}
|
|
54668
55971
|
};
|
|
54669
55972
|
app.post("/api/sync", async (c) => {
|
|
55973
|
+
if (boundaryFlushing) return c.json({ skipped: "in-flight", ...flushSnapshot() }, 409);
|
|
55974
|
+
beginFlush("principles");
|
|
54670
55975
|
try {
|
|
54671
55976
|
const principles = await daemon.syncPrinciplesPublic();
|
|
55977
|
+
flushStage("triage");
|
|
54672
55978
|
const triage = await daemon.syncTriagePublic();
|
|
55979
|
+
flushStage("instances");
|
|
54673
55980
|
const instances = await daemon.syncInstancesPublic();
|
|
54674
|
-
|
|
55981
|
+
flushStage("edge-backfill");
|
|
55982
|
+
const edgeBackfill = await daemon.backfillCausalEdges();
|
|
55983
|
+
return c.json({ principles, triage, instances, edgeBackfill });
|
|
54675
55984
|
} catch (err2) {
|
|
54676
55985
|
return c.json({ error: err2 instanceof Error ? err2.message : String(err2) }, 500);
|
|
55986
|
+
} finally {
|
|
55987
|
+
endFlush();
|
|
54677
55988
|
}
|
|
54678
55989
|
});
|
|
55990
|
+
app.get("/api/sync", (c) => c.json(flushSnapshot()));
|
|
54679
55991
|
app.post("/api/tick", async (c) => {
|
|
54680
55992
|
try {
|
|
54681
55993
|
return c.json({ reports: Object.fromEntries(await daemon.tickAll()) });
|
|
@@ -55658,21 +56970,21 @@ async function cmdInit() {
|
|
|
55658
56970
|
if (!skipHooks) {
|
|
55659
56971
|
console.log("");
|
|
55660
56972
|
console.log("installing harness hooks...");
|
|
55661
|
-
const { existsSync:
|
|
55662
|
-
const { join:
|
|
56973
|
+
const { existsSync: existsSync26 } = await import("node:fs");
|
|
56974
|
+
const { join: join29 } = await import("node:path");
|
|
55663
56975
|
try {
|
|
55664
56976
|
await installClaudeHooks(port);
|
|
55665
56977
|
} catch (err2) {
|
|
55666
56978
|
console.warn(` \u26A0\uFE0F Claude hook install failed: ${err2 instanceof Error ? err2.message : err2}`);
|
|
55667
56979
|
}
|
|
55668
|
-
if (
|
|
56980
|
+
if (existsSync26(join29(ROOT, ".cursor"))) {
|
|
55669
56981
|
try {
|
|
55670
56982
|
await installCursorMcpConfig();
|
|
55671
56983
|
} catch (err2) {
|
|
55672
56984
|
console.warn(` \u26A0\uFE0F Cursor MCP config failed: ${err2 instanceof Error ? err2.message : err2}`);
|
|
55673
56985
|
}
|
|
55674
56986
|
}
|
|
55675
|
-
if (
|
|
56987
|
+
if (existsSync26(join29(ROOT, ".codex"))) {
|
|
55676
56988
|
try {
|
|
55677
56989
|
await installCodexHooks(port);
|
|
55678
56990
|
} catch (err2) {
|
|
@@ -55829,8 +57141,30 @@ async function cmdStatus() {
|
|
|
55829
57141
|
console.log(` stack: ${profile.stack.join(", ") || "(none)"}`);
|
|
55830
57142
|
console.log(` languages: ${profile.languages.join(", ") || "(none)"}`);
|
|
55831
57143
|
}
|
|
55832
|
-
console.log(` graph db: ${
|
|
55833
|
-
console.log(` event log: ${
|
|
57144
|
+
console.log(` graph db: ${existsSync25(paths.castalia) ? "yes" : "no"} (${paths.castalia})`);
|
|
57145
|
+
console.log(` event log: ${existsSync25(paths.eventLog) ? "yes" : "no"} (${paths.eventLog})`);
|
|
57146
|
+
if (existsSync25(paths.castalia)) {
|
|
57147
|
+
try {
|
|
57148
|
+
const { openGraphStore: openGraphStore2 } = await Promise.resolve().then(() => (init_src4(), src_exports2));
|
|
57149
|
+
const store = openGraphStore2({ path: paths.castalia });
|
|
57150
|
+
try {
|
|
57151
|
+
let pending = 0;
|
|
57152
|
+
let total = 0;
|
|
57153
|
+
for (const label of ["Problem", "Solution", "RootCause"]) {
|
|
57154
|
+
for (const n of store.findNodesByLabel(label)) {
|
|
57155
|
+
if (n.attrs["source"] === "cloud") continue;
|
|
57156
|
+
total++;
|
|
57157
|
+
const c = n.attrs["contributedAtSeq"];
|
|
57158
|
+
if (typeof c !== "number" || (n.lastReinforcedAtSeq ?? 0) > c) pending++;
|
|
57159
|
+
}
|
|
57160
|
+
}
|
|
57161
|
+
console.log(` contribute: ${pending} pending of ${total} instance node(s)`);
|
|
57162
|
+
} finally {
|
|
57163
|
+
store.close();
|
|
57164
|
+
}
|
|
57165
|
+
} catch {
|
|
57166
|
+
}
|
|
57167
|
+
}
|
|
55834
57168
|
const lockPath = globalDaemonLock();
|
|
55835
57169
|
const running = isDaemonAlive(lockPath) ? readDaemonLock(lockPath) : null;
|
|
55836
57170
|
console.log(
|
|
@@ -56460,11 +57794,11 @@ function cmdInstallationProfile(args2) {
|
|
|
56460
57794
|
}
|
|
56461
57795
|
async function cmdReview() {
|
|
56462
57796
|
const paths = workspacePaths(ROOT);
|
|
56463
|
-
if (!
|
|
57797
|
+
if (!existsSync25(paths.reviewQueue)) {
|
|
56464
57798
|
console.log("(review queue empty)");
|
|
56465
57799
|
return;
|
|
56466
57800
|
}
|
|
56467
|
-
const queue = JSON.parse(
|
|
57801
|
+
const queue = JSON.parse(readFileSync24(paths.reviewQueue, "utf8"));
|
|
56468
57802
|
if (queue.length === 0) {
|
|
56469
57803
|
console.log("(review queue empty)");
|
|
56470
57804
|
return;
|
|
@@ -56883,8 +58217,8 @@ async function cmdSimilar(args2) {
|
|
|
56883
58217
|
const limitIdx = args2.indexOf("--limit");
|
|
56884
58218
|
const limit = limitIdx >= 0 && args2[limitIdx + 1] ? Number(args2[limitIdx + 1]) : 5;
|
|
56885
58219
|
const { runTool: runTool2 } = await Promise.resolve().then(() => (init_mcp(), mcp_exports));
|
|
56886
|
-
await withStore((store) => {
|
|
56887
|
-
const r = runTool2("errata.similar", { nodeId: seed, qname: seed, limit }, store);
|
|
58220
|
+
await withStore(async (store) => {
|
|
58221
|
+
const r = await runTool2("errata.similar", { nodeId: seed, qname: seed, limit }, store);
|
|
56888
58222
|
if (!r.found) {
|
|
56889
58223
|
console.log("seed not found");
|
|
56890
58224
|
return;
|
|
@@ -57135,7 +58469,7 @@ async function gatherRepo(store, ws) {
|
|
|
57135
58469
|
};
|
|
57136
58470
|
}
|
|
57137
58471
|
async function gatherReportData(generatedAt) {
|
|
57138
|
-
const { existsSync:
|
|
58472
|
+
const { existsSync: existsSync26 } = await import("node:fs");
|
|
57139
58473
|
const { openGraphStore: openGraphStore2 } = await Promise.resolve().then(() => (init_src4(), src_exports2));
|
|
57140
58474
|
const cfg = loadConfig();
|
|
57141
58475
|
const outbound = cfg.consent.sync ? "auto" : "off";
|
|
@@ -57143,7 +58477,7 @@ async function gatherReportData(generatedAt) {
|
|
|
57143
58477
|
for (const ws of listWorkspaces()) {
|
|
57144
58478
|
if (ws.missing) continue;
|
|
57145
58479
|
const dbPath = workspacePaths(ws.path).castalia;
|
|
57146
|
-
if (!
|
|
58480
|
+
if (!existsSync26(dbPath)) continue;
|
|
57147
58481
|
let store = null;
|
|
57148
58482
|
try {
|
|
57149
58483
|
store = openGraphStore2({ path: dbPath });
|
|
@@ -57174,7 +58508,7 @@ async function gatherReportData(generatedAt) {
|
|
|
57174
58508
|
};
|
|
57175
58509
|
}
|
|
57176
58510
|
async function cmdReport(args2) {
|
|
57177
|
-
const { mkdirSync: mkdirSync8, writeFileSync:
|
|
58511
|
+
const { mkdirSync: mkdirSync8, writeFileSync: writeFileSync20 } = await import("node:fs");
|
|
57178
58512
|
const { renderReport: renderReport2 } = await Promise.resolve().then(() => (init_report_render(), report_render_exports));
|
|
57179
58513
|
const includeFutureVerbs = args2.includes("--future-verbs");
|
|
57180
58514
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -57187,8 +58521,8 @@ async function cmdReport(args2) {
|
|
|
57187
58521
|
const outDir = workspacePaths(ROOT).configDir;
|
|
57188
58522
|
mkdirSync8(outDir, { recursive: true });
|
|
57189
58523
|
const files = renderReport2(data, { includeFutureVerbs });
|
|
57190
|
-
for (const f of files)
|
|
57191
|
-
const indexPath =
|
|
58524
|
+
for (const f of files) writeFileSync20(join28(outDir, f.name), f.html, "utf8");
|
|
58525
|
+
const indexPath = join28(outDir, "report.html");
|
|
57192
58526
|
console.log(`report \u2192 ${indexPath}`);
|
|
57193
58527
|
console.log(
|
|
57194
58528
|
` ${data.repos.length} repo(s) \xB7 ${files.length} file(s) \xB7 ${data.rollup.nodes.toLocaleString("en-US")} nodes`
|
|
@@ -57240,7 +58574,7 @@ function spawnDaemonDetached() {
|
|
|
57240
58574
|
try {
|
|
57241
58575
|
const logPath = daemonLogPath();
|
|
57242
58576
|
try {
|
|
57243
|
-
if (statSync6(logPath).size > 5 * 1024 * 1024)
|
|
58577
|
+
if (statSync6(logPath).size > 5 * 1024 * 1024) renameSync4(logPath, `${logPath}.1`);
|
|
57244
58578
|
} catch {
|
|
57245
58579
|
}
|
|
57246
58580
|
out2 = openSync2(logPath, "a");
|
|
@@ -57306,15 +58640,15 @@ function hookRelayCommand(port, path2) {
|
|
|
57306
58640
|
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 '{}'`;
|
|
57307
58641
|
}
|
|
57308
58642
|
async function installClaudeHooks(port) {
|
|
57309
|
-
const { mkdirSync: mkdirSync8, existsSync:
|
|
57310
|
-
const { join:
|
|
57311
|
-
const dir =
|
|
57312
|
-
if (!
|
|
57313
|
-
const file2 =
|
|
58643
|
+
const { mkdirSync: mkdirSync8, existsSync: existsSync26, readFileSync: readFileSync25, writeFileSync: writeFileSync20 } = await import("node:fs");
|
|
58644
|
+
const { join: join29 } = await import("node:path");
|
|
58645
|
+
const dir = join29(ROOT, ".claude");
|
|
58646
|
+
if (!existsSync26(dir)) mkdirSync8(dir, { recursive: true });
|
|
58647
|
+
const file2 = join29(dir, "settings.json");
|
|
57314
58648
|
let settings = {};
|
|
57315
|
-
if (
|
|
58649
|
+
if (existsSync26(file2)) {
|
|
57316
58650
|
try {
|
|
57317
|
-
settings = JSON.parse(
|
|
58651
|
+
settings = JSON.parse(readFileSync25(file2, "utf8"));
|
|
57318
58652
|
} catch {
|
|
57319
58653
|
console.error(`refusing to overwrite invalid JSON at ${file2}`);
|
|
57320
58654
|
process.exit(2);
|
|
@@ -57360,10 +58694,10 @@ async function installClaudeHooks(port) {
|
|
|
57360
58694
|
dropErrata(list);
|
|
57361
58695
|
list.push({ hooks: [{ type: "command", command: injectCmd }] });
|
|
57362
58696
|
}
|
|
57363
|
-
|
|
58697
|
+
writeFileSync20(file2, JSON.stringify(settings, null, 2) + "\n", "utf8");
|
|
57364
58698
|
console.log(`installed Claude Code hooks \u2192 ${file2}`);
|
|
57365
58699
|
await installClaudeMcpConfig();
|
|
57366
|
-
const claudeMd =
|
|
58700
|
+
const claudeMd = join29(ROOT, "CLAUDE.md");
|
|
57367
58701
|
const recall = writeManagedBlock(claudeMd, { body: RECALL_FIRST_BLOCK });
|
|
57368
58702
|
if (recall.kind === "collision") {
|
|
57369
58703
|
console.warn(
|
|
@@ -57375,15 +58709,15 @@ async function installClaudeHooks(port) {
|
|
|
57375
58709
|
console.log(` endpoint: http://127.0.0.1:${port}/api/hook`);
|
|
57376
58710
|
}
|
|
57377
58711
|
async function installClaudeMcpConfig() {
|
|
57378
|
-
const { mkdirSync: mkdirSync8, existsSync:
|
|
57379
|
-
const { join:
|
|
57380
|
-
const file2 =
|
|
57381
|
-
const dir =
|
|
57382
|
-
if (!
|
|
58712
|
+
const { mkdirSync: mkdirSync8, existsSync: existsSync26, readFileSync: readFileSync25, writeFileSync: writeFileSync20 } = await import("node:fs");
|
|
58713
|
+
const { join: join29, dirname: dirname11 } = await import("node:path");
|
|
58714
|
+
const file2 = join29(ROOT, ".mcp.json");
|
|
58715
|
+
const dir = dirname11(file2);
|
|
58716
|
+
if (!existsSync26(dir)) mkdirSync8(dir, { recursive: true });
|
|
57383
58717
|
let cfg = {};
|
|
57384
|
-
if (
|
|
58718
|
+
if (existsSync26(file2)) {
|
|
57385
58719
|
try {
|
|
57386
|
-
cfg = JSON.parse(
|
|
58720
|
+
cfg = JSON.parse(readFileSync25(file2, "utf8"));
|
|
57387
58721
|
} catch {
|
|
57388
58722
|
console.error(`refusing to overwrite invalid JSON at ${file2}`);
|
|
57389
58723
|
process.exit(2);
|
|
@@ -57391,21 +58725,21 @@ async function installClaudeMcpConfig() {
|
|
|
57391
58725
|
}
|
|
57392
58726
|
cfg.mcpServers ??= {};
|
|
57393
58727
|
cfg.mcpServers["errata"] = errataMcpInvocation();
|
|
57394
|
-
|
|
58728
|
+
writeFileSync20(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
|
|
57395
58729
|
console.log(`installed Claude Code MCP server config \u2192 ${file2}`);
|
|
57396
58730
|
console.log(` Claude Code will spawn \`errata mcp\` on workspace open.`);
|
|
57397
58731
|
console.log(` Tools: errata.search / locate / neighbors / callers_of / what_uses / show / similar`);
|
|
57398
58732
|
}
|
|
57399
58733
|
async function installCursorMcpConfig() {
|
|
57400
|
-
const { mkdirSync: mkdirSync8, existsSync:
|
|
57401
|
-
const { join:
|
|
57402
|
-
const dir =
|
|
57403
|
-
if (!
|
|
57404
|
-
const file2 =
|
|
58734
|
+
const { mkdirSync: mkdirSync8, existsSync: existsSync26, readFileSync: readFileSync25, writeFileSync: writeFileSync20 } = await import("node:fs");
|
|
58735
|
+
const { join: join29 } = await import("node:path");
|
|
58736
|
+
const dir = join29(ROOT, ".cursor");
|
|
58737
|
+
if (!existsSync26(dir)) mkdirSync8(dir, { recursive: true });
|
|
58738
|
+
const file2 = join29(dir, "mcp.json");
|
|
57405
58739
|
let cfg = {};
|
|
57406
|
-
if (
|
|
58740
|
+
if (existsSync26(file2)) {
|
|
57407
58741
|
try {
|
|
57408
|
-
cfg = JSON.parse(
|
|
58742
|
+
cfg = JSON.parse(readFileSync25(file2, "utf8"));
|
|
57409
58743
|
} catch {
|
|
57410
58744
|
console.error(`refusing to overwrite invalid JSON at ${file2}`);
|
|
57411
58745
|
process.exit(2);
|
|
@@ -57413,7 +58747,7 @@ async function installCursorMcpConfig() {
|
|
|
57413
58747
|
}
|
|
57414
58748
|
cfg.mcpServers ??= {};
|
|
57415
58749
|
cfg.mcpServers["errata"] = errataMcpInvocation();
|
|
57416
|
-
|
|
58750
|
+
writeFileSync20(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
|
|
57417
58751
|
console.log(`installed Cursor MCP server config \u2192 ${file2}`);
|
|
57418
58752
|
console.log(` Cursor will spawn \`errata mcp\` on workspace open.`);
|
|
57419
58753
|
console.log(` Tools: errata.search / locate / neighbors / callers_of / what_uses`);
|
|
@@ -57421,16 +58755,16 @@ async function installCursorMcpConfig() {
|
|
|
57421
58755
|
console.log(` \u26A0\uFE0F reload Cursor (Cmd/Ctrl-Shift-P \u2192 "Reload Window") to pick it up.`);
|
|
57422
58756
|
}
|
|
57423
58757
|
async function installCodexHooks(port) {
|
|
57424
|
-
const { mkdirSync: mkdirSync8, existsSync:
|
|
57425
|
-
const { join:
|
|
57426
|
-
const dir =
|
|
57427
|
-
if (!
|
|
57428
|
-
const file2 =
|
|
58758
|
+
const { mkdirSync: mkdirSync8, existsSync: existsSync26, readFileSync: readFileSync25, writeFileSync: writeFileSync20 } = await import("node:fs");
|
|
58759
|
+
const { join: join29 } = await import("node:path");
|
|
58760
|
+
const dir = join29(ROOT, ".codex");
|
|
58761
|
+
if (!existsSync26(dir)) mkdirSync8(dir, { recursive: true });
|
|
58762
|
+
const file2 = join29(dir, "config.toml");
|
|
57429
58763
|
const BEGIN = `# >>> errata hooks (errata-managed)`;
|
|
57430
58764
|
const END = `# <<< errata hooks`;
|
|
57431
58765
|
let existing = "";
|
|
57432
|
-
if (
|
|
57433
|
-
existing =
|
|
58766
|
+
if (existsSync26(file2)) {
|
|
58767
|
+
existing = readFileSync25(file2, "utf8");
|
|
57434
58768
|
const beginIdx = existing.indexOf(BEGIN);
|
|
57435
58769
|
const endIdx = existing.indexOf(END);
|
|
57436
58770
|
if (beginIdx >= 0 && endIdx > beginIdx) {
|
|
@@ -57459,7 +58793,7 @@ ${END}
|
|
|
57459
58793
|
const final = existing.length > 0 && !existing.endsWith("\n") ? `${existing}
|
|
57460
58794
|
|
|
57461
58795
|
${block}` : existing + (existing.endsWith("\n\n") ? "" : "\n") + block;
|
|
57462
|
-
|
|
58796
|
+
writeFileSync20(file2, final, "utf8");
|
|
57463
58797
|
console.log(`installed Codex hooks \u2192 ${file2}`);
|
|
57464
58798
|
console.log(` endpoint: http://127.0.0.1:${port}/api/hook`);
|
|
57465
58799
|
console.log("");
|
|
@@ -57497,8 +58831,35 @@ async function cmdSync(arg) {
|
|
|
57497
58831
|
try {
|
|
57498
58832
|
const res = await fetch(`${lock.webUiUrl}/api/sync`, {
|
|
57499
58833
|
method: "POST",
|
|
57500
|
-
signal: AbortSignal.timeout(
|
|
58834
|
+
signal: AbortSignal.timeout(15 * 6e4)
|
|
57501
58835
|
});
|
|
58836
|
+
if (res.status === 409) {
|
|
58837
|
+
const body2 = await res.json().catch(() => null);
|
|
58838
|
+
const ageMs = typeof body2?.ageMs === "number" ? body2.ageMs : 0;
|
|
58839
|
+
const dur = ageMs >= 6e4 ? `${Math.floor(ageMs / 6e4)}m` : `${Math.max(1, Math.round(ageMs / 1e3))}s`;
|
|
58840
|
+
const stage = body2?.stage ? ` \u2014 stage: ${body2.stage}` : "";
|
|
58841
|
+
const units = typeof body2?.units === "number" ? body2.units : 0;
|
|
58842
|
+
const items = typeof body2?.items === "number" ? body2.items : 0;
|
|
58843
|
+
const chunks = typeof body2?.chunks === "number" ? body2.chunks : 0;
|
|
58844
|
+
const stalledMs = typeof body2?.stalledMs === "number" ? body2.stalledMs : 0;
|
|
58845
|
+
const where = body2?.detail ? ` [${body2.detail}]` : "";
|
|
58846
|
+
const moved = chunks > 0 ? ` \xB7 ${chunks} chunk(s), ${items} shipped, ${units} accepted${where}` : "";
|
|
58847
|
+
console.log(
|
|
58848
|
+
ageMs > 0 ? `sync already running: the daemon has been draining for ${dur}${stage}${moved}. It will finish on its own; nothing new was started.` : "sync already running: the daemon is mid-drain \u2014 it will finish on its own. Nothing new was started."
|
|
58849
|
+
);
|
|
58850
|
+
if (stalledMs > 12e4 && chunks > 0) {
|
|
58851
|
+
const stalledMin = Math.floor(stalledMs / 6e4);
|
|
58852
|
+
console.log(
|
|
58853
|
+
` \u26A0 STALLED: ${chunks} chunk(s) shipped but nothing has moved for ${stalledMin}m \u2014 the lane is looping, not draining. Check \`errata status\` for the backlog depth and daemon.log for the failing lane.`
|
|
58854
|
+
);
|
|
58855
|
+
}
|
|
58856
|
+
if (ageMs > 30 * 6e4) {
|
|
58857
|
+
console.log(
|
|
58858
|
+
" \u26A0 this pass has run past 30 min \u2014 if daemon.log shows no upload progress it may be stranded (a sleep/resume can do this). Restart with: errata stop && errata start"
|
|
58859
|
+
);
|
|
58860
|
+
}
|
|
58861
|
+
return;
|
|
58862
|
+
}
|
|
57502
58863
|
if (!res.ok) {
|
|
57503
58864
|
const detail = await res.text().catch(() => "");
|
|
57504
58865
|
console.error(`sync failed: daemon at ${lock.webUiUrl} returned ${res.status}${detail ? ` \u2014 ${detail}` : ""}`);
|
|
@@ -57509,7 +58870,7 @@ async function cmdSync(arg) {
|
|
|
57509
58870
|
} catch (err2) {
|
|
57510
58871
|
const timedOut = err2 instanceof Error && err2.name === "TimeoutError";
|
|
57511
58872
|
console.error(
|
|
57512
|
-
timedOut ? `sync
|
|
58873
|
+
timedOut ? `sync gave up waiting after 15 min \u2014 the daemon's pass may STILL be running (aborting this request does not cancel it). Check daemon.log before retrying; a retry while it runs answers 409.` : `sync failed: could not reach the running daemon at ${lock.webUiUrl} (${err2 instanceof Error ? err2.message : err2})`
|
|
57513
58874
|
);
|
|
57514
58875
|
process.exit(1);
|
|
57515
58876
|
}
|
|
@@ -57572,7 +58933,19 @@ async function cmdConsent(args2) {
|
|
|
57572
58933
|
console.log(" note: run `errata login` to actually upload (no cloud credential yet).");
|
|
57573
58934
|
}
|
|
57574
58935
|
}
|
|
58936
|
+
function installLogTimestamps() {
|
|
58937
|
+
const ISO_AT_START = /^\[?\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/;
|
|
58938
|
+
for (const level of ["log", "warn", "error"]) {
|
|
58939
|
+
const original = console[level].bind(console);
|
|
58940
|
+
console[level] = (...args2) => {
|
|
58941
|
+
const first = args2[0];
|
|
58942
|
+
if (typeof first === "string" && ISO_AT_START.test(first)) return original(...args2);
|
|
58943
|
+
original(`[${(/* @__PURE__ */ new Date()).toISOString()}]`, ...args2);
|
|
58944
|
+
};
|
|
58945
|
+
}
|
|
58946
|
+
}
|
|
57575
58947
|
async function cmdDash(args2) {
|
|
58948
|
+
installLogTimestamps();
|
|
57576
58949
|
const portIdx = args2.indexOf("--port");
|
|
57577
58950
|
const port = portIdx >= 0 && args2[portIdx + 1] ? Number(args2[portIdx + 1]) : 7891;
|
|
57578
58951
|
const reindexOnStart = !args2.includes("--no-reindex");
|
|
@@ -57734,7 +59107,7 @@ async function cmdDash(args2) {
|
|
|
57734
59107
|
await yieldToLoop2();
|
|
57735
59108
|
try {
|
|
57736
59109
|
const items = selectDurableMemory(handle2.sharedStore, r.engine.profile);
|
|
57737
|
-
const res = bleedRules(
|
|
59110
|
+
const res = bleedRules(join28(r.root, ".claude", "rules"), items);
|
|
57738
59111
|
if (res.written || res.pruned) {
|
|
57739
59112
|
console.log(
|
|
57740
59113
|
`[rules:${r.entry.name}] ${res.written} collective principle(s) \u2192 .claude/rules` + (res.pruned ? `, ${res.pruned} pruned` : "")
|