@inerrata-corporation/errata 2.0.14-dev.3118 → 2.0.14-dev.3125
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 +89 -0
- package/errata.mjs +208 -65
- package/package.json +1 -1
- package/pass-worker.mjs +88 -0
package/consolidate-worker.mjs
CHANGED
|
@@ -16188,6 +16188,71 @@ function installHistoryCacheFloor(db) {
|
|
|
16188
16188
|
});
|
|
16189
16189
|
}
|
|
16190
16190
|
|
|
16191
|
+
// ../../packages/local-graph/src/session-evidence.ts
|
|
16192
|
+
function repairSessionEvidence(input, aliases = /* @__PURE__ */ new Map()) {
|
|
16193
|
+
const mapping = new Map(aliases);
|
|
16194
|
+
const uuid3 = "[a-f0-9]{8}(?:-[a-f0-9]{4}){3}-[a-f0-9]{12}";
|
|
16195
|
+
const codex = new RegExp(`^codex:(?:rollout-.*?)?(${uuid3})$`, "i");
|
|
16196
|
+
const arrays = /* @__PURE__ */ new Set(["sources", "recurrenceSources", "contributors", "inferredContributors", "citeSessions"]);
|
|
16197
|
+
const scalars = /* @__PURE__ */ new Set(["discriminatorSource", "originSession", "sessionId", "sourceSession"]);
|
|
16198
|
+
const discover = (value, key = "") => {
|
|
16199
|
+
if (typeof value === "string" && (arrays.has(key) || scalars.has(key) || key === "citeAnchorHints")) {
|
|
16200
|
+
const match = value.match(codex);
|
|
16201
|
+
if (match) {
|
|
16202
|
+
const canonical = `codex:${match[1].toLowerCase()}`;
|
|
16203
|
+
mapping.set(value, canonical);
|
|
16204
|
+
mapping.set(match[1].toLowerCase(), canonical);
|
|
16205
|
+
}
|
|
16206
|
+
} else if (Array.isArray(value)) value.forEach((v) => discover(v, key));
|
|
16207
|
+
else if (value && typeof value === "object") {
|
|
16208
|
+
for (const [k, v] of Object.entries(value)) discover(v, key === "citeAnchorHints" ? key : k);
|
|
16209
|
+
}
|
|
16210
|
+
};
|
|
16211
|
+
discover(input);
|
|
16212
|
+
const rewrite = (value, key = "") => {
|
|
16213
|
+
if (typeof value === "string" && (arrays.has(key) || scalars.has(key) || key === "citeAnchorHints")) {
|
|
16214
|
+
return mapping.get(value) ?? mapping.get(value.toLowerCase()) ?? value;
|
|
16215
|
+
}
|
|
16216
|
+
if (Array.isArray(value)) {
|
|
16217
|
+
const values = value.map((v) => rewrite(v, key));
|
|
16218
|
+
return arrays.has(key) || key === "citeAnchorHints" ? [...new Set(values)] : values;
|
|
16219
|
+
}
|
|
16220
|
+
if (!value || typeof value !== "object") return value;
|
|
16221
|
+
const before = value;
|
|
16222
|
+
const after = Object.fromEntries(Object.entries(before).map(([k, v]) => [k, rewrite(v, key === "citeAnchorHints" ? key : k)]));
|
|
16223
|
+
for (const field of ["sources", "contributors"]) {
|
|
16224
|
+
const old = before[field], next = after[field];
|
|
16225
|
+
if (!Array.isArray(old) || !Array.isArray(next) || old.length <= next.length) continue;
|
|
16226
|
+
after["sessionAliasRepair"] = { originalCount: old.length, distinctCount: next.length };
|
|
16227
|
+
if (field === "sources" && typeof after["corroborations"] === "number") {
|
|
16228
|
+
after["corroborations"] = Math.min(after["corroborations"], Math.max(0, next.length - 1));
|
|
16229
|
+
if (after["corroborations"] === 0) after["provisional"] = true;
|
|
16230
|
+
}
|
|
16231
|
+
if (field === "contributors" && typeof after["confirmed"] === "number") {
|
|
16232
|
+
after["preAliasRepairConfirmed"] = after["confirmed"];
|
|
16233
|
+
after["confirmed"] = Math.min(after["confirmed"], next.length);
|
|
16234
|
+
}
|
|
16235
|
+
}
|
|
16236
|
+
return after;
|
|
16237
|
+
};
|
|
16238
|
+
const repaired = rewrite(input);
|
|
16239
|
+
const source = repaired["discriminatorSource"];
|
|
16240
|
+
if (typeof source === "string") {
|
|
16241
|
+
const global = repaired["perContext"]?.["*"];
|
|
16242
|
+
const contributors = Array.isArray(global?.["contributors"]) ? global["contributors"] : [];
|
|
16243
|
+
const inferred = new Set(Array.isArray(global?.["inferredContributors"]) ? global["inferredContributors"] : []);
|
|
16244
|
+
if (contributors.includes(source) || contributors.filter((id) => !inferred.has(id)).length < 2) {
|
|
16245
|
+
repaired["withdrawnDiscriminator"] = repaired["discriminator"];
|
|
16246
|
+
repaired["discriminatorWithdrawalReason"] = "insufficient-independent-witnesses";
|
|
16247
|
+
repaired["provisional"] = true;
|
|
16248
|
+
delete repaired["discriminator"];
|
|
16249
|
+
delete repaired["discriminatorSource"];
|
|
16250
|
+
delete repaired["discriminatorAsked"];
|
|
16251
|
+
}
|
|
16252
|
+
}
|
|
16253
|
+
return repaired;
|
|
16254
|
+
}
|
|
16255
|
+
|
|
16191
16256
|
// ../../packages/local-graph/src/store.ts
|
|
16192
16257
|
var LOCAL_RULE_OVERRIDES = {
|
|
16193
16258
|
ANCHORED_AT: {
|
|
@@ -16432,6 +16497,12 @@ var SqliteGraphStore = class {
|
|
|
16432
16497
|
}
|
|
16433
16498
|
this.db.exec(TEMPORAL_INDEX_SQL);
|
|
16434
16499
|
installHistoryCacheFloor(this.db);
|
|
16500
|
+
if (!this.db.prepare("SELECT value FROM store_meta WHERE key = 'session-evidence-v1'").get()) {
|
|
16501
|
+
this.db.transaction(() => {
|
|
16502
|
+
this.repairSessionAliases();
|
|
16503
|
+
this.db.prepare("INSERT OR REPLACE INTO store_meta (key, value) VALUES ('session-evidence-v1', 'done')").run();
|
|
16504
|
+
});
|
|
16505
|
+
}
|
|
16435
16506
|
this.stmts = {
|
|
16436
16507
|
insertNode: this.db.prepare(`
|
|
16437
16508
|
INSERT INTO nodes (
|
|
@@ -16680,6 +16751,23 @@ var SqliteGraphStore = class {
|
|
|
16680
16751
|
this.db.prepare("UPDATE schema_version SET version = ?").run(SCHEMA_VERSION);
|
|
16681
16752
|
});
|
|
16682
16753
|
}
|
|
16754
|
+
repairSessionAliases(canonical, aliases = []) {
|
|
16755
|
+
const mapping = new Map(aliases.map((alias) => [alias, canonical]));
|
|
16756
|
+
let changed = 0;
|
|
16757
|
+
for (const table of ["nodes", "edges"]) {
|
|
16758
|
+
const predicates = canonical ? aliases.map(() => "instr(attrs_json, ?) > 0") : ["instr(attrs_json, 'codex:') > 0", "instr(attrs_json, 'discriminatorSource') > 0"];
|
|
16759
|
+
if (!predicates.length) continue;
|
|
16760
|
+
const rows = this.db.prepare(`SELECT id, attrs_json FROM ${table} WHERE ${predicates.join(" OR ")}`).all(...canonical ? aliases : []);
|
|
16761
|
+
const update = this.db.prepare(`UPDATE ${table} SET attrs_json = ?${table === "edges" ? ", type = CASE WHEN type = 'CONFIRMS' AND json_extract(?, '$.provisional') = 1 THEN 'INDICATES' ELSE type END" : ""} WHERE id = ?`);
|
|
16762
|
+
for (const row of rows) {
|
|
16763
|
+
const attrs = JSON.stringify(repairSessionEvidence(JSON.parse(row.attrs_json), mapping));
|
|
16764
|
+
if (attrs === row.attrs_json) continue;
|
|
16765
|
+
update.run(...table === "edges" ? [attrs, attrs, row.id] : [attrs, row.id]);
|
|
16766
|
+
changed++;
|
|
16767
|
+
}
|
|
16768
|
+
}
|
|
16769
|
+
return changed;
|
|
16770
|
+
}
|
|
16683
16771
|
deleteNode(id) {
|
|
16684
16772
|
this.stmts.deleteNode.run(id);
|
|
16685
16773
|
}
|
|
@@ -17761,6 +17849,7 @@ function recordTriageObservation(l2, obs, ts) {
|
|
|
17761
17849
|
}
|
|
17762
17850
|
const discriminator = obs.discriminator ?? existing?.attrs["discriminator"];
|
|
17763
17851
|
const attrs = {
|
|
17852
|
+
...existing?.attrs,
|
|
17764
17853
|
driftKind: obs.driftKind ?? existing?.attrs["driftKind"] ?? DRIFT_KIND.RELOCATION,
|
|
17765
17854
|
perContext,
|
|
17766
17855
|
// A discriminator (now or previously supplied) promotes the route to a router.
|
package/errata.mjs
CHANGED
|
@@ -18007,6 +18007,76 @@ var init_history_cache_floor = __esm({
|
|
|
18007
18007
|
}
|
|
18008
18008
|
});
|
|
18009
18009
|
|
|
18010
|
+
// ../../packages/local-graph/src/session-evidence.ts
|
|
18011
|
+
function repairSessionEvidence(input, aliases = /* @__PURE__ */ new Map()) {
|
|
18012
|
+
const mapping = new Map(aliases);
|
|
18013
|
+
const uuid3 = "[a-f0-9]{8}(?:-[a-f0-9]{4}){3}-[a-f0-9]{12}";
|
|
18014
|
+
const codex = new RegExp(`^codex:(?:rollout-.*?)?(${uuid3})$`, "i");
|
|
18015
|
+
const arrays = /* @__PURE__ */ new Set(["sources", "recurrenceSources", "contributors", "inferredContributors", "citeSessions"]);
|
|
18016
|
+
const scalars = /* @__PURE__ */ new Set(["discriminatorSource", "originSession", "sessionId", "sourceSession"]);
|
|
18017
|
+
const discover = (value, key = "") => {
|
|
18018
|
+
if (typeof value === "string" && (arrays.has(key) || scalars.has(key) || key === "citeAnchorHints")) {
|
|
18019
|
+
const match2 = value.match(codex);
|
|
18020
|
+
if (match2) {
|
|
18021
|
+
const canonical = `codex:${match2[1].toLowerCase()}`;
|
|
18022
|
+
mapping.set(value, canonical);
|
|
18023
|
+
mapping.set(match2[1].toLowerCase(), canonical);
|
|
18024
|
+
}
|
|
18025
|
+
} else if (Array.isArray(value)) value.forEach((v) => discover(v, key));
|
|
18026
|
+
else if (value && typeof value === "object") {
|
|
18027
|
+
for (const [k, v] of Object.entries(value)) discover(v, key === "citeAnchorHints" ? key : k);
|
|
18028
|
+
}
|
|
18029
|
+
};
|
|
18030
|
+
discover(input);
|
|
18031
|
+
const rewrite = (value, key = "") => {
|
|
18032
|
+
if (typeof value === "string" && (arrays.has(key) || scalars.has(key) || key === "citeAnchorHints")) {
|
|
18033
|
+
return mapping.get(value) ?? mapping.get(value.toLowerCase()) ?? value;
|
|
18034
|
+
}
|
|
18035
|
+
if (Array.isArray(value)) {
|
|
18036
|
+
const values = value.map((v) => rewrite(v, key));
|
|
18037
|
+
return arrays.has(key) || key === "citeAnchorHints" ? [...new Set(values)] : values;
|
|
18038
|
+
}
|
|
18039
|
+
if (!value || typeof value !== "object") return value;
|
|
18040
|
+
const before = value;
|
|
18041
|
+
const after = Object.fromEntries(Object.entries(before).map(([k, v]) => [k, rewrite(v, key === "citeAnchorHints" ? key : k)]));
|
|
18042
|
+
for (const field of ["sources", "contributors"]) {
|
|
18043
|
+
const old = before[field], next = after[field];
|
|
18044
|
+
if (!Array.isArray(old) || !Array.isArray(next) || old.length <= next.length) continue;
|
|
18045
|
+
after["sessionAliasRepair"] = { originalCount: old.length, distinctCount: next.length };
|
|
18046
|
+
if (field === "sources" && typeof after["corroborations"] === "number") {
|
|
18047
|
+
after["corroborations"] = Math.min(after["corroborations"], Math.max(0, next.length - 1));
|
|
18048
|
+
if (after["corroborations"] === 0) after["provisional"] = true;
|
|
18049
|
+
}
|
|
18050
|
+
if (field === "contributors" && typeof after["confirmed"] === "number") {
|
|
18051
|
+
after["preAliasRepairConfirmed"] = after["confirmed"];
|
|
18052
|
+
after["confirmed"] = Math.min(after["confirmed"], next.length);
|
|
18053
|
+
}
|
|
18054
|
+
}
|
|
18055
|
+
return after;
|
|
18056
|
+
};
|
|
18057
|
+
const repaired = rewrite(input);
|
|
18058
|
+
const source = repaired["discriminatorSource"];
|
|
18059
|
+
if (typeof source === "string") {
|
|
18060
|
+
const global2 = repaired["perContext"]?.["*"];
|
|
18061
|
+
const contributors = Array.isArray(global2?.["contributors"]) ? global2["contributors"] : [];
|
|
18062
|
+
const inferred = new Set(Array.isArray(global2?.["inferredContributors"]) ? global2["inferredContributors"] : []);
|
|
18063
|
+
if (contributors.includes(source) || contributors.filter((id) => !inferred.has(id)).length < 2) {
|
|
18064
|
+
repaired["withdrawnDiscriminator"] = repaired["discriminator"];
|
|
18065
|
+
repaired["discriminatorWithdrawalReason"] = "insufficient-independent-witnesses";
|
|
18066
|
+
repaired["provisional"] = true;
|
|
18067
|
+
delete repaired["discriminator"];
|
|
18068
|
+
delete repaired["discriminatorSource"];
|
|
18069
|
+
delete repaired["discriminatorAsked"];
|
|
18070
|
+
}
|
|
18071
|
+
}
|
|
18072
|
+
return repaired;
|
|
18073
|
+
}
|
|
18074
|
+
var init_session_evidence = __esm({
|
|
18075
|
+
"../../packages/local-graph/src/session-evidence.ts"() {
|
|
18076
|
+
"use strict";
|
|
18077
|
+
}
|
|
18078
|
+
});
|
|
18079
|
+
|
|
18010
18080
|
// ../../packages/local-graph/src/store.ts
|
|
18011
18081
|
function localEdgeViolation(fromLabel, type, toLabel) {
|
|
18012
18082
|
if (type in LOCAL_RULE_OVERRIDES) {
|
|
@@ -18090,6 +18160,7 @@ var init_store = __esm({
|
|
|
18090
18160
|
init_src2();
|
|
18091
18161
|
init_src();
|
|
18092
18162
|
init_history_cache_floor();
|
|
18163
|
+
init_session_evidence();
|
|
18093
18164
|
LOCAL_RULE_OVERRIDES = {
|
|
18094
18165
|
ANCHORED_AT: {
|
|
18095
18166
|
from: EDGE_RULES["ANCHORED_AT"]?.from,
|
|
@@ -18261,6 +18332,12 @@ CREATE INDEX IF NOT EXISTS nodes_anchor_hint_path ON nodes(json_extract(attrs_js
|
|
|
18261
18332
|
}
|
|
18262
18333
|
this.db.exec(TEMPORAL_INDEX_SQL);
|
|
18263
18334
|
installHistoryCacheFloor(this.db);
|
|
18335
|
+
if (!this.db.prepare("SELECT value FROM store_meta WHERE key = 'session-evidence-v1'").get()) {
|
|
18336
|
+
this.db.transaction(() => {
|
|
18337
|
+
this.repairSessionAliases();
|
|
18338
|
+
this.db.prepare("INSERT OR REPLACE INTO store_meta (key, value) VALUES ('session-evidence-v1', 'done')").run();
|
|
18339
|
+
});
|
|
18340
|
+
}
|
|
18264
18341
|
this.stmts = {
|
|
18265
18342
|
insertNode: this.db.prepare(`
|
|
18266
18343
|
INSERT INTO nodes (
|
|
@@ -18509,6 +18586,23 @@ CREATE INDEX IF NOT EXISTS nodes_anchor_hint_path ON nodes(json_extract(attrs_js
|
|
|
18509
18586
|
this.db.prepare("UPDATE schema_version SET version = ?").run(SCHEMA_VERSION);
|
|
18510
18587
|
});
|
|
18511
18588
|
}
|
|
18589
|
+
repairSessionAliases(canonical, aliases = []) {
|
|
18590
|
+
const mapping = new Map(aliases.map((alias) => [alias, canonical]));
|
|
18591
|
+
let changed = 0;
|
|
18592
|
+
for (const table of ["nodes", "edges"]) {
|
|
18593
|
+
const predicates = canonical ? aliases.map(() => "instr(attrs_json, ?) > 0") : ["instr(attrs_json, 'codex:') > 0", "instr(attrs_json, 'discriminatorSource') > 0"];
|
|
18594
|
+
if (!predicates.length) continue;
|
|
18595
|
+
const rows = this.db.prepare(`SELECT id, attrs_json FROM ${table} WHERE ${predicates.join(" OR ")}`).all(...canonical ? aliases : []);
|
|
18596
|
+
const update = this.db.prepare(`UPDATE ${table} SET attrs_json = ?${table === "edges" ? ", type = CASE WHEN type = 'CONFIRMS' AND json_extract(?, '$.provisional') = 1 THEN 'INDICATES' ELSE type END" : ""} WHERE id = ?`);
|
|
18597
|
+
for (const row of rows) {
|
|
18598
|
+
const attrs = JSON.stringify(repairSessionEvidence(JSON.parse(row.attrs_json), mapping));
|
|
18599
|
+
if (attrs === row.attrs_json) continue;
|
|
18600
|
+
update.run(...table === "edges" ? [attrs, attrs, row.id] : [attrs, row.id]);
|
|
18601
|
+
changed++;
|
|
18602
|
+
}
|
|
18603
|
+
}
|
|
18604
|
+
return changed;
|
|
18605
|
+
}
|
|
18512
18606
|
deleteNode(id) {
|
|
18513
18607
|
this.stmts.deleteNode.run(id);
|
|
18514
18608
|
}
|
|
@@ -23027,6 +23121,7 @@ function recordTriageObservation(l2, obs, ts) {
|
|
|
23027
23121
|
}
|
|
23028
23122
|
const discriminator = obs.discriminator ?? existing?.attrs["discriminator"];
|
|
23029
23123
|
const attrs = {
|
|
23124
|
+
...existing?.attrs,
|
|
23030
23125
|
driftKind: obs.driftKind ?? existing?.attrs["driftKind"] ?? DRIFT_KIND.RELOCATION,
|
|
23031
23126
|
perContext,
|
|
23032
23127
|
// A discriminator (now or previously supplied) promotes the route to a router.
|
|
@@ -23265,7 +23360,7 @@ function induceTriage(l2, opts) {
|
|
|
23265
23360
|
return report;
|
|
23266
23361
|
}
|
|
23267
23362
|
function pendingDiscriminators(l2, opts = {}) {
|
|
23268
|
-
const minSources = opts.minSources ??
|
|
23363
|
+
const minSources = opts.minSources ?? 2;
|
|
23269
23364
|
const minObservations = opts.minObservations ?? 2;
|
|
23270
23365
|
const out2 = [];
|
|
23271
23366
|
for (const triage of l2.findNodesByLabel("Triage")) {
|
|
@@ -23300,6 +23395,12 @@ function promoteRouteWithDiscriminator(l2, routeId, discriminator, ts, source) {
|
|
|
23300
23395
|
if (isUnfilledPlaceholder(test)) return false;
|
|
23301
23396
|
const existing = l2.getEdge(routeId);
|
|
23302
23397
|
if (!existing || !ROUTE_EDGE_TYPES.includes(existing.type)) return false;
|
|
23398
|
+
const global2 = (existing.attrs["perContext"] ?? {})[TRIAGE_GLOBAL_BUCKET] ?? {};
|
|
23399
|
+
const contributors = new Set(global2.contributors ?? []);
|
|
23400
|
+
const inferred = new Set(global2.inferredContributors ?? []);
|
|
23401
|
+
const witnesses = [...contributors].filter((id) => !inferred.has(id));
|
|
23402
|
+
if (!source || contributors.has(source) || witnesses.length < 2) return false;
|
|
23403
|
+
if (existing.attrs["discriminator"] && existing.attrs["discriminator"] !== test) return false;
|
|
23303
23404
|
const attrs = {
|
|
23304
23405
|
...existing.attrs,
|
|
23305
23406
|
discriminator: test,
|
|
@@ -31164,26 +31265,26 @@ function buildFileLexicon(store) {
|
|
|
31164
31265
|
for (const n of store.findNodesByLabel("File")) {
|
|
31165
31266
|
const relPath = typeof n.attrs["relPath"] === "string" && n.attrs["relPath"].length > 0 ? n.attrs["relPath"] : n.description;
|
|
31166
31267
|
if (!relPath) continue;
|
|
31167
|
-
const
|
|
31168
|
-
if (!
|
|
31169
|
-
entries.push({ relPath, basename:
|
|
31170
|
-
basenameCount.set(
|
|
31171
|
-
const stem =
|
|
31268
|
+
const basename9 = relPath.split("/").pop();
|
|
31269
|
+
if (!basename9.includes(".")) continue;
|
|
31270
|
+
entries.push({ relPath, basename: basename9 });
|
|
31271
|
+
basenameCount.set(basename9, (basenameCount.get(basename9) ?? 0) + 1);
|
|
31272
|
+
const stem = basename9.slice(0, basename9.indexOf("."));
|
|
31172
31273
|
if (isBareMatchableStem(stem)) {
|
|
31173
31274
|
let s = stemRelPaths.get(stem);
|
|
31174
31275
|
if (!s) stemRelPaths.set(stem, s = /* @__PURE__ */ new Set());
|
|
31175
31276
|
s.add(relPath);
|
|
31176
31277
|
}
|
|
31177
31278
|
}
|
|
31178
|
-
for (const { relPath, basename:
|
|
31279
|
+
for (const { relPath, basename: basename9 } of entries) {
|
|
31179
31280
|
const entry = { relPath };
|
|
31180
|
-
if (relPath !==
|
|
31181
|
-
const conventional = CONVENTION_FILENAMES.has(
|
|
31182
|
-
if (!conventional && !byKey.has(
|
|
31183
|
-
const list = byBasename.get(
|
|
31281
|
+
if (relPath !== basename9) byKey.set(relPath, entry);
|
|
31282
|
+
const conventional = CONVENTION_FILENAMES.has(basename9) || (basenameCount.get(basename9) ?? 0) >= CONVENTION_BASENAME_MIN_FILES;
|
|
31283
|
+
if (!conventional && !byKey.has(basename9)) byKey.set(basename9, entry);
|
|
31284
|
+
const list = byBasename.get(basename9);
|
|
31184
31285
|
if (list) list.push(entry);
|
|
31185
|
-
else byBasename.set(
|
|
31186
|
-
const stem =
|
|
31286
|
+
else byBasename.set(basename9, [entry]);
|
|
31287
|
+
const stem = basename9.slice(0, basename9.indexOf("."));
|
|
31187
31288
|
if (isBareMatchableStem(stem) && !CONVENTION_STEMS.has(stem) && !byStem.has(stem)) {
|
|
31188
31289
|
const dirStems = new Set(
|
|
31189
31290
|
[...stemRelPaths.get(stem) ?? []].map((p) => {
|
|
@@ -31200,8 +31301,8 @@ function resolveFileToken(token, lexicon) {
|
|
|
31200
31301
|
const exact = lexicon.byKey.get(token);
|
|
31201
31302
|
if (exact) return exact;
|
|
31202
31303
|
if (!token.includes("/")) return null;
|
|
31203
|
-
const
|
|
31204
|
-
for (const entry of lexicon.byBasename.get(
|
|
31304
|
+
const basename9 = token.split("/").pop();
|
|
31305
|
+
for (const entry of lexicon.byBasename.get(basename9) ?? []) {
|
|
31205
31306
|
if (entry.relPath === token || entry.relPath.endsWith(`/${token}`)) return entry;
|
|
31206
31307
|
}
|
|
31207
31308
|
return null;
|
|
@@ -31226,9 +31327,9 @@ function fileRolePhrase(relPath, level = 1) {
|
|
|
31226
31327
|
return "a source file";
|
|
31227
31328
|
}
|
|
31228
31329
|
function isSourceFileToken(token) {
|
|
31229
|
-
const
|
|
31230
|
-
if (CONVENTION_FILENAMES.has(
|
|
31231
|
-
const ext =
|
|
31330
|
+
const basename9 = token.split(/[/\\]/).pop() ?? token;
|
|
31331
|
+
if (CONVENTION_FILENAMES.has(basename9)) return false;
|
|
31332
|
+
const ext = basename9.split(".").pop();
|
|
31232
31333
|
return ext !== void 0 && SOURCE_EXTENSIONS.has(ext.toLowerCase());
|
|
31233
31334
|
}
|
|
31234
31335
|
function generalizeFileRefs(text, fileLexicon, level = 1) {
|
|
@@ -72764,7 +72865,7 @@ init_config();
|
|
|
72764
72865
|
// src/engine.ts
|
|
72765
72866
|
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
72766
72867
|
import { existsSync as existsSync25, statSync as statSync8, appendFileSync as appendFileSync4, readdirSync as readdirSync10, renameSync as renameSync3, readFileSync as readFileSync28, writeFileSync as writeFileSync21 } from "node:fs";
|
|
72767
|
-
import { join as join34, relative as relative6, sep as sep4 } from "node:path";
|
|
72868
|
+
import { basename as basename7, join as join34, relative as relative6, sep as sep4 } from "node:path";
|
|
72768
72869
|
|
|
72769
72870
|
// src/source-watcher.ts
|
|
72770
72871
|
import { EventEmitter as EventEmitter2 } from "node:events";
|
|
@@ -72924,10 +73025,10 @@ var ReaddirpStream = class extends Readable2 {
|
|
|
72924
73025
|
}
|
|
72925
73026
|
async _formatEntry(dirent, path2) {
|
|
72926
73027
|
let entry;
|
|
72927
|
-
const
|
|
73028
|
+
const basename9 = this._isDirent ? dirent.name : dirent;
|
|
72928
73029
|
try {
|
|
72929
|
-
const fullPath = presolve(pjoin(path2,
|
|
72930
|
-
entry = { path: prelative(this._root, fullPath), fullPath, basename:
|
|
73030
|
+
const fullPath = presolve(pjoin(path2, basename9));
|
|
73031
|
+
entry = { path: prelative(this._root, fullPath), fullPath, basename: basename9 };
|
|
72931
73032
|
entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
|
|
72932
73033
|
} catch (err2) {
|
|
72933
73034
|
this._onError(err2);
|
|
@@ -73466,9 +73567,9 @@ var NodeFsHandler = class {
|
|
|
73466
73567
|
_watchWithNodeFs(path2, listener) {
|
|
73467
73568
|
const opts = this.fsw.options;
|
|
73468
73569
|
const directory = sysPath.dirname(path2);
|
|
73469
|
-
const
|
|
73570
|
+
const basename9 = sysPath.basename(path2);
|
|
73470
73571
|
const parent = this.fsw._getWatchedDir(directory);
|
|
73471
|
-
parent.add(
|
|
73572
|
+
parent.add(basename9);
|
|
73472
73573
|
const absolutePath = sysPath.resolve(path2);
|
|
73473
73574
|
const options = {
|
|
73474
73575
|
persistent: opts.persistent
|
|
@@ -73478,7 +73579,7 @@ var NodeFsHandler = class {
|
|
|
73478
73579
|
let closer;
|
|
73479
73580
|
if (opts.usePolling) {
|
|
73480
73581
|
const enableBin = opts.interval !== opts.binaryInterval;
|
|
73481
|
-
options.interval = enableBin && isBinaryPath(
|
|
73582
|
+
options.interval = enableBin && isBinaryPath(basename9) ? opts.binaryInterval : opts.interval;
|
|
73482
73583
|
closer = setFsWatchFileListener(path2, absolutePath, options, {
|
|
73483
73584
|
listener,
|
|
73484
73585
|
rawEmitter: this.fsw._emitRaw
|
|
@@ -73501,10 +73602,10 @@ var NodeFsHandler = class {
|
|
|
73501
73602
|
return;
|
|
73502
73603
|
}
|
|
73503
73604
|
const dirname14 = sysPath.dirname(file2);
|
|
73504
|
-
const
|
|
73605
|
+
const basename9 = sysPath.basename(file2);
|
|
73505
73606
|
const parent = this.fsw._getWatchedDir(dirname14);
|
|
73506
73607
|
let prevStats = stats;
|
|
73507
|
-
if (parent.has(
|
|
73608
|
+
if (parent.has(basename9))
|
|
73508
73609
|
return;
|
|
73509
73610
|
const listener = async (path2, newStats) => {
|
|
73510
73611
|
if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file2, 5))
|
|
@@ -73529,9 +73630,9 @@ var NodeFsHandler = class {
|
|
|
73529
73630
|
prevStats = newStats2;
|
|
73530
73631
|
}
|
|
73531
73632
|
} catch (error48) {
|
|
73532
|
-
this.fsw._remove(dirname14,
|
|
73633
|
+
this.fsw._remove(dirname14, basename9);
|
|
73533
73634
|
}
|
|
73534
|
-
} else if (parent.has(
|
|
73635
|
+
} else if (parent.has(basename9)) {
|
|
73535
73636
|
const at = newStats.atimeMs;
|
|
73536
73637
|
const mt = newStats.mtimeMs;
|
|
73537
73638
|
if (!at || at <= mt || mt !== prevStats.mtimeMs) {
|
|
@@ -74811,6 +74912,16 @@ import { closeSync, existsSync as existsSync16, fstatSync, openSync, readdirSync
|
|
|
74811
74912
|
import { basename as basename5, delimiter, dirname as dirname10, join as join20, normalize as normalize3 } from "node:path";
|
|
74812
74913
|
import { homedir as homedir4 } from "node:os";
|
|
74813
74914
|
import { createHash as createHash16 } from "node:crypto";
|
|
74915
|
+
function completeJsonlPrefix(buf) {
|
|
74916
|
+
const end = buf.lastIndexOf(10) + 1;
|
|
74917
|
+
if (end === buf.length) return end;
|
|
74918
|
+
try {
|
|
74919
|
+
JSON.parse(buf.subarray(end).toString("utf8"));
|
|
74920
|
+
return buf.length;
|
|
74921
|
+
} catch {
|
|
74922
|
+
return end;
|
|
74923
|
+
}
|
|
74924
|
+
}
|
|
74814
74925
|
function readFrom(path2, fromByte, maxBytes) {
|
|
74815
74926
|
let fd;
|
|
74816
74927
|
try {
|
|
@@ -74827,11 +74938,12 @@ function readFrom(path2, fromByte, maxBytes) {
|
|
|
74827
74938
|
for (; ; ) {
|
|
74828
74939
|
const len = Math.min(cap, remaining);
|
|
74829
74940
|
const buf = Buffer.allocUnsafe(len);
|
|
74830
|
-
readSync(fd, buf, 0, len, start2);
|
|
74831
|
-
if (len >= remaining) {
|
|
74832
|
-
|
|
74941
|
+
const read2 = readSync(fd, buf, 0, len, start2);
|
|
74942
|
+
if (len >= remaining || read2 < len) {
|
|
74943
|
+
const end = completeJsonlPrefix(buf.subarray(0, read2));
|
|
74944
|
+
return { text: buf.subarray(0, end).toString("utf8"), nextOffset: start2 + end, more: false, ioFailed: false };
|
|
74833
74945
|
}
|
|
74834
|
-
const nl = buf.lastIndexOf(10);
|
|
74946
|
+
const nl = buf.subarray(0, read2).lastIndexOf(10);
|
|
74835
74947
|
if (nl >= 0) {
|
|
74836
74948
|
return {
|
|
74837
74949
|
text: buf.subarray(0, nl + 1).toString("utf8"),
|
|
@@ -74848,41 +74960,30 @@ function readFrom(path2, fromByte, maxBytes) {
|
|
|
74848
74960
|
closeSync(fd);
|
|
74849
74961
|
}
|
|
74850
74962
|
}
|
|
74851
|
-
function transcriptSize(path2) {
|
|
74852
|
-
try {
|
|
74853
|
-
const fd = openSync(path2, "r");
|
|
74854
|
-
try {
|
|
74855
|
-
return fstatSync(fd).size;
|
|
74856
|
-
} finally {
|
|
74857
|
-
closeSync(fd);
|
|
74858
|
-
}
|
|
74859
|
-
} catch {
|
|
74860
|
-
return 0;
|
|
74861
|
-
}
|
|
74862
|
-
}
|
|
74863
74963
|
function readTail(path2, maxBytes) {
|
|
74864
74964
|
return readTailWithLosses(path2, maxBytes).text;
|
|
74865
74965
|
}
|
|
74866
|
-
function readTailWithLosses(path2, maxBytes) {
|
|
74966
|
+
function readTailWithLosses(path2, maxBytes, completeLinesOnly = false) {
|
|
74867
74967
|
let fd;
|
|
74868
74968
|
try {
|
|
74869
74969
|
fd = openSync(path2, "r");
|
|
74870
74970
|
} catch {
|
|
74871
|
-
return { text: "", bytesUnreachable: 0, parseStartByte: 0, ioFailed: true };
|
|
74971
|
+
return { text: "", bytesUnreachable: 0, parseStartByte: 0, ioFailed: true, nextOffset: 0 };
|
|
74872
74972
|
}
|
|
74873
74973
|
try {
|
|
74874
74974
|
const size = fstatSync(fd).size;
|
|
74875
74975
|
const start2 = Math.max(0, size - maxBytes);
|
|
74876
74976
|
const len = size - start2;
|
|
74877
|
-
if (len <= 0) return { text: "", bytesUnreachable: 0, parseStartByte: 0, ioFailed: false };
|
|
74977
|
+
if (len <= 0) return { text: "", bytesUnreachable: 0, parseStartByte: 0, ioFailed: false, nextOffset: 0 };
|
|
74878
74978
|
const buf = Buffer.allocUnsafe(len);
|
|
74879
|
-
readSync(fd, buf, 0, len, start2);
|
|
74880
|
-
const
|
|
74979
|
+
const read2 = readSync(fd, buf, 0, len, start2);
|
|
74980
|
+
const end = completeLinesOnly ? completeJsonlPrefix(buf.subarray(0, read2)) : read2;
|
|
74981
|
+
const text = buf.subarray(0, end).toString("utf8");
|
|
74881
74982
|
const firstNewline = buf.indexOf(10);
|
|
74882
74983
|
const parseStartByte = firstNewline < 0 ? start2 : start2 + firstNewline + 1 - Buffer.byteLength(buf.subarray(0, firstNewline + 1).toString("utf8"));
|
|
74883
|
-
return { text, bytesUnreachable: start2, parseStartByte, ioFailed: false };
|
|
74984
|
+
return { text, bytesUnreachable: start2, parseStartByte, ioFailed: false, nextOffset: start2 + end };
|
|
74884
74985
|
} catch {
|
|
74885
|
-
return { text: "", bytesUnreachable: 0, parseStartByte: 0, ioFailed: true };
|
|
74986
|
+
return { text: "", bytesUnreachable: 0, parseStartByte: 0, ioFailed: true, nextOffset: 0 };
|
|
74886
74987
|
} finally {
|
|
74887
74988
|
closeSync(fd);
|
|
74888
74989
|
}
|
|
@@ -74945,10 +75046,11 @@ function isUserTurnBoundary(obj) {
|
|
|
74945
75046
|
return blocks.some((b) => b["type"] === "text");
|
|
74946
75047
|
}
|
|
74947
75048
|
function readAssistantTurnsWithLosses(transcriptPath, includeThinking = true, maxBytes = 2e6) {
|
|
74948
|
-
const tail = readTailWithLosses(transcriptPath, maxBytes);
|
|
75049
|
+
const tail = readTailWithLosses(transcriptPath, maxBytes, true);
|
|
74949
75050
|
const parsed = parseAssistantTurns(tail.text, includeThinking, false, tail.parseStartByte);
|
|
74950
75051
|
return {
|
|
74951
75052
|
turns: parsed.turns,
|
|
75053
|
+
nextOffset: tail.nextOffset,
|
|
74952
75054
|
losses: {
|
|
74953
75055
|
parseFailures: parsed.parseFailures,
|
|
74954
75056
|
ioFailed: tail.ioFailed,
|
|
@@ -75259,7 +75361,13 @@ function codexSessionRoots(env2 = process.env, home = homedir4()) {
|
|
|
75259
75361
|
roots.add(join20(home, ".codex", "sessions"));
|
|
75260
75362
|
return [...roots];
|
|
75261
75363
|
}
|
|
75262
|
-
function
|
|
75364
|
+
function readCodexRolloutIdentity(path2) {
|
|
75365
|
+
const legacy = `codex:${basename5(path2, ".jsonl")}`;
|
|
75366
|
+
const identity = (cwd, id) => {
|
|
75367
|
+
const uuid3 = typeof id === "string" && /^[a-f0-9]{8}(?:-[a-f0-9]{4}){3}-[a-f0-9]{12}$/i.test(id) ? id.toLowerCase() : basename5(path2, ".jsonl").match(/([a-f0-9]{8}(?:-[a-f0-9]{4}){3}-[a-f0-9]{12})$/i)?.[1]?.toLowerCase();
|
|
75368
|
+
const sessionId = uuid3 ? `codex:${uuid3}` : legacy;
|
|
75369
|
+
return { cwd, sessionId, aliases: [legacy, ...uuid3 ? [uuid3] : []].filter((s) => s !== sessionId) };
|
|
75370
|
+
};
|
|
75263
75371
|
let fd;
|
|
75264
75372
|
try {
|
|
75265
75373
|
fd = openSync(path2, "r");
|
|
@@ -75282,11 +75390,11 @@ function readCodexRolloutCwd(path2) {
|
|
|
75282
75390
|
const o = JSON.parse(firstLine);
|
|
75283
75391
|
const meta3 = o?.type === "session_meta" ? o.payload ?? o : o.payload ?? o;
|
|
75284
75392
|
const cwd = meta3?.cwd ?? o?.cwd;
|
|
75285
|
-
if (typeof cwd === "string") return cwd;
|
|
75393
|
+
if (typeof cwd === "string") return identity(cwd, o.type === "session_meta" ? meta3.id : void 0);
|
|
75286
75394
|
} catch {
|
|
75287
75395
|
}
|
|
75288
75396
|
const m = firstLine.match(/"cwd"\s*:\s*"((?:[^"\\]|\\.)*)"/);
|
|
75289
|
-
return m ? JSON.parse(`"${m[1]}"`) : null;
|
|
75397
|
+
return m ? identity(JSON.parse(`"${m[1]}"`)) : null;
|
|
75290
75398
|
} catch {
|
|
75291
75399
|
return null;
|
|
75292
75400
|
} finally {
|
|
@@ -75344,15 +75452,16 @@ function codexRolloutsForCwd(cwd, opts = {}) {
|
|
|
75344
75452
|
);
|
|
75345
75453
|
activity.set(full, { size: st.size, activeAt: activityAtMs });
|
|
75346
75454
|
if (activityAtMs < sinceMs) continue;
|
|
75347
|
-
const
|
|
75348
|
-
if (
|
|
75455
|
+
const identity = readCodexRolloutIdentity(full);
|
|
75456
|
+
if (identity === null) continue;
|
|
75457
|
+
const sessionCwd = identity.cwd;
|
|
75349
75458
|
let sessionOwner = owners.get(sessionCwd);
|
|
75350
75459
|
if (sessionOwner === void 0) {
|
|
75351
75460
|
sessionOwner = checkoutRootOf(sessionCwd);
|
|
75352
75461
|
owners.set(sessionCwd, sessionOwner);
|
|
75353
75462
|
}
|
|
75354
75463
|
if (sessionOwner !== owner) continue;
|
|
75355
|
-
out2.push({ path: full, sessionId:
|
|
75464
|
+
out2.push({ path: full, sessionId: identity.sessionId, mtimeMs: st.mtimeMs, activityAtMs });
|
|
75356
75465
|
}
|
|
75357
75466
|
}
|
|
75358
75467
|
for (const path2 of activity.keys()) if (!observed.has(path2)) activity.delete(path2);
|
|
@@ -80918,7 +81027,7 @@ function createWatchBreaker(deps) {
|
|
|
80918
81027
|
}
|
|
80919
81028
|
|
|
80920
81029
|
// src/engine.ts
|
|
80921
|
-
var DAEMON_VERSION = true ? "2.0.14-dev.
|
|
81030
|
+
var DAEMON_VERSION = true ? "2.0.14-dev.3125" : "2.0.0-alpha.0";
|
|
80922
81031
|
var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
|
|
80923
81032
|
var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
|
|
80924
81033
|
var GIT_OP_MUTE_MS = 4e3;
|
|
@@ -82651,7 +82760,7 @@ function createWorkspaceEngine(opts) {
|
|
|
82651
82760
|
readLosses.sliceGuardHits = 0;
|
|
82652
82761
|
}
|
|
82653
82762
|
};
|
|
82654
|
-
const
|
|
82763
|
+
const harvestTurnsUnqueued = async (sessionId, transcriptPath) => {
|
|
82655
82764
|
const known = turnOffset.get(sessionId);
|
|
82656
82765
|
let turns;
|
|
82657
82766
|
let nextOffset;
|
|
@@ -82659,7 +82768,7 @@ function createWorkspaceEngine(opts) {
|
|
|
82659
82768
|
if (known === void 0) {
|
|
82660
82769
|
const first = readAssistantTurnsWithLosses(transcriptPath);
|
|
82661
82770
|
turns = first.turns;
|
|
82662
|
-
nextOffset =
|
|
82771
|
+
nextOffset = first.nextOffset;
|
|
82663
82772
|
readLosses.bytesUnreachable += first.losses.bytesUnreachable;
|
|
82664
82773
|
readLosses.parseFailures += first.losses.parseFailures;
|
|
82665
82774
|
if (first.losses.ioFailed) readLosses.ioFailures++;
|
|
@@ -82719,6 +82828,37 @@ function createWorkspaceEngine(opts) {
|
|
|
82719
82828
|
}
|
|
82720
82829
|
setImmediate(() => void harvestTexts(e.sessionId, [{ text: e.text }]));
|
|
82721
82830
|
};
|
|
82831
|
+
const harvestInFlight = /* @__PURE__ */ new Map();
|
|
82832
|
+
const repairedSessions = /* @__PURE__ */ new Set();
|
|
82833
|
+
const harvestTurns = async (inputSessionId, transcriptPath) => {
|
|
82834
|
+
const identity = basename7(transcriptPath).startsWith("rollout-") ? readCodexRolloutIdentity(transcriptPath) : null;
|
|
82835
|
+
const sessionId = identity?.sessionId ?? inputSessionId;
|
|
82836
|
+
const work = (harvestInFlight.get(sessionId) ?? Promise.resolve()).catch(() => {
|
|
82837
|
+
}).then(async () => {
|
|
82838
|
+
if (identity && !repairedSessions.has(sessionId)) {
|
|
82839
|
+
store.repairSessionAliases(sessionId, identity.aliases);
|
|
82840
|
+
opts.sharedStore?.repairSessionAliases(sessionId, identity.aliases);
|
|
82841
|
+
repairedSessions.add(sessionId);
|
|
82842
|
+
}
|
|
82843
|
+
for (const alias of identity?.aliases ?? []) {
|
|
82844
|
+
const offset = turnOffset.get(alias);
|
|
82845
|
+
if (offset !== void 0 && offset > (turnOffset.get(sessionId) ?? -1)) {
|
|
82846
|
+
turnOffset.set(sessionId, offset);
|
|
82847
|
+
const uuid3 = lastTurnUuid.get(alias);
|
|
82848
|
+
if (uuid3) lastTurnUuid.set(sessionId, uuid3);
|
|
82849
|
+
}
|
|
82850
|
+
turnOffset.delete(alias);
|
|
82851
|
+
lastTurnUuid.delete(alias);
|
|
82852
|
+
}
|
|
82853
|
+
await harvestTurnsUnqueued(sessionId, transcriptPath);
|
|
82854
|
+
});
|
|
82855
|
+
harvestInFlight.set(sessionId, work);
|
|
82856
|
+
try {
|
|
82857
|
+
await work;
|
|
82858
|
+
} finally {
|
|
82859
|
+
if (harvestInFlight.get(sessionId) === work) harvestInFlight.delete(sessionId);
|
|
82860
|
+
}
|
|
82861
|
+
};
|
|
82722
82862
|
const harvestSession = async (sessionId, transcriptPath) => {
|
|
82723
82863
|
await harvestTurns(sessionId, transcriptPath);
|
|
82724
82864
|
for (const sub of subagentTranscripts(transcriptPath, sessionId)) {
|
|
@@ -85395,12 +85535,12 @@ var GENERATED_PATH_RES = [
|
|
|
85395
85535
|
];
|
|
85396
85536
|
var RELEASE_SUBJECT_RE = /^(release|bump|chore\(release\)|v?\d+\.\d+\.\d+)/i;
|
|
85397
85537
|
var RELEASE_TAG_RE = /^v?\d+\.\d+/;
|
|
85398
|
-
function
|
|
85538
|
+
function basename8(path2) {
|
|
85399
85539
|
const i2 = path2.lastIndexOf("/");
|
|
85400
85540
|
return i2 < 0 ? path2 : path2.slice(i2 + 1);
|
|
85401
85541
|
}
|
|
85402
85542
|
function isLockfilePath(path2) {
|
|
85403
|
-
const name2 =
|
|
85543
|
+
const name2 = basename8(path2);
|
|
85404
85544
|
return LOCKFILE_NAMES.has(name2) || LOCKFILE_SUFFIX_RE.test(name2);
|
|
85405
85545
|
}
|
|
85406
85546
|
function isGeneratedPath(path2) {
|
|
@@ -89419,7 +89559,7 @@ function buildCodexHooksToml(port, options) {
|
|
|
89419
89559
|
const quote = (value) => {
|
|
89420
89560
|
if (platform === "win32") {
|
|
89421
89561
|
if (/["\r\n]/.test(value)) throw new Error("Unsupported character in Codex hook path");
|
|
89422
|
-
return "'" + value.replace(/'/g,
|
|
89562
|
+
return "'" + value.replace(/['\u2018-\u201B]/g, (quote2) => quote2 + quote2) + "'";
|
|
89423
89563
|
}
|
|
89424
89564
|
return "'" + value.replace(/'/g, "'\\''") + "'";
|
|
89425
89565
|
};
|
|
@@ -89437,6 +89577,9 @@ import { readFileSync } from 'node:fs';
|
|
|
89437
89577
|
|
|
89438
89578
|
try {
|
|
89439
89579
|
const payload = JSON.parse(readFileSync(0, 'utf8') || '{}');
|
|
89580
|
+
if (typeof payload.session_id === 'string' && /^[a-f0-9]{8}(?:-[a-f0-9]{4}){3}-[a-f0-9]{12}$/i.test(payload.session_id)) {
|
|
89581
|
+
payload.session_id = 'codex:' + payload.session_id.toLowerCase();
|
|
89582
|
+
}
|
|
89440
89583
|
const port = Number(process.argv[2]);
|
|
89441
89584
|
const event = payload.hook_event_name;
|
|
89442
89585
|
if (!Number.isInteger(port) || port < 1 || port > 65535) process.exit(0);
|
package/package.json
CHANGED
package/pass-worker.mjs
CHANGED
|
@@ -24605,6 +24605,71 @@ function installHistoryCacheFloor(db) {
|
|
|
24605
24605
|
});
|
|
24606
24606
|
}
|
|
24607
24607
|
|
|
24608
|
+
// ../../packages/local-graph/src/session-evidence.ts
|
|
24609
|
+
function repairSessionEvidence(input, aliases = /* @__PURE__ */ new Map()) {
|
|
24610
|
+
const mapping = new Map(aliases);
|
|
24611
|
+
const uuid3 = "[a-f0-9]{8}(?:-[a-f0-9]{4}){3}-[a-f0-9]{12}";
|
|
24612
|
+
const codex = new RegExp(`^codex:(?:rollout-.*?)?(${uuid3})$`, "i");
|
|
24613
|
+
const arrays = /* @__PURE__ */ new Set(["sources", "recurrenceSources", "contributors", "inferredContributors", "citeSessions"]);
|
|
24614
|
+
const scalars = /* @__PURE__ */ new Set(["discriminatorSource", "originSession", "sessionId", "sourceSession"]);
|
|
24615
|
+
const discover = (value, key = "") => {
|
|
24616
|
+
if (typeof value === "string" && (arrays.has(key) || scalars.has(key) || key === "citeAnchorHints")) {
|
|
24617
|
+
const match = value.match(codex);
|
|
24618
|
+
if (match) {
|
|
24619
|
+
const canonical = `codex:${match[1].toLowerCase()}`;
|
|
24620
|
+
mapping.set(value, canonical);
|
|
24621
|
+
mapping.set(match[1].toLowerCase(), canonical);
|
|
24622
|
+
}
|
|
24623
|
+
} else if (Array.isArray(value)) value.forEach((v) => discover(v, key));
|
|
24624
|
+
else if (value && typeof value === "object") {
|
|
24625
|
+
for (const [k, v] of Object.entries(value)) discover(v, key === "citeAnchorHints" ? key : k);
|
|
24626
|
+
}
|
|
24627
|
+
};
|
|
24628
|
+
discover(input);
|
|
24629
|
+
const rewrite = (value, key = "") => {
|
|
24630
|
+
if (typeof value === "string" && (arrays.has(key) || scalars.has(key) || key === "citeAnchorHints")) {
|
|
24631
|
+
return mapping.get(value) ?? mapping.get(value.toLowerCase()) ?? value;
|
|
24632
|
+
}
|
|
24633
|
+
if (Array.isArray(value)) {
|
|
24634
|
+
const values = value.map((v) => rewrite(v, key));
|
|
24635
|
+
return arrays.has(key) || key === "citeAnchorHints" ? [...new Set(values)] : values;
|
|
24636
|
+
}
|
|
24637
|
+
if (!value || typeof value !== "object") return value;
|
|
24638
|
+
const before = value;
|
|
24639
|
+
const after = Object.fromEntries(Object.entries(before).map(([k, v]) => [k, rewrite(v, key === "citeAnchorHints" ? key : k)]));
|
|
24640
|
+
for (const field of ["sources", "contributors"]) {
|
|
24641
|
+
const old = before[field], next = after[field];
|
|
24642
|
+
if (!Array.isArray(old) || !Array.isArray(next) || old.length <= next.length) continue;
|
|
24643
|
+
after["sessionAliasRepair"] = { originalCount: old.length, distinctCount: next.length };
|
|
24644
|
+
if (field === "sources" && typeof after["corroborations"] === "number") {
|
|
24645
|
+
after["corroborations"] = Math.min(after["corroborations"], Math.max(0, next.length - 1));
|
|
24646
|
+
if (after["corroborations"] === 0) after["provisional"] = true;
|
|
24647
|
+
}
|
|
24648
|
+
if (field === "contributors" && typeof after["confirmed"] === "number") {
|
|
24649
|
+
after["preAliasRepairConfirmed"] = after["confirmed"];
|
|
24650
|
+
after["confirmed"] = Math.min(after["confirmed"], next.length);
|
|
24651
|
+
}
|
|
24652
|
+
}
|
|
24653
|
+
return after;
|
|
24654
|
+
};
|
|
24655
|
+
const repaired = rewrite(input);
|
|
24656
|
+
const source = repaired["discriminatorSource"];
|
|
24657
|
+
if (typeof source === "string") {
|
|
24658
|
+
const global = repaired["perContext"]?.["*"];
|
|
24659
|
+
const contributors = Array.isArray(global?.["contributors"]) ? global["contributors"] : [];
|
|
24660
|
+
const inferred = new Set(Array.isArray(global?.["inferredContributors"]) ? global["inferredContributors"] : []);
|
|
24661
|
+
if (contributors.includes(source) || contributors.filter((id) => !inferred.has(id)).length < 2) {
|
|
24662
|
+
repaired["withdrawnDiscriminator"] = repaired["discriminator"];
|
|
24663
|
+
repaired["discriminatorWithdrawalReason"] = "insufficient-independent-witnesses";
|
|
24664
|
+
repaired["provisional"] = true;
|
|
24665
|
+
delete repaired["discriminator"];
|
|
24666
|
+
delete repaired["discriminatorSource"];
|
|
24667
|
+
delete repaired["discriminatorAsked"];
|
|
24668
|
+
}
|
|
24669
|
+
}
|
|
24670
|
+
return repaired;
|
|
24671
|
+
}
|
|
24672
|
+
|
|
24608
24673
|
// ../../packages/local-graph/src/store.ts
|
|
24609
24674
|
var LOCAL_RULE_OVERRIDES = {
|
|
24610
24675
|
ANCHORED_AT: {
|
|
@@ -24849,6 +24914,12 @@ var SqliteGraphStore = class {
|
|
|
24849
24914
|
}
|
|
24850
24915
|
this.db.exec(TEMPORAL_INDEX_SQL);
|
|
24851
24916
|
installHistoryCacheFloor(this.db);
|
|
24917
|
+
if (!this.db.prepare("SELECT value FROM store_meta WHERE key = 'session-evidence-v1'").get()) {
|
|
24918
|
+
this.db.transaction(() => {
|
|
24919
|
+
this.repairSessionAliases();
|
|
24920
|
+
this.db.prepare("INSERT OR REPLACE INTO store_meta (key, value) VALUES ('session-evidence-v1', 'done')").run();
|
|
24921
|
+
});
|
|
24922
|
+
}
|
|
24852
24923
|
this.stmts = {
|
|
24853
24924
|
insertNode: this.db.prepare(`
|
|
24854
24925
|
INSERT INTO nodes (
|
|
@@ -25097,6 +25168,23 @@ var SqliteGraphStore = class {
|
|
|
25097
25168
|
this.db.prepare("UPDATE schema_version SET version = ?").run(SCHEMA_VERSION);
|
|
25098
25169
|
});
|
|
25099
25170
|
}
|
|
25171
|
+
repairSessionAliases(canonical, aliases = []) {
|
|
25172
|
+
const mapping = new Map(aliases.map((alias) => [alias, canonical]));
|
|
25173
|
+
let changed = 0;
|
|
25174
|
+
for (const table of ["nodes", "edges"]) {
|
|
25175
|
+
const predicates = canonical ? aliases.map(() => "instr(attrs_json, ?) > 0") : ["instr(attrs_json, 'codex:') > 0", "instr(attrs_json, 'discriminatorSource') > 0"];
|
|
25176
|
+
if (!predicates.length) continue;
|
|
25177
|
+
const rows = this.db.prepare(`SELECT id, attrs_json FROM ${table} WHERE ${predicates.join(" OR ")}`).all(...canonical ? aliases : []);
|
|
25178
|
+
const update = this.db.prepare(`UPDATE ${table} SET attrs_json = ?${table === "edges" ? ", type = CASE WHEN type = 'CONFIRMS' AND json_extract(?, '$.provisional') = 1 THEN 'INDICATES' ELSE type END" : ""} WHERE id = ?`);
|
|
25179
|
+
for (const row of rows) {
|
|
25180
|
+
const attrs = JSON.stringify(repairSessionEvidence(JSON.parse(row.attrs_json), mapping));
|
|
25181
|
+
if (attrs === row.attrs_json) continue;
|
|
25182
|
+
update.run(...table === "edges" ? [attrs, attrs, row.id] : [attrs, row.id]);
|
|
25183
|
+
changed++;
|
|
25184
|
+
}
|
|
25185
|
+
}
|
|
25186
|
+
return changed;
|
|
25187
|
+
}
|
|
25100
25188
|
deleteNode(id) {
|
|
25101
25189
|
this.stmts.deleteNode.run(id);
|
|
25102
25190
|
}
|