@mrciphersmith/keryx 0.3.64 → 0.3.66
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/dist/cli.js +851 -315
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -20107,7 +20107,7 @@ var package_default;
|
|
|
20107
20107
|
var init_package = __esm(() => {
|
|
20108
20108
|
package_default = {
|
|
20109
20109
|
name: "@mrciphersmith/keryx",
|
|
20110
|
-
version: "0.3.
|
|
20110
|
+
version: "0.3.66",
|
|
20111
20111
|
description: "Version-controlled project context for AI coding agents: code graph, architecture wiki, project memory, relevant tests, quality signals, and task flows.",
|
|
20112
20112
|
private: false,
|
|
20113
20113
|
publishConfig: {
|
|
@@ -88435,6 +88435,58 @@ var MAX_TEXT_LENGTH = 300;
|
|
|
88435
88435
|
function emptyTally() {
|
|
88436
88436
|
return { answered: 0, matched: 0 };
|
|
88437
88437
|
}
|
|
88438
|
+
function median(values) {
|
|
88439
|
+
if (values.length === 0)
|
|
88440
|
+
return null;
|
|
88441
|
+
const sorted = [...values].sort((a, b) => a - b);
|
|
88442
|
+
const mid = Math.floor(sorted.length / 2);
|
|
88443
|
+
const low = sorted[mid - 1] ?? 0;
|
|
88444
|
+
const high = sorted[mid] ?? 0;
|
|
88445
|
+
return sorted.length % 2 === 1 ? high : Math.round((low + high) / 2);
|
|
88446
|
+
}
|
|
88447
|
+
function buildBackfilled(history, firstAnswer, reasons) {
|
|
88448
|
+
const out = {
|
|
88449
|
+
total: history.length,
|
|
88450
|
+
answered: 0,
|
|
88451
|
+
withRecommendation: 0,
|
|
88452
|
+
withoutRecommendation: 0,
|
|
88453
|
+
matchTally: emptyTally(),
|
|
88454
|
+
matchShare: null,
|
|
88455
|
+
deviations: []
|
|
88456
|
+
};
|
|
88457
|
+
for (const open of history) {
|
|
88458
|
+
if (open.recommendation === null)
|
|
88459
|
+
out.withoutRecommendation += 1;
|
|
88460
|
+
else
|
|
88461
|
+
out.withRecommendation += 1;
|
|
88462
|
+
const first = firstAnswer(open.id);
|
|
88463
|
+
if (first === undefined)
|
|
88464
|
+
continue;
|
|
88465
|
+
out.answered += 1;
|
|
88466
|
+
if (open.recommendation === null)
|
|
88467
|
+
continue;
|
|
88468
|
+
out.matchTally.answered += 1;
|
|
88469
|
+
if (first.choice === open.recommendation.optionId) {
|
|
88470
|
+
out.matchTally.matched += 1;
|
|
88471
|
+
continue;
|
|
88472
|
+
}
|
|
88473
|
+
const reason = reasons.get(open.id)?.reason;
|
|
88474
|
+
out.deviations.push({
|
|
88475
|
+
id: open.id,
|
|
88476
|
+
flow: open.flow,
|
|
88477
|
+
stage: open.stage,
|
|
88478
|
+
mode: open.mode,
|
|
88479
|
+
question: open.question,
|
|
88480
|
+
recommended: open.recommendation.optionId,
|
|
88481
|
+
chose: first.choice,
|
|
88482
|
+
changed: false,
|
|
88483
|
+
...open.source !== undefined ? { source: open.source } : {},
|
|
88484
|
+
...reason !== undefined ? { reason } : {}
|
|
88485
|
+
});
|
|
88486
|
+
}
|
|
88487
|
+
out.matchShare = out.matchTally.answered === 0 ? null : out.matchTally.matched / out.matchTally.answered;
|
|
88488
|
+
return out;
|
|
88489
|
+
}
|
|
88438
88490
|
function buildReport2(records, skipped = 0) {
|
|
88439
88491
|
const opens = [];
|
|
88440
88492
|
const answers = new Map;
|
|
@@ -88454,8 +88506,11 @@ function buildReport2(records, skipped = 0) {
|
|
|
88454
88506
|
reasons.set(record.id, record);
|
|
88455
88507
|
}
|
|
88456
88508
|
}
|
|
88509
|
+
const live = opens.filter((open) => open.backfilled !== true);
|
|
88510
|
+
const history = opens.filter((open) => open.backfilled === true);
|
|
88511
|
+
const firstAnswer = (id) => [...answers.get(id) ?? []].sort((a, b) => a.seq - b.seq)[0];
|
|
88457
88512
|
const report = {
|
|
88458
|
-
total:
|
|
88513
|
+
total: live.length,
|
|
88459
88514
|
answered: 0,
|
|
88460
88515
|
unanswered: 0,
|
|
88461
88516
|
withoutRecommendation: 0,
|
|
@@ -88463,9 +88518,11 @@ function buildReport2(records, skipped = 0) {
|
|
|
88463
88518
|
byMode: { ordinary: emptyTally(), blind: emptyTally() },
|
|
88464
88519
|
byStage: [],
|
|
88465
88520
|
deviations: [],
|
|
88466
|
-
irreversible:
|
|
88467
|
-
blindRefused:
|
|
88468
|
-
inferredFlow:
|
|
88521
|
+
irreversible: live.filter((open) => open.irreversible).length,
|
|
88522
|
+
blindRefused: live.filter((open) => open.blindRefused === true).length,
|
|
88523
|
+
inferredFlow: live.filter((open) => open.flow !== null && open.flowSource === "inferred").length,
|
|
88524
|
+
timing: { answered: 0, medianMs: null },
|
|
88525
|
+
backfilled: buildBackfilled(history, firstAnswer, reasons),
|
|
88469
88526
|
skipped
|
|
88470
88527
|
};
|
|
88471
88528
|
const stages = new Map;
|
|
@@ -88474,7 +88531,8 @@ function buildReport2(records, skipped = 0) {
|
|
|
88474
88531
|
stages.set(name, found);
|
|
88475
88532
|
return found;
|
|
88476
88533
|
};
|
|
88477
|
-
|
|
88534
|
+
const times = [];
|
|
88535
|
+
for (const open of live) {
|
|
88478
88536
|
if (open.blindRefused === true)
|
|
88479
88537
|
stageOf(open.stage).blindRefused += 1;
|
|
88480
88538
|
const list = (answers.get(open.id) ?? []).sort((a, b) => a.seq - b.seq);
|
|
@@ -88484,6 +88542,7 @@ function buildReport2(records, skipped = 0) {
|
|
|
88484
88542
|
continue;
|
|
88485
88543
|
}
|
|
88486
88544
|
report.answered += 1;
|
|
88545
|
+
times.push(first.timeToAnswerMs);
|
|
88487
88546
|
if (list.length > 1)
|
|
88488
88547
|
report.changed += 1;
|
|
88489
88548
|
if (open.recommendation === null) {
|
|
@@ -88513,6 +88572,7 @@ function buildReport2(records, skipped = 0) {
|
|
|
88513
88572
|
});
|
|
88514
88573
|
}
|
|
88515
88574
|
}
|
|
88575
|
+
report.timing = { answered: times.length, medianMs: median(times) };
|
|
88516
88576
|
report.byStage = [...stages.entries()].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([stage, tallies]) => ({ stage, ...tallies }));
|
|
88517
88577
|
return report;
|
|
88518
88578
|
}
|
|
@@ -88521,14 +88581,45 @@ function share(tally) {
|
|
|
88521
88581
|
return "n/a";
|
|
88522
88582
|
return `${Math.round(tally.matched / tally.answered * 100)}% (${tally.matched}/${tally.answered})`;
|
|
88523
88583
|
}
|
|
88584
|
+
function backfilledShare(report) {
|
|
88585
|
+
if (report.matchTally.answered === 0)
|
|
88586
|
+
return "n/a";
|
|
88587
|
+
return `${Math.round(report.matchTally.matched / report.matchTally.answered * 100)}% (${report.matchTally.matched}/${report.matchTally.answered})`;
|
|
88588
|
+
}
|
|
88589
|
+
function renderBackfilled(report) {
|
|
88590
|
+
const lines = [
|
|
88591
|
+
"\u0414\u043E (\u0438\u0441\u0442\u043E\u0440\u0438\u0447\u0435\u0441\u043A\u043E\u0435, \u0434\u043E\u0437\u0430\u043F\u043E\u043B\u043D\u0435\u043D\u043E \u0437\u0430\u0434\u043D\u0438\u043C \u0447\u0438\u0441\u043B\u043E\u043C):",
|
|
88592
|
+
` \u0432\u0441\u0435\u0433\u043E: ${report.total}, \u0441 \u0440\u0435\u043A\u043E\u043C\u0435\u043D\u0434\u0430\u0446\u0438\u0435\u0439: ${report.withRecommendation}, \u0441\u043E\u0432\u043F\u0430\u0434\u0435\u043D\u0438\u0435: ${backfilledShare(report)}`,
|
|
88593
|
+
` \u043E\u0442\u043A\u043B\u043E\u043D\u0435\u043D\u0438\u0439: ${report.deviations.length}`
|
|
88594
|
+
];
|
|
88595
|
+
for (const dev of report.deviations) {
|
|
88596
|
+
const where = [dev.source === undefined ? undefined : oneLine2(dev.source), dev.flow === null ? "project" : `flow ${oneLine2(dev.flow)}`, oneLine2(dev.stage)].filter((part) => part !== undefined);
|
|
88597
|
+
lines.push(` ${oneLine2(dev.id)} [${where.join(", ")}]`);
|
|
88598
|
+
lines.push(` ${oneLine2(dev.question)}`);
|
|
88599
|
+
lines.push(` \u0440\u0435\u043A\u043E\u043C\u0435\u043D\u0434\u043E\u0432\u0430\u043D\u043E ${oneLine2(dev.recommended)}, \u0432\u044B\u0431\u0440\u0430\u043D\u043E ${oneLine2(dev.chose)}`);
|
|
88600
|
+
lines.push(` \u043F\u0440\u0438\u0447\u0438\u043D\u0430: ${dev.reason === undefined ? "(\u043D\u0435 \u0443\u043A\u0430\u0437\u0430\u043D\u0430)" : oneLine2(dev.reason)}`);
|
|
88601
|
+
}
|
|
88602
|
+
return lines;
|
|
88603
|
+
}
|
|
88604
|
+
function seconds(ms) {
|
|
88605
|
+
return `${(ms / 1000).toFixed(1)}s`;
|
|
88606
|
+
}
|
|
88524
88607
|
function renderReport(report) {
|
|
88525
88608
|
const skippedLine = report.skipped > 0 ? `Skipped ${report.skipped} unreadable journal record${report.skipped === 1 ? "" : "s"}.` : undefined;
|
|
88526
|
-
if (report.total === 0)
|
|
88609
|
+
if (report.total === 0 && report.backfilled.total === 0)
|
|
88527
88610
|
return skippedLine === undefined ? "No decisions recorded yet." : `No decisions recorded yet.
|
|
88528
88611
|
${skippedLine}`;
|
|
88612
|
+
if (report.total === 0) {
|
|
88613
|
+
const lines = ["No live decisions recorded yet.", "", ...renderBackfilled(report.backfilled)];
|
|
88614
|
+
if (skippedLine !== undefined)
|
|
88615
|
+
lines.push("", skippedLine);
|
|
88616
|
+
return lines.join(`
|
|
88617
|
+
`);
|
|
88618
|
+
}
|
|
88529
88619
|
const lines = [
|
|
88530
88620
|
`Decisions: ${report.total} recorded, ${report.answered} answered, ${report.unanswered} not answered yet`,
|
|
88531
88621
|
`Changed after the reveal: ${report.changed}. Without a recommendation: ${report.withoutRecommendation}.`,
|
|
88622
|
+
...report.timing.medianMs === null ? [] : [`Median time to answer: ${seconds(report.timing.medianMs)} (${report.timing.answered} answered).`],
|
|
88532
88623
|
"",
|
|
88533
88624
|
"Match with the recommendation, by mode (first answer):",
|
|
88534
88625
|
` ordinary ${share(report.byMode.ordinary)}`,
|
|
@@ -88555,15 +88646,27 @@ ${skippedLine}`;
|
|
|
88555
88646
|
if (report.inferredFlow > 0) {
|
|
88556
88647
|
lines.push("", `Flow attribution inferred (the one flow in progress, not named by KERYX_FLOW or the branch): ${report.inferredFlow} decision${report.inferredFlow === 1 ? "" : "s"}.`);
|
|
88557
88648
|
}
|
|
88649
|
+
if (report.backfilled.total > 0)
|
|
88650
|
+
lines.push("", ...renderBackfilled(report.backfilled));
|
|
88558
88651
|
if (skippedLine !== undefined)
|
|
88559
88652
|
lines.push("", skippedLine);
|
|
88560
88653
|
return lines.join(`
|
|
88561
88654
|
`);
|
|
88562
88655
|
}
|
|
88656
|
+
function percent(tally) {
|
|
88657
|
+
if (tally.answered === 0)
|
|
88658
|
+
return "\u043D\u0435\u0442 \u0434\u0430\u043D\u043D\u044B\u0445";
|
|
88659
|
+
return `${Math.round(tally.matched / tally.answered * 100)}% (${tally.matched}/${tally.answered})`;
|
|
88660
|
+
}
|
|
88661
|
+
function renderReportLine(report) {
|
|
88662
|
+
const all = report.total + report.backfilled.total;
|
|
88663
|
+
return `\u0416\u0443\u0440\u043D\u0430\u043B \u0440\u0435\u0448\u0435\u043D\u0438\u0439: \u0432\u0441\u0435\u0433\u043E ${all} (\u0434\u043E: ${report.backfilled.total}, \u043F\u043E\u0441\u043B\u0435: ${report.total}). ` + `\u0421\u043E\u0432\u043F\u0430\u0434\u0435\u043D\u0438\u0435 \u0441 \u0440\u0435\u043A\u043E\u043C\u0435\u043D\u0434\u0430\u0446\u0438\u0435\u0439: \u0432\u0438\u0434\u0438\u043C\u0430\u044F ${percent(report.byMode.ordinary)}, \u0441\u043A\u0440\u044B\u0442\u0430\u044F ${percent(report.byMode.blind)}; ` + `\u0434\u043E: ${percent(report.backfilled.matchTally)}.`;
|
|
88664
|
+
}
|
|
88563
88665
|
var init_report4 = () => {};
|
|
88564
88666
|
|
|
88565
88667
|
// src/decisions/store.ts
|
|
88566
|
-
import {
|
|
88668
|
+
import { randomUUID as randomUUID23 } from "crypto";
|
|
88669
|
+
import { appendFile as appendFile11, mkdir as mkdir52, open as open9, readFile as readFile102, rename as rename10, rm as rm13, stat as stat24 } from "fs/promises";
|
|
88567
88670
|
import path211 from "path";
|
|
88568
88671
|
async function journalRoot(cwd) {
|
|
88569
88672
|
const cached = rootCache.get(cwd);
|
|
@@ -88594,6 +88697,102 @@ async function appendRecord(cwd, record) {
|
|
|
88594
88697
|
await appendFile11(journalFile(root), `${JSON.stringify(record)}
|
|
88595
88698
|
`, { encoding: "utf8", mode: 384 });
|
|
88596
88699
|
}
|
|
88700
|
+
async function endsWithoutNewline2(file) {
|
|
88701
|
+
try {
|
|
88702
|
+
const text = await readFile102(file, "utf8");
|
|
88703
|
+
return text.length > 0 && !text.endsWith(`
|
|
88704
|
+
`);
|
|
88705
|
+
} catch {
|
|
88706
|
+
return false;
|
|
88707
|
+
}
|
|
88708
|
+
}
|
|
88709
|
+
async function appendRecords(cwd, records) {
|
|
88710
|
+
if (records.length === 0)
|
|
88711
|
+
return;
|
|
88712
|
+
const root = await journalRoot(cwd);
|
|
88713
|
+
await mkdir52(decisionsDir(root), { recursive: true });
|
|
88714
|
+
const file = journalFile(root);
|
|
88715
|
+
const lead = await endsWithoutNewline2(file) ? `
|
|
88716
|
+
` : "";
|
|
88717
|
+
await appendFile11(file, lead + records.map((record) => `${JSON.stringify(record)}
|
|
88718
|
+
`).join(""), { encoding: "utf8", mode: 384 });
|
|
88719
|
+
}
|
|
88720
|
+
function journalLockFile(root) {
|
|
88721
|
+
return `${journalFile(root)}.lock`;
|
|
88722
|
+
}
|
|
88723
|
+
function pidAlive(pid) {
|
|
88724
|
+
try {
|
|
88725
|
+
process.kill(pid, 0);
|
|
88726
|
+
return true;
|
|
88727
|
+
} catch (error) {
|
|
88728
|
+
return error.code === "EPERM";
|
|
88729
|
+
}
|
|
88730
|
+
}
|
|
88731
|
+
async function lockIsStale(file, staleMs) {
|
|
88732
|
+
let mtimeMs;
|
|
88733
|
+
try {
|
|
88734
|
+
mtimeMs = (await stat24(file)).mtimeMs;
|
|
88735
|
+
} catch {
|
|
88736
|
+
return false;
|
|
88737
|
+
}
|
|
88738
|
+
if (Date.now() - mtimeMs > staleMs)
|
|
88739
|
+
return true;
|
|
88740
|
+
try {
|
|
88741
|
+
const pid = JSON.parse(await readFile102(file, "utf8")).pid;
|
|
88742
|
+
return typeof pid === "number" && !pidAlive(pid);
|
|
88743
|
+
} catch {
|
|
88744
|
+
return false;
|
|
88745
|
+
}
|
|
88746
|
+
}
|
|
88747
|
+
async function ownsLock2(file, token) {
|
|
88748
|
+
try {
|
|
88749
|
+
return JSON.parse(await readFile102(file, "utf8")).token === token;
|
|
88750
|
+
} catch {
|
|
88751
|
+
return false;
|
|
88752
|
+
}
|
|
88753
|
+
}
|
|
88754
|
+
async function withJournalLock(cwd, fn, options = {}) {
|
|
88755
|
+
const staleMs = options.staleMs ?? JOURNAL_LOCK_STALE_MS;
|
|
88756
|
+
const timeoutMs = options.timeoutMs ?? JOURNAL_LOCK_TIMEOUT_MS;
|
|
88757
|
+
const pollMs = options.pollMs ?? 25;
|
|
88758
|
+
const root = await journalRoot(cwd);
|
|
88759
|
+
await mkdir52(decisionsDir(root), { recursive: true });
|
|
88760
|
+
const file = journalLockFile(root);
|
|
88761
|
+
const token = randomUUID23();
|
|
88762
|
+
const deadline = Date.now() + timeoutMs;
|
|
88763
|
+
for (;; ) {
|
|
88764
|
+
try {
|
|
88765
|
+
const handle = await open9(file, "wx", 384);
|
|
88766
|
+
try {
|
|
88767
|
+
await handle.writeFile(JSON.stringify({ pid: process.pid, at: new Date().toISOString(), token }));
|
|
88768
|
+
} finally {
|
|
88769
|
+
await handle.close();
|
|
88770
|
+
}
|
|
88771
|
+
break;
|
|
88772
|
+
} catch (error) {
|
|
88773
|
+
if (error.code !== "EEXIST")
|
|
88774
|
+
throw error;
|
|
88775
|
+
}
|
|
88776
|
+
if (await lockIsStale(file, staleMs)) {
|
|
88777
|
+
const aside = `${file}.stale-${process.pid}-${Date.now()}`;
|
|
88778
|
+
try {
|
|
88779
|
+
await rename10(file, aside);
|
|
88780
|
+
await rm13(aside, { force: true });
|
|
88781
|
+
} catch {}
|
|
88782
|
+
continue;
|
|
88783
|
+
}
|
|
88784
|
+
if (Date.now() >= deadline) {
|
|
88785
|
+
throw new Error(`the decisions journal is locked by another run (${file}); try again, or delete that file if no import is running`);
|
|
88786
|
+
}
|
|
88787
|
+
await new Promise((resolve) => setTimeout(resolve, pollMs));
|
|
88788
|
+
}
|
|
88789
|
+
try {
|
|
88790
|
+
return await fn();
|
|
88791
|
+
} finally {
|
|
88792
|
+
if (await ownsLock2(file, token))
|
|
88793
|
+
await rm13(file, { force: true });
|
|
88794
|
+
}
|
|
88795
|
+
}
|
|
88597
88796
|
function isOption(value) {
|
|
88598
88797
|
if (value === null || typeof value !== "object")
|
|
88599
88798
|
return false;
|
|
@@ -88669,7 +88868,7 @@ async function readJournal(cwd) {
|
|
|
88669
88868
|
async function readRecords(cwd) {
|
|
88670
88869
|
return (await readJournal(cwd)).records;
|
|
88671
88870
|
}
|
|
88672
|
-
var rootCache, isString2 = (value) => typeof value === "string";
|
|
88871
|
+
var rootCache, JOURNAL_LOCK_STALE_MS = 60000, JOURNAL_LOCK_TIMEOUT_MS = 15000, isString2 = (value) => typeof value === "string";
|
|
88673
88872
|
var init_store6 = __esm(() => {
|
|
88674
88873
|
init_git_worktrees();
|
|
88675
88874
|
rootCache = new Map;
|
|
@@ -88935,6 +89134,8 @@ async function answerDecision(input) {
|
|
|
88935
89134
|
const open = records.find((r) => r.kind === "open" && r.id === input.id);
|
|
88936
89135
|
if (open === undefined)
|
|
88937
89136
|
throw new Error(`no open decision with id ${input.id}`);
|
|
89137
|
+
if (open.backfilled === true)
|
|
89138
|
+
throw new Error(`decision ${open.id} is a backfilled historical record; its answer is not changed`);
|
|
88938
89139
|
const other = input.other === true;
|
|
88939
89140
|
const choice = other ? oneLine2(input.choice) : input.choice.trim();
|
|
88940
89141
|
if (choice.length === 0)
|
|
@@ -88979,8 +89180,11 @@ async function answerDecision(input) {
|
|
|
88979
89180
|
}
|
|
88980
89181
|
async function recordReason(cwd, id, text, now = () => new Date, options = {}) {
|
|
88981
89182
|
const records = await readRecords(cwd);
|
|
88982
|
-
|
|
89183
|
+
const open = records.find((r) => r.kind === "open" && r.id === id);
|
|
89184
|
+
if (open === undefined)
|
|
88983
89185
|
throw new Error(`no open decision with id ${id}`);
|
|
89186
|
+
if (open.backfilled === true)
|
|
89187
|
+
throw new Error(`decision ${id} is a backfilled historical record; its reason is not changed`);
|
|
88984
89188
|
if (options.replace !== true && records.some((r) => r.kind === "reason" && r.id === id))
|
|
88985
89189
|
return false;
|
|
88986
89190
|
const reason = text === undefined ? "" : oneLine2(text);
|
|
@@ -89116,6 +89320,244 @@ var init_ask2 = __esm(() => {
|
|
|
89116
89320
|
init_journal2();
|
|
89117
89321
|
});
|
|
89118
89322
|
|
|
89323
|
+
// src/decisions/import.ts
|
|
89324
|
+
function parseEntry3(raw) {
|
|
89325
|
+
if (!isObject(raw))
|
|
89326
|
+
return "a decision must be a JSON object";
|
|
89327
|
+
const id = raw["id"];
|
|
89328
|
+
if (!isString3(id) || id.trim().length === 0)
|
|
89329
|
+
return "needs a non-empty string id";
|
|
89330
|
+
const at = raw["at"];
|
|
89331
|
+
if (!isString3(at) || !Number.isFinite(Date.parse(at)))
|
|
89332
|
+
return `${id}: "at" must be an ISO date`;
|
|
89333
|
+
const flow = raw["flow"] === undefined ? null : raw["flow"];
|
|
89334
|
+
if (flow !== null && !isString3(flow))
|
|
89335
|
+
return `${id}: "flow" must be a string or null`;
|
|
89336
|
+
const stageRaw = raw["stage"];
|
|
89337
|
+
if (stageRaw !== undefined && !isString3(stageRaw))
|
|
89338
|
+
return `${id}: "stage" must be a string`;
|
|
89339
|
+
const question = raw["question"];
|
|
89340
|
+
if (!isString3(question) || oneLine2(question).length === 0)
|
|
89341
|
+
return `${id}: needs a question`;
|
|
89342
|
+
const optionsRaw = raw["options"];
|
|
89343
|
+
if (!Array.isArray(optionsRaw) || optionsRaw.length < 2)
|
|
89344
|
+
return `${id}: needs at least two options`;
|
|
89345
|
+
const options = [];
|
|
89346
|
+
const ids = new Set;
|
|
89347
|
+
for (const item of optionsRaw) {
|
|
89348
|
+
if (!isObject(item) || !isString3(item["id"]) || item["id"].trim().length === 0)
|
|
89349
|
+
return `${id}: every option needs an id`;
|
|
89350
|
+
const optionId = item["id"];
|
|
89351
|
+
if (ids.has(optionId))
|
|
89352
|
+
return `${id}: duplicate option id: ${optionId}`;
|
|
89353
|
+
ids.add(optionId);
|
|
89354
|
+
const label = isString3(item["label"]) && item["label"].length > 0 ? item["label"] : optionId;
|
|
89355
|
+
options.push({ id: optionId, label, ...isString3(item["description"]) && item["description"].length > 0 ? { description: item["description"] } : {} });
|
|
89356
|
+
}
|
|
89357
|
+
let recommendation = null;
|
|
89358
|
+
const recRaw = raw["recommendation"];
|
|
89359
|
+
if (recRaw !== undefined && recRaw !== null) {
|
|
89360
|
+
if (!isObject(recRaw) || !isString3(recRaw["optionId"]))
|
|
89361
|
+
return `${id}: "recommendation" needs an optionId`;
|
|
89362
|
+
if (!ids.has(recRaw["optionId"]))
|
|
89363
|
+
return `${id}: the recommended option "${recRaw["optionId"]}" is not one of the options`;
|
|
89364
|
+
recommendation = { optionId: recRaw["optionId"], reason: isString3(recRaw["reason"]) ? oneLine2(recRaw["reason"]) : "" };
|
|
89365
|
+
}
|
|
89366
|
+
let answer = null;
|
|
89367
|
+
const answerRaw = raw["answer"];
|
|
89368
|
+
if (answerRaw !== undefined && answerRaw !== null) {
|
|
89369
|
+
if (!isObject(answerRaw) || !isString3(answerRaw["choice"]) || answerRaw["choice"].trim().length === 0)
|
|
89370
|
+
return `${id}: "answer" needs a choice`;
|
|
89371
|
+
const other = answerRaw["other"] === true;
|
|
89372
|
+
if (!other && !ids.has(answerRaw["choice"].trim())) {
|
|
89373
|
+
return `${id}: the answer "${answerRaw["choice"]}" is not one of the options (use "other": true for the human's own words)`;
|
|
89374
|
+
}
|
|
89375
|
+
answer = { choice: other ? oneLine2(answerRaw["choice"]) : answerRaw["choice"].trim(), other };
|
|
89376
|
+
}
|
|
89377
|
+
const sourceRaw = raw["source"];
|
|
89378
|
+
if (sourceRaw !== undefined && !isString3(sourceRaw))
|
|
89379
|
+
return `${id}: "source" must be a string`;
|
|
89380
|
+
const reasonRaw = raw["reason"];
|
|
89381
|
+
if (reasonRaw !== undefined && reasonRaw !== null && !isString3(reasonRaw))
|
|
89382
|
+
return `${id}: "reason" must be a string`;
|
|
89383
|
+
const reason = isString3(reasonRaw) ? oneLine2(reasonRaw) : "";
|
|
89384
|
+
const source = isString3(sourceRaw) ? oneLine2(sourceRaw) : "";
|
|
89385
|
+
return {
|
|
89386
|
+
id,
|
|
89387
|
+
at,
|
|
89388
|
+
flow,
|
|
89389
|
+
stage: isString3(stageRaw) && stageRaw.trim().length > 0 ? oneLine2(stageRaw) : DEFAULT_STAGE,
|
|
89390
|
+
question: oneLine2(question),
|
|
89391
|
+
options,
|
|
89392
|
+
recommendation,
|
|
89393
|
+
...source.length > 0 ? { source } : {},
|
|
89394
|
+
answer,
|
|
89395
|
+
...reason.length > 0 ? { reason } : {}
|
|
89396
|
+
};
|
|
89397
|
+
}
|
|
89398
|
+
function parseBackfill(text) {
|
|
89399
|
+
const entries = [];
|
|
89400
|
+
const errors = [];
|
|
89401
|
+
text.split(`
|
|
89402
|
+
`).forEach((line, index) => {
|
|
89403
|
+
if (line.trim().length === 0)
|
|
89404
|
+
return;
|
|
89405
|
+
let parsed;
|
|
89406
|
+
try {
|
|
89407
|
+
parsed = JSON.parse(line);
|
|
89408
|
+
} catch {
|
|
89409
|
+
errors.push({ line: index + 1, message: "not valid JSON" });
|
|
89410
|
+
return;
|
|
89411
|
+
}
|
|
89412
|
+
const entry = parseEntry3(parsed);
|
|
89413
|
+
if (typeof entry === "string")
|
|
89414
|
+
errors.push({ line: index + 1, message: entry });
|
|
89415
|
+
else
|
|
89416
|
+
entries.push(entry);
|
|
89417
|
+
});
|
|
89418
|
+
return { entries, errors };
|
|
89419
|
+
}
|
|
89420
|
+
function answerRecordOf(entry, at) {
|
|
89421
|
+
if (entry.answer === null)
|
|
89422
|
+
return;
|
|
89423
|
+
return {
|
|
89424
|
+
kind: "answer",
|
|
89425
|
+
id: entry.id,
|
|
89426
|
+
at,
|
|
89427
|
+
seq: 1,
|
|
89428
|
+
choice: entry.answer.choice,
|
|
89429
|
+
timeToAnswerMs: 0,
|
|
89430
|
+
changed: false,
|
|
89431
|
+
...entry.answer.other ? { other: true } : {}
|
|
89432
|
+
};
|
|
89433
|
+
}
|
|
89434
|
+
function reasonRecordOf(entry, at) {
|
|
89435
|
+
return entry.reason === undefined ? undefined : { kind: "reason", id: entry.id, at, reason: entry.reason };
|
|
89436
|
+
}
|
|
89437
|
+
function backfillRecords(entry) {
|
|
89438
|
+
const open = {
|
|
89439
|
+
kind: "open",
|
|
89440
|
+
id: entry.id,
|
|
89441
|
+
at: entry.at,
|
|
89442
|
+
flow: entry.flow,
|
|
89443
|
+
stage: entry.stage,
|
|
89444
|
+
question: entry.question,
|
|
89445
|
+
options: entry.options,
|
|
89446
|
+
recommendation: entry.recommendation,
|
|
89447
|
+
mode: "ordinary",
|
|
89448
|
+
order: entry.options.map((option) => option.id),
|
|
89449
|
+
showMark: entry.recommendation !== null,
|
|
89450
|
+
irreversible: false,
|
|
89451
|
+
backfilled: true,
|
|
89452
|
+
...entry.source !== undefined ? { source: entry.source } : {}
|
|
89453
|
+
};
|
|
89454
|
+
const records = [open];
|
|
89455
|
+
const answer = answerRecordOf(entry, entry.at);
|
|
89456
|
+
if (answer !== undefined)
|
|
89457
|
+
records.push(answer);
|
|
89458
|
+
const reason = reasonRecordOf(entry, entry.at);
|
|
89459
|
+
if (reason !== undefined)
|
|
89460
|
+
records.push(reason);
|
|
89461
|
+
return records;
|
|
89462
|
+
}
|
|
89463
|
+
async function importBackfill(cwd, text, options = {}) {
|
|
89464
|
+
if (options.dryRun === true)
|
|
89465
|
+
return importUnlocked(cwd, text, options);
|
|
89466
|
+
return withJournalLock(cwd, () => importUnlocked(cwd, text, options));
|
|
89467
|
+
}
|
|
89468
|
+
async function importUnlocked(cwd, text, options) {
|
|
89469
|
+
const { entries, errors } = parseBackfill(text);
|
|
89470
|
+
const records = await readRecords(cwd);
|
|
89471
|
+
const known = new Map;
|
|
89472
|
+
const answered = new Set;
|
|
89473
|
+
const reasoned = new Set;
|
|
89474
|
+
for (const record of records) {
|
|
89475
|
+
if (record.kind === "open")
|
|
89476
|
+
known.set(record.id, record);
|
|
89477
|
+
else if (record.kind === "answer")
|
|
89478
|
+
answered.add(record.id);
|
|
89479
|
+
else
|
|
89480
|
+
reasoned.add(record.id);
|
|
89481
|
+
}
|
|
89482
|
+
const result = {
|
|
89483
|
+
dryRun: options.dryRun === true,
|
|
89484
|
+
imported: 0,
|
|
89485
|
+
skipped: 0,
|
|
89486
|
+
withRecommendation: 0,
|
|
89487
|
+
answered: 0,
|
|
89488
|
+
deviations: 0,
|
|
89489
|
+
skippedIds: [],
|
|
89490
|
+
repaired: 0,
|
|
89491
|
+
repairedIds: [],
|
|
89492
|
+
malformed: errors
|
|
89493
|
+
};
|
|
89494
|
+
const toWrite = [];
|
|
89495
|
+
for (const entry of entries) {
|
|
89496
|
+
const existing = known.get(entry.id);
|
|
89497
|
+
if (existing !== undefined) {
|
|
89498
|
+
const answer = entry.answer;
|
|
89499
|
+
const repairable = existing.backfilled === true && answer !== null && !answered.has(entry.id) && (answer.other || existing.options.some((option) => option.id === answer.choice));
|
|
89500
|
+
if (!repairable || answer === null) {
|
|
89501
|
+
result.skipped += 1;
|
|
89502
|
+
result.skippedIds.push(entry.id);
|
|
89503
|
+
continue;
|
|
89504
|
+
}
|
|
89505
|
+
const missing = [answerRecordOf(entry, existing.at), reasoned.has(entry.id) ? undefined : reasonRecordOf(entry, existing.at)].filter((record) => record !== undefined);
|
|
89506
|
+
toWrite.push(...missing);
|
|
89507
|
+
answered.add(entry.id);
|
|
89508
|
+
result.repaired += 1;
|
|
89509
|
+
result.repairedIds.push(entry.id);
|
|
89510
|
+
result.answered += 1;
|
|
89511
|
+
if (existing.recommendation !== null && answer.choice !== existing.recommendation.optionId)
|
|
89512
|
+
result.deviations += 1;
|
|
89513
|
+
continue;
|
|
89514
|
+
}
|
|
89515
|
+
known.set(entry.id, backfillRecords(entry)[0]);
|
|
89516
|
+
answered.add(entry.id);
|
|
89517
|
+
result.imported += 1;
|
|
89518
|
+
if (entry.recommendation !== null)
|
|
89519
|
+
result.withRecommendation += 1;
|
|
89520
|
+
if (entry.answer !== null) {
|
|
89521
|
+
result.answered += 1;
|
|
89522
|
+
if (entry.recommendation !== null && entry.answer.choice !== entry.recommendation.optionId)
|
|
89523
|
+
result.deviations += 1;
|
|
89524
|
+
}
|
|
89525
|
+
toWrite.push(...backfillRecords(entry));
|
|
89526
|
+
}
|
|
89527
|
+
if (!result.dryRun)
|
|
89528
|
+
await appendRecords(cwd, toWrite);
|
|
89529
|
+
return result;
|
|
89530
|
+
}
|
|
89531
|
+
function renderImportResult(result) {
|
|
89532
|
+
const repaired = result.repaired > 0 ? `, repaired: ${result.repaired}` : "";
|
|
89533
|
+
const malformed = result.malformed.length > 0 ? `, malformed: ${result.malformed.length}` : "";
|
|
89534
|
+
const lines = [
|
|
89535
|
+
`${result.dryRun ? "Dry run, nothing written. " : ""}Imported: ${result.imported}, skipped: ${result.skipped}, with recommendation: ${result.withRecommendation}, answered: ${result.answered}, deviations: ${result.deviations}${repaired}${malformed}`
|
|
89536
|
+
];
|
|
89537
|
+
if (result.skippedIds.length > 0) {
|
|
89538
|
+
const shown = result.skippedIds.slice(0, 20).map((id) => oneLine2(id, 80));
|
|
89539
|
+
lines.push(`Skipped (already in the journal): ${shown.join(", ")}${result.skippedIds.length > shown.length ? `, ... and ${result.skippedIds.length - shown.length} more` : ""}`);
|
|
89540
|
+
}
|
|
89541
|
+
if (result.repairedIds.length > 0) {
|
|
89542
|
+
const shown = result.repairedIds.slice(0, 20).map((id) => oneLine2(id, 80));
|
|
89543
|
+
lines.push(`Repaired (the answer was missing from the journal and was added): ${shown.join(", ")}${result.repairedIds.length > shown.length ? `, ... and ${result.repairedIds.length - shown.length} more` : ""}`);
|
|
89544
|
+
}
|
|
89545
|
+
if (result.malformed.length > 0) {
|
|
89546
|
+
lines.push("Malformed (skipped):");
|
|
89547
|
+
for (const error of result.malformed.slice(0, 20))
|
|
89548
|
+
lines.push(` line ${error.line}: ${oneLine2(error.message, 200)}`);
|
|
89549
|
+
if (result.malformed.length > 20)
|
|
89550
|
+
lines.push(` ... and ${result.malformed.length - 20} more`);
|
|
89551
|
+
}
|
|
89552
|
+
return lines.join(`
|
|
89553
|
+
`);
|
|
89554
|
+
}
|
|
89555
|
+
var isString3 = (value) => typeof value === "string", isObject = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
89556
|
+
var init_import = __esm(() => {
|
|
89557
|
+
init_journal2();
|
|
89558
|
+
init_store6();
|
|
89559
|
+
});
|
|
89560
|
+
|
|
89119
89561
|
// src/decisions/context.ts
|
|
89120
89562
|
async function currentBranch(cwd) {
|
|
89121
89563
|
try {
|
|
@@ -89203,7 +89645,7 @@ async function latestAnsweredDecision(cwd, flow) {
|
|
|
89203
89645
|
const answered = new Set(records.filter((r) => r.kind === "answer").map((r) => r.id));
|
|
89204
89646
|
for (let i = records.length - 1;i >= 0; i -= 1) {
|
|
89205
89647
|
const record = records[i];
|
|
89206
|
-
if (record !== undefined && record.kind === "open" && answered.has(record.id) && (flow === undefined || record.flow === flow))
|
|
89648
|
+
if (record !== undefined && record.kind === "open" && record.backfilled !== true && answered.has(record.id) && (flow === undefined || record.flow === flow))
|
|
89207
89649
|
return record.id;
|
|
89208
89650
|
}
|
|
89209
89651
|
return;
|
|
@@ -89261,6 +89703,8 @@ function resolveOptionId(open, typed) {
|
|
|
89261
89703
|
}
|
|
89262
89704
|
async function changeAnswer(input) {
|
|
89263
89705
|
const open = await resolveOpen(input.cwd, input.id, input.lastId, input.flow, input.session, "keryx decisions answer <id> --choice <option>");
|
|
89706
|
+
if (open.backfilled === true)
|
|
89707
|
+
throw new Error(`decision ${open.id} is a backfilled historical record; its answer is not changed`);
|
|
89264
89708
|
const choice = resolveOptionId(open, input.choice);
|
|
89265
89709
|
const answers = (await readRecords(input.cwd)).filter((r) => r.kind === "answer" && r.id === open.id);
|
|
89266
89710
|
const first = [...answers].sort((x, y) => x.seq - y.seq)[0];
|
|
@@ -89280,9 +89724,15 @@ async function loadReport(cwd) {
|
|
|
89280
89724
|
async function reportText(cwd) {
|
|
89281
89725
|
return renderReport(await loadReport(cwd));
|
|
89282
89726
|
}
|
|
89727
|
+
async function reportLine(cwd) {
|
|
89728
|
+
return renderReportLine(await loadReport(cwd));
|
|
89729
|
+
}
|
|
89283
89730
|
async function decisionCount(cwd) {
|
|
89284
89731
|
return (await loadReport(cwd)).total;
|
|
89285
89732
|
}
|
|
89733
|
+
async function backfilledCount(cwd) {
|
|
89734
|
+
return (await loadReport(cwd)).backfilled.total;
|
|
89735
|
+
}
|
|
89286
89736
|
var init_service13 = __esm(() => {
|
|
89287
89737
|
init_report4();
|
|
89288
89738
|
init_store6();
|
|
@@ -89290,13 +89740,14 @@ var init_service13 = __esm(() => {
|
|
|
89290
89740
|
init_blind();
|
|
89291
89741
|
init_journal2();
|
|
89292
89742
|
init_report4();
|
|
89743
|
+
init_import();
|
|
89293
89744
|
init_store6();
|
|
89294
89745
|
init_context2();
|
|
89295
89746
|
init_followup();
|
|
89296
89747
|
});
|
|
89297
89748
|
|
|
89298
89749
|
// src/tui/ask-user-bridge.ts
|
|
89299
|
-
import { randomUUID as
|
|
89750
|
+
import { randomUUID as randomUUID24 } from "crypto";
|
|
89300
89751
|
function setAskUserHost(fn) {
|
|
89301
89752
|
host = fn;
|
|
89302
89753
|
}
|
|
@@ -89331,7 +89782,7 @@ function journaledAskUser(cwd) {
|
|
|
89331
89782
|
var host, notice, lastDecisionId, sessionId;
|
|
89332
89783
|
var init_ask_user_bridge = __esm(() => {
|
|
89333
89784
|
init_service13();
|
|
89334
|
-
sessionId = `s-${
|
|
89785
|
+
sessionId = `s-${randomUUID24()}`;
|
|
89335
89786
|
});
|
|
89336
89787
|
|
|
89337
89788
|
// src/harness/tool/metaproject-operations.ts
|
|
@@ -90872,7 +91323,7 @@ var init_project_tools = __esm(() => {
|
|
|
90872
91323
|
});
|
|
90873
91324
|
|
|
90874
91325
|
// src/commands/interactive-agent-tools.ts
|
|
90875
|
-
import { randomUUID as
|
|
91326
|
+
import { randomUUID as randomUUID25 } from "crypto";
|
|
90876
91327
|
function denyInteractiveTools(tools, denied) {
|
|
90877
91328
|
if (denied.length === 0)
|
|
90878
91329
|
return [...tools];
|
|
@@ -90890,7 +91341,7 @@ function buildInteractiveAgentTools(input) {
|
|
|
90890
91341
|
const getSessionDir = input.getSessionDir ?? (() => {
|
|
90891
91342
|
return;
|
|
90892
91343
|
});
|
|
90893
|
-
const idSeq = input.idSeq ?? (() =>
|
|
91344
|
+
const idSeq = input.idSeq ?? (() => randomUUID25());
|
|
90894
91345
|
const clock = input.clock ?? (() => new Date().toISOString());
|
|
90895
91346
|
const jobRegistry = input.jobRegistry;
|
|
90896
91347
|
const project = buildProjectTools(input.cwd, input.metaprojectPort);
|
|
@@ -93393,9 +93844,9 @@ var init_registry3 = __esm(() => {
|
|
|
93393
93844
|
});
|
|
93394
93845
|
|
|
93395
93846
|
// src/harness/tool/builtin/spawn-subagent-tool.ts
|
|
93396
|
-
import { createHash as createHash60, randomUUID as
|
|
93847
|
+
import { createHash as createHash60, randomUUID as randomUUID26 } from "crypto";
|
|
93397
93848
|
import { execFile as execFile7 } from "child_process";
|
|
93398
|
-
import { lstat as lstat14, mkdtemp as mkdtemp2, readFile as readFile104, realpath as realpath17, rm as
|
|
93849
|
+
import { lstat as lstat14, mkdtemp as mkdtemp2, readFile as readFile104, realpath as realpath17, rm as rm14 } from "fs/promises";
|
|
93399
93850
|
import { tmpdir as tmpdir6 } from "os";
|
|
93400
93851
|
import path216 from "path";
|
|
93401
93852
|
import { promisify as promisify5 } from "util";
|
|
@@ -93585,7 +94036,7 @@ async function verifyWorktreeCandidate(candidate, commonDir, worktreesDir) {
|
|
|
93585
94036
|
}
|
|
93586
94037
|
}
|
|
93587
94038
|
function createSpawnSubagentTool(deps) {
|
|
93588
|
-
const idSeq = deps.idSeq ?? (() =>
|
|
94039
|
+
const idSeq = deps.idSeq ?? (() => randomUUID26());
|
|
93589
94040
|
const clock = deps.clock ?? (() => new Date().toISOString());
|
|
93590
94041
|
const parentRunId = deps.parentRunId ?? idSeq();
|
|
93591
94042
|
const parentSessionId = deps.parentSessionId ?? idSeq();
|
|
@@ -93946,7 +94397,7 @@ function createSpawnSubagentTool(deps) {
|
|
|
93946
94397
|
provider = deps.makeProvider(runModel.provider, runModel.model, parent.baseUrl);
|
|
93947
94398
|
} catch (cause) {
|
|
93948
94399
|
if (ephemeralDir !== undefined) {
|
|
93949
|
-
await
|
|
94400
|
+
await rm14(ephemeralDir, { recursive: true, force: true }).catch(() => {});
|
|
93950
94401
|
}
|
|
93951
94402
|
await fireSubagentStop("Error").catch(() => {});
|
|
93952
94403
|
ledger.release(spawned.reservation.reservationId, {
|
|
@@ -94072,7 +94523,7 @@ function createSpawnSubagentTool(deps) {
|
|
|
94072
94523
|
}
|
|
94073
94524
|
}
|
|
94074
94525
|
} finally {
|
|
94075
|
-
await
|
|
94526
|
+
await rm14(dirToClean, { recursive: true, force: true }).catch(() => {});
|
|
94076
94527
|
}
|
|
94077
94528
|
});
|
|
94078
94529
|
} catch (lockCause) {
|
|
@@ -94082,7 +94533,7 @@ function createSpawnSubagentTool(deps) {
|
|
|
94082
94533
|
id: workerId,
|
|
94083
94534
|
entry: { kind: "system", text: `slate cleanup lock failed (ignored): ${lockMsg}` }
|
|
94084
94535
|
});
|
|
94085
|
-
await
|
|
94536
|
+
await rm14(dirToClean, { recursive: true, force: true }).catch(() => {});
|
|
94086
94537
|
}
|
|
94087
94538
|
};
|
|
94088
94539
|
try {
|
|
@@ -95887,7 +96338,7 @@ var init_dispatch2 = __esm(() => {
|
|
|
95887
96338
|
|
|
95888
96339
|
// src/harness/external/acp-fs.ts
|
|
95889
96340
|
import { constants as constants2, realpathSync as realpathSync15, statSync as statSync12 } from "fs";
|
|
95890
|
-
import { mkdir as mkdir53, open as
|
|
96341
|
+
import { mkdir as mkdir53, open as open10, readFile as readFile105 } from "fs/promises";
|
|
95891
96342
|
import path219 from "path";
|
|
95892
96343
|
function refusedMethodError(method, reason) {
|
|
95893
96344
|
return new AcpError(JSON_RPC_ERROR_CODES.methodNotFound, `${method} refused: ${reason}`, { reason });
|
|
@@ -95956,7 +96407,7 @@ async function writeTextFileInWorktree(worktree, target, content, requested, hoo
|
|
|
95956
96407
|
const finalTarget = path219.join(parentReal, path219.basename(target));
|
|
95957
96408
|
let handle;
|
|
95958
96409
|
try {
|
|
95959
|
-
handle = await
|
|
96410
|
+
handle = await open10(finalTarget, constants2.O_WRONLY | constants2.O_CREAT | constants2.O_TRUNC | constants2.O_NOFOLLOW, 420);
|
|
95960
96411
|
} catch (error) {
|
|
95961
96412
|
const code = error.code;
|
|
95962
96413
|
if (code === "ELOOP" || code === "EMLINK") {
|
|
@@ -96121,7 +96572,7 @@ function describeOutcome(outcome) {
|
|
|
96121
96572
|
return outcome.reason;
|
|
96122
96573
|
return "an unexpected result";
|
|
96123
96574
|
}
|
|
96124
|
-
function
|
|
96575
|
+
function isObject2(value) {
|
|
96125
96576
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
96126
96577
|
}
|
|
96127
96578
|
function short(value, max = 500) {
|
|
@@ -96131,7 +96582,7 @@ function short(value, max = 500) {
|
|
|
96131
96582
|
function readOptions(raw) {
|
|
96132
96583
|
if (!Array.isArray(raw))
|
|
96133
96584
|
return [];
|
|
96134
|
-
return raw.filter((option) =>
|
|
96585
|
+
return raw.filter((option) => isObject2(option) && typeof option["optionId"] === "string" && typeof option["kind"] === "string");
|
|
96135
96586
|
}
|
|
96136
96587
|
async function superviseAcpRun(input, deps) {
|
|
96137
96588
|
const clientCapabilities = acpClientCapabilities(input.write);
|
|
@@ -96203,7 +96654,7 @@ async function superviseAcpRun(input, deps) {
|
|
|
96203
96654
|
let promptRequestId;
|
|
96204
96655
|
let boundSessionId;
|
|
96205
96656
|
const guardSession = (method, params) => {
|
|
96206
|
-
const claimed =
|
|
96657
|
+
const claimed = isObject2(params) ? params["sessionId"] : undefined;
|
|
96207
96658
|
let reason;
|
|
96208
96659
|
if (phase !== "prompting") {
|
|
96209
96660
|
reason = phase === "handshake" ? "no prompt is in progress yet; keryx answers only during this run's turn" : "this run's turn has ended; keryx no longer answers for it";
|
|
@@ -96234,9 +96685,9 @@ async function superviseAcpRun(input, deps) {
|
|
|
96234
96685
|
});
|
|
96235
96686
|
dispatcher.onRequest(ACP_CLIENT_METHODS.sessionRequestPermission, async (params, context) => {
|
|
96236
96687
|
guardSession(ACP_CLIENT_METHODS.sessionRequestPermission, params);
|
|
96237
|
-
const p =
|
|
96688
|
+
const p = isObject2(params) ? params : {};
|
|
96238
96689
|
const rawToolCall = p["toolCall"];
|
|
96239
|
-
const toolCall =
|
|
96690
|
+
const toolCall = isObject2(rawToolCall) && typeof rawToolCall["toolCallId"] === "string" ? rawToolCall : { toolCallId: "unidentified" };
|
|
96240
96691
|
const { answer, decision } = await answerAcpPermission({ requestId: context.id, toolCall, options: readOptions(p["options"]) }, permissionContext);
|
|
96241
96692
|
recordDecision(decision);
|
|
96242
96693
|
return { outcome: answer.outcome };
|
|
@@ -96244,7 +96695,7 @@ async function superviseAcpRun(input, deps) {
|
|
|
96244
96695
|
dispatcher.onRequest(ACP_CLIENT_METHODS.fsReadTextFile, async (params) => {
|
|
96245
96696
|
const method = ACP_CLIENT_METHODS.fsReadTextFile;
|
|
96246
96697
|
guardSession(method, params);
|
|
96247
|
-
const p =
|
|
96698
|
+
const p = isObject2(params) ? params : {};
|
|
96248
96699
|
try {
|
|
96249
96700
|
const { content } = await readTextFileInWorktree(input.cwd, p);
|
|
96250
96701
|
recordFs({ method, path: String(p["path"]), outcome: "served", bytes: Buffer.byteLength(content, "utf8") });
|
|
@@ -96257,7 +96708,7 @@ async function superviseAcpRun(input, deps) {
|
|
|
96257
96708
|
dispatcher.onRequest(ACP_CLIENT_METHODS.fsWriteTextFile, async (params, context) => {
|
|
96258
96709
|
const method = ACP_CLIENT_METHODS.fsWriteTextFile;
|
|
96259
96710
|
guardSession(method, params);
|
|
96260
|
-
const p =
|
|
96711
|
+
const p = isObject2(params) ? params : {};
|
|
96261
96712
|
const requested = typeof p["path"] === "string" ? p["path"] : String(p["path"]);
|
|
96262
96713
|
if (!input.write) {
|
|
96263
96714
|
const reason = "keryx did not advertise fs.writeTextFile (a read-only run)";
|
|
@@ -96294,7 +96745,7 @@ async function superviseAcpRun(input, deps) {
|
|
|
96294
96745
|
});
|
|
96295
96746
|
for (const [method, reason] of ACP_REFUSED_CLIENT_METHODS) {
|
|
96296
96747
|
dispatcher.onRequest(method, (params) => {
|
|
96297
|
-
const p =
|
|
96748
|
+
const p = isObject2(params) ? params : {};
|
|
96298
96749
|
recordFs({
|
|
96299
96750
|
method,
|
|
96300
96751
|
...typeof p["command"] === "string" ? { path: p["command"] } : {},
|
|
@@ -96308,7 +96759,7 @@ async function superviseAcpRun(input, deps) {
|
|
|
96308
96759
|
return;
|
|
96309
96760
|
});
|
|
96310
96761
|
dispatcher.onNotification(ACP_CLIENT_METHODS.sessionUpdate, (params) => {
|
|
96311
|
-
if (!
|
|
96762
|
+
if (!isObject2(params) || !isObject2(params["update"]))
|
|
96312
96763
|
return;
|
|
96313
96764
|
if (boundSessionId === undefined || params["sessionId"] !== boundSessionId) {
|
|
96314
96765
|
stderr.push(`[keryx] ignored a session/update for session ${JSON.stringify(params["sessionId"] ?? null)}`);
|
|
@@ -96368,7 +96819,7 @@ async function superviseAcpRun(input, deps) {
|
|
|
96368
96819
|
usage = { used: update.used, size: update.size };
|
|
96369
96820
|
}
|
|
96370
96821
|
const reported = update.cost;
|
|
96371
|
-
if (
|
|
96822
|
+
if (isObject2(reported) && typeof reported["amount"] === "number" && typeof reported["currency"] === "string") {
|
|
96372
96823
|
cost = { amount: reported["amount"], currency: reported["currency"] };
|
|
96373
96824
|
}
|
|
96374
96825
|
emit(cost !== undefined && cost.currency === "USD" ? { kind: "usage", costUnits: cost.amount } : { kind: "usage" });
|
|
@@ -96385,7 +96836,7 @@ async function superviseAcpRun(input, deps) {
|
|
|
96385
96836
|
if (phase === "prompting" && promptRequestId !== undefined && line.includes(promptRequestId)) {
|
|
96386
96837
|
try {
|
|
96387
96838
|
const value = JSON.parse(line);
|
|
96388
|
-
if (
|
|
96839
|
+
if (isObject2(value) && !("method" in value) && value["id"] === promptRequestId)
|
|
96389
96840
|
phase = "ended";
|
|
96390
96841
|
} catch {}
|
|
96391
96842
|
}
|
|
@@ -96465,16 +96916,16 @@ async function superviseAcpRun(input, deps) {
|
|
|
96465
96916
|
failure = `the agent did not answer initialize within ${input.timeoutMs}ms`;
|
|
96466
96917
|
return await finish();
|
|
96467
96918
|
}
|
|
96468
|
-
if (init.kind !== "result" || !
|
|
96919
|
+
if (init.kind !== "result" || !isObject2(init.result)) {
|
|
96469
96920
|
failure = `the agent did not answer initialize: ${describeOutcome(init)}`;
|
|
96470
96921
|
return await finish();
|
|
96471
96922
|
}
|
|
96472
96923
|
const initResult = init.result;
|
|
96473
96924
|
const version = initResult["protocolVersion"];
|
|
96474
96925
|
protocolVersion = typeof version === "number" ? version : undefined;
|
|
96475
|
-
if (
|
|
96926
|
+
if (isObject2(initResult["agentInfo"]))
|
|
96476
96927
|
agentInfo = initResult["agentInfo"];
|
|
96477
|
-
if (
|
|
96928
|
+
if (isObject2(initResult["agentCapabilities"]))
|
|
96478
96929
|
agentCapabilities = initResult["agentCapabilities"];
|
|
96479
96930
|
if (typeof version !== "number" || !ACP_SUPPORTED_PROTOCOL_VERSIONS.includes(version)) {
|
|
96480
96931
|
failure = `unsupported ACP protocol version: the agent answered initialize with protocolVersion ${JSON.stringify(version)}; ` + `keryx speaks ${ACP_SUPPORTED_PROTOCOL_VERSIONS.join(", ")}`;
|
|
@@ -96486,7 +96937,7 @@ async function superviseAcpRun(input, deps) {
|
|
|
96486
96937
|
failure = `the agent did not answer session/new within ${input.timeoutMs}ms`;
|
|
96487
96938
|
return await finish();
|
|
96488
96939
|
}
|
|
96489
|
-
if (created.kind !== "result" || !
|
|
96940
|
+
if (created.kind !== "result" || !isObject2(created.result) || typeof created.result["sessionId"] !== "string") {
|
|
96490
96941
|
failure = `the agent refused session/new: ${created.kind === "result" ? "no sessionId in the answer" : describeOutcome(created)}`;
|
|
96491
96942
|
return await finish();
|
|
96492
96943
|
}
|
|
@@ -96526,12 +96977,12 @@ ${resource.text}` });
|
|
|
96526
96977
|
const grace = afterMs(graceMs);
|
|
96527
96978
|
const late = await Promise.race([turn, grace.promise]);
|
|
96528
96979
|
grace.cancel();
|
|
96529
|
-
if (late !== TIMEOUT && late.kind === "result" &&
|
|
96980
|
+
if (late !== TIMEOUT && late.kind === "result" && isObject2(late.result) && typeof late.result["stopReason"] === "string") {
|
|
96530
96981
|
stopReason = late.result["stopReason"];
|
|
96531
96982
|
}
|
|
96532
96983
|
return await finish();
|
|
96533
96984
|
}
|
|
96534
|
-
if (answered.kind !== "result" || !
|
|
96985
|
+
if (answered.kind !== "result" || !isObject2(answered.result)) {
|
|
96535
96986
|
failure = `session/prompt did not complete: ${describeOutcome(answered)}`;
|
|
96536
96987
|
return await finish();
|
|
96537
96988
|
}
|
|
@@ -96610,7 +97061,7 @@ var init_acp_client = __esm(() => {
|
|
|
96610
97061
|
// src/harness/external/acp-run.ts
|
|
96611
97062
|
import { execFile as execFile9 } from "child_process";
|
|
96612
97063
|
import { existsSync as existsSync38, readFileSync as readFileSync20, writeFileSync as writeFileSync4 } from "fs";
|
|
96613
|
-
import { mkdtemp as mkdtemp3, rm as
|
|
97064
|
+
import { mkdtemp as mkdtemp3, rm as rm15 } from "fs/promises";
|
|
96614
97065
|
import { tmpdir as tmpdir7 } from "os";
|
|
96615
97066
|
import path220 from "path";
|
|
96616
97067
|
import { promisify as promisify7 } from "util";
|
|
@@ -96687,7 +97138,7 @@ async function captureWorktreePatch(worktreePath) {
|
|
|
96687
97138
|
} catch {
|
|
96688
97139
|
return;
|
|
96689
97140
|
} finally {
|
|
96690
|
-
await
|
|
97141
|
+
await rm15(dir, { recursive: true, force: true }).catch(() => {
|
|
96691
97142
|
return;
|
|
96692
97143
|
});
|
|
96693
97144
|
}
|
|
@@ -98048,7 +98499,7 @@ var init_codec2 = __esm(() => {
|
|
|
98048
98499
|
});
|
|
98049
98500
|
|
|
98050
98501
|
// src/harness/external/runtime.ts
|
|
98051
|
-
import { mkdtemp as mkdtemp4, rm as
|
|
98502
|
+
import { mkdtemp as mkdtemp4, rm as rm16, writeFile as writeFile34 } from "fs/promises";
|
|
98052
98503
|
import { tmpdir as tmpdir8 } from "os";
|
|
98053
98504
|
import path221 from "path";
|
|
98054
98505
|
function refuse2(status, output) {
|
|
@@ -98065,7 +98516,7 @@ async function prepareResultSchema() {
|
|
|
98065
98516
|
return { ok: true, schema, schemaText, schemaPath, schemaDir };
|
|
98066
98517
|
} catch (error) {
|
|
98067
98518
|
if (schemaDir !== undefined) {
|
|
98068
|
-
await
|
|
98519
|
+
await rm16(schemaDir, { recursive: true, force: true }).catch(() => {
|
|
98069
98520
|
return;
|
|
98070
98521
|
});
|
|
98071
98522
|
}
|
|
@@ -98172,7 +98623,7 @@ async function runExternalChild(input, deps) {
|
|
|
98172
98623
|
try {
|
|
98173
98624
|
await writeFile34(resultSchemaPathForCodec, JSON.stringify(toStrictOutputSchema(bundledResultSchema)), "utf8");
|
|
98174
98625
|
} catch (error) {
|
|
98175
|
-
await
|
|
98626
|
+
await rm16(schemaDir, { recursive: true, force: true }).catch(() => {
|
|
98176
98627
|
return;
|
|
98177
98628
|
});
|
|
98178
98629
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -98267,7 +98718,7 @@ async function runExternalChild(input, deps) {
|
|
|
98267
98718
|
});
|
|
98268
98719
|
}
|
|
98269
98720
|
} finally {
|
|
98270
|
-
await
|
|
98721
|
+
await rm16(schemaDir, { recursive: true, force: true }).catch(() => {
|
|
98271
98722
|
return;
|
|
98272
98723
|
});
|
|
98273
98724
|
}
|
|
@@ -98434,7 +98885,7 @@ var init_runtime2 = __esm(() => {
|
|
|
98434
98885
|
});
|
|
98435
98886
|
|
|
98436
98887
|
// src/harness/run-external-factory.ts
|
|
98437
|
-
import { randomUUID as
|
|
98888
|
+
import { randomUUID as randomUUID27 } from "crypto";
|
|
98438
98889
|
import { execFile as execFile10 } from "child_process";
|
|
98439
98890
|
import { mkdir as mkdir54 } from "fs/promises";
|
|
98440
98891
|
import { tmpdir as tmpdir9 } from "os";
|
|
@@ -98495,7 +98946,7 @@ async function createRunExternal(options) {
|
|
|
98495
98946
|
return;
|
|
98496
98947
|
}
|
|
98497
98948
|
const config = gate.config;
|
|
98498
|
-
const idSeq = options.idSeq ?? (() =>
|
|
98949
|
+
const idSeq = options.idSeq ?? (() => randomUUID27());
|
|
98499
98950
|
const worktreesDir = options.worktreesDir ?? path222.join(tmpdir9(), "keryx-external-worktrees");
|
|
98500
98951
|
const spawn = options.spawn ?? createBunSpawnPort();
|
|
98501
98952
|
const worktree = options.worktree ?? ensuringParentDir(createGitWorktreePort({ repoRoot: options.cwd, worktreesDir }), worktreesDir);
|
|
@@ -99434,7 +99885,7 @@ var init_client2 = __esm(() => {
|
|
|
99434
99885
|
|
|
99435
99886
|
// src/lib/file-lock.ts
|
|
99436
99887
|
import { closeSync as closeSync3, mkdirSync as mkdirSync7, openSync as openSync3, readFileSync as readFileSync21, rmSync as rmSync3, statSync as statSync13, writeFileSync as writeFileSync6 } from "fs";
|
|
99437
|
-
import { randomUUID as
|
|
99888
|
+
import { randomUUID as randomUUID28 } from "crypto";
|
|
99438
99889
|
import path225 from "path";
|
|
99439
99890
|
function sleepSync(ms) {
|
|
99440
99891
|
const bunSleep = globalThis.Bun?.sleepSync;
|
|
@@ -99451,7 +99902,7 @@ function withFileLock2(lockPath, fn, options = {}) {
|
|
|
99451
99902
|
} catch {
|
|
99452
99903
|
return null;
|
|
99453
99904
|
}
|
|
99454
|
-
const nonce =
|
|
99905
|
+
const nonce = randomUUID28();
|
|
99455
99906
|
const started = Date.now();
|
|
99456
99907
|
const deadline = started + LOCK_TIMEOUT_MS;
|
|
99457
99908
|
let handle = null;
|
|
@@ -101709,7 +102160,7 @@ import {
|
|
|
101709
102160
|
writeFileSync as writeFileSync7
|
|
101710
102161
|
} from "fs";
|
|
101711
102162
|
import path232 from "path";
|
|
101712
|
-
import { randomUUID as
|
|
102163
|
+
import { randomUUID as randomUUID29 } from "crypto";
|
|
101713
102164
|
function projectRegistryPath(dir) {
|
|
101714
102165
|
return path232.join(keryxConfigDir(dir), "projects.json");
|
|
101715
102166
|
}
|
|
@@ -101824,7 +102275,7 @@ function quarantineDamagedRegistry(dir, onWarn) {
|
|
|
101824
102275
|
}
|
|
101825
102276
|
function saveProjectRegistry(registry, dir, onWarn) {
|
|
101826
102277
|
const file = projectRegistryPath(dir);
|
|
101827
|
-
const temp = `${file}.${
|
|
102278
|
+
const temp = `${file}.${randomUUID29()}.tmp`;
|
|
101828
102279
|
try {
|
|
101829
102280
|
ensureKeryxConfigDir(dir);
|
|
101830
102281
|
const sorted = {
|
|
@@ -101880,7 +102331,7 @@ function registerProject(projectPath, options = {}) {
|
|
|
101880
102331
|
return { ok: true, entry: existing, created: false };
|
|
101881
102332
|
}
|
|
101882
102333
|
const entry = {
|
|
101883
|
-
projectId:
|
|
102334
|
+
projectId: randomUUID29(),
|
|
101884
102335
|
path: absolute,
|
|
101885
102336
|
displayName: options.displayName ?? path232.basename(absolute),
|
|
101886
102337
|
state: "active",
|
|
@@ -109019,7 +109470,7 @@ function formatHygieneTags(hygiene) {
|
|
|
109019
109470
|
}
|
|
109020
109471
|
|
|
109021
109472
|
// src/sac/lifecycle-flag.ts
|
|
109022
|
-
import { randomUUID as
|
|
109473
|
+
import { randomUUID as randomUUID30 } from "crypto";
|
|
109023
109474
|
function normalize3(raw) {
|
|
109024
109475
|
return raw.replace(/^\.\//, "");
|
|
109025
109476
|
}
|
|
@@ -109038,7 +109489,7 @@ async function computeLifecycleFlags(cwd, now = () => new Date) {
|
|
|
109038
109489
|
authorizationServer: localWorkspaceAuthorizationServer(),
|
|
109039
109490
|
strictGuard: { mode: "strict", availability: "available", decision: "pass", policyRevision: "local-offline-v1" }
|
|
109040
109491
|
});
|
|
109041
|
-
const workspaces = await workspaceService.list({ request: undefined, requestCorrelationId:
|
|
109492
|
+
const workspaces = await workspaceService.list({ request: undefined, requestCorrelationId: randomUUID30(), includeArchived: true });
|
|
109042
109493
|
for (const workspace of workspaces) {
|
|
109043
109494
|
const component = workspace.resources.find((r) => r.kind === "component")?.uri;
|
|
109044
109495
|
if (component !== undefined && !isStillPresent(component, valid)) {
|
|
@@ -109067,8 +109518,8 @@ var init_lifecycle_flag = __esm(() => {
|
|
|
109067
109518
|
});
|
|
109068
109519
|
|
|
109069
109520
|
// src/sac/catch-up.ts
|
|
109070
|
-
import { randomUUID as
|
|
109071
|
-
import { readdir as readdir36, stat as
|
|
109521
|
+
import { randomUUID as randomUUID31 } from "crypto";
|
|
109522
|
+
import { readdir as readdir36, stat as stat25 } from "fs/promises";
|
|
109072
109523
|
import path243 from "path";
|
|
109073
109524
|
async function buildCatchUp(input) {
|
|
109074
109525
|
const [proposals, sessionCategories, lifecycleFlagsAll, unreviewedPathsAll] = await Promise.all([
|
|
@@ -109083,7 +109534,7 @@ async function buildCatchUp(input) {
|
|
|
109083
109534
|
}
|
|
109084
109535
|
async function collectProposals(cwd, workspaceId) {
|
|
109085
109536
|
const authorizationServer = localWorkspaceAuthorizationServer();
|
|
109086
|
-
const actor = await authorizationServer.actorContextFor(undefined,
|
|
109537
|
+
const actor = await authorizationServer.actorContextFor(undefined, randomUUID31());
|
|
109087
109538
|
if (!actor)
|
|
109088
109539
|
throw new Error("trusted ActorContext is required for catch-up");
|
|
109089
109540
|
const proposalService = createLocalProposalLifecycleService(cwd);
|
|
@@ -109286,7 +109737,7 @@ async function collectReceiptTargets(cwd, owner) {
|
|
|
109286
109737
|
async function attributeToSession(absolutePath, sessionsNewestFirst) {
|
|
109287
109738
|
let mtimeMs;
|
|
109288
109739
|
try {
|
|
109289
|
-
mtimeMs = (await
|
|
109740
|
+
mtimeMs = (await stat25(absolutePath)).mtimeMs;
|
|
109290
109741
|
} catch {
|
|
109291
109742
|
return;
|
|
109292
109743
|
}
|
|
@@ -109572,7 +110023,7 @@ var init_session = __esm(() => {
|
|
|
109572
110023
|
});
|
|
109573
110024
|
|
|
109574
110025
|
// src/tui/inspector-sources.ts
|
|
109575
|
-
import { randomUUID as
|
|
110026
|
+
import { randomUUID as randomUUID32 } from "crypto";
|
|
109576
110027
|
function workspaceFromManifest(manifest) {
|
|
109577
110028
|
return {
|
|
109578
110029
|
id: manifest.id,
|
|
@@ -109651,7 +110102,7 @@ async function loadInspectorWorkspaces(cwd) {
|
|
|
109651
110102
|
authorizationServer: localWorkspaceAuthorizationServer(),
|
|
109652
110103
|
strictGuard: localSacGuard()
|
|
109653
110104
|
});
|
|
109654
|
-
const listed = await service.list({ request: undefined, requestCorrelationId:
|
|
110105
|
+
const listed = await service.list({ request: undefined, requestCorrelationId: randomUUID32() });
|
|
109655
110106
|
return listed.map(workspaceFromManifest);
|
|
109656
110107
|
} catch {
|
|
109657
110108
|
return [];
|
|
@@ -109664,7 +110115,7 @@ async function loadInspectorWorkspace(cwd, workspaceId) {
|
|
|
109664
110115
|
authorizationServer: localWorkspaceAuthorizationServer(),
|
|
109665
110116
|
strictGuard: localSacGuard()
|
|
109666
110117
|
});
|
|
109667
|
-
const manifest = await service.show({ request: undefined, requestCorrelationId:
|
|
110118
|
+
const manifest = await service.show({ request: undefined, requestCorrelationId: randomUUID32(), workspaceId });
|
|
109668
110119
|
return workspaceFromManifest(manifest);
|
|
109669
110120
|
} catch {
|
|
109670
110121
|
return;
|
|
@@ -111983,7 +112434,7 @@ var init_repair = __esm(() => {
|
|
|
111983
112434
|
});
|
|
111984
112435
|
|
|
111985
112436
|
// src/review/managed.ts
|
|
111986
|
-
import { mkdir as mkdir55, readFile as readFile117, readdir as readdir38, realpath as realpath18, rm as
|
|
112437
|
+
import { mkdir as mkdir55, readFile as readFile117, readdir as readdir38, realpath as realpath18, rm as rm17, stat as stat26 } from "fs/promises";
|
|
111987
112438
|
import path246 from "path";
|
|
111988
112439
|
function reviewsRoot(cwd) {
|
|
111989
112440
|
return path246.join(cwd, ".metaproject", "reviews");
|
|
@@ -112210,7 +112661,7 @@ async function persistScreenRadius(packageDir, resolved) {
|
|
|
112210
112661
|
`);
|
|
112211
112662
|
}
|
|
112212
112663
|
if (resolved.source === "handoff" && resolved.file !== undefined) {
|
|
112213
|
-
await
|
|
112664
|
+
await rm17(resolved.file, { force: true });
|
|
112214
112665
|
}
|
|
112215
112666
|
}
|
|
112216
112667
|
function concurrencyPlan(input, coverage) {
|
|
@@ -112489,7 +112940,7 @@ function readFromWorkingTree(input) {
|
|
|
112489
112940
|
return null;
|
|
112490
112941
|
}
|
|
112491
112942
|
try {
|
|
112492
|
-
const info = await
|
|
112943
|
+
const info = await stat26(real);
|
|
112493
112944
|
if (!info.isFile() || info.size > MAX_LOCATE_FILE_BYTES) {
|
|
112494
112945
|
return null;
|
|
112495
112946
|
}
|
|
@@ -114473,7 +114924,7 @@ var init_endpoint = __esm(() => {
|
|
|
114473
114924
|
});
|
|
114474
114925
|
|
|
114475
114926
|
// src/lib/serve-credential.ts
|
|
114476
|
-
import { createHash as createHash63, randomBytes as randomBytes11, randomUUID as
|
|
114927
|
+
import { createHash as createHash63, randomBytes as randomBytes11, randomUUID as randomUUID33 } from "crypto";
|
|
114477
114928
|
import {
|
|
114478
114929
|
chmodSync as chmodSync5,
|
|
114479
114930
|
closeSync as closeSync5,
|
|
@@ -114557,7 +115008,7 @@ function readServeCredential(dir) {
|
|
|
114557
115008
|
}
|
|
114558
115009
|
function writeStore(store, dir) {
|
|
114559
115010
|
const file = serveCredentialPath(dir);
|
|
114560
|
-
const temp = `${file}.${
|
|
115011
|
+
const temp = `${file}.${randomUUID33()}.tmp`;
|
|
114561
115012
|
try {
|
|
114562
115013
|
ensureKeryxConfigDir(dir);
|
|
114563
115014
|
const handle = openSync5(temp, "wx", 384);
|
|
@@ -114597,7 +115048,7 @@ function mintRecord(now) {
|
|
|
114597
115048
|
const salt = randomBytes11(32).toString("hex");
|
|
114598
115049
|
return {
|
|
114599
115050
|
token,
|
|
114600
|
-
record: { id:
|
|
115051
|
+
record: { id: randomUUID33(), algorithm: "sha256", salt, hash: hashToken(salt, token), createdAt: now }
|
|
114601
115052
|
};
|
|
114602
115053
|
}
|
|
114603
115054
|
function issueServeToken(dir, now = () => new Date().toISOString(), onWaiting) {
|
|
@@ -116193,7 +116644,7 @@ function fileExists(file) {
|
|
|
116193
116644
|
const read = readConfigFile(file);
|
|
116194
116645
|
return read.ok || read.reason !== "absent";
|
|
116195
116646
|
}
|
|
116196
|
-
function
|
|
116647
|
+
function isObject3(value) {
|
|
116197
116648
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
116198
116649
|
}
|
|
116199
116650
|
function plural2(count, one, many) {
|
|
@@ -116220,7 +116671,7 @@ class ChannelsClient {
|
|
|
116220
116671
|
status() {
|
|
116221
116672
|
return this.call("channels-status", (body) => {
|
|
116222
116673
|
const telegram = body.telegram;
|
|
116223
|
-
return typeof body.machine === "string" &&
|
|
116674
|
+
return typeof body.machine === "string" && isObject3(telegram) && typeof telegram.state === "string" && typeof telegram.sessions === "number";
|
|
116224
116675
|
});
|
|
116225
116676
|
}
|
|
116226
116677
|
async startPairing(token) {
|
|
@@ -116389,12 +116840,12 @@ class ChannelsClient {
|
|
|
116389
116840
|
parsed = undefined;
|
|
116390
116841
|
}
|
|
116391
116842
|
if (!response.ok) {
|
|
116392
|
-
const error =
|
|
116843
|
+
const error = isObject3(parsed) && isObject3(parsed.error) ? parsed.error : undefined;
|
|
116393
116844
|
const code = typeof error?.code === "string" ? error.code : `http-${response.status}`;
|
|
116394
116845
|
const message = typeof error?.message === "string" ? error.message : `keryx serve refused the request (HTTP ${response.status})`;
|
|
116395
116846
|
return { ok: false, code, reason: message };
|
|
116396
116847
|
}
|
|
116397
|
-
if (!
|
|
116848
|
+
if (!isObject3(parsed) || !guard(parsed)) {
|
|
116398
116849
|
return { ok: false, code: "unexpected-response", reason: "keryx serve sent an answer this shell does not understand; update keryx on both sides" };
|
|
116399
116850
|
}
|
|
116400
116851
|
return { ok: true, value: parsed };
|
|
@@ -116414,7 +116865,7 @@ class ChannelsClient {
|
|
|
116414
116865
|
}
|
|
116415
116866
|
function refusedConnection(error) {
|
|
116416
116867
|
const seen = new Set;
|
|
116417
|
-
for (let current = error;
|
|
116868
|
+
for (let current = error;isObject3(current) || current instanceof Error; ) {
|
|
116418
116869
|
if (seen.has(current))
|
|
116419
116870
|
break;
|
|
116420
116871
|
seen.add(current);
|
|
@@ -120921,7 +121372,7 @@ var init_serve_turn_store = __esm(() => {
|
|
|
120921
121372
|
});
|
|
120922
121373
|
|
|
120923
121374
|
// src/lib/serve-approvals-store.ts
|
|
120924
|
-
import { randomUUID as
|
|
121375
|
+
import { randomUUID as randomUUID34 } from "crypto";
|
|
120925
121376
|
import { existsSync as existsSync45, readdirSync as readdirSync10 } from "fs";
|
|
120926
121377
|
import path261 from "path";
|
|
120927
121378
|
function isApprovalId(value) {
|
|
@@ -121197,7 +121648,7 @@ function toPublicApproval(view) {
|
|
|
121197
121648
|
};
|
|
121198
121649
|
}
|
|
121199
121650
|
function newApprovalId() {
|
|
121200
|
-
return
|
|
121651
|
+
return randomUUID34();
|
|
121201
121652
|
}
|
|
121202
121653
|
var APPROVAL_SCHEMA_VERSION = "1.0.0", SUMMARY_MAX = 500, SCOPE_MAX = 300, CONSEQUENCE_MAX = 300, ID_PATTERN2;
|
|
121203
121654
|
var init_serve_approvals_store = __esm(() => {
|
|
@@ -121718,10 +122169,12 @@ async function openDecisions(otui, chrome, options) {
|
|
|
121718
122169
|
const text = await reportText(cwd).catch(() => UNREADABLE);
|
|
121719
122170
|
return presentDecisions((hostOtui, hostChrome, input) => openModal(hostOtui, hostChrome, input), otui, chrome, { ...rest, text });
|
|
121720
122171
|
}
|
|
121721
|
-
function projectDecisionsPanel(count, width) {
|
|
121722
|
-
if (count <= 0)
|
|
122172
|
+
function projectDecisionsPanel(count, width, backfilled = 0) {
|
|
122173
|
+
if (count <= 0 && backfilled <= 0)
|
|
121723
122174
|
return { visible: false, text: "" };
|
|
121724
|
-
const
|
|
122175
|
+
const live = count > 0 ? `${count} decision${count === 1 ? "" : "s"}` : "";
|
|
122176
|
+
const before = backfilled > 0 ? `${count > 0 ? " + " : ""}${backfilled} before` : "";
|
|
122177
|
+
const label = `${live}${before}`;
|
|
121725
122178
|
const candidates = [`${label} \xB7 /decisions`, label];
|
|
121726
122179
|
const text = candidates.find((candidate) => candidate.length <= width) ?? label.slice(0, Math.max(1, width));
|
|
121727
122180
|
return { visible: true, text };
|
|
@@ -121744,6 +122197,7 @@ function mountDecisionsSidebar(options) {
|
|
|
121744
122197
|
const { chrome } = options;
|
|
121745
122198
|
const r = chrome.renderer;
|
|
121746
122199
|
const count = options.count ?? (() => decisionCount(options.cwd));
|
|
122200
|
+
const backfilledTotal = options.backfilled ?? (() => backfilledCount(options.cwd));
|
|
121747
122201
|
const box = new core.BoxRenderable(r, { id: "sb-decisions", flexDirection: "column", flexShrink: 0 });
|
|
121748
122202
|
options.parent.add(box);
|
|
121749
122203
|
let modal;
|
|
@@ -121789,7 +122243,13 @@ function mountDecisionsSidebar(options) {
|
|
|
121789
122243
|
} catch {
|
|
121790
122244
|
n = 0;
|
|
121791
122245
|
}
|
|
121792
|
-
|
|
122246
|
+
let before;
|
|
122247
|
+
try {
|
|
122248
|
+
before = await backfilledTotal();
|
|
122249
|
+
} catch {
|
|
122250
|
+
before = 0;
|
|
122251
|
+
}
|
|
122252
|
+
projected = projectDecisionsPanel(n, options.width, before);
|
|
121793
122253
|
paint();
|
|
121794
122254
|
};
|
|
121795
122255
|
const unsubscribeTheme = onThemeChange(guardedThemeRepaint("decisions-row", () => paint(true), () => disposed || isRenderableGone(box)));
|
|
@@ -121837,8 +122297,8 @@ var init_decisions_surface = __esm(() => {
|
|
|
121837
122297
|
|
|
121838
122298
|
// src/harness/external/write-run.ts
|
|
121839
122299
|
import { execFile as execFile11 } from "child_process";
|
|
121840
|
-
import { createHash as createHash66, randomUUID as
|
|
121841
|
-
import { mkdtemp as mkdtemp5, readlink, realpath as realpath19, rm as
|
|
122300
|
+
import { createHash as createHash66, randomUUID as randomUUID35 } from "crypto";
|
|
122301
|
+
import { mkdtemp as mkdtemp5, readlink, realpath as realpath19, rm as rm18 } from "fs/promises";
|
|
121842
122302
|
import { tmpdir as tmpdir11 } from "os";
|
|
121843
122303
|
import path262 from "path";
|
|
121844
122304
|
import { promisify as promisify9 } from "util";
|
|
@@ -121957,7 +122417,7 @@ async function captureWriteDiff(input) {
|
|
|
121957
122417
|
refusedPaths
|
|
121958
122418
|
};
|
|
121959
122419
|
} finally {
|
|
121960
|
-
await
|
|
122420
|
+
await rm18(indexDir, { recursive: true, force: true }).catch(() => {
|
|
121961
122421
|
return;
|
|
121962
122422
|
});
|
|
121963
122423
|
}
|
|
@@ -122031,7 +122491,7 @@ async function runExternalWriteChild(input, deps) {
|
|
|
122031
122491
|
});
|
|
122032
122492
|
}
|
|
122033
122493
|
if (ownedDir !== undefined)
|
|
122034
|
-
await
|
|
122494
|
+
await rm18(ownedDir, { recursive: true, force: true }).catch(() => {
|
|
122035
122495
|
return;
|
|
122036
122496
|
});
|
|
122037
122497
|
}
|
|
@@ -122056,7 +122516,7 @@ async function runExternalWriteChild(input, deps) {
|
|
|
122056
122516
|
}
|
|
122057
122517
|
}
|
|
122058
122518
|
function persistWriteRun(args) {
|
|
122059
|
-
const runId =
|
|
122519
|
+
const runId = randomUUID35();
|
|
122060
122520
|
const title = `External write ${args.agentId}: ${args.runStatus}`;
|
|
122061
122521
|
const handle = createSession({
|
|
122062
122522
|
cwd: args.projectRoot,
|
|
@@ -122172,7 +122632,7 @@ var init_write_run = __esm(() => {
|
|
|
122172
122632
|
import { execFile as execFile12 } from "child_process";
|
|
122173
122633
|
import { createHash as createHash67 } from "crypto";
|
|
122174
122634
|
import { existsSync as existsSync46, rmSync as rmSync5 } from "fs";
|
|
122175
|
-
import { mkdtemp as mkdtemp6, rm as
|
|
122635
|
+
import { mkdtemp as mkdtemp6, rm as rm19 } from "fs/promises";
|
|
122176
122636
|
import { tmpdir as tmpdir12 } from "os";
|
|
122177
122637
|
import path263 from "path";
|
|
122178
122638
|
function errorMessage3(error) {
|
|
@@ -122292,11 +122752,11 @@ async function landWriteRun(input, deps = {}) {
|
|
|
122292
122752
|
return;
|
|
122293
122753
|
});
|
|
122294
122754
|
if (ownedDir !== undefined)
|
|
122295
|
-
await
|
|
122755
|
+
await rm19(ownedDir, { recursive: true, force: true }).catch(() => {
|
|
122296
122756
|
return;
|
|
122297
122757
|
});
|
|
122298
122758
|
else
|
|
122299
|
-
await
|
|
122759
|
+
await rm19(path263.join(worktreesDir, worktreeId), { recursive: true, force: true }).catch(() => {
|
|
122300
122760
|
return;
|
|
122301
122761
|
});
|
|
122302
122762
|
await git(["worktree", "prune"], repo).catch(() => {
|
|
@@ -126285,7 +126745,7 @@ function recordTaskCost(store, record) {
|
|
|
126285
126745
|
const next = existing.length >= MAX_SAMPLES_PER_KEY ? [...existing.slice(existing.length - MAX_SAMPLES_PER_KEY + 1), record] : [...existing, record];
|
|
126286
126746
|
return { ...store, [key]: next };
|
|
126287
126747
|
}
|
|
126288
|
-
function
|
|
126748
|
+
function median2(values) {
|
|
126289
126749
|
if (values.length === 0)
|
|
126290
126750
|
return 0;
|
|
126291
126751
|
const sorted = [...values].sort((a, b) => a - b);
|
|
@@ -126294,9 +126754,9 @@ function median(values) {
|
|
|
126294
126754
|
}
|
|
126295
126755
|
function statsForKey(records, providerId, modelId, category) {
|
|
126296
126756
|
const n = records.length;
|
|
126297
|
-
const medianTokens =
|
|
126757
|
+
const medianTokens = median2(records.map((r) => r.totalTokens));
|
|
126298
126758
|
const knownCosts = records.map((r) => r.costUsd).filter((c) => c !== undefined);
|
|
126299
|
-
const medianCostUsd = knownCosts.length > 0 ?
|
|
126759
|
+
const medianCostUsd = knownCosts.length > 0 ? median2(knownCosts) : undefined;
|
|
126300
126760
|
const successRate = records.filter((r) => r.success).length / n;
|
|
126301
126761
|
return { providerId, modelId, category, n, medianTokens, ...medianCostUsd !== undefined ? { medianCostUsd } : {}, successRate };
|
|
126302
126762
|
}
|
|
@@ -128677,7 +129137,7 @@ var init_conform_report = __esm(() => {
|
|
|
128677
129137
|
});
|
|
128678
129138
|
|
|
128679
129139
|
// src/tui/conform-source.ts
|
|
128680
|
-
import { readFile as readFile127, readdir as readdir41, stat as
|
|
129140
|
+
import { readFile as readFile127, readdir as readdir41, stat as stat27 } from "fs/promises";
|
|
128681
129141
|
import path270 from "path";
|
|
128682
129142
|
async function readRecentConformDocs(cwd) {
|
|
128683
129143
|
try {
|
|
@@ -128720,7 +129180,7 @@ async function mostRecentReviewPackage(cwd) {
|
|
|
128720
129180
|
continue;
|
|
128721
129181
|
const dir = path270.join(reviewsDir, reviewEntry.name);
|
|
128722
129182
|
try {
|
|
128723
|
-
const info = await
|
|
129183
|
+
const info = await stat27(path270.join(dir, "report.md"));
|
|
128724
129184
|
if (best === undefined || info.mtimeMs > best.mtimeMs)
|
|
128725
129185
|
best = { dir, mtimeMs: info.mtimeMs };
|
|
128726
129186
|
} catch {}
|
|
@@ -129687,7 +130147,7 @@ var init_jev_rules = __esm(() => {
|
|
|
129687
130147
|
});
|
|
129688
130148
|
|
|
129689
130149
|
// src/commands/review-jev-rules.ts
|
|
129690
|
-
import { readFile as readFile130, readdir as readdir42, stat as
|
|
130150
|
+
import { readFile as readFile130, readdir as readdir42, stat as stat28 } from "fs/promises";
|
|
129691
130151
|
import { basename as basename3, dirname as dirname2, isAbsolute as isAbsolute3, join as join5, relative as relative3 } from "path";
|
|
129692
130152
|
function rejectUnknownJevRulesFlags(args) {
|
|
129693
130153
|
const unknown = args.filter((arg) => arg.startsWith("--") && !JEV_RULES_FLAGS.includes(arg.split("=")[0]));
|
|
@@ -129800,7 +130260,7 @@ async function discoverRuleSources(cwd, explicitPaths) {
|
|
|
129800
130260
|
const explicitDirSources = [];
|
|
129801
130261
|
for (const raw of explicitPaths) {
|
|
129802
130262
|
const resolved = isAbsolute3(raw) ? raw : join5(cwd, raw);
|
|
129803
|
-
const stats = await
|
|
130263
|
+
const stats = await stat28(resolved).catch(() => {
|
|
129804
130264
|
return;
|
|
129805
130265
|
});
|
|
129806
130266
|
if (stats === undefined) {
|
|
@@ -131677,7 +132137,7 @@ var init_jev_triage = __esm(() => {
|
|
|
131677
132137
|
});
|
|
131678
132138
|
|
|
131679
132139
|
// src/commands/review-jev-triage.ts
|
|
131680
|
-
import { readFile as readFile136, stat as
|
|
132140
|
+
import { readFile as readFile136, stat as stat29 } from "fs/promises";
|
|
131681
132141
|
import path276 from "path";
|
|
131682
132142
|
function rejectUnknownJevTriageFlags(args) {
|
|
131683
132143
|
const unknown = args.filter((arg) => arg.startsWith("--") && !JEV_TRIAGE_FLAGS.includes(arg.split("=")[0]));
|
|
@@ -131712,7 +132172,7 @@ function isMaxTokensExceededError2(error) {
|
|
|
131712
132172
|
async function loadReportRaw(reportPath) {
|
|
131713
132173
|
let filePath = reportPath;
|
|
131714
132174
|
try {
|
|
131715
|
-
const stats = await
|
|
132175
|
+
const stats = await stat29(reportPath);
|
|
131716
132176
|
if (stats.isDirectory())
|
|
131717
132177
|
filePath = path276.join(reportPath, "findings.json");
|
|
131718
132178
|
} catch {}
|
|
@@ -131857,7 +132317,7 @@ var init_review_jev_triage = __esm(() => {
|
|
|
131857
132317
|
});
|
|
131858
132318
|
|
|
131859
132319
|
// src/tui/jev-triage-command.ts
|
|
131860
|
-
import { readdir as readdir43, readFile as readFile137, stat as
|
|
132320
|
+
import { readdir as readdir43, readFile as readFile137, stat as stat30 } from "fs/promises";
|
|
131861
132321
|
import path277 from "path";
|
|
131862
132322
|
function isJevTriageCommand(name) {
|
|
131863
132323
|
return name === JEV_TRIAGE_COMMAND;
|
|
@@ -131886,7 +132346,7 @@ async function resolveLatestReviewPackage(cwd) {
|
|
|
131886
132346
|
const packageDir = path277.join(reviewsDir, reviewName);
|
|
131887
132347
|
const findingsPath = path277.join(packageDir, "findings.json");
|
|
131888
132348
|
try {
|
|
131889
|
-
const stats = await
|
|
132349
|
+
const stats = await stat30(findingsPath);
|
|
131890
132350
|
candidates.push({ dir: packageDir, mtimeMs: stats.mtimeMs });
|
|
131891
132351
|
} catch {
|
|
131892
132352
|
continue;
|
|
@@ -139215,7 +139675,7 @@ function maxOverFiles(files, values) {
|
|
|
139215
139675
|
}
|
|
139216
139676
|
|
|
139217
139677
|
// src/wiki/deep-enrich.ts
|
|
139218
|
-
import { randomUUID as
|
|
139678
|
+
import { randomUUID as randomUUID36, createHash as createHash68 } from "crypto";
|
|
139219
139679
|
function errorMessage4(cause) {
|
|
139220
139680
|
return cause instanceof Error ? cause.message : String(cause);
|
|
139221
139681
|
}
|
|
@@ -139251,7 +139711,7 @@ function buildDeepUserPrompt(page, original, extra) {
|
|
|
139251
139711
|
`);
|
|
139252
139712
|
}
|
|
139253
139713
|
async function enrichPageDeep(input) {
|
|
139254
|
-
const idSeq = input.idSeq ?? (() =>
|
|
139714
|
+
const idSeq = input.idSeq ?? (() => randomUUID36());
|
|
139255
139715
|
const clock = input.clock ?? (() => new Date().toISOString());
|
|
139256
139716
|
const toolCalls = [];
|
|
139257
139717
|
if (input.signal?.aborted) {
|
|
@@ -144740,7 +145200,7 @@ var init_reflect = __esm(() => {
|
|
|
144740
145200
|
});
|
|
144741
145201
|
|
|
144742
145202
|
// src/commands/memory.ts
|
|
144743
|
-
import { randomUUID as
|
|
145203
|
+
import { randomUUID as randomUUID37 } from "crypto";
|
|
144744
145204
|
import { readdir as readdir46 } from "fs/promises";
|
|
144745
145205
|
import { join as join9 } from "path";
|
|
144746
145206
|
function getService2() {
|
|
@@ -144928,7 +145388,7 @@ async function runSearch(args) {
|
|
|
144928
145388
|
}
|
|
144929
145389
|
if (args.includes("--json")) {
|
|
144930
145390
|
const projection = renderMemorySearchReport({
|
|
144931
|
-
runId:
|
|
145391
|
+
runId: randomUUID37(),
|
|
144932
145392
|
generatedAt: new Date,
|
|
144933
145393
|
search: result,
|
|
144934
145394
|
filters
|
|
@@ -145932,8 +146392,8 @@ var init_proxy = __esm(() => {
|
|
|
145932
146392
|
|
|
145933
146393
|
// src/commands/trigger-agent-task.ts
|
|
145934
146394
|
import { execFile as execFile13 } from "child_process";
|
|
145935
|
-
import { randomUUID as
|
|
145936
|
-
import { mkdtemp as mkdtemp7, mkdir as mkdir61, readdir as readdir47, rm as
|
|
146395
|
+
import { randomUUID as randomUUID38 } from "crypto";
|
|
146396
|
+
import { mkdtemp as mkdtemp7, mkdir as mkdir61, readdir as readdir47, rm as rm20, writeFile as writeFile38 } from "fs/promises";
|
|
145937
146397
|
import { homedir as homedir12, tmpdir as tmpdir13 } from "os";
|
|
145938
146398
|
import path290 from "path";
|
|
145939
146399
|
function scrubGrantedOutput(text, env, secrets = []) {
|
|
@@ -146055,12 +146515,12 @@ function lastAssistantText(history) {
|
|
|
146055
146515
|
async function pruneReports(dir, keep) {
|
|
146056
146516
|
const names = (await readdir47(dir).catch(() => [])).filter((n) => n.endsWith(".md")).sort();
|
|
146057
146517
|
for (const old of names.slice(0, Math.max(0, names.length - keep))) {
|
|
146058
|
-
await
|
|
146518
|
+
await rm20(path290.join(dir, old), { force: true }).catch(() => {});
|
|
146059
146519
|
}
|
|
146060
146520
|
}
|
|
146061
146521
|
async function runAgentTaskDispatch(projectRoot, entry, action, deps = {}) {
|
|
146062
146522
|
const now = deps.now ?? (() => new Date);
|
|
146063
|
-
const runId = deps.runId?.() ?? `sch-${now().toISOString().replace(/[-:.]/g, "").slice(0, 15)}-${
|
|
146523
|
+
const runId = deps.runId?.() ?? `sch-${now().toISOString().replace(/[-:.]/g, "").slice(0, 15)}-${randomUUID38().slice(0, 8)}`;
|
|
146064
146524
|
await ensureLocksDir(projectRoot);
|
|
146065
146525
|
try {
|
|
146066
146526
|
return await withFileLock(dispatchLockPath(projectRoot, `schedule-${entry.name}`), () => runLocked(projectRoot, entry, action, deps, runId, now), {
|
|
@@ -146100,7 +146560,7 @@ async function runLocked(projectRoot, entry, action, deps, runId, now) {
|
|
|
146100
146560
|
await mkdir61(scratchHome, { recursive: true });
|
|
146101
146561
|
await mkdir61(grantedCwd, { recursive: true, mode: 448 });
|
|
146102
146562
|
const cleanup = async () => {
|
|
146103
|
-
await
|
|
146563
|
+
await rm20(scratch, { recursive: true, force: true }).catch(() => {});
|
|
146104
146564
|
};
|
|
146105
146565
|
let closeProxy = async () => {};
|
|
146106
146566
|
const networkDecisions = [];
|
|
@@ -146223,7 +146683,7 @@ async function runLocked(projectRoot, entry, action, deps, runId, now) {
|
|
|
146223
146683
|
modelId: dispatch.model,
|
|
146224
146684
|
toolNames: tools.map((t) => t.definition.name)
|
|
146225
146685
|
}),
|
|
146226
|
-
idSeq: () =>
|
|
146686
|
+
idSeq: () => randomUUID38(),
|
|
146227
146687
|
unattended: true,
|
|
146228
146688
|
hardDeny: unattendedRefusal,
|
|
146229
146689
|
...shellHooks !== undefined ? { hooks: shellHooks } : {}
|
|
@@ -146738,7 +147198,7 @@ var init_digest_limits = __esm(() => {
|
|
|
146738
147198
|
});
|
|
146739
147199
|
|
|
146740
147200
|
// src/scheduler/digest-summary.ts
|
|
146741
|
-
import { randomUUID as
|
|
147201
|
+
import { randomUUID as randomUUID39 } from "crypto";
|
|
146742
147202
|
var SYSTEM, MAX_OUTPUT_TOKENS = 400, defaultSummarize = async (input) => {
|
|
146743
147203
|
const { action, entry } = input;
|
|
146744
147204
|
const dispatch = action.dispatch;
|
|
@@ -146768,7 +147228,7 @@ var SYSTEM, MAX_OUTPUT_TOKENS = 400, defaultSummarize = async (input) => {
|
|
|
146768
147228
|
local.abort();
|
|
146769
147229
|
});
|
|
146770
147230
|
const provider = guardUsage(built, () => meter.markUsageMissing());
|
|
146771
|
-
const requestId = `digest-${
|
|
147231
|
+
const requestId = `digest-${randomUUID39().slice(0, 8)}`;
|
|
146772
147232
|
const request = {
|
|
146773
147233
|
providerId: dispatch.provider,
|
|
146774
147234
|
modelId: dispatch.model,
|
|
@@ -146817,8 +147277,8 @@ var init_digest_summary = __esm(() => {
|
|
|
146817
147277
|
});
|
|
146818
147278
|
|
|
146819
147279
|
// src/scheduler/digest-run.ts
|
|
146820
|
-
import { randomUUID as
|
|
146821
|
-
import { mkdir as mkdir62, mkdtemp as mkdtemp8, rm as
|
|
147280
|
+
import { randomUUID as randomUUID40 } from "crypto";
|
|
147281
|
+
import { mkdir as mkdir62, mkdtemp as mkdtemp8, rm as rm21, writeFile as writeFile39 } from "fs/promises";
|
|
146822
147282
|
import path292 from "path";
|
|
146823
147283
|
function capForDelivery(text, reportPath) {
|
|
146824
147284
|
if (text.length <= DELIVERY_TEXT_MAX)
|
|
@@ -146838,7 +147298,7 @@ async function announceRefusal(projectRoot, name, topic, runId, reason, result,
|
|
|
146838
147298
|
}
|
|
146839
147299
|
async function runDigestDispatch(projectRoot, entry, action, deps = {}) {
|
|
146840
147300
|
const now = deps.now ?? (() => new Date);
|
|
146841
|
-
const runId = deps.runId?.() ?? `dig-${now().toISOString().replace(/[-:.]/g, "").slice(0, 15)}-${
|
|
147301
|
+
const runId = deps.runId?.() ?? `dig-${now().toISOString().replace(/[-:.]/g, "").slice(0, 15)}-${randomUUID40().slice(0, 8)}`;
|
|
146842
147302
|
await ensureLocksDir(projectRoot);
|
|
146843
147303
|
try {
|
|
146844
147304
|
return await withFileLock(dispatchLockPath(projectRoot, `schedule-${entry.name}`), () => runLocked2(projectRoot, entry, action, deps, runId, now), {
|
|
@@ -146950,7 +147410,7 @@ async function runLocked2(projectRoot, entry, action, deps, runId, now) {
|
|
|
146950
147410
|
crashed = error instanceof Error ? error.message : String(error);
|
|
146951
147411
|
} finally {
|
|
146952
147412
|
limits.dispose();
|
|
146953
|
-
await
|
|
147413
|
+
await rm21(scratch, { recursive: true, force: true }).catch(() => {});
|
|
146954
147414
|
}
|
|
146955
147415
|
const tools = DIGEST_TOOL_IDS.filter((id) => action.grants.tools.includes(id));
|
|
146956
147416
|
const attempted = tools.length * action.grants.repos.length;
|
|
@@ -155829,7 +156289,7 @@ var init_debug_watcher = __esm(() => {
|
|
|
155829
156289
|
});
|
|
155830
156290
|
|
|
155831
156291
|
// src/commands/shell.ts
|
|
155832
|
-
import { randomUUID as
|
|
156292
|
+
import { randomUUID as randomUUID41 } from "crypto";
|
|
155833
156293
|
import { join as joinPath2 } from "path";
|
|
155834
156294
|
import * as readline2 from "readline";
|
|
155835
156295
|
function reportMcpProblems(runtime) {
|
|
@@ -158188,14 +158648,14 @@ Example: keryx shell --provider ollama --model llama3.1:latest`);
|
|
|
158188
158648
|
`);
|
|
158189
158649
|
}
|
|
158190
158650
|
const surface = chooseShellSurface(flags, runtime.isTty ?? process.stdout.isTTY === true);
|
|
158191
|
-
const shellHookSessionId =
|
|
158651
|
+
const shellHookSessionId = randomUUID41();
|
|
158192
158652
|
let shellHooks;
|
|
158193
158653
|
const getShellHooks = () => {
|
|
158194
158654
|
if (shellHooks === undefined) {
|
|
158195
158655
|
shellHooks = buildShellHookRuntime({
|
|
158196
158656
|
projectRoot: resolveProjectRoot2(process.cwd()),
|
|
158197
158657
|
sessionId: shellHookSessionId,
|
|
158198
|
-
runId:
|
|
158658
|
+
runId: randomUUID41(),
|
|
158199
158659
|
interactive: true,
|
|
158200
158660
|
profileId: "monitored-trusted-local",
|
|
158201
158661
|
...runtime.cacheDir === undefined ? {} : { configDir: runtime.cacheDir }
|
|
@@ -158300,7 +158760,7 @@ Example: keryx shell --provider ollama --model llama3.1:latest`);
|
|
|
158300
158760
|
sessionOverride: reasoningSessionOverride,
|
|
158301
158761
|
globalEffort: loadShellConfig(runtime.cacheDir).reasoningEffort
|
|
158302
158762
|
}),
|
|
158303
|
-
idSeq: () =>
|
|
158763
|
+
idSeq: () => randomUUID41(),
|
|
158304
158764
|
askUser: invokeAskUserHost,
|
|
158305
158765
|
sweepBackgroundJobs: () => jobRegistry.sweepAll(),
|
|
158306
158766
|
jobRegistry,
|
|
@@ -158371,7 +158831,7 @@ Example: keryx shell --provider ollama --model llama3.1:latest`);
|
|
|
158371
158831
|
return {
|
|
158372
158832
|
makeProvider: chatFactory,
|
|
158373
158833
|
clock: () => new Date().toISOString(),
|
|
158374
|
-
idSeq: () =>
|
|
158834
|
+
idSeq: () => randomUUID41(),
|
|
158375
158835
|
initial: Object.keys(resolvedModelParams).length > 0 ? { ...sel, modelParams: resolvedModelParams } : sel,
|
|
158376
158836
|
session: {
|
|
158377
158837
|
cwd,
|
|
@@ -158499,7 +158959,7 @@ Example: keryx shell --provider ollama --model llama3.1:latest`);
|
|
|
158499
158959
|
const deps = {
|
|
158500
158960
|
makeProvider: baseFactory,
|
|
158501
158961
|
clock: () => new Date().toISOString(),
|
|
158502
|
-
idSeq: () =>
|
|
158962
|
+
idSeq: () => randomUUID41(),
|
|
158503
158963
|
initial: {
|
|
158504
158964
|
provider,
|
|
158505
158965
|
model,
|
|
@@ -158580,7 +159040,7 @@ Example: keryx shell --provider ollama --model llama3.1:latest`);
|
|
|
158580
159040
|
sessionOverride: reasoningSessionOverride,
|
|
158581
159041
|
globalEffort: loadShellConfig(runtime.cacheDir).reasoningEffort
|
|
158582
159042
|
}),
|
|
158583
|
-
idSeq: () =>
|
|
159043
|
+
idSeq: () => randomUUID41(),
|
|
158584
159044
|
askUser: invokeAskUserHost,
|
|
158585
159045
|
mcpRuntime: () => mcpRuntime,
|
|
158586
159046
|
sweepBackgroundJobs: () => jobRegistry.sweepAll(),
|
|
@@ -163090,8 +163550,8 @@ var init_sweep = __esm(() => {
|
|
|
163090
163550
|
});
|
|
163091
163551
|
|
|
163092
163552
|
// src/retention/auto-sweep.ts
|
|
163093
|
-
import { mkdir as mkdir63, readFile as readFile158, rm as
|
|
163094
|
-
import { randomUUID as
|
|
163553
|
+
import { mkdir as mkdir63, readFile as readFile158, rm as rm22, stat as stat31, writeFile as writeFile40 } from "fs/promises";
|
|
163554
|
+
import { randomUUID as randomUUID42 } from "crypto";
|
|
163095
163555
|
import path309 from "path";
|
|
163096
163556
|
function autoSweepStampPath(cwd) {
|
|
163097
163557
|
return path309.join(cwd, ".metaproject", "data", "retention", "last-auto-sweep.json");
|
|
@@ -163123,7 +163583,7 @@ async function readAutoSweepStamp(cwd) {
|
|
|
163123
163583
|
}
|
|
163124
163584
|
async function claimIsLive(cwd, staleMs) {
|
|
163125
163585
|
const claimPath = autoSweepClaimPath(cwd);
|
|
163126
|
-
const held = await
|
|
163586
|
+
const held = await stat31(claimPath).catch(() => null);
|
|
163127
163587
|
if (held === null || Date.now() - held.mtimeMs > staleMs) {
|
|
163128
163588
|
return false;
|
|
163129
163589
|
}
|
|
@@ -163140,7 +163600,7 @@ async function claimIsLive(cwd, staleMs) {
|
|
|
163140
163600
|
}
|
|
163141
163601
|
}
|
|
163142
163602
|
async function acquireClaim(claimPath, staleMs) {
|
|
163143
|
-
const nonce = `${process.pid}:${
|
|
163603
|
+
const nonce = `${process.pid}:${randomUUID42()}`;
|
|
163144
163604
|
for (let attempt = 0;attempt < 2; attempt += 1) {
|
|
163145
163605
|
try {
|
|
163146
163606
|
await writeFile40(claimPath, nonce, { flag: "wx", mode: 384 });
|
|
@@ -163148,7 +163608,7 @@ async function acquireClaim(claimPath, staleMs) {
|
|
|
163148
163608
|
release: async () => {
|
|
163149
163609
|
try {
|
|
163150
163610
|
if (await readFile158(claimPath, "utf8") === nonce) {
|
|
163151
|
-
await
|
|
163611
|
+
await rm22(claimPath, { force: true });
|
|
163152
163612
|
}
|
|
163153
163613
|
} catch {}
|
|
163154
163614
|
}
|
|
@@ -163158,9 +163618,9 @@ async function acquireClaim(claimPath, staleMs) {
|
|
|
163158
163618
|
if (code !== "EEXIST") {
|
|
163159
163619
|
return null;
|
|
163160
163620
|
}
|
|
163161
|
-
const held = await
|
|
163621
|
+
const held = await stat31(claimPath).catch(() => null);
|
|
163162
163622
|
if (held !== null && Date.now() - held.mtimeMs > staleMs) {
|
|
163163
|
-
await
|
|
163623
|
+
await rm22(claimPath, { force: true }).catch(() => {
|
|
163164
163624
|
return;
|
|
163165
163625
|
});
|
|
163166
163626
|
continue;
|
|
@@ -163229,7 +163689,7 @@ var init_auto_sweep = __esm(() => {
|
|
|
163229
163689
|
|
|
163230
163690
|
// src/ctx/artifact-id.ts
|
|
163231
163691
|
import { randomBytes as randomBytes13 } from "crypto";
|
|
163232
|
-
import { mkdir as mkdir64, readFile as readFile159, rm as
|
|
163692
|
+
import { mkdir as mkdir64, readFile as readFile159, rm as rm23, writeFile as writeFile41 } from "fs/promises";
|
|
163233
163693
|
import path310 from "path";
|
|
163234
163694
|
function pinnedClock() {
|
|
163235
163695
|
const pin = process.env.KERYX_CTX_CLOCK_PIN_MS;
|
|
@@ -163278,7 +163738,7 @@ async function reserveArtifact(options) {
|
|
|
163278
163738
|
continue;
|
|
163279
163739
|
}
|
|
163280
163740
|
if (!await claim(summaryPath)) {
|
|
163281
|
-
await
|
|
163741
|
+
await rm23(rawPath, { force: true });
|
|
163282
163742
|
continue;
|
|
163283
163743
|
}
|
|
163284
163744
|
return { id, rawPath, summaryPath };
|
|
@@ -164754,7 +165214,7 @@ function readLiteral(source, start, quote) {
|
|
|
164754
165214
|
}
|
|
164755
165215
|
|
|
164756
165216
|
// src/wiki/freshness/queue.ts
|
|
164757
|
-
import { readFile as readFile161, rename as
|
|
165217
|
+
import { readFile as readFile161, rename as rename11, stat as stat32, unlink as unlink3, writeFile as writeFile43 } from "fs/promises";
|
|
164758
165218
|
import path312 from "path";
|
|
164759
165219
|
function queuePath(cwd) {
|
|
164760
165220
|
return path312.join(cwd, ".metaproject", "data", "wiki", QUEUE_FILE);
|
|
@@ -164776,7 +165236,7 @@ async function drainQueue(cwd) {
|
|
|
164776
165236
|
if (line.trim().length === 0) {
|
|
164777
165237
|
continue;
|
|
164778
165238
|
}
|
|
164779
|
-
const entry =
|
|
165239
|
+
const entry = parseEntry4(line);
|
|
164780
165240
|
if (entry === null) {
|
|
164781
165241
|
corruptLines += 1;
|
|
164782
165242
|
continue;
|
|
@@ -164798,7 +165258,7 @@ async function clearQueue(cwd) {
|
|
|
164798
165258
|
}
|
|
164799
165259
|
}
|
|
164800
165260
|
}
|
|
164801
|
-
function
|
|
165261
|
+
function parseEntry4(line) {
|
|
164802
165262
|
try {
|
|
164803
165263
|
const value = JSON.parse(line);
|
|
164804
165264
|
if (value.schemaVersion !== 1 || typeof value.rev !== "string" || !/^[0-9a-f]{40}$/.test(value.rev) || typeof value.recordedAt !== "string" || !Array.isArray(value.paths)) {
|
|
@@ -169551,7 +170011,7 @@ var init_sync2 = __esm(() => {
|
|
|
169551
170011
|
});
|
|
169552
170012
|
|
|
169553
170013
|
// src/gdskills/rule-references.ts
|
|
169554
|
-
import { stat as
|
|
170014
|
+
import { stat as stat33 } from "fs/promises";
|
|
169555
170015
|
import path328 from "path";
|
|
169556
170016
|
function ruleReferences(content) {
|
|
169557
170017
|
const refs = new Set;
|
|
@@ -169568,7 +170028,7 @@ function withKeryxDirSpelling(ref) {
|
|
|
169568
170028
|
}
|
|
169569
170029
|
async function isRegularFile(absolute) {
|
|
169570
170030
|
try {
|
|
169571
|
-
return (await
|
|
170031
|
+
return (await stat33(absolute)).isFile();
|
|
169572
170032
|
} catch {
|
|
169573
170033
|
return false;
|
|
169574
170034
|
}
|
|
@@ -169789,7 +170249,7 @@ var init_project_reviewers = __esm(() => {
|
|
|
169789
170249
|
});
|
|
169790
170250
|
|
|
169791
170251
|
// src/gdskills/import-skills.ts
|
|
169792
|
-
import { readdir as readdir54, readFile as readFile170, stat as
|
|
170252
|
+
import { readdir as readdir54, readFile as readFile170, stat as stat34 } from "fs/promises";
|
|
169793
170253
|
import { homedir as homedir14 } from "os";
|
|
169794
170254
|
import path330 from "path";
|
|
169795
170255
|
function emptyOnlyError(label) {
|
|
@@ -169830,7 +170290,7 @@ async function importProjectSkills(options) {
|
|
|
169830
170290
|
addFlagWarnings(imported, sources, existingFlags);
|
|
169831
170291
|
const rules = [];
|
|
169832
170292
|
for (const decision of ruleDecisions) {
|
|
169833
|
-
rules.push("row" in decision ? decision.row : options.dryRun ? unwrittenRow(decision.placement, [decision.dryRunReason, ...gateNotes(decision.gate, true)].filter(
|
|
170293
|
+
rules.push("row" in decision ? decision.row : options.dryRun ? unwrittenRow(decision.placement, [decision.dryRunReason, ...gateNotes(decision.gate, true)].filter(isString4).join(" \u2014 ") || undefined, decision.gate.security) : await writePlacedRule(options, decision.placement, decision.gate));
|
|
169834
170294
|
}
|
|
169835
170295
|
return {
|
|
169836
170296
|
from: options.from,
|
|
@@ -170150,7 +170610,7 @@ async function resolveImportSources(options) {
|
|
|
170150
170610
|
if (!await pathExists(resolved)) {
|
|
170151
170611
|
throw new Error(`keryx skills import: --from ${options.from} does not exist (resolved to ${resolved})`);
|
|
170152
170612
|
}
|
|
170153
|
-
const stats = await
|
|
170613
|
+
const stats = await stat34(resolved);
|
|
170154
170614
|
if (stats.isFile()) {
|
|
170155
170615
|
return [await sourceFromFile(options, resolved)];
|
|
170156
170616
|
}
|
|
@@ -170351,7 +170811,7 @@ function gateRowParts(gate, dryRun) {
|
|
|
170351
170811
|
return security;
|
|
170352
170812
|
}
|
|
170353
170813
|
function gateNotes(gate, dryRun) {
|
|
170354
|
-
return [gateRowParts(gate, dryRun).reason].filter(
|
|
170814
|
+
return [gateRowParts(gate, dryRun).reason].filter(isString4);
|
|
170355
170815
|
}
|
|
170356
170816
|
function plannedSkillText(content, header) {
|
|
170357
170817
|
const version = parseSkillFrontmatter(content).metadataVersion ?? "0.1.0";
|
|
@@ -170967,7 +171427,7 @@ Examples:
|
|
|
170967
171427
|
var BUNDLED_NAMES, PATHS_NONE_WARNING = 'paths: none \u2014 dispatched on every round. Declare `metadata.paths: "<glob>, <glob>"` in its frontmatter to gate it on the diff.', DEFAULT_FETCHER = async (url) => {
|
|
170968
171428
|
const response = await fetch(url);
|
|
170969
171429
|
return { ok: response.ok, status: response.status, text: await response.text() };
|
|
170970
|
-
}, DEPRECATED_REASON = "deprecated", KNOWN_CATEGORIES,
|
|
171430
|
+
}, DEPRECATED_REASON = "deprecated", KNOWN_CATEGORIES, isString4 = (value) => value !== undefined, REFUSED_NOTE = "A refused file was not written.", ALLOW_FLAGGED_HINT = "A prompt-injection refusal can be overridden after you read the file: run the command again with --allow-flagged.", IMPORT_HEADER_LABELS, IMPORT_HEADER_LINE, BYTE_ORDER_MARK = 65279, ALLOW_FLAGGED_FLAG = "--allow-flagged", SECURITY_GATE_HELP = `Security gate: a SKILL.md or rule is written as the gate returns it, so a secret is
|
|
170971
171431
|
masked and the row says it was redacted, and any other finding is reported on the
|
|
170972
171432
|
row. Text with a prompt-injection finding is refused in every security mode: the
|
|
170973
171433
|
row is \`refused\` (\`would-refuse\` on a dry run) with the gate's own summary,
|
|
@@ -181155,12 +181615,29 @@ var init_command_registry = __esm(() => {
|
|
|
181155
181615
|
{
|
|
181156
181616
|
module: "decisions",
|
|
181157
181617
|
command: "decisions report",
|
|
181158
|
-
summary: "Match share between the human's choice and the agent's recommendation, by mode (ordinary, blind) and by stage, " + "with every deviation and its reason. Deterministic, no model.",
|
|
181618
|
+
summary: "Match share between the human's choice and the agent's recommendation, by mode (ordinary, blind) and by stage, " + "with every deviation and its reason. Backfilled (imported, historical) decisions are reported in a block of their own and never counted in the live shares or the time to answer. Deterministic, no model.",
|
|
181159
181619
|
intent: ["decisions report", "\u043E\u0442\u0447\u0451\u0442 \u043F\u043E \u0440\u0435\u043A\u043E\u043C\u0435\u043D\u0434\u0430\u0446\u0438\u044F\u043C", "how often does the human follow the recommendation", "blind mode results"],
|
|
181160
|
-
args: [
|
|
181620
|
+
args: [
|
|
181621
|
+
{ name: "json", type: "bool", required: false, desc: "print the report as JSON (with a `backfilled` section)" },
|
|
181622
|
+
{ name: "line", type: "bool", required: false, desc: "print ONE line in Russian for the daily topic message: the total and the match share of the visible, hidden and historical decisions" }
|
|
181623
|
+
],
|
|
181161
181624
|
json: true,
|
|
181162
181625
|
read: true
|
|
181163
181626
|
},
|
|
181627
|
+
{
|
|
181628
|
+
module: "decisions",
|
|
181629
|
+
command: "decisions import",
|
|
181630
|
+
summary: 'Import historical decisions from a JSON-lines file as backfilled records: the "before" arm of a comparison with the live journal. ' + "Each is marked backfilled, is never blind, keeps the time it was asked, and is reported apart from the live ones. " + "A line that is not a decision is skipped, named with its line number and counted as malformed, and the rest is imported; an id already in the journal is skipped, so a second import changes nothing (except that a backfilled decision missing its answer gets just that answer).",
|
|
181631
|
+
intent: ["decisions import", "import historical decisions", "backfill the recommendation journal", "\u0438\u043C\u043F\u043E\u0440\u0442 \u0438\u0441\u0442\u043E\u0440\u0438\u0447\u0435\u0441\u043A\u0438\u0445 \u0440\u0435\u0448\u0435\u043D\u0438\u0439", "\u0434\u043E\u0437\u0430\u043F\u043E\u043B\u043D\u0438\u0442\u044C \u0436\u0443\u0440\u043D\u0430\u043B \u0440\u0435\u0448\u0435\u043D\u0438\u0439"],
|
|
181632
|
+
args: [
|
|
181633
|
+
{ name: "<file>", type: "string", required: true, desc: "a JSON-lines file, one decision per line: id, at, flow, stage, question, options, recommendation, source, answer, reason" },
|
|
181634
|
+
{ name: "dry-run", type: "bool", required: false, desc: "check and count without writing" },
|
|
181635
|
+
{ name: "json", type: "bool", required: false, desc: 'print the counts as JSON (a failure is {"error": "..."})' }
|
|
181636
|
+
],
|
|
181637
|
+
json: true,
|
|
181638
|
+
read: false,
|
|
181639
|
+
sideEffects: ["appends open, answer and reason records to .metaproject/data/decisions/journal.jsonl (nothing with --dry-run)"]
|
|
181640
|
+
},
|
|
181164
181641
|
{
|
|
181165
181642
|
module: "product",
|
|
181166
181643
|
command: "product index",
|
|
@@ -182014,7 +182491,7 @@ function isPassGate(gate) {
|
|
|
182014
182491
|
|
|
182015
182492
|
// src/commands/security-audit-harness.ts
|
|
182016
182493
|
import path347 from "path";
|
|
182017
|
-
import { stat as
|
|
182494
|
+
import { stat as stat35 } from "fs/promises";
|
|
182018
182495
|
function isSeverity(value) {
|
|
182019
182496
|
return value !== undefined && SEVERITIES3.includes(value);
|
|
182020
182497
|
}
|
|
@@ -182059,7 +182536,7 @@ async function handleAuditHarness(cwd, args = []) {
|
|
|
182059
182536
|
}
|
|
182060
182537
|
async function handleRun(cwd, args) {
|
|
182061
182538
|
const root = resolveRoot(cwd, args);
|
|
182062
|
-
const rootStat = await
|
|
182539
|
+
const rootStat = await stat35(root).catch(() => {
|
|
182063
182540
|
return;
|
|
182064
182541
|
});
|
|
182065
182542
|
if (!rootStat || !rootStat.isDirectory()) {
|
|
@@ -182146,7 +182623,7 @@ async function handleApply(cwd, args) {
|
|
|
182146
182623
|
process.exitCode = 1;
|
|
182147
182624
|
return;
|
|
182148
182625
|
}
|
|
182149
|
-
const rootStat = await
|
|
182626
|
+
const rootStat = await stat35(root).catch(() => {
|
|
182150
182627
|
return;
|
|
182151
182628
|
});
|
|
182152
182629
|
if (!rootStat || !rootStat.isDirectory()) {
|
|
@@ -184193,7 +184670,7 @@ var init_metaproject_tools2 = __esm(() => {
|
|
|
184193
184670
|
// src/mcp/tools.ts
|
|
184194
184671
|
import { readFile as readFile185, realpath as realpath22, writeFile as writeFile49 } from "fs/promises";
|
|
184195
184672
|
import path351 from "path";
|
|
184196
|
-
import { randomUUID as
|
|
184673
|
+
import { randomUUID as randomUUID43 } from "crypto";
|
|
184197
184674
|
function sacWorkspaceService(cwd) {
|
|
184198
184675
|
return new WorkspaceService({
|
|
184199
184676
|
workspaceRoot: cwd,
|
|
@@ -184279,7 +184756,7 @@ function buildToolRegistry() {
|
|
|
184279
184756
|
{ name: "sac.collaboration", module: "sac", description: "Read the collaboration references and activity for one Shared Agent Context workspace \u2014 who is participating and what has moved recently, redacted to what this actor may see. Local stdio only: over HTTP it returns `sac_transport_denied` without reading anything, because HTTP has no verified principal and must not inherit the local OS actor. Returns references and activity, not the items themselves \u2014 use sac.overview to enumerate items and sac.read to fetch one. Discover the workspaceId with sac.workspaceList.", inputSchema: OBJECT_SCHEMA({ workspaceId: { type: "string" } }, ["workspaceId"]), mutating: false, async invoke(cwd, params, context) {
|
|
184280
184757
|
if (context?.transport === "http")
|
|
184281
184758
|
return { code: "sac_transport_denied" };
|
|
184282
|
-
return normalizeCollaborationResult(await createLocalCollaborationService(cwd).overview({ workspaceId: stringParam2(params, "workspaceId") ?? "", request: undefined, requestCorrelationId:
|
|
184759
|
+
return normalizeCollaborationResult(await createLocalCollaborationService(cwd).overview({ workspaceId: stringParam2(params, "workspaceId") ?? "", request: undefined, requestCorrelationId: randomUUID43() }));
|
|
184283
184760
|
} },
|
|
184284
184761
|
{
|
|
184285
184762
|
name: "sac.overview",
|
|
@@ -184293,7 +184770,7 @@ function buildToolRegistry() {
|
|
|
184293
184770
|
const workspaceId = stringParam2(params, "workspaceId") ?? "";
|
|
184294
184771
|
const maxItems = typeof params.maxItems === "number" ? params.maxItems : 32;
|
|
184295
184772
|
const maxTokens = typeof params.maxTokens === "number" ? params.maxTokens : 4096;
|
|
184296
|
-
return normalizeFwkResult(await createLocalFwkReadService(cwd).overview({ workspaceId, request: undefined, requestCorrelationId:
|
|
184773
|
+
return normalizeFwkResult(await createLocalFwkReadService(cwd).overview({ workspaceId, request: undefined, requestCorrelationId: randomUUID43(), budget: { maxItems, maxTokens } }));
|
|
184297
184774
|
}
|
|
184298
184775
|
},
|
|
184299
184776
|
{
|
|
@@ -184309,7 +184786,7 @@ function buildToolRegistry() {
|
|
|
184309
184786
|
const itemId = stringParam2(params, "itemId") ?? "";
|
|
184310
184787
|
const maxItems = typeof params.maxItems === "number" ? params.maxItems : 1;
|
|
184311
184788
|
const maxTokens = typeof params.maxTokens === "number" ? params.maxTokens : 4096;
|
|
184312
|
-
return normalizeFwkResult(await createLocalFwkReadService(cwd).read({ workspaceId, itemId, request: undefined, requestCorrelationId:
|
|
184789
|
+
return normalizeFwkResult(await createLocalFwkReadService(cwd).read({ workspaceId, itemId, request: undefined, requestCorrelationId: randomUUID43(), budget: { maxItems, maxTokens } }));
|
|
184313
184790
|
}
|
|
184314
184791
|
},
|
|
184315
184792
|
{
|
|
@@ -184330,12 +184807,12 @@ function buildToolRegistry() {
|
|
|
184330
184807
|
if (!session)
|
|
184331
184808
|
throw new Error(`no session matching "${sessionRef}" in this project`);
|
|
184332
184809
|
const { service, wrapUpAuthority, authorizationServer } = createHarnessProposalLifecycleService(cwd, { workspaceId, ...note ? { note } : {} });
|
|
184333
|
-
const requestCorrelationId =
|
|
184810
|
+
const requestCorrelationId = randomUUID43();
|
|
184334
184811
|
const actor = await authorizationServer.actorContextFor(undefined, requestCorrelationId);
|
|
184335
184812
|
if (!actor)
|
|
184336
184813
|
throw new Error("trusted ActorContext is required");
|
|
184337
184814
|
const wrapUp = await wrapUpAuthority.issue({ actor, source: "session", sourceRef: sessionEvidenceRef(workspaceId, session.id) });
|
|
184338
|
-
const proposal = await service.create({ request: undefined, requestCorrelationId, workspaceId, id: `proposal-${
|
|
184815
|
+
const proposal = await service.create({ request: undefined, requestCorrelationId, workspaceId, id: `proposal-${randomUUID43().replace(/-/g, "").slice(0, 16)}`, proposalRevision, kind, wrapUp });
|
|
184339
184816
|
if (note)
|
|
184340
184817
|
await writeFile49(proposalNotePath(cwd, workspaceId, proposal.id), note, "utf8");
|
|
184341
184818
|
return normalizeProposalLifecycleResult(proposal);
|
|
@@ -184354,9 +184831,9 @@ function buildToolRegistry() {
|
|
|
184354
184831
|
const proposalId = stringParam2(params, "proposalId") ?? "";
|
|
184355
184832
|
const decision = stringParam2(params, "decision");
|
|
184356
184833
|
const reason = stringParam2(params, "reason");
|
|
184357
|
-
const idempotencyKey = stringParam2(params, "idempotencyKey") ??
|
|
184834
|
+
const idempotencyKey = stringParam2(params, "idempotencyKey") ?? randomUUID43();
|
|
184358
184835
|
const confirmToken = stringParam2(params, "confirmToken");
|
|
184359
|
-
const result = await createHarnessProposalLifecycleService(cwd, { workspaceId }).service.review({ request: undefined, requestCorrelationId:
|
|
184836
|
+
const result = await createHarnessProposalLifecycleService(cwd, { workspaceId }).service.review({ request: undefined, requestCorrelationId: randomUUID43(), workspaceId, proposalId, decision, idempotencyKey, interactive: true, ...reason ? { reason } : {}, ...confirmToken ? { confirmToken } : {} });
|
|
184360
184837
|
return normalizeProposalLifecycleResult(result);
|
|
184361
184838
|
}
|
|
184362
184839
|
},
|
|
@@ -184404,7 +184881,7 @@ function buildToolRegistry() {
|
|
|
184404
184881
|
throw new Error("sac.workspaceCreate requires a non-empty 'title'");
|
|
184405
184882
|
const rawComponent = stringParam2(params, "component");
|
|
184406
184883
|
const component = rawComponent === undefined ? undefined : requireWorkspaceReference(rawComponent);
|
|
184407
|
-
const workspace = await sacWorkspaceService(cwd).create({ request: undefined, requestCorrelationId:
|
|
184884
|
+
const workspace = await sacWorkspaceService(cwd).create({ request: undefined, requestCorrelationId: randomUUID43(), id: newWorkspaceId(), title, ...component ? { component: { kind: "component", uri: component } } : {} });
|
|
184408
184885
|
return workspace;
|
|
184409
184886
|
}
|
|
184410
184887
|
},
|
|
@@ -184465,7 +184942,7 @@ function buildToolRegistry() {
|
|
|
184465
184942
|
const text = redactSensitiveText(rawText);
|
|
184466
184943
|
const ts = new Date().toISOString();
|
|
184467
184944
|
const seed = {
|
|
184468
|
-
id: `seed-${
|
|
184945
|
+
id: `seed-${randomUUID43()}`,
|
|
184469
184946
|
text,
|
|
184470
184947
|
ts,
|
|
184471
184948
|
...kind ? { kind } : {},
|
|
@@ -184911,7 +185388,7 @@ var init_tools3 = __esm(() => {
|
|
|
184911
185388
|
|
|
184912
185389
|
// src/mcp/resources.ts
|
|
184913
185390
|
import path352 from "path";
|
|
184914
|
-
import { lstat as lstat19, readdir as readdir63, realpath as realpath23, stat as
|
|
185391
|
+
import { lstat as lstat19, readdir as readdir63, realpath as realpath23, stat as stat36 } from "fs/promises";
|
|
184915
185392
|
function mimeForPath(filePath) {
|
|
184916
185393
|
if (filePath.endsWith(".json") || filePath.endsWith(".jsonl")) {
|
|
184917
185394
|
return "application/json";
|
|
@@ -184954,7 +185431,7 @@ async function walkFiles(root, ownerRoot = root, ancestors = new Set) {
|
|
|
184954
185431
|
}
|
|
184955
185432
|
for (const entry of entries) {
|
|
184956
185433
|
const full = path352.join(root, entry.name);
|
|
184957
|
-
const info = await
|
|
185434
|
+
const info = await stat36(full).catch(() => null);
|
|
184958
185435
|
if (!info || !isPathInside(ownerReal, await realpath23(full).catch(() => "")))
|
|
184959
185436
|
continue;
|
|
184960
185437
|
if (info.isDirectory()) {
|
|
@@ -185075,7 +185552,7 @@ async function readResource(cwd, roots, uri, harnessIdentity = null) {
|
|
|
185075
185552
|
throw new Error(`Resource not found: ${uri}`);
|
|
185076
185553
|
}
|
|
185077
185554
|
}
|
|
185078
|
-
const info = await
|
|
185555
|
+
const info = await stat36(resolved.absolute).catch(() => null);
|
|
185079
185556
|
if (!info || !info.isFile()) {
|
|
185080
185557
|
throw new Error(`Resource not found: ${uri}`);
|
|
185081
185558
|
}
|
|
@@ -186593,7 +187070,7 @@ var init_service18 = __esm(() => {
|
|
|
186593
187070
|
|
|
186594
187071
|
// src/commands/stack.ts
|
|
186595
187072
|
import path356 from "path";
|
|
186596
|
-
import { stat as
|
|
187073
|
+
import { stat as stat37 } from "fs/promises";
|
|
186597
187074
|
async function stackCommand(args, cwd = process.cwd()) {
|
|
186598
187075
|
const sub = args[0];
|
|
186599
187076
|
if (sub === undefined || sub === "--help" || sub === "-h") {
|
|
@@ -186625,7 +187102,7 @@ async function handleDetect(args, cwd) {
|
|
|
186625
187102
|
const write = !args.includes("--no-write");
|
|
186626
187103
|
let rootStat;
|
|
186627
187104
|
try {
|
|
186628
|
-
rootStat = await
|
|
187105
|
+
rootStat = await stat37(root);
|
|
186629
187106
|
} catch {
|
|
186630
187107
|
console.error(`--cwd directory does not exist: ${root}`);
|
|
186631
187108
|
process.exitCode = 1;
|
|
@@ -188125,7 +188602,7 @@ function checkApproval(input) {
|
|
|
188125
188602
|
// src/commands/harness.ts
|
|
188126
188603
|
import { readFileSync as readFileSync28, writeFileSync as writeFileSync10 } from "fs";
|
|
188127
188604
|
import path357 from "path";
|
|
188128
|
-
import { randomUUID as
|
|
188605
|
+
import { randomUUID as randomUUID44 } from "crypto";
|
|
188129
188606
|
import { realpathSync as realpathSync18 } from "fs";
|
|
188130
188607
|
import { homedir as homedir15, tmpdir as tmpdir14 } from "os";
|
|
188131
188608
|
function canonicalPath2(p) {
|
|
@@ -188152,7 +188629,7 @@ function resolveRuntime(deps) {
|
|
|
188152
188629
|
const env = deps?.env ?? process.env;
|
|
188153
188630
|
const clock = deps?.clock ?? (() => new Date().toISOString());
|
|
188154
188631
|
let idCounter = 0;
|
|
188155
|
-
const idSeq = deps?.idSeq ?? (() => `${
|
|
188632
|
+
const idSeq = deps?.idSeq ?? (() => `${randomUUID44()}-${idCounter++}`);
|
|
188156
188633
|
return { env, clock, idSeq };
|
|
188157
188634
|
}
|
|
188158
188635
|
function shellAllowProfile() {
|
|
@@ -188256,7 +188733,7 @@ async function harnessCommand(args, deps) {
|
|
|
188256
188733
|
const env = deps?.env ?? process.env;
|
|
188257
188734
|
const clock = deps?.clock ?? (() => new Date().toISOString());
|
|
188258
188735
|
let idCounter = 0;
|
|
188259
|
-
const idSeq = deps?.idSeq ?? (() => `${
|
|
188736
|
+
const idSeq = deps?.idSeq ?? (() => `${randomUUID44()}-${idCounter++}`);
|
|
188260
188737
|
const fetchImpl = deps?.fetch ?? globalThis.fetch;
|
|
188261
188738
|
if (provider === "anthropic") {
|
|
188262
188739
|
const apiKey = env.ANTHROPIC_API_KEY;
|
|
@@ -188397,7 +188874,7 @@ function harnessReplay(args, deps) {
|
|
|
188397
188874
|
}
|
|
188398
188875
|
const clock = deps?.clock ?? (() => new Date().toISOString());
|
|
188399
188876
|
let idCounter = 0;
|
|
188400
|
-
const idSeq = deps?.idSeq ?? (() => `${
|
|
188877
|
+
const idSeq = deps?.idSeq ?? (() => `${randomUUID44()}-${idCounter++}`);
|
|
188401
188878
|
const fixture = (() => {
|
|
188402
188879
|
if (parsed.fixture === undefined || parsed.fixture.length === 0) {
|
|
188403
188880
|
return { ok: true, value: buildReplayFixture(run, { idSeq }), built: true };
|
|
@@ -189112,7 +189589,7 @@ var init_permission = __esm(() => {
|
|
|
189112
189589
|
});
|
|
189113
189590
|
|
|
189114
189591
|
// src/acp/agent-io.ts
|
|
189115
|
-
import { randomUUID as
|
|
189592
|
+
import { randomUUID as randomUUID45 } from "crypto";
|
|
189116
189593
|
function toolKindFor(name) {
|
|
189117
189594
|
return TOOL_KIND_BY_NAME[name] ?? "other";
|
|
189118
189595
|
}
|
|
@@ -189127,7 +189604,7 @@ function createAcpAgentIo(sessionId, send, askPermission) {
|
|
|
189127
189604
|
const pendingByName = new Map;
|
|
189128
189605
|
const emit = (update) => send(sessionId, update);
|
|
189129
189606
|
const openToolCall = (name, input, claimed) => {
|
|
189130
|
-
const toolCallId =
|
|
189607
|
+
const toolCallId = randomUUID45();
|
|
189131
189608
|
const queue = pendingByName.get(name) ?? [];
|
|
189132
189609
|
queue.push({ toolCallId, input, claimed });
|
|
189133
189610
|
pendingByName.set(name, queue);
|
|
@@ -189214,7 +189691,7 @@ function createAcpAgentIo(sessionId, send, askPermission) {
|
|
|
189214
189691
|
const toolCallId = pending?.toolCallId;
|
|
189215
189692
|
emit({
|
|
189216
189693
|
sessionUpdate: "tool_call_update",
|
|
189217
|
-
toolCallId: toolCallId ??
|
|
189694
|
+
toolCallId: toolCallId ?? randomUUID45(),
|
|
189218
189695
|
status: result.isError ? "failed" : "completed",
|
|
189219
189696
|
content: [{ type: "content", content: textBlock(result.output) }],
|
|
189220
189697
|
rawOutput: result.output
|
|
@@ -189813,7 +190290,7 @@ var init_session_mcp = __esm(() => {
|
|
|
189813
190290
|
});
|
|
189814
190291
|
|
|
189815
190292
|
// src/acp/server.ts
|
|
189816
|
-
import { randomUUID as
|
|
190293
|
+
import { randomUUID as randomUUID46 } from "crypto";
|
|
189817
190294
|
function finishReasonToStopReason(finishReason) {
|
|
189818
190295
|
switch (finishReason) {
|
|
189819
190296
|
case "budget":
|
|
@@ -189833,7 +190310,7 @@ function refuse5(error) {
|
|
|
189833
190310
|
async function runAcpServer(options) {
|
|
189834
190311
|
let initialized = false;
|
|
189835
190312
|
let clientCapabilities;
|
|
189836
|
-
const idSeq = options.idSeq ?? (() =>
|
|
190313
|
+
const idSeq = options.idSeq ?? (() => randomUUID46());
|
|
189837
190314
|
const registry = new AcpSessionRegistry({
|
|
189838
190315
|
providerId: options.providerId,
|
|
189839
190316
|
modelId: options.modelId,
|
|
@@ -190476,7 +190953,7 @@ Switch with /model <model>; it applies from the next turn.`;
|
|
|
190476
190953
|
}
|
|
190477
190954
|
continue;
|
|
190478
190955
|
}
|
|
190479
|
-
const toolCallId = message.toolCallId ??
|
|
190956
|
+
const toolCallId = message.toolCallId ?? randomUUID46();
|
|
190480
190957
|
sendUpdate(sessionId, {
|
|
190481
190958
|
sessionUpdate: "tool_call_update",
|
|
190482
190959
|
toolCallId,
|
|
@@ -190715,7 +191192,7 @@ var MODEL_PLACEHOLDER = "{{model}}";
|
|
|
190715
191192
|
var init_fixture_provider = () => {};
|
|
190716
191193
|
|
|
190717
191194
|
// src/commands/acp.ts
|
|
190718
|
-
import { randomUUID as
|
|
191195
|
+
import { randomUUID as randomUUID47 } from "crypto";
|
|
190719
191196
|
function parseAcpArgs(args) {
|
|
190720
191197
|
const parsed = {};
|
|
190721
191198
|
for (let i = 0;i < args.length; i += 1) {
|
|
@@ -190969,7 +191446,7 @@ async function acpCommand(args) {
|
|
|
190969
191446
|
} : { providerUnavailable: resolution.message, providerId: "", modelId: "" },
|
|
190970
191447
|
agentInfo: { name: "keryx", version: package_default.version },
|
|
190971
191448
|
...parsed.dataDir !== undefined ? { dataDir: parsed.dataDir } : {},
|
|
190972
|
-
idSeq: () =>
|
|
191449
|
+
idSeq: () => randomUUID47()
|
|
190973
191450
|
});
|
|
190974
191451
|
} finally {
|
|
190975
191452
|
process.off("SIGTERM", onSignal);
|
|
@@ -191036,7 +191513,7 @@ var init_acp = __esm(() => {
|
|
|
191036
191513
|
});
|
|
191037
191514
|
|
|
191038
191515
|
// src/bus/prune.ts
|
|
191039
|
-
import { randomUUID as
|
|
191516
|
+
import { randomUUID as randomUUID48 } from "crypto";
|
|
191040
191517
|
async function expiryAlreadyLogged(root, leaseId) {
|
|
191041
191518
|
const { events } = await readEvents(root, await cursorAtStart(root));
|
|
191042
191519
|
return events.some((event) => event.kind === "lease-expired" && event.refs?.leaseId === leaseId);
|
|
@@ -191070,7 +191547,7 @@ async function pruneBus(root, options = {}) {
|
|
|
191070
191547
|
const file = leasePath(root, lease.leaseId);
|
|
191071
191548
|
try {
|
|
191072
191549
|
await appendEvent(root, {
|
|
191073
|
-
from: { instanceId:
|
|
191550
|
+
from: { instanceId: randomUUID48(), name: "system", origin: "system" },
|
|
191074
191551
|
to: ["*"],
|
|
191075
191552
|
toLabel: "@all",
|
|
191076
191553
|
kind: "lease-expired",
|
|
@@ -191123,7 +191600,7 @@ var init_prune3 = __esm(() => {
|
|
|
191123
191600
|
});
|
|
191124
191601
|
|
|
191125
191602
|
// src/commands/bus.ts
|
|
191126
|
-
import { randomUUID as
|
|
191603
|
+
import { randomUUID as randomUUID49 } from "crypto";
|
|
191127
191604
|
async function busCommand(args) {
|
|
191128
191605
|
const code = await runBusCommand(args);
|
|
191129
191606
|
if (code !== 0)
|
|
@@ -191276,7 +191753,7 @@ ${PAUSE_USAGE3}`);
|
|
|
191276
191753
|
if (toLabel === undefined || reason === undefined || reason.length === 0) {
|
|
191277
191754
|
throw new BusRefusal("invalid-event", PAUSE_USAGE3);
|
|
191278
191755
|
}
|
|
191279
|
-
const holder = { instanceId:
|
|
191756
|
+
const holder = { instanceId: randomUUID49(), name: "cli", origin: "cli" };
|
|
191280
191757
|
const lease = await createPauseLease(busRoot, {
|
|
191281
191758
|
holder,
|
|
191282
191759
|
toLabel,
|
|
@@ -191298,7 +191775,7 @@ async function resume(args, busRoot, ctx) {
|
|
|
191298
191775
|
if (leaseId === undefined) {
|
|
191299
191776
|
throw new BusRefusal("invalid-event", "usage: keryx bus resume <leaseId> [--json]");
|
|
191300
191777
|
}
|
|
191301
|
-
await resumePauseLease(busRoot, { leaseId, by: { instanceId:
|
|
191778
|
+
await resumePauseLease(busRoot, { leaseId, by: { instanceId: randomUUID49(), name: "cli", origin: "cli" }, now: ctx.now });
|
|
191302
191779
|
if (args.includes("--json")) {
|
|
191303
191780
|
ctx.out(JSON.stringify({ schemaVersion: 1, leaseId }, null, 2));
|
|
191304
191781
|
} else {
|
|
@@ -191602,7 +192079,7 @@ var init_modules = __esm(() => {
|
|
|
191602
192079
|
});
|
|
191603
192080
|
|
|
191604
192081
|
// src/lib/serve-approvals-broker.ts
|
|
191605
|
-
import { randomUUID as
|
|
192082
|
+
import { randomUUID as randomUUID50 } from "crypto";
|
|
191606
192083
|
function describeAsk(ask) {
|
|
191607
192084
|
const floors = ask.floors.length > 0 ? ` Needs a fresh answer every time (${ask.floors.join(", ")}).` : "";
|
|
191608
192085
|
return {
|
|
@@ -191658,7 +192135,7 @@ function createApprovalBroker(options) {
|
|
|
191658
192135
|
sessionId: ask.sessionId,
|
|
191659
192136
|
...text,
|
|
191660
192137
|
expiresAt: new Date(createdAt.getTime() + options.expirySeconds * 1000),
|
|
191661
|
-
correlationId:
|
|
192138
|
+
correlationId: randomUUID50(),
|
|
191662
192139
|
callFingerprint: ask.callFingerprint,
|
|
191663
192140
|
floors: ask.floors
|
|
191664
192141
|
}, options.dir, createdAt);
|
|
@@ -191800,7 +192277,7 @@ var init_serve_throttle = __esm(() => {
|
|
|
191800
192277
|
});
|
|
191801
192278
|
|
|
191802
192279
|
// src/lib/serve-turn.ts
|
|
191803
|
-
import { randomUUID as
|
|
192280
|
+
import { randomUUID as randomUUID51 } from "crypto";
|
|
191804
192281
|
import path359 from "path";
|
|
191805
192282
|
function validateTurnRequest(body) {
|
|
191806
192283
|
const problem = (message) => ({
|
|
@@ -191975,7 +192452,7 @@ async function redactOut(security, text) {
|
|
|
191975
192452
|
async function runRemoteTurn(input) {
|
|
191976
192453
|
const scanRoot = input.scanRoot;
|
|
191977
192454
|
const security = createSecurityService(scanRoot);
|
|
191978
|
-
const newId = input.newId ?? (() =>
|
|
192455
|
+
const newId = input.newId ?? (() => randomUUID51());
|
|
191979
192456
|
const clock = input.clock ?? (() => new Date().toISOString());
|
|
191980
192457
|
const turnId = input.turnId ?? newId();
|
|
191981
192458
|
const sessionId = input.request.sessionId ?? newId();
|
|
@@ -192158,7 +192635,7 @@ function outcomeOf(status, gate, unresolvedBlockerIds) {
|
|
|
192158
192635
|
}
|
|
192159
192636
|
function createSubmitTurn(deps) {
|
|
192160
192637
|
return async (request, project) => {
|
|
192161
|
-
const turnId = (deps.newId ?? (() =>
|
|
192638
|
+
const turnId = (deps.newId ?? (() => randomUUID51()))();
|
|
192162
192639
|
const scanned = await scanPrompt(deps.dir, request.prompt);
|
|
192163
192640
|
if (scanned.rejected) {
|
|
192164
192641
|
return { kind: "rejected" };
|
|
@@ -192173,7 +192650,7 @@ function createSubmitTurn(deps) {
|
|
|
192173
192650
|
}
|
|
192174
192651
|
let effected = false;
|
|
192175
192652
|
const detached = deps.approvals !== undefined && (deps.toolRegistry?.list().length ?? 0) > 0;
|
|
192176
|
-
const sessionId = request.sessionId ?? (deps.newId ?? (() =>
|
|
192653
|
+
const sessionId = request.sessionId ?? (deps.newId ?? (() => randomUUID51()))();
|
|
192177
192654
|
let onStarted = () => {
|
|
192178
192655
|
return;
|
|
192179
192656
|
};
|
|
@@ -194059,7 +194536,7 @@ var init_durable_log = __esm(() => {
|
|
|
194059
194536
|
import { createHash as createHash80 } from "crypto";
|
|
194060
194537
|
import { unlinkSync as unlinkSync9 } from "fs";
|
|
194061
194538
|
import path361 from "path";
|
|
194062
|
-
function
|
|
194539
|
+
function parseEntry5(value) {
|
|
194063
194540
|
if (typeof value !== "object" || value === null) {
|
|
194064
194541
|
return;
|
|
194065
194542
|
}
|
|
@@ -194095,7 +194572,7 @@ class InboundQueues {
|
|
|
194095
194572
|
log(bindingKey) {
|
|
194096
194573
|
let log = this.logs.get(bindingKey);
|
|
194097
194574
|
if (log === undefined) {
|
|
194098
|
-
log = new DurableLog({ file: this.fileFor(bindingKey), parse:
|
|
194575
|
+
log = new DurableLog({ file: this.fileFor(bindingKey), parse: parseEntry5, maxEntries: MAX_INBOUND_PER_TOPIC });
|
|
194099
194576
|
log.load();
|
|
194100
194577
|
this.logs.set(bindingKey, log);
|
|
194101
194578
|
}
|
|
@@ -194736,9 +195213,9 @@ var init_rendering = __esm(() => {
|
|
|
194736
195213
|
});
|
|
194737
195214
|
|
|
194738
195215
|
// src/remote/outbound-queue.ts
|
|
194739
|
-
import { randomUUID as
|
|
195216
|
+
import { randomUUID as randomUUID52 } from "crypto";
|
|
194740
195217
|
import path363 from "path";
|
|
194741
|
-
function
|
|
195218
|
+
function parseEntry6(value) {
|
|
194742
195219
|
if (typeof value !== "object" || value === null) {
|
|
194743
195220
|
return;
|
|
194744
195221
|
}
|
|
@@ -194781,7 +195258,7 @@ class OutboundQueue {
|
|
|
194781
195258
|
this.log = new DurableLog({
|
|
194782
195259
|
file: path363.join(directory, OUTBOUND_FILE),
|
|
194783
195260
|
maxEntries: options.maxEntries ?? OUTBOUND_MAX_ENTRIES,
|
|
194784
|
-
parse:
|
|
195261
|
+
parse: parseEntry6
|
|
194785
195262
|
});
|
|
194786
195263
|
}
|
|
194787
195264
|
load() {
|
|
@@ -194798,7 +195275,7 @@ class OutboundQueue {
|
|
|
194798
195275
|
const entries = [];
|
|
194799
195276
|
parts.forEach((text, index) => {
|
|
194800
195277
|
const entry = {
|
|
194801
|
-
id:
|
|
195278
|
+
id: randomUUID52(),
|
|
194802
195279
|
chatId: message.chatId,
|
|
194803
195280
|
...message.threadId === undefined ? {} : { threadId: message.threadId },
|
|
194804
195281
|
text,
|
|
@@ -197932,7 +198409,7 @@ var init_serve_digest = __esm(() => {
|
|
|
197932
198409
|
});
|
|
197933
198410
|
|
|
197934
198411
|
// src/commands/serve.ts
|
|
197935
|
-
import { randomUUID as
|
|
198412
|
+
import { randomUUID as randomUUID53 } from "crypto";
|
|
197936
198413
|
function parseArgs5(args, valueFlags, booleanFlags) {
|
|
197937
198414
|
const values = new Map;
|
|
197938
198415
|
const flags = new Set;
|
|
@@ -198258,7 +198735,7 @@ function runConfig(args) {
|
|
|
198258
198735
|
return;
|
|
198259
198736
|
}
|
|
198260
198737
|
const credential = readServeCredential();
|
|
198261
|
-
const credentialId = credential.status === "ok" ? credential.record.id :
|
|
198738
|
+
const credentialId = credential.status === "ok" ? credential.record.id : randomUUID53();
|
|
198262
198739
|
const config = defaultServeConfig(credentialId, {
|
|
198263
198740
|
address: parsed.parsed.values.get("--bind") ?? DEFAULT_SERVE_BIND_ADDRESS,
|
|
198264
198741
|
port: port ?? DEFAULT_SERVE_PORT,
|
|
@@ -199932,7 +200409,7 @@ ${settled.stderr}` };
|
|
|
199932
200409
|
var PROBE_TIMEOUT_MS = 1e4;
|
|
199933
200410
|
|
|
199934
200411
|
// src/commands/agents-external.ts
|
|
199935
|
-
import { randomUUID as
|
|
200412
|
+
import { randomUUID as randomUUID54 } from "crypto";
|
|
199936
200413
|
import { mkdir as mkdir73 } from "fs/promises";
|
|
199937
200414
|
import { tmpdir as tmpdir15 } from "os";
|
|
199938
200415
|
import path369 from "path";
|
|
@@ -200219,7 +200696,7 @@ async function runCommand4(args, deps, log) {
|
|
|
200219
200696
|
taskTitle: task.length > 80 ? `${task.slice(0, 77)}...` : task,
|
|
200220
200697
|
taskDescription: task,
|
|
200221
200698
|
acceptanceCriteria: [],
|
|
200222
|
-
worktreeId: `acp-${
|
|
200699
|
+
worktreeId: `acp-${randomUUID54()}`,
|
|
200223
200700
|
maxPromptBytes: gate.config.maxPromptBytes,
|
|
200224
200701
|
timeoutMs,
|
|
200225
200702
|
parentEnv: env,
|
|
@@ -201865,7 +202342,7 @@ var init_metrics2 = __esm(() => {
|
|
|
201865
202342
|
});
|
|
201866
202343
|
|
|
201867
202344
|
// src/metrics/ablation-runner.ts
|
|
201868
|
-
function
|
|
202345
|
+
function median3(values) {
|
|
201869
202346
|
if (values.length === 0)
|
|
201870
202347
|
return null;
|
|
201871
202348
|
const sorted = [...values].sort((a, b) => a - b);
|
|
@@ -201891,7 +202368,7 @@ function toolCallDistribution(samples) {
|
|
|
201891
202368
|
}));
|
|
201892
202369
|
return {
|
|
201893
202370
|
samples: runSamples,
|
|
201894
|
-
median:
|
|
202371
|
+
median: median3(values),
|
|
201895
202372
|
spread: spread(values),
|
|
201896
202373
|
reliability: ABLATION_RELIABILITY
|
|
201897
202374
|
};
|
|
@@ -201901,7 +202378,7 @@ function tokenCost(samples, source) {
|
|
|
201901
202378
|
if (known.length === 0)
|
|
201902
202379
|
return;
|
|
201903
202380
|
const note = `median of ${known.length}/${samples.length} seed samples with a reported token count`;
|
|
201904
|
-
return { tokens: { raw: measured(
|
|
202381
|
+
return { tokens: { raw: measured(median3(known), source, note) } };
|
|
201905
202382
|
}
|
|
201906
202383
|
function successRate(samples) {
|
|
201907
202384
|
const successes = samples.filter((s) => s.success).length;
|
|
@@ -203228,7 +203705,7 @@ function formatFwkExplain(result) {
|
|
|
203228
203705
|
}
|
|
203229
203706
|
|
|
203230
203707
|
// src/commands/workspace.ts
|
|
203231
|
-
import { randomUUID as
|
|
203708
|
+
import { randomUUID as randomUUID55 } from "crypto";
|
|
203232
203709
|
import { writeFile as writeFile51 } from "fs/promises";
|
|
203233
203710
|
function service8() {
|
|
203234
203711
|
return new WorkspaceService({
|
|
@@ -203249,7 +203726,7 @@ async function workspaceCommand(args) {
|
|
|
203249
203726
|
const component = rawComponent === undefined ? undefined : requireWorkspaceReference(rawComponent);
|
|
203250
203727
|
if (!title)
|
|
203251
203728
|
throw new Error("Usage: keryx workspace create --title <title> [--component <workspace-relative-ref>]");
|
|
203252
|
-
const workspace = await service8().create({ request: undefined, requestCorrelationId:
|
|
203729
|
+
const workspace = await service8().create({ request: undefined, requestCorrelationId: randomUUID55(), id: newWorkspaceId(), title, ...component ? { component: { kind: "component", uri: component } } : {} });
|
|
203253
203730
|
console.log(JSON.stringify(workspace, null, 2));
|
|
203254
203731
|
return;
|
|
203255
203732
|
}
|
|
@@ -203279,7 +203756,7 @@ async function workspaceCommand(args) {
|
|
|
203279
203756
|
const revision = optionValue(args, "--revision");
|
|
203280
203757
|
if (!workspaceId || !kind || !rawUri)
|
|
203281
203758
|
throw new Error("Usage: keryx workspace add-resource <workspace-id> --kind <kind> --uri <workspace-relative-ref> [--revision <revision>]");
|
|
203282
|
-
console.log(JSON.stringify(await service8().addResource({ request: undefined, requestCorrelationId:
|
|
203759
|
+
console.log(JSON.stringify(await service8().addResource({ request: undefined, requestCorrelationId: randomUUID55(), workspaceId, resource: { kind, uri: requireWorkspaceReference(rawUri), ...revision ? { revision } : {} } }), null, 2));
|
|
203283
203760
|
return;
|
|
203284
203761
|
}
|
|
203285
203762
|
if (subcommand === "archive") {
|
|
@@ -203287,7 +203764,7 @@ async function workspaceCommand(args) {
|
|
|
203287
203764
|
const workspaceId = args[1];
|
|
203288
203765
|
if (!workspaceId)
|
|
203289
203766
|
throw new Error("Usage: keryx workspace archive <workspace-id>");
|
|
203290
|
-
console.log(JSON.stringify(await service8().archive({ request: undefined, requestCorrelationId:
|
|
203767
|
+
console.log(JSON.stringify(await service8().archive({ request: undefined, requestCorrelationId: randomUUID55(), workspaceId }), null, 2));
|
|
203291
203768
|
return;
|
|
203292
203769
|
}
|
|
203293
203770
|
if (subcommand === "remove-resource") {
|
|
@@ -203296,7 +203773,7 @@ async function workspaceCommand(args) {
|
|
|
203296
203773
|
const uri = optionValue(args, "--uri");
|
|
203297
203774
|
if (!workspaceId || !uri)
|
|
203298
203775
|
throw new Error("Usage: keryx workspace remove-resource <workspace-id> --uri <workspace-relative-ref>");
|
|
203299
|
-
console.log(JSON.stringify(await service8().removeResource({ request: undefined, requestCorrelationId:
|
|
203776
|
+
console.log(JSON.stringify(await service8().removeResource({ request: undefined, requestCorrelationId: randomUUID55(), workspaceId, uri }), null, 2));
|
|
203300
203777
|
return;
|
|
203301
203778
|
}
|
|
203302
203779
|
if (subcommand === "rename") {
|
|
@@ -203305,7 +203782,7 @@ async function workspaceCommand(args) {
|
|
|
203305
203782
|
const title = optionValue(args, "--title");
|
|
203306
203783
|
if (!workspaceId || !title)
|
|
203307
203784
|
throw new Error("Usage: keryx workspace rename <workspace-id> --title <title>");
|
|
203308
|
-
console.log(JSON.stringify(await service8().rename({ request: undefined, requestCorrelationId:
|
|
203785
|
+
console.log(JSON.stringify(await service8().rename({ request: undefined, requestCorrelationId: randomUUID55(), workspaceId, title }), null, 2));
|
|
203309
203786
|
return;
|
|
203310
203787
|
}
|
|
203311
203788
|
if (subcommand === "overview") {
|
|
@@ -203317,7 +203794,7 @@ async function workspaceCommand(args) {
|
|
|
203317
203794
|
const maxTokens = Number(optionValue(args, "--max-tokens") ?? "4096");
|
|
203318
203795
|
if (!Number.isInteger(maxItems) || !Number.isInteger(maxTokens) || maxItems < 0 || maxTokens < 0)
|
|
203319
203796
|
throw new Error("--max-items and --max-tokens must be non-negative integers");
|
|
203320
|
-
const result = await createLocalFwkReadService(process.cwd()).overview({ workspaceId, request: undefined, requestCorrelationId:
|
|
203797
|
+
const result = await createLocalFwkReadService(process.cwd()).overview({ workspaceId, request: undefined, requestCorrelationId: randomUUID55(), budget: { maxItems, maxTokens } });
|
|
203321
203798
|
const normalized = normalizeFwkResult(result);
|
|
203322
203799
|
console.log(JSON.stringify(normalized, null, 2));
|
|
203323
203800
|
if (args.includes("--explain"))
|
|
@@ -203334,7 +203811,7 @@ async function workspaceCommand(args) {
|
|
|
203334
203811
|
const maxTokens = Number(optionValue(args, "--max-tokens") ?? "4096");
|
|
203335
203812
|
if (!Number.isInteger(maxItems) || !Number.isInteger(maxTokens) || maxItems < 0 || maxTokens < 0)
|
|
203336
203813
|
throw new Error("--max-items and --max-tokens must be non-negative integers");
|
|
203337
|
-
const result = await createLocalFwkReadService(process.cwd()).read({ workspaceId, itemId, request: undefined, requestCorrelationId:
|
|
203814
|
+
const result = await createLocalFwkReadService(process.cwd()).read({ workspaceId, itemId, request: undefined, requestCorrelationId: randomUUID55(), budget: { maxItems, maxTokens } });
|
|
203338
203815
|
const normalized = normalizeFwkResult(result);
|
|
203339
203816
|
console.log(JSON.stringify(normalized, null, 2));
|
|
203340
203817
|
if (args.includes("--explain"))
|
|
@@ -203356,14 +203833,14 @@ async function workspaceCommand(args) {
|
|
|
203356
203833
|
const session = findSession(cwd, sessionRef);
|
|
203357
203834
|
if (!session)
|
|
203358
203835
|
throw new Error(`no session matching "${sessionRef}" in this project \u2014 use \`keryx sessions list\``);
|
|
203359
|
-
const proposalId = `proposal-${
|
|
203836
|
+
const proposalId = `proposal-${randomUUID55().replace(/-/g, "").slice(0, 16)}`;
|
|
203360
203837
|
const notePath = proposalNotePath(cwd, workspaceId, proposalId);
|
|
203361
203838
|
const materializedNote = note === undefined ? undefined : prepareOutputForPersistence(await guardOutput({ cwd, content: note, target: "task", source: "generated", path: notePath }), note);
|
|
203362
203839
|
if (materializedNote !== undefined && !materializedNote.allowed)
|
|
203363
203840
|
throw new Error(materializedNote.reason);
|
|
203364
203841
|
const persistedNote = materializedNote?.allowed ? materializedNote.content : undefined;
|
|
203365
203842
|
const { service, wrapUpAuthority, authorizationServer } = createHarnessProposalLifecycleService(cwd, { workspaceId, ...persistedNote ? { note: persistedNote } : {} });
|
|
203366
|
-
const requestCorrelationId =
|
|
203843
|
+
const requestCorrelationId = randomUUID55();
|
|
203367
203844
|
const actor = await authorizationServer.actorContextFor(undefined, requestCorrelationId);
|
|
203368
203845
|
if (!actor)
|
|
203369
203846
|
throw new Error("trusted ActorContext is required");
|
|
@@ -203404,13 +203881,13 @@ async function workspaceCommand(args) {
|
|
|
203404
203881
|
const proposalId = args[2];
|
|
203405
203882
|
const decision = optionValue(args, "--decision");
|
|
203406
203883
|
const reason = optionValue(args, "--reason");
|
|
203407
|
-
const idempotencyKey = optionValue(args, "--idempotency-key") ??
|
|
203884
|
+
const idempotencyKey = optionValue(args, "--idempotency-key") ?? randomUUID55();
|
|
203408
203885
|
const confirmToken = optionValue(args, "--confirm-token");
|
|
203409
203886
|
if (!workspaceId || !proposalId || !decision)
|
|
203410
203887
|
throw new Error("Usage: keryx workspace review <workspace-id> <proposal-id> --decision <accepted|rejected|dismissed> [--reason <reason>] [--idempotency-key <key>] [--confirm-token <token>]");
|
|
203411
203888
|
if (decision === "accepted" && !confirmToken)
|
|
203412
203889
|
throw new Error("--decision accepted requires --confirm-token \u2014 run `keryx workspace confirm-review " + workspaceId + " " + proposalId + "` first");
|
|
203413
|
-
const result = await createHarnessProposalLifecycleService(process.cwd(), { workspaceId }).service.review({ request: undefined, requestCorrelationId:
|
|
203890
|
+
const result = await createHarnessProposalLifecycleService(process.cwd(), { workspaceId }).service.review({ request: undefined, requestCorrelationId: randomUUID55(), workspaceId, proposalId, decision, idempotencyKey, interactive: true, ...reason ? { reason } : {}, ...confirmToken ? { confirmToken } : {} });
|
|
203414
203891
|
console.log(JSON.stringify(normalizeProposalLifecycleResult(result), null, 2));
|
|
203415
203892
|
return;
|
|
203416
203893
|
}
|
|
@@ -203435,7 +203912,7 @@ async function workspaceCommand(args) {
|
|
|
203435
203912
|
const artifactRef = optionValue(args, "--artifact");
|
|
203436
203913
|
if (!workspaceId || !to || !artifactRef)
|
|
203437
203914
|
throw new Error("Usage: keryx workspace handoff <workspace-id> --to <subject> --artifact <ref>");
|
|
203438
|
-
const activity = await createLocalCollaborationService(process.cwd()).record({ request: undefined, requestCorrelationId:
|
|
203915
|
+
const activity = await createLocalCollaborationService(process.cwd()).record({ request: undefined, requestCorrelationId: randomUUID55(), workspaceId, activity: { kind: "handoff-recorded", handoff: { to, artifactRef } } });
|
|
203439
203916
|
console.log(JSON.stringify(activity, null, 2));
|
|
203440
203917
|
return;
|
|
203441
203918
|
}
|
|
@@ -203444,7 +203921,7 @@ async function workspaceCommand(args) {
|
|
|
203444
203921
|
const workspaceId = args[1];
|
|
203445
203922
|
if (!workspaceId)
|
|
203446
203923
|
throw new Error("Usage: keryx workspace collaboration <workspace-id>");
|
|
203447
|
-
console.log(JSON.stringify(await createLocalCollaborationService(process.cwd()).overview({ workspaceId, request: undefined, requestCorrelationId:
|
|
203924
|
+
console.log(JSON.stringify(await createLocalCollaborationService(process.cwd()).overview({ workspaceId, request: undefined, requestCorrelationId: randomUUID55() }), null, 2));
|
|
203448
203925
|
return;
|
|
203449
203926
|
}
|
|
203450
203927
|
if (subcommand === "policy-readiness") {
|
|
@@ -203471,7 +203948,7 @@ async function workspaceCommand(args) {
|
|
|
203471
203948
|
const workspaceId = args[1];
|
|
203472
203949
|
const cwd = process.cwd();
|
|
203473
203950
|
const authorizationServer = localWorkspaceAuthorizationServer();
|
|
203474
|
-
const actor = await authorizationServer.actorContextFor(undefined,
|
|
203951
|
+
const actor = await authorizationServer.actorContextFor(undefined, randomUUID55());
|
|
203475
203952
|
if (!actor)
|
|
203476
203953
|
throw new Error("trusted ActorContext is required");
|
|
203477
203954
|
if (workspaceId) {
|
|
@@ -204614,6 +205091,8 @@ var init_forgetting = __esm(() => {
|
|
|
204614
205091
|
});
|
|
204615
205092
|
|
|
204616
205093
|
// src/commands/decisions.ts
|
|
205094
|
+
import { readFile as readFile190 } from "fs/promises";
|
|
205095
|
+
import path373 from "path";
|
|
204617
205096
|
function rejectUnknownFlags2(sub, args, accepted) {
|
|
204618
205097
|
const unknown = args.filter((argument) => argument.startsWith("--")).map((argument) => argument.split("=")[0]).filter((name) => !accepted.includes(name));
|
|
204619
205098
|
if (unknown.length > 0) {
|
|
@@ -204729,8 +205208,33 @@ async function runReason(args) {
|
|
|
204729
205208
|
}
|
|
204730
205209
|
console.log(recorded ? `decision ${id}: reason recorded` : `decision ${id}: the human was already asked once; nothing written`);
|
|
204731
205210
|
}
|
|
205211
|
+
async function runImport(args) {
|
|
205212
|
+
const file = positionalId(args);
|
|
205213
|
+
if (file === undefined)
|
|
205214
|
+
throw new Error("keryx decisions import needs the file: keryx decisions import <file.jsonl> [--dry-run] [--json]");
|
|
205215
|
+
const rest = args.slice(1);
|
|
205216
|
+
rejectUnknownFlags2("import", rest, IMPORT_FLAGS2);
|
|
205217
|
+
let text;
|
|
205218
|
+
try {
|
|
205219
|
+
text = await readFile190(path373.resolve(process.cwd(), file), "utf8");
|
|
205220
|
+
} catch {
|
|
205221
|
+
throw new Error(`cannot read ${file}`);
|
|
205222
|
+
}
|
|
205223
|
+
const result = await importBackfill(process.cwd(), text, { dryRun: rest.includes("--dry-run") });
|
|
205224
|
+
if (rest.includes("--json")) {
|
|
205225
|
+
console.log(JSON.stringify(result, null, 2));
|
|
205226
|
+
return;
|
|
205227
|
+
}
|
|
205228
|
+
console.log(renderImportResult(result));
|
|
205229
|
+
}
|
|
204732
205230
|
async function runReport3(args) {
|
|
204733
205231
|
rejectUnknownFlags2("report", args, REPORT_FLAGS);
|
|
205232
|
+
if (args.includes("--line") && args.includes("--json"))
|
|
205233
|
+
throw new Error("keryx decisions report: --line and --json cannot be combined");
|
|
205234
|
+
if (args.includes("--line")) {
|
|
205235
|
+
console.log(await reportLine(process.cwd()));
|
|
205236
|
+
return;
|
|
205237
|
+
}
|
|
204734
205238
|
if (args.includes("--json")) {
|
|
204735
205239
|
console.log(JSON.stringify(await loadReport(process.cwd()), null, 2));
|
|
204736
205240
|
return;
|
|
@@ -204752,8 +205256,14 @@ async function decisionsCommand(args = []) {
|
|
|
204752
205256
|
return await runReason(args.slice(1));
|
|
204753
205257
|
if (command === "report")
|
|
204754
205258
|
return await runReport3(args.slice(1));
|
|
205259
|
+
if (command === "import")
|
|
205260
|
+
return await runImport(args.slice(1));
|
|
204755
205261
|
} catch (cause) {
|
|
204756
|
-
|
|
205262
|
+
const message = cause instanceof Error ? cause.message : String(cause);
|
|
205263
|
+
if (command === "import" && args.includes("--json"))
|
|
205264
|
+
console.log(JSON.stringify({ error: message }, null, 2));
|
|
205265
|
+
else
|
|
205266
|
+
console.error(message);
|
|
204757
205267
|
process.exitCode = 1;
|
|
204758
205268
|
return;
|
|
204759
205269
|
}
|
|
@@ -204771,7 +205281,8 @@ Usage:
|
|
|
204771
205281
|
keryx decisions open --question "<text>" --option <id>=<label> [--option ...] [--recommend <id> --reason "<why>"] [--stage <name>] [--flow <id>] [--action <tag>] [--json]
|
|
204772
205282
|
keryx decisions answer <id> --choice <id> [--other] [--reason "<why>"] [--json]
|
|
204773
205283
|
keryx decisions reason <id> --text "<why>" [--json]
|
|
204774
|
-
keryx decisions report [--json]
|
|
205284
|
+
keryx decisions report [--json | --line]
|
|
205285
|
+
keryx decisions import <file.jsonl> [--dry-run] [--json]
|
|
204775
205286
|
|
|
204776
205287
|
Every agent question with options leaves one record: what was asked, what the
|
|
204777
205288
|
agent recommended and why, how it was shown, what the human chose and how long
|
|
@@ -204804,6 +205315,28 @@ it took. Call \`open\` BEFORE showing the question and \`answer\` after.
|
|
|
204804
205315
|
its reason. It also counts the questions that looked irreversible
|
|
204805
205316
|
and the ones where blind was refused because of it, per stage: a
|
|
204806
205317
|
high number on ordinary questions means the list over-matches.
|
|
205318
|
+
Backfilled decisions (see import) are reported in a separate block
|
|
205319
|
+
"\u0434\u043E (\u0438\u0441\u0442\u043E\u0440\u0438\u0447\u0435\u0441\u043A\u043E\u0435, \u0434\u043E\u0437\u0430\u043F\u043E\u043B\u043D\u0435\u043D\u043E \u0437\u0430\u0434\u043D\u0438\u043C \u0447\u0438\u0441\u043B\u043E\u043C)" and never counted in
|
|
205320
|
+
the live shares or in the time to answer. --line prints ONE line in
|
|
205321
|
+
Russian for the daily topic message: the total (before, after) and the
|
|
205322
|
+
match share of the visible, the hidden and the historical decisions.
|
|
205323
|
+
import loads historical decisions from a JSON-lines file, one per line:
|
|
205324
|
+
{"id","at","flow","stage","question","options":[{"id","label"}],
|
|
205325
|
+
"recommendation":{"optionId","reason"}|null,"source",
|
|
205326
|
+
"answer":{"choice","other"?}|null,"reason"?}
|
|
205327
|
+
Every one is marked backfilled (its recommendation was written down
|
|
205328
|
+
after the fact), is never blind, and keeps the time it was asked in
|
|
205329
|
+
"at"; its time to answer is unknown and never used. The file is
|
|
205330
|
+
read line by line: a line that is not a decision is skipped, named
|
|
205331
|
+
(line number and why) and counted, and the rest is imported. An id
|
|
205332
|
+
already in the journal is skipped and reported, so the same file can
|
|
205333
|
+
be imported twice; a backfilled decision whose answer is missing from
|
|
205334
|
+
the journal (an interrupted write) gets just that answer on the next
|
|
205335
|
+
import. --dry-run checks and counts without writing. It prints:
|
|
205336
|
+
Imported: N, skipped: S, with recommendation: R, answered: A,
|
|
205337
|
+
deviations: D, plus ", repaired: R" and ", malformed: M" when
|
|
205338
|
+
there are any. With --json a failure is {"error": "..."}. A bare /decisions change never touches a backfilled
|
|
205339
|
+
decision.
|
|
204807
205340
|
|
|
204808
205341
|
The journal is one file per repository, .metaproject/data/decisions/journal.jsonl
|
|
204809
205342
|
under the main checkout (every worktree shares it; it is git-ignored). Inside a
|
|
@@ -204813,14 +205346,15 @@ the answer also adds a line to that flow's journal.md, except for an inferred
|
|
|
204813
205346
|
flow, which only stays in the project-wide journal. A failure here never
|
|
204814
205347
|
stops the question.`);
|
|
204815
205348
|
}
|
|
204816
|
-
var OPEN_FLAGS, ANSWER_FLAGS, REASON_FLAGS, REPORT_FLAGS;
|
|
205349
|
+
var OPEN_FLAGS, ANSWER_FLAGS, REASON_FLAGS, REPORT_FLAGS, IMPORT_FLAGS2;
|
|
204817
205350
|
var init_decisions2 = __esm(() => {
|
|
204818
205351
|
init_args();
|
|
204819
205352
|
init_service13();
|
|
204820
205353
|
OPEN_FLAGS = ["--question", "--option", "--options-json", "--recommend", "--reason", "--stage", "--flow", "--action", "--json"];
|
|
204821
205354
|
ANSWER_FLAGS = ["--choice", "--other", "--reason", "--json"];
|
|
204822
205355
|
REASON_FLAGS = ["--text", "--json"];
|
|
204823
|
-
REPORT_FLAGS = ["--json"];
|
|
205356
|
+
REPORT_FLAGS = ["--json", "--line"];
|
|
205357
|
+
IMPORT_FLAGS2 = ["--dry-run", "--json"];
|
|
204824
205358
|
});
|
|
204825
205359
|
|
|
204826
205360
|
// src/commands/governance.ts
|
|
@@ -205034,7 +205568,7 @@ var init_product = __esm(() => {
|
|
|
205034
205568
|
|
|
205035
205569
|
// src/commands/hooks.ts
|
|
205036
205570
|
import { existsSync as existsSync58, readFileSync as readFileSync32 } from "fs";
|
|
205037
|
-
import
|
|
205571
|
+
import path374 from "path";
|
|
205038
205572
|
function resolveHomeDir(deps) {
|
|
205039
205573
|
return resolveHooksHomeDir(process.env, deps.homeDir);
|
|
205040
205574
|
}
|
|
@@ -205045,10 +205579,10 @@ function optConfigDir(deps) {
|
|
|
205045
205579
|
return deps.configDir !== undefined ? { configDir: deps.configDir } : {};
|
|
205046
205580
|
}
|
|
205047
205581
|
function userHooksPath(homeDir) {
|
|
205048
|
-
return
|
|
205582
|
+
return path374.join(homeDir, ".keryx", "hooks.json");
|
|
205049
205583
|
}
|
|
205050
205584
|
function projectHooksPath(projectRoot) {
|
|
205051
|
-
return
|
|
205585
|
+
return path374.join(projectRoot, ".metaproject", "hooks.json");
|
|
205052
205586
|
}
|
|
205053
205587
|
function fail6(message) {
|
|
205054
205588
|
console.error(message);
|
|
@@ -205166,10 +205700,10 @@ async function runList7(args, deps) {
|
|
|
205166
205700
|
function argv0Resolves(argv0) {
|
|
205167
205701
|
if (argv0 === "keryx")
|
|
205168
205702
|
return true;
|
|
205169
|
-
if (
|
|
205703
|
+
if (path374.isAbsolute(argv0))
|
|
205170
205704
|
return existsSync58(argv0);
|
|
205171
205705
|
const pathEnv = process.env.PATH ?? "";
|
|
205172
|
-
return pathEnv.split(
|
|
205706
|
+
return pathEnv.split(path374.delimiter).filter((dir) => dir.length > 0).some((dir) => existsSync58(path374.join(dir, argv0)));
|
|
205173
205707
|
}
|
|
205174
205708
|
function checkArgvResolutions(registrations) {
|
|
205175
205709
|
const seen = new Set;
|
|
@@ -205623,7 +206157,7 @@ async function writeDocAtomic(filePath, doc, scope, cwd, homeDir) {
|
|
|
205623
206157
|
if (scope === "project") {
|
|
205624
206158
|
await writeContained(cwd, PROJECT_HOOKS_REL, body);
|
|
205625
206159
|
} else {
|
|
205626
|
-
const userConfigDir =
|
|
206160
|
+
const userConfigDir = path374.join(homeDir, ".keryx");
|
|
205627
206161
|
if (!existsSync58(userConfigDir)) {
|
|
205628
206162
|
await mkdirContained(homeDir, ".keryx");
|
|
205629
206163
|
}
|
|
@@ -205938,13 +206472,13 @@ var init_types12 = __esm(() => {
|
|
|
205938
206472
|
});
|
|
205939
206473
|
|
|
205940
206474
|
// src/bundle/paths.ts
|
|
205941
|
-
import { lstat as lstat20, readFile as
|
|
205942
|
-
import
|
|
206475
|
+
import { lstat as lstat20, readFile as readFile191 } from "fs/promises";
|
|
206476
|
+
import path375 from "path";
|
|
205943
206477
|
function scopeRoot(scope, ctx) {
|
|
205944
206478
|
if (scope === "user") {
|
|
205945
206479
|
return userStoreRoot(ctx.env ?? process.env, ctx.homeDir);
|
|
205946
206480
|
}
|
|
205947
|
-
return
|
|
206481
|
+
return path375.join(ctx.projectRoot, ".metaproject");
|
|
205948
206482
|
}
|
|
205949
206483
|
function isPortablePath(relPath) {
|
|
205950
206484
|
return relPath.split("/").every((segment) => PORTABLE_SEGMENT_RE.test(segment));
|
|
@@ -206118,10 +206652,10 @@ async function targetFor(entry, targetScope, ctx) {
|
|
|
206118
206652
|
return { ok: true, absolutePath: containment.absolutePath };
|
|
206119
206653
|
}
|
|
206120
206654
|
async function resolveContainedPathForWrite(root, relPath) {
|
|
206121
|
-
const absolute =
|
|
206122
|
-
const rootResolved =
|
|
206123
|
-
const relative =
|
|
206124
|
-
if (relative === "" || relative === ".." || relative.startsWith(`..${
|
|
206655
|
+
const absolute = path375.resolve(root, relPath);
|
|
206656
|
+
const rootResolved = path375.resolve(root);
|
|
206657
|
+
const relative = path375.relative(rootResolved, absolute);
|
|
206658
|
+
if (relative === "" || relative === ".." || relative.startsWith(`..${path375.sep}`) || path375.isAbsolute(relative)) {
|
|
206125
206659
|
return {
|
|
206126
206660
|
ok: false,
|
|
206127
206661
|
refusal: { reason: BUNDLE_REFUSAL.pathEscape, path: relPath, message: `${relPath} resolves outside the scope root` }
|
|
@@ -206130,7 +206664,7 @@ async function resolveContainedPathForWrite(root, relPath) {
|
|
|
206130
206664
|
return { ok: true, absolutePath: absolute };
|
|
206131
206665
|
}
|
|
206132
206666
|
async function refuseSymlinkChain(root, relPath) {
|
|
206133
|
-
const rootResolved =
|
|
206667
|
+
const rootResolved = path375.resolve(root);
|
|
206134
206668
|
try {
|
|
206135
206669
|
const rootStat = await lstat20(rootResolved);
|
|
206136
206670
|
if (rootStat.isSymbolicLink()) {
|
|
@@ -206143,7 +206677,7 @@ async function refuseSymlinkChain(root, relPath) {
|
|
|
206143
206677
|
const segments = relPath.split("/");
|
|
206144
206678
|
let current = rootResolved;
|
|
206145
206679
|
for (const segment of segments) {
|
|
206146
|
-
current =
|
|
206680
|
+
current = path375.join(current, segment);
|
|
206147
206681
|
try {
|
|
206148
206682
|
const stat = await lstat20(current);
|
|
206149
206683
|
if (stat.isSymbolicLink()) {
|
|
@@ -206158,7 +206692,7 @@ async function refuseSymlinkChain(root, relPath) {
|
|
|
206158
206692
|
}
|
|
206159
206693
|
async function readTargetFile(absolutePath) {
|
|
206160
206694
|
try {
|
|
206161
|
-
const bytes = await
|
|
206695
|
+
const bytes = await readFile191(absolutePath);
|
|
206162
206696
|
return { ok: true, bytes };
|
|
206163
206697
|
} catch (err) {
|
|
206164
206698
|
const code = err.code;
|
|
@@ -206195,8 +206729,8 @@ var init_paths5 = __esm(() => {
|
|
|
206195
206729
|
});
|
|
206196
206730
|
|
|
206197
206731
|
// src/bundle/archive.ts
|
|
206198
|
-
import { readdir as readdir65, readFile as
|
|
206199
|
-
import
|
|
206732
|
+
import { readdir as readdir65, readFile as readFile192, lstat as lstat21 } from "fs/promises";
|
|
206733
|
+
import path376 from "path";
|
|
206200
206734
|
import { gzipSync, gunzipSync } from "zlib";
|
|
206201
206735
|
function resolveLimits(limits) {
|
|
206202
206736
|
const maxTotalBytes = limits?.maxTotalBytes ?? DEFAULT_BUNDLE_LIMITS.maxTotalBytes;
|
|
@@ -206279,11 +206813,11 @@ function buildBundleArchive(files, manifestBytes) {
|
|
|
206279
206813
|
const dirs = new Set;
|
|
206280
206814
|
const sortedPaths = [...files.keys()].sort();
|
|
206281
206815
|
for (const p of sortedPaths) {
|
|
206282
|
-
let dir =
|
|
206816
|
+
let dir = path376.dirname(p);
|
|
206283
206817
|
const segs = [];
|
|
206284
206818
|
while (dir !== "." && dir !== "/" && dir !== "") {
|
|
206285
206819
|
segs.unshift(dir);
|
|
206286
|
-
dir =
|
|
206820
|
+
dir = path376.dirname(dir);
|
|
206287
206821
|
}
|
|
206288
206822
|
for (const d of segs)
|
|
206289
206823
|
dirs.add(d);
|
|
@@ -206351,7 +206885,7 @@ function parseUstar(tar, limits) {
|
|
|
206351
206885
|
const name = prefix.length > 0 ? `${prefix}/${nameRaw}` : nameRaw;
|
|
206352
206886
|
const typeflag = String.fromCharCode(header[156] ?? 0);
|
|
206353
206887
|
const size = readOctal(header, 124, 12);
|
|
206354
|
-
if (
|
|
206888
|
+
if (path376.isAbsolute(name) || name.split("/").includes("..") || name.length === 0) {
|
|
206355
206889
|
return { ok: false, refusal: { reason: BUNDLE_REFUSAL.archiveInvalid, path: name, message: `unsafe entry name: ${name}` } };
|
|
206356
206890
|
}
|
|
206357
206891
|
const isDir = typeflag === "5";
|
|
@@ -206415,7 +206949,7 @@ async function openBundle(bundlePath, limits) {
|
|
|
206415
206949
|
async function walk(dir, relPrefix) {
|
|
206416
206950
|
const entries = await readdir65(dir, { withFileTypes: true });
|
|
206417
206951
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
206418
|
-
const abs =
|
|
206952
|
+
const abs = path376.join(dir, entry.name);
|
|
206419
206953
|
const rel = relPrefix.length > 0 ? `${relPrefix}/${entry.name}` : entry.name;
|
|
206420
206954
|
const entryStat = await lstat21(abs);
|
|
206421
206955
|
if (entryStat.isSymbolicLink()) {
|
|
@@ -206434,7 +206968,7 @@ async function openBundle(bundlePath, limits) {
|
|
|
206434
206968
|
if (entryStat.size > resolved.maxManifestBytes) {
|
|
206435
206969
|
return { reason: BUNDLE_REFUSAL.archiveTooLarge, path: rel, message: `bundle.json is ${entryStat.size} bytes, over the ${resolved.maxManifestBytes}-byte manifest cap` };
|
|
206436
206970
|
}
|
|
206437
|
-
manifestBytes = await
|
|
206971
|
+
manifestBytes = await readFile192(abs);
|
|
206438
206972
|
continue;
|
|
206439
206973
|
}
|
|
206440
206974
|
entryCount += 1;
|
|
@@ -206445,7 +206979,7 @@ async function openBundle(bundlePath, limits) {
|
|
|
206445
206979
|
if (totalBytes > resolved.maxTotalBytes) {
|
|
206446
206980
|
return { reason: BUNDLE_REFUSAL.archiveTooLarge, message: `bundle directory exceeds ${resolved.maxTotalBytes} bytes total` };
|
|
206447
206981
|
}
|
|
206448
|
-
const bytes = await
|
|
206982
|
+
const bytes = await readFile192(abs);
|
|
206449
206983
|
files.set(rel, bytes);
|
|
206450
206984
|
}
|
|
206451
206985
|
return null;
|
|
@@ -206462,7 +206996,7 @@ async function openBundle(bundlePath, limits) {
|
|
|
206462
206996
|
if (stat.size > resolved.maxCompressedBytes) {
|
|
206463
206997
|
return { ok: false, refusal: { reason: BUNDLE_REFUSAL.archiveTooLarge, message: `${bundlePath} is ${stat.size} bytes, over the ${resolved.maxCompressedBytes}-byte compressed-size cap` } };
|
|
206464
206998
|
}
|
|
206465
|
-
const raw = await
|
|
206999
|
+
const raw = await readFile192(bundlePath);
|
|
206466
207000
|
let tar;
|
|
206467
207001
|
try {
|
|
206468
207002
|
tar = gunzipSync(raw, { maxOutputLength: resolved.maxDecompressedBytes });
|
|
@@ -207292,9 +207826,9 @@ var init_learned_pattern_schema = __esm(() => {
|
|
|
207292
207826
|
|
|
207293
207827
|
// src/bundle/export.ts
|
|
207294
207828
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
207295
|
-
import { mkdir as mkdir75, readdir as readdir66, readFile as
|
|
207829
|
+
import { mkdir as mkdir75, readdir as readdir66, readFile as readFile193, writeFile as writeFile52, lstat as lstat22 } from "fs/promises";
|
|
207296
207830
|
import { existsSync as existsSync59 } from "fs";
|
|
207297
|
-
import
|
|
207831
|
+
import path377 from "path";
|
|
207298
207832
|
function globToRegExp5(glob) {
|
|
207299
207833
|
let out = "";
|
|
207300
207834
|
for (let i = 0;i < glob.length; i += 1) {
|
|
@@ -207377,7 +207911,7 @@ async function walkFiles2(dir, relPrefix, out, skipped) {
|
|
|
207377
207911
|
return;
|
|
207378
207912
|
}
|
|
207379
207913
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
207380
|
-
const abs =
|
|
207914
|
+
const abs = path377.join(dir, entry.name);
|
|
207381
207915
|
const rel = relPrefix.length > 0 ? `${relPrefix}/${entry.name}` : entry.name;
|
|
207382
207916
|
const st = await lstat22(abs);
|
|
207383
207917
|
if (st.isSymbolicLink()) {
|
|
@@ -207394,7 +207928,7 @@ async function walkFiles2(dir, relPrefix, out, skipped) {
|
|
|
207394
207928
|
async function collectSkills(root, scope, skipped) {
|
|
207395
207929
|
const candidates = [];
|
|
207396
207930
|
for (const baseDirName of scope === "project" ? ["skills", "project-skills"] : ["skills"]) {
|
|
207397
|
-
const base =
|
|
207931
|
+
const base = path377.join(root, baseDirName);
|
|
207398
207932
|
if (!existsSync59(base))
|
|
207399
207933
|
continue;
|
|
207400
207934
|
const files = [];
|
|
@@ -207407,7 +207941,7 @@ async function collectSkills(root, scope, skipped) {
|
|
|
207407
207941
|
async function collectRules(root, scope, skipped) {
|
|
207408
207942
|
if (scope === "user")
|
|
207409
207943
|
return [];
|
|
207410
|
-
const base =
|
|
207944
|
+
const base = path377.join(root, "rules");
|
|
207411
207945
|
if (!existsSync59(base))
|
|
207412
207946
|
return [];
|
|
207413
207947
|
const files = [];
|
|
@@ -207415,7 +207949,7 @@ async function collectRules(root, scope, skipped) {
|
|
|
207415
207949
|
return files.filter((f) => /\.(md|mdc)$/.test(f.path)).map((f) => ({ bundlePath: f.path, kind: "rule", absolutePath: f.abs }));
|
|
207416
207950
|
}
|
|
207417
207951
|
async function collectAgents(root, skipped) {
|
|
207418
|
-
const base =
|
|
207952
|
+
const base = path377.join(root, "agents");
|
|
207419
207953
|
if (!existsSync59(base))
|
|
207420
207954
|
return [];
|
|
207421
207955
|
let entries;
|
|
@@ -207426,7 +207960,7 @@ async function collectAgents(root, skipped) {
|
|
|
207426
207960
|
}
|
|
207427
207961
|
const candidates = [];
|
|
207428
207962
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
207429
|
-
const abs =
|
|
207963
|
+
const abs = path377.join(base, entry.name);
|
|
207430
207964
|
const st = await lstat22(abs);
|
|
207431
207965
|
if (st.isSymbolicLink()) {
|
|
207432
207966
|
skipped.push({ path: `agents/${entry.name}`, reason: "symlink" });
|
|
@@ -207441,7 +207975,7 @@ async function collectAgents(root, skipped) {
|
|
|
207441
207975
|
async function collectMemory(root, skipped) {
|
|
207442
207976
|
const candidates = [];
|
|
207443
207977
|
for (const { folder } of MEMORY_TYPES) {
|
|
207444
|
-
const base =
|
|
207978
|
+
const base = path377.join(root, "memory", folder);
|
|
207445
207979
|
if (!existsSync59(base))
|
|
207446
207980
|
continue;
|
|
207447
207981
|
let entries;
|
|
@@ -207451,7 +207985,7 @@ async function collectMemory(root, skipped) {
|
|
|
207451
207985
|
continue;
|
|
207452
207986
|
}
|
|
207453
207987
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
207454
|
-
const abs =
|
|
207988
|
+
const abs = path377.join(base, entry.name);
|
|
207455
207989
|
const st = await lstat22(abs);
|
|
207456
207990
|
if (st.isSymbolicLink()) {
|
|
207457
207991
|
skipped.push({ path: `memory/${folder}/${entry.name}`, reason: "symlink" });
|
|
@@ -207465,7 +207999,7 @@ async function collectMemory(root, skipped) {
|
|
|
207465
207999
|
return candidates;
|
|
207466
208000
|
}
|
|
207467
208001
|
async function collectHookConfig(root) {
|
|
207468
|
-
const abs =
|
|
208002
|
+
const abs = path377.join(root, "hooks.json");
|
|
207469
208003
|
if (!existsSync59(abs))
|
|
207470
208004
|
return [];
|
|
207471
208005
|
const st = await lstat22(abs);
|
|
@@ -207475,7 +208009,7 @@ async function collectHookConfig(root) {
|
|
|
207475
208009
|
}
|
|
207476
208010
|
async function collectLearnedPatterns(root, scope) {
|
|
207477
208011
|
const relDir = scope === "user" ? "learning/patterns" : "data/learning/candidates";
|
|
207478
|
-
const base =
|
|
208012
|
+
const base = path377.join(root, ...relDir.split("/"));
|
|
207479
208013
|
if (!existsSync59(base))
|
|
207480
208014
|
return [];
|
|
207481
208015
|
let entries;
|
|
@@ -207487,7 +208021,7 @@ async function collectLearnedPatterns(root, scope) {
|
|
|
207487
208021
|
const candidates = [];
|
|
207488
208022
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
207489
208023
|
if (entry.isFile() && entry.name.endsWith(".json")) {
|
|
207490
|
-
candidates.push({ bundlePath: `${relDir}/${entry.name}`, kind: "learned-pattern", absolutePath:
|
|
208024
|
+
candidates.push({ bundlePath: `${relDir}/${entry.name}`, kind: "learned-pattern", absolutePath: path377.join(base, entry.name) });
|
|
207491
208025
|
}
|
|
207492
208026
|
}
|
|
207493
208027
|
return candidates;
|
|
@@ -207528,10 +208062,10 @@ async function outDirIsEmpty(out) {
|
|
|
207528
208062
|
}
|
|
207529
208063
|
async function writeDirectoryBundle(out, manifestBytes, files) {
|
|
207530
208064
|
await mkdir75(out, { recursive: true });
|
|
207531
|
-
await writeFile52(
|
|
208065
|
+
await writeFile52(path377.join(out, "bundle.json"), manifestBytes);
|
|
207532
208066
|
for (const [rel, bytes] of files) {
|
|
207533
|
-
const abs =
|
|
207534
|
-
await mkdir75(
|
|
208067
|
+
const abs = path377.join(out, ...rel.split("/"));
|
|
208068
|
+
await mkdir75(path377.dirname(abs), { recursive: true });
|
|
207535
208069
|
await writeFile52(abs, bytes);
|
|
207536
208070
|
}
|
|
207537
208071
|
}
|
|
@@ -207563,7 +208097,7 @@ async function exportBundle(opts) {
|
|
|
207563
208097
|
} else {
|
|
207564
208098
|
const rawDigestEntries = [];
|
|
207565
208099
|
for (const candidate of filtered) {
|
|
207566
|
-
const bytes = await
|
|
208100
|
+
const bytes = await readFile193(candidate.absolutePath);
|
|
207567
208101
|
rawDigestEntries.push({ path: candidate.bundlePath, sha256: sha256Hex5(bytes) });
|
|
207568
208102
|
}
|
|
207569
208103
|
bundleId = contentDigestBundleId(opts.scope, rawDigestEntries);
|
|
@@ -207578,7 +208112,7 @@ async function exportBundle(opts) {
|
|
|
207578
208112
|
skipped.push({ path: candidate.bundlePath, reason: `non-portable-name: ${portable.refusal.message}` });
|
|
207579
208113
|
continue;
|
|
207580
208114
|
}
|
|
207581
|
-
let bytes = await
|
|
208115
|
+
let bytes = await readFile193(candidate.absolutePath);
|
|
207582
208116
|
if (candidate.kind === "hook-config") {
|
|
207583
208117
|
let parsed;
|
|
207584
208118
|
try {
|
|
@@ -207665,7 +208199,7 @@ async function exportBundle(opts) {
|
|
|
207665
208199
|
const archive = buildBundleArchive(files, manifestBytes);
|
|
207666
208200
|
if (!archive.ok)
|
|
207667
208201
|
return { ok: false, refusals: [archive.refusal] };
|
|
207668
|
-
await mkdir75(
|
|
208202
|
+
await mkdir75(path377.dirname(opts.out), { recursive: true });
|
|
207669
208203
|
await writeFile52(opts.out, archive.value);
|
|
207670
208204
|
} else {
|
|
207671
208205
|
if (existsSync59(opts.out) && !await outDirIsEmpty(opts.out)) {
|
|
@@ -207731,16 +208265,16 @@ var init_verify3 = __esm(() => {
|
|
|
207731
208265
|
});
|
|
207732
208266
|
|
|
207733
208267
|
// src/bundle/applied-state.ts
|
|
207734
|
-
import { readFile as
|
|
207735
|
-
import
|
|
208268
|
+
import { readFile as readFile194 } from "fs/promises";
|
|
208269
|
+
import path378 from "path";
|
|
207736
208270
|
function emptyState2() {
|
|
207737
208271
|
return { schemaVersion: APPLIED_STATE_SCHEMA_VERSION, entries: {} };
|
|
207738
208272
|
}
|
|
207739
208273
|
function appliedStatePath(scope, ctx) {
|
|
207740
208274
|
if (scope === "user") {
|
|
207741
|
-
return
|
|
208275
|
+
return path378.join(scopeRoot("user", ctx), "bundles", "applied-state.json");
|
|
207742
208276
|
}
|
|
207743
|
-
return
|
|
208277
|
+
return path378.join(scopeRoot(scope, ctx), "data", "bundles", "applied-state.json");
|
|
207744
208278
|
}
|
|
207745
208279
|
function isPlainEntryShape(value) {
|
|
207746
208280
|
if (typeof value !== "object" || value === null)
|
|
@@ -207799,7 +208333,7 @@ function migrateV1(v1) {
|
|
|
207799
208333
|
async function readAppliedState(ledgerPath) {
|
|
207800
208334
|
let raw;
|
|
207801
208335
|
try {
|
|
207802
|
-
raw = await
|
|
208336
|
+
raw = await readFile194(ledgerPath, "utf8");
|
|
207803
208337
|
} catch (err) {
|
|
207804
208338
|
const code = err.code;
|
|
207805
208339
|
if (code === "ENOENT") {
|
|
@@ -207822,14 +208356,14 @@ async function readAppliedState(ledgerPath) {
|
|
|
207822
208356
|
return { ok: false, reason: "corrupt-ledger", message: `applied-state ledger at ${ledgerPath} has an unrecognized shape` };
|
|
207823
208357
|
}
|
|
207824
208358
|
function containedRootAndRel(ledgerPath) {
|
|
207825
|
-
const marker = `${
|
|
208359
|
+
const marker = `${path378.sep}.metaproject${path378.sep}`;
|
|
207826
208360
|
const idx = ledgerPath.indexOf(marker);
|
|
207827
208361
|
if (idx >= 0) {
|
|
207828
|
-
return { root: ledgerPath.slice(0, idx), rel: ledgerPath.slice(idx +
|
|
208362
|
+
return { root: ledgerPath.slice(0, idx), rel: ledgerPath.slice(idx + path378.sep.length).split(path378.sep).join("/") };
|
|
207829
208363
|
}
|
|
207830
|
-
const bundlesDir =
|
|
207831
|
-
const root =
|
|
207832
|
-
const rel =
|
|
208364
|
+
const bundlesDir = path378.dirname(ledgerPath);
|
|
208365
|
+
const root = path378.dirname(bundlesDir);
|
|
208366
|
+
const rel = path378.join(path378.basename(bundlesDir), path378.basename(ledgerPath)).split(path378.sep).join("/");
|
|
207833
208367
|
return { root, rel };
|
|
207834
208368
|
}
|
|
207835
208369
|
async function writeAppliedState(ledgerPath, state) {
|
|
@@ -207849,14 +208383,14 @@ var init_applied_state = __esm(() => {
|
|
|
207849
208383
|
});
|
|
207850
208384
|
|
|
207851
208385
|
// src/lib/private-dir.ts
|
|
207852
|
-
import { lstat as lstat23, mkdir as mkdir76, open as
|
|
207853
|
-
import
|
|
208386
|
+
import { lstat as lstat23, mkdir as mkdir76, open as open11, readFile as readFile195 } from "fs/promises";
|
|
208387
|
+
import path379 from "path";
|
|
207854
208388
|
async function checkPrivateDirGitignore(dir, root) {
|
|
207855
208389
|
if (root !== undefined) {
|
|
207856
|
-
const rootResolved =
|
|
207857
|
-
const dirResolved =
|
|
207858
|
-
const relative =
|
|
207859
|
-
const relativePosix = relative.split(
|
|
208390
|
+
const rootResolved = path379.resolve(root);
|
|
208391
|
+
const dirResolved = path379.resolve(dir);
|
|
208392
|
+
const relative = path379.relative(rootResolved, dirResolved);
|
|
208393
|
+
const relativePosix = relative.split(path379.sep).join("/");
|
|
207860
208394
|
const refusal = await refuseEscapingSymlink(rootResolved, relativePosix);
|
|
207861
208395
|
if (refusal !== undefined) {
|
|
207862
208396
|
return {
|
|
@@ -207886,7 +208420,7 @@ async function checkPrivateDirGitignore(dir, root) {
|
|
|
207886
208420
|
message: `${dir} is a symlink; keryx will not manage a private directory reached through a symlink.`
|
|
207887
208421
|
};
|
|
207888
208422
|
}
|
|
207889
|
-
const gitignorePath =
|
|
208423
|
+
const gitignorePath = path379.join(dir, ".gitignore");
|
|
207890
208424
|
let stats;
|
|
207891
208425
|
try {
|
|
207892
208426
|
stats = await lstat23(gitignorePath);
|
|
@@ -207916,7 +208450,7 @@ async function checkPrivateDirGitignore(dir, root) {
|
|
|
207916
208450
|
}
|
|
207917
208451
|
let bytes;
|
|
207918
208452
|
try {
|
|
207919
|
-
bytes = await
|
|
208453
|
+
bytes = await readFile195(gitignorePath);
|
|
207920
208454
|
} catch (error) {
|
|
207921
208455
|
return {
|
|
207922
208456
|
ok: false,
|
|
@@ -207938,10 +208472,10 @@ async function ensurePrivateDirGitignore(dir, root) {
|
|
|
207938
208472
|
if (!check.ok || check.action === "present") {
|
|
207939
208473
|
return check;
|
|
207940
208474
|
}
|
|
207941
|
-
const gitignorePath =
|
|
208475
|
+
const gitignorePath = path379.join(dir, ".gitignore");
|
|
207942
208476
|
await mkdir76(dir, { recursive: true });
|
|
207943
208477
|
try {
|
|
207944
|
-
const handle = await
|
|
208478
|
+
const handle = await open11(gitignorePath, "wx");
|
|
207945
208479
|
try {
|
|
207946
208480
|
await handle.writeFile(PRIVATE_DIR_GITIGNORE, "utf8");
|
|
207947
208481
|
} finally {
|
|
@@ -208354,9 +208888,9 @@ var init_plan2 = __esm(() => {
|
|
|
208354
208888
|
});
|
|
208355
208889
|
|
|
208356
208890
|
// src/bundle/audit.ts
|
|
208357
|
-
import { mkdtemp as mkdtemp9, mkdir as mkdir77, rm as
|
|
208891
|
+
import { mkdtemp as mkdtemp9, mkdir as mkdir77, rm as rm24, writeFile as writeFile53 } from "fs/promises";
|
|
208358
208892
|
import { tmpdir as tmpdir16 } from "os";
|
|
208359
|
-
import
|
|
208893
|
+
import path380 from "path";
|
|
208360
208894
|
function entriesToStage(plan) {
|
|
208361
208895
|
return plan.entries.filter((e) => e.bucket === "new" || e.bucket === "update" || e.bucket === "conflict" && e.forced);
|
|
208362
208896
|
}
|
|
@@ -208366,12 +208900,12 @@ async function auditBundlePlan(plan, opts = {}) {
|
|
|
208366
208900
|
return { ok: true, refusals: [], report: null };
|
|
208367
208901
|
}
|
|
208368
208902
|
const runAudit = opts.runAudit ?? runHarnessAudit;
|
|
208369
|
-
const stagingDir = await mkdtemp9(
|
|
208903
|
+
const stagingDir = await mkdtemp9(path380.join(tmpdir16(), "keryx-bundle-audit-"));
|
|
208370
208904
|
try {
|
|
208371
208905
|
try {
|
|
208372
208906
|
for (const entry of toStage) {
|
|
208373
|
-
const abs =
|
|
208374
|
-
await mkdir77(
|
|
208907
|
+
const abs = path380.join(stagingDir, ...entry.path.split("/"));
|
|
208908
|
+
await mkdir77(path380.dirname(abs), { recursive: true });
|
|
208375
208909
|
await writeFile53(abs, entry.bytes);
|
|
208376
208910
|
}
|
|
208377
208911
|
} catch (err) {
|
|
@@ -208396,7 +208930,7 @@ async function auditBundlePlan(plan, opts = {}) {
|
|
|
208396
208930
|
}
|
|
208397
208931
|
return { ok: refusals.length === 0, refusals, report };
|
|
208398
208932
|
} finally {
|
|
208399
|
-
await
|
|
208933
|
+
await rm24(stagingDir, { recursive: true, force: true });
|
|
208400
208934
|
}
|
|
208401
208935
|
}
|
|
208402
208936
|
var init_audit = __esm(() => {
|
|
@@ -208405,8 +208939,8 @@ var init_audit = __esm(() => {
|
|
|
208405
208939
|
});
|
|
208406
208940
|
|
|
208407
208941
|
// src/bundle/apply.ts
|
|
208408
|
-
import { mkdir as mkdir78, rmdir as rmdir2, stat as
|
|
208409
|
-
import
|
|
208942
|
+
import { mkdir as mkdir78, rmdir as rmdir2, stat as stat38 } from "fs/promises";
|
|
208943
|
+
import path381 from "path";
|
|
208410
208944
|
function writableEntries(plan) {
|
|
208411
208945
|
return plan.entries.filter((e) => e.bucket === "new" || e.bucket === "update" || e.bucket === "conflict" && e.forced);
|
|
208412
208946
|
}
|
|
@@ -208477,7 +209011,7 @@ async function applyBundlePlan(plan, auditResult, opts = {}) {
|
|
|
208477
209011
|
throw new ApplyAbort({ ...previousFile.refusal, path: entry.path });
|
|
208478
209012
|
}
|
|
208479
209013
|
const previousBytes = previousFile.bytes ?? null;
|
|
208480
|
-
const createdDirs = await mkdirRecordingCreated(
|
|
209014
|
+
const createdDirs = await mkdirRecordingCreated(path381.dirname(entry.targetPath));
|
|
208481
209015
|
for (const dir of [...createdDirs].reverse())
|
|
208482
209016
|
rollback.push({ kind: "dir", absolutePath: dir });
|
|
208483
209017
|
rollback.push({ kind: "file", root, rel: entry.targetRelative, previousBytes });
|
|
@@ -208560,14 +209094,14 @@ async function applyBundlePlan(plan, auditResult, opts = {}) {
|
|
|
208560
209094
|
}
|
|
208561
209095
|
async function mkdirRecordingCreated(dir) {
|
|
208562
209096
|
const missing = [];
|
|
208563
|
-
let current =
|
|
209097
|
+
let current = path381.resolve(dir);
|
|
208564
209098
|
for (;; ) {
|
|
208565
209099
|
try {
|
|
208566
|
-
await
|
|
209100
|
+
await stat38(current);
|
|
208567
209101
|
break;
|
|
208568
209102
|
} catch {
|
|
208569
209103
|
missing.push(current);
|
|
208570
|
-
const parent =
|
|
209104
|
+
const parent = path381.dirname(current);
|
|
208571
209105
|
if (parent === current)
|
|
208572
209106
|
break;
|
|
208573
209107
|
current = parent;
|
|
@@ -208582,9 +209116,9 @@ function resolveLedgerPathForEntry(entry, opts) {
|
|
|
208582
209116
|
if (entry.targetScope === "user") {
|
|
208583
209117
|
return userStorePaths(opts.env ?? process.env, opts.homeDir).appliedState;
|
|
208584
209118
|
}
|
|
208585
|
-
const metaprojectIdx = entry.targetPath.indexOf(`${
|
|
208586
|
-
const metaprojectRoot = metaprojectIdx === -1 ?
|
|
208587
|
-
return
|
|
209119
|
+
const metaprojectIdx = entry.targetPath.indexOf(`${path381.sep}.metaproject${path381.sep}`);
|
|
209120
|
+
const metaprojectRoot = metaprojectIdx === -1 ? path381.join(path381.dirname(entry.targetPath), ".metaproject") : entry.targetPath.slice(0, metaprojectIdx + `${path381.sep}.metaproject`.length);
|
|
209121
|
+
return path381.join(metaprojectRoot, "data", "bundles", "applied-state.json");
|
|
208588
209122
|
}
|
|
208589
209123
|
var ApplyAbort;
|
|
208590
209124
|
var init_apply4 = __esm(() => {
|
|
@@ -208660,26 +209194,26 @@ var init_inspect = __esm(() => {
|
|
|
208660
209194
|
});
|
|
208661
209195
|
|
|
208662
209196
|
// src/bundle/uninstall.ts
|
|
208663
|
-
import
|
|
209197
|
+
import path382 from "path";
|
|
208664
209198
|
function isContained(root, candidate) {
|
|
208665
|
-
const rel =
|
|
208666
|
-
return rel === "" || !rel.startsWith(`..${
|
|
209199
|
+
const rel = path382.relative(root, candidate);
|
|
209200
|
+
return rel === "" || !rel.startsWith(`..${path382.sep}`) && rel !== ".." && !path382.isAbsolute(rel);
|
|
208667
209201
|
}
|
|
208668
209202
|
async function removeNowEmptyParents(root, relFilePath) {
|
|
208669
|
-
let relDir =
|
|
209203
|
+
let relDir = path382.posix.dirname(relFilePath);
|
|
208670
209204
|
while (relDir !== "." && relDir !== "/" && relDir !== "") {
|
|
208671
209205
|
if (PROTECTED_KIND_ROOTS.has(relDir))
|
|
208672
209206
|
break;
|
|
208673
209207
|
const removed = await rmdirIfEmptyContained(root, relDir).catch(() => false);
|
|
208674
209208
|
if (!removed)
|
|
208675
209209
|
break;
|
|
208676
|
-
relDir =
|
|
209210
|
+
relDir = path382.posix.dirname(relDir);
|
|
208677
209211
|
}
|
|
208678
209212
|
}
|
|
208679
209213
|
async function uninstallBundle(opts) {
|
|
208680
209214
|
const ctx = { projectRoot: opts.projectRoot, env: opts.env, homeDir: opts.homeDir };
|
|
208681
209215
|
const root = scopeRoot(opts.targetScope, ctx);
|
|
208682
|
-
const rootResolved =
|
|
209216
|
+
const rootResolved = path382.resolve(root);
|
|
208683
209217
|
const ledgerPath = appliedStatePath(opts.targetScope, ctx);
|
|
208684
209218
|
const ledgerRead = await readAppliedState(ledgerPath);
|
|
208685
209219
|
if (!ledgerRead.ok) {
|
|
@@ -208719,7 +209253,7 @@ async function uninstallBundle(opts) {
|
|
|
208719
209253
|
if (!kindCheck.ok) {
|
|
208720
209254
|
return { ok: false, refusals: [{ reason: BUNDLE_REFUSAL.corruptLedger, path: relPath, message: `applied-state ledger record "${relPath}" does not match its recorded kind "${record.kind}": ${kindCheck.refusal.message}` }], removed: [], kept: [], missing: [] };
|
|
208721
209255
|
}
|
|
208722
|
-
const absolute =
|
|
209256
|
+
const absolute = path382.resolve(rootResolved, normalized.path);
|
|
208723
209257
|
if (!isContained(rootResolved, absolute)) {
|
|
208724
209258
|
return { ok: false, refusals: [{ reason: BUNDLE_REFUSAL.corruptLedger, path: relPath, message: `applied-state ledger record "${relPath}" resolves outside the scope root` }], removed: [], kept: [], missing: [] };
|
|
208725
209259
|
}
|
|
@@ -208798,7 +209332,7 @@ var init_service20 = __esm(() => {
|
|
|
208798
209332
|
});
|
|
208799
209333
|
|
|
208800
209334
|
// src/commands/bundle.ts
|
|
208801
|
-
import
|
|
209335
|
+
import path383 from "path";
|
|
208802
209336
|
async function bundleCommand(args, cwd = process.cwd()) {
|
|
208803
209337
|
const sub = args[0];
|
|
208804
209338
|
if (sub === undefined || sub === "--help" || sub === "-h") {
|
|
@@ -208931,7 +209465,7 @@ async function handleExport(args, cwd) {
|
|
|
208931
209465
|
const outcome = await exportBundle({
|
|
208932
209466
|
projectRoot,
|
|
208933
209467
|
scope: scopeArg,
|
|
208934
|
-
out:
|
|
209468
|
+
out: path383.resolve(cwd, out),
|
|
208935
209469
|
include: include.length > 0 ? include : undefined,
|
|
208936
209470
|
kinds: kindsRaw.length > 0 ? kindsRaw : undefined,
|
|
208937
209471
|
bundleId,
|
|
@@ -208976,7 +209510,7 @@ async function handleImport(args, cwd) {
|
|
|
208976
209510
|
}
|
|
208977
209511
|
const projectRoot = resolveBundleProjectRoot(cwd);
|
|
208978
209512
|
if (external) {
|
|
208979
|
-
await handleImportExternal(
|
|
209513
|
+
await handleImportExternal(path383.resolve(cwd, target), projectRoot, { dryRun, json });
|
|
208980
209514
|
return;
|
|
208981
209515
|
}
|
|
208982
209516
|
const targetScopeArg = optionValue([...args], "--target-scope");
|
|
@@ -209003,7 +209537,7 @@ async function handleImport(args, cwd) {
|
|
|
209003
209537
|
return;
|
|
209004
209538
|
}
|
|
209005
209539
|
}
|
|
209006
|
-
const opened = await openBundle(
|
|
209540
|
+
const opened = await openBundle(path383.resolve(cwd, target));
|
|
209007
209541
|
if (!opened.ok) {
|
|
209008
209542
|
printRefusals([opened.refusal], json);
|
|
209009
209543
|
process.exitCode = 1;
|
|
@@ -209181,7 +209715,7 @@ async function handleInspect(args, cwd) {
|
|
|
209181
209715
|
return;
|
|
209182
209716
|
}
|
|
209183
209717
|
const projectRoot = resolveBundleProjectRoot(cwd);
|
|
209184
|
-
const result = await inspectBundle(
|
|
209718
|
+
const result = await inspectBundle(path383.resolve(cwd, bundlePath), {
|
|
209185
209719
|
projectRoot,
|
|
209186
209720
|
targetScope: targetScopeArg
|
|
209187
209721
|
});
|
|
@@ -209225,7 +209759,7 @@ async function handleVerify(args, cwd) {
|
|
|
209225
209759
|
failUsage("keryx bundle verify requires a <bundle> argument (or --external-imports)");
|
|
209226
209760
|
return;
|
|
209227
209761
|
}
|
|
209228
|
-
const outcome = await verifyBundlePath(
|
|
209762
|
+
const outcome = await verifyBundlePath(path383.resolve(cwd, bundlePath));
|
|
209229
209763
|
if (!outcome.ok) {
|
|
209230
209764
|
printRefusals(outcome.refusals, json);
|
|
209231
209765
|
process.exitCode = 1;
|
|
@@ -209368,23 +209902,23 @@ var init_bundle = __esm(() => {
|
|
|
209368
209902
|
|
|
209369
209903
|
// src/commands/learn.ts
|
|
209370
209904
|
import { existsSync as existsSync60 } from "fs";
|
|
209371
|
-
import { readFile as
|
|
209905
|
+
import { readFile as readFile196 } from "fs/promises";
|
|
209372
209906
|
import { createInterface as createInterface4 } from "readline/promises";
|
|
209373
|
-
import
|
|
209907
|
+
import path384 from "path";
|
|
209374
209908
|
function resolveRoot2(deps) {
|
|
209375
209909
|
return resolveProjectRoot2(deps.cwd ?? process.cwd());
|
|
209376
209910
|
}
|
|
209377
209911
|
function resolveLearnRoot(startDir, env) {
|
|
209378
|
-
const hasMetaproject = (dir) => existsSync60(
|
|
209912
|
+
const hasMetaproject = (dir) => existsSync60(path384.join(dir, ".metaproject"));
|
|
209379
209913
|
const fromEnv = env.CLAUDE_PROJECT_DIR;
|
|
209380
209914
|
if (typeof fromEnv === "string" && fromEnv.length > 0 && hasMetaproject(fromEnv)) {
|
|
209381
209915
|
return fromEnv;
|
|
209382
209916
|
}
|
|
209383
|
-
let current =
|
|
209917
|
+
let current = path384.resolve(startDir);
|
|
209384
209918
|
for (;; ) {
|
|
209385
209919
|
if (hasMetaproject(current))
|
|
209386
209920
|
return current;
|
|
209387
|
-
const parent =
|
|
209921
|
+
const parent = path384.dirname(current);
|
|
209388
209922
|
if (parent === current)
|
|
209389
209923
|
return;
|
|
209390
209924
|
current = parent;
|
|
@@ -209480,7 +210014,7 @@ async function runObserveHook(deps) {
|
|
|
209480
210014
|
}
|
|
209481
210015
|
async function countObservationLines(filePath) {
|
|
209482
210016
|
try {
|
|
209483
|
-
const raw = await
|
|
210017
|
+
const raw = await readFile196(filePath, "utf8");
|
|
209484
210018
|
return raw.split(`
|
|
209485
210019
|
`).filter((line) => line.length > 0).length;
|
|
209486
210020
|
} catch {
|
|
@@ -210217,7 +210751,7 @@ var init_group_subcommands = __esm(() => {
|
|
|
210217
210751
|
["trigger", ["run", "install", "uninstall", "list", "status", "schedule", "resolve"]],
|
|
210218
210752
|
["schedule", ["add", "list", "show", "pause", "resume", "run", "remove"]],
|
|
210219
210753
|
["governance", ["report", "show"]],
|
|
210220
|
-
["decisions", ["open", "answer", "reason", "report"]],
|
|
210754
|
+
["decisions", ["open", "answer", "reason", "report", "import"]],
|
|
210221
210755
|
["product", ["index", "open"]],
|
|
210222
210756
|
["hooks", ["list", "validate", "test", "enable", "disable", "trust", "untrust"]],
|
|
210223
210757
|
["bundle", ["export", "import", "inspect", "verify", "uninstall"]],
|
|
@@ -210521,9 +211055,11 @@ var VERSION3, CLI_ROUTES, MCP_KNOWN_SUBCOMMANDS, USAGE_BODY = `Usage:
|
|
|
210521
211055
|
Spend, confirmations, signatures and gate outcomes,
|
|
210522
211056
|
unified across flows; writes latest.md/latest.json
|
|
210523
211057
|
keryx governance show [--json] Reprint the most recently written governance report
|
|
210524
|
-
keryx decisions open|answer|reason|report
|
|
211058
|
+
keryx decisions open|answer|reason|report [--json|--line]|import <file.jsonl> [--dry-run] [--json]
|
|
211059
|
+
Recommendation journal: record a question with options and its
|
|
210525
211060
|
recommendation before showing it, the human's choice after;
|
|
210526
|
-
report = match share by mode and stage, deviations (no model)
|
|
211061
|
+
report = match share by mode and stage, deviations (no model);
|
|
211062
|
+
import = earlier decisions from a JSON-lines file, kept apart
|
|
210527
211063
|
keryx product index [--json] Read every flow and requirements package into a disposable intent index; reports entries with no stated intent
|
|
210528
211064
|
keryx product open [--json] Intents closed in code with no recorded look back, each with its outcome criterion
|
|
210529
211065
|
keryx hooks list [--json] Resolved keryx shell lifecycle hooks (built-in -> user -> project)
|