@inerrata-corporation/errata 2.0.21-dev.3707 → 2.0.21-dev.3740
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 +1 -1
- package/errata.mjs +218 -32
- package/generalize-worker.mjs +17184 -0
- package/install.ps1 +1 -1
- package/package.json +2 -1
- package/resources/context-plugin/.codex-plugin/plugin.json +1 -1
- package/resources/context-plugin/SHA256SUMS +1 -1
package/consolidate-worker.mjs
CHANGED
|
@@ -774,7 +774,7 @@ function claimStructure(text, scope) {
|
|
|
774
774
|
const predicate = normalizePredicate(text);
|
|
775
775
|
const stance = detectStance(text);
|
|
776
776
|
const base = { entities, predicate, stance, scope: scope ?? {} };
|
|
777
|
-
if (predicate === "") base.raw = conceptBag(text);
|
|
777
|
+
if (predicate === "" || entities.length === 0) base.raw = conceptBag(text);
|
|
778
778
|
return base;
|
|
779
779
|
}
|
|
780
780
|
function canonicalClaimId(text, scope) {
|
package/errata.mjs
CHANGED
|
@@ -1056,7 +1056,7 @@ function claimStructure(text, scope) {
|
|
|
1056
1056
|
const predicate = normalizePredicate(text);
|
|
1057
1057
|
const stance = detectStance(text);
|
|
1058
1058
|
const base = { entities, predicate, stance, scope: scope ?? {} };
|
|
1059
|
-
if (predicate === "") base.raw = conceptBag(text);
|
|
1059
|
+
if (predicate === "" || entities.length === 0) base.raw = conceptBag(text);
|
|
1060
1060
|
return base;
|
|
1061
1061
|
}
|
|
1062
1062
|
function canonicalClaimId(text, scope) {
|
|
@@ -32475,7 +32475,7 @@ function triageBullet(ref) {
|
|
|
32475
32475
|
" \u2022 you diagnosed a cause \u2014 fold the chain into the flag with <- (caused-by), deepest",
|
|
32476
32476
|
" sure mechanism rightmost: [!symptom <- cause <- root cause]. Symptom and cause far",
|
|
32477
32477
|
" apart? open a thread [!#slug symptom] \u2026 later bind (cause:#slug mechanism);",
|
|
32478
|
-
` explaining a problem
|
|
32478
|
+
` explaining a SHOWN problem \u2192 ${TAG_EXAMPLE.triageExplain(ref)}`
|
|
32479
32479
|
].join("\n");
|
|
32480
32480
|
}
|
|
32481
32481
|
function linkBullet(ref) {
|
|
@@ -32536,6 +32536,8 @@ var init_agent_signals = __esm({
|
|
|
32536
32536
|
// links to a cited RootCause/Solution node; `(cause: free text)` mints a RootCause
|
|
32537
32537
|
// from the text. Harvested in prior-tags.ts → engine.ts (see the triage note below).
|
|
32538
32538
|
triage: (ref) => `(cause:[${ref}])`,
|
|
32539
|
+
// Unlike a bare cause citation, this handle names the Problem being explained.
|
|
32540
|
+
triageExplain: (ref) => `(cause:[${ref}] the mechanism)`,
|
|
32539
32541
|
// The MINT form — free-text cause that mints a RootCause. Prime-time surfacing
|
|
32540
32542
|
// (recallForFile) pastes this next to an open Problem that has no cause yet, so the
|
|
32541
32543
|
// diagnostic moment is cued when the agent is looking at the problem. Kept here so
|
|
@@ -34899,7 +34901,7 @@ function isQuotaError(err2) {
|
|
|
34899
34901
|
return status === 403 && /quota/i.test(msg);
|
|
34900
34902
|
}
|
|
34901
34903
|
async function dualAugment(opts) {
|
|
34902
|
-
const { store, cloud, localHits, seedNode, queryText, limit } = opts;
|
|
34904
|
+
const { store, cloud, localHits, seedNode, queryText, limit, generalizeSoft } = opts;
|
|
34903
34905
|
const cloudHits = [];
|
|
34904
34906
|
let seedUsageCount;
|
|
34905
34907
|
let seedProvenance = "local";
|
|
@@ -34910,7 +34912,7 @@ async function dualAugment(opts) {
|
|
|
34910
34912
|
return !!n && isHardBridge(n);
|
|
34911
34913
|
});
|
|
34912
34914
|
const softText = queryText ?? (seedNode && BRIDGE_LABELS.has(seedNode.label) ? seedNode.description : void 0);
|
|
34913
|
-
const softQ = softText ? generalizeSymbols(softText, lexiconsFor(store).symbols, 1) : void 0;
|
|
34915
|
+
const softQ = softText ? await generalizeSoft?.(softText) ?? generalizeSymbols(softText, lexiconsFor(store).symbols, 1) : void 0;
|
|
34914
34916
|
if (seedNode?.label === "Package") {
|
|
34915
34917
|
calls.push(
|
|
34916
34918
|
cloud.packages(seedNode.id).then((pn) => {
|
|
@@ -35022,6 +35024,50 @@ var init_dual_augment = __esm({
|
|
|
35022
35024
|
}
|
|
35023
35025
|
});
|
|
35024
35026
|
|
|
35027
|
+
// src/daemon-generalize-client.ts
|
|
35028
|
+
function daemonLoopbackUrl(lockPath = globalDaemonLock()) {
|
|
35029
|
+
const url2 = readDaemonLock(lockPath)?.webUiUrl;
|
|
35030
|
+
if (!url2) return null;
|
|
35031
|
+
try {
|
|
35032
|
+
const u = new URL(url2);
|
|
35033
|
+
const isLoopback = u.hostname === "127.0.0.1" || u.hostname === "localhost" || u.hostname === "[::1]";
|
|
35034
|
+
return u.protocol === "http:" && isLoopback ? u.origin : null;
|
|
35035
|
+
} catch {
|
|
35036
|
+
return null;
|
|
35037
|
+
}
|
|
35038
|
+
}
|
|
35039
|
+
function daemonGeneralizer(workspaceRoot, opts = {}) {
|
|
35040
|
+
const baseUrl = opts.baseUrl ?? (() => daemonLoopbackUrl());
|
|
35041
|
+
const fetchFn = opts.fetchFn ?? fetch;
|
|
35042
|
+
const timeoutMs = opts.timeoutMs ?? DAEMON_GENERALIZE_TIMEOUT_MS;
|
|
35043
|
+
return async (text) => {
|
|
35044
|
+
try {
|
|
35045
|
+
const base = baseUrl();
|
|
35046
|
+
if (!base) return void 0;
|
|
35047
|
+
const res = await fetchFn(`${base}/api/generalize`, {
|
|
35048
|
+
method: "POST",
|
|
35049
|
+
headers: { "content-type": "application/json" },
|
|
35050
|
+
body: JSON.stringify({ workspaceRoot, text }),
|
|
35051
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
35052
|
+
});
|
|
35053
|
+
if (!res.ok) return void 0;
|
|
35054
|
+
const body2 = await res.json();
|
|
35055
|
+
return typeof body2.generalized === "string" ? body2.generalized : void 0;
|
|
35056
|
+
} catch {
|
|
35057
|
+
return void 0;
|
|
35058
|
+
}
|
|
35059
|
+
};
|
|
35060
|
+
}
|
|
35061
|
+
var DAEMON_GENERALIZE_TIMEOUT_MS;
|
|
35062
|
+
var init_daemon_generalize_client = __esm({
|
|
35063
|
+
"src/daemon-generalize-client.ts"() {
|
|
35064
|
+
"use strict";
|
|
35065
|
+
init_lock();
|
|
35066
|
+
init_paths();
|
|
35067
|
+
DAEMON_GENERALIZE_TIMEOUT_MS = 3e3;
|
|
35068
|
+
}
|
|
35069
|
+
});
|
|
35070
|
+
|
|
35025
35071
|
// ../../packages/indexer/src/parse-cache.ts
|
|
35026
35072
|
import { createHash as createHash6 } from "node:crypto";
|
|
35027
35073
|
import { existsSync as existsSync15, mkdirSync as mkdirSync6, readFileSync as readFileSync14, readdirSync as readdirSync2, rmSync as rmSync2, statSync as statSync2, writeFileSync as writeFileSync11 } from "node:fs";
|
|
@@ -44382,6 +44428,7 @@ async function runMcpServer(workspaceRoot, options = {}) {
|
|
|
44382
44428
|
const store = openGraphStore({ path: paths.castalia });
|
|
44383
44429
|
const handle2 = createMcpHandler(store, {
|
|
44384
44430
|
...buildToolContext(workspaceRoot),
|
|
44431
|
+
generalizeSoft: daemonGeneralizer(workspaceRoot),
|
|
44385
44432
|
sharedDbPath: sharedStorePath()
|
|
44386
44433
|
}, options);
|
|
44387
44434
|
process.stdin.setEncoding("utf8");
|
|
@@ -44427,6 +44474,7 @@ var init_mcp = __esm({
|
|
|
44427
44474
|
init_src8();
|
|
44428
44475
|
init_dual_burst();
|
|
44429
44476
|
init_paths();
|
|
44477
|
+
init_daemon_generalize_client();
|
|
44430
44478
|
init_webui();
|
|
44431
44479
|
init_reconcile();
|
|
44432
44480
|
init_agent_signals();
|
|
@@ -44502,6 +44550,7 @@ var init_mcp = __esm({
|
|
|
44502
44550
|
const dual = await dualAugment({
|
|
44503
44551
|
store,
|
|
44504
44552
|
cloud: ctx.cloud,
|
|
44553
|
+
...ctx.generalizeSoft ? { generalizeSoft: ctx.generalizeSoft } : {},
|
|
44505
44554
|
localHits,
|
|
44506
44555
|
queryText: query,
|
|
44507
44556
|
limit
|
|
@@ -44681,6 +44730,7 @@ var init_mcp = __esm({
|
|
|
44681
44730
|
const dual = await dualAugment({
|
|
44682
44731
|
store,
|
|
44683
44732
|
cloud: ctx.cloud,
|
|
44733
|
+
...ctx.generalizeSoft ? { generalizeSoft: ctx.generalizeSoft } : {},
|
|
44684
44734
|
localHits,
|
|
44685
44735
|
seedNode,
|
|
44686
44736
|
limit: args2["limit"] != null ? Number(args2["limit"]) : 20
|
|
@@ -45252,6 +45302,7 @@ var init_mcp = __esm({
|
|
|
45252
45302
|
const dual = await dualAugment({
|
|
45253
45303
|
store,
|
|
45254
45304
|
cloud: ctx.cloud,
|
|
45305
|
+
...ctx.generalizeSoft ? { generalizeSoft: ctx.generalizeSoft } : {},
|
|
45255
45306
|
localHits,
|
|
45256
45307
|
seedNode: node2,
|
|
45257
45308
|
limit
|
|
@@ -77444,6 +77495,32 @@ function emptyTagDispositions() {
|
|
|
77444
77495
|
flagAsHandle: 0
|
|
77445
77496
|
};
|
|
77446
77497
|
}
|
|
77498
|
+
function parseCauseTag(content, sentence, threadId, dispositions) {
|
|
77499
|
+
const body2 = content.replace(/\s+/g, " ").trim();
|
|
77500
|
+
const cited = new RegExp(HANDLE_RE.source, "i").exec(body2);
|
|
77501
|
+
const handle2 = cited ? cited[1] ?? cited[2] : void 0;
|
|
77502
|
+
const base = { kind: "triage", sentence, ...threadId ? { threadId } : {} };
|
|
77503
|
+
if (handle2 && cited) {
|
|
77504
|
+
if (isPlaceholderHandle(handle2)) {
|
|
77505
|
+
dispositions.placeholderEcho++;
|
|
77506
|
+
return;
|
|
77507
|
+
}
|
|
77508
|
+
const mechanism = body2.slice(cited.index + cited[0].length).trim();
|
|
77509
|
+
if (!threadId && cited.index === 0 && mechanism) {
|
|
77510
|
+
if (mechanism.length < CAUSE_TEXT_MIN) {
|
|
77511
|
+
dispositions.causeTooShort++;
|
|
77512
|
+
return;
|
|
77513
|
+
}
|
|
77514
|
+
return { ...base, symptomHandle: handle2, causeText: mechanism };
|
|
77515
|
+
}
|
|
77516
|
+
return { ...base, handle: handle2 };
|
|
77517
|
+
}
|
|
77518
|
+
if (body2.length < CAUSE_TEXT_MIN) {
|
|
77519
|
+
dispositions.causeTooShort++;
|
|
77520
|
+
return;
|
|
77521
|
+
}
|
|
77522
|
+
return { ...base, causeText: body2 };
|
|
77523
|
+
}
|
|
77447
77524
|
function addTagDispositions(a, b) {
|
|
77448
77525
|
a.invalidVulnerability += b.invalidVulnerability;
|
|
77449
77526
|
a.oversizeSegments += b.oversizeSegments;
|
|
@@ -77566,22 +77643,8 @@ function parseInlineTagsWithDispositions(text) {
|
|
|
77566
77643
|
if (isFix) content = content.replace(FIX_PREFIX, "");
|
|
77567
77644
|
else if (isCause) content = content.replace(CAUSE_PREFIX, "");
|
|
77568
77645
|
if (isCause) {
|
|
77569
|
-
|
|
77570
|
-
|
|
77571
|
-
let handle2 = h2 ? h2[1] ?? h2[2] : void 0;
|
|
77572
|
-
if (handle2 && isPlaceholderHandle(handle2)) {
|
|
77573
|
-
dispositions.placeholderEcho++;
|
|
77574
|
-
handle2 = void 0;
|
|
77575
|
-
}
|
|
77576
|
-
if (handle2) {
|
|
77577
|
-
out2.push({ kind: "triage", handle: handle2, sentence: sfield, ...verbThread ? { threadId: verbThread } : {} });
|
|
77578
|
-
} else {
|
|
77579
|
-
const raw3 = content.replace(/\s+/g, " ").trim();
|
|
77580
|
-
if (raw3.length >= CAUSE_TEXT_MIN) {
|
|
77581
|
-
const causeText = raw3;
|
|
77582
|
-
out2.push({ kind: "triage", causeText, sentence: sfield, ...verbThread ? { threadId: verbThread } : {} });
|
|
77583
|
-
} else dispositions.causeTooShort++;
|
|
77584
|
-
}
|
|
77646
|
+
const cause = parseCauseTag(content, sfield, verbThread, dispositions);
|
|
77647
|
+
if (cause) out2.push(cause);
|
|
77585
77648
|
continue;
|
|
77586
77649
|
}
|
|
77587
77650
|
if (!isFix && NEG.test(clauseBefore(sentence, g.index))) {
|
|
@@ -77632,6 +77695,11 @@ function parseInlineTagsWithDispositions(text) {
|
|
|
77632
77695
|
if (citeMatched.has(lm.index)) continue;
|
|
77633
77696
|
const verbThread = lm[1] ?? void 0;
|
|
77634
77697
|
const content = lm[2];
|
|
77698
|
+
if (!pass.isFix) {
|
|
77699
|
+
const cause = parseCauseTag(content, sfield, verbThread, dispositions);
|
|
77700
|
+
if (cause) out2.push(cause);
|
|
77701
|
+
continue;
|
|
77702
|
+
}
|
|
77635
77703
|
HANDLE_RE.lastIndex = 0;
|
|
77636
77704
|
const h = HANDLE_RE.exec(content);
|
|
77637
77705
|
let handle2 = h ? h[1] ?? h[2] : void 0;
|
|
@@ -77639,16 +77707,6 @@ function parseInlineTagsWithDispositions(text) {
|
|
|
77639
77707
|
dispositions.placeholderEcho++;
|
|
77640
77708
|
handle2 = void 0;
|
|
77641
77709
|
}
|
|
77642
|
-
if (!pass.isFix) {
|
|
77643
|
-
if (handle2) {
|
|
77644
|
-
out2.push({ kind: "triage", handle: handle2, sentence: sfield, ...verbThread ? { threadId: verbThread } : {} });
|
|
77645
|
-
} else {
|
|
77646
|
-
const causeText = content.replace(/\s+/g, " ").trim();
|
|
77647
|
-
if (causeText.length >= CAUSE_TEXT_MIN)
|
|
77648
|
-
out2.push({ kind: "triage", causeText, sentence: sfield, ...verbThread ? { threadId: verbThread } : {} });
|
|
77649
|
-
}
|
|
77650
|
-
continue;
|
|
77651
|
-
}
|
|
77652
77710
|
if (handle2) {
|
|
77653
77711
|
const inGroup = content.replace(new RegExp(HANDLE_RE.source, "gi"), " ").replace(/\s+/g, " ").trim();
|
|
77654
77712
|
const r = inGroup.length >= FIX_RATIONALE_MIN ? inGroup : deriveFixRationale(sentence, lm.index, lm.index + lm[0].length);
|
|
@@ -78165,7 +78223,14 @@ function harvestInlineTags(store, text, opts) {
|
|
|
78165
78223
|
}
|
|
78166
78224
|
}
|
|
78167
78225
|
} else if (tag.kind === "triage") {
|
|
78168
|
-
const
|
|
78226
|
+
const symptomId = tag.symptomHandle ? resolveCited("triage", tag.symptomHandle) : null;
|
|
78227
|
+
const symptom = symptomId ? store.getNode(symptomId) : null;
|
|
78228
|
+
if (tag.symptomHandle && !symptom) continue;
|
|
78229
|
+
if (symptom && (symptom.label !== "Problem" || !symptom.description?.trim())) {
|
|
78230
|
+
plan.dispositions.unparseable++;
|
|
78231
|
+
continue;
|
|
78232
|
+
}
|
|
78233
|
+
const b = symptom ? { statement: symptom.description, problemId: symptom.id, evidence: "witnessed" } : bindSymptom(tag.seq, tag.threadId);
|
|
78169
78234
|
const bound = {
|
|
78170
78235
|
...b.statement ? { symptomStatement: b.statement } : {},
|
|
78171
78236
|
...b.problemId ? { symptomProblemId: b.problemId } : {},
|
|
@@ -82804,7 +82869,7 @@ function createWatchBreaker(deps) {
|
|
|
82804
82869
|
}
|
|
82805
82870
|
|
|
82806
82871
|
// src/engine.ts
|
|
82807
|
-
var DAEMON_VERSION = true ? "2.0.21-dev.
|
|
82872
|
+
var DAEMON_VERSION = true ? "2.0.21-dev.3740" : "2.0.0-alpha.0";
|
|
82808
82873
|
var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
|
|
82809
82874
|
var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
|
|
82810
82875
|
var GIT_OP_MUTE_MS = 4e3;
|
|
@@ -86970,6 +87035,98 @@ var ConsolidateWorker = class {
|
|
|
86970
87035
|
}
|
|
86971
87036
|
};
|
|
86972
87037
|
|
|
87038
|
+
// src/generalize-worker-client.ts
|
|
87039
|
+
import { Worker as Worker3 } from "node:worker_threads";
|
|
87040
|
+
var GENERALIZE_WORKER_IDLE_MS = 30 * 6e4;
|
|
87041
|
+
var GeneralizeWorker = class {
|
|
87042
|
+
worker = null;
|
|
87043
|
+
ready = null;
|
|
87044
|
+
pending = /* @__PURE__ */ new Map();
|
|
87045
|
+
nextId = 1;
|
|
87046
|
+
stopped = false;
|
|
87047
|
+
idleTimer = null;
|
|
87048
|
+
async generalize(castaliaPath, text) {
|
|
87049
|
+
if (this.stopped) throw new Error("generalize worker stopped");
|
|
87050
|
+
this.ensureWorker();
|
|
87051
|
+
this.touch();
|
|
87052
|
+
await this.ready;
|
|
87053
|
+
const id = this.nextId++;
|
|
87054
|
+
return new Promise((resolve10, reject) => {
|
|
87055
|
+
this.pending.set(id, { resolve: resolve10, reject });
|
|
87056
|
+
const req = { id, castaliaPath, text };
|
|
87057
|
+
this.worker.postMessage(req);
|
|
87058
|
+
});
|
|
87059
|
+
}
|
|
87060
|
+
touch() {
|
|
87061
|
+
if (this.idleTimer) clearTimeout(this.idleTimer);
|
|
87062
|
+
this.idleTimer = setTimeout(() => {
|
|
87063
|
+
if (this.pending.size > 0) return this.touch();
|
|
87064
|
+
const w = this.worker;
|
|
87065
|
+
this.worker = null;
|
|
87066
|
+
this.ready = null;
|
|
87067
|
+
void w?.terminate().catch(() => {
|
|
87068
|
+
});
|
|
87069
|
+
}, GENERALIZE_WORKER_IDLE_MS);
|
|
87070
|
+
this.idleTimer.unref?.();
|
|
87071
|
+
}
|
|
87072
|
+
ensureWorker() {
|
|
87073
|
+
if (this.worker) return;
|
|
87074
|
+
const worker = new Worker3(new URL("./generalize-worker.mjs", import.meta.url), {
|
|
87075
|
+
workerData: {},
|
|
87076
|
+
execArgv: process.execArgv,
|
|
87077
|
+
resourceLimits: workerResourceLimits()
|
|
87078
|
+
});
|
|
87079
|
+
noteIsolateSpawned();
|
|
87080
|
+
this.worker = worker;
|
|
87081
|
+
this.ready = new Promise((resolve10, reject) => {
|
|
87082
|
+
const onReady = (m) => {
|
|
87083
|
+
if (m?.ready) {
|
|
87084
|
+
worker.off("message", onReady);
|
|
87085
|
+
worker.off("error", onErr);
|
|
87086
|
+
resolve10();
|
|
87087
|
+
}
|
|
87088
|
+
};
|
|
87089
|
+
const onErr = (err2) => {
|
|
87090
|
+
worker.off("message", onReady);
|
|
87091
|
+
reject(err2);
|
|
87092
|
+
};
|
|
87093
|
+
worker.once("error", onErr);
|
|
87094
|
+
worker.on("message", onReady);
|
|
87095
|
+
});
|
|
87096
|
+
worker.on("message", (m) => {
|
|
87097
|
+
if (typeof m?.id !== "number") return;
|
|
87098
|
+
const p = this.pending.get(m.id);
|
|
87099
|
+
if (!p) return;
|
|
87100
|
+
this.pending.delete(m.id);
|
|
87101
|
+
if (m.ok && typeof m.result === "string") p.resolve(m.result);
|
|
87102
|
+
else p.reject(new Error(m.error ?? "generalization failed"));
|
|
87103
|
+
});
|
|
87104
|
+
const onGone = (err2) => {
|
|
87105
|
+
const e = err2 instanceof Error ? err2 : new Error("generalize worker exited");
|
|
87106
|
+
for (const [, p] of this.pending) p.reject(e);
|
|
87107
|
+
this.pending.clear();
|
|
87108
|
+
if (this.worker === worker) {
|
|
87109
|
+
this.worker = null;
|
|
87110
|
+
this.ready = null;
|
|
87111
|
+
}
|
|
87112
|
+
};
|
|
87113
|
+
worker.on("error", onGone);
|
|
87114
|
+
worker.on("exit", () => {
|
|
87115
|
+
noteIsolateExited();
|
|
87116
|
+
onGone();
|
|
87117
|
+
});
|
|
87118
|
+
}
|
|
87119
|
+
async stop() {
|
|
87120
|
+
this.stopped = true;
|
|
87121
|
+
if (this.idleTimer) clearTimeout(this.idleTimer);
|
|
87122
|
+
if (this.worker) {
|
|
87123
|
+
await this.worker.terminate().catch(() => {
|
|
87124
|
+
});
|
|
87125
|
+
this.worker = null;
|
|
87126
|
+
}
|
|
87127
|
+
}
|
|
87128
|
+
};
|
|
87129
|
+
|
|
86973
87130
|
// src/prepare-store.ts
|
|
86974
87131
|
init_src5();
|
|
86975
87132
|
async function prepareStore(path2, root, workspaceId2) {
|
|
@@ -89925,6 +90082,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
89925
90082
|
const sharedStore = openGraphStore({ path: sharedDbPath });
|
|
89926
90083
|
const bundledRun = import.meta.url.endsWith(".mjs");
|
|
89927
90084
|
const consolidateWorker = bundledRun && sharedDbPath !== ":memory:" ? new ConsolidateWorker() : null;
|
|
90085
|
+
const generalizeWorker = bundledRun ? new GeneralizeWorker() : null;
|
|
89928
90086
|
startLoopLagMonitor();
|
|
89929
90087
|
let baseUrl = "";
|
|
89930
90088
|
const records = [];
|
|
@@ -91612,6 +91770,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
91612
91770
|
await Promise.allSettled(attaching.values());
|
|
91613
91771
|
for (const r of records) await r.engine.stop();
|
|
91614
91772
|
if (consolidateWorker) await consolidateWorker.stop();
|
|
91773
|
+
if (generalizeWorker) await generalizeWorker.stop();
|
|
91615
91774
|
try {
|
|
91616
91775
|
sharedStore.close();
|
|
91617
91776
|
} catch {
|
|
@@ -91640,6 +91799,33 @@ async function startMultiDaemon(opts = {}) {
|
|
|
91640
91799
|
}
|
|
91641
91800
|
});
|
|
91642
91801
|
app.get("/api/sync", (c) => c.json(flushSnapshot()));
|
|
91802
|
+
const GENERALIZE_MAX_CHARS = 8e3;
|
|
91803
|
+
app.post("/api/generalize", async (c) => {
|
|
91804
|
+
const host = (c.req.header("host") ?? "").toLowerCase();
|
|
91805
|
+
if (!/^(127\.0\.0\.1|localhost|\[::1\])(:\d+)?$/.test(host)) return c.json({ error: "forbidden" }, 403);
|
|
91806
|
+
if (!(c.req.header("content-type") ?? "").toLowerCase().startsWith("application/json")) {
|
|
91807
|
+
return c.json({ error: "json required" }, 415);
|
|
91808
|
+
}
|
|
91809
|
+
let body2;
|
|
91810
|
+
try {
|
|
91811
|
+
body2 = await c.req.json();
|
|
91812
|
+
} catch {
|
|
91813
|
+
return c.json({ error: "bad json" }, 400);
|
|
91814
|
+
}
|
|
91815
|
+
if (typeof body2.workspaceRoot !== "string" || typeof body2.text !== "string") {
|
|
91816
|
+
return c.json({ error: "workspaceRoot and text required" }, 400);
|
|
91817
|
+
}
|
|
91818
|
+
if (body2.text.length > GENERALIZE_MAX_CHARS) return c.json({ error: "text too long" }, 413);
|
|
91819
|
+
const entry = workspaceEntryForPath(pathResolve(body2.workspaceRoot));
|
|
91820
|
+
if (!entry) return c.json({ error: "unregistered workspace" }, 404);
|
|
91821
|
+
if (!generalizeWorker) return c.json({ error: "no worker" }, 503);
|
|
91822
|
+
try {
|
|
91823
|
+
const generalized = await generalizeWorker.generalize(workspacePaths(entry.path).castalia, body2.text);
|
|
91824
|
+
return c.json({ generalized });
|
|
91825
|
+
} catch (err2) {
|
|
91826
|
+
return c.json({ error: err2 instanceof Error ? err2.message : String(err2) }, 503);
|
|
91827
|
+
}
|
|
91828
|
+
});
|
|
91643
91829
|
app.post("/api/tick", async (c) => {
|
|
91644
91830
|
try {
|
|
91645
91831
|
return c.json({ reports: Object.fromEntries(await daemon.tickAll()) });
|