@mrciphersmith/keryx 0.3.15 → 0.3.17
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 +1535 -880
- package/dist/core.js +50 -8
- package/package.json +1 -1
- package/src/gdgraph/service.ts +7 -0
package/dist/cli.js
CHANGED
|
@@ -5275,10 +5275,14 @@ function configuredProviders(env = process.env, dir) {
|
|
|
5275
5275
|
}
|
|
5276
5276
|
async function providersCommand(args, deps = {}) {
|
|
5277
5277
|
const command = args[0];
|
|
5278
|
-
if (
|
|
5278
|
+
if (command === "--help" || command === "-h") {
|
|
5279
5279
|
printProvidersHelp();
|
|
5280
5280
|
return;
|
|
5281
5281
|
}
|
|
5282
|
+
if (!command) {
|
|
5283
|
+
await runProvidersStatus([], deps);
|
|
5284
|
+
return;
|
|
5285
|
+
}
|
|
5282
5286
|
if (command === "list") {
|
|
5283
5287
|
runProvidersList(args.slice(1));
|
|
5284
5288
|
return;
|
|
@@ -17637,7 +17641,7 @@ var package_default;
|
|
|
17637
17641
|
var init_package = __esm(() => {
|
|
17638
17642
|
package_default = {
|
|
17639
17643
|
name: "@mrciphersmith/keryx",
|
|
17640
|
-
version: "0.3.
|
|
17644
|
+
version: "0.3.17",
|
|
17641
17645
|
description: "Version-controlled project context for AI coding agents: code graph, architecture wiki, project memory, relevant tests, quality signals, and task flows.",
|
|
17642
17646
|
private: false,
|
|
17643
17647
|
publishConfig: {
|
|
@@ -34739,6 +34743,23 @@ function tokenize(text) {
|
|
|
34739
34743
|
function tokenSet(text) {
|
|
34740
34744
|
return new Set(tokenize(text));
|
|
34741
34745
|
}
|
|
34746
|
+
function stem(token) {
|
|
34747
|
+
let base = token;
|
|
34748
|
+
if (base.length >= 6 && base.endsWith("ies")) {
|
|
34749
|
+
base = `${base.slice(0, -3)}y`;
|
|
34750
|
+
} else {
|
|
34751
|
+
for (const suffix of ["ing", "edly", "ed", "es", "s"]) {
|
|
34752
|
+
if (base.length - suffix.length >= 3 && base.endsWith(suffix)) {
|
|
34753
|
+
base = base.slice(0, base.length - suffix.length);
|
|
34754
|
+
break;
|
|
34755
|
+
}
|
|
34756
|
+
}
|
|
34757
|
+
}
|
|
34758
|
+
if (base.length >= 4 && base.endsWith("e")) {
|
|
34759
|
+
base = base.slice(0, -1);
|
|
34760
|
+
}
|
|
34761
|
+
return base;
|
|
34762
|
+
}
|
|
34742
34763
|
function jaccard(a, b) {
|
|
34743
34764
|
if (a.size === 0 || b.size === 0) {
|
|
34744
34765
|
return 0;
|
|
@@ -35296,7 +35317,7 @@ var init_ingest = __esm(() => {
|
|
|
35296
35317
|
function searchEntries(entries, query, filters, config, now) {
|
|
35297
35318
|
validateQuery(query);
|
|
35298
35319
|
validateSearchFilters(filters, now);
|
|
35299
|
-
const queryTokens = [...new Set(tokenize(query))];
|
|
35320
|
+
const queryTokens = [...new Set(tokenize(query).map(stem))];
|
|
35300
35321
|
const today = now.toISOString().slice(0, 10);
|
|
35301
35322
|
const filtered = entries.filter((entry) => matchesFilters(entry, filters) && classMatch(entry, filters.class) && temporalMatch(entry, filters.asOf ?? null, config, today, Boolean(filters.status)));
|
|
35302
35323
|
const scored = filtered.map((entry) => scoreEntry(entry, queryTokens, filters, config, now));
|
|
@@ -35305,7 +35326,7 @@ function searchEntries(entries, query, filters, config, now) {
|
|
|
35305
35326
|
function candidatePool(entries, query, filters, config, now, k) {
|
|
35306
35327
|
validateQuery(query);
|
|
35307
35328
|
validateSearchFilters(filters, now);
|
|
35308
|
-
const queryTokens = [...new Set(tokenize(query))];
|
|
35329
|
+
const queryTokens = [...new Set(tokenize(query).map(stem))];
|
|
35309
35330
|
const today = now.toISOString().slice(0, 10);
|
|
35310
35331
|
return entries.filter((entry) => matchesFilters(entry, filters) && classMatch(entry, filters.class) && temporalMatch(entry, filters.asOf ?? null, config, today, Boolean(filters.status))).map((entry) => scoreEntry(entry, queryTokens, filters, config, now)).sort((a, b) => b.score - a.score).slice(0, Math.min(MAX_GENERAL_RESULTS, Math.max(0, k)));
|
|
35311
35332
|
}
|
|
@@ -35356,8 +35377,8 @@ function temporalMatch(entry, asOf, config, today, hasStatusFilter) {
|
|
|
35356
35377
|
}, new Date(`${today}T00:00:00.000Z`)).current;
|
|
35357
35378
|
}
|
|
35358
35379
|
function scoreEntry(entry, queryTokens, filters, config, now) {
|
|
35359
|
-
const bodyTokens = tokenSet(`${entry.title} ${entry.summary} ${entry.details} ${entry.tags.join(" ")}`);
|
|
35360
|
-
const titleTokens = tokenSet(entry.title);
|
|
35380
|
+
const bodyTokens = new Set([...tokenSet(`${entry.title} ${entry.summary} ${entry.details} ${entry.tags.join(" ")}`)].map(stem));
|
|
35381
|
+
const titleTokens = new Set([...tokenSet(entry.title)].map(stem));
|
|
35361
35382
|
let hits = 0;
|
|
35362
35383
|
let titleHits = 0;
|
|
35363
35384
|
for (const token of queryTokens) {
|
|
@@ -36214,6 +36235,7 @@ var init_service5 = __esm(() => {
|
|
|
36214
36235
|
init_harness_identity();
|
|
36215
36236
|
init_embedding();
|
|
36216
36237
|
init_types3();
|
|
36238
|
+
init_embedding();
|
|
36217
36239
|
});
|
|
36218
36240
|
|
|
36219
36241
|
// src/wiki/ask.ts
|
|
@@ -39595,6 +39617,7 @@ var init_service7 = __esm(() => {
|
|
|
39595
39617
|
init_query();
|
|
39596
39618
|
init_repomap();
|
|
39597
39619
|
init_affected_report();
|
|
39620
|
+
init_staleness();
|
|
39598
39621
|
UnknownGraphTargetError = class UnknownGraphTargetError extends Error {
|
|
39599
39622
|
target;
|
|
39600
39623
|
constructor(target) {
|
|
@@ -58996,7 +59019,13 @@ ${hint}
|
|
|
58996
59019
|
}
|
|
58997
59020
|
if (roundState.round < roundState.maxRounds) {
|
|
58998
59021
|
roundState.round += 1;
|
|
58999
|
-
await finishWithBudgetSummary(io, deps, history, parentRunId, { maxAttempts, toolLog }, signal);
|
|
59022
|
+
const wrapUp = await finishWithBudgetSummary(io, deps, history, parentRunId, { maxAttempts, toolLog }, signal);
|
|
59023
|
+
if (wrapUp.aborted) {
|
|
59024
|
+
system(`
|
|
59025
|
+
[stopped] Model turn interrupted by user.
|
|
59026
|
+
`);
|
|
59027
|
+
return { finishReason: "interrupted" };
|
|
59028
|
+
}
|
|
59000
59029
|
} else {
|
|
59001
59030
|
system(`
|
|
59002
59031
|
[budget] Stopping tools: no progress (only repeated/exhausted tool signatures; ` + `max ${maxAttempts} attempts each). No model rounds remain for a wrap-up.
|
|
@@ -59208,6 +59237,9 @@ ${logBlock}
|
|
|
59208
59237
|
};
|
|
59209
59238
|
const request = signal === undefined ? { ...baseRequest } : { ...baseRequest, signal };
|
|
59210
59239
|
const round = await streamWrapUpRound(io, deps, request, signal, system);
|
|
59240
|
+
if (round.aborted || signal?.aborted === true) {
|
|
59241
|
+
return { aborted: true };
|
|
59242
|
+
}
|
|
59211
59243
|
if (round.thrownError !== undefined) {
|
|
59212
59244
|
system(`
|
|
59213
59245
|
[error] wrap-up failed: ${round.thrownError}
|
|
@@ -59226,6 +59258,7 @@ ${logBlock}
|
|
|
59226
59258
|
system(`
|
|
59227
59259
|
[budget] No wrap-up text from the model. Re-run your request, or call the ` + "needed `keryx \u2026` command directly (e.g. `keryx wiki enrich --all`).\n");
|
|
59228
59260
|
}
|
|
59261
|
+
return { aborted: false };
|
|
59229
59262
|
}
|
|
59230
59263
|
async function finishWithSubmitResult(io, deps, history, parentRunId, why, signal) {
|
|
59231
59264
|
const system = (text) => {
|
|
@@ -60492,7 +60525,8 @@ function computeGate2(input) {
|
|
|
60492
60525
|
}
|
|
60493
60526
|
const missingOptional = sources.filter((s) => !s.required && s.status === "missing");
|
|
60494
60527
|
for (const source of missingOptional) {
|
|
60495
|
-
|
|
60528
|
+
const detail = source.error ? `: ${source.error}` : "";
|
|
60529
|
+
reasons.push(`OPTIONAL: ${source.source} source missing${detail}`);
|
|
60496
60530
|
}
|
|
60497
60531
|
const brokenOptional = sources.filter((s) => !s.required && s.status === "configured-but-failed");
|
|
60498
60532
|
if (brokenOptional.length > 0) {
|
|
@@ -62297,6 +62331,12 @@ function errorCodeSuffix(error) {
|
|
|
62297
62331
|
const code = safeErrorCode(error);
|
|
62298
62332
|
return code ? ` (${code})` : "";
|
|
62299
62333
|
}
|
|
62334
|
+
function missingSourceReason(sourceId) {
|
|
62335
|
+
if (sourceId === "tests") {
|
|
62336
|
+
return "no `bun` binary found (checked node_modules/.bin and PATH)";
|
|
62337
|
+
}
|
|
62338
|
+
return;
|
|
62339
|
+
}
|
|
62300
62340
|
function safeValidationError(error) {
|
|
62301
62341
|
return error !== undefined && KNOWN_VALIDATION_ERRORS.has(error) ? error : "source output format was not recognized";
|
|
62302
62342
|
}
|
|
@@ -62331,7 +62371,8 @@ async function runAdapter(adapter, ctx, cfg, stamp) {
|
|
|
62331
62371
|
};
|
|
62332
62372
|
}
|
|
62333
62373
|
if (status === "skipped" || status === "missing") {
|
|
62334
|
-
|
|
62374
|
+
const reason = missingSourceReason(adapter.id);
|
|
62375
|
+
return { info: { ...base, status, ...reason !== undefined ? { error: reason } : {} }, findings: [] };
|
|
62335
62376
|
}
|
|
62336
62377
|
let raw;
|
|
62337
62378
|
try {
|
|
@@ -62345,7 +62386,7 @@ async function runAdapter(adapter, ctx, cfg, stamp) {
|
|
|
62345
62386
|
} catch (error) {
|
|
62346
62387
|
if (error instanceof NoImportError) {
|
|
62347
62388
|
if (adapter.id === "tests") {
|
|
62348
|
-
return { info: { ...base, status
|
|
62389
|
+
return { info: { ...base, status }, findings: [] };
|
|
62349
62390
|
}
|
|
62350
62391
|
raw = await adapter.run(ctx);
|
|
62351
62392
|
} else {
|
|
@@ -62710,6 +62751,7 @@ var init_service10 = __esm(() => {
|
|
|
62710
62751
|
init_sources();
|
|
62711
62752
|
init_util();
|
|
62712
62753
|
init_lifecycle2();
|
|
62754
|
+
init_wiki_freshness();
|
|
62713
62755
|
});
|
|
62714
62756
|
|
|
62715
62757
|
// src/flow/machine.ts
|
|
@@ -68912,6 +68954,7 @@ async function enrichPageDeep(input) {
|
|
|
68912
68954
|
if (input.signal?.aborted) {
|
|
68913
68955
|
return { fallback: true, reason: "deep enrich cancelled", toolCalls };
|
|
68914
68956
|
}
|
|
68957
|
+
let disposeComposed;
|
|
68915
68958
|
try {
|
|
68916
68959
|
const env = envWithSavedApiKeys(input.env ?? process.env);
|
|
68917
68960
|
const credentialAvailable = hasCredential(input.provider, env);
|
|
@@ -68988,6 +69031,7 @@ async function enrichPageDeep(input) {
|
|
|
68988
69031
|
let pending;
|
|
68989
69032
|
const abort = new AbortController;
|
|
68990
69033
|
const composed = composeAbortSignals(input.signal, abort.signal);
|
|
69034
|
+
disposeComposed = composed.dispose;
|
|
68991
69035
|
const io = {
|
|
68992
69036
|
write: (s) => {
|
|
68993
69037
|
assistant += s;
|
|
@@ -69086,6 +69130,7 @@ async function enrichPageDeep(input) {
|
|
|
69086
69130
|
}
|
|
69087
69131
|
return { enriched: raw, toolCalls };
|
|
69088
69132
|
} catch (cause) {
|
|
69133
|
+
disposeComposed?.();
|
|
69089
69134
|
return { fallback: true, reason: `deep enrich failed: ${errorMessage2(cause)}`, toolCalls };
|
|
69090
69135
|
}
|
|
69091
69136
|
}
|
|
@@ -70718,6 +70763,7 @@ async function runSearch(args) {
|
|
|
70718
70763
|
}
|
|
70719
70764
|
const report = args.includes("--save-report") ? await getService().writeReport({ cwd: process.cwd(), search: result, filters }) : undefined;
|
|
70720
70765
|
const removalTrail = result.results.length === 0 ? searchRemovals(await loadDeletionTrail(process.cwd()), query) : null;
|
|
70766
|
+
const semanticHint = result.results.length === 0 && !filters.semantic ? await loadEmbeddingIndex(process.cwd()) !== null ? "Zero hits in lexical mode. An embeddings index exists for this project \u2014 try `--semantic`." : "Zero hits in lexical mode. No embeddings index exists yet \u2014 build one with `keryx memory index --embeddings`, then retry with `--semantic`." : undefined;
|
|
70721
70767
|
const asOfMode = Boolean(filters.asOf);
|
|
70722
70768
|
const now = new Date;
|
|
70723
70769
|
const historicalByPath = new Map;
|
|
@@ -70746,11 +70792,16 @@ async function runSearch(args) {
|
|
|
70746
70792
|
};
|
|
70747
70793
|
}),
|
|
70748
70794
|
...removalTrail ? { removalTrail } : {},
|
|
70795
|
+
...semanticHint ? { semanticHint } : {},
|
|
70749
70796
|
...report ? { report } : {}
|
|
70750
70797
|
}, null, 2));
|
|
70751
70798
|
return;
|
|
70752
70799
|
}
|
|
70753
70800
|
console.log(renderSearchMarkdown(query, result.results).trimEnd());
|
|
70801
|
+
if (semanticHint) {
|
|
70802
|
+
console.log("");
|
|
70803
|
+
console.log(semanticHint);
|
|
70804
|
+
}
|
|
70754
70805
|
if (removalTrail) {
|
|
70755
70806
|
console.log("");
|
|
70756
70807
|
console.log("## Removal trail");
|
|
@@ -71047,6 +71098,7 @@ var init_memory = __esm(() => {
|
|
|
71047
71098
|
init_config4();
|
|
71048
71099
|
init_reflect();
|
|
71049
71100
|
init_search();
|
|
71101
|
+
init_service5();
|
|
71050
71102
|
init_report2();
|
|
71051
71103
|
init_lifecycle();
|
|
71052
71104
|
init_args();
|
|
@@ -71623,7 +71675,7 @@ var init_debug_log = __esm(() => {
|
|
|
71623
71675
|
// src/tui/debug-watcher.ts
|
|
71624
71676
|
import { spawn as spawn8, spawnSync as spawnSync8 } from "child_process";
|
|
71625
71677
|
import { closeSync as closeSync6, constants as constants4, openSync as openSync7, readdirSync as readdirSync11, readFileSync as readFileSync24, readlinkSync as readlinkSync3, statSync as statSync16 } from "fs";
|
|
71626
|
-
import
|
|
71678
|
+
import path317 from "path";
|
|
71627
71679
|
function parseEpollFdinfo(text) {
|
|
71628
71680
|
const out = [];
|
|
71629
71681
|
for (const line of text.split(`
|
|
@@ -71812,8 +71864,8 @@ async function runDebugWatcher(argv) {
|
|
|
71812
71864
|
process.exitCode = 2;
|
|
71813
71865
|
return;
|
|
71814
71866
|
}
|
|
71815
|
-
const logFile =
|
|
71816
|
-
const shellLog =
|
|
71867
|
+
const logFile = path317.join(dirArg, "watcher.ndjson");
|
|
71868
|
+
const shellLog = path317.join(dirArg, "shell.ndjson");
|
|
71817
71869
|
const log = (kind, data = {}) => {
|
|
71818
71870
|
try {
|
|
71819
71871
|
appendOwnerOnlyLine(logFile, JSON.stringify({ ts: new Date().toISOString(), watcher: process.pid, target: pid, kind, ...data }));
|
|
@@ -107071,6 +107123,18 @@ var HELP_GROUPS = [
|
|
|
107071
107123
|
summary: "Grouped command help by task \u2014 keryx help [group|command]."
|
|
107072
107124
|
},
|
|
107073
107125
|
{ kind: "slash", name: "/help", group: "Start here", summary: "Show available commands, grouped by task." },
|
|
107126
|
+
{
|
|
107127
|
+
kind: "cli",
|
|
107128
|
+
name: "doctor",
|
|
107129
|
+
group: "Start here",
|
|
107130
|
+
summary: "One-page health check: version, Bun floor, ripgrep, sandbox, providers, MCP, integrations, standard, worktrees, graph/wiki freshness."
|
|
107131
|
+
},
|
|
107132
|
+
{
|
|
107133
|
+
kind: "slash",
|
|
107134
|
+
name: "/doctor",
|
|
107135
|
+
group: "Start here",
|
|
107136
|
+
summary: "Same one-page health check, inside the session."
|
|
107137
|
+
},
|
|
107074
107138
|
{
|
|
107075
107139
|
kind: "cli",
|
|
107076
107140
|
name: "auth",
|
|
@@ -109203,6 +109267,19 @@ var COMMAND_DESCRIPTORS = [
|
|
|
109203
109267
|
json: false,
|
|
109204
109268
|
read: true
|
|
109205
109269
|
},
|
|
109270
|
+
{
|
|
109271
|
+
module: "core",
|
|
109272
|
+
command: "doctor",
|
|
109273
|
+
summary: "One-page health check: version, Bun floor, ripgrep, sandbox, providers, MCP, integrations, standard, worktrees, graph/wiki freshness.",
|
|
109274
|
+
intent: ["keryx doctor", "health check", "\u043F\u0440\u043E\u0432\u0435\u0440\u044C \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u0435", "is keryx set up correctly", "\u0434\u0438\u0430\u0433\u043D\u043E\u0441\u0442\u0438\u043A\u0430"],
|
|
109275
|
+
args: [{ name: "json", type: "bool", required: false, desc: "structured {checks:[{id,status,detail,fix?}]}" }],
|
|
109276
|
+
json: true,
|
|
109277
|
+
read: false,
|
|
109278
|
+
sideEffects: [
|
|
109279
|
+
"makes an outbound HTTPS request to the npm registry as part of its version check, unless served from the local cache or failure-backoff window",
|
|
109280
|
+
"writes <per-user keryx config dir>/version-check.json (outside this project) as part of that same check"
|
|
109281
|
+
]
|
|
109282
|
+
},
|
|
109206
109283
|
{
|
|
109207
109284
|
module: "core",
|
|
109208
109285
|
command: "status",
|
|
@@ -111294,6 +111371,49 @@ async function sandboxCommand(args = [], deps = {}) {
|
|
|
111294
111371
|
init_args();
|
|
111295
111372
|
init_ui();
|
|
111296
111373
|
|
|
111374
|
+
// src/lib/suggest.ts
|
|
111375
|
+
var MAX_SUGGESTIONS = 3;
|
|
111376
|
+
var MAX_EDIT_DISTANCE = 2;
|
|
111377
|
+
function levenshtein2(a, b) {
|
|
111378
|
+
const rows = a.length + 1;
|
|
111379
|
+
const cols = b.length + 1;
|
|
111380
|
+
const dp = Array.from({ length: rows }, () => new Array(cols).fill(0));
|
|
111381
|
+
for (let i = 0;i < rows; i += 1) {
|
|
111382
|
+
const row = dp[i];
|
|
111383
|
+
if (row !== undefined)
|
|
111384
|
+
row[0] = i;
|
|
111385
|
+
}
|
|
111386
|
+
const first = dp[0];
|
|
111387
|
+
if (first !== undefined) {
|
|
111388
|
+
for (let j = 0;j < cols; j += 1)
|
|
111389
|
+
first[j] = j;
|
|
111390
|
+
}
|
|
111391
|
+
for (let i = 1;i < rows; i += 1) {
|
|
111392
|
+
for (let j = 1;j < cols; j += 1) {
|
|
111393
|
+
const same = a[i - 1] === b[j - 1];
|
|
111394
|
+
const up = dp[i - 1]?.[j] ?? 0;
|
|
111395
|
+
const left = dp[i]?.[j - 1] ?? 0;
|
|
111396
|
+
const diag = dp[i - 1]?.[j - 1] ?? 0;
|
|
111397
|
+
const row = dp[i];
|
|
111398
|
+
if (row !== undefined)
|
|
111399
|
+
row[j] = same ? diag : 1 + Math.min(up, left, diag);
|
|
111400
|
+
}
|
|
111401
|
+
}
|
|
111402
|
+
return dp[rows - 1]?.[cols - 1] ?? Math.max(a.length, b.length);
|
|
111403
|
+
}
|
|
111404
|
+
function suggestClosest(input, known) {
|
|
111405
|
+
const needle = input.trim().toLowerCase();
|
|
111406
|
+
if (needle.length === 0) {
|
|
111407
|
+
return [];
|
|
111408
|
+
}
|
|
111409
|
+
return [...new Set(known)].map((candidate) => ({ candidate, distance: levenshtein2(needle, candidate.toLowerCase()) })).filter((entry) => entry.distance <= MAX_EDIT_DISTANCE).sort((a, b) => a.distance - b.distance || a.candidate.localeCompare(b.candidate)).slice(0, MAX_SUGGESTIONS).map((entry) => entry.candidate);
|
|
111410
|
+
}
|
|
111411
|
+
function formatUnknownCommandMessage(input, known, helpCommand = "keryx --help") {
|
|
111412
|
+
const suggestions = suggestClosest(input, known);
|
|
111413
|
+
const didYouMean = suggestions.length > 0 ? ` Did you mean: ${suggestions.join(", ")}?` : "";
|
|
111414
|
+
return `Unknown command: ${input}.${didYouMean} Run \`${helpCommand}\` for the list.`;
|
|
111415
|
+
}
|
|
111416
|
+
|
|
111297
111417
|
// src/commands/integrate.ts
|
|
111298
111418
|
init_ui();
|
|
111299
111419
|
import path257 from "path";
|
|
@@ -111840,12 +111960,12 @@ function loadMcpServers(options) {
|
|
|
111840
111960
|
const home = options.home ?? (options.configDir === undefined ? undefined : NO_HOME);
|
|
111841
111961
|
for (const entry of compatFiles(options.cwd, home)) {
|
|
111842
111962
|
const read = readCompatFile(entry, options.cwd);
|
|
111843
|
-
problems.push(...read.problems);
|
|
111963
|
+
problems.push(...read.problems.map((p) => ({ ...p, foreign: true })));
|
|
111844
111964
|
for (const [name, value] of Object.entries(read.servers)) {
|
|
111845
111965
|
const found = entryProblems(name, value);
|
|
111846
111966
|
if (found.length > 0) {
|
|
111847
111967
|
for (const message of found)
|
|
111848
|
-
problems.push({ file: entry.file, message });
|
|
111968
|
+
problems.push({ file: entry.file, message, foreign: true });
|
|
111849
111969
|
continue;
|
|
111850
111970
|
}
|
|
111851
111971
|
winner.set(name, {
|
|
@@ -114019,19 +114139,31 @@ function publicView(server, env) {
|
|
|
114019
114139
|
function listCommand(args, deps) {
|
|
114020
114140
|
const config = load(deps);
|
|
114021
114141
|
const wantJson = splitAtSeparator(args).own.includes("--json");
|
|
114142
|
+
const ownProblems = config.problems.filter((p) => !p.foreign);
|
|
114143
|
+
const foreignProblems = config.problems.filter((p) => p.foreign);
|
|
114022
114144
|
if (wantJson) {
|
|
114023
114145
|
const env = deps.env ?? process.env;
|
|
114024
|
-
deps.log(JSON.stringify({
|
|
114025
|
-
|
|
114146
|
+
deps.log(JSON.stringify({
|
|
114147
|
+
servers: config.servers.map((s) => publicView(s, env)),
|
|
114148
|
+
problems: ownProblems,
|
|
114149
|
+
warnings: foreignProblems
|
|
114150
|
+
}, null, 2));
|
|
114151
|
+
return ownProblems.length > 0 ? 1 : 0;
|
|
114026
114152
|
}
|
|
114027
|
-
for (const problem of
|
|
114153
|
+
for (const problem of ownProblems) {
|
|
114028
114154
|
deps.err(`config problem \u2014 ${problem.file}: ${problem.message}`);
|
|
114029
114155
|
}
|
|
114156
|
+
if (foreignProblems.length > 0) {
|
|
114157
|
+
deps.err("warnings:");
|
|
114158
|
+
for (const problem of foreignProblems) {
|
|
114159
|
+
deps.err(` ${problem.file}: ${problem.message}`);
|
|
114160
|
+
}
|
|
114161
|
+
}
|
|
114030
114162
|
if (config.servers.length === 0) {
|
|
114031
114163
|
deps.log("No MCP servers configured.");
|
|
114032
114164
|
deps.log(` user: ${userConfigFile(deps.configDir)}`);
|
|
114033
114165
|
deps.log(` project: ${projectConfigFile(projectRootOf2(deps))}`);
|
|
114034
|
-
return
|
|
114166
|
+
return ownProblems.length > 0 ? 1 : 0;
|
|
114035
114167
|
}
|
|
114036
114168
|
const approvals = loadTrustStore(deps.configDir);
|
|
114037
114169
|
let held = 0;
|
|
@@ -114050,7 +114182,7 @@ function listCommand(args, deps) {
|
|
|
114050
114182
|
deps.log(`${held} server(s) from committed config are not started until approved \u2014 a committed config is code someone else wrote.`);
|
|
114051
114183
|
deps.log("Read what it launches above, then: keryx mcp trust <name>");
|
|
114052
114184
|
}
|
|
114053
|
-
return
|
|
114185
|
+
return ownProblems.length > 0 ? 1 : 0;
|
|
114054
114186
|
}
|
|
114055
114187
|
function describeTarget(server) {
|
|
114056
114188
|
const raw = server.raw;
|
|
@@ -116947,8 +117079,12 @@ async function mcpCommand(args = [], cwd = process.cwd()) {
|
|
|
116947
117079
|
await serveMcpCommand(args.slice(1), cwd);
|
|
116948
117080
|
return;
|
|
116949
117081
|
}
|
|
116950
|
-
console.error(
|
|
116951
|
-
|
|
117082
|
+
console.error(formatUnknownCommandMessage(subcommand ?? "", [
|
|
117083
|
+
...MCP_CONSUMER_SUBCOMMANDS,
|
|
117084
|
+
"install",
|
|
117085
|
+
"uninstall",
|
|
117086
|
+
"serve"
|
|
117087
|
+
], "keryx mcp --help"));
|
|
116952
117088
|
process.exitCode = 1;
|
|
116953
117089
|
}
|
|
116954
117090
|
function announceRename(retired, replacement) {
|
|
@@ -135466,6 +135602,569 @@ class NextStepSuggestionGate {
|
|
|
135466
135602
|
}
|
|
135467
135603
|
}
|
|
135468
135604
|
|
|
135605
|
+
// src/commands/doctor.ts
|
|
135606
|
+
init_package();
|
|
135607
|
+
import { readdir as readdir53 } from "fs/promises";
|
|
135608
|
+
import { existsSync as existsSync48 } from "fs";
|
|
135609
|
+
import path302 from "path";
|
|
135610
|
+
|
|
135611
|
+
// src/lib/version-check.ts
|
|
135612
|
+
init_config_dir();
|
|
135613
|
+
init_fs();
|
|
135614
|
+
import path301 from "path";
|
|
135615
|
+
var REGISTRY_URL = "https://registry.npmjs.org/@mrciphersmith%2Fkeryx/latest";
|
|
135616
|
+
var FIXED_INSTALL_COMMAND = "npm install -g @mrciphersmith/keryx@latest";
|
|
135617
|
+
var RESPONSE_BODY_LIMIT_BYTES = 64 * 1024;
|
|
135618
|
+
var VERSION_STRING_LIMIT_CHARS = 64;
|
|
135619
|
+
var REQUEST_TIMEOUT_MS = 2000;
|
|
135620
|
+
var SUCCESS_CACHE_TTL_MS = 24 * 60 * 60 * 1000;
|
|
135621
|
+
var FAILURE_BACKOFF_MS = 15 * 60 * 1000;
|
|
135622
|
+
var CACHE_LOCK_TIMEOUT_MS2 = 250;
|
|
135623
|
+
var CACHE_LOCK_RETRY_MS2 = 10;
|
|
135624
|
+
var CACHE_LOCK_STALE_MS2 = 5000;
|
|
135625
|
+
var SYSTEM_TIMER = {
|
|
135626
|
+
schedule: (callback, delayMs) => setTimeout(callback, delayMs),
|
|
135627
|
+
cancel: (handle) => clearTimeout(handle)
|
|
135628
|
+
};
|
|
135629
|
+
function formatVersionUpdateAdvisory(result) {
|
|
135630
|
+
if (result.status !== "update-available")
|
|
135631
|
+
return;
|
|
135632
|
+
return `Keryx update ${result.currentVersion} \u2192 ${result.latestVersion}
|
|
135633
|
+
${result.installCommand}`;
|
|
135634
|
+
}
|
|
135635
|
+
var STRICT_SEMVER = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/;
|
|
135636
|
+
function parseSemVer(value) {
|
|
135637
|
+
if (value.length > VERSION_STRING_LIMIT_CHARS)
|
|
135638
|
+
return;
|
|
135639
|
+
const match = STRICT_SEMVER.exec(value);
|
|
135640
|
+
if (match === null)
|
|
135641
|
+
return;
|
|
135642
|
+
const prereleaseText = match[4];
|
|
135643
|
+
const prerelease = [];
|
|
135644
|
+
if (prereleaseText !== undefined) {
|
|
135645
|
+
for (const identifier of prereleaseText.split(".")) {
|
|
135646
|
+
if (/^\d+$/.test(identifier)) {
|
|
135647
|
+
if (identifier.length > 1 && identifier.startsWith("0"))
|
|
135648
|
+
return;
|
|
135649
|
+
prerelease.push(BigInt(identifier));
|
|
135650
|
+
} else {
|
|
135651
|
+
prerelease.push(identifier);
|
|
135652
|
+
}
|
|
135653
|
+
}
|
|
135654
|
+
}
|
|
135655
|
+
return {
|
|
135656
|
+
major: BigInt(match[1]),
|
|
135657
|
+
minor: BigInt(match[2]),
|
|
135658
|
+
patch: BigInt(match[3]),
|
|
135659
|
+
prerelease
|
|
135660
|
+
};
|
|
135661
|
+
}
|
|
135662
|
+
function compareSemVer(left, right) {
|
|
135663
|
+
for (const key of ["major", "minor", "patch"]) {
|
|
135664
|
+
if (left[key] < right[key])
|
|
135665
|
+
return -1;
|
|
135666
|
+
if (left[key] > right[key])
|
|
135667
|
+
return 1;
|
|
135668
|
+
}
|
|
135669
|
+
if (left.prerelease.length === 0 || right.prerelease.length === 0) {
|
|
135670
|
+
if (left.prerelease.length === right.prerelease.length)
|
|
135671
|
+
return 0;
|
|
135672
|
+
return left.prerelease.length === 0 ? 1 : -1;
|
|
135673
|
+
}
|
|
135674
|
+
const length = Math.max(left.prerelease.length, right.prerelease.length);
|
|
135675
|
+
for (let index = 0;index < length; index += 1) {
|
|
135676
|
+
const a = left.prerelease[index];
|
|
135677
|
+
const b = right.prerelease[index];
|
|
135678
|
+
if (a === undefined || b === undefined) {
|
|
135679
|
+
if (a === b)
|
|
135680
|
+
return 0;
|
|
135681
|
+
return a === undefined ? -1 : 1;
|
|
135682
|
+
}
|
|
135683
|
+
if (typeof a === "bigint" && typeof b === "bigint") {
|
|
135684
|
+
if (a < b)
|
|
135685
|
+
return -1;
|
|
135686
|
+
if (a > b)
|
|
135687
|
+
return 1;
|
|
135688
|
+
} else if (typeof a === "bigint") {
|
|
135689
|
+
return -1;
|
|
135690
|
+
} else if (typeof b === "bigint") {
|
|
135691
|
+
return 1;
|
|
135692
|
+
} else if (a !== b) {
|
|
135693
|
+
return a < b ? -1 : 1;
|
|
135694
|
+
}
|
|
135695
|
+
}
|
|
135696
|
+
return 0;
|
|
135697
|
+
}
|
|
135698
|
+
function parseCache(file) {
|
|
135699
|
+
const read = readConfigFile(file);
|
|
135700
|
+
if (!read.ok)
|
|
135701
|
+
return;
|
|
135702
|
+
try {
|
|
135703
|
+
const value = JSON.parse(read.text);
|
|
135704
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
135705
|
+
return;
|
|
135706
|
+
const record = value;
|
|
135707
|
+
const cache = {};
|
|
135708
|
+
if (typeof record.latestVersion === "string" && parseSemVer(record.latestVersion) !== undefined) {
|
|
135709
|
+
cache.latestVersion = record.latestVersion;
|
|
135710
|
+
}
|
|
135711
|
+
if (typeof record.successAt === "number" && Number.isFinite(record.successAt))
|
|
135712
|
+
cache.successAt = record.successAt;
|
|
135713
|
+
if (typeof record.failureAt === "number" && Number.isFinite(record.failureAt))
|
|
135714
|
+
cache.failureAt = record.failureAt;
|
|
135715
|
+
return cache;
|
|
135716
|
+
} catch {
|
|
135717
|
+
return;
|
|
135718
|
+
}
|
|
135719
|
+
}
|
|
135720
|
+
function resultFor(currentVersion, current, latestVersion, source) {
|
|
135721
|
+
const latest = parseSemVer(latestVersion);
|
|
135722
|
+
return compareSemVer(current, latest) < 0 ? { status: "update-available", currentVersion, latestVersion, installCommand: FIXED_INSTALL_COMMAND, source } : { status: "up-to-date", currentVersion, latestVersion, source };
|
|
135723
|
+
}
|
|
135724
|
+
function cancelWithoutWaiting(cancel) {
|
|
135725
|
+
try {
|
|
135726
|
+
cancel().catch(() => {});
|
|
135727
|
+
} catch {}
|
|
135728
|
+
}
|
|
135729
|
+
async function boundedResponseText(response) {
|
|
135730
|
+
const declared = response.headers.get("content-length");
|
|
135731
|
+
if (declared !== null && /^\d+$/.test(declared) && BigInt(declared) > BigInt(RESPONSE_BODY_LIMIT_BYTES)) {
|
|
135732
|
+
if (response.body !== null) {
|
|
135733
|
+
cancelWithoutWaiting(() => response.body.cancel());
|
|
135734
|
+
}
|
|
135735
|
+
return;
|
|
135736
|
+
}
|
|
135737
|
+
if (response.body === null)
|
|
135738
|
+
return "";
|
|
135739
|
+
const reader = response.body.getReader();
|
|
135740
|
+
const decoder = new TextDecoder;
|
|
135741
|
+
let size = 0;
|
|
135742
|
+
let text = "";
|
|
135743
|
+
try {
|
|
135744
|
+
for (;; ) {
|
|
135745
|
+
const chunk = await reader.read();
|
|
135746
|
+
if (chunk.done)
|
|
135747
|
+
break;
|
|
135748
|
+
size += chunk.value.byteLength;
|
|
135749
|
+
if (size > RESPONSE_BODY_LIMIT_BYTES) {
|
|
135750
|
+
cancelWithoutWaiting(() => reader.cancel());
|
|
135751
|
+
return;
|
|
135752
|
+
}
|
|
135753
|
+
text += decoder.decode(chunk.value, { stream: true });
|
|
135754
|
+
}
|
|
135755
|
+
return text + decoder.decode();
|
|
135756
|
+
} finally {
|
|
135757
|
+
reader.releaseLock();
|
|
135758
|
+
}
|
|
135759
|
+
}
|
|
135760
|
+
function unavailable(currentVersion, reason, cache) {
|
|
135761
|
+
return {
|
|
135762
|
+
status: "unavailable",
|
|
135763
|
+
currentVersion,
|
|
135764
|
+
reason,
|
|
135765
|
+
...cache?.latestVersion !== undefined ? { cachedLatestVersion: cache.latestVersion } : {}
|
|
135766
|
+
};
|
|
135767
|
+
}
|
|
135768
|
+
function saveCache2(file, cache) {
|
|
135769
|
+
try {
|
|
135770
|
+
writeOwnerOnlyFileAtomic(file, `${JSON.stringify(cache, null, 2)}
|
|
135771
|
+
`);
|
|
135772
|
+
return true;
|
|
135773
|
+
} catch {
|
|
135774
|
+
return false;
|
|
135775
|
+
}
|
|
135776
|
+
}
|
|
135777
|
+
function mergeSuccessfulCache(committed, latestVersion, successAt) {
|
|
135778
|
+
if (committed.latestVersion === undefined || committed.successAt === undefined) {
|
|
135779
|
+
return { latestVersion, successAt };
|
|
135780
|
+
}
|
|
135781
|
+
if (committed.successAt > successAt)
|
|
135782
|
+
return committed;
|
|
135783
|
+
if (committed.successAt < successAt)
|
|
135784
|
+
return { latestVersion, successAt };
|
|
135785
|
+
const committedVersion = parseSemVer(committed.latestVersion);
|
|
135786
|
+
const candidateVersion = parseSemVer(latestVersion);
|
|
135787
|
+
if (committedVersion !== undefined && candidateVersion !== undefined) {
|
|
135788
|
+
const precedence = compareSemVer(committedVersion, candidateVersion);
|
|
135789
|
+
if (precedence > 0)
|
|
135790
|
+
return committed;
|
|
135791
|
+
if (precedence < 0)
|
|
135792
|
+
return { latestVersion, successAt };
|
|
135793
|
+
if (committed.latestVersion >= latestVersion)
|
|
135794
|
+
return committed;
|
|
135795
|
+
}
|
|
135796
|
+
return { latestVersion, successAt };
|
|
135797
|
+
}
|
|
135798
|
+
async function updateCache(file, update) {
|
|
135799
|
+
try {
|
|
135800
|
+
return await withFileLock(`${file}.lock`, async () => saveCache2(file, update(parseCache(file) ?? {})), {
|
|
135801
|
+
timeoutMs: CACHE_LOCK_TIMEOUT_MS2,
|
|
135802
|
+
retryMs: CACHE_LOCK_RETRY_MS2,
|
|
135803
|
+
staleMs: CACHE_LOCK_STALE_MS2
|
|
135804
|
+
});
|
|
135805
|
+
} catch {
|
|
135806
|
+
return false;
|
|
135807
|
+
}
|
|
135808
|
+
}
|
|
135809
|
+
async function checkVersion(options) {
|
|
135810
|
+
const current = parseSemVer(options.currentVersion);
|
|
135811
|
+
if (current === undefined)
|
|
135812
|
+
return unavailable(options.currentVersion, "invalid-current-version");
|
|
135813
|
+
const now = options.now ?? Date.now;
|
|
135814
|
+
const timestamp = now();
|
|
135815
|
+
const configDir = ensureKeryxConfigDir(options.cacheDir);
|
|
135816
|
+
const cacheFile = path301.join(configDir, "version-check.json");
|
|
135817
|
+
const cache = parseCache(cacheFile);
|
|
135818
|
+
if (cache?.latestVersion !== undefined && cache.successAt !== undefined && timestamp - cache.successAt >= 0 && timestamp - cache.successAt < SUCCESS_CACHE_TTL_MS) {
|
|
135819
|
+
return resultFor(options.currentVersion, current, cache.latestVersion, "cache");
|
|
135820
|
+
}
|
|
135821
|
+
if (cache?.failureAt !== undefined && timestamp - cache.failureAt >= 0 && timestamp - cache.failureAt < FAILURE_BACKOFF_MS) {
|
|
135822
|
+
return unavailable(options.currentVersion, "suppressed", cache);
|
|
135823
|
+
}
|
|
135824
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
135825
|
+
const controller = new AbortController;
|
|
135826
|
+
const timer = options.timer ?? SYSTEM_TIMER;
|
|
135827
|
+
let timeout;
|
|
135828
|
+
let timeoutScheduled = false;
|
|
135829
|
+
let failure;
|
|
135830
|
+
let latestVersion;
|
|
135831
|
+
try {
|
|
135832
|
+
timeout = timer.schedule(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
135833
|
+
timeoutScheduled = true;
|
|
135834
|
+
const response = await fetchImpl(REGISTRY_URL, {
|
|
135835
|
+
method: "GET",
|
|
135836
|
+
headers: { accept: "application/json" },
|
|
135837
|
+
signal: controller.signal,
|
|
135838
|
+
credentials: "omit"
|
|
135839
|
+
});
|
|
135840
|
+
if (!response.ok) {
|
|
135841
|
+
failure = "http";
|
|
135842
|
+
} else {
|
|
135843
|
+
const body = await boundedResponseText(response);
|
|
135844
|
+
if (body === undefined) {
|
|
135845
|
+
failure = "response-too-large";
|
|
135846
|
+
} else {
|
|
135847
|
+
let parsed;
|
|
135848
|
+
try {
|
|
135849
|
+
parsed = JSON.parse(body);
|
|
135850
|
+
} catch {
|
|
135851
|
+
parsed = undefined;
|
|
135852
|
+
}
|
|
135853
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
135854
|
+
failure = "malformed-response";
|
|
135855
|
+
} else {
|
|
135856
|
+
const record = parsed;
|
|
135857
|
+
if (record.name !== "@mrciphersmith/keryx" || typeof record.version !== "string") {
|
|
135858
|
+
failure = "malformed-response";
|
|
135859
|
+
} else if (parseSemVer(record.version) === undefined) {
|
|
135860
|
+
failure = "invalid-latest-version";
|
|
135861
|
+
} else {
|
|
135862
|
+
latestVersion = record.version;
|
|
135863
|
+
}
|
|
135864
|
+
}
|
|
135865
|
+
}
|
|
135866
|
+
}
|
|
135867
|
+
} catch {
|
|
135868
|
+
failure = controller.signal.aborted ? "timeout" : "network";
|
|
135869
|
+
} finally {
|
|
135870
|
+
if (timeoutScheduled) {
|
|
135871
|
+
try {
|
|
135872
|
+
timer.cancel(timeout);
|
|
135873
|
+
} catch {}
|
|
135874
|
+
}
|
|
135875
|
+
}
|
|
135876
|
+
if (latestVersion === undefined) {
|
|
135877
|
+
await updateCache(cacheFile, (committed) => ({ ...committed, failureAt: timestamp }));
|
|
135878
|
+
return unavailable(options.currentVersion, failure ?? "network", cache);
|
|
135879
|
+
}
|
|
135880
|
+
await updateCache(cacheFile, (committed) => mergeSuccessfulCache(committed, latestVersion, timestamp));
|
|
135881
|
+
return resultFor(options.currentVersion, current, latestVersion, "registry");
|
|
135882
|
+
}
|
|
135883
|
+
|
|
135884
|
+
// src/commands/doctor.ts
|
|
135885
|
+
init_contained_path();
|
|
135886
|
+
init_providers();
|
|
135887
|
+
init_service();
|
|
135888
|
+
init_service7();
|
|
135889
|
+
init_service10();
|
|
135890
|
+
async function registeredWorktrees(cwd) {
|
|
135891
|
+
if (!Bun.which("git"))
|
|
135892
|
+
return new Set;
|
|
135893
|
+
try {
|
|
135894
|
+
const proc = Bun.spawn(["git", "worktree", "list", "--porcelain"], { cwd, stdout: "pipe", stderr: "ignore" });
|
|
135895
|
+
const [stdout, code] = await Promise.all([new Response(proc.stdout).text(), proc.exited]);
|
|
135896
|
+
if (code !== 0)
|
|
135897
|
+
return new Set;
|
|
135898
|
+
const paths = new Set;
|
|
135899
|
+
for (const line of stdout.split(`
|
|
135900
|
+
`)) {
|
|
135901
|
+
if (line.startsWith("worktree ")) {
|
|
135902
|
+
paths.add(path302.resolve(line.slice("worktree ".length).trim()));
|
|
135903
|
+
}
|
|
135904
|
+
}
|
|
135905
|
+
return paths;
|
|
135906
|
+
} catch {
|
|
135907
|
+
return new Set;
|
|
135908
|
+
}
|
|
135909
|
+
}
|
|
135910
|
+
async function checkWorktrees(cwd) {
|
|
135911
|
+
const worktreesDir = path302.join(cwd, ".claude", "worktrees");
|
|
135912
|
+
let entries;
|
|
135913
|
+
try {
|
|
135914
|
+
entries = (await readdir53(worktreesDir, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
|
|
135915
|
+
} catch {
|
|
135916
|
+
return { id: "worktrees", status: "ok", detail: "no .claude/worktrees directory" };
|
|
135917
|
+
}
|
|
135918
|
+
if (entries.length === 0) {
|
|
135919
|
+
return { id: "worktrees", status: "ok", detail: ".claude/worktrees is empty" };
|
|
135920
|
+
}
|
|
135921
|
+
const registered = await registeredWorktrees(cwd);
|
|
135922
|
+
const stale = entries.filter((name) => {
|
|
135923
|
+
const full = path302.resolve(worktreesDir, name);
|
|
135924
|
+
return !existsSync48(path302.join(full, ".git")) || !registered.has(full);
|
|
135925
|
+
});
|
|
135926
|
+
if (stale.length === 0) {
|
|
135927
|
+
return {
|
|
135928
|
+
id: "worktrees",
|
|
135929
|
+
status: "ok",
|
|
135930
|
+
detail: `${entries.length} worktree(s) under .claude/worktrees, all registered`
|
|
135931
|
+
};
|
|
135932
|
+
}
|
|
135933
|
+
return {
|
|
135934
|
+
id: "worktrees",
|
|
135935
|
+
status: "warn",
|
|
135936
|
+
detail: `${stale.length} stale entr${stale.length === 1 ? "y" : "ies"} under .claude/worktrees: ${stale.join(", ")}`,
|
|
135937
|
+
fix: "git worktree prune, then remove the listed directories under .claude/worktrees by hand"
|
|
135938
|
+
};
|
|
135939
|
+
}
|
|
135940
|
+
function meetsBunFloor(current, floor) {
|
|
135941
|
+
const floorMatch = /^>=\s*(\d+)\.(\d+)\.(\d+)/.exec(floor);
|
|
135942
|
+
const currentMatch = /^(\d+)\.(\d+)\.(\d+)/.exec(current);
|
|
135943
|
+
if (!floorMatch || !currentMatch)
|
|
135944
|
+
return true;
|
|
135945
|
+
for (let i = 1;i <= 3; i += 1) {
|
|
135946
|
+
const f = Number(floorMatch[i]);
|
|
135947
|
+
const c = Number(currentMatch[i]);
|
|
135948
|
+
if (c !== f)
|
|
135949
|
+
return c > f;
|
|
135950
|
+
}
|
|
135951
|
+
return true;
|
|
135952
|
+
}
|
|
135953
|
+
function checkBun(bunFloorOverride) {
|
|
135954
|
+
const floor = bunFloorOverride ?? package_default.engines?.bun;
|
|
135955
|
+
const current = Bun.version;
|
|
135956
|
+
if (floor === undefined || meetsBunFloor(current, floor)) {
|
|
135957
|
+
return { id: "bun", status: "ok", detail: `Bun ${current}${floor ? ` (floor ${floor})` : ""}` };
|
|
135958
|
+
}
|
|
135959
|
+
return {
|
|
135960
|
+
id: "bun",
|
|
135961
|
+
status: "fail",
|
|
135962
|
+
detail: `Bun ${current} is below the documented floor ${floor}`,
|
|
135963
|
+
fix: "upgrade Bun: https://bun.sh/docs/installation"
|
|
135964
|
+
};
|
|
135965
|
+
}
|
|
135966
|
+
function checkRipgrep() {
|
|
135967
|
+
const rg = Bun.which("rg");
|
|
135968
|
+
return rg ? { id: "ripgrep", status: "ok", detail: `rg at ${rg}` } : {
|
|
135969
|
+
id: "ripgrep",
|
|
135970
|
+
status: "warn",
|
|
135971
|
+
detail: "ripgrep (rg) not found on PATH \u2014 keryx ctx rg and search_code are unavailable",
|
|
135972
|
+
fix: "brew install ripgrep (macOS) or apt install ripgrep (Debian/Ubuntu)"
|
|
135973
|
+
};
|
|
135974
|
+
}
|
|
135975
|
+
async function checkVersionAvailability() {
|
|
135976
|
+
const result = await checkVersion({ currentVersion: package_default.version });
|
|
135977
|
+
if (result.status === "update-available") {
|
|
135978
|
+
return {
|
|
135979
|
+
id: "version",
|
|
135980
|
+
status: "warn",
|
|
135981
|
+
detail: `keryx ${result.currentVersion} \u2192 ${result.latestVersion} is available`,
|
|
135982
|
+
fix: result.installCommand
|
|
135983
|
+
};
|
|
135984
|
+
}
|
|
135985
|
+
if (result.status === "up-to-date") {
|
|
135986
|
+
return { id: "version", status: "ok", detail: `keryx ${result.currentVersion} is up to date` };
|
|
135987
|
+
}
|
|
135988
|
+
return { id: "version", status: "ok", detail: `keryx ${result.currentVersion}; update check unavailable (${result.reason})` };
|
|
135989
|
+
}
|
|
135990
|
+
function checkSandbox() {
|
|
135991
|
+
const report = buildSandboxReport();
|
|
135992
|
+
if (report.launcher.available) {
|
|
135993
|
+
return { id: "sandbox", status: "ok", detail: `${report.launcherName ?? "sandbox launcher"} available` };
|
|
135994
|
+
}
|
|
135995
|
+
const known = report.launcherName !== undefined;
|
|
135996
|
+
return {
|
|
135997
|
+
id: "sandbox",
|
|
135998
|
+
status: "warn",
|
|
135999
|
+
detail: known ? `${report.launcherName} not installed on ${report.platform} \u2014 OS-sandboxed shell exec is unavailable` : `no OS sandbox launcher support on ${report.platform}`,
|
|
136000
|
+
fix: known ? "keryx sandbox status for what installing it would unlock" : "keryx sandbox status for details"
|
|
136001
|
+
};
|
|
136002
|
+
}
|
|
136003
|
+
function checkProviders(env) {
|
|
136004
|
+
const providers = configuredProviders(env);
|
|
136005
|
+
if (providers.length === 0) {
|
|
136006
|
+
return {
|
|
136007
|
+
id: "providers",
|
|
136008
|
+
status: "warn",
|
|
136009
|
+
detail: "no provider credentials configured",
|
|
136010
|
+
fix: "keryx auth login <provider>, or set a provider API key"
|
|
136011
|
+
};
|
|
136012
|
+
}
|
|
136013
|
+
return {
|
|
136014
|
+
id: "providers",
|
|
136015
|
+
status: "ok",
|
|
136016
|
+
detail: `${providers.length} provider(s) configured: ${providers.map((p) => p.name).join(", ")}`
|
|
136017
|
+
};
|
|
136018
|
+
}
|
|
136019
|
+
function checkMcp(cwd) {
|
|
136020
|
+
const projectRoot = resolveProjectRoot(cwd);
|
|
136021
|
+
const config = loadMcpServers({ cwd, gitRoot: projectRoot });
|
|
136022
|
+
const ownProblems = config.problems.filter((p) => !p.foreign);
|
|
136023
|
+
if (ownProblems.length > 0) {
|
|
136024
|
+
return {
|
|
136025
|
+
id: "mcp",
|
|
136026
|
+
status: "fail",
|
|
136027
|
+
detail: `${ownProblems.length} config problem(s) in keryx's own MCP config: ${ownProblems.map((p) => p.message).join("; ")}`,
|
|
136028
|
+
fix: "keryx mcp list for details"
|
|
136029
|
+
};
|
|
136030
|
+
}
|
|
136031
|
+
const approvals = loadTrustStore();
|
|
136032
|
+
const held = config.servers.filter((server) => server.enabled && requiresApproval(server, approvals));
|
|
136033
|
+
if (held.length > 0) {
|
|
136034
|
+
return {
|
|
136035
|
+
id: "mcp",
|
|
136036
|
+
status: "warn",
|
|
136037
|
+
detail: `${held.length} server(s) from committed config awaiting approval: ${held.map((s) => s.name).join(", ")}`,
|
|
136038
|
+
fix: "keryx mcp trust <name>, after reading what it launches"
|
|
136039
|
+
};
|
|
136040
|
+
}
|
|
136041
|
+
return {
|
|
136042
|
+
id: "mcp",
|
|
136043
|
+
status: "ok",
|
|
136044
|
+
detail: `${config.servers.length} server(s) configured; run \`keryx mcp doctor\` to also check connectivity`
|
|
136045
|
+
};
|
|
136046
|
+
}
|
|
136047
|
+
async function checkIntegrations(cwd) {
|
|
136048
|
+
const results = await Promise.all(harnessAdapterIds().map(async (id) => {
|
|
136049
|
+
try {
|
|
136050
|
+
return await doctorIntegration(cwd, id);
|
|
136051
|
+
} catch {
|
|
136052
|
+
return { runtimeId: id, surfaces: [], problems: [], ok: true };
|
|
136053
|
+
}
|
|
136054
|
+
}));
|
|
136055
|
+
const drifted = results.filter((r) => !r.ok);
|
|
136056
|
+
if (drifted.length === 0) {
|
|
136057
|
+
return { id: "integrations", status: "ok", detail: "no drift in any installed integration" };
|
|
136058
|
+
}
|
|
136059
|
+
return {
|
|
136060
|
+
id: "integrations",
|
|
136061
|
+
status: "warn",
|
|
136062
|
+
detail: `drift in: ${drifted.map((r) => r.runtimeId).join(", ")}`,
|
|
136063
|
+
fix: "keryx integrations doctor --runtime all"
|
|
136064
|
+
};
|
|
136065
|
+
}
|
|
136066
|
+
async function checkStandard(cwd) {
|
|
136067
|
+
const result = await runDoctor(cwd);
|
|
136068
|
+
if (result.errors.length > 0) {
|
|
136069
|
+
return {
|
|
136070
|
+
id: "standard",
|
|
136071
|
+
status: "fail",
|
|
136072
|
+
detail: `${result.errors.length} error(s): ${result.errors.map((e) => e.message).join("; ")}`,
|
|
136073
|
+
fix: "keryx standard doctor"
|
|
136074
|
+
};
|
|
136075
|
+
}
|
|
136076
|
+
if (result.warnings.length > 0) {
|
|
136077
|
+
return {
|
|
136078
|
+
id: "standard",
|
|
136079
|
+
status: "warn",
|
|
136080
|
+
detail: `${result.warnings.length} warning(s): ${result.warnings.map((w) => w.message).join("; ")}`,
|
|
136081
|
+
fix: "keryx standard doctor"
|
|
136082
|
+
};
|
|
136083
|
+
}
|
|
136084
|
+
return { id: "standard", status: "ok", detail: "workspace is Metaproject Standard compliant" };
|
|
136085
|
+
}
|
|
136086
|
+
async function checkGraphFreshness(cwd) {
|
|
136087
|
+
const result = await checkGraphStaleness(cwd);
|
|
136088
|
+
if (result.status === "fresh") {
|
|
136089
|
+
return { id: "graph-freshness", status: "ok", detail: "code graph is fresh" };
|
|
136090
|
+
}
|
|
136091
|
+
return {
|
|
136092
|
+
id: "graph-freshness",
|
|
136093
|
+
status: "warn",
|
|
136094
|
+
detail: result.reasons.join("; ") || `code graph is ${result.status}`,
|
|
136095
|
+
fix: "keryx gdgraph build"
|
|
136096
|
+
};
|
|
136097
|
+
}
|
|
136098
|
+
async function checkWikiFreshness(cwd) {
|
|
136099
|
+
const metric = await readWikiFreshnessMetric(cwd);
|
|
136100
|
+
if (metric.status === "measured") {
|
|
136101
|
+
const pct = metric.ratio !== undefined ? `${Math.round(metric.ratio * 100)}%` : "an unmeasured share";
|
|
136102
|
+
return {
|
|
136103
|
+
id: "wiki-freshness",
|
|
136104
|
+
status: "ok",
|
|
136105
|
+
detail: `${pct} of ${metric.pagesTotal ?? "?"} wiki page(s) fresh`
|
|
136106
|
+
};
|
|
136107
|
+
}
|
|
136108
|
+
return {
|
|
136109
|
+
id: "wiki-freshness",
|
|
136110
|
+
status: "warn",
|
|
136111
|
+
detail: metric.reason ?? `wiki freshness: ${metric.status}`,
|
|
136112
|
+
fix: "keryx wiki freshness"
|
|
136113
|
+
};
|
|
136114
|
+
}
|
|
136115
|
+
async function buildDoctorReport(cwd, env = process.env, overrides = {}) {
|
|
136116
|
+
const checks = await Promise.all([
|
|
136117
|
+
checkVersionAvailability(),
|
|
136118
|
+
Promise.resolve(checkBun(overrides.bunFloor)),
|
|
136119
|
+
Promise.resolve(checkRipgrep()),
|
|
136120
|
+
Promise.resolve(checkSandbox()),
|
|
136121
|
+
Promise.resolve(checkProviders(env)),
|
|
136122
|
+
Promise.resolve(checkMcp(cwd)),
|
|
136123
|
+
checkIntegrations(cwd),
|
|
136124
|
+
checkStandard(cwd),
|
|
136125
|
+
checkWorktrees(cwd),
|
|
136126
|
+
checkGraphFreshness(cwd),
|
|
136127
|
+
checkWikiFreshness(cwd)
|
|
136128
|
+
]);
|
|
136129
|
+
return { checks };
|
|
136130
|
+
}
|
|
136131
|
+
function doctorFailed(report) {
|
|
136132
|
+
return report.checks.some((check) => check.status === "fail");
|
|
136133
|
+
}
|
|
136134
|
+
function formatDoctorReport2(report) {
|
|
136135
|
+
const symbolFor = { ok: "\u2713", warn: "!", fail: "\u2717" };
|
|
136136
|
+
const lines = ["keryx doctor", ""];
|
|
136137
|
+
for (const check of report.checks) {
|
|
136138
|
+
lines.push(` ${symbolFor[check.status]} ${check.id}: ${check.detail}`);
|
|
136139
|
+
if (check.fix) {
|
|
136140
|
+
lines.push(` fix: ${check.fix}`);
|
|
136141
|
+
}
|
|
136142
|
+
}
|
|
136143
|
+
return lines.join(`
|
|
136144
|
+
`);
|
|
136145
|
+
}
|
|
136146
|
+
async function doctorCommand2(args = [], cwd = process.cwd(), overrides = {}) {
|
|
136147
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
136148
|
+
console.log(`keryx doctor [--json]
|
|
136149
|
+
|
|
136150
|
+
One page: keryx's own version and update availability, the Bun floor,
|
|
136151
|
+
ripgrep on PATH, the OS sandbox launcher, providers with a credential
|
|
136152
|
+
present (names only), MCP servers and their trust state, integrations
|
|
136153
|
+
drift, Metaproject Standard warnings, stale .claude/worktrees entries, and
|
|
136154
|
+
graph/wiki freshness. Exits 0 unless something is a "fail".`);
|
|
136155
|
+
return;
|
|
136156
|
+
}
|
|
136157
|
+
const report = await buildDoctorReport(cwd, process.env, overrides);
|
|
136158
|
+
if (args.includes("--json")) {
|
|
136159
|
+
console.log(JSON.stringify(report, null, 2));
|
|
136160
|
+
} else {
|
|
136161
|
+
console.log(formatDoctorReport2(report));
|
|
136162
|
+
}
|
|
136163
|
+
if (doctorFailed(report)) {
|
|
136164
|
+
process.exitCode = 1;
|
|
136165
|
+
}
|
|
136166
|
+
}
|
|
136167
|
+
|
|
135469
136168
|
// src/tui/tui-shell.ts
|
|
135470
136169
|
init_slate_lifecycle();
|
|
135471
136170
|
init_slate();
|
|
@@ -135478,7 +136177,7 @@ init_workspace_service();
|
|
|
135478
136177
|
init_service11();
|
|
135479
136178
|
init_store3();
|
|
135480
136179
|
init_fs();
|
|
135481
|
-
import
|
|
136180
|
+
import path303 from "path";
|
|
135482
136181
|
import { readFile as readFile157 } from "fs/promises";
|
|
135483
136182
|
var POSITIVE_INTEGER = /^[1-9][0-9]*$/;
|
|
135484
136183
|
var DEFAULT_AUTO_GOAL_ROUNDS = 8;
|
|
@@ -135554,7 +136253,7 @@ function getFlowService() {
|
|
|
135554
136253
|
async function autoProvisionFlow(cwd, goalText) {
|
|
135555
136254
|
const service = getFlowService();
|
|
135556
136255
|
const result = await service.init({ cwd, title: goalText });
|
|
135557
|
-
const acFile =
|
|
136256
|
+
const acFile = path303.join(cwd, result.dir, "acceptance-criteria.md");
|
|
135558
136257
|
await writeFileAtomic(acFile, [
|
|
135559
136258
|
"# Acceptance Criteria",
|
|
135560
136259
|
"",
|
|
@@ -137242,8 +137941,8 @@ init_store4();
|
|
|
137242
137941
|
init_proposal_lifecycle();
|
|
137243
137942
|
init_workspace_service();
|
|
137244
137943
|
import { randomUUID as randomUUID34 } from "crypto";
|
|
137245
|
-
import { readdir as
|
|
137246
|
-
import
|
|
137944
|
+
import { readdir as readdir54, stat as stat30 } from "fs/promises";
|
|
137945
|
+
import path304 from "path";
|
|
137247
137946
|
|
|
137248
137947
|
// src/sac/lifecycle-flag.ts
|
|
137249
137948
|
init_store();
|
|
@@ -137382,7 +138081,7 @@ async function readExternalUnboundCandidates(cwd) {
|
|
|
137382
138081
|
const extDir = externalSlatesDir(cwd);
|
|
137383
138082
|
let externalIds;
|
|
137384
138083
|
try {
|
|
137385
|
-
const entries = await
|
|
138084
|
+
const entries = await readdir54(extDir);
|
|
137386
138085
|
externalIds = entries.filter((name) => name.endsWith(".json")).map((name) => name.slice(0, -".json".length));
|
|
137387
138086
|
} catch {
|
|
137388
138087
|
return [];
|
|
@@ -137413,7 +138112,7 @@ async function readExternalUnboundCandidates(cwd) {
|
|
|
137413
138112
|
}
|
|
137414
138113
|
return groups;
|
|
137415
138114
|
}, []));
|
|
137416
|
-
const metaPath =
|
|
138115
|
+
const metaPath = path304.join(extDir, `${id}.json`);
|
|
137417
138116
|
if (await pathExists(unboundDismissedReceiptPath(metaPath)))
|
|
137418
138117
|
continue;
|
|
137419
138118
|
candidates.push({
|
|
@@ -137427,16 +138126,16 @@ async function readExternalUnboundCandidates(cwd) {
|
|
|
137427
138126
|
return candidates;
|
|
137428
138127
|
}
|
|
137429
138128
|
async function readNewestUnboundCandidateForExternal(cwd, externalSessionId) {
|
|
137430
|
-
const evidenceDir =
|
|
138129
|
+
const evidenceDir = path304.join(externalSlatesDir(cwd), externalSessionId);
|
|
137431
138130
|
let entries;
|
|
137432
138131
|
try {
|
|
137433
|
-
entries = (await
|
|
138132
|
+
entries = (await readdir54(evidenceDir)).filter((name) => name.endsWith("-unbound-candidate.json"));
|
|
137434
138133
|
} catch {
|
|
137435
138134
|
return;
|
|
137436
138135
|
}
|
|
137437
138136
|
entries.sort();
|
|
137438
138137
|
for (let i = entries.length - 1;i >= 0; i--) {
|
|
137439
|
-
const evidencePath =
|
|
138138
|
+
const evidencePath = path304.join(evidenceDir, entries[i]);
|
|
137440
138139
|
if (await pathExists(unboundDismissedReceiptPath(evidencePath)))
|
|
137441
138140
|
continue;
|
|
137442
138141
|
const result = readConfigFile(evidencePath);
|
|
@@ -137479,23 +138178,23 @@ var SESSION_ATTRIBUTION_SLACK_MS = 5 * 60000;
|
|
|
137479
138178
|
var MTIME_CLOCK_SKEW_TOLERANCE_MS = 5000;
|
|
137480
138179
|
async function collectReceiptTargets(cwd, owner) {
|
|
137481
138180
|
const targets = new Set;
|
|
137482
|
-
const workspacesDir =
|
|
138181
|
+
const workspacesDir = path304.join(cwd, ".metaproject", "workspaces");
|
|
137483
138182
|
let workspaceIds;
|
|
137484
138183
|
try {
|
|
137485
|
-
workspaceIds = (await
|
|
138184
|
+
workspaceIds = (await readdir54(workspacesDir, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
|
|
137486
138185
|
} catch {
|
|
137487
138186
|
return targets;
|
|
137488
138187
|
}
|
|
137489
138188
|
for (const workspaceId of workspaceIds) {
|
|
137490
|
-
const receiptsDir =
|
|
138189
|
+
const receiptsDir = path304.join(workspacesDir, workspaceId, `${owner}-write-receipts`);
|
|
137491
138190
|
let files;
|
|
137492
138191
|
try {
|
|
137493
|
-
files = (await
|
|
138192
|
+
files = (await readdir54(receiptsDir)).filter((name) => name.endsWith(".json"));
|
|
137494
138193
|
} catch {
|
|
137495
138194
|
continue;
|
|
137496
138195
|
}
|
|
137497
138196
|
for (const file of files) {
|
|
137498
|
-
const result = readConfigFile(
|
|
138197
|
+
const result = readConfigFile(path304.join(receiptsDir, file));
|
|
137499
138198
|
if (!result.ok)
|
|
137500
138199
|
continue;
|
|
137501
138200
|
try {
|
|
@@ -137532,13 +138231,13 @@ async function attributeToSession(absolutePath, sessionsNewestFirst) {
|
|
|
137532
138231
|
async function findSkillFiles(dir) {
|
|
137533
138232
|
let entries;
|
|
137534
138233
|
try {
|
|
137535
|
-
entries = await
|
|
138234
|
+
entries = await readdir54(dir, { withFileTypes: true });
|
|
137536
138235
|
} catch {
|
|
137537
138236
|
return [];
|
|
137538
138237
|
}
|
|
137539
138238
|
const found = [];
|
|
137540
138239
|
for (const entry of entries) {
|
|
137541
|
-
const full =
|
|
138240
|
+
const full = path304.join(dir, entry.name);
|
|
137542
138241
|
if (entry.isDirectory()) {
|
|
137543
138242
|
found.push(...await findSkillFiles(full));
|
|
137544
138243
|
} else if (entry.isFile() && entry.name === "SKILL.md") {
|
|
@@ -137597,10 +138296,10 @@ async function detectUnreviewedSacPathChanges(cwd, sessions) {
|
|
|
137597
138296
|
changedAt: attribution.changedAt
|
|
137598
138297
|
});
|
|
137599
138298
|
}
|
|
137600
|
-
const sacSkillsDir =
|
|
138299
|
+
const sacSkillsDir = path304.join(cwd, ".metaproject", "project-skills", "sac");
|
|
137601
138300
|
const skillFiles = await findSkillFiles(sacSkillsDir);
|
|
137602
138301
|
for (const absolutePath of skillFiles) {
|
|
137603
|
-
const targetRef =
|
|
138302
|
+
const targetRef = path304.relative(path304.join(cwd, ".metaproject"), absolutePath).split(path304.sep).join("/");
|
|
137604
138303
|
if (skillReceipts.has(targetRef))
|
|
137605
138304
|
continue;
|
|
137606
138305
|
const attribution = await attributeToSession(absolutePath, scoped);
|
|
@@ -137618,12 +138317,12 @@ async function detectUnreviewedSacPathChanges(cwd, sessions) {
|
|
|
137618
138317
|
return items;
|
|
137619
138318
|
}
|
|
137620
138319
|
async function isSlateEngaged(dir) {
|
|
137621
|
-
if (await pathExists(
|
|
138320
|
+
if (await pathExists(path304.join(dir, "slate.json")))
|
|
137622
138321
|
return true;
|
|
137623
|
-
if (await pathExists(
|
|
138322
|
+
if (await pathExists(path304.join(dir, "terminal-state.json")))
|
|
137624
138323
|
return true;
|
|
137625
138324
|
try {
|
|
137626
|
-
const entries = await
|
|
138325
|
+
const entries = await readdir54(path304.join(dir, "slate-archive"));
|
|
137627
138326
|
return entries.length > 0;
|
|
137628
138327
|
} catch {
|
|
137629
138328
|
return false;
|
|
@@ -137648,7 +138347,7 @@ async function safeReadSlate(dir) {
|
|
|
137648
138347
|
}
|
|
137649
138348
|
}
|
|
137650
138349
|
async function readTerminalState(dir) {
|
|
137651
|
-
const result = readConfigFile(
|
|
138350
|
+
const result = readConfigFile(path304.join(dir, "terminal-state.json"));
|
|
137652
138351
|
if (!result.ok) {
|
|
137653
138352
|
return;
|
|
137654
138353
|
}
|
|
@@ -137672,17 +138371,17 @@ async function resolveUnboundCandidateTarget(cwd, target) {
|
|
|
137672
138371
|
if (session === undefined) {
|
|
137673
138372
|
throw new Error(`No session or evidence path matches "${target}"`);
|
|
137674
138373
|
}
|
|
137675
|
-
const archiveDir =
|
|
138374
|
+
const archiveDir = path304.join(sessionDir(session.projectPath, session.id), "slate-archive");
|
|
137676
138375
|
let entries;
|
|
137677
138376
|
try {
|
|
137678
|
-
entries = (await
|
|
138377
|
+
entries = (await readdir54(archiveDir)).filter((name) => name.endsWith("-unbound-candidate.json"));
|
|
137679
138378
|
} catch {
|
|
137680
138379
|
throw new Error(`No unbound-candidate artifacts for session ${session.id}`);
|
|
137681
138380
|
}
|
|
137682
138381
|
if (entries.length === 0)
|
|
137683
138382
|
throw new Error(`No unbound-candidate artifacts for session ${session.id}`);
|
|
137684
138383
|
entries.sort();
|
|
137685
|
-
return
|
|
138384
|
+
return path304.join(archiveDir, entries[entries.length - 1]);
|
|
137686
138385
|
}
|
|
137687
138386
|
async function dismissUnboundByTarget(cwd, target, reason) {
|
|
137688
138387
|
const evidencePath = await resolveUnboundCandidateTarget(cwd, target);
|
|
@@ -137708,16 +138407,16 @@ async function dismissUnboundCandidate(candidatePath, reason) {
|
|
|
137708
138407
|
return { removed: candidatePath, receipt: receiptPath };
|
|
137709
138408
|
}
|
|
137710
138409
|
async function readNewestUnboundCandidate(dir) {
|
|
137711
|
-
const archiveDir =
|
|
138410
|
+
const archiveDir = path304.join(dir, "slate-archive");
|
|
137712
138411
|
let entries;
|
|
137713
138412
|
try {
|
|
137714
|
-
entries = (await
|
|
138413
|
+
entries = (await readdir54(archiveDir)).filter((name) => name.endsWith("-unbound-candidate.json"));
|
|
137715
138414
|
} catch {
|
|
137716
138415
|
return;
|
|
137717
138416
|
}
|
|
137718
138417
|
entries.sort();
|
|
137719
138418
|
for (let i = entries.length - 1;i >= 0; i--) {
|
|
137720
|
-
const evidencePath =
|
|
138419
|
+
const evidencePath = path304.join(archiveDir, entries[i]);
|
|
137721
138420
|
if (await pathExists(unboundDismissedReceiptPath(evidencePath)))
|
|
137722
138421
|
continue;
|
|
137723
138422
|
const result = readConfigFile(evidencePath);
|
|
@@ -137747,16 +138446,16 @@ function isFailureOutcome2(g) {
|
|
|
137747
138446
|
return g.outcome === "error" || g.outcome === "no_credential" || g.outcome === "conflict";
|
|
137748
138447
|
}
|
|
137749
138448
|
async function readNewestWrapUpOutcome(dir) {
|
|
137750
|
-
const archiveDir =
|
|
138449
|
+
const archiveDir = path304.join(dir, "slate-archive");
|
|
137751
138450
|
let entries;
|
|
137752
138451
|
try {
|
|
137753
|
-
entries = (await
|
|
138452
|
+
entries = (await readdir54(archiveDir)).filter((name) => name.endsWith("-wrap-up-outcome.json"));
|
|
137754
138453
|
} catch {
|
|
137755
138454
|
return;
|
|
137756
138455
|
}
|
|
137757
138456
|
entries.sort();
|
|
137758
138457
|
for (let i = entries.length - 1;i >= 0; i--) {
|
|
137759
|
-
const evidencePath =
|
|
138458
|
+
const evidencePath = path304.join(archiveDir, entries[i]);
|
|
137760
138459
|
const result = readConfigFile(evidencePath);
|
|
137761
138460
|
if (!result.ok) {
|
|
137762
138461
|
continue;
|
|
@@ -138363,6 +139062,11 @@ var AGENT_SLASH_COMMANDS = [
|
|
|
138363
139062
|
modes: BOTH
|
|
138364
139063
|
},
|
|
138365
139064
|
{ name: "/flows", description: "Browse project flows and inspect one", modes: BOTH },
|
|
139065
|
+
{
|
|
139066
|
+
name: "/doctor",
|
|
139067
|
+
description: "One-page health check: version, sandbox, providers, MCP, integrations, freshness",
|
|
139068
|
+
modes: BOTH
|
|
139069
|
+
},
|
|
138366
139070
|
{
|
|
138367
139071
|
name: "/ac",
|
|
138368
139072
|
description: "Check the active flow's acceptance criteria (advisory, cached) \u2014 press `c` in /flows to re-check",
|
|
@@ -138705,7 +139409,7 @@ function classifyBusyDispatch(params) {
|
|
|
138705
139409
|
init_fs();
|
|
138706
139410
|
init_json();
|
|
138707
139411
|
import { mkdir as mkdir67 } from "fs/promises";
|
|
138708
|
-
import
|
|
139412
|
+
import path306 from "path";
|
|
138709
139413
|
|
|
138710
139414
|
// src/governance/aggregate.ts
|
|
138711
139415
|
init_store3();
|
|
@@ -138713,17 +139417,17 @@ init_store3();
|
|
|
138713
139417
|
// src/governance/spend.ts
|
|
138714
139418
|
init_fs();
|
|
138715
139419
|
init_store3();
|
|
138716
|
-
import { readdir as
|
|
138717
|
-
import
|
|
139420
|
+
import { readdir as readdir55, readFile as readFile158 } from "fs/promises";
|
|
139421
|
+
import path305 from "path";
|
|
138718
139422
|
async function readFlowReviewManifests(cwd, flowDir) {
|
|
138719
|
-
const reviewsDir =
|
|
139423
|
+
const reviewsDir = path305.join(flowsRoot(cwd), flowDir, "reviews");
|
|
138720
139424
|
if (!await pathExists(reviewsDir)) {
|
|
138721
139425
|
return [];
|
|
138722
139426
|
}
|
|
138723
|
-
const entries = (await
|
|
139427
|
+
const entries = (await readdir55(reviewsDir, { withFileTypes: true })).filter((entry) => entry.isDirectory());
|
|
138724
139428
|
const manifests = [];
|
|
138725
139429
|
for (const entry of entries) {
|
|
138726
|
-
const manifestPath =
|
|
139430
|
+
const manifestPath = path305.join(reviewsDir, entry.name, "manifest.json");
|
|
138727
139431
|
if (!await pathExists(manifestPath)) {
|
|
138728
139432
|
continue;
|
|
138729
139433
|
}
|
|
@@ -138970,11 +139674,11 @@ async function collectProjectGovernance(root, filters, displayName) {
|
|
|
138970
139674
|
// src/governance/report.ts
|
|
138971
139675
|
var GOVERNANCE_SCHEMA_VERSION = 1;
|
|
138972
139676
|
function governanceDataRoot(cwd) {
|
|
138973
|
-
return
|
|
139677
|
+
return path306.join(cwd, ".metaproject", "data", "governance");
|
|
138974
139678
|
}
|
|
138975
139679
|
function artifactPaths(cwd) {
|
|
138976
|
-
const artifacts =
|
|
138977
|
-
return { markdown:
|
|
139680
|
+
const artifacts = path306.join(governanceDataRoot(cwd), "artifacts");
|
|
139681
|
+
return { markdown: path306.join(artifacts, "latest.md"), json: path306.join(artifacts, "latest.json") };
|
|
138978
139682
|
}
|
|
138979
139683
|
async function buildGovernanceReport(options) {
|
|
138980
139684
|
const { cwd, filters, allProjects, now } = options;
|
|
@@ -138982,9 +139686,9 @@ async function buildGovernanceReport(options) {
|
|
|
138982
139686
|
if (allProjects) {
|
|
138983
139687
|
const warnings = [];
|
|
138984
139688
|
const registered = listProjects(options.registryDir, (message) => warnings.push(message));
|
|
138985
|
-
const seen = new Set([
|
|
139689
|
+
const seen = new Set([path306.resolve(cwd)]);
|
|
138986
139690
|
for (const entry of registered) {
|
|
138987
|
-
const resolved =
|
|
139691
|
+
const resolved = path306.resolve(entry.path);
|
|
138988
139692
|
if (seen.has(resolved)) {
|
|
138989
139693
|
continue;
|
|
138990
139694
|
}
|
|
@@ -139137,7 +139841,7 @@ function renderTriggerSpendLine(spend) {
|
|
|
139137
139841
|
}
|
|
139138
139842
|
async function writeGovernanceArtifacts(cwd, report) {
|
|
139139
139843
|
const { markdown, json } = artifactPaths(cwd);
|
|
139140
|
-
await mkdir67(
|
|
139844
|
+
await mkdir67(path306.dirname(markdown), { recursive: true });
|
|
139141
139845
|
await writeFileAtomic(markdown, renderGovernanceMarkdown(report));
|
|
139142
139846
|
await writeFileAtomic(json, `${JSON.stringify(report, null, 2)}
|
|
139143
139847
|
`);
|
|
@@ -139342,7 +140046,7 @@ function mountGovernancePanel(otui, renderer, parent, options) {
|
|
|
139342
140046
|
|
|
139343
140047
|
// src/tui/governance-inspector.ts
|
|
139344
140048
|
import { readFile as readFile159 } from "fs/promises";
|
|
139345
|
-
import
|
|
140049
|
+
import path307 from "path";
|
|
139346
140050
|
var GOVERNANCE_COMMAND = "/governance";
|
|
139347
140051
|
var GOVERNANCE_FOOTER = [
|
|
139348
140052
|
{ key: "\u2191/\u2193 j/k", label: "scroll" },
|
|
@@ -139353,7 +140057,7 @@ var GOVERNANCE_FOOTER = [
|
|
|
139353
140057
|
var HEADER_TEXT_ROWS = 2;
|
|
139354
140058
|
var GOVERNANCE_HEADER_ROWS = HEADER_TEXT_ROWS + 1;
|
|
139355
140059
|
function governanceMarkdownPath(cwd) {
|
|
139356
|
-
return
|
|
140060
|
+
return path307.join(governanceDataRoot(cwd), "artifacts", "latest.md");
|
|
139357
140061
|
}
|
|
139358
140062
|
async function defaultReadMarkdown(cwd) {
|
|
139359
140063
|
try {
|
|
@@ -139498,7 +140202,7 @@ function openGovernanceReport(otui, chrome, options) {
|
|
|
139498
140202
|
|
|
139499
140203
|
// src/tui/trigger-ledger.ts
|
|
139500
140204
|
import { stat as fsStat2 } from "fs/promises";
|
|
139501
|
-
import
|
|
140205
|
+
import path308 from "path";
|
|
139502
140206
|
var DEFAULT_RECORDS_PER_ENTRY = 20;
|
|
139503
140207
|
function isScheduledEntry(entry) {
|
|
139504
140208
|
return entry.fire.kind === "schedule";
|
|
@@ -139557,7 +140261,7 @@ function triggerLedgerPaths(root) {
|
|
|
139557
140261
|
return {
|
|
139558
140262
|
runs: triggerRunsPath(root),
|
|
139559
140263
|
triggers: triggersConfigPath(root),
|
|
139560
|
-
governance:
|
|
140264
|
+
governance: path308.join(governanceDataRoot(root), "artifacts", "latest.json"),
|
|
139561
140265
|
schedules: scheduleStorePath(root)
|
|
139562
140266
|
};
|
|
139563
140267
|
}
|
|
@@ -140130,7 +140834,7 @@ function openTriggers(otui, chrome, options) {
|
|
|
140130
140834
|
// src/tui/trigger-run-now.ts
|
|
140131
140835
|
import { spawn as nodeSpawn2 } from "child_process";
|
|
140132
140836
|
import { closeSync as closeSync5, constants as constants3, fstatSync as fstatSync3, lstatSync as lstatSync6, mkdirSync as mkdirSync7, openSync as openSync5, readdirSync as readdirSync10, readSync as readSync3, unlinkSync as unlinkSync4, writeSync } from "fs";
|
|
140133
|
-
import
|
|
140837
|
+
import path309 from "path";
|
|
140134
140838
|
var OUTPUT_TAIL_CHARS = 4000;
|
|
140135
140839
|
var defaultSpawn = (command, args, options) => nodeSpawn2(command, [...args], { cwd: options.cwd, env: options.env, detached: true, stdio: [...options.stdio] });
|
|
140136
140840
|
function triggerRunArgv(name, invocation = resolveKeryxInvocation(), options = {}) {
|
|
@@ -140145,7 +140849,7 @@ function runNowChildEnv(env) {
|
|
|
140145
140849
|
return out;
|
|
140146
140850
|
}
|
|
140147
140851
|
function runNowLogDir(root) {
|
|
140148
|
-
return
|
|
140852
|
+
return path309.join(triggerDataDir(root), "run-now");
|
|
140149
140853
|
}
|
|
140150
140854
|
var RUN_NOW_LOGS_KEPT = 5;
|
|
140151
140855
|
var OUTPUT_TAIL_BYTES = 16 * 1024;
|
|
@@ -140153,13 +140857,13 @@ function stampOf(iso) {
|
|
|
140153
140857
|
return iso.replace(/[:.]/g, "-");
|
|
140154
140858
|
}
|
|
140155
140859
|
function runNowLogPath(root, name, startedAt) {
|
|
140156
|
-
return
|
|
140860
|
+
return path309.join(runNowLogDir(root), `${name}-${stampOf(startedAt)}.log`);
|
|
140157
140861
|
}
|
|
140158
140862
|
function isCode(error, code) {
|
|
140159
140863
|
return typeof error === "object" && error !== null && "code" in error && error.code === code;
|
|
140160
140864
|
}
|
|
140161
140865
|
function prepareRunNowLogDir(root) {
|
|
140162
|
-
mkdirSync7(
|
|
140866
|
+
mkdirSync7(path309.join(root, ".metaproject", "data"), { recursive: true });
|
|
140163
140867
|
for (const segment of [triggerDataDir(root), runNowLogDir(root)]) {
|
|
140164
140868
|
let info;
|
|
140165
140869
|
try {
|
|
@@ -140178,7 +140882,7 @@ function prepareRunNowLogDir(root) {
|
|
|
140178
140882
|
}
|
|
140179
140883
|
const dir = runNowLogDir(root);
|
|
140180
140884
|
try {
|
|
140181
|
-
const fd = openSync5(
|
|
140885
|
+
const fd = openSync5(path309.join(dir, ".gitignore"), constants3.O_WRONLY | constants3.O_CREAT | constants3.O_EXCL | (constants3.O_NOFOLLOW ?? 0), 420);
|
|
140182
140886
|
try {
|
|
140183
140887
|
writeSync(fd, `# keryx run-now logs \u2014 never commit
|
|
140184
140888
|
*
|
|
@@ -140219,7 +140923,7 @@ function pruneRunLogs(dir, name, keep) {
|
|
|
140219
140923
|
}
|
|
140220
140924
|
for (const old of names.slice(0, Math.max(0, names.length - keep))) {
|
|
140221
140925
|
try {
|
|
140222
|
-
unlinkSync4(
|
|
140926
|
+
unlinkSync4(path309.join(dir, old));
|
|
140223
140927
|
} catch {}
|
|
140224
140928
|
}
|
|
140225
140929
|
}
|
|
@@ -141237,279 +141941,6 @@ function mountSchedulesSidebar(options) {
|
|
|
141237
141941
|
// src/tui/tui-shell.ts
|
|
141238
141942
|
init_debug_log();
|
|
141239
141943
|
|
|
141240
|
-
// src/lib/version-check.ts
|
|
141241
|
-
init_config_dir();
|
|
141242
|
-
init_fs();
|
|
141243
|
-
import path308 from "path";
|
|
141244
|
-
var REGISTRY_URL = "https://registry.npmjs.org/@mrciphersmith%2Fkeryx/latest";
|
|
141245
|
-
var FIXED_INSTALL_COMMAND = "npm install -g @mrciphersmith/keryx@latest";
|
|
141246
|
-
var RESPONSE_BODY_LIMIT_BYTES = 64 * 1024;
|
|
141247
|
-
var VERSION_STRING_LIMIT_CHARS = 64;
|
|
141248
|
-
var REQUEST_TIMEOUT_MS = 2000;
|
|
141249
|
-
var SUCCESS_CACHE_TTL_MS = 24 * 60 * 60 * 1000;
|
|
141250
|
-
var FAILURE_BACKOFF_MS = 15 * 60 * 1000;
|
|
141251
|
-
var CACHE_LOCK_TIMEOUT_MS2 = 250;
|
|
141252
|
-
var CACHE_LOCK_RETRY_MS2 = 10;
|
|
141253
|
-
var CACHE_LOCK_STALE_MS2 = 5000;
|
|
141254
|
-
var SYSTEM_TIMER = {
|
|
141255
|
-
schedule: (callback, delayMs) => setTimeout(callback, delayMs),
|
|
141256
|
-
cancel: (handle) => clearTimeout(handle)
|
|
141257
|
-
};
|
|
141258
|
-
function formatVersionUpdateAdvisory(result) {
|
|
141259
|
-
if (result.status !== "update-available")
|
|
141260
|
-
return;
|
|
141261
|
-
return `Keryx update ${result.currentVersion} \u2192 ${result.latestVersion}
|
|
141262
|
-
${result.installCommand}`;
|
|
141263
|
-
}
|
|
141264
|
-
var STRICT_SEMVER = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/;
|
|
141265
|
-
function parseSemVer(value) {
|
|
141266
|
-
if (value.length > VERSION_STRING_LIMIT_CHARS)
|
|
141267
|
-
return;
|
|
141268
|
-
const match = STRICT_SEMVER.exec(value);
|
|
141269
|
-
if (match === null)
|
|
141270
|
-
return;
|
|
141271
|
-
const prereleaseText = match[4];
|
|
141272
|
-
const prerelease = [];
|
|
141273
|
-
if (prereleaseText !== undefined) {
|
|
141274
|
-
for (const identifier of prereleaseText.split(".")) {
|
|
141275
|
-
if (/^\d+$/.test(identifier)) {
|
|
141276
|
-
if (identifier.length > 1 && identifier.startsWith("0"))
|
|
141277
|
-
return;
|
|
141278
|
-
prerelease.push(BigInt(identifier));
|
|
141279
|
-
} else {
|
|
141280
|
-
prerelease.push(identifier);
|
|
141281
|
-
}
|
|
141282
|
-
}
|
|
141283
|
-
}
|
|
141284
|
-
return {
|
|
141285
|
-
major: BigInt(match[1]),
|
|
141286
|
-
minor: BigInt(match[2]),
|
|
141287
|
-
patch: BigInt(match[3]),
|
|
141288
|
-
prerelease
|
|
141289
|
-
};
|
|
141290
|
-
}
|
|
141291
|
-
function compareSemVer(left, right) {
|
|
141292
|
-
for (const key of ["major", "minor", "patch"]) {
|
|
141293
|
-
if (left[key] < right[key])
|
|
141294
|
-
return -1;
|
|
141295
|
-
if (left[key] > right[key])
|
|
141296
|
-
return 1;
|
|
141297
|
-
}
|
|
141298
|
-
if (left.prerelease.length === 0 || right.prerelease.length === 0) {
|
|
141299
|
-
if (left.prerelease.length === right.prerelease.length)
|
|
141300
|
-
return 0;
|
|
141301
|
-
return left.prerelease.length === 0 ? 1 : -1;
|
|
141302
|
-
}
|
|
141303
|
-
const length = Math.max(left.prerelease.length, right.prerelease.length);
|
|
141304
|
-
for (let index = 0;index < length; index += 1) {
|
|
141305
|
-
const a = left.prerelease[index];
|
|
141306
|
-
const b = right.prerelease[index];
|
|
141307
|
-
if (a === undefined || b === undefined) {
|
|
141308
|
-
if (a === b)
|
|
141309
|
-
return 0;
|
|
141310
|
-
return a === undefined ? -1 : 1;
|
|
141311
|
-
}
|
|
141312
|
-
if (typeof a === "bigint" && typeof b === "bigint") {
|
|
141313
|
-
if (a < b)
|
|
141314
|
-
return -1;
|
|
141315
|
-
if (a > b)
|
|
141316
|
-
return 1;
|
|
141317
|
-
} else if (typeof a === "bigint") {
|
|
141318
|
-
return -1;
|
|
141319
|
-
} else if (typeof b === "bigint") {
|
|
141320
|
-
return 1;
|
|
141321
|
-
} else if (a !== b) {
|
|
141322
|
-
return a < b ? -1 : 1;
|
|
141323
|
-
}
|
|
141324
|
-
}
|
|
141325
|
-
return 0;
|
|
141326
|
-
}
|
|
141327
|
-
function parseCache(file) {
|
|
141328
|
-
const read = readConfigFile(file);
|
|
141329
|
-
if (!read.ok)
|
|
141330
|
-
return;
|
|
141331
|
-
try {
|
|
141332
|
-
const value = JSON.parse(read.text);
|
|
141333
|
-
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
141334
|
-
return;
|
|
141335
|
-
const record = value;
|
|
141336
|
-
const cache = {};
|
|
141337
|
-
if (typeof record.latestVersion === "string" && parseSemVer(record.latestVersion) !== undefined) {
|
|
141338
|
-
cache.latestVersion = record.latestVersion;
|
|
141339
|
-
}
|
|
141340
|
-
if (typeof record.successAt === "number" && Number.isFinite(record.successAt))
|
|
141341
|
-
cache.successAt = record.successAt;
|
|
141342
|
-
if (typeof record.failureAt === "number" && Number.isFinite(record.failureAt))
|
|
141343
|
-
cache.failureAt = record.failureAt;
|
|
141344
|
-
return cache;
|
|
141345
|
-
} catch {
|
|
141346
|
-
return;
|
|
141347
|
-
}
|
|
141348
|
-
}
|
|
141349
|
-
function resultFor(currentVersion, current, latestVersion, source) {
|
|
141350
|
-
const latest = parseSemVer(latestVersion);
|
|
141351
|
-
return compareSemVer(current, latest) < 0 ? { status: "update-available", currentVersion, latestVersion, installCommand: FIXED_INSTALL_COMMAND, source } : { status: "up-to-date", currentVersion, latestVersion, source };
|
|
141352
|
-
}
|
|
141353
|
-
function cancelWithoutWaiting(cancel) {
|
|
141354
|
-
try {
|
|
141355
|
-
cancel().catch(() => {});
|
|
141356
|
-
} catch {}
|
|
141357
|
-
}
|
|
141358
|
-
async function boundedResponseText(response) {
|
|
141359
|
-
const declared = response.headers.get("content-length");
|
|
141360
|
-
if (declared !== null && /^\d+$/.test(declared) && BigInt(declared) > BigInt(RESPONSE_BODY_LIMIT_BYTES)) {
|
|
141361
|
-
if (response.body !== null) {
|
|
141362
|
-
cancelWithoutWaiting(() => response.body.cancel());
|
|
141363
|
-
}
|
|
141364
|
-
return;
|
|
141365
|
-
}
|
|
141366
|
-
if (response.body === null)
|
|
141367
|
-
return "";
|
|
141368
|
-
const reader = response.body.getReader();
|
|
141369
|
-
const decoder = new TextDecoder;
|
|
141370
|
-
let size = 0;
|
|
141371
|
-
let text = "";
|
|
141372
|
-
try {
|
|
141373
|
-
for (;; ) {
|
|
141374
|
-
const chunk = await reader.read();
|
|
141375
|
-
if (chunk.done)
|
|
141376
|
-
break;
|
|
141377
|
-
size += chunk.value.byteLength;
|
|
141378
|
-
if (size > RESPONSE_BODY_LIMIT_BYTES) {
|
|
141379
|
-
cancelWithoutWaiting(() => reader.cancel());
|
|
141380
|
-
return;
|
|
141381
|
-
}
|
|
141382
|
-
text += decoder.decode(chunk.value, { stream: true });
|
|
141383
|
-
}
|
|
141384
|
-
return text + decoder.decode();
|
|
141385
|
-
} finally {
|
|
141386
|
-
reader.releaseLock();
|
|
141387
|
-
}
|
|
141388
|
-
}
|
|
141389
|
-
function unavailable(currentVersion, reason, cache) {
|
|
141390
|
-
return {
|
|
141391
|
-
status: "unavailable",
|
|
141392
|
-
currentVersion,
|
|
141393
|
-
reason,
|
|
141394
|
-
...cache?.latestVersion !== undefined ? { cachedLatestVersion: cache.latestVersion } : {}
|
|
141395
|
-
};
|
|
141396
|
-
}
|
|
141397
|
-
function saveCache2(file, cache) {
|
|
141398
|
-
try {
|
|
141399
|
-
writeOwnerOnlyFileAtomic(file, `${JSON.stringify(cache, null, 2)}
|
|
141400
|
-
`);
|
|
141401
|
-
return true;
|
|
141402
|
-
} catch {
|
|
141403
|
-
return false;
|
|
141404
|
-
}
|
|
141405
|
-
}
|
|
141406
|
-
function mergeSuccessfulCache(committed, latestVersion, successAt) {
|
|
141407
|
-
if (committed.latestVersion === undefined || committed.successAt === undefined) {
|
|
141408
|
-
return { latestVersion, successAt };
|
|
141409
|
-
}
|
|
141410
|
-
if (committed.successAt > successAt)
|
|
141411
|
-
return committed;
|
|
141412
|
-
if (committed.successAt < successAt)
|
|
141413
|
-
return { latestVersion, successAt };
|
|
141414
|
-
const committedVersion = parseSemVer(committed.latestVersion);
|
|
141415
|
-
const candidateVersion = parseSemVer(latestVersion);
|
|
141416
|
-
if (committedVersion !== undefined && candidateVersion !== undefined) {
|
|
141417
|
-
const precedence = compareSemVer(committedVersion, candidateVersion);
|
|
141418
|
-
if (precedence > 0)
|
|
141419
|
-
return committed;
|
|
141420
|
-
if (precedence < 0)
|
|
141421
|
-
return { latestVersion, successAt };
|
|
141422
|
-
if (committed.latestVersion >= latestVersion)
|
|
141423
|
-
return committed;
|
|
141424
|
-
}
|
|
141425
|
-
return { latestVersion, successAt };
|
|
141426
|
-
}
|
|
141427
|
-
async function updateCache(file, update) {
|
|
141428
|
-
try {
|
|
141429
|
-
return await withFileLock(`${file}.lock`, async () => saveCache2(file, update(parseCache(file) ?? {})), {
|
|
141430
|
-
timeoutMs: CACHE_LOCK_TIMEOUT_MS2,
|
|
141431
|
-
retryMs: CACHE_LOCK_RETRY_MS2,
|
|
141432
|
-
staleMs: CACHE_LOCK_STALE_MS2
|
|
141433
|
-
});
|
|
141434
|
-
} catch {
|
|
141435
|
-
return false;
|
|
141436
|
-
}
|
|
141437
|
-
}
|
|
141438
|
-
async function checkVersion(options) {
|
|
141439
|
-
const current = parseSemVer(options.currentVersion);
|
|
141440
|
-
if (current === undefined)
|
|
141441
|
-
return unavailable(options.currentVersion, "invalid-current-version");
|
|
141442
|
-
const now = options.now ?? Date.now;
|
|
141443
|
-
const timestamp = now();
|
|
141444
|
-
const configDir = ensureKeryxConfigDir(options.cacheDir);
|
|
141445
|
-
const cacheFile = path308.join(configDir, "version-check.json");
|
|
141446
|
-
const cache = parseCache(cacheFile);
|
|
141447
|
-
if (cache?.latestVersion !== undefined && cache.successAt !== undefined && timestamp - cache.successAt >= 0 && timestamp - cache.successAt < SUCCESS_CACHE_TTL_MS) {
|
|
141448
|
-
return resultFor(options.currentVersion, current, cache.latestVersion, "cache");
|
|
141449
|
-
}
|
|
141450
|
-
if (cache?.failureAt !== undefined && timestamp - cache.failureAt >= 0 && timestamp - cache.failureAt < FAILURE_BACKOFF_MS) {
|
|
141451
|
-
return unavailable(options.currentVersion, "suppressed", cache);
|
|
141452
|
-
}
|
|
141453
|
-
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
141454
|
-
const controller = new AbortController;
|
|
141455
|
-
const timer = options.timer ?? SYSTEM_TIMER;
|
|
141456
|
-
let timeout;
|
|
141457
|
-
let timeoutScheduled = false;
|
|
141458
|
-
let failure;
|
|
141459
|
-
let latestVersion;
|
|
141460
|
-
try {
|
|
141461
|
-
timeout = timer.schedule(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
141462
|
-
timeoutScheduled = true;
|
|
141463
|
-
const response = await fetchImpl(REGISTRY_URL, {
|
|
141464
|
-
method: "GET",
|
|
141465
|
-
headers: { accept: "application/json" },
|
|
141466
|
-
signal: controller.signal,
|
|
141467
|
-
credentials: "omit"
|
|
141468
|
-
});
|
|
141469
|
-
if (!response.ok) {
|
|
141470
|
-
failure = "http";
|
|
141471
|
-
} else {
|
|
141472
|
-
const body = await boundedResponseText(response);
|
|
141473
|
-
if (body === undefined) {
|
|
141474
|
-
failure = "response-too-large";
|
|
141475
|
-
} else {
|
|
141476
|
-
let parsed;
|
|
141477
|
-
try {
|
|
141478
|
-
parsed = JSON.parse(body);
|
|
141479
|
-
} catch {
|
|
141480
|
-
parsed = undefined;
|
|
141481
|
-
}
|
|
141482
|
-
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
141483
|
-
failure = "malformed-response";
|
|
141484
|
-
} else {
|
|
141485
|
-
const record = parsed;
|
|
141486
|
-
if (record.name !== "@mrciphersmith/keryx" || typeof record.version !== "string") {
|
|
141487
|
-
failure = "malformed-response";
|
|
141488
|
-
} else if (parseSemVer(record.version) === undefined) {
|
|
141489
|
-
failure = "invalid-latest-version";
|
|
141490
|
-
} else {
|
|
141491
|
-
latestVersion = record.version;
|
|
141492
|
-
}
|
|
141493
|
-
}
|
|
141494
|
-
}
|
|
141495
|
-
}
|
|
141496
|
-
} catch {
|
|
141497
|
-
failure = controller.signal.aborted ? "timeout" : "network";
|
|
141498
|
-
} finally {
|
|
141499
|
-
if (timeoutScheduled) {
|
|
141500
|
-
try {
|
|
141501
|
-
timer.cancel(timeout);
|
|
141502
|
-
} catch {}
|
|
141503
|
-
}
|
|
141504
|
-
}
|
|
141505
|
-
if (latestVersion === undefined) {
|
|
141506
|
-
await updateCache(cacheFile, (committed) => ({ ...committed, failureAt: timestamp }));
|
|
141507
|
-
return unavailable(options.currentVersion, failure ?? "network", cache);
|
|
141508
|
-
}
|
|
141509
|
-
await updateCache(cacheFile, (committed) => mergeSuccessfulCache(committed, latestVersion, timestamp));
|
|
141510
|
-
return resultFor(options.currentVersion, current, latestVersion, "registry");
|
|
141511
|
-
}
|
|
141512
|
-
|
|
141513
141944
|
// src/tui/shell-chrome.ts
|
|
141514
141945
|
init_debug_log();
|
|
141515
141946
|
|
|
@@ -143813,7 +144244,7 @@ init_model_tier();
|
|
|
143813
144244
|
init_config_dir();
|
|
143814
144245
|
init_fs();
|
|
143815
144246
|
init_table();
|
|
143816
|
-
import
|
|
144247
|
+
import path310 from "path";
|
|
143817
144248
|
var UNCATEGORIZED = "uncategorized";
|
|
143818
144249
|
var EMPTY_TASK_COST_STORE = {};
|
|
143819
144250
|
var MIN_MEASURED_TASKS = 20;
|
|
@@ -143879,7 +144310,7 @@ var TASK_COST_LOCK_TIMEOUT_MS = 3000;
|
|
|
143879
144310
|
var TASK_COST_LOCK_RETRY_MS = 15;
|
|
143880
144311
|
var TASK_COST_LOCK_STALE_MS = 1e4;
|
|
143881
144312
|
function taskCostFilePath(dir) {
|
|
143882
|
-
return
|
|
144313
|
+
return path310.join(ensureKeryxSubdir(["routing"], dir), TASK_COST_FILE);
|
|
143883
144314
|
}
|
|
143884
144315
|
function isTaskCostRecord(value) {
|
|
143885
144316
|
if (typeof value !== "object" || value === null)
|
|
@@ -144943,11 +145374,11 @@ function openConform(otui, chrome, options) {
|
|
|
144943
145374
|
}
|
|
144944
145375
|
|
|
144945
145376
|
// src/tui/conform-source.ts
|
|
144946
|
-
import { readFile as readFile160, readdir as
|
|
144947
|
-
import
|
|
145377
|
+
import { readFile as readFile160, readdir as readdir56, stat as stat31 } from "fs/promises";
|
|
145378
|
+
import path311 from "path";
|
|
144948
145379
|
async function readRecentConformDocs2(cwd) {
|
|
144949
145380
|
try {
|
|
144950
|
-
const raw = JSON.parse(await readFile160(
|
|
145381
|
+
const raw = JSON.parse(await readFile160(path311.join(cwd, CONFORM_RECENTS_PATH), "utf8"));
|
|
144951
145382
|
return Array.isArray(raw) ? raw : [];
|
|
144952
145383
|
} catch {
|
|
144953
145384
|
return [];
|
|
@@ -144968,25 +145399,25 @@ async function currentBranchPrTarget(cwd) {
|
|
|
144968
145399
|
}
|
|
144969
145400
|
}
|
|
144970
145401
|
async function mostRecentReviewPackage(cwd) {
|
|
144971
|
-
const flowsDir =
|
|
145402
|
+
const flowsDir = path311.join(cwd, ".metaproject", "flows");
|
|
144972
145403
|
let best;
|
|
144973
145404
|
try {
|
|
144974
|
-
for (const flowEntry of await
|
|
145405
|
+
for (const flowEntry of await readdir56(flowsDir, { withFileTypes: true })) {
|
|
144975
145406
|
if (!flowEntry.isDirectory())
|
|
144976
145407
|
continue;
|
|
144977
|
-
const reviewsDir =
|
|
145408
|
+
const reviewsDir = path311.join(flowsDir, flowEntry.name, "reviews");
|
|
144978
145409
|
let reviewEntries;
|
|
144979
145410
|
try {
|
|
144980
|
-
reviewEntries = await
|
|
145411
|
+
reviewEntries = await readdir56(reviewsDir, { withFileTypes: true });
|
|
144981
145412
|
} catch {
|
|
144982
145413
|
continue;
|
|
144983
145414
|
}
|
|
144984
145415
|
for (const reviewEntry of reviewEntries) {
|
|
144985
145416
|
if (!reviewEntry.isDirectory())
|
|
144986
145417
|
continue;
|
|
144987
|
-
const dir =
|
|
145418
|
+
const dir = path311.join(reviewsDir, reviewEntry.name);
|
|
144988
145419
|
try {
|
|
144989
|
-
const info = await stat31(
|
|
145420
|
+
const info = await stat31(path311.join(dir, "report.md"));
|
|
144990
145421
|
if (best === undefined || info.mtimeMs > best.mtimeMs)
|
|
144991
145422
|
best = { dir, mtimeMs: info.mtimeMs };
|
|
144992
145423
|
} catch {}
|
|
@@ -145012,14 +145443,14 @@ async function loadConformSetup(cwd) {
|
|
|
145012
145443
|
targets.push(pr);
|
|
145013
145444
|
const reviewDir = await mostRecentReviewPackage(cwd);
|
|
145014
145445
|
if (reviewDir !== undefined) {
|
|
145015
|
-
targets.push({ id: `report:${reviewDir}`, kind: "report", label: `most recent review package \u2014 ${
|
|
145446
|
+
targets.push({ id: `report:${reviewDir}`, kind: "report", label: `most recent review package \u2014 ${path311.relative(cwd, reviewDir)}` });
|
|
145016
145447
|
}
|
|
145017
145448
|
targets.push({ id: "diff:working", kind: "diff", label: "the working diff" });
|
|
145018
145449
|
return { recents, targets };
|
|
145019
145450
|
}
|
|
145020
145451
|
async function readReportFindings2(reportDir) {
|
|
145021
145452
|
try {
|
|
145022
|
-
const raw = JSON.parse(await readFile160(
|
|
145453
|
+
const raw = JSON.parse(await readFile160(path311.join(reportDir, "findings.json"), "utf8"));
|
|
145023
145454
|
return Array.isArray(raw) ? raw : [];
|
|
145024
145455
|
} catch {
|
|
145025
145456
|
return [];
|
|
@@ -145135,7 +145566,7 @@ async function runConformForTarget(cwd, refPath, target, signal) {
|
|
|
145135
145566
|
await scoreHunkRegions(hunkClauses, hunkRegionsFromDiff(info.diff));
|
|
145136
145567
|
} else if (target.kind === "report") {
|
|
145137
145568
|
const reportDir = target.id.slice("report:".length);
|
|
145138
|
-
const reportMarkdown = await readFile160(
|
|
145569
|
+
const reportMarkdown = await readFile160(path311.join(reportDir, "report.md"), "utf8").catch(() => "");
|
|
145139
145570
|
const findings = await readReportFindings2(reportDir);
|
|
145140
145571
|
const facts = computeReportConformFacts(reportMarkdown, findings);
|
|
145141
145572
|
const redacted = reportRedactedStateText(reportMarkdown);
|
|
@@ -145161,7 +145592,7 @@ async function runConformForTarget(cwd, refPath, target, signal) {
|
|
|
145161
145592
|
async function writeRecentConformDoc(cwd, refPath) {
|
|
145162
145593
|
await Promise.resolve().then(() => init_fs());
|
|
145163
145594
|
const current = await readRecentConformDocs2(cwd);
|
|
145164
|
-
await writeFileAtomic(
|
|
145595
|
+
await writeFileAtomic(path311.join(cwd, CONFORM_RECENTS_PATH), `${JSON.stringify(withRecentDoc(current, refPath), null, 2)}
|
|
145165
145596
|
`, {
|
|
145166
145597
|
mode: 384
|
|
145167
145598
|
}).catch(() => {});
|
|
@@ -145297,8 +145728,8 @@ async function runJevContractForShell(cwd, gitDiff = defaultGitDiff3) {
|
|
|
145297
145728
|
}
|
|
145298
145729
|
|
|
145299
145730
|
// src/tui/jev-triage-command.ts
|
|
145300
|
-
import { readdir as
|
|
145301
|
-
import
|
|
145731
|
+
import { readdir as readdir57, readFile as readFile161, stat as stat32 } from "fs/promises";
|
|
145732
|
+
import path312 from "path";
|
|
145302
145733
|
var JEV_TRIAGE_COMMAND = "/triage";
|
|
145303
145734
|
function isJevTriageCommand(name) {
|
|
145304
145735
|
return name === JEV_TRIAGE_COMMAND;
|
|
@@ -145307,25 +145738,25 @@ function renderJevTriageForShell(result) {
|
|
|
145307
145738
|
return renderTriageMarkdown(result).trimEnd();
|
|
145308
145739
|
}
|
|
145309
145740
|
async function resolveLatestReviewPackage(cwd) {
|
|
145310
|
-
const flowsDir =
|
|
145741
|
+
const flowsDir = path312.join(cwd, ".metaproject", "flows");
|
|
145311
145742
|
let flowEntries;
|
|
145312
145743
|
try {
|
|
145313
|
-
flowEntries = (await
|
|
145744
|
+
flowEntries = (await readdir57(flowsDir, { withFileTypes: true })).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
145314
145745
|
} catch {
|
|
145315
145746
|
return;
|
|
145316
145747
|
}
|
|
145317
145748
|
const candidates = [];
|
|
145318
145749
|
for (const flowName of flowEntries) {
|
|
145319
|
-
const reviewsDir =
|
|
145750
|
+
const reviewsDir = path312.join(flowsDir, flowName, "reviews");
|
|
145320
145751
|
let reviewEntries;
|
|
145321
145752
|
try {
|
|
145322
|
-
reviewEntries = (await
|
|
145753
|
+
reviewEntries = (await readdir57(reviewsDir, { withFileTypes: true })).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
145323
145754
|
} catch {
|
|
145324
145755
|
continue;
|
|
145325
145756
|
}
|
|
145326
145757
|
for (const reviewName of reviewEntries) {
|
|
145327
|
-
const packageDir =
|
|
145328
|
-
const findingsPath =
|
|
145758
|
+
const packageDir = path312.join(reviewsDir, reviewName);
|
|
145759
|
+
const findingsPath = path312.join(packageDir, "findings.json");
|
|
145329
145760
|
try {
|
|
145330
145761
|
const stats = await stat32(findingsPath);
|
|
145331
145762
|
candidates.push({ dir: packageDir, mtimeMs: stats.mtimeMs });
|
|
@@ -145348,9 +145779,9 @@ async function runJevTriageForShell(cwd) {
|
|
|
145348
145779
|
if (packageDir === undefined) {
|
|
145349
145780
|
return "review-jev-triage: no review package found under .metaproject/flows/*/reviews/ \u2014 run a review round first.";
|
|
145350
145781
|
}
|
|
145351
|
-
const findingsRaw = JSON.parse(await readFile161(
|
|
145782
|
+
const findingsRaw = JSON.parse(await readFile161(path312.join(packageDir, "findings.json"), "utf8"));
|
|
145352
145783
|
const result = await computeJevTriageResult({ findingsRaw });
|
|
145353
|
-
return `review-jev-triage: ${
|
|
145784
|
+
return `review-jev-triage: ${path312.relative(cwd, packageDir)}
|
|
145354
145785
|
${renderJevTriageForShell(result)}`;
|
|
145355
145786
|
}
|
|
145356
145787
|
|
|
@@ -148264,10 +148695,10 @@ function openHelpModal(otui, chrome, options) {
|
|
|
148264
148695
|
|
|
148265
148696
|
// src/tui/help-first-run.ts
|
|
148266
148697
|
init_config_dir();
|
|
148267
|
-
import
|
|
148698
|
+
import path313 from "path";
|
|
148268
148699
|
var FIRST_RUN_HELP_FILE = "help-first-run.json";
|
|
148269
148700
|
function firstRunHelpPath(dir) {
|
|
148270
|
-
return
|
|
148701
|
+
return path313.join(keryxConfigDir(dir), FIRST_RUN_HELP_FILE);
|
|
148271
148702
|
}
|
|
148272
148703
|
function helpFirstRunShown(dir) {
|
|
148273
148704
|
const result = readConfigFile(firstRunHelpPath(dir));
|
|
@@ -149351,10 +149782,10 @@ function describeElicitationPrompt(tool, inputJson) {
|
|
|
149351
149782
|
// src/lib/permission-mode-config.ts
|
|
149352
149783
|
init_permission_mode();
|
|
149353
149784
|
init_config_dir();
|
|
149354
|
-
import
|
|
149785
|
+
import path314 from "path";
|
|
149355
149786
|
var EMPTY3 = { schemaVersion: 1, projects: {} };
|
|
149356
149787
|
function permissionModeConfigPath(dir) {
|
|
149357
|
-
return
|
|
149788
|
+
return path314.join(keryxConfigDir(dir), "permission-mode.json");
|
|
149358
149789
|
}
|
|
149359
149790
|
function withRegistryLock2(dir, fn) {
|
|
149360
149791
|
return withFileLock2(`${permissionModeConfigPath(dir)}.lock`, fn, {
|
|
@@ -152303,7 +152734,7 @@ function mountExecutionPlanPanel(otui, renderer, parent, options) {
|
|
|
152303
152734
|
// src/commands/schedule.ts
|
|
152304
152735
|
import { createInterface } from "readline/promises";
|
|
152305
152736
|
import { readFile as readFile162 } from "fs/promises";
|
|
152306
|
-
import
|
|
152737
|
+
import path316 from "path";
|
|
152307
152738
|
|
|
152308
152739
|
// src/commands/trigger.ts
|
|
152309
152740
|
init_gdgraph();
|
|
@@ -152314,9 +152745,9 @@ init_agent();
|
|
|
152314
152745
|
init_agent_hooks();
|
|
152315
152746
|
import { execFile as execFile11 } from "child_process";
|
|
152316
152747
|
import { randomUUID as randomUUID36 } from "crypto";
|
|
152317
|
-
import { mkdtemp as mkdtemp5, mkdir as mkdir68, readdir as
|
|
152748
|
+
import { mkdtemp as mkdtemp5, mkdir as mkdir68, readdir as readdir58, rm as rm19, writeFile as writeFile47 } from "fs/promises";
|
|
152318
152749
|
import { homedir as homedir13, tmpdir as tmpdir11 } from "os";
|
|
152319
|
-
import
|
|
152750
|
+
import path315 from "path";
|
|
152320
152751
|
init_interactive_tools();
|
|
152321
152752
|
|
|
152322
152753
|
// src/harness/process/sandbox/proxy.ts
|
|
@@ -152784,9 +153215,9 @@ function refusal3(runId, code, detail, action) {
|
|
|
152784
153215
|
function agentTaskScratchParent(env = process.env) {
|
|
152785
153216
|
const uid = typeof process.getuid === "function" ? process.getuid() : 0;
|
|
152786
153217
|
const runtime = env["XDG_RUNTIME_DIR"];
|
|
152787
|
-
if (runtime !== undefined && runtime.length > 0 &&
|
|
152788
|
-
return
|
|
152789
|
-
return
|
|
153218
|
+
if (runtime !== undefined && runtime.length > 0 && path315.isAbsolute(runtime))
|
|
153219
|
+
return path315.join(runtime, "keryx-agent-tasks");
|
|
153220
|
+
return path315.join(tmpdir11(), `keryx-agent-tasks-${uid}`);
|
|
152790
153221
|
}
|
|
152791
153222
|
function lastAssistantText(history) {
|
|
152792
153223
|
for (let i = history.length - 1;i >= 0; i -= 1) {
|
|
@@ -152797,9 +153228,9 @@ function lastAssistantText(history) {
|
|
|
152797
153228
|
return "";
|
|
152798
153229
|
}
|
|
152799
153230
|
async function pruneReports(dir, keep) {
|
|
152800
|
-
const names = (await
|
|
153231
|
+
const names = (await readdir58(dir).catch(() => [])).filter((n) => n.endsWith(".md")).sort();
|
|
152801
153232
|
for (const old of names.slice(0, Math.max(0, names.length - keep))) {
|
|
152802
|
-
await rm19(
|
|
153233
|
+
await rm19(path315.join(dir, old), { force: true }).catch(() => {});
|
|
152803
153234
|
}
|
|
152804
153235
|
}
|
|
152805
153236
|
async function runAgentTaskDispatch(projectRoot, entry, action, deps = {}) {
|
|
@@ -152836,10 +153267,10 @@ async function runLocked(projectRoot, entry, action, deps, runId, now) {
|
|
|
152836
153267
|
};
|
|
152837
153268
|
}
|
|
152838
153269
|
const scratchParent = parent.dir;
|
|
152839
|
-
const scratch = await mkdtemp5(
|
|
152840
|
-
const workdir =
|
|
152841
|
-
const scratchHome =
|
|
152842
|
-
const grantedCwd =
|
|
153270
|
+
const scratch = await mkdtemp5(path315.join(scratchParent, `${entry.name.replace(/[^A-Za-z0-9._-]/g, "-")}-`));
|
|
153271
|
+
const workdir = path315.join(scratch, "work");
|
|
153272
|
+
const scratchHome = path315.join(scratch, "home");
|
|
153273
|
+
const grantedCwd = path315.join(scratch, "granted-cwd");
|
|
152843
153274
|
await mkdir68(workdir, { recursive: true });
|
|
152844
153275
|
await mkdir68(scratchHome, { recursive: true });
|
|
152845
153276
|
await mkdir68(grantedCwd, { recursive: true, mode: 448 });
|
|
@@ -152852,7 +153283,7 @@ async function runLocked(projectRoot, entry, action, deps, runId, now) {
|
|
|
152852
153283
|
const invocation = keryxInvocation();
|
|
152853
153284
|
let networkInput = action.grants.network === "full";
|
|
152854
153285
|
if (action.grants.network === "allowlist") {
|
|
152855
|
-
const proxySocketPath =
|
|
153286
|
+
const proxySocketPath = path315.join(scratch, "net-proxy.sock");
|
|
152856
153287
|
try {
|
|
152857
153288
|
const proxy = await createAllowlistProxy({
|
|
152858
153289
|
allowedDomains: [...action.grants.domains],
|
|
@@ -153001,12 +153432,12 @@ async function runLocked(projectRoot, entry, action, deps, runId, now) {
|
|
|
153001
153432
|
let reportNote = "";
|
|
153002
153433
|
try {
|
|
153003
153434
|
await ensureTriggerDataIgnored(projectRoot);
|
|
153004
|
-
const dir =
|
|
153435
|
+
const dir = path315.join(triggerReportsDir(projectRoot), entry.name);
|
|
153005
153436
|
await mkdir68(dir, { recursive: true });
|
|
153006
|
-
const file =
|
|
153437
|
+
const file = path315.join(dir, `${runId}.md`);
|
|
153007
153438
|
await writeFile47(file, renderReport2({ entry, action, runId, at: now().toISOString(), outcome, why, cost, grantedCalls, denials, sandboxNote, summary, networkDecisions }), "utf8");
|
|
153008
153439
|
await pruneReports(dir, action.report.keep);
|
|
153009
|
-
reportPath =
|
|
153440
|
+
reportPath = path315.relative(projectRoot, file);
|
|
153010
153441
|
} catch (error) {
|
|
153011
153442
|
reportNote = ` (report NOT written: ${error instanceof Error ? error.message : String(error)})`;
|
|
153012
153443
|
}
|
|
@@ -153914,7 +154345,7 @@ async function showSubcommand(cwd, name, host, deps) {
|
|
|
153914
154345
|
if (row.reportPath !== undefined) {
|
|
153915
154346
|
console.log(`
|
|
153916
154347
|
--- ${row.reportPath} ---`);
|
|
153917
|
-
console.log(await readFile162(
|
|
154348
|
+
console.log(await readFile162(path316.join(cwd, row.reportPath), "utf8").catch(() => "(the report could not be read)"));
|
|
153918
154349
|
}
|
|
153919
154350
|
}
|
|
153920
154351
|
async function simpleAction(cwd, name, verb, action) {
|
|
@@ -159547,6 +159978,14 @@ ${formatThemeList(getThemeId())}`);
|
|
|
159547
159978
|
});
|
|
159548
159979
|
return;
|
|
159549
159980
|
}
|
|
159981
|
+
if (command.name === "/doctor") {
|
|
159982
|
+
(async () => {
|
|
159983
|
+
const report = await buildDoctorReport(sessionCwd);
|
|
159984
|
+
io.onSystem?.(`${formatDoctorReport2(report)}
|
|
159985
|
+
`);
|
|
159986
|
+
})();
|
|
159987
|
+
return;
|
|
159988
|
+
}
|
|
159550
159989
|
if (command.name === "/game") {
|
|
159551
159990
|
showGame(line);
|
|
159552
159991
|
return;
|
|
@@ -160502,6 +160941,7 @@ var READLINE_AGENT_COMMANDS = [
|
|
|
160502
160941
|
"/compact",
|
|
160503
160942
|
"/status",
|
|
160504
160943
|
"/flows",
|
|
160944
|
+
"/doctor",
|
|
160505
160945
|
"/theme",
|
|
160506
160946
|
"/mode",
|
|
160507
160947
|
"/reasoning",
|
|
@@ -160994,256 +161434,263 @@ Kept the current session.
|
|
|
160994
161434
|
`);
|
|
160995
161435
|
}
|
|
160996
161436
|
};
|
|
160997
|
-
|
|
160998
|
-
io.
|
|
160999
|
-
|
|
161000
|
-
|
|
161001
|
-
|
|
161002
|
-
|
|
161003
|
-
|
|
161004
|
-
|
|
161005
|
-
|
|
161006
|
-
return;
|
|
161007
|
-
}
|
|
161008
|
-
if (command === "/bus") {
|
|
161009
|
-
await runBusSlashCommand(bus, argument, system);
|
|
161010
|
-
continue;
|
|
161011
|
-
}
|
|
161012
|
-
if (command === "/help") {
|
|
161013
|
-
system(HELP_TEXT);
|
|
161014
|
-
continue;
|
|
161015
|
-
}
|
|
161016
|
-
if (isSessionInfoCommand(command)) {
|
|
161017
|
-
const cwd = deps.session?.cwd;
|
|
161018
|
-
const [workspaces, flows] = cwd === undefined ? [[], []] : await Promise.all([loadInspectorWorkspaces(cwd), loadInspectorFlows(cwd)]);
|
|
161019
|
-
system(formatSessionInfoText(buildSessionInfoSnapshot({
|
|
161020
|
-
summary: live?.summary,
|
|
161021
|
-
selection: { provider: providerName, model: modelName },
|
|
161022
|
-
version: package_default.version,
|
|
161023
|
-
estimateTokens: estimateContextTokens(history),
|
|
161024
|
-
limits: await loadSessionLimits({
|
|
161025
|
-
provider: providerName,
|
|
161026
|
-
model: modelName,
|
|
161027
|
-
...baseUrl !== undefined ? { baseUrl } : {}
|
|
161028
|
-
}),
|
|
161029
|
-
sessionText: history.map((message) => message.content).join(`
|
|
161030
|
-
`),
|
|
161031
|
-
workspaces,
|
|
161032
|
-
flows
|
|
161033
|
-
})));
|
|
161034
|
-
continue;
|
|
161035
|
-
}
|
|
161036
|
-
if (isFlowsCommand(command)) {
|
|
161037
|
-
const cwd = deps.session?.cwd;
|
|
161038
|
-
const items = cwd === undefined ? [] : await loadInspectorFlows(cwd);
|
|
161039
|
-
const query = argument.trim();
|
|
161040
|
-
if (query.length > 0) {
|
|
161041
|
-
const found = findFlowItem(items, query);
|
|
161042
|
-
system(found !== undefined ? formatFlowDetailText(found) : `No flow matching '${query}'.
|
|
161043
|
-
`);
|
|
161044
|
-
continue;
|
|
161437
|
+
try {
|
|
161438
|
+
for await (const line of io.lines) {
|
|
161439
|
+
io.onSafeBoundary?.();
|
|
161440
|
+
if (line.startsWith("/")) {
|
|
161441
|
+
const parts = line.trim().split(/\s+/);
|
|
161442
|
+
const command = parts[0] ?? "";
|
|
161443
|
+
const argument = parts.slice(1).join(" ");
|
|
161444
|
+
if (command === "/exit" || command === "/quit") {
|
|
161445
|
+
return;
|
|
161045
161446
|
}
|
|
161046
|
-
|
|
161047
|
-
|
|
161048
|
-
}
|
|
161049
|
-
if (command === "/theme") {
|
|
161050
|
-
const wanted = argument.trim();
|
|
161051
|
-
if (wanted.length === 0) {
|
|
161052
|
-
system(formatThemeList(getThemeId()));
|
|
161447
|
+
if (command === "/bus") {
|
|
161448
|
+
await runBusSlashCommand(bus, argument, system);
|
|
161053
161449
|
continue;
|
|
161054
161450
|
}
|
|
161055
|
-
|
|
161056
|
-
|
|
161057
|
-
system(`Unknown theme '${wanted}'.
|
|
161058
|
-
${formatThemeList(getThemeId())}`);
|
|
161451
|
+
if (command === "/help") {
|
|
161452
|
+
system(HELP_TEXT);
|
|
161059
161453
|
continue;
|
|
161060
161454
|
}
|
|
161061
|
-
|
|
161062
|
-
|
|
161063
|
-
|
|
161455
|
+
if (command === "/doctor") {
|
|
161456
|
+
const report = await buildDoctorReport(deps.session?.cwd ?? process.cwd());
|
|
161457
|
+
system(`${formatDoctorReport2(report)}
|
|
161064
161458
|
`);
|
|
161065
|
-
|
|
161066
|
-
|
|
161067
|
-
|
|
161068
|
-
|
|
161069
|
-
|
|
161070
|
-
|
|
161071
|
-
|
|
161072
|
-
|
|
161073
|
-
|
|
161074
|
-
|
|
161075
|
-
|
|
161459
|
+
continue;
|
|
161460
|
+
}
|
|
161461
|
+
if (isSessionInfoCommand(command)) {
|
|
161462
|
+
const cwd = deps.session?.cwd;
|
|
161463
|
+
const [workspaces, flows] = cwd === undefined ? [[], []] : await Promise.all([loadInspectorWorkspaces(cwd), loadInspectorFlows(cwd)]);
|
|
161464
|
+
system(formatSessionInfoText(buildSessionInfoSnapshot({
|
|
161465
|
+
summary: live?.summary,
|
|
161466
|
+
selection: { provider: providerName, model: modelName },
|
|
161467
|
+
version: package_default.version,
|
|
161468
|
+
estimateTokens: estimateContextTokens(history),
|
|
161469
|
+
limits: await loadSessionLimits({
|
|
161470
|
+
provider: providerName,
|
|
161471
|
+
model: modelName,
|
|
161472
|
+
...baseUrl !== undefined ? { baseUrl } : {}
|
|
161473
|
+
}),
|
|
161474
|
+
sessionText: history.map((message) => message.content).join(`
|
|
161475
|
+
`),
|
|
161476
|
+
workspaces,
|
|
161477
|
+
flows
|
|
161478
|
+
})));
|
|
161479
|
+
continue;
|
|
161480
|
+
}
|
|
161481
|
+
if (isFlowsCommand(command)) {
|
|
161482
|
+
const cwd = deps.session?.cwd;
|
|
161483
|
+
const items = cwd === undefined ? [] : await loadInspectorFlows(cwd);
|
|
161484
|
+
const query = argument.trim();
|
|
161485
|
+
if (query.length > 0) {
|
|
161486
|
+
const found = findFlowItem(items, query);
|
|
161487
|
+
system(found !== undefined ? formatFlowDetailText(found) : `No flow matching '${query}'.
|
|
161076
161488
|
`);
|
|
161077
161489
|
continue;
|
|
161078
161490
|
}
|
|
161079
|
-
|
|
161080
|
-
|
|
161081
|
-
try {
|
|
161082
|
-
await bus?.setSession(live.summary.id);
|
|
161083
|
-
} catch (cause) {
|
|
161084
|
-
system(busErrorLine(cause));
|
|
161085
|
-
}
|
|
161086
|
-
system(`New session ${shortSessionId(live.summary.id)} (previous kept on disk)
|
|
161087
|
-
`);
|
|
161088
|
-
} else {
|
|
161089
|
-
history.length = 0;
|
|
161491
|
+
system(formatFlowListText(items));
|
|
161492
|
+
continue;
|
|
161090
161493
|
}
|
|
161091
|
-
|
|
161092
|
-
|
|
161093
|
-
|
|
161094
|
-
|
|
161095
|
-
|
|
161494
|
+
if (command === "/theme") {
|
|
161495
|
+
const wanted = argument.trim();
|
|
161496
|
+
if (wanted.length === 0) {
|
|
161497
|
+
system(formatThemeList(getThemeId()));
|
|
161498
|
+
continue;
|
|
161499
|
+
}
|
|
161500
|
+
const next = parseThemeId(wanted);
|
|
161501
|
+
if (next === undefined) {
|
|
161502
|
+
system(`Unknown theme '${wanted}'.
|
|
161503
|
+
${formatThemeList(getThemeId())}`);
|
|
161504
|
+
continue;
|
|
161505
|
+
}
|
|
161506
|
+
applyThemeId(next);
|
|
161507
|
+
persistThemeId(next);
|
|
161508
|
+
system(`Theme: ${themeLabel(next)}
|
|
161096
161509
|
`);
|
|
161097
161510
|
continue;
|
|
161098
161511
|
}
|
|
161099
|
-
if (
|
|
161100
|
-
|
|
161512
|
+
if (command === "/clear" || command === "/new") {
|
|
161513
|
+
if (sessionsOn) {
|
|
161514
|
+
try {
|
|
161515
|
+
const next = switchLeasedSession(lease, () => openLeased({ cwd: sessionCwd, provider: providerName, model: modelName }));
|
|
161516
|
+
holdLease(next.lease);
|
|
161517
|
+
live = next.handle;
|
|
161518
|
+
} catch (cause) {
|
|
161519
|
+
system(`${cause instanceof Error ? cause.message : String(cause)}
|
|
161520
|
+
Kept the current session.
|
|
161521
|
+
`);
|
|
161522
|
+
continue;
|
|
161523
|
+
}
|
|
161524
|
+
history = [];
|
|
161525
|
+
archive = [];
|
|
161526
|
+
try {
|
|
161527
|
+
await bus?.setSession(live.summary.id);
|
|
161528
|
+
} catch (cause) {
|
|
161529
|
+
system(busErrorLine(cause));
|
|
161530
|
+
}
|
|
161531
|
+
system(`New session ${shortSessionId(live.summary.id)} (previous kept on disk)
|
|
161532
|
+
`);
|
|
161533
|
+
} else {
|
|
161534
|
+
history.length = 0;
|
|
161535
|
+
}
|
|
161101
161536
|
continue;
|
|
161102
161537
|
}
|
|
161103
|
-
|
|
161104
|
-
|
|
161105
|
-
|
|
161106
|
-
...focus.length > 0 ? { focus } : {},
|
|
161107
|
-
provider: providerName,
|
|
161108
|
-
model: modelName
|
|
161109
|
-
});
|
|
161110
|
-
live = packed.handle;
|
|
161111
|
-
history = packed.context;
|
|
161112
|
-
if (packed.result.noop) {
|
|
161113
|
-
system(`Nothing to compact (context already small).
|
|
161538
|
+
if (command === "/compact") {
|
|
161539
|
+
if (live === undefined) {
|
|
161540
|
+
system(`No persistent session in this mode.
|
|
161114
161541
|
`);
|
|
161115
|
-
|
|
161116
|
-
|
|
161542
|
+
continue;
|
|
161543
|
+
}
|
|
161544
|
+
if (!leaseWatch.canPersist()) {
|
|
161545
|
+
system(LOST_LEASE_COMPACT_REFUSAL);
|
|
161546
|
+
continue;
|
|
161547
|
+
}
|
|
161548
|
+
const focus = argument.trim();
|
|
161549
|
+
const packed = compactSession(live, history, archive, {
|
|
161550
|
+
keepLastUserTurns: 3,
|
|
161551
|
+
...focus.length > 0 ? { focus } : {},
|
|
161552
|
+
provider: providerName,
|
|
161553
|
+
model: modelName
|
|
161554
|
+
});
|
|
161555
|
+
live = packed.handle;
|
|
161556
|
+
history = packed.context;
|
|
161557
|
+
if (packed.result.noop) {
|
|
161558
|
+
system(`Nothing to compact (context already small).
|
|
161559
|
+
`);
|
|
161560
|
+
} else {
|
|
161561
|
+
system(`Compacted: removed ${packed.result.removed} msgs from context \xB7 archive ${live.summary.archiveMessageCount} \xB7 compact\xD7${live.summary.compactCount}
|
|
161117
161562
|
`);
|
|
161563
|
+
}
|
|
161564
|
+
continue;
|
|
161118
161565
|
}
|
|
161119
|
-
|
|
161120
|
-
|
|
161121
|
-
|
|
161122
|
-
|
|
161123
|
-
|
|
161124
|
-
|
|
161566
|
+
if (command === "/model") {
|
|
161567
|
+
if (argument.length > 0) {
|
|
161568
|
+
modelName = argument;
|
|
161569
|
+
provider = makeActive();
|
|
161570
|
+
}
|
|
161571
|
+
continue;
|
|
161125
161572
|
}
|
|
161126
|
-
|
|
161127
|
-
|
|
161128
|
-
|
|
161129
|
-
if (deps.selectProviderModel === undefined) {
|
|
161130
|
-
system(`Interactive model selection is not available in this session.
|
|
161573
|
+
if (command === "/models") {
|
|
161574
|
+
if (deps.selectProviderModel === undefined) {
|
|
161575
|
+
system(`Interactive model selection is not available in this session.
|
|
161131
161576
|
`);
|
|
161577
|
+
continue;
|
|
161578
|
+
}
|
|
161579
|
+
await selectAndApply({ onlyProvider: providerName });
|
|
161132
161580
|
continue;
|
|
161133
161581
|
}
|
|
161134
|
-
|
|
161135
|
-
|
|
161136
|
-
|
|
161137
|
-
|
|
161138
|
-
|
|
161139
|
-
|
|
161140
|
-
|
|
161141
|
-
|
|
161142
|
-
|
|
161143
|
-
await selectAndApply({ onlyProvider: "openai-codex" });
|
|
161582
|
+
if (command === "/provider") {
|
|
161583
|
+
if (argument.length > 0) {
|
|
161584
|
+
if (argument === "openai-codex") {
|
|
161585
|
+
if (deps.selectProviderModel === undefined) {
|
|
161586
|
+
system("Interactive subscription selection is not available. Run `keryx auth login openai-codex` and select an authorized model.\n");
|
|
161587
|
+
} else {
|
|
161588
|
+
await selectAndApply({ onlyProvider: "openai-codex" });
|
|
161589
|
+
}
|
|
161590
|
+
continue;
|
|
161144
161591
|
}
|
|
161592
|
+
providerName = argument;
|
|
161593
|
+
provider = makeActive();
|
|
161145
161594
|
continue;
|
|
161146
161595
|
}
|
|
161147
|
-
|
|
161148
|
-
|
|
161596
|
+
if (deps.selectProviderModel === undefined) {
|
|
161597
|
+
system(`Interactive provider selection is not available in this session.
|
|
161598
|
+
`);
|
|
161599
|
+
continue;
|
|
161600
|
+
}
|
|
161601
|
+
await selectAndApply({});
|
|
161149
161602
|
continue;
|
|
161150
161603
|
}
|
|
161151
|
-
if (
|
|
161152
|
-
|
|
161153
|
-
|
|
161604
|
+
if (command === "/connect") {
|
|
161605
|
+
if (deps.selectProviderModel === undefined) {
|
|
161606
|
+
system(CONNECT_GUIDANCE);
|
|
161607
|
+
continue;
|
|
161608
|
+
}
|
|
161609
|
+
await selectAndApply({ onlyConnected: true });
|
|
161154
161610
|
continue;
|
|
161155
161611
|
}
|
|
161156
|
-
|
|
161157
|
-
|
|
161158
|
-
|
|
161159
|
-
if (command === "/connect") {
|
|
161160
|
-
if (deps.selectProviderModel === undefined) {
|
|
161161
|
-
system(CONNECT_GUIDANCE);
|
|
161612
|
+
const wrongMode = describeUnavailableCommand(command, "chat");
|
|
161613
|
+
if (wrongMode !== undefined) {
|
|
161614
|
+
system(wrongMode);
|
|
161162
161615
|
continue;
|
|
161163
161616
|
}
|
|
161164
|
-
|
|
161617
|
+
system(`Unknown command: ${command}. Type /help for commands.
|
|
161618
|
+
`);
|
|
161165
161619
|
continue;
|
|
161166
161620
|
}
|
|
161167
|
-
|
|
161168
|
-
if (wrongMode !== undefined) {
|
|
161169
|
-
system(wrongMode);
|
|
161621
|
+
if (line.trim().length === 0) {
|
|
161170
161622
|
continue;
|
|
161171
161623
|
}
|
|
161172
|
-
|
|
161173
|
-
|
|
161174
|
-
|
|
161175
|
-
|
|
161176
|
-
|
|
161177
|
-
|
|
161178
|
-
|
|
161179
|
-
|
|
161180
|
-
|
|
161181
|
-
|
|
161182
|
-
|
|
161183
|
-
|
|
161184
|
-
systemInstruction: SYSTEM_INSTRUCTION,
|
|
161185
|
-
messages: [...history],
|
|
161186
|
-
budget: { maxOutputTokens: resolvedMaxOutputTokens, runReservation: resolvedMaxOutputTokens },
|
|
161187
|
-
...modelParams.temperature !== undefined ? { options: { temperature: modelParams.temperature } } : {},
|
|
161188
|
-
stream: true,
|
|
161189
|
-
requestId: deps.idSeq(),
|
|
161190
|
-
parentRunId
|
|
161191
|
-
};
|
|
161192
|
-
let accumulated = "";
|
|
161193
|
-
let errored = false;
|
|
161194
|
-
busWorking = true;
|
|
161195
|
-
io.onTurnStart?.();
|
|
161196
|
-
try {
|
|
161197
|
-
const streamOptions = {
|
|
161198
|
-
attemptId: deps.idSeq(),
|
|
161199
|
-
...modelParams.timeoutMs !== undefined ? { timeoutMs: modelParams.timeoutMs } : {}
|
|
161624
|
+
history.push({ role: "user", content: line, provenance: "project" });
|
|
161625
|
+
const resolvedMaxOutputTokens = modelParams.maxOutputTokens ?? DEFAULT_MAX_OUTPUT_TOKENS;
|
|
161626
|
+
const request = {
|
|
161627
|
+
providerId: providerName,
|
|
161628
|
+
modelId: modelName,
|
|
161629
|
+
systemInstruction: SYSTEM_INSTRUCTION,
|
|
161630
|
+
messages: [...history],
|
|
161631
|
+
budget: { maxOutputTokens: resolvedMaxOutputTokens, runReservation: resolvedMaxOutputTokens },
|
|
161632
|
+
...modelParams.temperature !== undefined ? { options: { temperature: modelParams.temperature } } : {},
|
|
161633
|
+
stream: true,
|
|
161634
|
+
requestId: deps.idSeq(),
|
|
161635
|
+
parentRunId
|
|
161200
161636
|
};
|
|
161201
|
-
|
|
161202
|
-
|
|
161203
|
-
|
|
161204
|
-
|
|
161205
|
-
|
|
161206
|
-
|
|
161207
|
-
|
|
161208
|
-
|
|
161637
|
+
let accumulated = "";
|
|
161638
|
+
let errored = false;
|
|
161639
|
+
busWorking = true;
|
|
161640
|
+
io.onTurnStart?.();
|
|
161641
|
+
try {
|
|
161642
|
+
const streamOptions = {
|
|
161643
|
+
attemptId: deps.idSeq(),
|
|
161644
|
+
...modelParams.timeoutMs !== undefined ? { timeoutMs: modelParams.timeoutMs } : {}
|
|
161645
|
+
};
|
|
161646
|
+
for await (const event of provider.stream(request, streamOptions)) {
|
|
161647
|
+
if (event.kind === "text_delta") {
|
|
161648
|
+
const text = event.text ?? "";
|
|
161649
|
+
io.write(text);
|
|
161650
|
+
accumulated += text;
|
|
161651
|
+
} else if (event.kind === "provider_error") {
|
|
161652
|
+
const detail = event.error?.message ?? event.error?.kind ?? "provider error";
|
|
161653
|
+
system(`
|
|
161209
161654
|
[error] ${detail}
|
|
161210
161655
|
`);
|
|
161211
|
-
|
|
161212
|
-
|
|
161213
|
-
|
|
161214
|
-
|
|
161656
|
+
errored = true;
|
|
161657
|
+
break;
|
|
161658
|
+
} else if (event.kind === "model_end") {
|
|
161659
|
+
break;
|
|
161660
|
+
}
|
|
161215
161661
|
}
|
|
161216
|
-
}
|
|
161217
|
-
|
|
161218
|
-
system(`
|
|
161662
|
+
} catch (cause) {
|
|
161663
|
+
system(`
|
|
161219
161664
|
[error] ${cause instanceof Error ? cause.message : String(cause)}
|
|
161220
161665
|
`);
|
|
161221
|
-
|
|
161222
|
-
|
|
161223
|
-
|
|
161224
|
-
|
|
161225
|
-
|
|
161226
|
-
|
|
161227
|
-
|
|
161228
|
-
|
|
161229
|
-
|
|
161230
|
-
|
|
161231
|
-
|
|
161232
|
-
|
|
161233
|
-
|
|
161234
|
-
|
|
161235
|
-
|
|
161236
|
-
|
|
161237
|
-
|
|
161238
|
-
|
|
161239
|
-
|
|
161240
|
-
|
|
161241
|
-
|
|
161666
|
+
errored = true;
|
|
161667
|
+
}
|
|
161668
|
+
if (accumulated.length > 0) {
|
|
161669
|
+
io.onTurnEnd?.(accumulated);
|
|
161670
|
+
}
|
|
161671
|
+
if (!errored) {
|
|
161672
|
+
history.push({ role: "assistant", content: accumulated, provenance: "model" });
|
|
161673
|
+
archive.push({ role: "user", content: line, provenance: "project" });
|
|
161674
|
+
archive.push({ role: "assistant", content: accumulated, provenance: "model" });
|
|
161675
|
+
save();
|
|
161676
|
+
} else if (accumulated.length > 0) {
|
|
161677
|
+
history.push({ role: "assistant", content: accumulated, provenance: "model" });
|
|
161678
|
+
archive.push({ role: "user", content: line, provenance: "project" });
|
|
161679
|
+
archive.push({ role: "assistant", content: accumulated, provenance: "model" });
|
|
161680
|
+
save();
|
|
161681
|
+
} else {
|
|
161682
|
+
history.pop();
|
|
161683
|
+
}
|
|
161684
|
+
busWorking = false;
|
|
161685
|
+
io.onSafeBoundary?.();
|
|
161686
|
+
io.write(`
|
|
161242
161687
|
|
|
161243
161688
|
`);
|
|
161689
|
+
}
|
|
161690
|
+
} finally {
|
|
161691
|
+
leaveBus();
|
|
161692
|
+
releaseLease();
|
|
161244
161693
|
}
|
|
161245
|
-
leaveBus();
|
|
161246
|
-
releaseLease();
|
|
161247
161694
|
}
|
|
161248
161695
|
function realMakeProvider(write) {
|
|
161249
161696
|
return (name, model, baseUrl) => {
|
|
@@ -162180,6 +162627,10 @@ ${GUTTER}${turnSeparator()}
|
|
|
162180
162627
|
await runBusSlashCommand(bus, rest, (text) => agentIo.onSystem?.(text));
|
|
162181
162628
|
} else if (command === "/help") {
|
|
162182
162629
|
agentIo.onSystem?.(readlineAgentHelpText());
|
|
162630
|
+
} else if (command === "/doctor") {
|
|
162631
|
+
const report = await buildDoctorReport(sessionCwd);
|
|
162632
|
+
agentIo.onSystem?.(`${formatDoctorReport2(report)}
|
|
162633
|
+
`);
|
|
162183
162634
|
} else if (isSessionInfoCommand(command)) {
|
|
162184
162635
|
const cwd = sessionCwd;
|
|
162185
162636
|
const [workspaces, flows] = await Promise.all([
|
|
@@ -165724,7 +166175,7 @@ init_fs();
|
|
|
165724
166175
|
init_prompt();
|
|
165725
166176
|
import { readFile as readFile163 } from "fs/promises";
|
|
165726
166177
|
import { stdin } from "process";
|
|
165727
|
-
import
|
|
166178
|
+
import path318 from "path";
|
|
165728
166179
|
init_ui();
|
|
165729
166180
|
var MODULES = [
|
|
165730
166181
|
{ name: "gdgraph", flag: "--no-gdgraph", desc: "code graph, symbols, affected context", defaultEnabled: true },
|
|
@@ -165771,8 +166222,8 @@ async function modulesCommand(args = []) {
|
|
|
165771
166222
|
return;
|
|
165772
166223
|
}
|
|
165773
166224
|
const wantsJson = args.includes("--json") && (sub === undefined || sub === "status" || sub === "list" || sub === "--json");
|
|
165774
|
-
const metaprojectRoot =
|
|
165775
|
-
const manifestPath =
|
|
166225
|
+
const metaprojectRoot = path318.join(process.cwd(), ".metaproject");
|
|
166226
|
+
const manifestPath = path318.join(metaprojectRoot, "metaproject.json");
|
|
165776
166227
|
if (!await pathExists(manifestPath)) {
|
|
165777
166228
|
if (wantsJson) {
|
|
165778
166229
|
console.log(JSON.stringify({ schemaVersion: 1, error: "not-initialized", modules: [] }, null, 2));
|
|
@@ -165895,7 +166346,7 @@ import { createHash as createHash68, randomBytes as randomBytes11, randomUUID as
|
|
|
165895
166346
|
import {
|
|
165896
166347
|
chmodSync as chmodSync5,
|
|
165897
166348
|
closeSync as closeSync7,
|
|
165898
|
-
existsSync as
|
|
166349
|
+
existsSync as existsSync49,
|
|
165899
166350
|
fsyncSync as fsyncSync2,
|
|
165900
166351
|
openSync as openSync8,
|
|
165901
166352
|
renameSync as renameSync5,
|
|
@@ -165903,9 +166354,9 @@ import {
|
|
|
165903
166354
|
unlinkSync as unlinkSync6,
|
|
165904
166355
|
writeFileSync as writeFileSync10
|
|
165905
166356
|
} from "fs";
|
|
165906
|
-
import
|
|
166357
|
+
import path319 from "path";
|
|
165907
166358
|
function serveCredentialPath(dir) {
|
|
165908
|
-
return
|
|
166359
|
+
return path319.join(keryxConfigDir(dir), "serve-credentials.json");
|
|
165909
166360
|
}
|
|
165910
166361
|
function constantTimeEqual(a, b) {
|
|
165911
166362
|
const width = Math.max(a.length, b.length);
|
|
@@ -165939,7 +166390,7 @@ function isGroupOrOtherAccessible(file) {
|
|
|
165939
166390
|
}
|
|
165940
166391
|
function readServeCredential(dir) {
|
|
165941
166392
|
const file = serveCredentialPath(dir);
|
|
165942
|
-
if (!
|
|
166393
|
+
if (!existsSync49(file)) {
|
|
165943
166394
|
return { status: "absent" };
|
|
165944
166395
|
}
|
|
165945
166396
|
if (isGroupOrOtherAccessible(file)) {
|
|
@@ -166138,23 +166589,23 @@ class AuthFailureThrottle {
|
|
|
166138
166589
|
// src/lib/serve-turn-store.ts
|
|
166139
166590
|
init_config_dir();
|
|
166140
166591
|
import { createHash as createHash69 } from "crypto";
|
|
166141
|
-
import { existsSync as
|
|
166142
|
-
import
|
|
166592
|
+
import { existsSync as existsSync50, readdirSync as readdirSync12, rmSync as rmSync4 } from "fs";
|
|
166593
|
+
import path320 from "path";
|
|
166143
166594
|
var MAX_TURN_EVENTS = 1e4;
|
|
166144
166595
|
function turnsRoot(dir) {
|
|
166145
|
-
return
|
|
166596
|
+
return path320.join(keryxConfigDir(dir), "turns");
|
|
166146
166597
|
}
|
|
166147
166598
|
function turnDir(turnId, dir) {
|
|
166148
|
-
return
|
|
166599
|
+
return path320.join(turnsRoot(dir), turnId);
|
|
166149
166600
|
}
|
|
166150
166601
|
function keyPath(project, idempotencyKey, dir) {
|
|
166151
166602
|
const projectBytes = Buffer.byteLength(project, "utf8");
|
|
166152
166603
|
const digest = createHash69("sha256").update(`${projectBytes}:${project}\x00${idempotencyKey}`, "utf8").digest("hex");
|
|
166153
|
-
return
|
|
166604
|
+
return path320.join(turnsRoot(dir), "keys", `${digest}.json`);
|
|
166154
166605
|
}
|
|
166155
166606
|
function legacyKeyPath(idempotencyKey, dir) {
|
|
166156
166607
|
const digest = createHash69("sha256").update(idempotencyKey, "utf8").digest("hex");
|
|
166157
|
-
return
|
|
166608
|
+
return path320.join(turnsRoot(dir), "keys", `${digest}.json`);
|
|
166158
166609
|
}
|
|
166159
166610
|
function adoptLegacyClaim(project, idempotencyKey, dir) {
|
|
166160
166611
|
const legacy = legacyKeyPath(idempotencyKey, dir);
|
|
@@ -166218,7 +166669,7 @@ function ensureTurnDir(turnId, dir) {
|
|
|
166218
166669
|
}
|
|
166219
166670
|
function createTurnRecord(record, dir) {
|
|
166220
166671
|
ensureTurnDir(record.turnId, dir);
|
|
166221
|
-
writeOwnerOnlyFile(
|
|
166672
|
+
writeOwnerOnlyFile(path320.join(turnDir(record.turnId, dir), "turn.json"), `${JSON.stringify(record, null, 2)}
|
|
166222
166673
|
`);
|
|
166223
166674
|
}
|
|
166224
166675
|
function appendTurnEvent(event, dir, opts) {
|
|
@@ -166227,12 +166678,12 @@ function appendTurnEvent(event, dir, opts) {
|
|
|
166227
166678
|
}
|
|
166228
166679
|
const line = JSON.stringify(event);
|
|
166229
166680
|
try {
|
|
166230
|
-
appendOwnerOnlyLine(
|
|
166681
|
+
appendOwnerOnlyLine(path320.join(turnDir(event.turnId, dir), "events.jsonl"), line);
|
|
166231
166682
|
} catch (error) {
|
|
166232
166683
|
if (error?.code !== "ENOENT") {
|
|
166233
166684
|
throw error;
|
|
166234
166685
|
}
|
|
166235
|
-
appendOwnerOnlyLine(
|
|
166686
|
+
appendOwnerOnlyLine(path320.join(ensureTurnDir(event.turnId, dir), "events.jsonl"), line);
|
|
166236
166687
|
}
|
|
166237
166688
|
return true;
|
|
166238
166689
|
}
|
|
@@ -166240,7 +166691,7 @@ function readTurnEvents(turnId, after = -1, dir) {
|
|
|
166240
166691
|
if (!isTurnId(turnId)) {
|
|
166241
166692
|
return { ok: false, reason: "not-a-turn-id" };
|
|
166242
166693
|
}
|
|
166243
|
-
const read = readTurnFile(
|
|
166694
|
+
const read = readTurnFile(path320.join(turnDir(turnId, dir), "events.jsonl"));
|
|
166244
166695
|
if (!read.ok) {
|
|
166245
166696
|
if (isDefiniteAbsence2(read.reason)) {
|
|
166246
166697
|
return { ok: true, value: [] };
|
|
@@ -166268,7 +166719,7 @@ function readTurnRecord(turnId, dir) {
|
|
|
166268
166719
|
if (!isTurnId(turnId)) {
|
|
166269
166720
|
return { ok: false, reason: "not-a-turn-id" };
|
|
166270
166721
|
}
|
|
166271
|
-
const read = readTurnFile(
|
|
166722
|
+
const read = readTurnFile(path320.join(turnDir(turnId, dir), "turn.json"));
|
|
166272
166723
|
if (!read.ok) {
|
|
166273
166724
|
return { ok: false, reason: read.reason };
|
|
166274
166725
|
}
|
|
@@ -166287,7 +166738,7 @@ function finishTurn(turnId, result, dir) {
|
|
|
166287
166738
|
if (!record.ok) {
|
|
166288
166739
|
return false;
|
|
166289
166740
|
}
|
|
166290
|
-
writeOwnerOnlyFile(
|
|
166741
|
+
writeOwnerOnlyFile(path320.join(turnDir(turnId, dir), "turn.json"), `${JSON.stringify({ ...record.value, result }, null, 2)}
|
|
166291
166742
|
`);
|
|
166292
166743
|
return true;
|
|
166293
166744
|
}
|
|
@@ -166334,7 +166785,7 @@ function releaseIdempotencyKey(project, idempotencyKey, turnId, dir) {
|
|
|
166334
166785
|
// src/lib/serve-turn.ts
|
|
166335
166786
|
import { randomUUID as randomUUID44 } from "crypto";
|
|
166336
166787
|
init_hooks();
|
|
166337
|
-
import
|
|
166788
|
+
import path321 from "path";
|
|
166338
166789
|
init_service4();
|
|
166339
166790
|
init_service9();
|
|
166340
166791
|
init_impact_evidence_hook_adapter();
|
|
@@ -166405,9 +166856,9 @@ function isUuid(value) {
|
|
|
166405
166856
|
return typeof value === "string" && /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(value);
|
|
166406
166857
|
}
|
|
166407
166858
|
function resolveProject(declared, dir) {
|
|
166408
|
-
const wanted =
|
|
166859
|
+
const wanted = path321.resolve(declared);
|
|
166409
166860
|
for (const entry of listProjects(dir, () => {})) {
|
|
166410
|
-
if (
|
|
166861
|
+
if (path321.resolve(entry.path) === wanted) {
|
|
166411
166862
|
return { ok: true, project: entry.path };
|
|
166412
166863
|
}
|
|
166413
166864
|
}
|
|
@@ -166480,7 +166931,7 @@ function buildRemoteHookRuntime(opts) {
|
|
|
166480
166931
|
});
|
|
166481
166932
|
emitRemoteHookNotices(opts.projectRoot, formatHookLoadNotices(loaded, {
|
|
166482
166933
|
projectRoot: opts.projectRoot,
|
|
166483
|
-
userFile:
|
|
166934
|
+
userFile: path321.join(homeDir, ".keryx", "hooks.json"),
|
|
166484
166935
|
surface: "headless"
|
|
166485
166936
|
}));
|
|
166486
166937
|
if (!loaded.ok) {
|
|
@@ -167529,9 +167980,9 @@ function printHelp23() {
|
|
|
167529
167980
|
// src/commands/update.ts
|
|
167530
167981
|
init_contained_write();
|
|
167531
167982
|
import { spawn as spawn9 } from "child_process";
|
|
167532
|
-
import { readFile as readFile164, readdir as
|
|
167533
|
-
import { access as access4, constants as constants5, existsSync as
|
|
167534
|
-
import
|
|
167983
|
+
import { readFile as readFile164, readdir as readdir59 } from "fs/promises";
|
|
167984
|
+
import { access as access4, constants as constants5, existsSync as existsSync51 } from "fs";
|
|
167985
|
+
import path322 from "path";
|
|
167535
167986
|
import { fileURLToPath as fileURLToPath10 } from "url";
|
|
167536
167987
|
init_catalog2();
|
|
167537
167988
|
init_model_choice();
|
|
@@ -167546,17 +167997,17 @@ init_ui();
|
|
|
167546
167997
|
init_install_plan();
|
|
167547
167998
|
init_templates3();
|
|
167548
167999
|
function containFromMetaprojectPath(filePath) {
|
|
167549
|
-
const marker = `${
|
|
168000
|
+
const marker = `${path322.sep}.metaproject${path322.sep}`;
|
|
167550
168001
|
const idx = filePath.lastIndexOf(marker);
|
|
167551
168002
|
if (idx < 0) {
|
|
167552
|
-
if (filePath.endsWith(`${
|
|
167553
|
-
const root = filePath.slice(0, filePath.length - ".metaproject".length -
|
|
168003
|
+
if (filePath.endsWith(`${path322.sep}.metaproject`)) {
|
|
168004
|
+
const root = filePath.slice(0, filePath.length - ".metaproject".length - path322.sep.length);
|
|
167554
168005
|
return { root, rel: ".metaproject" };
|
|
167555
168006
|
}
|
|
167556
168007
|
throw new Error(`${filePath}: expected a path under a .metaproject directory`);
|
|
167557
168008
|
}
|
|
167558
168009
|
const root = filePath.slice(0, idx);
|
|
167559
|
-
const rel = filePath.slice(idx +
|
|
168010
|
+
const rel = filePath.slice(idx + path322.sep.length).split(path322.sep).join("/");
|
|
167560
168011
|
return { root, rel };
|
|
167561
168012
|
}
|
|
167562
168013
|
async function updateCommand(args = []) {
|
|
@@ -167566,8 +168017,8 @@ async function updateCommand(args = []) {
|
|
|
167566
168017
|
return;
|
|
167567
168018
|
}
|
|
167568
168019
|
const projectRoot = process.cwd();
|
|
167569
|
-
const metaprojectRoot =
|
|
167570
|
-
banner("keryx update", `Refreshing the .metaproject workspace in ${
|
|
168020
|
+
const metaprojectRoot = path322.join(projectRoot, ".metaproject");
|
|
168021
|
+
banner("keryx update", `Refreshing the .metaproject workspace in ${path322.basename(projectRoot)}/`);
|
|
167571
168022
|
if (!await pathExists(metaprojectRoot)) {
|
|
167572
168023
|
console.log(` ${style.red(symbols.cross)} Metaproject is not initialized.`);
|
|
167573
168024
|
console.log(` ${style.cyan(symbols.arrow)} Run ${style.cyan("keryx init")} first.`);
|
|
@@ -167643,7 +168094,7 @@ async function updateCommand(args = []) {
|
|
|
167643
168094
|
nextSteps(steps);
|
|
167644
168095
|
}
|
|
167645
168096
|
async function previewServiceFiles(projectRoot, options) {
|
|
167646
|
-
const metaprojectRoot =
|
|
168097
|
+
const metaprojectRoot = path322.join(projectRoot, ".metaproject");
|
|
167647
168098
|
const manifestState = await readManifest5(metaprojectRoot);
|
|
167648
168099
|
const manifest = manifestState.manifest;
|
|
167649
168100
|
const enableTasks = moduleEnabled2(manifest, "tasks") || !options.noTasks;
|
|
@@ -167672,13 +168123,13 @@ async function previewServiceFiles(projectRoot, options) {
|
|
|
167672
168123
|
});
|
|
167673
168124
|
}
|
|
167674
168125
|
async function refreshServiceFiles(projectRoot, options) {
|
|
167675
|
-
const metaprojectRoot =
|
|
168126
|
+
const metaprojectRoot = path322.join(projectRoot, ".metaproject");
|
|
167676
168127
|
const manifestState = await readManifest5(metaprojectRoot);
|
|
167677
168128
|
const manifest = manifestState.manifest;
|
|
167678
168129
|
const recoveredManifest = !manifestState.exists || !manifestState.valid;
|
|
167679
168130
|
if (manifestState.migrated) {
|
|
167680
168131
|
{
|
|
167681
|
-
const { root, rel } = containFromMetaprojectPath(
|
|
168132
|
+
const { root, rel } = containFromMetaprojectPath(path322.join(metaprojectRoot, "metaproject.json"));
|
|
167682
168133
|
await writeContained(root, rel, `${JSON.stringify(manifest, null, 2)}
|
|
167683
168134
|
`);
|
|
167684
168135
|
}
|
|
@@ -167718,9 +168169,9 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
167718
168169
|
enableSecurity,
|
|
167719
168170
|
enableSac
|
|
167720
168171
|
});
|
|
167721
|
-
await writeTextIfChanged4(
|
|
167722
|
-
await writeTextIfChanged4(
|
|
167723
|
-
await writeTextIfChanged4(
|
|
168172
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "core", "README.md"), renderMetaprojectCoreReadme());
|
|
168173
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "hooks", "README.md"), renderHooksReadme());
|
|
168174
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "skills", "project-rules", "README.md"), renderProjectRulesSkillReadme({ sources: ruleSources }));
|
|
167724
168175
|
await writeRoutingEntrypointPair(metaprojectRoot, {
|
|
167725
168176
|
enableGdgraph,
|
|
167726
168177
|
enableGdctx,
|
|
@@ -167744,7 +168195,7 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
167744
168195
|
}
|
|
167745
168196
|
});
|
|
167746
168197
|
console.log(` ${await describeModelChoiceStatus(projectRoot)}`);
|
|
167747
|
-
await writeTextIfChanged4(
|
|
168198
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "keryx-dashboard.html"), renderMetaprojectDashboardHtml({
|
|
167748
168199
|
enableGdgraph,
|
|
167749
168200
|
enableGdctx,
|
|
167750
168201
|
enableGdwiki,
|
|
@@ -167756,7 +168207,7 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
167756
168207
|
enableSecurity,
|
|
167757
168208
|
data: dashboardData
|
|
167758
168209
|
}));
|
|
167759
|
-
await writeTextIfMissing4(
|
|
168210
|
+
await writeTextIfMissing4(path322.join(metaprojectRoot, "README.md"), renderMetaprojectReadme({
|
|
167760
168211
|
enableGdgraph,
|
|
167761
168212
|
enableGdctx,
|
|
167762
168213
|
enableGdwiki,
|
|
@@ -167769,9 +168220,9 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
167769
168220
|
}));
|
|
167770
168221
|
if (enableGdgraph) {
|
|
167771
168222
|
await installGdgraphCoreScripts2(metaprojectRoot);
|
|
167772
|
-
await writeTextIfChanged4(
|
|
167773
|
-
await writeTextIfChanged4(
|
|
167774
|
-
await writeTextIfChanged4(
|
|
168223
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "modules", "gdgraph.md"), renderGdgraphManifest());
|
|
168224
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "core", "gdgraph", "README.md"), renderGdgraphCoreReadme());
|
|
168225
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "skills", "gdgraph", "SKILL.md"), renderGdgraphSkillReadme());
|
|
167775
168226
|
await seedAssetsLock(metaprojectRoot);
|
|
167776
168227
|
if (manifest.modules?.gdgraph?.hooks?.gitPostCommit) {
|
|
167777
168228
|
const warning = await installManagedHookOrWarn(projectRoot, "post-commit", "gdgraph-post-commit", renderGdgraphPostCommitHook());
|
|
@@ -167780,15 +168231,15 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
167780
168231
|
}
|
|
167781
168232
|
}
|
|
167782
168233
|
if (enableGdctx) {
|
|
167783
|
-
await writeTextIfMissing4(
|
|
167784
|
-
await writeTextIfChanged4(
|
|
167785
|
-
await writeTextIfChanged4(
|
|
167786
|
-
await writeTextIfChanged4(
|
|
168234
|
+
await writeTextIfMissing4(path322.join(metaprojectRoot, "gdctx.config.json"), renderGdctxConfig());
|
|
168235
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "modules", "gdctx.md"), renderGdctxManifest());
|
|
168236
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "core", "gdctx", "README.md"), renderGdctxCoreReadme());
|
|
168237
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "skills", "gdctx", "SKILL.md"), renderGdctxSkillReadme());
|
|
167787
168238
|
}
|
|
167788
168239
|
if (enableGdwiki) {
|
|
167789
|
-
await writeTextIfMissing4(
|
|
167790
|
-
await writeTextIfChanged4(
|
|
167791
|
-
await writeTextIfChanged4(
|
|
168240
|
+
await writeTextIfMissing4(path322.join(metaprojectRoot, "wiki", "templates", "page.md"), renderWikiPageTemplate());
|
|
168241
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "modules", "gdwiki.md"), renderGdwikiManifest());
|
|
168242
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "skills", "gdwiki", "SKILL.md"), renderGdwikiSkillReadme());
|
|
167792
168243
|
if (manifest.modules?.gdgraph?.hooks?.gitPostCommit) {
|
|
167793
168244
|
const warning = await installManagedHookOrWarn(projectRoot, "post-commit", "gdwiki-post-commit", renderGdwikiPostCommitHook());
|
|
167794
168245
|
if (warning)
|
|
@@ -167796,8 +168247,8 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
167796
168247
|
}
|
|
167797
168248
|
}
|
|
167798
168249
|
if (enableSac) {
|
|
167799
|
-
await writeTextIfMissing4(
|
|
167800
|
-
await writeTextIfChanged4(
|
|
168250
|
+
await writeTextIfMissing4(path322.join(metaprojectRoot, "modules", "sac.md"), renderSacManifest());
|
|
168251
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "skills", "sac", "SKILL.md"), renderSacSkillReadme());
|
|
167801
168252
|
}
|
|
167802
168253
|
let gdskillsWarnings = [];
|
|
167803
168254
|
let gdskillsNotices = [];
|
|
@@ -167812,10 +168263,10 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
167812
168263
|
}
|
|
167813
168264
|
}
|
|
167814
168265
|
if (enableHealth) {
|
|
167815
|
-
await writeTextIfMissing4(
|
|
167816
|
-
await writeTextIfChanged4(
|
|
167817
|
-
await writeTextIfChanged4(
|
|
167818
|
-
await writeTextIfChanged4(
|
|
168266
|
+
await writeTextIfMissing4(path322.join(metaprojectRoot, "health.config.json"), renderHealthConfig());
|
|
168267
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "modules", "health.md"), renderHealthManifest());
|
|
168268
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "core", "health", "README.md"), renderHealthCoreReadme());
|
|
168269
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "skills", "health", "SKILL.md"), renderHealthSkillReadme());
|
|
167819
168270
|
if (manifest.modules?.health?.hooks?.gitPostCommit) {
|
|
167820
168271
|
const warning = await installManagedHookOrWarn(projectRoot, "post-commit", "health-post-commit", renderHealthPostCommitHook());
|
|
167821
168272
|
if (warning)
|
|
@@ -167823,16 +168274,16 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
167823
168274
|
}
|
|
167824
168275
|
}
|
|
167825
168276
|
if (enableTesting) {
|
|
167826
|
-
await writeTextIfMissing4(
|
|
168277
|
+
await writeTextIfMissing4(path322.join(metaprojectRoot, "testing.config.json"), renderTestingConfig({
|
|
167827
168278
|
postCommitRefresh: Boolean(manifest.modules?.testing?.hooks?.gitPostCommit),
|
|
167828
168279
|
prePushGate: Boolean(manifest.modules?.testing?.hooks?.prePush)
|
|
167829
168280
|
}));
|
|
167830
|
-
await writeTextIfChanged4(
|
|
167831
|
-
await writeTextIfChanged4(
|
|
167832
|
-
await writeTextIfChanged4(
|
|
168281
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "modules", "testing.md"), renderTestingManifest());
|
|
168282
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "core", "testing", "README.md"), renderTestingCoreReadme());
|
|
168283
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "skills", "testing", "SKILL.md"), renderTestingSkillReadme());
|
|
167833
168284
|
if (enableGdwiki) {
|
|
167834
|
-
await writeTextIfMissing4(
|
|
167835
|
-
await writeTextIfMissing4(
|
|
168285
|
+
await writeTextIfMissing4(path322.join(metaprojectRoot, "wiki", "testing", "README.md"), renderTestingWikiReadme());
|
|
168286
|
+
await writeTextIfMissing4(path322.join(metaprojectRoot, "wiki", "testing", "conventions.md"), renderTestingWikiConventions());
|
|
167836
168287
|
}
|
|
167837
168288
|
if (manifest.modules?.testing?.hooks?.gitPostCommit) {
|
|
167838
168289
|
const warning = await installManagedHookOrWarn(projectRoot, "post-commit", "testing-post-commit", renderTestingPostCommitHook());
|
|
@@ -167851,24 +168302,24 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
167851
168302
|
hookWarnings.push(warning);
|
|
167852
168303
|
}
|
|
167853
168304
|
if (enableMemory) {
|
|
167854
|
-
await writeTextIfMissing4(
|
|
167855
|
-
await writeTextIfMissing4(
|
|
167856
|
-
await writeTextIfChanged4(
|
|
167857
|
-
await writeTextIfChanged4(
|
|
167858
|
-
await writeTextIfChanged4(
|
|
168305
|
+
await writeTextIfMissing4(path322.join(metaprojectRoot, "memory.config.json"), renderMemoryConfig());
|
|
168306
|
+
await writeTextIfMissing4(path322.join(metaprojectRoot, "memory", "templates", "entry.md"), renderMemoryEntryTemplate());
|
|
168307
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "modules", "memory.md"), renderMemoryManifest());
|
|
168308
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "core", "memory", "README.md"), renderMemoryCoreReadme());
|
|
168309
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "skills", "memory", "SKILL.md"), renderMemorySkillReadme());
|
|
167859
168310
|
}
|
|
167860
168311
|
if (enableTasks) {
|
|
167861
|
-
await writeTextIfChanged4(
|
|
167862
|
-
await writeTextIfChanged4(
|
|
167863
|
-
await writeTextIfChanged4(
|
|
167864
|
-
await writeTextIfChanged4(
|
|
167865
|
-
await writeTextIfChanged4(
|
|
167866
|
-
await writeTextIfChanged4(
|
|
168312
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "flows", "README.md"), renderFlowsReadme());
|
|
168313
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "modules", "tasks.md"), renderTasksManifest());
|
|
168314
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "skills", "flow", "SKILL.md"), renderFlowSkillRouter());
|
|
168315
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "skills", "flow", "init.md"), renderFlowInitSkill());
|
|
168316
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "skills", "flow", "manage.md"), renderFlowManageSkill());
|
|
168317
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "skills", "flow", "complete.md"), renderFlowCompleteSkill());
|
|
167867
168318
|
}
|
|
167868
168319
|
if (enableSecurity) {
|
|
167869
|
-
await writeTextIfMissing4(
|
|
167870
|
-
await writeTextIfChanged4(
|
|
167871
|
-
await writeTextIfChanged4(
|
|
168320
|
+
await writeTextIfMissing4(path322.join(metaprojectRoot, "security.config.json"), renderSecurityConfig());
|
|
168321
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "modules", "security.md"), renderSecurityManifest());
|
|
168322
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "core", "security", "README.md"), renderSecurityCoreReadme());
|
|
167872
168323
|
if (manifest.modules?.security?.hooks?.prePush) {
|
|
167873
168324
|
const warning = await installManagedHookOrWarn(projectRoot, "pre-push", "security-pre-push", renderSecurityPrePushHook());
|
|
167874
168325
|
if (warning)
|
|
@@ -167926,13 +168377,13 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
167926
168377
|
};
|
|
167927
168378
|
}
|
|
167928
168379
|
async function buildDashboard(projectRoot = process.cwd()) {
|
|
167929
|
-
const metaprojectRoot =
|
|
168380
|
+
const metaprojectRoot = path322.join(projectRoot, ".metaproject");
|
|
167930
168381
|
if (!await pathExists(metaprojectRoot)) {
|
|
167931
168382
|
throw new Error("Metaproject is not initialized. Run: keryx init");
|
|
167932
168383
|
}
|
|
167933
168384
|
const manifest = (await readManifest5(metaprojectRoot)).manifest;
|
|
167934
168385
|
const data = await collectDashboardData(metaprojectRoot);
|
|
167935
|
-
const dashboardPath =
|
|
168386
|
+
const dashboardPath = path322.join(metaprojectRoot, "keryx-dashboard.html");
|
|
167936
168387
|
await writeTextIfChanged4(dashboardPath, renderMetaprojectDashboardHtml({
|
|
167937
168388
|
enableGdgraph: moduleEnabled2(manifest, "gdgraph"),
|
|
167938
168389
|
enableGdctx: moduleEnabled2(manifest, "gdctx"),
|
|
@@ -167952,7 +168403,7 @@ async function shouldInstallDashboardPostCommitHook(projectRoot, manifest) {
|
|
|
167952
168403
|
if (Object.values(modules).some((module) => Boolean(module.hooks?.gitPostCommit))) {
|
|
167953
168404
|
return true;
|
|
167954
168405
|
}
|
|
167955
|
-
const hookPath =
|
|
168406
|
+
const hookPath = path322.join(projectRoot, ".git", "hooks", "post-commit");
|
|
167956
168407
|
if (!await pathExists(hookPath)) {
|
|
167957
168408
|
return false;
|
|
167958
168409
|
}
|
|
@@ -167972,11 +168423,11 @@ async function collectDashboardData(metaprojectRoot) {
|
|
|
167972
168423
|
if (testing) {
|
|
167973
168424
|
data.testing = testing;
|
|
167974
168425
|
}
|
|
167975
|
-
const wiki = await collectMarkdownPages(
|
|
168426
|
+
const wiki = await collectMarkdownPages(path322.join(metaprojectRoot, "wiki"), "wiki");
|
|
167976
168427
|
if (wiki.length > 0) {
|
|
167977
168428
|
data.wiki = { pages: wiki };
|
|
167978
168429
|
}
|
|
167979
|
-
const memory = await collectMarkdownPages(
|
|
168430
|
+
const memory = await collectMarkdownPages(path322.join(metaprojectRoot, "memory"), "memory");
|
|
167980
168431
|
if (memory.length > 0) {
|
|
167981
168432
|
data.memory = { entries: memory };
|
|
167982
168433
|
}
|
|
@@ -167991,19 +168442,19 @@ async function collectDashboardData(metaprojectRoot) {
|
|
|
167991
168442
|
return data;
|
|
167992
168443
|
}
|
|
167993
168444
|
async function collectTasksDashboardData(metaprojectRoot) {
|
|
167994
|
-
const flowsRoot =
|
|
168445
|
+
const flowsRoot = path322.join(metaprojectRoot, "flows");
|
|
167995
168446
|
if (!await pathExists(flowsRoot)) {
|
|
167996
168447
|
return null;
|
|
167997
168448
|
}
|
|
167998
168449
|
let dirEntries;
|
|
167999
168450
|
try {
|
|
168000
|
-
dirEntries = (await
|
|
168451
|
+
dirEntries = (await readdir59(flowsRoot, { withFileTypes: true })).filter((entry) => entry.isDirectory() && /^\d{3}-/.test(entry.name)).map((entry) => entry.name).sort();
|
|
168001
168452
|
} catch {
|
|
168002
168453
|
return null;
|
|
168003
168454
|
}
|
|
168004
168455
|
const flows = [];
|
|
168005
168456
|
for (const dir of dirEntries) {
|
|
168006
|
-
const flowPath =
|
|
168457
|
+
const flowPath = path322.join(flowsRoot, dir, "flow.json");
|
|
168007
168458
|
if (!await pathExists(flowPath)) {
|
|
168008
168459
|
continue;
|
|
168009
168460
|
}
|
|
@@ -168011,7 +168462,7 @@ async function collectTasksDashboardData(metaprojectRoot) {
|
|
|
168011
168462
|
const flow = JSON.parse(await readFile164(flowPath, "utf8"));
|
|
168012
168463
|
const tasks = Array.isArray(flow.tasks) ? flow.tasks : [];
|
|
168013
168464
|
let acTotal = 0;
|
|
168014
|
-
const acPath =
|
|
168465
|
+
const acPath = path322.join(flowsRoot, dir, "acceptance-criteria.md");
|
|
168015
168466
|
if (await pathExists(acPath)) {
|
|
168016
168467
|
const acContent = await readFile164(acPath, "utf8");
|
|
168017
168468
|
acTotal = (acContent.match(/^- AC\d+:/gm) ?? []).length;
|
|
@@ -168065,7 +168516,7 @@ async function collectDashboardDocs(metaprojectRoot, wiki, memory) {
|
|
|
168065
168516
|
"data/testing/context.md"
|
|
168066
168517
|
];
|
|
168067
168518
|
for (const href of staticHrefs) {
|
|
168068
|
-
const filePath =
|
|
168519
|
+
const filePath = path322.join(metaprojectRoot, ...href.split("/"));
|
|
168069
168520
|
if (!await pathExists(filePath)) {
|
|
168070
168521
|
continue;
|
|
168071
168522
|
}
|
|
@@ -168082,7 +168533,7 @@ async function collectDashboardDocs(metaprojectRoot, wiki, memory) {
|
|
|
168082
168533
|
return docs;
|
|
168083
168534
|
}
|
|
168084
168535
|
async function collectHealthDashboardData(metaprojectRoot) {
|
|
168085
|
-
const reportPath =
|
|
168536
|
+
const reportPath = path322.join(metaprojectRoot, "data", "health", "artifacts", "latest.json");
|
|
168086
168537
|
if (!await pathExists(reportPath)) {
|
|
168087
168538
|
return;
|
|
168088
168539
|
}
|
|
@@ -168191,8 +168642,8 @@ function metricToScope(metric) {
|
|
|
168191
168642
|
};
|
|
168192
168643
|
}
|
|
168193
168644
|
async function collectGraphDashboardData(metaprojectRoot) {
|
|
168194
|
-
const nodesPath =
|
|
168195
|
-
const edgesPath =
|
|
168645
|
+
const nodesPath = path322.join(metaprojectRoot, "data", "gdgraph", "storage", "nodes.jsonl");
|
|
168646
|
+
const edgesPath = path322.join(metaprojectRoot, "data", "gdgraph", "storage", "edges.jsonl");
|
|
168196
168647
|
if (!await pathExists(nodesPath) || !await pathExists(edgesPath)) {
|
|
168197
168648
|
return;
|
|
168198
168649
|
}
|
|
@@ -168243,8 +168694,8 @@ async function collectGraphDashboardData(metaprojectRoot) {
|
|
|
168243
168694
|
};
|
|
168244
168695
|
}
|
|
168245
168696
|
async function collectTestingDashboardData(metaprojectRoot) {
|
|
168246
|
-
const reportPath =
|
|
168247
|
-
const contextPath =
|
|
168697
|
+
const reportPath = path322.join(metaprojectRoot, "data", "testing", "artifacts", "latest.json");
|
|
168698
|
+
const contextPath = path322.join(metaprojectRoot, "data", "testing", "context.md");
|
|
168248
168699
|
if (await pathExists(reportPath)) {
|
|
168249
168700
|
const report = JSON.parse(await readFile164(reportPath, "utf8"));
|
|
168250
168701
|
const totalTests = numberOrUndefined(report.total);
|
|
@@ -168273,7 +168724,7 @@ async function collectMarkdownPages(root, hrefPrefix) {
|
|
|
168273
168724
|
const files = await listMarkdownFiles(root);
|
|
168274
168725
|
const pages = [];
|
|
168275
168726
|
for (const filePath of files.slice(0, 40)) {
|
|
168276
|
-
const relativePath =
|
|
168727
|
+
const relativePath = path322.relative(root, filePath).split(path322.sep).join("/");
|
|
168277
168728
|
if (relativePath === "index.md" || relativePath.startsWith("templates/")) {
|
|
168278
168729
|
continue;
|
|
168279
168730
|
}
|
|
@@ -168291,10 +168742,10 @@ async function collectMarkdownPages(root, hrefPrefix) {
|
|
|
168291
168742
|
return pages;
|
|
168292
168743
|
}
|
|
168293
168744
|
async function listMarkdownFiles(root) {
|
|
168294
|
-
const entries = await
|
|
168745
|
+
const entries = await readdir59(root, { withFileTypes: true });
|
|
168295
168746
|
const files = [];
|
|
168296
168747
|
for (const entry of entries) {
|
|
168297
|
-
const fullPath =
|
|
168748
|
+
const fullPath = path322.join(root, entry.name);
|
|
168298
168749
|
if (entry.isDirectory()) {
|
|
168299
168750
|
files.push(...await listMarkdownFiles(fullPath));
|
|
168300
168751
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
@@ -168342,7 +168793,7 @@ async function writeRecoveredManifest(metaprojectRoot, modules) {
|
|
|
168342
168793
|
const manifest = {
|
|
168343
168794
|
schemaVersion: 1,
|
|
168344
168795
|
standardVersion: STANDARD_VERSION,
|
|
168345
|
-
name: `${
|
|
168796
|
+
name: `${path322.basename(path322.dirname(metaprojectRoot))}-metaproject`,
|
|
168346
168797
|
createdBy: "keryx",
|
|
168347
168798
|
profiles: computeProfiles(enabledModuleKeys),
|
|
168348
168799
|
paths: {
|
|
@@ -168433,13 +168884,13 @@ async function writeRecoveredManifest(metaprojectRoot, modules) {
|
|
|
168433
168884
|
}
|
|
168434
168885
|
};
|
|
168435
168886
|
{
|
|
168436
|
-
const { root, rel } = containFromMetaprojectPath(
|
|
168887
|
+
const { root, rel } = containFromMetaprojectPath(path322.join(metaprojectRoot, "metaproject.json"));
|
|
168437
168888
|
await writeContained(root, rel, `${JSON.stringify(manifest, null, 2)}
|
|
168438
168889
|
`);
|
|
168439
168890
|
}
|
|
168440
168891
|
}
|
|
168441
168892
|
async function enableTasksInManifest(metaprojectRoot) {
|
|
168442
|
-
const manifestPath =
|
|
168893
|
+
const manifestPath = path322.join(metaprojectRoot, "metaproject.json");
|
|
168443
168894
|
if (!await pathExists(manifestPath)) {
|
|
168444
168895
|
return;
|
|
168445
168896
|
}
|
|
@@ -168465,7 +168916,7 @@ async function enableTasksInManifest(metaprojectRoot) {
|
|
|
168465
168916
|
}
|
|
168466
168917
|
}
|
|
168467
168918
|
async function updateManifestAgentEntrypoints(metaprojectRoot, ruleSources) {
|
|
168468
|
-
const manifestPath =
|
|
168919
|
+
const manifestPath = path322.join(metaprojectRoot, "metaproject.json");
|
|
168469
168920
|
if (!await pathExists(manifestPath)) {
|
|
168470
168921
|
return;
|
|
168471
168922
|
}
|
|
@@ -168533,61 +168984,61 @@ async function updateRuntime(projectRoot) {
|
|
|
168533
168984
|
}
|
|
168534
168985
|
}
|
|
168535
168986
|
async function findRuntimeRoot(projectRoot) {
|
|
168536
|
-
const projectRuntime =
|
|
168537
|
-
if (await pathExists(
|
|
168987
|
+
const projectRuntime = path322.join(projectRoot, ".metaproject", "runtime", "keryx");
|
|
168988
|
+
if (await pathExists(path322.join(projectRuntime, ".git"))) {
|
|
168538
168989
|
return projectRuntime;
|
|
168539
168990
|
}
|
|
168540
168991
|
const home = process.env.HOME;
|
|
168541
168992
|
if (!home) {
|
|
168542
168993
|
return null;
|
|
168543
168994
|
}
|
|
168544
|
-
const globalRuntime =
|
|
168545
|
-
if (await pathExists(
|
|
168995
|
+
const globalRuntime = path322.join(home, ".keryx", "keryx");
|
|
168996
|
+
if (await pathExists(path322.join(globalRuntime, ".git"))) {
|
|
168546
168997
|
return globalRuntime;
|
|
168547
168998
|
}
|
|
168548
168999
|
return null;
|
|
168549
169000
|
}
|
|
168550
169001
|
async function createServiceDirs(metaprojectRoot, modules) {
|
|
168551
169002
|
const dirs = [
|
|
168552
|
-
|
|
168553
|
-
|
|
168554
|
-
|
|
168555
|
-
|
|
168556
|
-
|
|
169003
|
+
path322.join(metaprojectRoot, "core"),
|
|
169004
|
+
path322.join(metaprojectRoot, "hooks", "post-update.d"),
|
|
169005
|
+
path322.join(metaprojectRoot, "modules"),
|
|
169006
|
+
path322.join(metaprojectRoot, "rules"),
|
|
169007
|
+
path322.join(metaprojectRoot, "skills", "project-rules"),
|
|
168557
169008
|
...modules.enableGdgraph ? [
|
|
168558
|
-
|
|
168559
|
-
|
|
169009
|
+
path322.join(metaprojectRoot, "core", "gdgraph"),
|
|
169010
|
+
path322.join(metaprojectRoot, "skills", "gdgraph")
|
|
168560
169011
|
] : [],
|
|
168561
169012
|
...modules.enableGdctx ? [
|
|
168562
|
-
|
|
168563
|
-
|
|
169013
|
+
path322.join(metaprojectRoot, "core", "gdctx"),
|
|
169014
|
+
path322.join(metaprojectRoot, "skills", "gdctx")
|
|
168564
169015
|
] : [],
|
|
168565
169016
|
...modules.enableGdwiki ? [
|
|
168566
|
-
|
|
168567
|
-
|
|
169017
|
+
path322.join(metaprojectRoot, "skills", "gdwiki"),
|
|
169018
|
+
path322.join(metaprojectRoot, "wiki", "templates")
|
|
168568
169019
|
] : [],
|
|
168569
169020
|
...modules.enableHealth ? [
|
|
168570
|
-
|
|
168571
|
-
|
|
169021
|
+
path322.join(metaprojectRoot, "core", "health"),
|
|
169022
|
+
path322.join(metaprojectRoot, "skills", "health")
|
|
168572
169023
|
] : [],
|
|
168573
169024
|
...modules.enableTesting ? [
|
|
168574
|
-
|
|
168575
|
-
|
|
169025
|
+
path322.join(metaprojectRoot, "core", "testing"),
|
|
169026
|
+
path322.join(metaprojectRoot, "skills", "testing")
|
|
168576
169027
|
] : [],
|
|
168577
169028
|
...modules.enableMemory ? [
|
|
168578
|
-
|
|
168579
|
-
|
|
168580
|
-
|
|
169029
|
+
path322.join(metaprojectRoot, "core", "memory"),
|
|
169030
|
+
path322.join(metaprojectRoot, "skills", "memory"),
|
|
169031
|
+
path322.join(metaprojectRoot, "memory", "templates")
|
|
168581
169032
|
] : [],
|
|
168582
169033
|
...modules.enableTasks ? [
|
|
168583
|
-
|
|
168584
|
-
|
|
169034
|
+
path322.join(metaprojectRoot, "flows"),
|
|
169035
|
+
path322.join(metaprojectRoot, "skills", "flow")
|
|
168585
169036
|
] : [],
|
|
168586
169037
|
...modules.enableSecurity ? [
|
|
168587
|
-
|
|
169038
|
+
path322.join(metaprojectRoot, "core", "security")
|
|
168588
169039
|
] : [],
|
|
168589
169040
|
...modules.enableSac ? [
|
|
168590
|
-
|
|
169041
|
+
path322.join(metaprojectRoot, "skills", "sac")
|
|
168591
169042
|
] : []
|
|
168592
169043
|
];
|
|
168593
169044
|
await Promise.all(dirs.map((dir) => {
|
|
@@ -168596,22 +169047,22 @@ async function createServiceDirs(metaprojectRoot, modules) {
|
|
|
168596
169047
|
}));
|
|
168597
169048
|
}
|
|
168598
169049
|
async function installGdgraphCoreScripts2(metaprojectRoot) {
|
|
168599
|
-
const gdgraphCoreRoot =
|
|
169050
|
+
const gdgraphCoreRoot = path322.join(metaprojectRoot, "core", "gdgraph");
|
|
168600
169051
|
{
|
|
168601
169052
|
const { root, rel } = containFromMetaprojectPath(gdgraphCoreRoot);
|
|
168602
169053
|
await mkdirContained(root, rel);
|
|
168603
169054
|
}
|
|
168604
169055
|
for (const file of GDGRAPH_CORE_SOURCES) {
|
|
168605
|
-
await copyFileIfChanged2(runtimeSourcePath2(`../gdgraph/${file}`),
|
|
169056
|
+
await copyFileIfChanged2(runtimeSourcePath2(`../gdgraph/${file}`), path322.join(gdgraphCoreRoot, file));
|
|
168606
169057
|
}
|
|
168607
|
-
await writeTextIfChanged4(
|
|
169058
|
+
await writeTextIfChanged4(path322.join(gdgraphCoreRoot, "cli.ts"), renderGdgraphCoreCli());
|
|
168608
169059
|
}
|
|
168609
169060
|
async function prePushHasSecurityBlock2(projectRoot) {
|
|
168610
169061
|
const hooksRoot = await resolveGitHooksRoot(projectRoot);
|
|
168611
169062
|
if (!hooksRoot) {
|
|
168612
169063
|
return false;
|
|
168613
169064
|
}
|
|
168614
|
-
const hookPath =
|
|
169065
|
+
const hookPath = path322.join(hooksRoot, "pre-push");
|
|
168615
169066
|
if (!await pathExists(hookPath)) {
|
|
168616
169067
|
return false;
|
|
168617
169068
|
}
|
|
@@ -168626,7 +169077,7 @@ async function agentSettingsHasSecuritySentinel2(projectRoot) {
|
|
|
168626
169077
|
return (await readFile164(file, "utf8")).includes(AGENT_HOOKS_SENTINEL);
|
|
168627
169078
|
}
|
|
168628
169079
|
async function readManifest5(metaprojectRoot) {
|
|
168629
|
-
const manifestPath =
|
|
169080
|
+
const manifestPath = path322.join(metaprojectRoot, "metaproject.json");
|
|
168630
169081
|
if (!await pathExists(manifestPath)) {
|
|
168631
169082
|
return {
|
|
168632
169083
|
exists: false,
|
|
@@ -168695,7 +169146,7 @@ async function inferManifestFromExistingMetaproject(metaprojectRoot) {
|
|
|
168695
169146
|
}
|
|
168696
169147
|
async function anyPathExists(root, candidates) {
|
|
168697
169148
|
for (const candidate of candidates) {
|
|
168698
|
-
if (await pathExists(
|
|
169149
|
+
if (await pathExists(path322.join(root, candidate))) {
|
|
168699
169150
|
return true;
|
|
168700
169151
|
}
|
|
168701
169152
|
}
|
|
@@ -168718,13 +169169,13 @@ function parseUpdateArgs(args) {
|
|
|
168718
169169
|
};
|
|
168719
169170
|
}
|
|
168720
169171
|
async function runPostUpdateHooks(projectRoot) {
|
|
168721
|
-
const hooksDir =
|
|
169172
|
+
const hooksDir = path322.join(projectRoot, ".metaproject", "hooks", "post-update.d");
|
|
168722
169173
|
if (!await pathExists(hooksDir)) {
|
|
168723
169174
|
return;
|
|
168724
169175
|
}
|
|
168725
|
-
const entries = (await
|
|
169176
|
+
const entries = (await readdir59(hooksDir)).sort();
|
|
168726
169177
|
for (const entry of entries) {
|
|
168727
|
-
const hookPath =
|
|
169178
|
+
const hookPath = path322.join(hooksDir, entry);
|
|
168728
169179
|
try {
|
|
168729
169180
|
await accessExecutable(hookPath);
|
|
168730
169181
|
} catch {
|
|
@@ -168785,12 +169236,12 @@ async function copyFileIfChanged2(from, to) {
|
|
|
168785
169236
|
}
|
|
168786
169237
|
function runtimeSourcePath2(relativePath) {
|
|
168787
169238
|
const directPath = fileURLToPath10(new URL(relativePath, import.meta.url));
|
|
168788
|
-
if (
|
|
169239
|
+
if (existsSync51(directPath)) {
|
|
168789
169240
|
return directPath;
|
|
168790
169241
|
}
|
|
168791
169242
|
if (relativePath.startsWith("../")) {
|
|
168792
|
-
const packagedSourcePath =
|
|
168793
|
-
if (
|
|
169243
|
+
const packagedSourcePath = path322.join(path322.dirname(fileURLToPath10(import.meta.url)), "..", "src", relativePath.slice(3));
|
|
169244
|
+
if (existsSync51(packagedSourcePath)) {
|
|
168794
169245
|
return packagedSourcePath;
|
|
168795
169246
|
}
|
|
168796
169247
|
}
|
|
@@ -168821,7 +169272,7 @@ function printHelp24() {
|
|
|
168821
169272
|
|
|
168822
169273
|
// src/commands/dashboard.ts
|
|
168823
169274
|
import { spawn as spawn10 } from "child_process";
|
|
168824
|
-
import
|
|
169275
|
+
import path323 from "path";
|
|
168825
169276
|
init_args();
|
|
168826
169277
|
init_ui();
|
|
168827
169278
|
async function dashboardCommand(args = []) {
|
|
@@ -168833,7 +169284,7 @@ async function dashboardCommand(args = []) {
|
|
|
168833
169284
|
}
|
|
168834
169285
|
if (subcommand === "build") {
|
|
168835
169286
|
const result = await buildDashboard();
|
|
168836
|
-
const rel =
|
|
169287
|
+
const rel = path323.relative(process.cwd(), result.path);
|
|
168837
169288
|
console.log(` ${style.green(symbols.ok)} Dashboard built ${style.cyan(symbols.arrow)} ${style.cyan(rel)}`);
|
|
168838
169289
|
note(`Open it: keryx dashboard open`);
|
|
168839
169290
|
return;
|
|
@@ -168841,7 +169292,7 @@ async function dashboardCommand(args = []) {
|
|
|
168841
169292
|
if (subcommand === "open") {
|
|
168842
169293
|
const result = await buildDashboard();
|
|
168843
169294
|
await openFile(result.path);
|
|
168844
|
-
const rel =
|
|
169295
|
+
const rel = path323.relative(process.cwd(), result.path);
|
|
168845
169296
|
console.log(` ${style.green(symbols.ok)} Opened ${style.cyan(rel)}`);
|
|
168846
169297
|
return;
|
|
168847
169298
|
}
|
|
@@ -168892,7 +169343,7 @@ import { readFileSync as readFileSync27 } from "fs";
|
|
|
168892
169343
|
import { randomUUID as randomUUID46 } from "crypto";
|
|
168893
169344
|
import { mkdir as mkdir69 } from "fs/promises";
|
|
168894
169345
|
import { tmpdir as tmpdir12 } from "os";
|
|
168895
|
-
import
|
|
169346
|
+
import path324 from "path";
|
|
168896
169347
|
import { createInterface as createInterface3 } from "readline";
|
|
168897
169348
|
|
|
168898
169349
|
// src/harness/external-agent-probe.ts
|
|
@@ -169154,7 +169605,7 @@ async function runCommand4(args, deps, log) {
|
|
|
169154
169605
|
const requestApproval = unattended ? undefined : seams.requestApproval ?? terminalApprover();
|
|
169155
169606
|
const timeoutRaw = optionValue(args, "--timeout");
|
|
169156
169607
|
const timeoutMs = timeoutRaw !== undefined && Number.isInteger(Number(timeoutRaw)) && Number(timeoutRaw) > 0 ? Number(timeoutRaw) : gate.config.defaultTimeoutMs;
|
|
169157
|
-
const worktreesDir =
|
|
169608
|
+
const worktreesDir = path324.join(tmpdir12(), "keryx-external-worktrees");
|
|
169158
169609
|
const worktree = seams.worktree ?? createGitWorktreePort({ repoRoot: cwd, worktreesDir });
|
|
169159
169610
|
if (seams.worktree === undefined)
|
|
169160
169611
|
await mkdir69(worktreesDir, { recursive: true });
|
|
@@ -169242,8 +169693,8 @@ init_service8();
|
|
|
169242
169693
|
init_bundled_eval();
|
|
169243
169694
|
init_args();
|
|
169244
169695
|
init_ui();
|
|
169245
|
-
import { existsSync as
|
|
169246
|
-
import
|
|
169696
|
+
import { existsSync as existsSync52, lstatSync as lstatSync7, readFileSync as readFileSync26, writeFileSync as writeFileSync11 } from "fs";
|
|
169697
|
+
import path325 from "path";
|
|
169247
169698
|
function resolveDeps(deps) {
|
|
169248
169699
|
return {
|
|
169249
169700
|
cwd: deps.cwd ?? process.cwd(),
|
|
@@ -169576,11 +170027,11 @@ function generateCommand(args, depsIn) {
|
|
|
169576
170027
|
process.exitCode = 1;
|
|
169577
170028
|
return;
|
|
169578
170029
|
}
|
|
169579
|
-
const bundledAgentsRoot =
|
|
169580
|
-
const stacksRoot =
|
|
169581
|
-
const packDir =
|
|
169582
|
-
const packJsonPath =
|
|
169583
|
-
if (!
|
|
170030
|
+
const bundledAgentsRoot = path325.join(depsIn.bundledRoot ?? defaultBundledRoot(), "agents");
|
|
170031
|
+
const stacksRoot = path325.join(bundledAgentsRoot, "..", "stacks");
|
|
170032
|
+
const packDir = path325.join(stacksRoot, stackId);
|
|
170033
|
+
const packJsonPath = path325.join(packDir, "pack.json");
|
|
170034
|
+
if (!existsSync52(packJsonPath)) {
|
|
169584
170035
|
error(`No stack pack "${stackId}" found at ${packJsonPath}.`);
|
|
169585
170036
|
process.exitCode = 1;
|
|
169586
170037
|
return;
|
|
@@ -169626,9 +170077,9 @@ function generateCommand(args, depsIn) {
|
|
|
169626
170077
|
}
|
|
169627
170078
|
const prepared = [];
|
|
169628
170079
|
for (const file of generatedFiles) {
|
|
169629
|
-
const filePath =
|
|
169630
|
-
const relative =
|
|
169631
|
-
if (relative.startsWith("..") ||
|
|
170080
|
+
const filePath = path325.join(bundledAgentsRoot, file.fileName);
|
|
170081
|
+
const relative = path325.relative(bundledAgentsRoot, filePath);
|
|
170082
|
+
if (relative.startsWith("..") || path325.isAbsolute(relative)) {
|
|
169632
170083
|
error(`Refusing to write "${file.fileName}": it resolves outside the bundled agents directory.`);
|
|
169633
170084
|
process.exitCode = 1;
|
|
169634
170085
|
return;
|
|
@@ -169949,7 +170400,7 @@ function printBootstrapHelp() {
|
|
|
169949
170400
|
// src/commands/metrics.ts
|
|
169950
170401
|
init_args();
|
|
169951
170402
|
import { readFile as readFile165 } from "fs/promises";
|
|
169952
|
-
import
|
|
170403
|
+
import path327 from "path";
|
|
169953
170404
|
|
|
169954
170405
|
// src/metrics/benchmark.ts
|
|
169955
170406
|
var RELIABILITIES2 = new Set(["exact", "estimated", "unknown"]);
|
|
@@ -170766,7 +171217,7 @@ function buildContainmentManifest(inputs, options = {}) {
|
|
|
170766
171217
|
|
|
170767
171218
|
// src/metrics/oracle-runner.ts
|
|
170768
171219
|
import { mkdir as mkdir70, writeFile as writeFile48 } from "fs/promises";
|
|
170769
|
-
import
|
|
171220
|
+
import path326 from "path";
|
|
170770
171221
|
|
|
170771
171222
|
// src/metrics/ir.ts
|
|
170772
171223
|
function toIdSet(ids) {
|
|
@@ -171212,9 +171663,9 @@ function buildEvidenceBundle(input, options = {}) {
|
|
|
171212
171663
|
async function persistEvidenceBundle(outDir, bundle, ladder = "metastore") {
|
|
171213
171664
|
const safeTarget = bundle.target.replace(/[^A-Za-z0-9._/-]/g, "_");
|
|
171214
171665
|
const safeCase = bundle.caseId.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
171215
|
-
const dir =
|
|
171666
|
+
const dir = path326.join(outDir, "bench", ladder, safeTarget, safeCase, bundle.variant, String(bundle.seed));
|
|
171216
171667
|
await mkdir70(dir, { recursive: true });
|
|
171217
|
-
const write = (name, value) => writeFile48(
|
|
171668
|
+
const write = (name, value) => writeFile48(path326.join(dir, name), `${JSON.stringify(value, null, 2)}
|
|
171218
171669
|
`, "utf8");
|
|
171219
171670
|
await Promise.all([
|
|
171220
171671
|
write("inputs.json", bundle.inputs),
|
|
@@ -171254,7 +171705,7 @@ async function metricsCommand(args = [], projectRoot = process.cwd()) {
|
|
|
171254
171705
|
console.log("# metrics status");
|
|
171255
171706
|
console.log("");
|
|
171256
171707
|
console.log(`root: ${root}`);
|
|
171257
|
-
console.log(`enabled: ${await Bun.file(
|
|
171708
|
+
console.log(`enabled: ${await Bun.file(path327.join(projectRoot, ".metaproject", "metaproject.json")).exists() ? "yes" : "no"}`);
|
|
171258
171709
|
const latest = await readLatestPointer(root);
|
|
171259
171710
|
console.log(`latest: ${latest.status}`);
|
|
171260
171711
|
return;
|
|
@@ -171266,7 +171717,7 @@ async function metricsCommand(args = [], projectRoot = process.cwd()) {
|
|
|
171266
171717
|
process.exitCode = 1;
|
|
171267
171718
|
return;
|
|
171268
171719
|
}
|
|
171269
|
-
const record = JSON.parse(await readFile165(
|
|
171720
|
+
const record = JSON.parse(await readFile165(path327.resolve(projectRoot, file), "utf8"));
|
|
171270
171721
|
const result = validateRunRecord(record);
|
|
171271
171722
|
console.log(result.valid ? "valid: yes" : "valid: no");
|
|
171272
171723
|
for (const error of result.errors)
|
|
@@ -171291,7 +171742,7 @@ async function metricsCommand(args = [], projectRoot = process.cwd()) {
|
|
|
171291
171742
|
process.exitCode = 1;
|
|
171292
171743
|
return;
|
|
171293
171744
|
}
|
|
171294
|
-
const file =
|
|
171745
|
+
const file = path327.join(metricsRoot(projectRoot), "runs", `${runId}.json`);
|
|
171295
171746
|
if (!await Bun.file(file).exists()) {
|
|
171296
171747
|
console.error(`Run not found: ${runId}`);
|
|
171297
171748
|
process.exitCode = 1;
|
|
@@ -171308,8 +171759,8 @@ async function metricsCommand(args = [], projectRoot = process.cwd()) {
|
|
|
171308
171759
|
process.exitCode = 1;
|
|
171309
171760
|
return;
|
|
171310
171761
|
}
|
|
171311
|
-
const a = JSON.parse(await readFile165(
|
|
171312
|
-
const b = JSON.parse(await readFile165(
|
|
171762
|
+
const a = JSON.parse(await readFile165(path327.join(metricsRoot(projectRoot), "runs", `${runA}.json`), "utf8"));
|
|
171763
|
+
const b = JSON.parse(await readFile165(path327.join(metricsRoot(projectRoot), "runs", `${runB}.json`), "utf8"));
|
|
171313
171764
|
const comparison = compareExecutionRuns(a, b);
|
|
171314
171765
|
console.log(stableJson(comparison));
|
|
171315
171766
|
return;
|
|
@@ -171343,8 +171794,8 @@ async function metricsCommand(args = [], projectRoot = process.cwd()) {
|
|
|
171343
171794
|
return;
|
|
171344
171795
|
}
|
|
171345
171796
|
const template = createPairedBenchmarkTemplate(taskIds);
|
|
171346
|
-
await Bun.write(
|
|
171347
|
-
console.log(`manifest: ${
|
|
171797
|
+
await Bun.write(path327.resolve(projectRoot, out), stableJson(template));
|
|
171798
|
+
console.log(`manifest: ${path327.relative(projectRoot, path327.resolve(projectRoot, out))}`);
|
|
171348
171799
|
return;
|
|
171349
171800
|
}
|
|
171350
171801
|
if (subcommand === "benchmark" && args[1] === "run") {
|
|
@@ -171358,7 +171809,7 @@ async function metricsCommand(args = [], projectRoot = process.cwd()) {
|
|
|
171358
171809
|
process.exitCode = 1;
|
|
171359
171810
|
return;
|
|
171360
171811
|
}
|
|
171361
|
-
const raw = JSON.parse(await readFile165(
|
|
171812
|
+
const raw = JSON.parse(await readFile165(path327.resolve(projectRoot, file), "utf8"));
|
|
171362
171813
|
const input = Array.isArray(raw) ? raw : raw.runs ?? [];
|
|
171363
171814
|
const result = validatePairedBenchmark(input);
|
|
171364
171815
|
console.log(stableJson(result));
|
|
@@ -171370,7 +171821,7 @@ async function metricsCommand(args = [], projectRoot = process.cwd()) {
|
|
|
171370
171821
|
process.exitCode = 1;
|
|
171371
171822
|
}
|
|
171372
171823
|
async function loadAffectedSets(projectRoot, file) {
|
|
171373
|
-
const raw = JSON.parse(await readFile165(
|
|
171824
|
+
const raw = JSON.parse(await readFile165(path327.resolve(projectRoot, file), "utf8"));
|
|
171374
171825
|
const map = new Map;
|
|
171375
171826
|
for (const entry of raw.targets ?? []) {
|
|
171376
171827
|
if (typeof entry.target === "string")
|
|
@@ -171441,7 +171892,7 @@ async function runHarnessLayer(projectRoot, args, ladder) {
|
|
|
171441
171892
|
let tasks;
|
|
171442
171893
|
let model;
|
|
171443
171894
|
try {
|
|
171444
|
-
const raw = JSON.parse(await readFile165(
|
|
171895
|
+
const raw = JSON.parse(await readFile165(path327.resolve(projectRoot, resultsPath), "utf8"));
|
|
171445
171896
|
tasks = raw.tasks ?? [];
|
|
171446
171897
|
model = raw.model;
|
|
171447
171898
|
} catch (error) {
|
|
@@ -171472,7 +171923,7 @@ async function runSafetyCompletionHonestyLayer(projectRoot, args, ladder) {
|
|
|
171472
171923
|
let cases;
|
|
171473
171924
|
let model;
|
|
171474
171925
|
try {
|
|
171475
|
-
const raw = JSON.parse(await readFile165(
|
|
171926
|
+
const raw = JSON.parse(await readFile165(path327.resolve(projectRoot, resultsPath), "utf8"));
|
|
171476
171927
|
cases = raw.cases ?? [];
|
|
171477
171928
|
model = raw.model;
|
|
171478
171929
|
} catch (error) {
|
|
@@ -171497,7 +171948,7 @@ async function runSafetyFalsePremiseLayer(projectRoot, args, ladder) {
|
|
|
171497
171948
|
let cases;
|
|
171498
171949
|
let model;
|
|
171499
171950
|
try {
|
|
171500
|
-
const raw = JSON.parse(await readFile165(
|
|
171951
|
+
const raw = JSON.parse(await readFile165(path327.resolve(projectRoot, resultsPath), "utf8"));
|
|
171501
171952
|
cases = raw.cases ?? [];
|
|
171502
171953
|
model = raw.model;
|
|
171503
171954
|
} catch (error) {
|
|
@@ -171522,7 +171973,7 @@ async function runSafetyContainmentLayer(projectRoot, args, ladder, caseClass) {
|
|
|
171522
171973
|
let cases;
|
|
171523
171974
|
let model;
|
|
171524
171975
|
try {
|
|
171525
|
-
const raw = JSON.parse(await readFile165(
|
|
171976
|
+
const raw = JSON.parse(await readFile165(path327.resolve(projectRoot, resultsPath), "utf8"));
|
|
171526
171977
|
cases = raw.cases ?? [];
|
|
171527
171978
|
model = raw.model;
|
|
171528
171979
|
} catch (error) {
|
|
@@ -171584,12 +172035,12 @@ async function runGdgraphLayer(projectRoot, args, ladder) {
|
|
|
171584
172035
|
}
|
|
171585
172036
|
const manifests = buildOracleManifestsByGold(inputs, { ladder });
|
|
171586
172037
|
if (outDir) {
|
|
171587
|
-
const resolvedOut =
|
|
172038
|
+
const resolvedOut = path327.resolve(projectRoot, outDir);
|
|
171588
172039
|
for (const input of inputs) {
|
|
171589
172040
|
for (const named of input.golds) {
|
|
171590
172041
|
const bundle = buildEvidenceBundle({ target: input.target, system: input.system, gold: named.gold }, { ladder, goldReference: goldPathFor(named.kind), timestamp: new Date().toISOString() });
|
|
171591
|
-
const dir = await persistEvidenceBundle(
|
|
171592
|
-
console.error(`bundle[${named.kind}]: ${
|
|
172042
|
+
const dir = await persistEvidenceBundle(path327.join(resolvedOut, named.kind), bundle, ladder);
|
|
172043
|
+
console.error(`bundle[${named.kind}]: ${path327.relative(projectRoot, dir)}`);
|
|
171593
172044
|
}
|
|
171594
172045
|
}
|
|
171595
172046
|
}
|
|
@@ -171613,7 +172064,7 @@ async function runGdgraphLayer(projectRoot, args, ladder) {
|
|
|
171613
172064
|
return allValid;
|
|
171614
172065
|
}
|
|
171615
172066
|
async function loadCoverageMap2(projectRoot, file) {
|
|
171616
|
-
const raw = JSON.parse(await readFile165(
|
|
172067
|
+
const raw = JSON.parse(await readFile165(path327.resolve(projectRoot, file), "utf8"));
|
|
171617
172068
|
return raw.coverageMap ?? {};
|
|
171618
172069
|
}
|
|
171619
172070
|
async function runTestingLayer(projectRoot, args, ladder) {
|
|
@@ -171650,7 +172101,7 @@ async function runTestingLayer(projectRoot, args, ladder) {
|
|
|
171650
172101
|
return result.valid;
|
|
171651
172102
|
}
|
|
171652
172103
|
async function loadMemoryGoldK(projectRoot, file) {
|
|
171653
|
-
const raw = JSON.parse(await readFile165(
|
|
172104
|
+
const raw = JSON.parse(await readFile165(path327.resolve(projectRoot, file), "utf8"));
|
|
171654
172105
|
return typeof raw.k === "number" && raw.k > 0 ? raw.k : 3;
|
|
171655
172106
|
}
|
|
171656
172107
|
async function runMemoryLayer(projectRoot, args, ladder) {
|
|
@@ -171687,11 +172138,11 @@ async function runMemoryLayer(projectRoot, args, ladder) {
|
|
|
171687
172138
|
return result.valid;
|
|
171688
172139
|
}
|
|
171689
172140
|
async function loadWikiGoldK(projectRoot, file) {
|
|
171690
|
-
const raw = JSON.parse(await readFile165(
|
|
172141
|
+
const raw = JSON.parse(await readFile165(path327.resolve(projectRoot, file), "utf8"));
|
|
171691
172142
|
return typeof raw.k === "number" && raw.k > 0 ? raw.k : 5;
|
|
171692
172143
|
}
|
|
171693
172144
|
async function loadWikiGroundedness(projectRoot, file) {
|
|
171694
|
-
const raw = JSON.parse(await readFile165(
|
|
172145
|
+
const raw = JSON.parse(await readFile165(path327.resolve(projectRoot, file), "utf8"));
|
|
171695
172146
|
const map = new Map;
|
|
171696
172147
|
for (const entry of raw.targets ?? []) {
|
|
171697
172148
|
if (typeof entry.target !== "string" || !Array.isArray(entry.scores) || entry.scores.length !== 3)
|
|
@@ -171747,7 +172198,7 @@ async function runWikiLayer(projectRoot, args, ladder) {
|
|
|
171747
172198
|
return result.valid;
|
|
171748
172199
|
}
|
|
171749
172200
|
async function loadGdctxFacts(projectRoot, file) {
|
|
171750
|
-
const raw = JSON.parse(await readFile165(
|
|
172201
|
+
const raw = JSON.parse(await readFile165(path327.resolve(projectRoot, file), "utf8"));
|
|
171751
172202
|
const inputs = [];
|
|
171752
172203
|
for (const entry of raw.inputs ?? []) {
|
|
171753
172204
|
if (typeof entry.input === "string") {
|
|
@@ -171785,7 +172236,7 @@ async function collect(projectRoot, args) {
|
|
|
171785
172236
|
process.exitCode = 1;
|
|
171786
172237
|
return;
|
|
171787
172238
|
}
|
|
171788
|
-
const raw = JSON.parse(await readFile165(
|
|
172239
|
+
const raw = JSON.parse(await readFile165(path327.resolve(projectRoot, eventFile), "utf8"));
|
|
171789
172240
|
const events = Array.isArray(raw) ? raw : raw.events;
|
|
171790
172241
|
const startedAt = optionValue(args, "--started-at") ?? events[0]?.timestamp_utc ?? new Date().toISOString();
|
|
171791
172242
|
const finishedAt = optionValue(args, "--finished-at") ?? events.at(-1)?.timestamp_utc ?? startedAt;
|
|
@@ -171801,11 +172252,11 @@ async function collect(projectRoot, args) {
|
|
|
171801
172252
|
parentRunId: optionValue(args, "--parent-run-id") ?? null
|
|
171802
172253
|
});
|
|
171803
172254
|
const result = await writeRunArtifacts(metricsRoot(projectRoot), record, { cwd: projectRoot });
|
|
171804
|
-
console.log(`json: ${
|
|
171805
|
-
console.log(`markdown: ${
|
|
172255
|
+
console.log(`json: ${path327.relative(projectRoot, result.jsonPath)}`);
|
|
172256
|
+
console.log(`markdown: ${path327.relative(projectRoot, result.markdownPath)}`);
|
|
171806
172257
|
}
|
|
171807
172258
|
function metricsRoot(projectRoot) {
|
|
171808
|
-
return
|
|
172259
|
+
return path327.join(projectRoot, ".metaproject", "data", "metrics");
|
|
171809
172260
|
}
|
|
171810
172261
|
function printMetricsHelp() {
|
|
171811
172262
|
console.log(`keryx metrics
|
|
@@ -173222,8 +173673,8 @@ init_contained_write();
|
|
|
173222
173673
|
init_prompt();
|
|
173223
173674
|
init_terminal_safe();
|
|
173224
173675
|
init_agent_hooks();
|
|
173225
|
-
import { existsSync as
|
|
173226
|
-
import
|
|
173676
|
+
import { existsSync as existsSync53, readFileSync as readFileSync28 } from "fs";
|
|
173677
|
+
import path328 from "path";
|
|
173227
173678
|
init_hooks();
|
|
173228
173679
|
init_package();
|
|
173229
173680
|
var CLI_VERSION = package_default.version;
|
|
@@ -173239,10 +173690,10 @@ function optConfigDir(deps) {
|
|
|
173239
173690
|
return deps.configDir !== undefined ? { configDir: deps.configDir } : {};
|
|
173240
173691
|
}
|
|
173241
173692
|
function userHooksPath(homeDir) {
|
|
173242
|
-
return
|
|
173693
|
+
return path328.join(homeDir, ".keryx", "hooks.json");
|
|
173243
173694
|
}
|
|
173244
173695
|
function projectHooksPath(projectRoot) {
|
|
173245
|
-
return
|
|
173696
|
+
return path328.join(projectRoot, ".metaproject", "hooks.json");
|
|
173246
173697
|
}
|
|
173247
173698
|
function fail3(message) {
|
|
173248
173699
|
console.error(message);
|
|
@@ -173363,10 +173814,10 @@ async function runList6(args, deps) {
|
|
|
173363
173814
|
function argv0Resolves(argv0) {
|
|
173364
173815
|
if (argv0 === "keryx")
|
|
173365
173816
|
return true;
|
|
173366
|
-
if (
|
|
173367
|
-
return
|
|
173817
|
+
if (path328.isAbsolute(argv0))
|
|
173818
|
+
return existsSync53(argv0);
|
|
173368
173819
|
const pathEnv = process.env.PATH ?? "";
|
|
173369
|
-
return pathEnv.split(
|
|
173820
|
+
return pathEnv.split(path328.delimiter).filter((dir) => dir.length > 0).some((dir) => existsSync53(path328.join(dir, argv0)));
|
|
173370
173821
|
}
|
|
173371
173822
|
function checkArgvResolutions(registrations) {
|
|
173372
173823
|
const seen = new Set;
|
|
@@ -173821,8 +174272,8 @@ async function writeDocAtomic(filePath, doc, scope, cwd, homeDir) {
|
|
|
173821
174272
|
if (scope === "project") {
|
|
173822
174273
|
await writeContained(cwd, PROJECT_HOOKS_REL, body);
|
|
173823
174274
|
} else {
|
|
173824
|
-
const userConfigDir =
|
|
173825
|
-
if (!
|
|
174275
|
+
const userConfigDir = path328.join(homeDir, ".keryx");
|
|
174276
|
+
if (!existsSync53(userConfigDir)) {
|
|
173826
174277
|
await mkdirContained(homeDir, ".keryx");
|
|
173827
174278
|
}
|
|
173828
174279
|
await writeContained(userConfigDir, "hooks.json", body);
|
|
@@ -174079,7 +174530,7 @@ init_ui();
|
|
|
174079
174530
|
init_args();
|
|
174080
174531
|
init_contained_path();
|
|
174081
174532
|
init_package();
|
|
174082
|
-
import
|
|
174533
|
+
import path337 from "path";
|
|
174083
174534
|
|
|
174084
174535
|
// src/bundle/types.ts
|
|
174085
174536
|
var BUNDLE_FORMAT_VERSION = "1.0.0";
|
|
@@ -174133,13 +174584,13 @@ init_contained_path();
|
|
|
174133
174584
|
init_keryx_home();
|
|
174134
174585
|
init_types3();
|
|
174135
174586
|
import { lstat as lstat18, readFile as readFile166 } from "fs/promises";
|
|
174136
|
-
import
|
|
174587
|
+
import path329 from "path";
|
|
174137
174588
|
var MEMORY_FOLDERS = new Set(MEMORY_TYPES.map((entry) => entry.folder));
|
|
174138
174589
|
function scopeRoot(scope, ctx) {
|
|
174139
174590
|
if (scope === "user") {
|
|
174140
174591
|
return userStoreRoot(ctx.env ?? process.env, ctx.homeDir);
|
|
174141
174592
|
}
|
|
174142
|
-
return
|
|
174593
|
+
return path329.join(ctx.projectRoot, ".metaproject");
|
|
174143
174594
|
}
|
|
174144
174595
|
var CONTROL_CHAR_RE = /[\x00-\x1f\x7f\u2028\u2029]/;
|
|
174145
174596
|
var MARKER_FORGING_RE = /[<>`]|<!--|-->/;
|
|
@@ -174328,10 +174779,10 @@ async function targetFor(entry, targetScope, ctx) {
|
|
|
174328
174779
|
return { ok: true, absolutePath: containment.absolutePath };
|
|
174329
174780
|
}
|
|
174330
174781
|
async function resolveContainedPathForWrite(root, relPath) {
|
|
174331
|
-
const absolute =
|
|
174332
|
-
const rootResolved =
|
|
174333
|
-
const relative =
|
|
174334
|
-
if (relative === "" || relative === ".." || relative.startsWith(`..${
|
|
174782
|
+
const absolute = path329.resolve(root, relPath);
|
|
174783
|
+
const rootResolved = path329.resolve(root);
|
|
174784
|
+
const relative = path329.relative(rootResolved, absolute);
|
|
174785
|
+
if (relative === "" || relative === ".." || relative.startsWith(`..${path329.sep}`) || path329.isAbsolute(relative)) {
|
|
174335
174786
|
return {
|
|
174336
174787
|
ok: false,
|
|
174337
174788
|
refusal: { reason: BUNDLE_REFUSAL.pathEscape, path: relPath, message: `${relPath} resolves outside the scope root` }
|
|
@@ -174340,7 +174791,7 @@ async function resolveContainedPathForWrite(root, relPath) {
|
|
|
174340
174791
|
return { ok: true, absolutePath: absolute };
|
|
174341
174792
|
}
|
|
174342
174793
|
async function refuseSymlinkChain(root, relPath) {
|
|
174343
|
-
const rootResolved =
|
|
174794
|
+
const rootResolved = path329.resolve(root);
|
|
174344
174795
|
try {
|
|
174345
174796
|
const rootStat = await lstat18(rootResolved);
|
|
174346
174797
|
if (rootStat.isSymbolicLink()) {
|
|
@@ -174353,7 +174804,7 @@ async function refuseSymlinkChain(root, relPath) {
|
|
|
174353
174804
|
const segments = relPath.split("/");
|
|
174354
174805
|
let current = rootResolved;
|
|
174355
174806
|
for (const segment of segments) {
|
|
174356
|
-
current =
|
|
174807
|
+
current = path329.join(current, segment);
|
|
174357
174808
|
try {
|
|
174358
174809
|
const stat = await lstat18(current);
|
|
174359
174810
|
if (stat.isSymbolicLink()) {
|
|
@@ -174381,8 +174832,8 @@ async function readTargetFile(absolutePath) {
|
|
|
174381
174832
|
}
|
|
174382
174833
|
}
|
|
174383
174834
|
// src/bundle/archive.ts
|
|
174384
|
-
import { readdir as
|
|
174385
|
-
import
|
|
174835
|
+
import { readdir as readdir60, readFile as readFile167, lstat as lstat19 } from "fs/promises";
|
|
174836
|
+
import path330 from "path";
|
|
174386
174837
|
import { gzipSync, gunzipSync } from "zlib";
|
|
174387
174838
|
var BLOCK = 512;
|
|
174388
174839
|
var BUNDLE_MANIFEST_NAME = "bundle.json";
|
|
@@ -174473,11 +174924,11 @@ function buildBundleArchive(files, manifestBytes) {
|
|
|
174473
174924
|
const dirs = new Set;
|
|
174474
174925
|
const sortedPaths = [...files.keys()].sort();
|
|
174475
174926
|
for (const p of sortedPaths) {
|
|
174476
|
-
let dir =
|
|
174927
|
+
let dir = path330.dirname(p);
|
|
174477
174928
|
const segs = [];
|
|
174478
174929
|
while (dir !== "." && dir !== "/" && dir !== "") {
|
|
174479
174930
|
segs.unshift(dir);
|
|
174480
|
-
dir =
|
|
174931
|
+
dir = path330.dirname(dir);
|
|
174481
174932
|
}
|
|
174482
174933
|
for (const d of segs)
|
|
174483
174934
|
dirs.add(d);
|
|
@@ -174545,7 +174996,7 @@ function parseUstar(tar, limits) {
|
|
|
174545
174996
|
const name = prefix.length > 0 ? `${prefix}/${nameRaw}` : nameRaw;
|
|
174546
174997
|
const typeflag = String.fromCharCode(header[156] ?? 0);
|
|
174547
174998
|
const size = readOctal(header, 124, 12);
|
|
174548
|
-
if (
|
|
174999
|
+
if (path330.isAbsolute(name) || name.split("/").includes("..") || name.length === 0) {
|
|
174549
175000
|
return { ok: false, refusal: { reason: BUNDLE_REFUSAL.archiveInvalid, path: name, message: `unsafe entry name: ${name}` } };
|
|
174550
175001
|
}
|
|
174551
175002
|
const isDir = typeflag === "5";
|
|
@@ -174607,9 +175058,9 @@ async function openBundle(bundlePath, limits) {
|
|
|
174607
175058
|
let entryCount = 0;
|
|
174608
175059
|
let totalBytes = 0;
|
|
174609
175060
|
async function walk(dir, relPrefix) {
|
|
174610
|
-
const entries = await
|
|
175061
|
+
const entries = await readdir60(dir, { withFileTypes: true });
|
|
174611
175062
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
174612
|
-
const abs =
|
|
175063
|
+
const abs = path330.join(dir, entry.name);
|
|
174613
175064
|
const rel = relPrefix.length > 0 ? `${relPrefix}/${entry.name}` : entry.name;
|
|
174614
175065
|
const entryStat = await lstat19(abs);
|
|
174615
175066
|
if (entryStat.isSymbolicLink()) {
|
|
@@ -174996,9 +175447,9 @@ init_validator();
|
|
|
174996
175447
|
init_frontmatter();
|
|
174997
175448
|
init_types3();
|
|
174998
175449
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
174999
|
-
import { mkdir as mkdir71, readdir as
|
|
175000
|
-
import { existsSync as
|
|
175001
|
-
import
|
|
175450
|
+
import { mkdir as mkdir71, readdir as readdir61, readFile as readFile168, writeFile as writeFile50, lstat as lstat20 } from "fs/promises";
|
|
175451
|
+
import { existsSync as existsSync54 } from "fs";
|
|
175452
|
+
import path331 from "path";
|
|
175002
175453
|
// docs/requirements/keryx-agent-platform-expansion/schemas/hook-config.schema.json
|
|
175003
175454
|
var hook_config_schema_default2 = {
|
|
175004
175455
|
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
@@ -175542,12 +175993,12 @@ function contentDigestBundleId(scope, entries) {
|
|
|
175542
175993
|
async function walkFiles2(dir, relPrefix, out, skipped) {
|
|
175543
175994
|
let entries;
|
|
175544
175995
|
try {
|
|
175545
|
-
entries = await
|
|
175996
|
+
entries = await readdir61(dir, { withFileTypes: true });
|
|
175546
175997
|
} catch {
|
|
175547
175998
|
return;
|
|
175548
175999
|
}
|
|
175549
176000
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
175550
|
-
const abs =
|
|
176001
|
+
const abs = path331.join(dir, entry.name);
|
|
175551
176002
|
const rel = relPrefix.length > 0 ? `${relPrefix}/${entry.name}` : entry.name;
|
|
175552
176003
|
const st = await lstat20(abs);
|
|
175553
176004
|
if (st.isSymbolicLink()) {
|
|
@@ -175564,8 +176015,8 @@ async function walkFiles2(dir, relPrefix, out, skipped) {
|
|
|
175564
176015
|
async function collectSkills(root, scope, skipped) {
|
|
175565
176016
|
const candidates = [];
|
|
175566
176017
|
for (const baseDirName of scope === "project" ? ["skills", "project-skills"] : ["skills"]) {
|
|
175567
|
-
const base =
|
|
175568
|
-
if (!
|
|
176018
|
+
const base = path331.join(root, baseDirName);
|
|
176019
|
+
if (!existsSync54(base))
|
|
175569
176020
|
continue;
|
|
175570
176021
|
const files = [];
|
|
175571
176022
|
await walkFiles2(base, baseDirName, files, skipped);
|
|
@@ -175577,26 +176028,26 @@ async function collectSkills(root, scope, skipped) {
|
|
|
175577
176028
|
async function collectRules(root, scope, skipped) {
|
|
175578
176029
|
if (scope === "user")
|
|
175579
176030
|
return [];
|
|
175580
|
-
const base =
|
|
175581
|
-
if (!
|
|
176031
|
+
const base = path331.join(root, "rules");
|
|
176032
|
+
if (!existsSync54(base))
|
|
175582
176033
|
return [];
|
|
175583
176034
|
const files = [];
|
|
175584
176035
|
await walkFiles2(base, "rules", files, skipped);
|
|
175585
176036
|
return files.filter((f) => /\.(md|mdc)$/.test(f.path)).map((f) => ({ bundlePath: f.path, kind: "rule", absolutePath: f.abs }));
|
|
175586
176037
|
}
|
|
175587
176038
|
async function collectAgents(root, skipped) {
|
|
175588
|
-
const base =
|
|
175589
|
-
if (!
|
|
176039
|
+
const base = path331.join(root, "agents");
|
|
176040
|
+
if (!existsSync54(base))
|
|
175590
176041
|
return [];
|
|
175591
176042
|
let entries;
|
|
175592
176043
|
try {
|
|
175593
|
-
entries = await
|
|
176044
|
+
entries = await readdir61(base, { withFileTypes: true });
|
|
175594
176045
|
} catch {
|
|
175595
176046
|
return [];
|
|
175596
176047
|
}
|
|
175597
176048
|
const candidates = [];
|
|
175598
176049
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
175599
|
-
const abs =
|
|
176050
|
+
const abs = path331.join(base, entry.name);
|
|
175600
176051
|
const st = await lstat20(abs);
|
|
175601
176052
|
if (st.isSymbolicLink()) {
|
|
175602
176053
|
skipped.push({ path: `agents/${entry.name}`, reason: "symlink" });
|
|
@@ -175611,17 +176062,17 @@ async function collectAgents(root, skipped) {
|
|
|
175611
176062
|
async function collectMemory(root, skipped) {
|
|
175612
176063
|
const candidates = [];
|
|
175613
176064
|
for (const { folder } of MEMORY_TYPES) {
|
|
175614
|
-
const base =
|
|
175615
|
-
if (!
|
|
176065
|
+
const base = path331.join(root, "memory", folder);
|
|
176066
|
+
if (!existsSync54(base))
|
|
175616
176067
|
continue;
|
|
175617
176068
|
let entries;
|
|
175618
176069
|
try {
|
|
175619
|
-
entries = await
|
|
176070
|
+
entries = await readdir61(base, { withFileTypes: true });
|
|
175620
176071
|
} catch {
|
|
175621
176072
|
continue;
|
|
175622
176073
|
}
|
|
175623
176074
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
175624
|
-
const abs =
|
|
176075
|
+
const abs = path331.join(base, entry.name);
|
|
175625
176076
|
const st = await lstat20(abs);
|
|
175626
176077
|
if (st.isSymbolicLink()) {
|
|
175627
176078
|
skipped.push({ path: `memory/${folder}/${entry.name}`, reason: "symlink" });
|
|
@@ -175635,8 +176086,8 @@ async function collectMemory(root, skipped) {
|
|
|
175635
176086
|
return candidates;
|
|
175636
176087
|
}
|
|
175637
176088
|
async function collectHookConfig(root) {
|
|
175638
|
-
const abs =
|
|
175639
|
-
if (!
|
|
176089
|
+
const abs = path331.join(root, "hooks.json");
|
|
176090
|
+
if (!existsSync54(abs))
|
|
175640
176091
|
return [];
|
|
175641
176092
|
const st = await lstat20(abs);
|
|
175642
176093
|
if (st.isSymbolicLink() || !st.isFile())
|
|
@@ -175645,19 +176096,19 @@ async function collectHookConfig(root) {
|
|
|
175645
176096
|
}
|
|
175646
176097
|
async function collectLearnedPatterns(root, scope) {
|
|
175647
176098
|
const relDir = scope === "user" ? "learning/patterns" : "data/learning/candidates";
|
|
175648
|
-
const base =
|
|
175649
|
-
if (!
|
|
176099
|
+
const base = path331.join(root, ...relDir.split("/"));
|
|
176100
|
+
if (!existsSync54(base))
|
|
175650
176101
|
return [];
|
|
175651
176102
|
let entries;
|
|
175652
176103
|
try {
|
|
175653
|
-
entries = await
|
|
176104
|
+
entries = await readdir61(base, { withFileTypes: true });
|
|
175654
176105
|
} catch {
|
|
175655
176106
|
return [];
|
|
175656
176107
|
}
|
|
175657
176108
|
const candidates = [];
|
|
175658
176109
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
175659
176110
|
if (entry.isFile() && entry.name.endsWith(".json")) {
|
|
175660
|
-
candidates.push({ bundlePath: `${relDir}/${entry.name}`, kind: "learned-pattern", absolutePath:
|
|
176111
|
+
candidates.push({ bundlePath: `${relDir}/${entry.name}`, kind: "learned-pattern", absolutePath: path331.join(base, entry.name) });
|
|
175661
176112
|
}
|
|
175662
176113
|
}
|
|
175663
176114
|
return candidates;
|
|
@@ -175690,7 +176141,7 @@ function rewriteAgentOrigin(content, sourceRef) {
|
|
|
175690
176141
|
}
|
|
175691
176142
|
async function outDirIsEmpty(out) {
|
|
175692
176143
|
try {
|
|
175693
|
-
const entries = await
|
|
176144
|
+
const entries = await readdir61(out);
|
|
175694
176145
|
return entries.length === 0;
|
|
175695
176146
|
} catch {
|
|
175696
176147
|
return true;
|
|
@@ -175698,10 +176149,10 @@ async function outDirIsEmpty(out) {
|
|
|
175698
176149
|
}
|
|
175699
176150
|
async function writeDirectoryBundle(out, manifestBytes, files) {
|
|
175700
176151
|
await mkdir71(out, { recursive: true });
|
|
175701
|
-
await writeFile50(
|
|
176152
|
+
await writeFile50(path331.join(out, "bundle.json"), manifestBytes);
|
|
175702
176153
|
for (const [rel, bytes] of files) {
|
|
175703
|
-
const abs =
|
|
175704
|
-
await mkdir71(
|
|
176154
|
+
const abs = path331.join(out, ...rel.split("/"));
|
|
176155
|
+
await mkdir71(path331.dirname(abs), { recursive: true });
|
|
175705
176156
|
await writeFile50(abs, bytes);
|
|
175706
176157
|
}
|
|
175707
176158
|
}
|
|
@@ -175829,16 +176280,16 @@ async function exportBundle(opts) {
|
|
|
175829
176280
|
const manifestBytes = Buffer.from(serializeManifest(manifest), "utf8");
|
|
175830
176281
|
const isArchive = opts.out.endsWith(".tar.gz") || opts.out.endsWith(".tgz");
|
|
175831
176282
|
if (isArchive) {
|
|
175832
|
-
if (
|
|
176283
|
+
if (existsSync54(opts.out)) {
|
|
175833
176284
|
return { ok: false, refusals: [{ reason: BUNDLE_REFUSAL.notABundle, message: `${opts.out} already exists` }] };
|
|
175834
176285
|
}
|
|
175835
176286
|
const archive = buildBundleArchive(files, manifestBytes);
|
|
175836
176287
|
if (!archive.ok)
|
|
175837
176288
|
return { ok: false, refusals: [archive.refusal] };
|
|
175838
|
-
await mkdir71(
|
|
176289
|
+
await mkdir71(path331.dirname(opts.out), { recursive: true });
|
|
175839
176290
|
await writeFile50(opts.out, archive.value);
|
|
175840
176291
|
} else {
|
|
175841
|
-
if (
|
|
176292
|
+
if (existsSync54(opts.out) && !await outDirIsEmpty(opts.out)) {
|
|
175842
176293
|
return { ok: false, refusals: [{ reason: BUNDLE_REFUSAL.notABundle, message: `${opts.out} already exists and is not empty` }] };
|
|
175843
176294
|
}
|
|
175844
176295
|
await writeDirectoryBundle(opts.out, manifestBytes, files);
|
|
@@ -175885,16 +176336,16 @@ async function verifyBundlePath(bundlePath) {
|
|
|
175885
176336
|
// src/bundle/applied-state.ts
|
|
175886
176337
|
init_contained_write();
|
|
175887
176338
|
import { readFile as readFile169 } from "fs/promises";
|
|
175888
|
-
import
|
|
176339
|
+
import path332 from "path";
|
|
175889
176340
|
var APPLIED_STATE_SCHEMA_VERSION = 2;
|
|
175890
176341
|
function emptyState() {
|
|
175891
176342
|
return { schemaVersion: APPLIED_STATE_SCHEMA_VERSION, entries: {} };
|
|
175892
176343
|
}
|
|
175893
176344
|
function appliedStatePath(scope, ctx) {
|
|
175894
176345
|
if (scope === "user") {
|
|
175895
|
-
return
|
|
176346
|
+
return path332.join(scopeRoot("user", ctx), "bundles", "applied-state.json");
|
|
175896
176347
|
}
|
|
175897
|
-
return
|
|
176348
|
+
return path332.join(scopeRoot(scope, ctx), "data", "bundles", "applied-state.json");
|
|
175898
176349
|
}
|
|
175899
176350
|
function isPlainEntryShape(value) {
|
|
175900
176351
|
if (typeof value !== "object" || value === null)
|
|
@@ -175976,14 +176427,14 @@ async function readAppliedState(ledgerPath) {
|
|
|
175976
176427
|
return { ok: false, reason: "corrupt-ledger", message: `applied-state ledger at ${ledgerPath} has an unrecognized shape` };
|
|
175977
176428
|
}
|
|
175978
176429
|
function containedRootAndRel(ledgerPath) {
|
|
175979
|
-
const marker = `${
|
|
176430
|
+
const marker = `${path332.sep}.metaproject${path332.sep}`;
|
|
175980
176431
|
const idx = ledgerPath.indexOf(marker);
|
|
175981
176432
|
if (idx >= 0) {
|
|
175982
|
-
return { root: ledgerPath.slice(0, idx), rel: ledgerPath.slice(idx +
|
|
176433
|
+
return { root: ledgerPath.slice(0, idx), rel: ledgerPath.slice(idx + path332.sep.length).split(path332.sep).join("/") };
|
|
175983
176434
|
}
|
|
175984
|
-
const bundlesDir =
|
|
175985
|
-
const root =
|
|
175986
|
-
const rel =
|
|
176435
|
+
const bundlesDir = path332.dirname(ledgerPath);
|
|
176436
|
+
const root = path332.dirname(bundlesDir);
|
|
176437
|
+
const rel = path332.join(path332.basename(bundlesDir), path332.basename(ledgerPath)).split(path332.sep).join("/");
|
|
175987
176438
|
return { root, rel };
|
|
175988
176439
|
}
|
|
175989
176440
|
async function writeAppliedState(ledgerPath, state) {
|
|
@@ -176004,17 +176455,17 @@ init_service8();
|
|
|
176004
176455
|
init_fs();
|
|
176005
176456
|
init_symlink_safety();
|
|
176006
176457
|
import { lstat as lstat21, mkdir as mkdir72, open as open8, readFile as readFile170 } from "fs/promises";
|
|
176007
|
-
import
|
|
176458
|
+
import path333 from "path";
|
|
176008
176459
|
var PRIVATE_DIR_GITIGNORE = `# keryx:private-dir \u2014 managed by keryx; this directory stays out of version control
|
|
176009
176460
|
*
|
|
176010
176461
|
!.gitignore
|
|
176011
176462
|
`;
|
|
176012
176463
|
async function checkPrivateDirGitignore(dir, root) {
|
|
176013
176464
|
if (root !== undefined) {
|
|
176014
|
-
const rootResolved =
|
|
176015
|
-
const dirResolved =
|
|
176016
|
-
const relative =
|
|
176017
|
-
const relativePosix = relative.split(
|
|
176465
|
+
const rootResolved = path333.resolve(root);
|
|
176466
|
+
const dirResolved = path333.resolve(dir);
|
|
176467
|
+
const relative = path333.relative(rootResolved, dirResolved);
|
|
176468
|
+
const relativePosix = relative.split(path333.sep).join("/");
|
|
176018
176469
|
const refusal = await refuseEscapingSymlink(rootResolved, relativePosix);
|
|
176019
176470
|
if (refusal !== undefined) {
|
|
176020
176471
|
return {
|
|
@@ -176044,7 +176495,7 @@ async function checkPrivateDirGitignore(dir, root) {
|
|
|
176044
176495
|
message: `${dir} is a symlink; keryx will not manage a private directory reached through a symlink.`
|
|
176045
176496
|
};
|
|
176046
176497
|
}
|
|
176047
|
-
const gitignorePath =
|
|
176498
|
+
const gitignorePath = path333.join(dir, ".gitignore");
|
|
176048
176499
|
let stats;
|
|
176049
176500
|
try {
|
|
176050
176501
|
stats = await lstat21(gitignorePath);
|
|
@@ -176096,7 +176547,7 @@ async function ensurePrivateDirGitignore(dir, root) {
|
|
|
176096
176547
|
if (!check.ok || check.action === "present") {
|
|
176097
176548
|
return check;
|
|
176098
176549
|
}
|
|
176099
|
-
const gitignorePath =
|
|
176550
|
+
const gitignorePath = path333.join(dir, ".gitignore");
|
|
176100
176551
|
await mkdir72(dir, { recursive: true });
|
|
176101
176552
|
try {
|
|
176102
176553
|
const handle = await open8(gitignorePath, "wx");
|
|
@@ -176493,7 +176944,7 @@ async function planBundleImport(opts) {
|
|
|
176493
176944
|
init_service4();
|
|
176494
176945
|
import { mkdtemp as mkdtemp6, mkdir as mkdir73, rm as rm20, writeFile as writeFile51 } from "fs/promises";
|
|
176495
176946
|
import { tmpdir as tmpdir13 } from "os";
|
|
176496
|
-
import
|
|
176947
|
+
import path334 from "path";
|
|
176497
176948
|
function entriesToStage(plan) {
|
|
176498
176949
|
return plan.entries.filter((e) => e.bucket === "new" || e.bucket === "update" || e.bucket === "conflict" && e.forced);
|
|
176499
176950
|
}
|
|
@@ -176503,12 +176954,12 @@ async function auditBundlePlan(plan, opts = {}) {
|
|
|
176503
176954
|
return { ok: true, refusals: [], report: null };
|
|
176504
176955
|
}
|
|
176505
176956
|
const runAudit = opts.runAudit ?? runHarnessAudit;
|
|
176506
|
-
const stagingDir = await mkdtemp6(
|
|
176957
|
+
const stagingDir = await mkdtemp6(path334.join(tmpdir13(), "keryx-bundle-audit-"));
|
|
176507
176958
|
try {
|
|
176508
176959
|
try {
|
|
176509
176960
|
for (const entry of toStage) {
|
|
176510
|
-
const abs =
|
|
176511
|
-
await mkdir73(
|
|
176961
|
+
const abs = path334.join(stagingDir, ...entry.path.split("/"));
|
|
176962
|
+
await mkdir73(path334.dirname(abs), { recursive: true });
|
|
176512
176963
|
await writeFile51(abs, entry.bytes);
|
|
176513
176964
|
}
|
|
176514
176965
|
} catch (err) {
|
|
@@ -176539,7 +176990,7 @@ async function auditBundlePlan(plan, opts = {}) {
|
|
|
176539
176990
|
// src/bundle/apply.ts
|
|
176540
176991
|
init_contained_write();
|
|
176541
176992
|
import { mkdir as mkdir74, rmdir as rmdir2, stat as stat33 } from "fs/promises";
|
|
176542
|
-
import
|
|
176993
|
+
import path335 from "path";
|
|
176543
176994
|
init_keryx_home();
|
|
176544
176995
|
init_checksum();
|
|
176545
176996
|
class ApplyAbort extends Error {
|
|
@@ -176619,7 +177070,7 @@ async function applyBundlePlan(plan, auditResult, opts = {}) {
|
|
|
176619
177070
|
throw new ApplyAbort({ ...previousFile.refusal, path: entry.path });
|
|
176620
177071
|
}
|
|
176621
177072
|
const previousBytes = previousFile.bytes ?? null;
|
|
176622
|
-
const createdDirs = await mkdirRecordingCreated(
|
|
177073
|
+
const createdDirs = await mkdirRecordingCreated(path335.dirname(entry.targetPath));
|
|
176623
177074
|
for (const dir of [...createdDirs].reverse())
|
|
176624
177075
|
rollback.push({ kind: "dir", absolutePath: dir });
|
|
176625
177076
|
rollback.push({ kind: "file", root, rel: entry.targetRelative, previousBytes });
|
|
@@ -176702,14 +177153,14 @@ async function applyBundlePlan(plan, auditResult, opts = {}) {
|
|
|
176702
177153
|
}
|
|
176703
177154
|
async function mkdirRecordingCreated(dir) {
|
|
176704
177155
|
const missing = [];
|
|
176705
|
-
let current =
|
|
177156
|
+
let current = path335.resolve(dir);
|
|
176706
177157
|
for (;; ) {
|
|
176707
177158
|
try {
|
|
176708
177159
|
await stat33(current);
|
|
176709
177160
|
break;
|
|
176710
177161
|
} catch {
|
|
176711
177162
|
missing.push(current);
|
|
176712
|
-
const parent =
|
|
177163
|
+
const parent = path335.dirname(current);
|
|
176713
177164
|
if (parent === current)
|
|
176714
177165
|
break;
|
|
176715
177166
|
current = parent;
|
|
@@ -176724,9 +177175,9 @@ function resolveLedgerPathForEntry(entry, opts) {
|
|
|
176724
177175
|
if (entry.targetScope === "user") {
|
|
176725
177176
|
return userStorePaths(opts.env ?? process.env, opts.homeDir).appliedState;
|
|
176726
177177
|
}
|
|
176727
|
-
const metaprojectIdx = entry.targetPath.indexOf(`${
|
|
176728
|
-
const metaprojectRoot = metaprojectIdx === -1 ?
|
|
176729
|
-
return
|
|
177178
|
+
const metaprojectIdx = entry.targetPath.indexOf(`${path335.sep}.metaproject${path335.sep}`);
|
|
177179
|
+
const metaprojectRoot = metaprojectIdx === -1 ? path335.join(path335.dirname(entry.targetPath), ".metaproject") : entry.targetPath.slice(0, metaprojectIdx + `${path335.sep}.metaproject`.length);
|
|
177180
|
+
return path335.join(metaprojectRoot, "data", "bundles", "applied-state.json");
|
|
176730
177181
|
}
|
|
176731
177182
|
// src/bundle/inspect.ts
|
|
176732
177183
|
init_matrix();
|
|
@@ -176778,28 +177229,28 @@ function defaultCapabilityLookup() {
|
|
|
176778
177229
|
}
|
|
176779
177230
|
// src/bundle/uninstall.ts
|
|
176780
177231
|
init_contained_write();
|
|
176781
|
-
import
|
|
177232
|
+
import path336 from "path";
|
|
176782
177233
|
init_checksum();
|
|
176783
177234
|
var PROTECTED_KIND_ROOTS = new Set(["skills", "project-skills", "rules", "agents", "memory", "learning", "data/learning"]);
|
|
176784
177235
|
function isContained(root, candidate) {
|
|
176785
|
-
const rel =
|
|
176786
|
-
return rel === "" || !rel.startsWith(`..${
|
|
177236
|
+
const rel = path336.relative(root, candidate);
|
|
177237
|
+
return rel === "" || !rel.startsWith(`..${path336.sep}`) && rel !== ".." && !path336.isAbsolute(rel);
|
|
176787
177238
|
}
|
|
176788
177239
|
async function removeNowEmptyParents(root, relFilePath) {
|
|
176789
|
-
let relDir =
|
|
177240
|
+
let relDir = path336.posix.dirname(relFilePath);
|
|
176790
177241
|
while (relDir !== "." && relDir !== "/" && relDir !== "") {
|
|
176791
177242
|
if (PROTECTED_KIND_ROOTS.has(relDir))
|
|
176792
177243
|
break;
|
|
176793
177244
|
const removed = await rmdirIfEmptyContained(root, relDir).catch(() => false);
|
|
176794
177245
|
if (!removed)
|
|
176795
177246
|
break;
|
|
176796
|
-
relDir =
|
|
177247
|
+
relDir = path336.posix.dirname(relDir);
|
|
176797
177248
|
}
|
|
176798
177249
|
}
|
|
176799
177250
|
async function uninstallBundle(opts) {
|
|
176800
177251
|
const ctx = { projectRoot: opts.projectRoot, env: opts.env, homeDir: opts.homeDir };
|
|
176801
177252
|
const root = scopeRoot(opts.targetScope, ctx);
|
|
176802
|
-
const rootResolved =
|
|
177253
|
+
const rootResolved = path336.resolve(root);
|
|
176803
177254
|
const ledgerPath = appliedStatePath(opts.targetScope, ctx);
|
|
176804
177255
|
const ledgerRead = await readAppliedState(ledgerPath);
|
|
176805
177256
|
if (!ledgerRead.ok) {
|
|
@@ -176839,7 +177290,7 @@ async function uninstallBundle(opts) {
|
|
|
176839
177290
|
if (!kindCheck.ok) {
|
|
176840
177291
|
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: [] };
|
|
176841
177292
|
}
|
|
176842
|
-
const absolute =
|
|
177293
|
+
const absolute = path336.resolve(rootResolved, normalized.path);
|
|
176843
177294
|
if (!isContained(rootResolved, absolute)) {
|
|
176844
177295
|
return { ok: false, refusals: [{ reason: BUNDLE_REFUSAL.corruptLedger, path: relPath, message: `applied-state ledger record "${relPath}" resolves outside the scope root` }], removed: [], kept: [], missing: [] };
|
|
176845
177296
|
}
|
|
@@ -177031,7 +177482,7 @@ async function handleExport(args, cwd) {
|
|
|
177031
177482
|
const outcome = await exportBundle({
|
|
177032
177483
|
projectRoot,
|
|
177033
177484
|
scope: scopeArg,
|
|
177034
|
-
out:
|
|
177485
|
+
out: path337.resolve(cwd, out),
|
|
177035
177486
|
include: include.length > 0 ? include : undefined,
|
|
177036
177487
|
kinds: kindsRaw.length > 0 ? kindsRaw : undefined,
|
|
177037
177488
|
bundleId,
|
|
@@ -177078,7 +177529,7 @@ async function handleImport(args, cwd) {
|
|
|
177078
177529
|
}
|
|
177079
177530
|
const projectRoot = resolveBundleProjectRoot(cwd);
|
|
177080
177531
|
if (external) {
|
|
177081
|
-
await handleImportExternal(
|
|
177532
|
+
await handleImportExternal(path337.resolve(cwd, target), projectRoot, { dryRun, json });
|
|
177082
177533
|
return;
|
|
177083
177534
|
}
|
|
177084
177535
|
const targetScopeArg = optionValue([...args], "--target-scope");
|
|
@@ -177105,7 +177556,7 @@ async function handleImport(args, cwd) {
|
|
|
177105
177556
|
return;
|
|
177106
177557
|
}
|
|
177107
177558
|
}
|
|
177108
|
-
const opened = await openBundle(
|
|
177559
|
+
const opened = await openBundle(path337.resolve(cwd, target));
|
|
177109
177560
|
if (!opened.ok) {
|
|
177110
177561
|
printRefusals([opened.refusal], json);
|
|
177111
177562
|
process.exitCode = 1;
|
|
@@ -177283,7 +177734,7 @@ async function handleInspect(args, cwd) {
|
|
|
177283
177734
|
return;
|
|
177284
177735
|
}
|
|
177285
177736
|
const projectRoot = resolveBundleProjectRoot(cwd);
|
|
177286
|
-
const result = await inspectBundle(
|
|
177737
|
+
const result = await inspectBundle(path337.resolve(cwd, bundlePath), {
|
|
177287
177738
|
projectRoot,
|
|
177288
177739
|
targetScope: targetScopeArg
|
|
177289
177740
|
});
|
|
@@ -177327,7 +177778,7 @@ async function handleVerify(args, cwd) {
|
|
|
177327
177778
|
failUsage("keryx bundle verify requires a <bundle> argument (or --external-imports)");
|
|
177328
177779
|
return;
|
|
177329
177780
|
}
|
|
177330
|
-
const outcome = await verifyBundlePath(
|
|
177781
|
+
const outcome = await verifyBundlePath(path337.resolve(cwd, bundlePath));
|
|
177331
177782
|
if (!outcome.ok) {
|
|
177332
177783
|
printRefusals(outcome.refusals, json);
|
|
177333
177784
|
process.exitCode = 1;
|
|
@@ -177455,10 +177906,10 @@ function printUninstallHelp2() {
|
|
|
177455
177906
|
}
|
|
177456
177907
|
|
|
177457
177908
|
// src/commands/learn.ts
|
|
177458
|
-
import { existsSync as
|
|
177909
|
+
import { existsSync as existsSync55 } from "fs";
|
|
177459
177910
|
import { readFile as readFile171 } from "fs/promises";
|
|
177460
177911
|
import { createInterface as createInterface4 } from "readline/promises";
|
|
177461
|
-
import
|
|
177912
|
+
import path338 from "path";
|
|
177462
177913
|
init_contained_path();
|
|
177463
177914
|
init_service9();
|
|
177464
177915
|
var STDIN_DEADLINE_MS2 = 2000;
|
|
@@ -177481,16 +177932,16 @@ function resolveRoot2(deps) {
|
|
|
177481
177932
|
return resolveProjectRoot(deps.cwd ?? process.cwd());
|
|
177482
177933
|
}
|
|
177483
177934
|
function resolveLearnRoot(startDir, env) {
|
|
177484
|
-
const hasMetaproject = (dir) =>
|
|
177935
|
+
const hasMetaproject = (dir) => existsSync55(path338.join(dir, ".metaproject"));
|
|
177485
177936
|
const fromEnv = env.CLAUDE_PROJECT_DIR;
|
|
177486
177937
|
if (typeof fromEnv === "string" && fromEnv.length > 0 && hasMetaproject(fromEnv)) {
|
|
177487
177938
|
return fromEnv;
|
|
177488
177939
|
}
|
|
177489
|
-
let current =
|
|
177940
|
+
let current = path338.resolve(startDir);
|
|
177490
177941
|
for (;; ) {
|
|
177491
177942
|
if (hasMetaproject(current))
|
|
177492
177943
|
return current;
|
|
177493
|
-
const parent =
|
|
177944
|
+
const parent = path338.dirname(current);
|
|
177494
177945
|
if (parent === current)
|
|
177495
177946
|
return;
|
|
177496
177947
|
current = parent;
|
|
@@ -178155,6 +178606,190 @@ async function helpCommand(rest) {
|
|
|
178155
178606
|
process.exitCode = 1;
|
|
178156
178607
|
}
|
|
178157
178608
|
|
|
178609
|
+
// src/lib/group-subcommands.ts
|
|
178610
|
+
var GROUP_SUBCOMMANDS = new Map([
|
|
178611
|
+
["modules", ["status", "list", "enable", "on", "disable", "off", "interactive", "help"]],
|
|
178612
|
+
["projects", ["list", "register", "forget", "help"]],
|
|
178613
|
+
["providers", ["list", "status", "cross-family", "test", "remove"]],
|
|
178614
|
+
["routing", ["list", "set", "unset", "trust", "profile", "stats"]],
|
|
178615
|
+
["external", ["on", "off", "status", "list"]],
|
|
178616
|
+
["auth", ["list", "login", "logout", "status"]],
|
|
178617
|
+
["version", ["check"]],
|
|
178618
|
+
["gdgraph", ["build", "query", "find", "symbol", "symbols", "path", "affected", "repomap", "context", "assets"]],
|
|
178619
|
+
["ctx", ["status", "diff", "rg", "read", "run", "show", "hook", "install-hook", "uninstall-hook"]],
|
|
178620
|
+
[
|
|
178621
|
+
"wiki",
|
|
178622
|
+
[
|
|
178623
|
+
"status",
|
|
178624
|
+
"new",
|
|
178625
|
+
"index",
|
|
178626
|
+
"collect",
|
|
178627
|
+
"check-links",
|
|
178628
|
+
"validate",
|
|
178629
|
+
"freshness",
|
|
178630
|
+
"refresh",
|
|
178631
|
+
"verify",
|
|
178632
|
+
"migrate-markers",
|
|
178633
|
+
"ask",
|
|
178634
|
+
"sections",
|
|
178635
|
+
"enrich",
|
|
178636
|
+
"context",
|
|
178637
|
+
"backlinks"
|
|
178638
|
+
]
|
|
178639
|
+
],
|
|
178640
|
+
["stack", ["detect"]],
|
|
178641
|
+
["health", ["run", "status", "gate", "sources", "explain", "baseline", "trend"]],
|
|
178642
|
+
["metrics", ["status", "validate", "collect", "latest", "show", "compare", "rebuild", "plan", "benchmark"]],
|
|
178643
|
+
["test", ["init", "analyze", "run", "status", "context", "report", "related", "explain", "coverage-map", "suggest"]],
|
|
178644
|
+
["memory", ["new", "index", "search", "supersede", "transition", "assets", "ingest", "check", "reflect", "handoff"]],
|
|
178645
|
+
[
|
|
178646
|
+
"flow",
|
|
178647
|
+
[
|
|
178648
|
+
"init",
|
|
178649
|
+
"list",
|
|
178650
|
+
"status",
|
|
178651
|
+
"freeze",
|
|
178652
|
+
"start",
|
|
178653
|
+
"next",
|
|
178654
|
+
"task",
|
|
178655
|
+
"ac",
|
|
178656
|
+
"check-ac",
|
|
178657
|
+
"owner",
|
|
178658
|
+
"implemented",
|
|
178659
|
+
"complete",
|
|
178660
|
+
"confirm",
|
|
178661
|
+
"recover",
|
|
178662
|
+
"block",
|
|
178663
|
+
"unblock",
|
|
178664
|
+
"check",
|
|
178665
|
+
"renumber",
|
|
178666
|
+
"repair-reviews",
|
|
178667
|
+
"plan",
|
|
178668
|
+
"schema"
|
|
178669
|
+
]
|
|
178670
|
+
],
|
|
178671
|
+
["job", ["init", "status", "step", "document", "complete", "list"]],
|
|
178672
|
+
[
|
|
178673
|
+
"review",
|
|
178674
|
+
[
|
|
178675
|
+
"attach",
|
|
178676
|
+
"start",
|
|
178677
|
+
"ingest",
|
|
178678
|
+
"scope",
|
|
178679
|
+
"floor",
|
|
178680
|
+
"blast-radius",
|
|
178681
|
+
"budget",
|
|
178682
|
+
"tier",
|
|
178683
|
+
"comments",
|
|
178684
|
+
"ci-triage",
|
|
178685
|
+
"conform",
|
|
178686
|
+
"jev-rules",
|
|
178687
|
+
"jev-edit-guard",
|
|
178688
|
+
"jev-risk",
|
|
178689
|
+
"jev-scenarios",
|
|
178690
|
+
"jev-docs",
|
|
178691
|
+
"jev-comments",
|
|
178692
|
+
"jev-contract",
|
|
178693
|
+
"jev-triage",
|
|
178694
|
+
"jev-select",
|
|
178695
|
+
"jev-profile",
|
|
178696
|
+
"learn",
|
|
178697
|
+
"loop",
|
|
178698
|
+
"stack",
|
|
178699
|
+
"reviewers",
|
|
178700
|
+
"import",
|
|
178701
|
+
"status",
|
|
178702
|
+
"complete",
|
|
178703
|
+
"lightweight"
|
|
178704
|
+
]
|
|
178705
|
+
],
|
|
178706
|
+
["rules", ["distill", "sync"]],
|
|
178707
|
+
["standard", ["validate", "doctor", "capabilities", "baseline", "emit"]],
|
|
178708
|
+
[
|
|
178709
|
+
"security",
|
|
178710
|
+
[
|
|
178711
|
+
"status",
|
|
178712
|
+
"scan",
|
|
178713
|
+
"scan-mcp",
|
|
178714
|
+
"audit-harness",
|
|
178715
|
+
"impact-evidence",
|
|
178716
|
+
"check-input",
|
|
178717
|
+
"check-output",
|
|
178718
|
+
"redact",
|
|
178719
|
+
"report",
|
|
178720
|
+
"policy",
|
|
178721
|
+
"incidents",
|
|
178722
|
+
"hooks",
|
|
178723
|
+
"eval"
|
|
178724
|
+
]
|
|
178725
|
+
],
|
|
178726
|
+
["sandbox", ["status"]],
|
|
178727
|
+
["integrations", ["install", "uninstall", "doctor", "matrix"]],
|
|
178728
|
+
[
|
|
178729
|
+
"workspace",
|
|
178730
|
+
[
|
|
178731
|
+
"create",
|
|
178732
|
+
"list",
|
|
178733
|
+
"show",
|
|
178734
|
+
"add-resource",
|
|
178735
|
+
"archive",
|
|
178736
|
+
"remove-resource",
|
|
178737
|
+
"rename",
|
|
178738
|
+
"overview",
|
|
178739
|
+
"read",
|
|
178740
|
+
"propose",
|
|
178741
|
+
"confirm-review",
|
|
178742
|
+
"review",
|
|
178743
|
+
"dismiss-candidate",
|
|
178744
|
+
"handoff",
|
|
178745
|
+
"collaboration",
|
|
178746
|
+
"policy-readiness",
|
|
178747
|
+
"catch-up",
|
|
178748
|
+
"list-proposals",
|
|
178749
|
+
"help"
|
|
178750
|
+
]
|
|
178751
|
+
],
|
|
178752
|
+
["retention", ["status", "sweep"]],
|
|
178753
|
+
["forgetting", ["trail", "lookup"]],
|
|
178754
|
+
["trigger", ["run", "install", "uninstall", "list", "status", "schedule", "resolve"]],
|
|
178755
|
+
["schedule", ["add", "list", "show", "pause", "resume", "run", "remove"]],
|
|
178756
|
+
["governance", ["report", "show"]],
|
|
178757
|
+
["hooks", ["list", "validate", "test", "enable", "disable", "trust", "untrust"]],
|
|
178758
|
+
["bundle", ["export", "import", "inspect", "verify", "uninstall"]],
|
|
178759
|
+
["learn", ["observe", "extract", "list", "review", "accept", "reject", "apply", "promote", "graduate", "prune"]],
|
|
178760
|
+
["sessions", ["list", "fork", "export", "path", "help"]],
|
|
178761
|
+
["session", ["list", "fork", "export", "path", "help"]],
|
|
178762
|
+
["serve", ["status", "token", "config"]],
|
|
178763
|
+
["bus", ["list", "log", "send", "pause", "resume", "prune", "help"]],
|
|
178764
|
+
["dashboard", ["build", "open"]],
|
|
178765
|
+
[
|
|
178766
|
+
"skills",
|
|
178767
|
+
[
|
|
178768
|
+
"catalog",
|
|
178769
|
+
"install",
|
|
178770
|
+
"doctor",
|
|
178771
|
+
"uninstall",
|
|
178772
|
+
"status",
|
|
178773
|
+
"list",
|
|
178774
|
+
"inspect",
|
|
178775
|
+
"route",
|
|
178776
|
+
"create",
|
|
178777
|
+
"generate",
|
|
178778
|
+
"import",
|
|
178779
|
+
"update",
|
|
178780
|
+
"verify",
|
|
178781
|
+
"learn",
|
|
178782
|
+
"export",
|
|
178783
|
+
"sync",
|
|
178784
|
+
"contracts",
|
|
178785
|
+
"scout",
|
|
178786
|
+
"eval",
|
|
178787
|
+
"judge-check",
|
|
178788
|
+
"stocktake"
|
|
178789
|
+
]
|
|
178790
|
+
]
|
|
178791
|
+
]);
|
|
178792
|
+
|
|
178158
178793
|
// src/cli.ts
|
|
178159
178794
|
init_package();
|
|
178160
178795
|
if (import.meta.main) {
|
|
@@ -178164,6 +178799,7 @@ var VERSION2 = package_default.version;
|
|
|
178164
178799
|
var CLI_ROUTES = {
|
|
178165
178800
|
init: initCommand,
|
|
178166
178801
|
help: helpCommand,
|
|
178802
|
+
doctor: doctorCommand2,
|
|
178167
178803
|
status: statusCommand,
|
|
178168
178804
|
modules: modulesCommand,
|
|
178169
178805
|
projects: projectsCommand,
|
|
@@ -178218,6 +178854,15 @@ var CLI_ROUTES = {
|
|
|
178218
178854
|
learn: learnCommand,
|
|
178219
178855
|
"__sandbox-net-forward": sandboxNetForwardCommand
|
|
178220
178856
|
};
|
|
178857
|
+
var MCP_KNOWN_SUBCOMMANDS = [...MCP_CONSUMER_SUBCOMMANDS, "install", "uninstall", "serve"];
|
|
178858
|
+
function knownSubcommandsFor(command) {
|
|
178859
|
+
if (command === "mcp")
|
|
178860
|
+
return MCP_KNOWN_SUBCOMMANDS;
|
|
178861
|
+
return GROUP_SUBCOMMANDS.get(command);
|
|
178862
|
+
}
|
|
178863
|
+
function groupsWithKnownSubcommands() {
|
|
178864
|
+
return ["mcp", ...GROUP_SUBCOMMANDS.keys()];
|
|
178865
|
+
}
|
|
178221
178866
|
async function main() {
|
|
178222
178867
|
setModelTurnPort(async (request) => runModelTurn(request));
|
|
178223
178868
|
const args = process.argv.slice(2);
|
|
@@ -178236,16 +178881,23 @@ async function main() {
|
|
|
178236
178881
|
await printCommandHelp(command);
|
|
178237
178882
|
return;
|
|
178238
178883
|
}
|
|
178884
|
+
const known = knownSubcommandsFor(command);
|
|
178885
|
+
const sub = args[1];
|
|
178886
|
+
if (known !== undefined && sub !== undefined && !sub.startsWith("-") && !known.includes(sub)) {
|
|
178887
|
+
console.error(formatUnknownCommandMessage(sub, known, `keryx ${command} --help`));
|
|
178888
|
+
process.exitCode = 1;
|
|
178889
|
+
return;
|
|
178890
|
+
}
|
|
178239
178891
|
await route(args.slice(1));
|
|
178240
178892
|
return;
|
|
178241
178893
|
}
|
|
178242
|
-
console.error(
|
|
178243
|
-
printHelp30();
|
|
178894
|
+
console.error(formatUnknownCommandMessage(command, Object.keys(CLI_ROUTES).filter((name) => name !== "__sandbox-net-forward")));
|
|
178244
178895
|
process.exitCode = 1;
|
|
178245
178896
|
}
|
|
178246
178897
|
var USAGE_BODY = `Usage:
|
|
178247
178898
|
keryx Show CLI usage
|
|
178248
178899
|
keryx help [group|command] Grouped command help by task (--help/-h keep this flat usage)
|
|
178900
|
+
keryx doctor [--json] One page: version, Bun floor, ripgrep, sandbox, providers, MCP, integrations, standard, worktrees, graph/wiki freshness
|
|
178249
178901
|
keryx shell [-c|--continue] [-r|--resume [id]] [--provider <p>] [--model <m>] [--base-url <url>] [--agent|--chat] [--tui|--no-tui]
|
|
178250
178902
|
Start TUI agent shell (sessions are per-project)
|
|
178251
178903
|
keryx sessions list|fork <id>|export <id>|path
|
|
@@ -178425,6 +179077,7 @@ var USAGE_BODY = `Usage:
|
|
|
178425
179077
|
|
|
178426
179078
|
Commands:
|
|
178427
179079
|
help Grouped command help by task: every verb, in nine onboarding-ordered groups
|
|
179080
|
+
doctor One-page health check with a fix hint per line; --json for {checks:[...]}
|
|
178428
179081
|
shell Start the interactive TUI agent harness. Use --no-tui or --chat to opt out.
|
|
178429
179082
|
Sessions: -c continue last in this project, -r [id] resume (per-project).
|
|
178430
179083
|
sessions List or export per-project shell sessions
|
|
@@ -178573,7 +179226,9 @@ export {
|
|
|
178573
179226
|
USAGE_BODY,
|
|
178574
179227
|
exitCodeForError,
|
|
178575
179228
|
groupUsage,
|
|
179229
|
+
groupsWithKnownSubcommands,
|
|
178576
179230
|
helpRequestedFor,
|
|
179231
|
+
knownSubcommandsFor,
|
|
178577
179232
|
main,
|
|
178578
179233
|
printCommandHelp,
|
|
178579
179234
|
shouldInterceptHelp
|