@mrciphersmith/keryx 0.3.16 → 0.3.18
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 +1403 -689
- 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.18",
|
|
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: {
|
|
@@ -28951,7 +28955,7 @@ function retryableFor2(kind, fallback) {
|
|
|
28951
28955
|
const concrete = defaultRetryable(kind);
|
|
28952
28956
|
return concrete === undefined ? fallback : concrete;
|
|
28953
28957
|
}
|
|
28954
|
-
function mergeUsage2(promptTokens, completionTokens, totalTokens) {
|
|
28958
|
+
function mergeUsage2(promptTokens, completionTokens, totalTokens, cacheReadTokens) {
|
|
28955
28959
|
const usage = { exact: true };
|
|
28956
28960
|
if (promptTokens !== undefined) {
|
|
28957
28961
|
usage.inputTokens = promptTokens;
|
|
@@ -28964,6 +28968,9 @@ function mergeUsage2(promptTokens, completionTokens, totalTokens) {
|
|
|
28964
28968
|
} else if (promptTokens !== undefined || completionTokens !== undefined) {
|
|
28965
28969
|
usage.totalTokens = (promptTokens ?? 0) + (completionTokens ?? 0);
|
|
28966
28970
|
}
|
|
28971
|
+
if (cacheReadTokens !== undefined) {
|
|
28972
|
+
usage.cacheReadTokens = cacheReadTokens;
|
|
28973
|
+
}
|
|
28967
28974
|
return usage;
|
|
28968
28975
|
}
|
|
28969
28976
|
function classifyHttpError2(status, headers, code) {
|
|
@@ -29390,6 +29397,14 @@ ${message.content}` });
|
|
|
29390
29397
|
}
|
|
29391
29398
|
return "idx:0";
|
|
29392
29399
|
};
|
|
29400
|
+
const pendingToolCallStillAccumulating = () => {
|
|
29401
|
+
for (const acc of pendingTools.values()) {
|
|
29402
|
+
if (!acc.ended) {
|
|
29403
|
+
return acc.id;
|
|
29404
|
+
}
|
|
29405
|
+
}
|
|
29406
|
+
return;
|
|
29407
|
+
};
|
|
29393
29408
|
const flushPendingToolEnds = () => {
|
|
29394
29409
|
for (const acc of pendingTools.values()) {
|
|
29395
29410
|
if (acc.ended) {
|
|
@@ -29483,7 +29498,7 @@ ${message.content}` });
|
|
|
29483
29498
|
const usage = asRecord4(data.usage);
|
|
29484
29499
|
bodies.push({
|
|
29485
29500
|
kind: "usage_update",
|
|
29486
|
-
usage: mergeUsage2(asNumber3(usage.prompt_tokens), asNumber3(usage.completion_tokens), asNumber3(usage.total_tokens))
|
|
29501
|
+
usage: mergeUsage2(asNumber3(usage.prompt_tokens), asNumber3(usage.completion_tokens), asNumber3(usage.total_tokens), asNumber3(asRecord4(usage.prompt_tokens_details).cached_tokens))
|
|
29487
29502
|
});
|
|
29488
29503
|
}
|
|
29489
29504
|
const choice0 = asRecord4(asArray(data.choices)[0]);
|
|
@@ -29596,6 +29611,7 @@ ${message.content}` });
|
|
|
29596
29611
|
parser.push(trailing);
|
|
29597
29612
|
}
|
|
29598
29613
|
const torn = parser.flush();
|
|
29614
|
+
const pendingToolCallId = pendingToolCallStillAccumulating();
|
|
29599
29615
|
if (torn.length > 0) {
|
|
29600
29616
|
malformed = {
|
|
29601
29617
|
kind: "malformed",
|
|
@@ -29608,8 +29624,14 @@ ${message.content}` });
|
|
|
29608
29624
|
retryable: retryableFor2("malformed", false),
|
|
29609
29625
|
message: "empty response body"
|
|
29610
29626
|
};
|
|
29627
|
+
} else if (pendingToolCallId !== undefined) {
|
|
29628
|
+
malformed = {
|
|
29629
|
+
kind: "malformed",
|
|
29630
|
+
retryable: retryableFor2("malformed", false),
|
|
29631
|
+
message: `${this.label} SSE stream ended while a tool call was still accumulating`,
|
|
29632
|
+
detail: { pendingToolCallId }
|
|
29633
|
+
};
|
|
29611
29634
|
} else {
|
|
29612
|
-
flushPendingToolEnds();
|
|
29613
29635
|
if (sawStart && sawFinish) {
|
|
29614
29636
|
flushThinkTagParser();
|
|
29615
29637
|
flushFieldTagStripper();
|
|
@@ -30268,6 +30290,16 @@ class GeminiProvider {
|
|
|
30268
30290
|
break;
|
|
30269
30291
|
}
|
|
30270
30292
|
const chunk = asRecord5(parsed);
|
|
30293
|
+
const errorEnvelope = asRecord5(chunk.error);
|
|
30294
|
+
if (Object.keys(errorEnvelope).length > 0) {
|
|
30295
|
+
const classified = classifyGeminiError(asNumber4(errorEnvelope.code) ?? 0, asString4(errorEnvelope.status));
|
|
30296
|
+
const envelopeMessage = asString4(errorEnvelope.message);
|
|
30297
|
+
malformed = {
|
|
30298
|
+
...classified,
|
|
30299
|
+
message: redact(envelopeMessage !== undefined && envelopeMessage.length > 0 ? envelopeMessage : "Gemini stream carried an in-band error envelope")
|
|
30300
|
+
};
|
|
30301
|
+
break;
|
|
30302
|
+
}
|
|
30271
30303
|
if (!sawFirstChunk) {
|
|
30272
30304
|
sawFirstChunk = true;
|
|
30273
30305
|
bodies.push({ kind: "model_start" });
|
|
@@ -30291,7 +30323,7 @@ class GeminiProvider {
|
|
|
30291
30323
|
bodies.push({ kind: "text_delta", text });
|
|
30292
30324
|
}
|
|
30293
30325
|
} else if (callName !== undefined) {
|
|
30294
|
-
const callId = asString4(functionCall.id) ?? callName
|
|
30326
|
+
const callId = asString4(functionCall.id) ?? `${callName}#${functionCallIndexInRound}`;
|
|
30295
30327
|
const argsInput = JSON.stringify(asRecord5(functionCall.args));
|
|
30296
30328
|
bodies.push({ kind: "tool_call_start", toolCallId: callId, toolName: callName });
|
|
30297
30329
|
bodies.push({ kind: "tool_call_end", toolCallId: callId, input: argsInput });
|
|
@@ -30508,7 +30540,7 @@ function retryableFor4(kind, fallback) {
|
|
|
30508
30540
|
const concrete = defaultRetryable(kind);
|
|
30509
30541
|
return concrete === undefined ? fallback : concrete;
|
|
30510
30542
|
}
|
|
30511
|
-
function mergeUsage4(inputTokens, outputTokens, totalTokens) {
|
|
30543
|
+
function mergeUsage4(inputTokens, outputTokens, totalTokens, cacheReadTokens) {
|
|
30512
30544
|
const usage = { exact: true };
|
|
30513
30545
|
if (inputTokens !== undefined) {
|
|
30514
30546
|
usage.inputTokens = inputTokens;
|
|
@@ -30521,6 +30553,9 @@ function mergeUsage4(inputTokens, outputTokens, totalTokens) {
|
|
|
30521
30553
|
} else if (inputTokens !== undefined || outputTokens !== undefined) {
|
|
30522
30554
|
usage.totalTokens = (inputTokens ?? 0) + (outputTokens ?? 0);
|
|
30523
30555
|
}
|
|
30556
|
+
if (cacheReadTokens !== undefined) {
|
|
30557
|
+
usage.cacheReadTokens = cacheReadTokens;
|
|
30558
|
+
}
|
|
30524
30559
|
return usage;
|
|
30525
30560
|
}
|
|
30526
30561
|
function extractErrorFields(data) {
|
|
@@ -30938,9 +30973,10 @@ class OpenAiProvider {
|
|
|
30938
30973
|
const outputTokens = asNumber5(usage.output_tokens);
|
|
30939
30974
|
const totalTokens = asNumber5(usage.total_tokens);
|
|
30940
30975
|
const reasoningTokens = asNumber5(asRecord6(usage.output_tokens_details).reasoning_tokens);
|
|
30976
|
+
const cacheReadTokens = asNumber5(asRecord6(usage.input_tokens_details).cached_tokens);
|
|
30941
30977
|
const usageBody = {
|
|
30942
30978
|
kind: "usage_update",
|
|
30943
|
-
usage: mergeUsage4(inputTokens, outputTokens, totalTokens)
|
|
30979
|
+
usage: mergeUsage4(inputTokens, outputTokens, totalTokens, cacheReadTokens)
|
|
30944
30980
|
};
|
|
30945
30981
|
if (reasoningTokens !== undefined) {
|
|
30946
30982
|
usageBody.unknownExtensions = { "openai.reasoning_tokens": reasoningTokens };
|
|
@@ -34739,6 +34775,23 @@ function tokenize(text) {
|
|
|
34739
34775
|
function tokenSet(text) {
|
|
34740
34776
|
return new Set(tokenize(text));
|
|
34741
34777
|
}
|
|
34778
|
+
function stem(token) {
|
|
34779
|
+
let base = token;
|
|
34780
|
+
if (base.length >= 6 && base.endsWith("ies")) {
|
|
34781
|
+
base = `${base.slice(0, -3)}y`;
|
|
34782
|
+
} else {
|
|
34783
|
+
for (const suffix of ["ing", "edly", "ed", "es", "s"]) {
|
|
34784
|
+
if (base.length - suffix.length >= 3 && base.endsWith(suffix)) {
|
|
34785
|
+
base = base.slice(0, base.length - suffix.length);
|
|
34786
|
+
break;
|
|
34787
|
+
}
|
|
34788
|
+
}
|
|
34789
|
+
}
|
|
34790
|
+
if (base.length >= 4 && base.endsWith("e")) {
|
|
34791
|
+
base = base.slice(0, -1);
|
|
34792
|
+
}
|
|
34793
|
+
return base;
|
|
34794
|
+
}
|
|
34742
34795
|
function jaccard(a, b) {
|
|
34743
34796
|
if (a.size === 0 || b.size === 0) {
|
|
34744
34797
|
return 0;
|
|
@@ -35296,7 +35349,7 @@ var init_ingest = __esm(() => {
|
|
|
35296
35349
|
function searchEntries(entries, query, filters, config, now) {
|
|
35297
35350
|
validateQuery(query);
|
|
35298
35351
|
validateSearchFilters(filters, now);
|
|
35299
|
-
const queryTokens = [...new Set(tokenize(query))];
|
|
35352
|
+
const queryTokens = [...new Set(tokenize(query).map(stem))];
|
|
35300
35353
|
const today = now.toISOString().slice(0, 10);
|
|
35301
35354
|
const filtered = entries.filter((entry) => matchesFilters(entry, filters) && classMatch(entry, filters.class) && temporalMatch(entry, filters.asOf ?? null, config, today, Boolean(filters.status)));
|
|
35302
35355
|
const scored = filtered.map((entry) => scoreEntry(entry, queryTokens, filters, config, now));
|
|
@@ -35305,7 +35358,7 @@ function searchEntries(entries, query, filters, config, now) {
|
|
|
35305
35358
|
function candidatePool(entries, query, filters, config, now, k) {
|
|
35306
35359
|
validateQuery(query);
|
|
35307
35360
|
validateSearchFilters(filters, now);
|
|
35308
|
-
const queryTokens = [...new Set(tokenize(query))];
|
|
35361
|
+
const queryTokens = [...new Set(tokenize(query).map(stem))];
|
|
35309
35362
|
const today = now.toISOString().slice(0, 10);
|
|
35310
35363
|
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
35364
|
}
|
|
@@ -35356,8 +35409,8 @@ function temporalMatch(entry, asOf, config, today, hasStatusFilter) {
|
|
|
35356
35409
|
}, new Date(`${today}T00:00:00.000Z`)).current;
|
|
35357
35410
|
}
|
|
35358
35411
|
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);
|
|
35412
|
+
const bodyTokens = new Set([...tokenSet(`${entry.title} ${entry.summary} ${entry.details} ${entry.tags.join(" ")}`)].map(stem));
|
|
35413
|
+
const titleTokens = new Set([...tokenSet(entry.title)].map(stem));
|
|
35361
35414
|
let hits = 0;
|
|
35362
35415
|
let titleHits = 0;
|
|
35363
35416
|
for (const token of queryTokens) {
|
|
@@ -36214,6 +36267,7 @@ var init_service5 = __esm(() => {
|
|
|
36214
36267
|
init_harness_identity();
|
|
36215
36268
|
init_embedding();
|
|
36216
36269
|
init_types3();
|
|
36270
|
+
init_embedding();
|
|
36217
36271
|
});
|
|
36218
36272
|
|
|
36219
36273
|
// src/wiki/ask.ts
|
|
@@ -39595,6 +39649,7 @@ var init_service7 = __esm(() => {
|
|
|
39595
39649
|
init_query();
|
|
39596
39650
|
init_repomap();
|
|
39597
39651
|
init_affected_report();
|
|
39652
|
+
init_staleness();
|
|
39598
39653
|
UnknownGraphTargetError = class UnknownGraphTargetError extends Error {
|
|
39599
39654
|
target;
|
|
39600
39655
|
constructor(target) {
|
|
@@ -58125,8 +58180,10 @@ async function runAgentTurn(io, deps, history, userLine, options = {}) {
|
|
|
58125
58180
|
|
|
58126
58181
|
${buildControlMarkerInstruction(controlNonce)}`
|
|
58127
58182
|
};
|
|
58183
|
+
const caughtToolErrors = [];
|
|
58128
58184
|
try {
|
|
58129
|
-
const
|
|
58185
|
+
const coreResult = await runAgentTurnCore(io, turnDeps, history, userLine, options, caughtToolErrors);
|
|
58186
|
+
const result = caughtToolErrors.length > 0 ? { ...coreResult, caughtToolErrors } : coreResult;
|
|
58130
58187
|
await fireStopHookBestEffort(io, deps, result);
|
|
58131
58188
|
return result;
|
|
58132
58189
|
} finally {
|
|
@@ -58208,7 +58265,7 @@ function computeReasoningDurationMs(startedAt, endedAt) {
|
|
|
58208
58265
|
const endMs = Date.parse(endedAt);
|
|
58209
58266
|
return !Number.isNaN(startMs) && !Number.isNaN(endMs) && endMs >= startMs ? endMs - startMs : undefined;
|
|
58210
58267
|
}
|
|
58211
|
-
async function runAgentTurnCore(io, deps, history, userLine, options = {}) {
|
|
58268
|
+
async function runAgentTurnCore(io, deps, history, userLine, options = {}, caughtToolErrors = []) {
|
|
58212
58269
|
const now = deps.now ?? (() => new Date().toISOString());
|
|
58213
58270
|
const controlNonce = deps.controlNonce ?? generateControlNonce();
|
|
58214
58271
|
const scrub = (text) => scrubControlNonce(text, controlNonce);
|
|
@@ -58798,7 +58855,7 @@ ${shown.join(`
|
|
|
58798
58855
|
}
|
|
58799
58856
|
const spawnConcurrencyCandidates = calls.filter((call) => call.name === "spawn_subagent" && reservationByCallId.get(call.id)?.ok === true);
|
|
58800
58857
|
const untrustedGateBlocksSpawns = untrustedContentSeen || batchContainsUntrustedWeb;
|
|
58801
|
-
const concurrentSpawnResults = spawnConcurrencyCandidates.length >= 2 && !untrustedGateBlocksSpawns && maxToolCalls === undefined ? await runConcurrentSpawnBatch(spawnConcurrencyCandidates, toolByName, io, deps, hasInvocationCapacity, reserveInvocation, signal) : undefined;
|
|
58858
|
+
const concurrentSpawnResults = spawnConcurrencyCandidates.length >= 2 && !untrustedGateBlocksSpawns && maxToolCalls === undefined ? await runConcurrentSpawnBatch(spawnConcurrencyCandidates, toolByName, io, deps, hasInvocationCapacity, reserveInvocation, signal, caughtToolErrors) : undefined;
|
|
58802
58859
|
const answeredToolIds = new Set;
|
|
58803
58860
|
let anchorsToAnnounce;
|
|
58804
58861
|
let repeatedFailureHint;
|
|
@@ -58898,7 +58955,19 @@ ${shown.join(`
|
|
|
58898
58955
|
if (toolByName.has(call.name)) {
|
|
58899
58956
|
turnExecutedToolCall = true;
|
|
58900
58957
|
}
|
|
58901
|
-
const
|
|
58958
|
+
const precomputedResult = concurrentSpawnResults?.get(call.id);
|
|
58959
|
+
let result;
|
|
58960
|
+
if (precomputedResult !== undefined) {
|
|
58961
|
+
result = precomputedResult;
|
|
58962
|
+
} else {
|
|
58963
|
+
try {
|
|
58964
|
+
result = await executeCall(call, toolByName, io.requestApproval, io.permissionMode, io.readOnly, io.onAutoApproved, hasInvocationCapacity, reserveInvocation, invocationBudget.maxCalls, signal, deps.busLeases, deps.hardDeny === undefined ? undefined : { check: deps.hardDeny, onDenied: io.onUnattendedDenial }, deps.hooks);
|
|
58965
|
+
} catch (err) {
|
|
58966
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
58967
|
+
result = { output: `${call.name} failed: ${message}`, isError: true };
|
|
58968
|
+
caughtToolErrors.push({ toolName: call.name, message });
|
|
58969
|
+
}
|
|
58970
|
+
}
|
|
58902
58971
|
io.onToolResult?.(call.name, result);
|
|
58903
58972
|
const modelOutput = redactSensitiveText(result.output);
|
|
58904
58973
|
const untrusted = result.untrusted === true;
|
|
@@ -59348,7 +59417,7 @@ function isApprovalFor(response, fingerprint) {
|
|
|
59348
59417
|
}
|
|
59349
59418
|
return response.fingerprint === undefined || response.fingerprint === fingerprint;
|
|
59350
59419
|
}
|
|
59351
|
-
async function runConcurrentSpawnBatch(spawnCalls, toolByName, io, deps, hasInvocationCapacity, reserveInvocation, signal) {
|
|
59420
|
+
async function runConcurrentSpawnBatch(spawnCalls, toolByName, io, deps, hasInvocationCapacity, reserveInvocation, signal, caughtToolErrors) {
|
|
59352
59421
|
const maxConcurrency = deps.maxSubagentConcurrency ?? DEFAULT_MAX_SUBAGENT_CONCURRENCY;
|
|
59353
59422
|
const perTaskRuntimeMs = NOMINAL_CONCURRENT_SPAWN_RUNTIME_MS;
|
|
59354
59423
|
const tasks = spawnCalls.map((call) => ({
|
|
@@ -59375,6 +59444,7 @@ async function runConcurrentSpawnBatch(spawnCalls, toolByName, io, deps, hasInvo
|
|
|
59375
59444
|
output: `subagent call ${call.id} failed: sequential fallback error: ${message}`,
|
|
59376
59445
|
isError: true
|
|
59377
59446
|
});
|
|
59447
|
+
caughtToolErrors.push({ toolName: call.name, message });
|
|
59378
59448
|
}
|
|
59379
59449
|
}
|
|
59380
59450
|
return results;
|
|
@@ -59402,6 +59472,9 @@ async function runConcurrentSpawnBatch(spawnCalls, toolByName, io, deps, hasInvo
|
|
|
59402
59472
|
const results = new Map;
|
|
59403
59473
|
for (const call of spawnCalls) {
|
|
59404
59474
|
const settled = partialResults?.get(call.id);
|
|
59475
|
+
if (settled === undefined) {
|
|
59476
|
+
caughtToolErrors.push({ toolName: call.name, message });
|
|
59477
|
+
}
|
|
59405
59478
|
results.set(call.id, settled ?? {
|
|
59406
59479
|
output: `subagent call ${call.id} failed: concurrent wave error: ${message}`,
|
|
59407
59480
|
isError: true
|
|
@@ -60502,7 +60575,8 @@ function computeGate2(input) {
|
|
|
60502
60575
|
}
|
|
60503
60576
|
const missingOptional = sources.filter((s) => !s.required && s.status === "missing");
|
|
60504
60577
|
for (const source of missingOptional) {
|
|
60505
|
-
|
|
60578
|
+
const detail = source.error ? `: ${source.error}` : "";
|
|
60579
|
+
reasons.push(`OPTIONAL: ${source.source} source missing${detail}`);
|
|
60506
60580
|
}
|
|
60507
60581
|
const brokenOptional = sources.filter((s) => !s.required && s.status === "configured-but-failed");
|
|
60508
60582
|
if (brokenOptional.length > 0) {
|
|
@@ -62307,6 +62381,12 @@ function errorCodeSuffix(error) {
|
|
|
62307
62381
|
const code = safeErrorCode(error);
|
|
62308
62382
|
return code ? ` (${code})` : "";
|
|
62309
62383
|
}
|
|
62384
|
+
function missingSourceReason(sourceId) {
|
|
62385
|
+
if (sourceId === "tests") {
|
|
62386
|
+
return "no `bun` binary found (checked node_modules/.bin and PATH)";
|
|
62387
|
+
}
|
|
62388
|
+
return;
|
|
62389
|
+
}
|
|
62310
62390
|
function safeValidationError(error) {
|
|
62311
62391
|
return error !== undefined && KNOWN_VALIDATION_ERRORS.has(error) ? error : "source output format was not recognized";
|
|
62312
62392
|
}
|
|
@@ -62341,7 +62421,8 @@ async function runAdapter(adapter, ctx, cfg, stamp) {
|
|
|
62341
62421
|
};
|
|
62342
62422
|
}
|
|
62343
62423
|
if (status === "skipped" || status === "missing") {
|
|
62344
|
-
|
|
62424
|
+
const reason = missingSourceReason(adapter.id);
|
|
62425
|
+
return { info: { ...base, status, ...reason !== undefined ? { error: reason } : {} }, findings: [] };
|
|
62345
62426
|
}
|
|
62346
62427
|
let raw;
|
|
62347
62428
|
try {
|
|
@@ -62355,7 +62436,7 @@ async function runAdapter(adapter, ctx, cfg, stamp) {
|
|
|
62355
62436
|
} catch (error) {
|
|
62356
62437
|
if (error instanceof NoImportError) {
|
|
62357
62438
|
if (adapter.id === "tests") {
|
|
62358
|
-
return { info: { ...base, status
|
|
62439
|
+
return { info: { ...base, status }, findings: [] };
|
|
62359
62440
|
}
|
|
62360
62441
|
raw = await adapter.run(ctx);
|
|
62361
62442
|
} else {
|
|
@@ -62720,6 +62801,7 @@ var init_service10 = __esm(() => {
|
|
|
62720
62801
|
init_sources();
|
|
62721
62802
|
init_util();
|
|
62722
62803
|
init_lifecycle2();
|
|
62804
|
+
init_wiki_freshness();
|
|
62723
62805
|
});
|
|
62724
62806
|
|
|
62725
62807
|
// src/flow/machine.ts
|
|
@@ -70731,6 +70813,7 @@ async function runSearch(args) {
|
|
|
70731
70813
|
}
|
|
70732
70814
|
const report = args.includes("--save-report") ? await getService().writeReport({ cwd: process.cwd(), search: result, filters }) : undefined;
|
|
70733
70815
|
const removalTrail = result.results.length === 0 ? searchRemovals(await loadDeletionTrail(process.cwd()), query) : null;
|
|
70816
|
+
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;
|
|
70734
70817
|
const asOfMode = Boolean(filters.asOf);
|
|
70735
70818
|
const now = new Date;
|
|
70736
70819
|
const historicalByPath = new Map;
|
|
@@ -70759,11 +70842,16 @@ async function runSearch(args) {
|
|
|
70759
70842
|
};
|
|
70760
70843
|
}),
|
|
70761
70844
|
...removalTrail ? { removalTrail } : {},
|
|
70845
|
+
...semanticHint ? { semanticHint } : {},
|
|
70762
70846
|
...report ? { report } : {}
|
|
70763
70847
|
}, null, 2));
|
|
70764
70848
|
return;
|
|
70765
70849
|
}
|
|
70766
70850
|
console.log(renderSearchMarkdown(query, result.results).trimEnd());
|
|
70851
|
+
if (semanticHint) {
|
|
70852
|
+
console.log("");
|
|
70853
|
+
console.log(semanticHint);
|
|
70854
|
+
}
|
|
70767
70855
|
if (removalTrail) {
|
|
70768
70856
|
console.log("");
|
|
70769
70857
|
console.log("## Removal trail");
|
|
@@ -71060,6 +71148,7 @@ var init_memory = __esm(() => {
|
|
|
71060
71148
|
init_config4();
|
|
71061
71149
|
init_reflect();
|
|
71062
71150
|
init_search();
|
|
71151
|
+
init_service5();
|
|
71063
71152
|
init_report2();
|
|
71064
71153
|
init_lifecycle();
|
|
71065
71154
|
init_args();
|
|
@@ -71636,7 +71725,7 @@ var init_debug_log = __esm(() => {
|
|
|
71636
71725
|
// src/tui/debug-watcher.ts
|
|
71637
71726
|
import { spawn as spawn8, spawnSync as spawnSync8 } from "child_process";
|
|
71638
71727
|
import { closeSync as closeSync6, constants as constants4, openSync as openSync7, readdirSync as readdirSync11, readFileSync as readFileSync24, readlinkSync as readlinkSync3, statSync as statSync16 } from "fs";
|
|
71639
|
-
import
|
|
71728
|
+
import path317 from "path";
|
|
71640
71729
|
function parseEpollFdinfo(text) {
|
|
71641
71730
|
const out = [];
|
|
71642
71731
|
for (const line of text.split(`
|
|
@@ -71825,8 +71914,8 @@ async function runDebugWatcher(argv) {
|
|
|
71825
71914
|
process.exitCode = 2;
|
|
71826
71915
|
return;
|
|
71827
71916
|
}
|
|
71828
|
-
const logFile =
|
|
71829
|
-
const shellLog =
|
|
71917
|
+
const logFile = path317.join(dirArg, "watcher.ndjson");
|
|
71918
|
+
const shellLog = path317.join(dirArg, "shell.ndjson");
|
|
71830
71919
|
const log = (kind, data = {}) => {
|
|
71831
71920
|
try {
|
|
71832
71921
|
appendOwnerOnlyLine(logFile, JSON.stringify({ ts: new Date().toISOString(), watcher: process.pid, target: pid, kind, ...data }));
|
|
@@ -107084,6 +107173,18 @@ var HELP_GROUPS = [
|
|
|
107084
107173
|
summary: "Grouped command help by task \u2014 keryx help [group|command]."
|
|
107085
107174
|
},
|
|
107086
107175
|
{ kind: "slash", name: "/help", group: "Start here", summary: "Show available commands, grouped by task." },
|
|
107176
|
+
{
|
|
107177
|
+
kind: "cli",
|
|
107178
|
+
name: "doctor",
|
|
107179
|
+
group: "Start here",
|
|
107180
|
+
summary: "One-page health check: version, Bun floor, ripgrep, sandbox, providers, MCP, integrations, standard, worktrees, graph/wiki freshness."
|
|
107181
|
+
},
|
|
107182
|
+
{
|
|
107183
|
+
kind: "slash",
|
|
107184
|
+
name: "/doctor",
|
|
107185
|
+
group: "Start here",
|
|
107186
|
+
summary: "Same one-page health check, inside the session."
|
|
107187
|
+
},
|
|
107087
107188
|
{
|
|
107088
107189
|
kind: "cli",
|
|
107089
107190
|
name: "auth",
|
|
@@ -109216,6 +109317,19 @@ var COMMAND_DESCRIPTORS = [
|
|
|
109216
109317
|
json: false,
|
|
109217
109318
|
read: true
|
|
109218
109319
|
},
|
|
109320
|
+
{
|
|
109321
|
+
module: "core",
|
|
109322
|
+
command: "doctor",
|
|
109323
|
+
summary: "One-page health check: version, Bun floor, ripgrep, sandbox, providers, MCP, integrations, standard, worktrees, graph/wiki freshness.",
|
|
109324
|
+
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"],
|
|
109325
|
+
args: [{ name: "json", type: "bool", required: false, desc: "structured {checks:[{id,status,detail,fix?}]}" }],
|
|
109326
|
+
json: true,
|
|
109327
|
+
read: false,
|
|
109328
|
+
sideEffects: [
|
|
109329
|
+
"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",
|
|
109330
|
+
"writes <per-user keryx config dir>/version-check.json (outside this project) as part of that same check"
|
|
109331
|
+
]
|
|
109332
|
+
},
|
|
109219
109333
|
{
|
|
109220
109334
|
module: "core",
|
|
109221
109335
|
command: "status",
|
|
@@ -111307,6 +111421,49 @@ async function sandboxCommand(args = [], deps = {}) {
|
|
|
111307
111421
|
init_args();
|
|
111308
111422
|
init_ui();
|
|
111309
111423
|
|
|
111424
|
+
// src/lib/suggest.ts
|
|
111425
|
+
var MAX_SUGGESTIONS = 3;
|
|
111426
|
+
var MAX_EDIT_DISTANCE = 2;
|
|
111427
|
+
function levenshtein2(a, b) {
|
|
111428
|
+
const rows = a.length + 1;
|
|
111429
|
+
const cols = b.length + 1;
|
|
111430
|
+
const dp = Array.from({ length: rows }, () => new Array(cols).fill(0));
|
|
111431
|
+
for (let i = 0;i < rows; i += 1) {
|
|
111432
|
+
const row = dp[i];
|
|
111433
|
+
if (row !== undefined)
|
|
111434
|
+
row[0] = i;
|
|
111435
|
+
}
|
|
111436
|
+
const first = dp[0];
|
|
111437
|
+
if (first !== undefined) {
|
|
111438
|
+
for (let j = 0;j < cols; j += 1)
|
|
111439
|
+
first[j] = j;
|
|
111440
|
+
}
|
|
111441
|
+
for (let i = 1;i < rows; i += 1) {
|
|
111442
|
+
for (let j = 1;j < cols; j += 1) {
|
|
111443
|
+
const same = a[i - 1] === b[j - 1];
|
|
111444
|
+
const up = dp[i - 1]?.[j] ?? 0;
|
|
111445
|
+
const left = dp[i]?.[j - 1] ?? 0;
|
|
111446
|
+
const diag = dp[i - 1]?.[j - 1] ?? 0;
|
|
111447
|
+
const row = dp[i];
|
|
111448
|
+
if (row !== undefined)
|
|
111449
|
+
row[j] = same ? diag : 1 + Math.min(up, left, diag);
|
|
111450
|
+
}
|
|
111451
|
+
}
|
|
111452
|
+
return dp[rows - 1]?.[cols - 1] ?? Math.max(a.length, b.length);
|
|
111453
|
+
}
|
|
111454
|
+
function suggestClosest(input, known) {
|
|
111455
|
+
const needle = input.trim().toLowerCase();
|
|
111456
|
+
if (needle.length === 0) {
|
|
111457
|
+
return [];
|
|
111458
|
+
}
|
|
111459
|
+
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);
|
|
111460
|
+
}
|
|
111461
|
+
function formatUnknownCommandMessage(input, known, helpCommand = "keryx --help") {
|
|
111462
|
+
const suggestions = suggestClosest(input, known);
|
|
111463
|
+
const didYouMean = suggestions.length > 0 ? ` Did you mean: ${suggestions.join(", ")}?` : "";
|
|
111464
|
+
return `Unknown command: ${input}.${didYouMean} Run \`${helpCommand}\` for the list.`;
|
|
111465
|
+
}
|
|
111466
|
+
|
|
111310
111467
|
// src/commands/integrate.ts
|
|
111311
111468
|
init_ui();
|
|
111312
111469
|
import path257 from "path";
|
|
@@ -111853,12 +112010,12 @@ function loadMcpServers(options) {
|
|
|
111853
112010
|
const home = options.home ?? (options.configDir === undefined ? undefined : NO_HOME);
|
|
111854
112011
|
for (const entry of compatFiles(options.cwd, home)) {
|
|
111855
112012
|
const read = readCompatFile(entry, options.cwd);
|
|
111856
|
-
problems.push(...read.problems);
|
|
112013
|
+
problems.push(...read.problems.map((p) => ({ ...p, foreign: true })));
|
|
111857
112014
|
for (const [name, value] of Object.entries(read.servers)) {
|
|
111858
112015
|
const found = entryProblems(name, value);
|
|
111859
112016
|
if (found.length > 0) {
|
|
111860
112017
|
for (const message of found)
|
|
111861
|
-
problems.push({ file: entry.file, message });
|
|
112018
|
+
problems.push({ file: entry.file, message, foreign: true });
|
|
111862
112019
|
continue;
|
|
111863
112020
|
}
|
|
111864
112021
|
winner.set(name, {
|
|
@@ -114032,19 +114189,31 @@ function publicView(server, env) {
|
|
|
114032
114189
|
function listCommand(args, deps) {
|
|
114033
114190
|
const config = load(deps);
|
|
114034
114191
|
const wantJson = splitAtSeparator(args).own.includes("--json");
|
|
114192
|
+
const ownProblems = config.problems.filter((p) => !p.foreign);
|
|
114193
|
+
const foreignProblems = config.problems.filter((p) => p.foreign);
|
|
114035
114194
|
if (wantJson) {
|
|
114036
114195
|
const env = deps.env ?? process.env;
|
|
114037
|
-
deps.log(JSON.stringify({
|
|
114038
|
-
|
|
114196
|
+
deps.log(JSON.stringify({
|
|
114197
|
+
servers: config.servers.map((s) => publicView(s, env)),
|
|
114198
|
+
problems: ownProblems,
|
|
114199
|
+
warnings: foreignProblems
|
|
114200
|
+
}, null, 2));
|
|
114201
|
+
return ownProblems.length > 0 ? 1 : 0;
|
|
114039
114202
|
}
|
|
114040
|
-
for (const problem of
|
|
114203
|
+
for (const problem of ownProblems) {
|
|
114041
114204
|
deps.err(`config problem \u2014 ${problem.file}: ${problem.message}`);
|
|
114042
114205
|
}
|
|
114206
|
+
if (foreignProblems.length > 0) {
|
|
114207
|
+
deps.err("warnings:");
|
|
114208
|
+
for (const problem of foreignProblems) {
|
|
114209
|
+
deps.err(` ${problem.file}: ${problem.message}`);
|
|
114210
|
+
}
|
|
114211
|
+
}
|
|
114043
114212
|
if (config.servers.length === 0) {
|
|
114044
114213
|
deps.log("No MCP servers configured.");
|
|
114045
114214
|
deps.log(` user: ${userConfigFile(deps.configDir)}`);
|
|
114046
114215
|
deps.log(` project: ${projectConfigFile(projectRootOf2(deps))}`);
|
|
114047
|
-
return
|
|
114216
|
+
return ownProblems.length > 0 ? 1 : 0;
|
|
114048
114217
|
}
|
|
114049
114218
|
const approvals = loadTrustStore(deps.configDir);
|
|
114050
114219
|
let held = 0;
|
|
@@ -114063,7 +114232,7 @@ function listCommand(args, deps) {
|
|
|
114063
114232
|
deps.log(`${held} server(s) from committed config are not started until approved \u2014 a committed config is code someone else wrote.`);
|
|
114064
114233
|
deps.log("Read what it launches above, then: keryx mcp trust <name>");
|
|
114065
114234
|
}
|
|
114066
|
-
return
|
|
114235
|
+
return ownProblems.length > 0 ? 1 : 0;
|
|
114067
114236
|
}
|
|
114068
114237
|
function describeTarget(server) {
|
|
114069
114238
|
const raw = server.raw;
|
|
@@ -116960,8 +117129,12 @@ async function mcpCommand(args = [], cwd = process.cwd()) {
|
|
|
116960
117129
|
await serveMcpCommand(args.slice(1), cwd);
|
|
116961
117130
|
return;
|
|
116962
117131
|
}
|
|
116963
|
-
console.error(
|
|
116964
|
-
|
|
117132
|
+
console.error(formatUnknownCommandMessage(subcommand ?? "", [
|
|
117133
|
+
...MCP_CONSUMER_SUBCOMMANDS,
|
|
117134
|
+
"install",
|
|
117135
|
+
"uninstall",
|
|
117136
|
+
"serve"
|
|
117137
|
+
], "keryx mcp --help"));
|
|
116965
117138
|
process.exitCode = 1;
|
|
116966
117139
|
}
|
|
116967
117140
|
function announceRename(retired, replacement) {
|
|
@@ -127578,7 +127751,7 @@ async function dispatchLocked(projectRoot, entry, flow, dispatch, deps, runId) {
|
|
|
127578
127751
|
});
|
|
127579
127752
|
const provider = guardUsage(built, () => meter.markUsageMissing());
|
|
127580
127753
|
try {
|
|
127581
|
-
const tools = buildUnattendedRoster(worktree, unattendedRunner(worktree, sandbox));
|
|
127754
|
+
const tools = [...buildUnattendedRoster(worktree, unattendedRunner(worktree, sandbox)), ...deps.extraTools ?? []];
|
|
127582
127755
|
const toolNames = tools.map((t) => t.definition.name);
|
|
127583
127756
|
const shellHooks = buildShellHookRuntime({
|
|
127584
127757
|
projectRoot: worktree,
|
|
@@ -127633,6 +127806,9 @@ async function dispatchLocked(projectRoot, entry, flow, dispatch, deps, runId) {
|
|
|
127633
127806
|
signal: controller.signal
|
|
127634
127807
|
});
|
|
127635
127808
|
finishReason = result.finishReason;
|
|
127809
|
+
if (result.caughtToolErrors !== undefined && result.caughtToolErrors.length > 0) {
|
|
127810
|
+
crashed = result.caughtToolErrors.map((e) => `${e.toolName}: ${e.message}`).join("; ");
|
|
127811
|
+
}
|
|
127636
127812
|
} catch (error) {
|
|
127637
127813
|
crashed = error instanceof Error ? error.message : String(error);
|
|
127638
127814
|
} finally {
|
|
@@ -135479,6 +135655,569 @@ class NextStepSuggestionGate {
|
|
|
135479
135655
|
}
|
|
135480
135656
|
}
|
|
135481
135657
|
|
|
135658
|
+
// src/commands/doctor.ts
|
|
135659
|
+
init_package();
|
|
135660
|
+
import { readdir as readdir53 } from "fs/promises";
|
|
135661
|
+
import { existsSync as existsSync48 } from "fs";
|
|
135662
|
+
import path302 from "path";
|
|
135663
|
+
|
|
135664
|
+
// src/lib/version-check.ts
|
|
135665
|
+
init_config_dir();
|
|
135666
|
+
init_fs();
|
|
135667
|
+
import path301 from "path";
|
|
135668
|
+
var REGISTRY_URL = "https://registry.npmjs.org/@mrciphersmith%2Fkeryx/latest";
|
|
135669
|
+
var FIXED_INSTALL_COMMAND = "npm install -g @mrciphersmith/keryx@latest";
|
|
135670
|
+
var RESPONSE_BODY_LIMIT_BYTES = 64 * 1024;
|
|
135671
|
+
var VERSION_STRING_LIMIT_CHARS = 64;
|
|
135672
|
+
var REQUEST_TIMEOUT_MS = 2000;
|
|
135673
|
+
var SUCCESS_CACHE_TTL_MS = 24 * 60 * 60 * 1000;
|
|
135674
|
+
var FAILURE_BACKOFF_MS = 15 * 60 * 1000;
|
|
135675
|
+
var CACHE_LOCK_TIMEOUT_MS2 = 250;
|
|
135676
|
+
var CACHE_LOCK_RETRY_MS2 = 10;
|
|
135677
|
+
var CACHE_LOCK_STALE_MS2 = 5000;
|
|
135678
|
+
var SYSTEM_TIMER = {
|
|
135679
|
+
schedule: (callback, delayMs) => setTimeout(callback, delayMs),
|
|
135680
|
+
cancel: (handle) => clearTimeout(handle)
|
|
135681
|
+
};
|
|
135682
|
+
function formatVersionUpdateAdvisory(result) {
|
|
135683
|
+
if (result.status !== "update-available")
|
|
135684
|
+
return;
|
|
135685
|
+
return `Keryx update ${result.currentVersion} \u2192 ${result.latestVersion}
|
|
135686
|
+
${result.installCommand}`;
|
|
135687
|
+
}
|
|
135688
|
+
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-]+)*))?$/;
|
|
135689
|
+
function parseSemVer(value) {
|
|
135690
|
+
if (value.length > VERSION_STRING_LIMIT_CHARS)
|
|
135691
|
+
return;
|
|
135692
|
+
const match = STRICT_SEMVER.exec(value);
|
|
135693
|
+
if (match === null)
|
|
135694
|
+
return;
|
|
135695
|
+
const prereleaseText = match[4];
|
|
135696
|
+
const prerelease = [];
|
|
135697
|
+
if (prereleaseText !== undefined) {
|
|
135698
|
+
for (const identifier of prereleaseText.split(".")) {
|
|
135699
|
+
if (/^\d+$/.test(identifier)) {
|
|
135700
|
+
if (identifier.length > 1 && identifier.startsWith("0"))
|
|
135701
|
+
return;
|
|
135702
|
+
prerelease.push(BigInt(identifier));
|
|
135703
|
+
} else {
|
|
135704
|
+
prerelease.push(identifier);
|
|
135705
|
+
}
|
|
135706
|
+
}
|
|
135707
|
+
}
|
|
135708
|
+
return {
|
|
135709
|
+
major: BigInt(match[1]),
|
|
135710
|
+
minor: BigInt(match[2]),
|
|
135711
|
+
patch: BigInt(match[3]),
|
|
135712
|
+
prerelease
|
|
135713
|
+
};
|
|
135714
|
+
}
|
|
135715
|
+
function compareSemVer(left, right) {
|
|
135716
|
+
for (const key of ["major", "minor", "patch"]) {
|
|
135717
|
+
if (left[key] < right[key])
|
|
135718
|
+
return -1;
|
|
135719
|
+
if (left[key] > right[key])
|
|
135720
|
+
return 1;
|
|
135721
|
+
}
|
|
135722
|
+
if (left.prerelease.length === 0 || right.prerelease.length === 0) {
|
|
135723
|
+
if (left.prerelease.length === right.prerelease.length)
|
|
135724
|
+
return 0;
|
|
135725
|
+
return left.prerelease.length === 0 ? 1 : -1;
|
|
135726
|
+
}
|
|
135727
|
+
const length = Math.max(left.prerelease.length, right.prerelease.length);
|
|
135728
|
+
for (let index = 0;index < length; index += 1) {
|
|
135729
|
+
const a = left.prerelease[index];
|
|
135730
|
+
const b = right.prerelease[index];
|
|
135731
|
+
if (a === undefined || b === undefined) {
|
|
135732
|
+
if (a === b)
|
|
135733
|
+
return 0;
|
|
135734
|
+
return a === undefined ? -1 : 1;
|
|
135735
|
+
}
|
|
135736
|
+
if (typeof a === "bigint" && typeof b === "bigint") {
|
|
135737
|
+
if (a < b)
|
|
135738
|
+
return -1;
|
|
135739
|
+
if (a > b)
|
|
135740
|
+
return 1;
|
|
135741
|
+
} else if (typeof a === "bigint") {
|
|
135742
|
+
return -1;
|
|
135743
|
+
} else if (typeof b === "bigint") {
|
|
135744
|
+
return 1;
|
|
135745
|
+
} else if (a !== b) {
|
|
135746
|
+
return a < b ? -1 : 1;
|
|
135747
|
+
}
|
|
135748
|
+
}
|
|
135749
|
+
return 0;
|
|
135750
|
+
}
|
|
135751
|
+
function parseCache(file) {
|
|
135752
|
+
const read = readConfigFile(file);
|
|
135753
|
+
if (!read.ok)
|
|
135754
|
+
return;
|
|
135755
|
+
try {
|
|
135756
|
+
const value = JSON.parse(read.text);
|
|
135757
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
135758
|
+
return;
|
|
135759
|
+
const record = value;
|
|
135760
|
+
const cache = {};
|
|
135761
|
+
if (typeof record.latestVersion === "string" && parseSemVer(record.latestVersion) !== undefined) {
|
|
135762
|
+
cache.latestVersion = record.latestVersion;
|
|
135763
|
+
}
|
|
135764
|
+
if (typeof record.successAt === "number" && Number.isFinite(record.successAt))
|
|
135765
|
+
cache.successAt = record.successAt;
|
|
135766
|
+
if (typeof record.failureAt === "number" && Number.isFinite(record.failureAt))
|
|
135767
|
+
cache.failureAt = record.failureAt;
|
|
135768
|
+
return cache;
|
|
135769
|
+
} catch {
|
|
135770
|
+
return;
|
|
135771
|
+
}
|
|
135772
|
+
}
|
|
135773
|
+
function resultFor(currentVersion, current, latestVersion, source) {
|
|
135774
|
+
const latest = parseSemVer(latestVersion);
|
|
135775
|
+
return compareSemVer(current, latest) < 0 ? { status: "update-available", currentVersion, latestVersion, installCommand: FIXED_INSTALL_COMMAND, source } : { status: "up-to-date", currentVersion, latestVersion, source };
|
|
135776
|
+
}
|
|
135777
|
+
function cancelWithoutWaiting(cancel) {
|
|
135778
|
+
try {
|
|
135779
|
+
cancel().catch(() => {});
|
|
135780
|
+
} catch {}
|
|
135781
|
+
}
|
|
135782
|
+
async function boundedResponseText(response) {
|
|
135783
|
+
const declared = response.headers.get("content-length");
|
|
135784
|
+
if (declared !== null && /^\d+$/.test(declared) && BigInt(declared) > BigInt(RESPONSE_BODY_LIMIT_BYTES)) {
|
|
135785
|
+
if (response.body !== null) {
|
|
135786
|
+
cancelWithoutWaiting(() => response.body.cancel());
|
|
135787
|
+
}
|
|
135788
|
+
return;
|
|
135789
|
+
}
|
|
135790
|
+
if (response.body === null)
|
|
135791
|
+
return "";
|
|
135792
|
+
const reader = response.body.getReader();
|
|
135793
|
+
const decoder = new TextDecoder;
|
|
135794
|
+
let size = 0;
|
|
135795
|
+
let text = "";
|
|
135796
|
+
try {
|
|
135797
|
+
for (;; ) {
|
|
135798
|
+
const chunk = await reader.read();
|
|
135799
|
+
if (chunk.done)
|
|
135800
|
+
break;
|
|
135801
|
+
size += chunk.value.byteLength;
|
|
135802
|
+
if (size > RESPONSE_BODY_LIMIT_BYTES) {
|
|
135803
|
+
cancelWithoutWaiting(() => reader.cancel());
|
|
135804
|
+
return;
|
|
135805
|
+
}
|
|
135806
|
+
text += decoder.decode(chunk.value, { stream: true });
|
|
135807
|
+
}
|
|
135808
|
+
return text + decoder.decode();
|
|
135809
|
+
} finally {
|
|
135810
|
+
reader.releaseLock();
|
|
135811
|
+
}
|
|
135812
|
+
}
|
|
135813
|
+
function unavailable(currentVersion, reason, cache) {
|
|
135814
|
+
return {
|
|
135815
|
+
status: "unavailable",
|
|
135816
|
+
currentVersion,
|
|
135817
|
+
reason,
|
|
135818
|
+
...cache?.latestVersion !== undefined ? { cachedLatestVersion: cache.latestVersion } : {}
|
|
135819
|
+
};
|
|
135820
|
+
}
|
|
135821
|
+
function saveCache2(file, cache) {
|
|
135822
|
+
try {
|
|
135823
|
+
writeOwnerOnlyFileAtomic(file, `${JSON.stringify(cache, null, 2)}
|
|
135824
|
+
`);
|
|
135825
|
+
return true;
|
|
135826
|
+
} catch {
|
|
135827
|
+
return false;
|
|
135828
|
+
}
|
|
135829
|
+
}
|
|
135830
|
+
function mergeSuccessfulCache(committed, latestVersion, successAt) {
|
|
135831
|
+
if (committed.latestVersion === undefined || committed.successAt === undefined) {
|
|
135832
|
+
return { latestVersion, successAt };
|
|
135833
|
+
}
|
|
135834
|
+
if (committed.successAt > successAt)
|
|
135835
|
+
return committed;
|
|
135836
|
+
if (committed.successAt < successAt)
|
|
135837
|
+
return { latestVersion, successAt };
|
|
135838
|
+
const committedVersion = parseSemVer(committed.latestVersion);
|
|
135839
|
+
const candidateVersion = parseSemVer(latestVersion);
|
|
135840
|
+
if (committedVersion !== undefined && candidateVersion !== undefined) {
|
|
135841
|
+
const precedence = compareSemVer(committedVersion, candidateVersion);
|
|
135842
|
+
if (precedence > 0)
|
|
135843
|
+
return committed;
|
|
135844
|
+
if (precedence < 0)
|
|
135845
|
+
return { latestVersion, successAt };
|
|
135846
|
+
if (committed.latestVersion >= latestVersion)
|
|
135847
|
+
return committed;
|
|
135848
|
+
}
|
|
135849
|
+
return { latestVersion, successAt };
|
|
135850
|
+
}
|
|
135851
|
+
async function updateCache(file, update) {
|
|
135852
|
+
try {
|
|
135853
|
+
return await withFileLock(`${file}.lock`, async () => saveCache2(file, update(parseCache(file) ?? {})), {
|
|
135854
|
+
timeoutMs: CACHE_LOCK_TIMEOUT_MS2,
|
|
135855
|
+
retryMs: CACHE_LOCK_RETRY_MS2,
|
|
135856
|
+
staleMs: CACHE_LOCK_STALE_MS2
|
|
135857
|
+
});
|
|
135858
|
+
} catch {
|
|
135859
|
+
return false;
|
|
135860
|
+
}
|
|
135861
|
+
}
|
|
135862
|
+
async function checkVersion(options) {
|
|
135863
|
+
const current = parseSemVer(options.currentVersion);
|
|
135864
|
+
if (current === undefined)
|
|
135865
|
+
return unavailable(options.currentVersion, "invalid-current-version");
|
|
135866
|
+
const now = options.now ?? Date.now;
|
|
135867
|
+
const timestamp = now();
|
|
135868
|
+
const configDir = ensureKeryxConfigDir(options.cacheDir);
|
|
135869
|
+
const cacheFile = path301.join(configDir, "version-check.json");
|
|
135870
|
+
const cache = parseCache(cacheFile);
|
|
135871
|
+
if (cache?.latestVersion !== undefined && cache.successAt !== undefined && timestamp - cache.successAt >= 0 && timestamp - cache.successAt < SUCCESS_CACHE_TTL_MS) {
|
|
135872
|
+
return resultFor(options.currentVersion, current, cache.latestVersion, "cache");
|
|
135873
|
+
}
|
|
135874
|
+
if (cache?.failureAt !== undefined && timestamp - cache.failureAt >= 0 && timestamp - cache.failureAt < FAILURE_BACKOFF_MS) {
|
|
135875
|
+
return unavailable(options.currentVersion, "suppressed", cache);
|
|
135876
|
+
}
|
|
135877
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
135878
|
+
const controller = new AbortController;
|
|
135879
|
+
const timer = options.timer ?? SYSTEM_TIMER;
|
|
135880
|
+
let timeout;
|
|
135881
|
+
let timeoutScheduled = false;
|
|
135882
|
+
let failure;
|
|
135883
|
+
let latestVersion;
|
|
135884
|
+
try {
|
|
135885
|
+
timeout = timer.schedule(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
135886
|
+
timeoutScheduled = true;
|
|
135887
|
+
const response = await fetchImpl(REGISTRY_URL, {
|
|
135888
|
+
method: "GET",
|
|
135889
|
+
headers: { accept: "application/json" },
|
|
135890
|
+
signal: controller.signal,
|
|
135891
|
+
credentials: "omit"
|
|
135892
|
+
});
|
|
135893
|
+
if (!response.ok) {
|
|
135894
|
+
failure = "http";
|
|
135895
|
+
} else {
|
|
135896
|
+
const body = await boundedResponseText(response);
|
|
135897
|
+
if (body === undefined) {
|
|
135898
|
+
failure = "response-too-large";
|
|
135899
|
+
} else {
|
|
135900
|
+
let parsed;
|
|
135901
|
+
try {
|
|
135902
|
+
parsed = JSON.parse(body);
|
|
135903
|
+
} catch {
|
|
135904
|
+
parsed = undefined;
|
|
135905
|
+
}
|
|
135906
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
135907
|
+
failure = "malformed-response";
|
|
135908
|
+
} else {
|
|
135909
|
+
const record = parsed;
|
|
135910
|
+
if (record.name !== "@mrciphersmith/keryx" || typeof record.version !== "string") {
|
|
135911
|
+
failure = "malformed-response";
|
|
135912
|
+
} else if (parseSemVer(record.version) === undefined) {
|
|
135913
|
+
failure = "invalid-latest-version";
|
|
135914
|
+
} else {
|
|
135915
|
+
latestVersion = record.version;
|
|
135916
|
+
}
|
|
135917
|
+
}
|
|
135918
|
+
}
|
|
135919
|
+
}
|
|
135920
|
+
} catch {
|
|
135921
|
+
failure = controller.signal.aborted ? "timeout" : "network";
|
|
135922
|
+
} finally {
|
|
135923
|
+
if (timeoutScheduled) {
|
|
135924
|
+
try {
|
|
135925
|
+
timer.cancel(timeout);
|
|
135926
|
+
} catch {}
|
|
135927
|
+
}
|
|
135928
|
+
}
|
|
135929
|
+
if (latestVersion === undefined) {
|
|
135930
|
+
await updateCache(cacheFile, (committed) => ({ ...committed, failureAt: timestamp }));
|
|
135931
|
+
return unavailable(options.currentVersion, failure ?? "network", cache);
|
|
135932
|
+
}
|
|
135933
|
+
await updateCache(cacheFile, (committed) => mergeSuccessfulCache(committed, latestVersion, timestamp));
|
|
135934
|
+
return resultFor(options.currentVersion, current, latestVersion, "registry");
|
|
135935
|
+
}
|
|
135936
|
+
|
|
135937
|
+
// src/commands/doctor.ts
|
|
135938
|
+
init_contained_path();
|
|
135939
|
+
init_providers();
|
|
135940
|
+
init_service();
|
|
135941
|
+
init_service7();
|
|
135942
|
+
init_service10();
|
|
135943
|
+
async function registeredWorktrees(cwd) {
|
|
135944
|
+
if (!Bun.which("git"))
|
|
135945
|
+
return new Set;
|
|
135946
|
+
try {
|
|
135947
|
+
const proc = Bun.spawn(["git", "worktree", "list", "--porcelain"], { cwd, stdout: "pipe", stderr: "ignore" });
|
|
135948
|
+
const [stdout, code] = await Promise.all([new Response(proc.stdout).text(), proc.exited]);
|
|
135949
|
+
if (code !== 0)
|
|
135950
|
+
return new Set;
|
|
135951
|
+
const paths = new Set;
|
|
135952
|
+
for (const line of stdout.split(`
|
|
135953
|
+
`)) {
|
|
135954
|
+
if (line.startsWith("worktree ")) {
|
|
135955
|
+
paths.add(path302.resolve(line.slice("worktree ".length).trim()));
|
|
135956
|
+
}
|
|
135957
|
+
}
|
|
135958
|
+
return paths;
|
|
135959
|
+
} catch {
|
|
135960
|
+
return new Set;
|
|
135961
|
+
}
|
|
135962
|
+
}
|
|
135963
|
+
async function checkWorktrees(cwd) {
|
|
135964
|
+
const worktreesDir = path302.join(cwd, ".claude", "worktrees");
|
|
135965
|
+
let entries;
|
|
135966
|
+
try {
|
|
135967
|
+
entries = (await readdir53(worktreesDir, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
|
|
135968
|
+
} catch {
|
|
135969
|
+
return { id: "worktrees", status: "ok", detail: "no .claude/worktrees directory" };
|
|
135970
|
+
}
|
|
135971
|
+
if (entries.length === 0) {
|
|
135972
|
+
return { id: "worktrees", status: "ok", detail: ".claude/worktrees is empty" };
|
|
135973
|
+
}
|
|
135974
|
+
const registered = await registeredWorktrees(cwd);
|
|
135975
|
+
const stale = entries.filter((name) => {
|
|
135976
|
+
const full = path302.resolve(worktreesDir, name);
|
|
135977
|
+
return !existsSync48(path302.join(full, ".git")) || !registered.has(full);
|
|
135978
|
+
});
|
|
135979
|
+
if (stale.length === 0) {
|
|
135980
|
+
return {
|
|
135981
|
+
id: "worktrees",
|
|
135982
|
+
status: "ok",
|
|
135983
|
+
detail: `${entries.length} worktree(s) under .claude/worktrees, all registered`
|
|
135984
|
+
};
|
|
135985
|
+
}
|
|
135986
|
+
return {
|
|
135987
|
+
id: "worktrees",
|
|
135988
|
+
status: "warn",
|
|
135989
|
+
detail: `${stale.length} stale entr${stale.length === 1 ? "y" : "ies"} under .claude/worktrees: ${stale.join(", ")}`,
|
|
135990
|
+
fix: "git worktree prune, then remove the listed directories under .claude/worktrees by hand"
|
|
135991
|
+
};
|
|
135992
|
+
}
|
|
135993
|
+
function meetsBunFloor(current, floor) {
|
|
135994
|
+
const floorMatch = /^>=\s*(\d+)\.(\d+)\.(\d+)/.exec(floor);
|
|
135995
|
+
const currentMatch = /^(\d+)\.(\d+)\.(\d+)/.exec(current);
|
|
135996
|
+
if (!floorMatch || !currentMatch)
|
|
135997
|
+
return true;
|
|
135998
|
+
for (let i = 1;i <= 3; i += 1) {
|
|
135999
|
+
const f = Number(floorMatch[i]);
|
|
136000
|
+
const c = Number(currentMatch[i]);
|
|
136001
|
+
if (c !== f)
|
|
136002
|
+
return c > f;
|
|
136003
|
+
}
|
|
136004
|
+
return true;
|
|
136005
|
+
}
|
|
136006
|
+
function checkBun(bunFloorOverride) {
|
|
136007
|
+
const floor = bunFloorOverride ?? package_default.engines?.bun;
|
|
136008
|
+
const current = Bun.version;
|
|
136009
|
+
if (floor === undefined || meetsBunFloor(current, floor)) {
|
|
136010
|
+
return { id: "bun", status: "ok", detail: `Bun ${current}${floor ? ` (floor ${floor})` : ""}` };
|
|
136011
|
+
}
|
|
136012
|
+
return {
|
|
136013
|
+
id: "bun",
|
|
136014
|
+
status: "fail",
|
|
136015
|
+
detail: `Bun ${current} is below the documented floor ${floor}`,
|
|
136016
|
+
fix: "upgrade Bun: https://bun.sh/docs/installation"
|
|
136017
|
+
};
|
|
136018
|
+
}
|
|
136019
|
+
function checkRipgrep() {
|
|
136020
|
+
const rg = Bun.which("rg");
|
|
136021
|
+
return rg ? { id: "ripgrep", status: "ok", detail: `rg at ${rg}` } : {
|
|
136022
|
+
id: "ripgrep",
|
|
136023
|
+
status: "warn",
|
|
136024
|
+
detail: "ripgrep (rg) not found on PATH \u2014 keryx ctx rg and search_code are unavailable",
|
|
136025
|
+
fix: "brew install ripgrep (macOS) or apt install ripgrep (Debian/Ubuntu)"
|
|
136026
|
+
};
|
|
136027
|
+
}
|
|
136028
|
+
async function checkVersionAvailability() {
|
|
136029
|
+
const result = await checkVersion({ currentVersion: package_default.version });
|
|
136030
|
+
if (result.status === "update-available") {
|
|
136031
|
+
return {
|
|
136032
|
+
id: "version",
|
|
136033
|
+
status: "warn",
|
|
136034
|
+
detail: `keryx ${result.currentVersion} \u2192 ${result.latestVersion} is available`,
|
|
136035
|
+
fix: result.installCommand
|
|
136036
|
+
};
|
|
136037
|
+
}
|
|
136038
|
+
if (result.status === "up-to-date") {
|
|
136039
|
+
return { id: "version", status: "ok", detail: `keryx ${result.currentVersion} is up to date` };
|
|
136040
|
+
}
|
|
136041
|
+
return { id: "version", status: "ok", detail: `keryx ${result.currentVersion}; update check unavailable (${result.reason})` };
|
|
136042
|
+
}
|
|
136043
|
+
function checkSandbox() {
|
|
136044
|
+
const report = buildSandboxReport();
|
|
136045
|
+
if (report.launcher.available) {
|
|
136046
|
+
return { id: "sandbox", status: "ok", detail: `${report.launcherName ?? "sandbox launcher"} available` };
|
|
136047
|
+
}
|
|
136048
|
+
const known = report.launcherName !== undefined;
|
|
136049
|
+
return {
|
|
136050
|
+
id: "sandbox",
|
|
136051
|
+
status: "warn",
|
|
136052
|
+
detail: known ? `${report.launcherName} not installed on ${report.platform} \u2014 OS-sandboxed shell exec is unavailable` : `no OS sandbox launcher support on ${report.platform}`,
|
|
136053
|
+
fix: known ? "keryx sandbox status for what installing it would unlock" : "keryx sandbox status for details"
|
|
136054
|
+
};
|
|
136055
|
+
}
|
|
136056
|
+
function checkProviders(env) {
|
|
136057
|
+
const providers = configuredProviders(env);
|
|
136058
|
+
if (providers.length === 0) {
|
|
136059
|
+
return {
|
|
136060
|
+
id: "providers",
|
|
136061
|
+
status: "warn",
|
|
136062
|
+
detail: "no provider credentials configured",
|
|
136063
|
+
fix: "keryx auth login <provider>, or set a provider API key"
|
|
136064
|
+
};
|
|
136065
|
+
}
|
|
136066
|
+
return {
|
|
136067
|
+
id: "providers",
|
|
136068
|
+
status: "ok",
|
|
136069
|
+
detail: `${providers.length} provider(s) configured: ${providers.map((p) => p.name).join(", ")}`
|
|
136070
|
+
};
|
|
136071
|
+
}
|
|
136072
|
+
function checkMcp(cwd) {
|
|
136073
|
+
const projectRoot = resolveProjectRoot(cwd);
|
|
136074
|
+
const config = loadMcpServers({ cwd, gitRoot: projectRoot });
|
|
136075
|
+
const ownProblems = config.problems.filter((p) => !p.foreign);
|
|
136076
|
+
if (ownProblems.length > 0) {
|
|
136077
|
+
return {
|
|
136078
|
+
id: "mcp",
|
|
136079
|
+
status: "fail",
|
|
136080
|
+
detail: `${ownProblems.length} config problem(s) in keryx's own MCP config: ${ownProblems.map((p) => p.message).join("; ")}`,
|
|
136081
|
+
fix: "keryx mcp list for details"
|
|
136082
|
+
};
|
|
136083
|
+
}
|
|
136084
|
+
const approvals = loadTrustStore();
|
|
136085
|
+
const held = config.servers.filter((server) => server.enabled && requiresApproval(server, approvals));
|
|
136086
|
+
if (held.length > 0) {
|
|
136087
|
+
return {
|
|
136088
|
+
id: "mcp",
|
|
136089
|
+
status: "warn",
|
|
136090
|
+
detail: `${held.length} server(s) from committed config awaiting approval: ${held.map((s) => s.name).join(", ")}`,
|
|
136091
|
+
fix: "keryx mcp trust <name>, after reading what it launches"
|
|
136092
|
+
};
|
|
136093
|
+
}
|
|
136094
|
+
return {
|
|
136095
|
+
id: "mcp",
|
|
136096
|
+
status: "ok",
|
|
136097
|
+
detail: `${config.servers.length} server(s) configured; run \`keryx mcp doctor\` to also check connectivity`
|
|
136098
|
+
};
|
|
136099
|
+
}
|
|
136100
|
+
async function checkIntegrations(cwd) {
|
|
136101
|
+
const results = await Promise.all(harnessAdapterIds().map(async (id) => {
|
|
136102
|
+
try {
|
|
136103
|
+
return await doctorIntegration(cwd, id);
|
|
136104
|
+
} catch {
|
|
136105
|
+
return { runtimeId: id, surfaces: [], problems: [], ok: true };
|
|
136106
|
+
}
|
|
136107
|
+
}));
|
|
136108
|
+
const drifted = results.filter((r) => !r.ok);
|
|
136109
|
+
if (drifted.length === 0) {
|
|
136110
|
+
return { id: "integrations", status: "ok", detail: "no drift in any installed integration" };
|
|
136111
|
+
}
|
|
136112
|
+
return {
|
|
136113
|
+
id: "integrations",
|
|
136114
|
+
status: "warn",
|
|
136115
|
+
detail: `drift in: ${drifted.map((r) => r.runtimeId).join(", ")}`,
|
|
136116
|
+
fix: "keryx integrations doctor --runtime all"
|
|
136117
|
+
};
|
|
136118
|
+
}
|
|
136119
|
+
async function checkStandard(cwd) {
|
|
136120
|
+
const result = await runDoctor(cwd);
|
|
136121
|
+
if (result.errors.length > 0) {
|
|
136122
|
+
return {
|
|
136123
|
+
id: "standard",
|
|
136124
|
+
status: "fail",
|
|
136125
|
+
detail: `${result.errors.length} error(s): ${result.errors.map((e) => e.message).join("; ")}`,
|
|
136126
|
+
fix: "keryx standard doctor"
|
|
136127
|
+
};
|
|
136128
|
+
}
|
|
136129
|
+
if (result.warnings.length > 0) {
|
|
136130
|
+
return {
|
|
136131
|
+
id: "standard",
|
|
136132
|
+
status: "warn",
|
|
136133
|
+
detail: `${result.warnings.length} warning(s): ${result.warnings.map((w) => w.message).join("; ")}`,
|
|
136134
|
+
fix: "keryx standard doctor"
|
|
136135
|
+
};
|
|
136136
|
+
}
|
|
136137
|
+
return { id: "standard", status: "ok", detail: "workspace is Metaproject Standard compliant" };
|
|
136138
|
+
}
|
|
136139
|
+
async function checkGraphFreshness(cwd) {
|
|
136140
|
+
const result = await checkGraphStaleness(cwd);
|
|
136141
|
+
if (result.status === "fresh") {
|
|
136142
|
+
return { id: "graph-freshness", status: "ok", detail: "code graph is fresh" };
|
|
136143
|
+
}
|
|
136144
|
+
return {
|
|
136145
|
+
id: "graph-freshness",
|
|
136146
|
+
status: "warn",
|
|
136147
|
+
detail: result.reasons.join("; ") || `code graph is ${result.status}`,
|
|
136148
|
+
fix: "keryx gdgraph build"
|
|
136149
|
+
};
|
|
136150
|
+
}
|
|
136151
|
+
async function checkWikiFreshness(cwd) {
|
|
136152
|
+
const metric = await readWikiFreshnessMetric(cwd);
|
|
136153
|
+
if (metric.status === "measured") {
|
|
136154
|
+
const pct = metric.ratio !== undefined ? `${Math.round(metric.ratio * 100)}%` : "an unmeasured share";
|
|
136155
|
+
return {
|
|
136156
|
+
id: "wiki-freshness",
|
|
136157
|
+
status: "ok",
|
|
136158
|
+
detail: `${pct} of ${metric.pagesTotal ?? "?"} wiki page(s) fresh`
|
|
136159
|
+
};
|
|
136160
|
+
}
|
|
136161
|
+
return {
|
|
136162
|
+
id: "wiki-freshness",
|
|
136163
|
+
status: "warn",
|
|
136164
|
+
detail: metric.reason ?? `wiki freshness: ${metric.status}`,
|
|
136165
|
+
fix: "keryx wiki freshness"
|
|
136166
|
+
};
|
|
136167
|
+
}
|
|
136168
|
+
async function buildDoctorReport(cwd, env = process.env, overrides = {}) {
|
|
136169
|
+
const checks = await Promise.all([
|
|
136170
|
+
checkVersionAvailability(),
|
|
136171
|
+
Promise.resolve(checkBun(overrides.bunFloor)),
|
|
136172
|
+
Promise.resolve(checkRipgrep()),
|
|
136173
|
+
Promise.resolve(checkSandbox()),
|
|
136174
|
+
Promise.resolve(checkProviders(env)),
|
|
136175
|
+
Promise.resolve(checkMcp(cwd)),
|
|
136176
|
+
checkIntegrations(cwd),
|
|
136177
|
+
checkStandard(cwd),
|
|
136178
|
+
checkWorktrees(cwd),
|
|
136179
|
+
checkGraphFreshness(cwd),
|
|
136180
|
+
checkWikiFreshness(cwd)
|
|
136181
|
+
]);
|
|
136182
|
+
return { checks };
|
|
136183
|
+
}
|
|
136184
|
+
function doctorFailed(report) {
|
|
136185
|
+
return report.checks.some((check) => check.status === "fail");
|
|
136186
|
+
}
|
|
136187
|
+
function formatDoctorReport2(report) {
|
|
136188
|
+
const symbolFor = { ok: "\u2713", warn: "!", fail: "\u2717" };
|
|
136189
|
+
const lines = ["keryx doctor", ""];
|
|
136190
|
+
for (const check of report.checks) {
|
|
136191
|
+
lines.push(` ${symbolFor[check.status]} ${check.id}: ${check.detail}`);
|
|
136192
|
+
if (check.fix) {
|
|
136193
|
+
lines.push(` fix: ${check.fix}`);
|
|
136194
|
+
}
|
|
136195
|
+
}
|
|
136196
|
+
return lines.join(`
|
|
136197
|
+
`);
|
|
136198
|
+
}
|
|
136199
|
+
async function doctorCommand2(args = [], cwd = process.cwd(), overrides = {}) {
|
|
136200
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
136201
|
+
console.log(`keryx doctor [--json]
|
|
136202
|
+
|
|
136203
|
+
One page: keryx's own version and update availability, the Bun floor,
|
|
136204
|
+
ripgrep on PATH, the OS sandbox launcher, providers with a credential
|
|
136205
|
+
present (names only), MCP servers and their trust state, integrations
|
|
136206
|
+
drift, Metaproject Standard warnings, stale .claude/worktrees entries, and
|
|
136207
|
+
graph/wiki freshness. Exits 0 unless something is a "fail".`);
|
|
136208
|
+
return;
|
|
136209
|
+
}
|
|
136210
|
+
const report = await buildDoctorReport(cwd, process.env, overrides);
|
|
136211
|
+
if (args.includes("--json")) {
|
|
136212
|
+
console.log(JSON.stringify(report, null, 2));
|
|
136213
|
+
} else {
|
|
136214
|
+
console.log(formatDoctorReport2(report));
|
|
136215
|
+
}
|
|
136216
|
+
if (doctorFailed(report)) {
|
|
136217
|
+
process.exitCode = 1;
|
|
136218
|
+
}
|
|
136219
|
+
}
|
|
136220
|
+
|
|
135482
136221
|
// src/tui/tui-shell.ts
|
|
135483
136222
|
init_slate_lifecycle();
|
|
135484
136223
|
init_slate();
|
|
@@ -135491,7 +136230,7 @@ init_workspace_service();
|
|
|
135491
136230
|
init_service11();
|
|
135492
136231
|
init_store3();
|
|
135493
136232
|
init_fs();
|
|
135494
|
-
import
|
|
136233
|
+
import path303 from "path";
|
|
135495
136234
|
import { readFile as readFile157 } from "fs/promises";
|
|
135496
136235
|
var POSITIVE_INTEGER = /^[1-9][0-9]*$/;
|
|
135497
136236
|
var DEFAULT_AUTO_GOAL_ROUNDS = 8;
|
|
@@ -135567,7 +136306,7 @@ function getFlowService() {
|
|
|
135567
136306
|
async function autoProvisionFlow(cwd, goalText) {
|
|
135568
136307
|
const service = getFlowService();
|
|
135569
136308
|
const result = await service.init({ cwd, title: goalText });
|
|
135570
|
-
const acFile =
|
|
136309
|
+
const acFile = path303.join(cwd, result.dir, "acceptance-criteria.md");
|
|
135571
136310
|
await writeFileAtomic(acFile, [
|
|
135572
136311
|
"# Acceptance Criteria",
|
|
135573
136312
|
"",
|
|
@@ -137255,8 +137994,8 @@ init_store4();
|
|
|
137255
137994
|
init_proposal_lifecycle();
|
|
137256
137995
|
init_workspace_service();
|
|
137257
137996
|
import { randomUUID as randomUUID34 } from "crypto";
|
|
137258
|
-
import { readdir as
|
|
137259
|
-
import
|
|
137997
|
+
import { readdir as readdir54, stat as stat30 } from "fs/promises";
|
|
137998
|
+
import path304 from "path";
|
|
137260
137999
|
|
|
137261
138000
|
// src/sac/lifecycle-flag.ts
|
|
137262
138001
|
init_store();
|
|
@@ -137395,7 +138134,7 @@ async function readExternalUnboundCandidates(cwd) {
|
|
|
137395
138134
|
const extDir = externalSlatesDir(cwd);
|
|
137396
138135
|
let externalIds;
|
|
137397
138136
|
try {
|
|
137398
|
-
const entries = await
|
|
138137
|
+
const entries = await readdir54(extDir);
|
|
137399
138138
|
externalIds = entries.filter((name) => name.endsWith(".json")).map((name) => name.slice(0, -".json".length));
|
|
137400
138139
|
} catch {
|
|
137401
138140
|
return [];
|
|
@@ -137426,7 +138165,7 @@ async function readExternalUnboundCandidates(cwd) {
|
|
|
137426
138165
|
}
|
|
137427
138166
|
return groups;
|
|
137428
138167
|
}, []));
|
|
137429
|
-
const metaPath =
|
|
138168
|
+
const metaPath = path304.join(extDir, `${id}.json`);
|
|
137430
138169
|
if (await pathExists(unboundDismissedReceiptPath(metaPath)))
|
|
137431
138170
|
continue;
|
|
137432
138171
|
candidates.push({
|
|
@@ -137440,16 +138179,16 @@ async function readExternalUnboundCandidates(cwd) {
|
|
|
137440
138179
|
return candidates;
|
|
137441
138180
|
}
|
|
137442
138181
|
async function readNewestUnboundCandidateForExternal(cwd, externalSessionId) {
|
|
137443
|
-
const evidenceDir =
|
|
138182
|
+
const evidenceDir = path304.join(externalSlatesDir(cwd), externalSessionId);
|
|
137444
138183
|
let entries;
|
|
137445
138184
|
try {
|
|
137446
|
-
entries = (await
|
|
138185
|
+
entries = (await readdir54(evidenceDir)).filter((name) => name.endsWith("-unbound-candidate.json"));
|
|
137447
138186
|
} catch {
|
|
137448
138187
|
return;
|
|
137449
138188
|
}
|
|
137450
138189
|
entries.sort();
|
|
137451
138190
|
for (let i = entries.length - 1;i >= 0; i--) {
|
|
137452
|
-
const evidencePath =
|
|
138191
|
+
const evidencePath = path304.join(evidenceDir, entries[i]);
|
|
137453
138192
|
if (await pathExists(unboundDismissedReceiptPath(evidencePath)))
|
|
137454
138193
|
continue;
|
|
137455
138194
|
const result = readConfigFile(evidencePath);
|
|
@@ -137492,23 +138231,23 @@ var SESSION_ATTRIBUTION_SLACK_MS = 5 * 60000;
|
|
|
137492
138231
|
var MTIME_CLOCK_SKEW_TOLERANCE_MS = 5000;
|
|
137493
138232
|
async function collectReceiptTargets(cwd, owner) {
|
|
137494
138233
|
const targets = new Set;
|
|
137495
|
-
const workspacesDir =
|
|
138234
|
+
const workspacesDir = path304.join(cwd, ".metaproject", "workspaces");
|
|
137496
138235
|
let workspaceIds;
|
|
137497
138236
|
try {
|
|
137498
|
-
workspaceIds = (await
|
|
138237
|
+
workspaceIds = (await readdir54(workspacesDir, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
|
|
137499
138238
|
} catch {
|
|
137500
138239
|
return targets;
|
|
137501
138240
|
}
|
|
137502
138241
|
for (const workspaceId of workspaceIds) {
|
|
137503
|
-
const receiptsDir =
|
|
138242
|
+
const receiptsDir = path304.join(workspacesDir, workspaceId, `${owner}-write-receipts`);
|
|
137504
138243
|
let files;
|
|
137505
138244
|
try {
|
|
137506
|
-
files = (await
|
|
138245
|
+
files = (await readdir54(receiptsDir)).filter((name) => name.endsWith(".json"));
|
|
137507
138246
|
} catch {
|
|
137508
138247
|
continue;
|
|
137509
138248
|
}
|
|
137510
138249
|
for (const file of files) {
|
|
137511
|
-
const result = readConfigFile(
|
|
138250
|
+
const result = readConfigFile(path304.join(receiptsDir, file));
|
|
137512
138251
|
if (!result.ok)
|
|
137513
138252
|
continue;
|
|
137514
138253
|
try {
|
|
@@ -137545,13 +138284,13 @@ async function attributeToSession(absolutePath, sessionsNewestFirst) {
|
|
|
137545
138284
|
async function findSkillFiles(dir) {
|
|
137546
138285
|
let entries;
|
|
137547
138286
|
try {
|
|
137548
|
-
entries = await
|
|
138287
|
+
entries = await readdir54(dir, { withFileTypes: true });
|
|
137549
138288
|
} catch {
|
|
137550
138289
|
return [];
|
|
137551
138290
|
}
|
|
137552
138291
|
const found = [];
|
|
137553
138292
|
for (const entry of entries) {
|
|
137554
|
-
const full =
|
|
138293
|
+
const full = path304.join(dir, entry.name);
|
|
137555
138294
|
if (entry.isDirectory()) {
|
|
137556
138295
|
found.push(...await findSkillFiles(full));
|
|
137557
138296
|
} else if (entry.isFile() && entry.name === "SKILL.md") {
|
|
@@ -137610,10 +138349,10 @@ async function detectUnreviewedSacPathChanges(cwd, sessions) {
|
|
|
137610
138349
|
changedAt: attribution.changedAt
|
|
137611
138350
|
});
|
|
137612
138351
|
}
|
|
137613
|
-
const sacSkillsDir =
|
|
138352
|
+
const sacSkillsDir = path304.join(cwd, ".metaproject", "project-skills", "sac");
|
|
137614
138353
|
const skillFiles = await findSkillFiles(sacSkillsDir);
|
|
137615
138354
|
for (const absolutePath of skillFiles) {
|
|
137616
|
-
const targetRef =
|
|
138355
|
+
const targetRef = path304.relative(path304.join(cwd, ".metaproject"), absolutePath).split(path304.sep).join("/");
|
|
137617
138356
|
if (skillReceipts.has(targetRef))
|
|
137618
138357
|
continue;
|
|
137619
138358
|
const attribution = await attributeToSession(absolutePath, scoped);
|
|
@@ -137631,12 +138370,12 @@ async function detectUnreviewedSacPathChanges(cwd, sessions) {
|
|
|
137631
138370
|
return items;
|
|
137632
138371
|
}
|
|
137633
138372
|
async function isSlateEngaged(dir) {
|
|
137634
|
-
if (await pathExists(
|
|
138373
|
+
if (await pathExists(path304.join(dir, "slate.json")))
|
|
137635
138374
|
return true;
|
|
137636
|
-
if (await pathExists(
|
|
138375
|
+
if (await pathExists(path304.join(dir, "terminal-state.json")))
|
|
137637
138376
|
return true;
|
|
137638
138377
|
try {
|
|
137639
|
-
const entries = await
|
|
138378
|
+
const entries = await readdir54(path304.join(dir, "slate-archive"));
|
|
137640
138379
|
return entries.length > 0;
|
|
137641
138380
|
} catch {
|
|
137642
138381
|
return false;
|
|
@@ -137661,7 +138400,7 @@ async function safeReadSlate(dir) {
|
|
|
137661
138400
|
}
|
|
137662
138401
|
}
|
|
137663
138402
|
async function readTerminalState(dir) {
|
|
137664
|
-
const result = readConfigFile(
|
|
138403
|
+
const result = readConfigFile(path304.join(dir, "terminal-state.json"));
|
|
137665
138404
|
if (!result.ok) {
|
|
137666
138405
|
return;
|
|
137667
138406
|
}
|
|
@@ -137685,17 +138424,17 @@ async function resolveUnboundCandidateTarget(cwd, target) {
|
|
|
137685
138424
|
if (session === undefined) {
|
|
137686
138425
|
throw new Error(`No session or evidence path matches "${target}"`);
|
|
137687
138426
|
}
|
|
137688
|
-
const archiveDir =
|
|
138427
|
+
const archiveDir = path304.join(sessionDir(session.projectPath, session.id), "slate-archive");
|
|
137689
138428
|
let entries;
|
|
137690
138429
|
try {
|
|
137691
|
-
entries = (await
|
|
138430
|
+
entries = (await readdir54(archiveDir)).filter((name) => name.endsWith("-unbound-candidate.json"));
|
|
137692
138431
|
} catch {
|
|
137693
138432
|
throw new Error(`No unbound-candidate artifacts for session ${session.id}`);
|
|
137694
138433
|
}
|
|
137695
138434
|
if (entries.length === 0)
|
|
137696
138435
|
throw new Error(`No unbound-candidate artifacts for session ${session.id}`);
|
|
137697
138436
|
entries.sort();
|
|
137698
|
-
return
|
|
138437
|
+
return path304.join(archiveDir, entries[entries.length - 1]);
|
|
137699
138438
|
}
|
|
137700
138439
|
async function dismissUnboundByTarget(cwd, target, reason) {
|
|
137701
138440
|
const evidencePath = await resolveUnboundCandidateTarget(cwd, target);
|
|
@@ -137721,16 +138460,16 @@ async function dismissUnboundCandidate(candidatePath, reason) {
|
|
|
137721
138460
|
return { removed: candidatePath, receipt: receiptPath };
|
|
137722
138461
|
}
|
|
137723
138462
|
async function readNewestUnboundCandidate(dir) {
|
|
137724
|
-
const archiveDir =
|
|
138463
|
+
const archiveDir = path304.join(dir, "slate-archive");
|
|
137725
138464
|
let entries;
|
|
137726
138465
|
try {
|
|
137727
|
-
entries = (await
|
|
138466
|
+
entries = (await readdir54(archiveDir)).filter((name) => name.endsWith("-unbound-candidate.json"));
|
|
137728
138467
|
} catch {
|
|
137729
138468
|
return;
|
|
137730
138469
|
}
|
|
137731
138470
|
entries.sort();
|
|
137732
138471
|
for (let i = entries.length - 1;i >= 0; i--) {
|
|
137733
|
-
const evidencePath =
|
|
138472
|
+
const evidencePath = path304.join(archiveDir, entries[i]);
|
|
137734
138473
|
if (await pathExists(unboundDismissedReceiptPath(evidencePath)))
|
|
137735
138474
|
continue;
|
|
137736
138475
|
const result = readConfigFile(evidencePath);
|
|
@@ -137760,16 +138499,16 @@ function isFailureOutcome2(g) {
|
|
|
137760
138499
|
return g.outcome === "error" || g.outcome === "no_credential" || g.outcome === "conflict";
|
|
137761
138500
|
}
|
|
137762
138501
|
async function readNewestWrapUpOutcome(dir) {
|
|
137763
|
-
const archiveDir =
|
|
138502
|
+
const archiveDir = path304.join(dir, "slate-archive");
|
|
137764
138503
|
let entries;
|
|
137765
138504
|
try {
|
|
137766
|
-
entries = (await
|
|
138505
|
+
entries = (await readdir54(archiveDir)).filter((name) => name.endsWith("-wrap-up-outcome.json"));
|
|
137767
138506
|
} catch {
|
|
137768
138507
|
return;
|
|
137769
138508
|
}
|
|
137770
138509
|
entries.sort();
|
|
137771
138510
|
for (let i = entries.length - 1;i >= 0; i--) {
|
|
137772
|
-
const evidencePath =
|
|
138511
|
+
const evidencePath = path304.join(archiveDir, entries[i]);
|
|
137773
138512
|
const result = readConfigFile(evidencePath);
|
|
137774
138513
|
if (!result.ok) {
|
|
137775
138514
|
continue;
|
|
@@ -138376,6 +139115,11 @@ var AGENT_SLASH_COMMANDS = [
|
|
|
138376
139115
|
modes: BOTH
|
|
138377
139116
|
},
|
|
138378
139117
|
{ name: "/flows", description: "Browse project flows and inspect one", modes: BOTH },
|
|
139118
|
+
{
|
|
139119
|
+
name: "/doctor",
|
|
139120
|
+
description: "One-page health check: version, sandbox, providers, MCP, integrations, freshness",
|
|
139121
|
+
modes: BOTH
|
|
139122
|
+
},
|
|
138379
139123
|
{
|
|
138380
139124
|
name: "/ac",
|
|
138381
139125
|
description: "Check the active flow's acceptance criteria (advisory, cached) \u2014 press `c` in /flows to re-check",
|
|
@@ -138718,7 +139462,7 @@ function classifyBusyDispatch(params) {
|
|
|
138718
139462
|
init_fs();
|
|
138719
139463
|
init_json();
|
|
138720
139464
|
import { mkdir as mkdir67 } from "fs/promises";
|
|
138721
|
-
import
|
|
139465
|
+
import path306 from "path";
|
|
138722
139466
|
|
|
138723
139467
|
// src/governance/aggregate.ts
|
|
138724
139468
|
init_store3();
|
|
@@ -138726,17 +139470,17 @@ init_store3();
|
|
|
138726
139470
|
// src/governance/spend.ts
|
|
138727
139471
|
init_fs();
|
|
138728
139472
|
init_store3();
|
|
138729
|
-
import { readdir as
|
|
138730
|
-
import
|
|
139473
|
+
import { readdir as readdir55, readFile as readFile158 } from "fs/promises";
|
|
139474
|
+
import path305 from "path";
|
|
138731
139475
|
async function readFlowReviewManifests(cwd, flowDir) {
|
|
138732
|
-
const reviewsDir =
|
|
139476
|
+
const reviewsDir = path305.join(flowsRoot(cwd), flowDir, "reviews");
|
|
138733
139477
|
if (!await pathExists(reviewsDir)) {
|
|
138734
139478
|
return [];
|
|
138735
139479
|
}
|
|
138736
|
-
const entries = (await
|
|
139480
|
+
const entries = (await readdir55(reviewsDir, { withFileTypes: true })).filter((entry) => entry.isDirectory());
|
|
138737
139481
|
const manifests = [];
|
|
138738
139482
|
for (const entry of entries) {
|
|
138739
|
-
const manifestPath =
|
|
139483
|
+
const manifestPath = path305.join(reviewsDir, entry.name, "manifest.json");
|
|
138740
139484
|
if (!await pathExists(manifestPath)) {
|
|
138741
139485
|
continue;
|
|
138742
139486
|
}
|
|
@@ -138983,11 +139727,11 @@ async function collectProjectGovernance(root, filters, displayName) {
|
|
|
138983
139727
|
// src/governance/report.ts
|
|
138984
139728
|
var GOVERNANCE_SCHEMA_VERSION = 1;
|
|
138985
139729
|
function governanceDataRoot(cwd) {
|
|
138986
|
-
return
|
|
139730
|
+
return path306.join(cwd, ".metaproject", "data", "governance");
|
|
138987
139731
|
}
|
|
138988
139732
|
function artifactPaths(cwd) {
|
|
138989
|
-
const artifacts =
|
|
138990
|
-
return { markdown:
|
|
139733
|
+
const artifacts = path306.join(governanceDataRoot(cwd), "artifacts");
|
|
139734
|
+
return { markdown: path306.join(artifacts, "latest.md"), json: path306.join(artifacts, "latest.json") };
|
|
138991
139735
|
}
|
|
138992
139736
|
async function buildGovernanceReport(options) {
|
|
138993
139737
|
const { cwd, filters, allProjects, now } = options;
|
|
@@ -138995,9 +139739,9 @@ async function buildGovernanceReport(options) {
|
|
|
138995
139739
|
if (allProjects) {
|
|
138996
139740
|
const warnings = [];
|
|
138997
139741
|
const registered = listProjects(options.registryDir, (message) => warnings.push(message));
|
|
138998
|
-
const seen = new Set([
|
|
139742
|
+
const seen = new Set([path306.resolve(cwd)]);
|
|
138999
139743
|
for (const entry of registered) {
|
|
139000
|
-
const resolved =
|
|
139744
|
+
const resolved = path306.resolve(entry.path);
|
|
139001
139745
|
if (seen.has(resolved)) {
|
|
139002
139746
|
continue;
|
|
139003
139747
|
}
|
|
@@ -139150,7 +139894,7 @@ function renderTriggerSpendLine(spend) {
|
|
|
139150
139894
|
}
|
|
139151
139895
|
async function writeGovernanceArtifacts(cwd, report) {
|
|
139152
139896
|
const { markdown, json } = artifactPaths(cwd);
|
|
139153
|
-
await mkdir67(
|
|
139897
|
+
await mkdir67(path306.dirname(markdown), { recursive: true });
|
|
139154
139898
|
await writeFileAtomic(markdown, renderGovernanceMarkdown(report));
|
|
139155
139899
|
await writeFileAtomic(json, `${JSON.stringify(report, null, 2)}
|
|
139156
139900
|
`);
|
|
@@ -139355,7 +140099,7 @@ function mountGovernancePanel(otui, renderer, parent, options) {
|
|
|
139355
140099
|
|
|
139356
140100
|
// src/tui/governance-inspector.ts
|
|
139357
140101
|
import { readFile as readFile159 } from "fs/promises";
|
|
139358
|
-
import
|
|
140102
|
+
import path307 from "path";
|
|
139359
140103
|
var GOVERNANCE_COMMAND = "/governance";
|
|
139360
140104
|
var GOVERNANCE_FOOTER = [
|
|
139361
140105
|
{ key: "\u2191/\u2193 j/k", label: "scroll" },
|
|
@@ -139366,7 +140110,7 @@ var GOVERNANCE_FOOTER = [
|
|
|
139366
140110
|
var HEADER_TEXT_ROWS = 2;
|
|
139367
140111
|
var GOVERNANCE_HEADER_ROWS = HEADER_TEXT_ROWS + 1;
|
|
139368
140112
|
function governanceMarkdownPath(cwd) {
|
|
139369
|
-
return
|
|
140113
|
+
return path307.join(governanceDataRoot(cwd), "artifacts", "latest.md");
|
|
139370
140114
|
}
|
|
139371
140115
|
async function defaultReadMarkdown(cwd) {
|
|
139372
140116
|
try {
|
|
@@ -139511,7 +140255,7 @@ function openGovernanceReport(otui, chrome, options) {
|
|
|
139511
140255
|
|
|
139512
140256
|
// src/tui/trigger-ledger.ts
|
|
139513
140257
|
import { stat as fsStat2 } from "fs/promises";
|
|
139514
|
-
import
|
|
140258
|
+
import path308 from "path";
|
|
139515
140259
|
var DEFAULT_RECORDS_PER_ENTRY = 20;
|
|
139516
140260
|
function isScheduledEntry(entry) {
|
|
139517
140261
|
return entry.fire.kind === "schedule";
|
|
@@ -139570,7 +140314,7 @@ function triggerLedgerPaths(root) {
|
|
|
139570
140314
|
return {
|
|
139571
140315
|
runs: triggerRunsPath(root),
|
|
139572
140316
|
triggers: triggersConfigPath(root),
|
|
139573
|
-
governance:
|
|
140317
|
+
governance: path308.join(governanceDataRoot(root), "artifacts", "latest.json"),
|
|
139574
140318
|
schedules: scheduleStorePath(root)
|
|
139575
140319
|
};
|
|
139576
140320
|
}
|
|
@@ -140143,7 +140887,7 @@ function openTriggers(otui, chrome, options) {
|
|
|
140143
140887
|
// src/tui/trigger-run-now.ts
|
|
140144
140888
|
import { spawn as nodeSpawn2 } from "child_process";
|
|
140145
140889
|
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";
|
|
140146
|
-
import
|
|
140890
|
+
import path309 from "path";
|
|
140147
140891
|
var OUTPUT_TAIL_CHARS = 4000;
|
|
140148
140892
|
var defaultSpawn = (command, args, options) => nodeSpawn2(command, [...args], { cwd: options.cwd, env: options.env, detached: true, stdio: [...options.stdio] });
|
|
140149
140893
|
function triggerRunArgv(name, invocation = resolveKeryxInvocation(), options = {}) {
|
|
@@ -140158,7 +140902,7 @@ function runNowChildEnv(env) {
|
|
|
140158
140902
|
return out;
|
|
140159
140903
|
}
|
|
140160
140904
|
function runNowLogDir(root) {
|
|
140161
|
-
return
|
|
140905
|
+
return path309.join(triggerDataDir(root), "run-now");
|
|
140162
140906
|
}
|
|
140163
140907
|
var RUN_NOW_LOGS_KEPT = 5;
|
|
140164
140908
|
var OUTPUT_TAIL_BYTES = 16 * 1024;
|
|
@@ -140166,13 +140910,13 @@ function stampOf(iso) {
|
|
|
140166
140910
|
return iso.replace(/[:.]/g, "-");
|
|
140167
140911
|
}
|
|
140168
140912
|
function runNowLogPath(root, name, startedAt) {
|
|
140169
|
-
return
|
|
140913
|
+
return path309.join(runNowLogDir(root), `${name}-${stampOf(startedAt)}.log`);
|
|
140170
140914
|
}
|
|
140171
140915
|
function isCode(error, code) {
|
|
140172
140916
|
return typeof error === "object" && error !== null && "code" in error && error.code === code;
|
|
140173
140917
|
}
|
|
140174
140918
|
function prepareRunNowLogDir(root) {
|
|
140175
|
-
mkdirSync7(
|
|
140919
|
+
mkdirSync7(path309.join(root, ".metaproject", "data"), { recursive: true });
|
|
140176
140920
|
for (const segment of [triggerDataDir(root), runNowLogDir(root)]) {
|
|
140177
140921
|
let info;
|
|
140178
140922
|
try {
|
|
@@ -140191,7 +140935,7 @@ function prepareRunNowLogDir(root) {
|
|
|
140191
140935
|
}
|
|
140192
140936
|
const dir = runNowLogDir(root);
|
|
140193
140937
|
try {
|
|
140194
|
-
const fd = openSync5(
|
|
140938
|
+
const fd = openSync5(path309.join(dir, ".gitignore"), constants3.O_WRONLY | constants3.O_CREAT | constants3.O_EXCL | (constants3.O_NOFOLLOW ?? 0), 420);
|
|
140195
140939
|
try {
|
|
140196
140940
|
writeSync(fd, `# keryx run-now logs \u2014 never commit
|
|
140197
140941
|
*
|
|
@@ -140232,7 +140976,7 @@ function pruneRunLogs(dir, name, keep) {
|
|
|
140232
140976
|
}
|
|
140233
140977
|
for (const old of names.slice(0, Math.max(0, names.length - keep))) {
|
|
140234
140978
|
try {
|
|
140235
|
-
unlinkSync4(
|
|
140979
|
+
unlinkSync4(path309.join(dir, old));
|
|
140236
140980
|
} catch {}
|
|
140237
140981
|
}
|
|
140238
140982
|
}
|
|
@@ -141250,279 +141994,6 @@ function mountSchedulesSidebar(options) {
|
|
|
141250
141994
|
// src/tui/tui-shell.ts
|
|
141251
141995
|
init_debug_log();
|
|
141252
141996
|
|
|
141253
|
-
// src/lib/version-check.ts
|
|
141254
|
-
init_config_dir();
|
|
141255
|
-
init_fs();
|
|
141256
|
-
import path308 from "path";
|
|
141257
|
-
var REGISTRY_URL = "https://registry.npmjs.org/@mrciphersmith%2Fkeryx/latest";
|
|
141258
|
-
var FIXED_INSTALL_COMMAND = "npm install -g @mrciphersmith/keryx@latest";
|
|
141259
|
-
var RESPONSE_BODY_LIMIT_BYTES = 64 * 1024;
|
|
141260
|
-
var VERSION_STRING_LIMIT_CHARS = 64;
|
|
141261
|
-
var REQUEST_TIMEOUT_MS = 2000;
|
|
141262
|
-
var SUCCESS_CACHE_TTL_MS = 24 * 60 * 60 * 1000;
|
|
141263
|
-
var FAILURE_BACKOFF_MS = 15 * 60 * 1000;
|
|
141264
|
-
var CACHE_LOCK_TIMEOUT_MS2 = 250;
|
|
141265
|
-
var CACHE_LOCK_RETRY_MS2 = 10;
|
|
141266
|
-
var CACHE_LOCK_STALE_MS2 = 5000;
|
|
141267
|
-
var SYSTEM_TIMER = {
|
|
141268
|
-
schedule: (callback, delayMs) => setTimeout(callback, delayMs),
|
|
141269
|
-
cancel: (handle) => clearTimeout(handle)
|
|
141270
|
-
};
|
|
141271
|
-
function formatVersionUpdateAdvisory(result) {
|
|
141272
|
-
if (result.status !== "update-available")
|
|
141273
|
-
return;
|
|
141274
|
-
return `Keryx update ${result.currentVersion} \u2192 ${result.latestVersion}
|
|
141275
|
-
${result.installCommand}`;
|
|
141276
|
-
}
|
|
141277
|
-
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-]+)*))?$/;
|
|
141278
|
-
function parseSemVer(value) {
|
|
141279
|
-
if (value.length > VERSION_STRING_LIMIT_CHARS)
|
|
141280
|
-
return;
|
|
141281
|
-
const match = STRICT_SEMVER.exec(value);
|
|
141282
|
-
if (match === null)
|
|
141283
|
-
return;
|
|
141284
|
-
const prereleaseText = match[4];
|
|
141285
|
-
const prerelease = [];
|
|
141286
|
-
if (prereleaseText !== undefined) {
|
|
141287
|
-
for (const identifier of prereleaseText.split(".")) {
|
|
141288
|
-
if (/^\d+$/.test(identifier)) {
|
|
141289
|
-
if (identifier.length > 1 && identifier.startsWith("0"))
|
|
141290
|
-
return;
|
|
141291
|
-
prerelease.push(BigInt(identifier));
|
|
141292
|
-
} else {
|
|
141293
|
-
prerelease.push(identifier);
|
|
141294
|
-
}
|
|
141295
|
-
}
|
|
141296
|
-
}
|
|
141297
|
-
return {
|
|
141298
|
-
major: BigInt(match[1]),
|
|
141299
|
-
minor: BigInt(match[2]),
|
|
141300
|
-
patch: BigInt(match[3]),
|
|
141301
|
-
prerelease
|
|
141302
|
-
};
|
|
141303
|
-
}
|
|
141304
|
-
function compareSemVer(left, right) {
|
|
141305
|
-
for (const key of ["major", "minor", "patch"]) {
|
|
141306
|
-
if (left[key] < right[key])
|
|
141307
|
-
return -1;
|
|
141308
|
-
if (left[key] > right[key])
|
|
141309
|
-
return 1;
|
|
141310
|
-
}
|
|
141311
|
-
if (left.prerelease.length === 0 || right.prerelease.length === 0) {
|
|
141312
|
-
if (left.prerelease.length === right.prerelease.length)
|
|
141313
|
-
return 0;
|
|
141314
|
-
return left.prerelease.length === 0 ? 1 : -1;
|
|
141315
|
-
}
|
|
141316
|
-
const length = Math.max(left.prerelease.length, right.prerelease.length);
|
|
141317
|
-
for (let index = 0;index < length; index += 1) {
|
|
141318
|
-
const a = left.prerelease[index];
|
|
141319
|
-
const b = right.prerelease[index];
|
|
141320
|
-
if (a === undefined || b === undefined) {
|
|
141321
|
-
if (a === b)
|
|
141322
|
-
return 0;
|
|
141323
|
-
return a === undefined ? -1 : 1;
|
|
141324
|
-
}
|
|
141325
|
-
if (typeof a === "bigint" && typeof b === "bigint") {
|
|
141326
|
-
if (a < b)
|
|
141327
|
-
return -1;
|
|
141328
|
-
if (a > b)
|
|
141329
|
-
return 1;
|
|
141330
|
-
} else if (typeof a === "bigint") {
|
|
141331
|
-
return -1;
|
|
141332
|
-
} else if (typeof b === "bigint") {
|
|
141333
|
-
return 1;
|
|
141334
|
-
} else if (a !== b) {
|
|
141335
|
-
return a < b ? -1 : 1;
|
|
141336
|
-
}
|
|
141337
|
-
}
|
|
141338
|
-
return 0;
|
|
141339
|
-
}
|
|
141340
|
-
function parseCache(file) {
|
|
141341
|
-
const read = readConfigFile(file);
|
|
141342
|
-
if (!read.ok)
|
|
141343
|
-
return;
|
|
141344
|
-
try {
|
|
141345
|
-
const value = JSON.parse(read.text);
|
|
141346
|
-
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
141347
|
-
return;
|
|
141348
|
-
const record = value;
|
|
141349
|
-
const cache = {};
|
|
141350
|
-
if (typeof record.latestVersion === "string" && parseSemVer(record.latestVersion) !== undefined) {
|
|
141351
|
-
cache.latestVersion = record.latestVersion;
|
|
141352
|
-
}
|
|
141353
|
-
if (typeof record.successAt === "number" && Number.isFinite(record.successAt))
|
|
141354
|
-
cache.successAt = record.successAt;
|
|
141355
|
-
if (typeof record.failureAt === "number" && Number.isFinite(record.failureAt))
|
|
141356
|
-
cache.failureAt = record.failureAt;
|
|
141357
|
-
return cache;
|
|
141358
|
-
} catch {
|
|
141359
|
-
return;
|
|
141360
|
-
}
|
|
141361
|
-
}
|
|
141362
|
-
function resultFor(currentVersion, current, latestVersion, source) {
|
|
141363
|
-
const latest = parseSemVer(latestVersion);
|
|
141364
|
-
return compareSemVer(current, latest) < 0 ? { status: "update-available", currentVersion, latestVersion, installCommand: FIXED_INSTALL_COMMAND, source } : { status: "up-to-date", currentVersion, latestVersion, source };
|
|
141365
|
-
}
|
|
141366
|
-
function cancelWithoutWaiting(cancel) {
|
|
141367
|
-
try {
|
|
141368
|
-
cancel().catch(() => {});
|
|
141369
|
-
} catch {}
|
|
141370
|
-
}
|
|
141371
|
-
async function boundedResponseText(response) {
|
|
141372
|
-
const declared = response.headers.get("content-length");
|
|
141373
|
-
if (declared !== null && /^\d+$/.test(declared) && BigInt(declared) > BigInt(RESPONSE_BODY_LIMIT_BYTES)) {
|
|
141374
|
-
if (response.body !== null) {
|
|
141375
|
-
cancelWithoutWaiting(() => response.body.cancel());
|
|
141376
|
-
}
|
|
141377
|
-
return;
|
|
141378
|
-
}
|
|
141379
|
-
if (response.body === null)
|
|
141380
|
-
return "";
|
|
141381
|
-
const reader = response.body.getReader();
|
|
141382
|
-
const decoder = new TextDecoder;
|
|
141383
|
-
let size = 0;
|
|
141384
|
-
let text = "";
|
|
141385
|
-
try {
|
|
141386
|
-
for (;; ) {
|
|
141387
|
-
const chunk = await reader.read();
|
|
141388
|
-
if (chunk.done)
|
|
141389
|
-
break;
|
|
141390
|
-
size += chunk.value.byteLength;
|
|
141391
|
-
if (size > RESPONSE_BODY_LIMIT_BYTES) {
|
|
141392
|
-
cancelWithoutWaiting(() => reader.cancel());
|
|
141393
|
-
return;
|
|
141394
|
-
}
|
|
141395
|
-
text += decoder.decode(chunk.value, { stream: true });
|
|
141396
|
-
}
|
|
141397
|
-
return text + decoder.decode();
|
|
141398
|
-
} finally {
|
|
141399
|
-
reader.releaseLock();
|
|
141400
|
-
}
|
|
141401
|
-
}
|
|
141402
|
-
function unavailable(currentVersion, reason, cache) {
|
|
141403
|
-
return {
|
|
141404
|
-
status: "unavailable",
|
|
141405
|
-
currentVersion,
|
|
141406
|
-
reason,
|
|
141407
|
-
...cache?.latestVersion !== undefined ? { cachedLatestVersion: cache.latestVersion } : {}
|
|
141408
|
-
};
|
|
141409
|
-
}
|
|
141410
|
-
function saveCache2(file, cache) {
|
|
141411
|
-
try {
|
|
141412
|
-
writeOwnerOnlyFileAtomic(file, `${JSON.stringify(cache, null, 2)}
|
|
141413
|
-
`);
|
|
141414
|
-
return true;
|
|
141415
|
-
} catch {
|
|
141416
|
-
return false;
|
|
141417
|
-
}
|
|
141418
|
-
}
|
|
141419
|
-
function mergeSuccessfulCache(committed, latestVersion, successAt) {
|
|
141420
|
-
if (committed.latestVersion === undefined || committed.successAt === undefined) {
|
|
141421
|
-
return { latestVersion, successAt };
|
|
141422
|
-
}
|
|
141423
|
-
if (committed.successAt > successAt)
|
|
141424
|
-
return committed;
|
|
141425
|
-
if (committed.successAt < successAt)
|
|
141426
|
-
return { latestVersion, successAt };
|
|
141427
|
-
const committedVersion = parseSemVer(committed.latestVersion);
|
|
141428
|
-
const candidateVersion = parseSemVer(latestVersion);
|
|
141429
|
-
if (committedVersion !== undefined && candidateVersion !== undefined) {
|
|
141430
|
-
const precedence = compareSemVer(committedVersion, candidateVersion);
|
|
141431
|
-
if (precedence > 0)
|
|
141432
|
-
return committed;
|
|
141433
|
-
if (precedence < 0)
|
|
141434
|
-
return { latestVersion, successAt };
|
|
141435
|
-
if (committed.latestVersion >= latestVersion)
|
|
141436
|
-
return committed;
|
|
141437
|
-
}
|
|
141438
|
-
return { latestVersion, successAt };
|
|
141439
|
-
}
|
|
141440
|
-
async function updateCache(file, update) {
|
|
141441
|
-
try {
|
|
141442
|
-
return await withFileLock(`${file}.lock`, async () => saveCache2(file, update(parseCache(file) ?? {})), {
|
|
141443
|
-
timeoutMs: CACHE_LOCK_TIMEOUT_MS2,
|
|
141444
|
-
retryMs: CACHE_LOCK_RETRY_MS2,
|
|
141445
|
-
staleMs: CACHE_LOCK_STALE_MS2
|
|
141446
|
-
});
|
|
141447
|
-
} catch {
|
|
141448
|
-
return false;
|
|
141449
|
-
}
|
|
141450
|
-
}
|
|
141451
|
-
async function checkVersion(options) {
|
|
141452
|
-
const current = parseSemVer(options.currentVersion);
|
|
141453
|
-
if (current === undefined)
|
|
141454
|
-
return unavailable(options.currentVersion, "invalid-current-version");
|
|
141455
|
-
const now = options.now ?? Date.now;
|
|
141456
|
-
const timestamp = now();
|
|
141457
|
-
const configDir = ensureKeryxConfigDir(options.cacheDir);
|
|
141458
|
-
const cacheFile = path308.join(configDir, "version-check.json");
|
|
141459
|
-
const cache = parseCache(cacheFile);
|
|
141460
|
-
if (cache?.latestVersion !== undefined && cache.successAt !== undefined && timestamp - cache.successAt >= 0 && timestamp - cache.successAt < SUCCESS_CACHE_TTL_MS) {
|
|
141461
|
-
return resultFor(options.currentVersion, current, cache.latestVersion, "cache");
|
|
141462
|
-
}
|
|
141463
|
-
if (cache?.failureAt !== undefined && timestamp - cache.failureAt >= 0 && timestamp - cache.failureAt < FAILURE_BACKOFF_MS) {
|
|
141464
|
-
return unavailable(options.currentVersion, "suppressed", cache);
|
|
141465
|
-
}
|
|
141466
|
-
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
141467
|
-
const controller = new AbortController;
|
|
141468
|
-
const timer = options.timer ?? SYSTEM_TIMER;
|
|
141469
|
-
let timeout;
|
|
141470
|
-
let timeoutScheduled = false;
|
|
141471
|
-
let failure;
|
|
141472
|
-
let latestVersion;
|
|
141473
|
-
try {
|
|
141474
|
-
timeout = timer.schedule(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
141475
|
-
timeoutScheduled = true;
|
|
141476
|
-
const response = await fetchImpl(REGISTRY_URL, {
|
|
141477
|
-
method: "GET",
|
|
141478
|
-
headers: { accept: "application/json" },
|
|
141479
|
-
signal: controller.signal,
|
|
141480
|
-
credentials: "omit"
|
|
141481
|
-
});
|
|
141482
|
-
if (!response.ok) {
|
|
141483
|
-
failure = "http";
|
|
141484
|
-
} else {
|
|
141485
|
-
const body = await boundedResponseText(response);
|
|
141486
|
-
if (body === undefined) {
|
|
141487
|
-
failure = "response-too-large";
|
|
141488
|
-
} else {
|
|
141489
|
-
let parsed;
|
|
141490
|
-
try {
|
|
141491
|
-
parsed = JSON.parse(body);
|
|
141492
|
-
} catch {
|
|
141493
|
-
parsed = undefined;
|
|
141494
|
-
}
|
|
141495
|
-
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
141496
|
-
failure = "malformed-response";
|
|
141497
|
-
} else {
|
|
141498
|
-
const record = parsed;
|
|
141499
|
-
if (record.name !== "@mrciphersmith/keryx" || typeof record.version !== "string") {
|
|
141500
|
-
failure = "malformed-response";
|
|
141501
|
-
} else if (parseSemVer(record.version) === undefined) {
|
|
141502
|
-
failure = "invalid-latest-version";
|
|
141503
|
-
} else {
|
|
141504
|
-
latestVersion = record.version;
|
|
141505
|
-
}
|
|
141506
|
-
}
|
|
141507
|
-
}
|
|
141508
|
-
}
|
|
141509
|
-
} catch {
|
|
141510
|
-
failure = controller.signal.aborted ? "timeout" : "network";
|
|
141511
|
-
} finally {
|
|
141512
|
-
if (timeoutScheduled) {
|
|
141513
|
-
try {
|
|
141514
|
-
timer.cancel(timeout);
|
|
141515
|
-
} catch {}
|
|
141516
|
-
}
|
|
141517
|
-
}
|
|
141518
|
-
if (latestVersion === undefined) {
|
|
141519
|
-
await updateCache(cacheFile, (committed) => ({ ...committed, failureAt: timestamp }));
|
|
141520
|
-
return unavailable(options.currentVersion, failure ?? "network", cache);
|
|
141521
|
-
}
|
|
141522
|
-
await updateCache(cacheFile, (committed) => mergeSuccessfulCache(committed, latestVersion, timestamp));
|
|
141523
|
-
return resultFor(options.currentVersion, current, latestVersion, "registry");
|
|
141524
|
-
}
|
|
141525
|
-
|
|
141526
141997
|
// src/tui/shell-chrome.ts
|
|
141527
141998
|
init_debug_log();
|
|
141528
141999
|
|
|
@@ -143826,7 +144297,7 @@ init_model_tier();
|
|
|
143826
144297
|
init_config_dir();
|
|
143827
144298
|
init_fs();
|
|
143828
144299
|
init_table();
|
|
143829
|
-
import
|
|
144300
|
+
import path310 from "path";
|
|
143830
144301
|
var UNCATEGORIZED = "uncategorized";
|
|
143831
144302
|
var EMPTY_TASK_COST_STORE = {};
|
|
143832
144303
|
var MIN_MEASURED_TASKS = 20;
|
|
@@ -143892,7 +144363,7 @@ var TASK_COST_LOCK_TIMEOUT_MS = 3000;
|
|
|
143892
144363
|
var TASK_COST_LOCK_RETRY_MS = 15;
|
|
143893
144364
|
var TASK_COST_LOCK_STALE_MS = 1e4;
|
|
143894
144365
|
function taskCostFilePath(dir) {
|
|
143895
|
-
return
|
|
144366
|
+
return path310.join(ensureKeryxSubdir(["routing"], dir), TASK_COST_FILE);
|
|
143896
144367
|
}
|
|
143897
144368
|
function isTaskCostRecord(value) {
|
|
143898
144369
|
if (typeof value !== "object" || value === null)
|
|
@@ -144956,11 +145427,11 @@ function openConform(otui, chrome, options) {
|
|
|
144956
145427
|
}
|
|
144957
145428
|
|
|
144958
145429
|
// src/tui/conform-source.ts
|
|
144959
|
-
import { readFile as readFile160, readdir as
|
|
144960
|
-
import
|
|
145430
|
+
import { readFile as readFile160, readdir as readdir56, stat as stat31 } from "fs/promises";
|
|
145431
|
+
import path311 from "path";
|
|
144961
145432
|
async function readRecentConformDocs2(cwd) {
|
|
144962
145433
|
try {
|
|
144963
|
-
const raw = JSON.parse(await readFile160(
|
|
145434
|
+
const raw = JSON.parse(await readFile160(path311.join(cwd, CONFORM_RECENTS_PATH), "utf8"));
|
|
144964
145435
|
return Array.isArray(raw) ? raw : [];
|
|
144965
145436
|
} catch {
|
|
144966
145437
|
return [];
|
|
@@ -144981,25 +145452,25 @@ async function currentBranchPrTarget(cwd) {
|
|
|
144981
145452
|
}
|
|
144982
145453
|
}
|
|
144983
145454
|
async function mostRecentReviewPackage(cwd) {
|
|
144984
|
-
const flowsDir =
|
|
145455
|
+
const flowsDir = path311.join(cwd, ".metaproject", "flows");
|
|
144985
145456
|
let best;
|
|
144986
145457
|
try {
|
|
144987
|
-
for (const flowEntry of await
|
|
145458
|
+
for (const flowEntry of await readdir56(flowsDir, { withFileTypes: true })) {
|
|
144988
145459
|
if (!flowEntry.isDirectory())
|
|
144989
145460
|
continue;
|
|
144990
|
-
const reviewsDir =
|
|
145461
|
+
const reviewsDir = path311.join(flowsDir, flowEntry.name, "reviews");
|
|
144991
145462
|
let reviewEntries;
|
|
144992
145463
|
try {
|
|
144993
|
-
reviewEntries = await
|
|
145464
|
+
reviewEntries = await readdir56(reviewsDir, { withFileTypes: true });
|
|
144994
145465
|
} catch {
|
|
144995
145466
|
continue;
|
|
144996
145467
|
}
|
|
144997
145468
|
for (const reviewEntry of reviewEntries) {
|
|
144998
145469
|
if (!reviewEntry.isDirectory())
|
|
144999
145470
|
continue;
|
|
145000
|
-
const dir =
|
|
145471
|
+
const dir = path311.join(reviewsDir, reviewEntry.name);
|
|
145001
145472
|
try {
|
|
145002
|
-
const info = await stat31(
|
|
145473
|
+
const info = await stat31(path311.join(dir, "report.md"));
|
|
145003
145474
|
if (best === undefined || info.mtimeMs > best.mtimeMs)
|
|
145004
145475
|
best = { dir, mtimeMs: info.mtimeMs };
|
|
145005
145476
|
} catch {}
|
|
@@ -145025,14 +145496,14 @@ async function loadConformSetup(cwd) {
|
|
|
145025
145496
|
targets.push(pr);
|
|
145026
145497
|
const reviewDir = await mostRecentReviewPackage(cwd);
|
|
145027
145498
|
if (reviewDir !== undefined) {
|
|
145028
|
-
targets.push({ id: `report:${reviewDir}`, kind: "report", label: `most recent review package \u2014 ${
|
|
145499
|
+
targets.push({ id: `report:${reviewDir}`, kind: "report", label: `most recent review package \u2014 ${path311.relative(cwd, reviewDir)}` });
|
|
145029
145500
|
}
|
|
145030
145501
|
targets.push({ id: "diff:working", kind: "diff", label: "the working diff" });
|
|
145031
145502
|
return { recents, targets };
|
|
145032
145503
|
}
|
|
145033
145504
|
async function readReportFindings2(reportDir) {
|
|
145034
145505
|
try {
|
|
145035
|
-
const raw = JSON.parse(await readFile160(
|
|
145506
|
+
const raw = JSON.parse(await readFile160(path311.join(reportDir, "findings.json"), "utf8"));
|
|
145036
145507
|
return Array.isArray(raw) ? raw : [];
|
|
145037
145508
|
} catch {
|
|
145038
145509
|
return [];
|
|
@@ -145148,7 +145619,7 @@ async function runConformForTarget(cwd, refPath, target, signal) {
|
|
|
145148
145619
|
await scoreHunkRegions(hunkClauses, hunkRegionsFromDiff(info.diff));
|
|
145149
145620
|
} else if (target.kind === "report") {
|
|
145150
145621
|
const reportDir = target.id.slice("report:".length);
|
|
145151
|
-
const reportMarkdown = await readFile160(
|
|
145622
|
+
const reportMarkdown = await readFile160(path311.join(reportDir, "report.md"), "utf8").catch(() => "");
|
|
145152
145623
|
const findings = await readReportFindings2(reportDir);
|
|
145153
145624
|
const facts = computeReportConformFacts(reportMarkdown, findings);
|
|
145154
145625
|
const redacted = reportRedactedStateText(reportMarkdown);
|
|
@@ -145174,7 +145645,7 @@ async function runConformForTarget(cwd, refPath, target, signal) {
|
|
|
145174
145645
|
async function writeRecentConformDoc(cwd, refPath) {
|
|
145175
145646
|
await Promise.resolve().then(() => init_fs());
|
|
145176
145647
|
const current = await readRecentConformDocs2(cwd);
|
|
145177
|
-
await writeFileAtomic(
|
|
145648
|
+
await writeFileAtomic(path311.join(cwd, CONFORM_RECENTS_PATH), `${JSON.stringify(withRecentDoc(current, refPath), null, 2)}
|
|
145178
145649
|
`, {
|
|
145179
145650
|
mode: 384
|
|
145180
145651
|
}).catch(() => {});
|
|
@@ -145310,8 +145781,8 @@ async function runJevContractForShell(cwd, gitDiff = defaultGitDiff3) {
|
|
|
145310
145781
|
}
|
|
145311
145782
|
|
|
145312
145783
|
// src/tui/jev-triage-command.ts
|
|
145313
|
-
import { readdir as
|
|
145314
|
-
import
|
|
145784
|
+
import { readdir as readdir57, readFile as readFile161, stat as stat32 } from "fs/promises";
|
|
145785
|
+
import path312 from "path";
|
|
145315
145786
|
var JEV_TRIAGE_COMMAND = "/triage";
|
|
145316
145787
|
function isJevTriageCommand(name) {
|
|
145317
145788
|
return name === JEV_TRIAGE_COMMAND;
|
|
@@ -145320,25 +145791,25 @@ function renderJevTriageForShell(result) {
|
|
|
145320
145791
|
return renderTriageMarkdown(result).trimEnd();
|
|
145321
145792
|
}
|
|
145322
145793
|
async function resolveLatestReviewPackage(cwd) {
|
|
145323
|
-
const flowsDir =
|
|
145794
|
+
const flowsDir = path312.join(cwd, ".metaproject", "flows");
|
|
145324
145795
|
let flowEntries;
|
|
145325
145796
|
try {
|
|
145326
|
-
flowEntries = (await
|
|
145797
|
+
flowEntries = (await readdir57(flowsDir, { withFileTypes: true })).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
145327
145798
|
} catch {
|
|
145328
145799
|
return;
|
|
145329
145800
|
}
|
|
145330
145801
|
const candidates = [];
|
|
145331
145802
|
for (const flowName of flowEntries) {
|
|
145332
|
-
const reviewsDir =
|
|
145803
|
+
const reviewsDir = path312.join(flowsDir, flowName, "reviews");
|
|
145333
145804
|
let reviewEntries;
|
|
145334
145805
|
try {
|
|
145335
|
-
reviewEntries = (await
|
|
145806
|
+
reviewEntries = (await readdir57(reviewsDir, { withFileTypes: true })).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
145336
145807
|
} catch {
|
|
145337
145808
|
continue;
|
|
145338
145809
|
}
|
|
145339
145810
|
for (const reviewName of reviewEntries) {
|
|
145340
|
-
const packageDir =
|
|
145341
|
-
const findingsPath =
|
|
145811
|
+
const packageDir = path312.join(reviewsDir, reviewName);
|
|
145812
|
+
const findingsPath = path312.join(packageDir, "findings.json");
|
|
145342
145813
|
try {
|
|
145343
145814
|
const stats = await stat32(findingsPath);
|
|
145344
145815
|
candidates.push({ dir: packageDir, mtimeMs: stats.mtimeMs });
|
|
@@ -145361,9 +145832,9 @@ async function runJevTriageForShell(cwd) {
|
|
|
145361
145832
|
if (packageDir === undefined) {
|
|
145362
145833
|
return "review-jev-triage: no review package found under .metaproject/flows/*/reviews/ \u2014 run a review round first.";
|
|
145363
145834
|
}
|
|
145364
|
-
const findingsRaw = JSON.parse(await readFile161(
|
|
145835
|
+
const findingsRaw = JSON.parse(await readFile161(path312.join(packageDir, "findings.json"), "utf8"));
|
|
145365
145836
|
const result = await computeJevTriageResult({ findingsRaw });
|
|
145366
|
-
return `review-jev-triage: ${
|
|
145837
|
+
return `review-jev-triage: ${path312.relative(cwd, packageDir)}
|
|
145367
145838
|
${renderJevTriageForShell(result)}`;
|
|
145368
145839
|
}
|
|
145369
145840
|
|
|
@@ -148277,10 +148748,10 @@ function openHelpModal(otui, chrome, options) {
|
|
|
148277
148748
|
|
|
148278
148749
|
// src/tui/help-first-run.ts
|
|
148279
148750
|
init_config_dir();
|
|
148280
|
-
import
|
|
148751
|
+
import path313 from "path";
|
|
148281
148752
|
var FIRST_RUN_HELP_FILE = "help-first-run.json";
|
|
148282
148753
|
function firstRunHelpPath(dir) {
|
|
148283
|
-
return
|
|
148754
|
+
return path313.join(keryxConfigDir(dir), FIRST_RUN_HELP_FILE);
|
|
148284
148755
|
}
|
|
148285
148756
|
function helpFirstRunShown(dir) {
|
|
148286
148757
|
const result = readConfigFile(firstRunHelpPath(dir));
|
|
@@ -149364,10 +149835,10 @@ function describeElicitationPrompt(tool, inputJson) {
|
|
|
149364
149835
|
// src/lib/permission-mode-config.ts
|
|
149365
149836
|
init_permission_mode();
|
|
149366
149837
|
init_config_dir();
|
|
149367
|
-
import
|
|
149838
|
+
import path314 from "path";
|
|
149368
149839
|
var EMPTY3 = { schemaVersion: 1, projects: {} };
|
|
149369
149840
|
function permissionModeConfigPath(dir) {
|
|
149370
|
-
return
|
|
149841
|
+
return path314.join(keryxConfigDir(dir), "permission-mode.json");
|
|
149371
149842
|
}
|
|
149372
149843
|
function withRegistryLock2(dir, fn) {
|
|
149373
149844
|
return withFileLock2(`${permissionModeConfigPath(dir)}.lock`, fn, {
|
|
@@ -152316,7 +152787,7 @@ function mountExecutionPlanPanel(otui, renderer, parent, options) {
|
|
|
152316
152787
|
// src/commands/schedule.ts
|
|
152317
152788
|
import { createInterface } from "readline/promises";
|
|
152318
152789
|
import { readFile as readFile162 } from "fs/promises";
|
|
152319
|
-
import
|
|
152790
|
+
import path316 from "path";
|
|
152320
152791
|
|
|
152321
152792
|
// src/commands/trigger.ts
|
|
152322
152793
|
init_gdgraph();
|
|
@@ -152327,9 +152798,9 @@ init_agent();
|
|
|
152327
152798
|
init_agent_hooks();
|
|
152328
152799
|
import { execFile as execFile11 } from "child_process";
|
|
152329
152800
|
import { randomUUID as randomUUID36 } from "crypto";
|
|
152330
|
-
import { mkdtemp as mkdtemp5, mkdir as mkdir68, readdir as
|
|
152801
|
+
import { mkdtemp as mkdtemp5, mkdir as mkdir68, readdir as readdir58, rm as rm19, writeFile as writeFile47 } from "fs/promises";
|
|
152331
152802
|
import { homedir as homedir13, tmpdir as tmpdir11 } from "os";
|
|
152332
|
-
import
|
|
152803
|
+
import path315 from "path";
|
|
152333
152804
|
init_interactive_tools();
|
|
152334
152805
|
|
|
152335
152806
|
// src/harness/process/sandbox/proxy.ts
|
|
@@ -152797,9 +153268,9 @@ function refusal3(runId, code, detail, action) {
|
|
|
152797
153268
|
function agentTaskScratchParent(env = process.env) {
|
|
152798
153269
|
const uid = typeof process.getuid === "function" ? process.getuid() : 0;
|
|
152799
153270
|
const runtime = env["XDG_RUNTIME_DIR"];
|
|
152800
|
-
if (runtime !== undefined && runtime.length > 0 &&
|
|
152801
|
-
return
|
|
152802
|
-
return
|
|
153271
|
+
if (runtime !== undefined && runtime.length > 0 && path315.isAbsolute(runtime))
|
|
153272
|
+
return path315.join(runtime, "keryx-agent-tasks");
|
|
153273
|
+
return path315.join(tmpdir11(), `keryx-agent-tasks-${uid}`);
|
|
152803
153274
|
}
|
|
152804
153275
|
function lastAssistantText(history) {
|
|
152805
153276
|
for (let i = history.length - 1;i >= 0; i -= 1) {
|
|
@@ -152810,9 +153281,9 @@ function lastAssistantText(history) {
|
|
|
152810
153281
|
return "";
|
|
152811
153282
|
}
|
|
152812
153283
|
async function pruneReports(dir, keep) {
|
|
152813
|
-
const names = (await
|
|
153284
|
+
const names = (await readdir58(dir).catch(() => [])).filter((n) => n.endsWith(".md")).sort();
|
|
152814
153285
|
for (const old of names.slice(0, Math.max(0, names.length - keep))) {
|
|
152815
|
-
await rm19(
|
|
153286
|
+
await rm19(path315.join(dir, old), { force: true }).catch(() => {});
|
|
152816
153287
|
}
|
|
152817
153288
|
}
|
|
152818
153289
|
async function runAgentTaskDispatch(projectRoot, entry, action, deps = {}) {
|
|
@@ -152849,10 +153320,10 @@ async function runLocked(projectRoot, entry, action, deps, runId, now) {
|
|
|
152849
153320
|
};
|
|
152850
153321
|
}
|
|
152851
153322
|
const scratchParent = parent.dir;
|
|
152852
|
-
const scratch = await mkdtemp5(
|
|
152853
|
-
const workdir =
|
|
152854
|
-
const scratchHome =
|
|
152855
|
-
const grantedCwd =
|
|
153323
|
+
const scratch = await mkdtemp5(path315.join(scratchParent, `${entry.name.replace(/[^A-Za-z0-9._-]/g, "-")}-`));
|
|
153324
|
+
const workdir = path315.join(scratch, "work");
|
|
153325
|
+
const scratchHome = path315.join(scratch, "home");
|
|
153326
|
+
const grantedCwd = path315.join(scratch, "granted-cwd");
|
|
152856
153327
|
await mkdir68(workdir, { recursive: true });
|
|
152857
153328
|
await mkdir68(scratchHome, { recursive: true });
|
|
152858
153329
|
await mkdir68(grantedCwd, { recursive: true, mode: 448 });
|
|
@@ -152865,7 +153336,7 @@ async function runLocked(projectRoot, entry, action, deps, runId, now) {
|
|
|
152865
153336
|
const invocation = keryxInvocation();
|
|
152866
153337
|
let networkInput = action.grants.network === "full";
|
|
152867
153338
|
if (action.grants.network === "allowlist") {
|
|
152868
|
-
const proxySocketPath =
|
|
153339
|
+
const proxySocketPath = path315.join(scratch, "net-proxy.sock");
|
|
152869
153340
|
try {
|
|
152870
153341
|
const proxy = await createAllowlistProxy({
|
|
152871
153342
|
allowedDomains: [...action.grants.domains],
|
|
@@ -152950,7 +153421,12 @@ async function runLocked(projectRoot, entry, action, deps, runId, now) {
|
|
|
152950
153421
|
const env = deps.grantedEnv ?? process.env;
|
|
152951
153422
|
const extraSecrets = await ghAuthToken(binaries.realpaths["gh"], grantedCwd, env);
|
|
152952
153423
|
const granted = action.grants.tools.map((id) => grantedToolSpec(id)).filter((spec) => spec !== undefined).map((spec) => grantedTool(spec, action, grantedCwd, env, grantedCalls, binaries.realpaths, extraSecrets, binaries.stats));
|
|
152953
|
-
const tools = [
|
|
153424
|
+
const tools = [
|
|
153425
|
+
...builtinReadOnlyTools(projectRoot),
|
|
153426
|
+
shellExecTool(workdir, sandboxedRunner(workdir, sandbox)),
|
|
153427
|
+
...granted,
|
|
153428
|
+
...deps.extraTools ?? []
|
|
153429
|
+
];
|
|
152954
153430
|
const offending = tools.filter((t) => UNATTENDED_EXCLUDED_TOOLS.includes(t.definition.name));
|
|
152955
153431
|
if (offending.length > 0)
|
|
152956
153432
|
throw new Error(`agent-task roster must not offer: ${offending.map((t) => t.definition.name).join(", ")}`);
|
|
@@ -153000,6 +153476,9 @@ async function runLocked(projectRoot, entry, action, deps, runId, now) {
|
|
|
153000
153476
|
};
|
|
153001
153477
|
const result = await runAgentTurn(io, agentDeps, history, buildAgentTaskPrompt(entry, action), { signal: controller.signal });
|
|
153002
153478
|
finishReason = result.finishReason;
|
|
153479
|
+
if (result.caughtToolErrors !== undefined && result.caughtToolErrors.length > 0) {
|
|
153480
|
+
crashed = result.caughtToolErrors.map((e) => `${e.toolName}: ${e.message}`).join("; ");
|
|
153481
|
+
}
|
|
153003
153482
|
} catch (error) {
|
|
153004
153483
|
crashed = error instanceof Error ? error.message : String(error);
|
|
153005
153484
|
} finally {
|
|
@@ -153014,12 +153493,12 @@ async function runLocked(projectRoot, entry, action, deps, runId, now) {
|
|
|
153014
153493
|
let reportNote = "";
|
|
153015
153494
|
try {
|
|
153016
153495
|
await ensureTriggerDataIgnored(projectRoot);
|
|
153017
|
-
const dir =
|
|
153496
|
+
const dir = path315.join(triggerReportsDir(projectRoot), entry.name);
|
|
153018
153497
|
await mkdir68(dir, { recursive: true });
|
|
153019
|
-
const file =
|
|
153498
|
+
const file = path315.join(dir, `${runId}.md`);
|
|
153020
153499
|
await writeFile47(file, renderReport2({ entry, action, runId, at: now().toISOString(), outcome, why, cost, grantedCalls, denials, sandboxNote, summary, networkDecisions }), "utf8");
|
|
153021
153500
|
await pruneReports(dir, action.report.keep);
|
|
153022
|
-
reportPath =
|
|
153501
|
+
reportPath = path315.relative(projectRoot, file);
|
|
153023
153502
|
} catch (error) {
|
|
153024
153503
|
reportNote = ` (report NOT written: ${error instanceof Error ? error.message : String(error)})`;
|
|
153025
153504
|
}
|
|
@@ -153927,7 +154406,7 @@ async function showSubcommand(cwd, name, host, deps) {
|
|
|
153927
154406
|
if (row.reportPath !== undefined) {
|
|
153928
154407
|
console.log(`
|
|
153929
154408
|
--- ${row.reportPath} ---`);
|
|
153930
|
-
console.log(await readFile162(
|
|
154409
|
+
console.log(await readFile162(path316.join(cwd, row.reportPath), "utf8").catch(() => "(the report could not be read)"));
|
|
153931
154410
|
}
|
|
153932
154411
|
}
|
|
153933
154412
|
async function simpleAction(cwd, name, verb, action) {
|
|
@@ -155089,14 +155568,19 @@ function attachUsageIo(io, chrome) {
|
|
|
155089
155568
|
}
|
|
155090
155569
|
});
|
|
155091
155570
|
}
|
|
155092
|
-
|
|
155571
|
+
var OPENAI_CACHED_INPUT_DISCOUNT = 0.5;
|
|
155572
|
+
function estimateTaskCostUsd(profile, providerId, inputTokens, outputTokens, cacheReadTokens) {
|
|
155093
155573
|
if (profile === undefined)
|
|
155094
155574
|
return;
|
|
155095
155575
|
const priceIn = profile.priceInputPerMillion.value;
|
|
155096
155576
|
const priceOut = profile.priceOutputPerMillion.value;
|
|
155097
155577
|
if (priceIn === "unknown" || priceOut === "unknown")
|
|
155098
155578
|
return;
|
|
155099
|
-
|
|
155579
|
+
const cachedInputDiscount = providerId === "openai" || providerId === "openai-codex" ? OPENAI_CACHED_INPUT_DISCOUNT : 1;
|
|
155580
|
+
const cacheRead = cacheReadTokens !== undefined && cacheReadTokens > 0 ? Math.min(cacheReadTokens, inputTokens) : 0;
|
|
155581
|
+
const fullPriceInputTokens = inputTokens - cacheRead;
|
|
155582
|
+
const inputCost = fullPriceInputTokens / 1e6 * priceIn + cacheRead / 1e6 * priceIn * cachedInputDiscount;
|
|
155583
|
+
return inputCost + outputTokens / 1e6 * priceOut;
|
|
155100
155584
|
}
|
|
155101
155585
|
async function recordTurnTaskCostBestEffort(input) {
|
|
155102
155586
|
if (input.inputTokens === 0 && input.outputTokens === 0)
|
|
@@ -155104,7 +155588,7 @@ async function recordTurnTaskCostBestEffort(input) {
|
|
|
155104
155588
|
try {
|
|
155105
155589
|
const profiles = loadModelProfiles(input.userConfigDir);
|
|
155106
155590
|
const profile = profiles[profileKey(input.providerId, input.modelId)];
|
|
155107
|
-
const costUsd = estimateTaskCostUsd(profile, input.inputTokens, input.outputTokens);
|
|
155591
|
+
const costUsd = estimateTaskCostUsd(profile, input.providerId, input.inputTokens, input.outputTokens, input.cacheReadTokens);
|
|
155108
155592
|
await appendTaskCostRecord({
|
|
155109
155593
|
providerId: input.providerId,
|
|
155110
155594
|
modelId: input.modelId,
|
|
@@ -159560,6 +160044,14 @@ ${formatThemeList(getThemeId())}`);
|
|
|
159560
160044
|
});
|
|
159561
160045
|
return;
|
|
159562
160046
|
}
|
|
160047
|
+
if (command.name === "/doctor") {
|
|
160048
|
+
(async () => {
|
|
160049
|
+
const report = await buildDoctorReport(sessionCwd);
|
|
160050
|
+
io.onSystem?.(`${formatDoctorReport2(report)}
|
|
160051
|
+
`);
|
|
160052
|
+
})();
|
|
160053
|
+
return;
|
|
160054
|
+
}
|
|
159563
160055
|
if (command.name === "/game") {
|
|
159564
160056
|
showGame(line);
|
|
159565
160057
|
return;
|
|
@@ -159870,10 +160362,12 @@ Usage: /reasoning <${REASONING_EFFORT_LEVELS.join("|")}>
|
|
|
159870
160362
|
};
|
|
159871
160363
|
let turnInputTokens = 0;
|
|
159872
160364
|
let turnOutputTokens = 0;
|
|
160365
|
+
let turnCacheReadTokens = 0;
|
|
159873
160366
|
const prevOnUsageForCost = io.onUsage;
|
|
159874
160367
|
io.onUsage = (usage) => {
|
|
159875
160368
|
turnInputTokens += usage.inputTokens ?? 0;
|
|
159876
160369
|
turnOutputTokens += usage.outputTokens ?? 0;
|
|
160370
|
+
turnCacheReadTokens += usage.cacheReadTokens ?? 0;
|
|
159877
160371
|
prevOnUsageForCost?.(usage);
|
|
159878
160372
|
};
|
|
159879
160373
|
const suggestNextStep = async () => {
|
|
@@ -159973,6 +160467,7 @@ Usage: /reasoning <${REASONING_EFFORT_LEVELS.join("|")}>
|
|
|
159973
160467
|
modelId: deps.modelId,
|
|
159974
160468
|
inputTokens: turnInputTokens,
|
|
159975
160469
|
outputTokens: turnOutputTokens,
|
|
160470
|
+
...turnCacheReadTokens > 0 ? { cacheReadTokens: turnCacheReadTokens } : {},
|
|
159976
160471
|
success: !turnFailed,
|
|
159977
160472
|
...turnCategory !== undefined ? { category: turnCategory } : {}
|
|
159978
160473
|
});
|
|
@@ -160515,6 +161010,7 @@ var READLINE_AGENT_COMMANDS = [
|
|
|
160515
161010
|
"/compact",
|
|
160516
161011
|
"/status",
|
|
160517
161012
|
"/flows",
|
|
161013
|
+
"/doctor",
|
|
160518
161014
|
"/theme",
|
|
160519
161015
|
"/mode",
|
|
160520
161016
|
"/reasoning",
|
|
@@ -161025,6 +161521,12 @@ Kept the current session.
|
|
|
161025
161521
|
system(HELP_TEXT);
|
|
161026
161522
|
continue;
|
|
161027
161523
|
}
|
|
161524
|
+
if (command === "/doctor") {
|
|
161525
|
+
const report = await buildDoctorReport(deps.session?.cwd ?? process.cwd());
|
|
161526
|
+
system(`${formatDoctorReport2(report)}
|
|
161527
|
+
`);
|
|
161528
|
+
continue;
|
|
161529
|
+
}
|
|
161028
161530
|
if (isSessionInfoCommand(command)) {
|
|
161029
161531
|
const cwd = deps.session?.cwd;
|
|
161030
161532
|
const [workspaces, flows] = cwd === undefined ? [[], []] : await Promise.all([loadInspectorWorkspaces(cwd), loadInspectorFlows(cwd)]);
|
|
@@ -161579,7 +162081,9 @@ async function runAgentRepl(lines, rich, deps, metaprojectPort, sessionOpts, ini
|
|
|
161579
162081
|
return settled;
|
|
161580
162082
|
}
|
|
161581
162083
|
const completion = new Promise((resolve) => {
|
|
162084
|
+
completionWaiters = [];
|
|
161582
162085
|
completionWaiters.push(() => resolve({ kind: "completion" }));
|
|
162086
|
+
rich.onCompletionWaitersSize?.(completionWaiters.length);
|
|
161583
162087
|
});
|
|
161584
162088
|
const winner = await Promise.race([pendingLine, completion]);
|
|
161585
162089
|
if (winner.kind !== "completion") {
|
|
@@ -162194,6 +162698,10 @@ ${GUTTER}${turnSeparator()}
|
|
|
162194
162698
|
await runBusSlashCommand(bus, rest, (text) => agentIo.onSystem?.(text));
|
|
162195
162699
|
} else if (command === "/help") {
|
|
162196
162700
|
agentIo.onSystem?.(readlineAgentHelpText());
|
|
162701
|
+
} else if (command === "/doctor") {
|
|
162702
|
+
const report = await buildDoctorReport(sessionCwd);
|
|
162703
|
+
agentIo.onSystem?.(`${formatDoctorReport2(report)}
|
|
162704
|
+
`);
|
|
162197
162705
|
} else if (isSessionInfoCommand(command)) {
|
|
162198
162706
|
const cwd = sessionCwd;
|
|
162199
162707
|
const [workspaces, flows] = await Promise.all([
|
|
@@ -162240,6 +162748,8 @@ ${GUTTER}${turnSeparator()}
|
|
|
162240
162748
|
continue;
|
|
162241
162749
|
}
|
|
162242
162750
|
await closeSlateSession(slateSession, mintTimestampAttemptId);
|
|
162751
|
+
lastToolOutput = undefined;
|
|
162752
|
+
lastToolName = undefined;
|
|
162243
162753
|
if (nextLive !== undefined) {
|
|
162244
162754
|
live = nextLive;
|
|
162245
162755
|
history = [];
|
|
@@ -165738,7 +166248,7 @@ init_fs();
|
|
|
165738
166248
|
init_prompt();
|
|
165739
166249
|
import { readFile as readFile163 } from "fs/promises";
|
|
165740
166250
|
import { stdin } from "process";
|
|
165741
|
-
import
|
|
166251
|
+
import path318 from "path";
|
|
165742
166252
|
init_ui();
|
|
165743
166253
|
var MODULES = [
|
|
165744
166254
|
{ name: "gdgraph", flag: "--no-gdgraph", desc: "code graph, symbols, affected context", defaultEnabled: true },
|
|
@@ -165785,8 +166295,8 @@ async function modulesCommand(args = []) {
|
|
|
165785
166295
|
return;
|
|
165786
166296
|
}
|
|
165787
166297
|
const wantsJson = args.includes("--json") && (sub === undefined || sub === "status" || sub === "list" || sub === "--json");
|
|
165788
|
-
const metaprojectRoot =
|
|
165789
|
-
const manifestPath =
|
|
166298
|
+
const metaprojectRoot = path318.join(process.cwd(), ".metaproject");
|
|
166299
|
+
const manifestPath = path318.join(metaprojectRoot, "metaproject.json");
|
|
165790
166300
|
if (!await pathExists(manifestPath)) {
|
|
165791
166301
|
if (wantsJson) {
|
|
165792
166302
|
console.log(JSON.stringify({ schemaVersion: 1, error: "not-initialized", modules: [] }, null, 2));
|
|
@@ -165909,7 +166419,7 @@ import { createHash as createHash68, randomBytes as randomBytes11, randomUUID as
|
|
|
165909
166419
|
import {
|
|
165910
166420
|
chmodSync as chmodSync5,
|
|
165911
166421
|
closeSync as closeSync7,
|
|
165912
|
-
existsSync as
|
|
166422
|
+
existsSync as existsSync49,
|
|
165913
166423
|
fsyncSync as fsyncSync2,
|
|
165914
166424
|
openSync as openSync8,
|
|
165915
166425
|
renameSync as renameSync5,
|
|
@@ -165917,9 +166427,9 @@ import {
|
|
|
165917
166427
|
unlinkSync as unlinkSync6,
|
|
165918
166428
|
writeFileSync as writeFileSync10
|
|
165919
166429
|
} from "fs";
|
|
165920
|
-
import
|
|
166430
|
+
import path319 from "path";
|
|
165921
166431
|
function serveCredentialPath(dir) {
|
|
165922
|
-
return
|
|
166432
|
+
return path319.join(keryxConfigDir(dir), "serve-credentials.json");
|
|
165923
166433
|
}
|
|
165924
166434
|
function constantTimeEqual(a, b) {
|
|
165925
166435
|
const width = Math.max(a.length, b.length);
|
|
@@ -165953,7 +166463,7 @@ function isGroupOrOtherAccessible(file) {
|
|
|
165953
166463
|
}
|
|
165954
166464
|
function readServeCredential(dir) {
|
|
165955
166465
|
const file = serveCredentialPath(dir);
|
|
165956
|
-
if (!
|
|
166466
|
+
if (!existsSync49(file)) {
|
|
165957
166467
|
return { status: "absent" };
|
|
165958
166468
|
}
|
|
165959
166469
|
if (isGroupOrOtherAccessible(file)) {
|
|
@@ -166152,23 +166662,23 @@ class AuthFailureThrottle {
|
|
|
166152
166662
|
// src/lib/serve-turn-store.ts
|
|
166153
166663
|
init_config_dir();
|
|
166154
166664
|
import { createHash as createHash69 } from "crypto";
|
|
166155
|
-
import { existsSync as
|
|
166156
|
-
import
|
|
166665
|
+
import { existsSync as existsSync50, readdirSync as readdirSync12, rmSync as rmSync4 } from "fs";
|
|
166666
|
+
import path320 from "path";
|
|
166157
166667
|
var MAX_TURN_EVENTS = 1e4;
|
|
166158
166668
|
function turnsRoot(dir) {
|
|
166159
|
-
return
|
|
166669
|
+
return path320.join(keryxConfigDir(dir), "turns");
|
|
166160
166670
|
}
|
|
166161
166671
|
function turnDir(turnId, dir) {
|
|
166162
|
-
return
|
|
166672
|
+
return path320.join(turnsRoot(dir), turnId);
|
|
166163
166673
|
}
|
|
166164
166674
|
function keyPath(project, idempotencyKey, dir) {
|
|
166165
166675
|
const projectBytes = Buffer.byteLength(project, "utf8");
|
|
166166
166676
|
const digest = createHash69("sha256").update(`${projectBytes}:${project}\x00${idempotencyKey}`, "utf8").digest("hex");
|
|
166167
|
-
return
|
|
166677
|
+
return path320.join(turnsRoot(dir), "keys", `${digest}.json`);
|
|
166168
166678
|
}
|
|
166169
166679
|
function legacyKeyPath(idempotencyKey, dir) {
|
|
166170
166680
|
const digest = createHash69("sha256").update(idempotencyKey, "utf8").digest("hex");
|
|
166171
|
-
return
|
|
166681
|
+
return path320.join(turnsRoot(dir), "keys", `${digest}.json`);
|
|
166172
166682
|
}
|
|
166173
166683
|
function adoptLegacyClaim(project, idempotencyKey, dir) {
|
|
166174
166684
|
const legacy = legacyKeyPath(idempotencyKey, dir);
|
|
@@ -166232,7 +166742,7 @@ function ensureTurnDir(turnId, dir) {
|
|
|
166232
166742
|
}
|
|
166233
166743
|
function createTurnRecord(record, dir) {
|
|
166234
166744
|
ensureTurnDir(record.turnId, dir);
|
|
166235
|
-
writeOwnerOnlyFile(
|
|
166745
|
+
writeOwnerOnlyFile(path320.join(turnDir(record.turnId, dir), "turn.json"), `${JSON.stringify(record, null, 2)}
|
|
166236
166746
|
`);
|
|
166237
166747
|
}
|
|
166238
166748
|
function appendTurnEvent(event, dir, opts) {
|
|
@@ -166241,12 +166751,12 @@ function appendTurnEvent(event, dir, opts) {
|
|
|
166241
166751
|
}
|
|
166242
166752
|
const line = JSON.stringify(event);
|
|
166243
166753
|
try {
|
|
166244
|
-
appendOwnerOnlyLine(
|
|
166754
|
+
appendOwnerOnlyLine(path320.join(turnDir(event.turnId, dir), "events.jsonl"), line);
|
|
166245
166755
|
} catch (error) {
|
|
166246
166756
|
if (error?.code !== "ENOENT") {
|
|
166247
166757
|
throw error;
|
|
166248
166758
|
}
|
|
166249
|
-
appendOwnerOnlyLine(
|
|
166759
|
+
appendOwnerOnlyLine(path320.join(ensureTurnDir(event.turnId, dir), "events.jsonl"), line);
|
|
166250
166760
|
}
|
|
166251
166761
|
return true;
|
|
166252
166762
|
}
|
|
@@ -166254,7 +166764,7 @@ function readTurnEvents(turnId, after = -1, dir) {
|
|
|
166254
166764
|
if (!isTurnId(turnId)) {
|
|
166255
166765
|
return { ok: false, reason: "not-a-turn-id" };
|
|
166256
166766
|
}
|
|
166257
|
-
const read = readTurnFile(
|
|
166767
|
+
const read = readTurnFile(path320.join(turnDir(turnId, dir), "events.jsonl"));
|
|
166258
166768
|
if (!read.ok) {
|
|
166259
166769
|
if (isDefiniteAbsence2(read.reason)) {
|
|
166260
166770
|
return { ok: true, value: [] };
|
|
@@ -166282,7 +166792,7 @@ function readTurnRecord(turnId, dir) {
|
|
|
166282
166792
|
if (!isTurnId(turnId)) {
|
|
166283
166793
|
return { ok: false, reason: "not-a-turn-id" };
|
|
166284
166794
|
}
|
|
166285
|
-
const read = readTurnFile(
|
|
166795
|
+
const read = readTurnFile(path320.join(turnDir(turnId, dir), "turn.json"));
|
|
166286
166796
|
if (!read.ok) {
|
|
166287
166797
|
return { ok: false, reason: read.reason };
|
|
166288
166798
|
}
|
|
@@ -166301,7 +166811,7 @@ function finishTurn(turnId, result, dir) {
|
|
|
166301
166811
|
if (!record.ok) {
|
|
166302
166812
|
return false;
|
|
166303
166813
|
}
|
|
166304
|
-
writeOwnerOnlyFile(
|
|
166814
|
+
writeOwnerOnlyFile(path320.join(turnDir(turnId, dir), "turn.json"), `${JSON.stringify({ ...record.value, result }, null, 2)}
|
|
166305
166815
|
`);
|
|
166306
166816
|
return true;
|
|
166307
166817
|
}
|
|
@@ -166348,7 +166858,7 @@ function releaseIdempotencyKey(project, idempotencyKey, turnId, dir) {
|
|
|
166348
166858
|
// src/lib/serve-turn.ts
|
|
166349
166859
|
import { randomUUID as randomUUID44 } from "crypto";
|
|
166350
166860
|
init_hooks();
|
|
166351
|
-
import
|
|
166861
|
+
import path321 from "path";
|
|
166352
166862
|
init_service4();
|
|
166353
166863
|
init_service9();
|
|
166354
166864
|
init_impact_evidence_hook_adapter();
|
|
@@ -166419,9 +166929,9 @@ function isUuid(value) {
|
|
|
166419
166929
|
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);
|
|
166420
166930
|
}
|
|
166421
166931
|
function resolveProject(declared, dir) {
|
|
166422
|
-
const wanted =
|
|
166932
|
+
const wanted = path321.resolve(declared);
|
|
166423
166933
|
for (const entry of listProjects(dir, () => {})) {
|
|
166424
|
-
if (
|
|
166934
|
+
if (path321.resolve(entry.path) === wanted) {
|
|
166425
166935
|
return { ok: true, project: entry.path };
|
|
166426
166936
|
}
|
|
166427
166937
|
}
|
|
@@ -166494,7 +167004,7 @@ function buildRemoteHookRuntime(opts) {
|
|
|
166494
167004
|
});
|
|
166495
167005
|
emitRemoteHookNotices(opts.projectRoot, formatHookLoadNotices(loaded, {
|
|
166496
167006
|
projectRoot: opts.projectRoot,
|
|
166497
|
-
userFile:
|
|
167007
|
+
userFile: path321.join(homeDir, ".keryx", "hooks.json"),
|
|
166498
167008
|
surface: "headless"
|
|
166499
167009
|
}));
|
|
166500
167010
|
if (!loaded.ok) {
|
|
@@ -167543,9 +168053,9 @@ function printHelp23() {
|
|
|
167543
168053
|
// src/commands/update.ts
|
|
167544
168054
|
init_contained_write();
|
|
167545
168055
|
import { spawn as spawn9 } from "child_process";
|
|
167546
|
-
import { readFile as readFile164, readdir as
|
|
167547
|
-
import { access as access4, constants as constants5, existsSync as
|
|
167548
|
-
import
|
|
168056
|
+
import { readFile as readFile164, readdir as readdir59 } from "fs/promises";
|
|
168057
|
+
import { access as access4, constants as constants5, existsSync as existsSync51 } from "fs";
|
|
168058
|
+
import path322 from "path";
|
|
167549
168059
|
import { fileURLToPath as fileURLToPath10 } from "url";
|
|
167550
168060
|
init_catalog2();
|
|
167551
168061
|
init_model_choice();
|
|
@@ -167560,17 +168070,17 @@ init_ui();
|
|
|
167560
168070
|
init_install_plan();
|
|
167561
168071
|
init_templates3();
|
|
167562
168072
|
function containFromMetaprojectPath(filePath) {
|
|
167563
|
-
const marker = `${
|
|
168073
|
+
const marker = `${path322.sep}.metaproject${path322.sep}`;
|
|
167564
168074
|
const idx = filePath.lastIndexOf(marker);
|
|
167565
168075
|
if (idx < 0) {
|
|
167566
|
-
if (filePath.endsWith(`${
|
|
167567
|
-
const root = filePath.slice(0, filePath.length - ".metaproject".length -
|
|
168076
|
+
if (filePath.endsWith(`${path322.sep}.metaproject`)) {
|
|
168077
|
+
const root = filePath.slice(0, filePath.length - ".metaproject".length - path322.sep.length);
|
|
167568
168078
|
return { root, rel: ".metaproject" };
|
|
167569
168079
|
}
|
|
167570
168080
|
throw new Error(`${filePath}: expected a path under a .metaproject directory`);
|
|
167571
168081
|
}
|
|
167572
168082
|
const root = filePath.slice(0, idx);
|
|
167573
|
-
const rel = filePath.slice(idx +
|
|
168083
|
+
const rel = filePath.slice(idx + path322.sep.length).split(path322.sep).join("/");
|
|
167574
168084
|
return { root, rel };
|
|
167575
168085
|
}
|
|
167576
168086
|
async function updateCommand(args = []) {
|
|
@@ -167580,8 +168090,8 @@ async function updateCommand(args = []) {
|
|
|
167580
168090
|
return;
|
|
167581
168091
|
}
|
|
167582
168092
|
const projectRoot = process.cwd();
|
|
167583
|
-
const metaprojectRoot =
|
|
167584
|
-
banner("keryx update", `Refreshing the .metaproject workspace in ${
|
|
168093
|
+
const metaprojectRoot = path322.join(projectRoot, ".metaproject");
|
|
168094
|
+
banner("keryx update", `Refreshing the .metaproject workspace in ${path322.basename(projectRoot)}/`);
|
|
167585
168095
|
if (!await pathExists(metaprojectRoot)) {
|
|
167586
168096
|
console.log(` ${style.red(symbols.cross)} Metaproject is not initialized.`);
|
|
167587
168097
|
console.log(` ${style.cyan(symbols.arrow)} Run ${style.cyan("keryx init")} first.`);
|
|
@@ -167657,7 +168167,7 @@ async function updateCommand(args = []) {
|
|
|
167657
168167
|
nextSteps(steps);
|
|
167658
168168
|
}
|
|
167659
168169
|
async function previewServiceFiles(projectRoot, options) {
|
|
167660
|
-
const metaprojectRoot =
|
|
168170
|
+
const metaprojectRoot = path322.join(projectRoot, ".metaproject");
|
|
167661
168171
|
const manifestState = await readManifest5(metaprojectRoot);
|
|
167662
168172
|
const manifest = manifestState.manifest;
|
|
167663
168173
|
const enableTasks = moduleEnabled2(manifest, "tasks") || !options.noTasks;
|
|
@@ -167686,13 +168196,13 @@ async function previewServiceFiles(projectRoot, options) {
|
|
|
167686
168196
|
});
|
|
167687
168197
|
}
|
|
167688
168198
|
async function refreshServiceFiles(projectRoot, options) {
|
|
167689
|
-
const metaprojectRoot =
|
|
168199
|
+
const metaprojectRoot = path322.join(projectRoot, ".metaproject");
|
|
167690
168200
|
const manifestState = await readManifest5(metaprojectRoot);
|
|
167691
168201
|
const manifest = manifestState.manifest;
|
|
167692
168202
|
const recoveredManifest = !manifestState.exists || !manifestState.valid;
|
|
167693
168203
|
if (manifestState.migrated) {
|
|
167694
168204
|
{
|
|
167695
|
-
const { root, rel } = containFromMetaprojectPath(
|
|
168205
|
+
const { root, rel } = containFromMetaprojectPath(path322.join(metaprojectRoot, "metaproject.json"));
|
|
167696
168206
|
await writeContained(root, rel, `${JSON.stringify(manifest, null, 2)}
|
|
167697
168207
|
`);
|
|
167698
168208
|
}
|
|
@@ -167732,9 +168242,9 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
167732
168242
|
enableSecurity,
|
|
167733
168243
|
enableSac
|
|
167734
168244
|
});
|
|
167735
|
-
await writeTextIfChanged4(
|
|
167736
|
-
await writeTextIfChanged4(
|
|
167737
|
-
await writeTextIfChanged4(
|
|
168245
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "core", "README.md"), renderMetaprojectCoreReadme());
|
|
168246
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "hooks", "README.md"), renderHooksReadme());
|
|
168247
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "skills", "project-rules", "README.md"), renderProjectRulesSkillReadme({ sources: ruleSources }));
|
|
167738
168248
|
await writeRoutingEntrypointPair(metaprojectRoot, {
|
|
167739
168249
|
enableGdgraph,
|
|
167740
168250
|
enableGdctx,
|
|
@@ -167758,7 +168268,7 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
167758
168268
|
}
|
|
167759
168269
|
});
|
|
167760
168270
|
console.log(` ${await describeModelChoiceStatus(projectRoot)}`);
|
|
167761
|
-
await writeTextIfChanged4(
|
|
168271
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "keryx-dashboard.html"), renderMetaprojectDashboardHtml({
|
|
167762
168272
|
enableGdgraph,
|
|
167763
168273
|
enableGdctx,
|
|
167764
168274
|
enableGdwiki,
|
|
@@ -167770,7 +168280,7 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
167770
168280
|
enableSecurity,
|
|
167771
168281
|
data: dashboardData
|
|
167772
168282
|
}));
|
|
167773
|
-
await writeTextIfMissing4(
|
|
168283
|
+
await writeTextIfMissing4(path322.join(metaprojectRoot, "README.md"), renderMetaprojectReadme({
|
|
167774
168284
|
enableGdgraph,
|
|
167775
168285
|
enableGdctx,
|
|
167776
168286
|
enableGdwiki,
|
|
@@ -167783,9 +168293,9 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
167783
168293
|
}));
|
|
167784
168294
|
if (enableGdgraph) {
|
|
167785
168295
|
await installGdgraphCoreScripts2(metaprojectRoot);
|
|
167786
|
-
await writeTextIfChanged4(
|
|
167787
|
-
await writeTextIfChanged4(
|
|
167788
|
-
await writeTextIfChanged4(
|
|
168296
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "modules", "gdgraph.md"), renderGdgraphManifest());
|
|
168297
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "core", "gdgraph", "README.md"), renderGdgraphCoreReadme());
|
|
168298
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "skills", "gdgraph", "SKILL.md"), renderGdgraphSkillReadme());
|
|
167789
168299
|
await seedAssetsLock(metaprojectRoot);
|
|
167790
168300
|
if (manifest.modules?.gdgraph?.hooks?.gitPostCommit) {
|
|
167791
168301
|
const warning = await installManagedHookOrWarn(projectRoot, "post-commit", "gdgraph-post-commit", renderGdgraphPostCommitHook());
|
|
@@ -167794,15 +168304,15 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
167794
168304
|
}
|
|
167795
168305
|
}
|
|
167796
168306
|
if (enableGdctx) {
|
|
167797
|
-
await writeTextIfMissing4(
|
|
167798
|
-
await writeTextIfChanged4(
|
|
167799
|
-
await writeTextIfChanged4(
|
|
167800
|
-
await writeTextIfChanged4(
|
|
168307
|
+
await writeTextIfMissing4(path322.join(metaprojectRoot, "gdctx.config.json"), renderGdctxConfig());
|
|
168308
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "modules", "gdctx.md"), renderGdctxManifest());
|
|
168309
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "core", "gdctx", "README.md"), renderGdctxCoreReadme());
|
|
168310
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "skills", "gdctx", "SKILL.md"), renderGdctxSkillReadme());
|
|
167801
168311
|
}
|
|
167802
168312
|
if (enableGdwiki) {
|
|
167803
|
-
await writeTextIfMissing4(
|
|
167804
|
-
await writeTextIfChanged4(
|
|
167805
|
-
await writeTextIfChanged4(
|
|
168313
|
+
await writeTextIfMissing4(path322.join(metaprojectRoot, "wiki", "templates", "page.md"), renderWikiPageTemplate());
|
|
168314
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "modules", "gdwiki.md"), renderGdwikiManifest());
|
|
168315
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "skills", "gdwiki", "SKILL.md"), renderGdwikiSkillReadme());
|
|
167806
168316
|
if (manifest.modules?.gdgraph?.hooks?.gitPostCommit) {
|
|
167807
168317
|
const warning = await installManagedHookOrWarn(projectRoot, "post-commit", "gdwiki-post-commit", renderGdwikiPostCommitHook());
|
|
167808
168318
|
if (warning)
|
|
@@ -167810,8 +168320,8 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
167810
168320
|
}
|
|
167811
168321
|
}
|
|
167812
168322
|
if (enableSac) {
|
|
167813
|
-
await writeTextIfMissing4(
|
|
167814
|
-
await writeTextIfChanged4(
|
|
168323
|
+
await writeTextIfMissing4(path322.join(metaprojectRoot, "modules", "sac.md"), renderSacManifest());
|
|
168324
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "skills", "sac", "SKILL.md"), renderSacSkillReadme());
|
|
167815
168325
|
}
|
|
167816
168326
|
let gdskillsWarnings = [];
|
|
167817
168327
|
let gdskillsNotices = [];
|
|
@@ -167826,10 +168336,10 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
167826
168336
|
}
|
|
167827
168337
|
}
|
|
167828
168338
|
if (enableHealth) {
|
|
167829
|
-
await writeTextIfMissing4(
|
|
167830
|
-
await writeTextIfChanged4(
|
|
167831
|
-
await writeTextIfChanged4(
|
|
167832
|
-
await writeTextIfChanged4(
|
|
168339
|
+
await writeTextIfMissing4(path322.join(metaprojectRoot, "health.config.json"), renderHealthConfig());
|
|
168340
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "modules", "health.md"), renderHealthManifest());
|
|
168341
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "core", "health", "README.md"), renderHealthCoreReadme());
|
|
168342
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "skills", "health", "SKILL.md"), renderHealthSkillReadme());
|
|
167833
168343
|
if (manifest.modules?.health?.hooks?.gitPostCommit) {
|
|
167834
168344
|
const warning = await installManagedHookOrWarn(projectRoot, "post-commit", "health-post-commit", renderHealthPostCommitHook());
|
|
167835
168345
|
if (warning)
|
|
@@ -167837,16 +168347,16 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
167837
168347
|
}
|
|
167838
168348
|
}
|
|
167839
168349
|
if (enableTesting) {
|
|
167840
|
-
await writeTextIfMissing4(
|
|
168350
|
+
await writeTextIfMissing4(path322.join(metaprojectRoot, "testing.config.json"), renderTestingConfig({
|
|
167841
168351
|
postCommitRefresh: Boolean(manifest.modules?.testing?.hooks?.gitPostCommit),
|
|
167842
168352
|
prePushGate: Boolean(manifest.modules?.testing?.hooks?.prePush)
|
|
167843
168353
|
}));
|
|
167844
|
-
await writeTextIfChanged4(
|
|
167845
|
-
await writeTextIfChanged4(
|
|
167846
|
-
await writeTextIfChanged4(
|
|
168354
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "modules", "testing.md"), renderTestingManifest());
|
|
168355
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "core", "testing", "README.md"), renderTestingCoreReadme());
|
|
168356
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "skills", "testing", "SKILL.md"), renderTestingSkillReadme());
|
|
167847
168357
|
if (enableGdwiki) {
|
|
167848
|
-
await writeTextIfMissing4(
|
|
167849
|
-
await writeTextIfMissing4(
|
|
168358
|
+
await writeTextIfMissing4(path322.join(metaprojectRoot, "wiki", "testing", "README.md"), renderTestingWikiReadme());
|
|
168359
|
+
await writeTextIfMissing4(path322.join(metaprojectRoot, "wiki", "testing", "conventions.md"), renderTestingWikiConventions());
|
|
167850
168360
|
}
|
|
167851
168361
|
if (manifest.modules?.testing?.hooks?.gitPostCommit) {
|
|
167852
168362
|
const warning = await installManagedHookOrWarn(projectRoot, "post-commit", "testing-post-commit", renderTestingPostCommitHook());
|
|
@@ -167865,24 +168375,24 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
167865
168375
|
hookWarnings.push(warning);
|
|
167866
168376
|
}
|
|
167867
168377
|
if (enableMemory) {
|
|
167868
|
-
await writeTextIfMissing4(
|
|
167869
|
-
await writeTextIfMissing4(
|
|
167870
|
-
await writeTextIfChanged4(
|
|
167871
|
-
await writeTextIfChanged4(
|
|
167872
|
-
await writeTextIfChanged4(
|
|
168378
|
+
await writeTextIfMissing4(path322.join(metaprojectRoot, "memory.config.json"), renderMemoryConfig());
|
|
168379
|
+
await writeTextIfMissing4(path322.join(metaprojectRoot, "memory", "templates", "entry.md"), renderMemoryEntryTemplate());
|
|
168380
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "modules", "memory.md"), renderMemoryManifest());
|
|
168381
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "core", "memory", "README.md"), renderMemoryCoreReadme());
|
|
168382
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "skills", "memory", "SKILL.md"), renderMemorySkillReadme());
|
|
167873
168383
|
}
|
|
167874
168384
|
if (enableTasks) {
|
|
167875
|
-
await writeTextIfChanged4(
|
|
167876
|
-
await writeTextIfChanged4(
|
|
167877
|
-
await writeTextIfChanged4(
|
|
167878
|
-
await writeTextIfChanged4(
|
|
167879
|
-
await writeTextIfChanged4(
|
|
167880
|
-
await writeTextIfChanged4(
|
|
168385
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "flows", "README.md"), renderFlowsReadme());
|
|
168386
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "modules", "tasks.md"), renderTasksManifest());
|
|
168387
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "skills", "flow", "SKILL.md"), renderFlowSkillRouter());
|
|
168388
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "skills", "flow", "init.md"), renderFlowInitSkill());
|
|
168389
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "skills", "flow", "manage.md"), renderFlowManageSkill());
|
|
168390
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "skills", "flow", "complete.md"), renderFlowCompleteSkill());
|
|
167881
168391
|
}
|
|
167882
168392
|
if (enableSecurity) {
|
|
167883
|
-
await writeTextIfMissing4(
|
|
167884
|
-
await writeTextIfChanged4(
|
|
167885
|
-
await writeTextIfChanged4(
|
|
168393
|
+
await writeTextIfMissing4(path322.join(metaprojectRoot, "security.config.json"), renderSecurityConfig());
|
|
168394
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "modules", "security.md"), renderSecurityManifest());
|
|
168395
|
+
await writeTextIfChanged4(path322.join(metaprojectRoot, "core", "security", "README.md"), renderSecurityCoreReadme());
|
|
167886
168396
|
if (manifest.modules?.security?.hooks?.prePush) {
|
|
167887
168397
|
const warning = await installManagedHookOrWarn(projectRoot, "pre-push", "security-pre-push", renderSecurityPrePushHook());
|
|
167888
168398
|
if (warning)
|
|
@@ -167940,13 +168450,13 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
167940
168450
|
};
|
|
167941
168451
|
}
|
|
167942
168452
|
async function buildDashboard(projectRoot = process.cwd()) {
|
|
167943
|
-
const metaprojectRoot =
|
|
168453
|
+
const metaprojectRoot = path322.join(projectRoot, ".metaproject");
|
|
167944
168454
|
if (!await pathExists(metaprojectRoot)) {
|
|
167945
168455
|
throw new Error("Metaproject is not initialized. Run: keryx init");
|
|
167946
168456
|
}
|
|
167947
168457
|
const manifest = (await readManifest5(metaprojectRoot)).manifest;
|
|
167948
168458
|
const data = await collectDashboardData(metaprojectRoot);
|
|
167949
|
-
const dashboardPath =
|
|
168459
|
+
const dashboardPath = path322.join(metaprojectRoot, "keryx-dashboard.html");
|
|
167950
168460
|
await writeTextIfChanged4(dashboardPath, renderMetaprojectDashboardHtml({
|
|
167951
168461
|
enableGdgraph: moduleEnabled2(manifest, "gdgraph"),
|
|
167952
168462
|
enableGdctx: moduleEnabled2(manifest, "gdctx"),
|
|
@@ -167966,7 +168476,7 @@ async function shouldInstallDashboardPostCommitHook(projectRoot, manifest) {
|
|
|
167966
168476
|
if (Object.values(modules).some((module) => Boolean(module.hooks?.gitPostCommit))) {
|
|
167967
168477
|
return true;
|
|
167968
168478
|
}
|
|
167969
|
-
const hookPath =
|
|
168479
|
+
const hookPath = path322.join(projectRoot, ".git", "hooks", "post-commit");
|
|
167970
168480
|
if (!await pathExists(hookPath)) {
|
|
167971
168481
|
return false;
|
|
167972
168482
|
}
|
|
@@ -167986,11 +168496,11 @@ async function collectDashboardData(metaprojectRoot) {
|
|
|
167986
168496
|
if (testing) {
|
|
167987
168497
|
data.testing = testing;
|
|
167988
168498
|
}
|
|
167989
|
-
const wiki = await collectMarkdownPages(
|
|
168499
|
+
const wiki = await collectMarkdownPages(path322.join(metaprojectRoot, "wiki"), "wiki");
|
|
167990
168500
|
if (wiki.length > 0) {
|
|
167991
168501
|
data.wiki = { pages: wiki };
|
|
167992
168502
|
}
|
|
167993
|
-
const memory = await collectMarkdownPages(
|
|
168503
|
+
const memory = await collectMarkdownPages(path322.join(metaprojectRoot, "memory"), "memory");
|
|
167994
168504
|
if (memory.length > 0) {
|
|
167995
168505
|
data.memory = { entries: memory };
|
|
167996
168506
|
}
|
|
@@ -168005,19 +168515,19 @@ async function collectDashboardData(metaprojectRoot) {
|
|
|
168005
168515
|
return data;
|
|
168006
168516
|
}
|
|
168007
168517
|
async function collectTasksDashboardData(metaprojectRoot) {
|
|
168008
|
-
const flowsRoot =
|
|
168518
|
+
const flowsRoot = path322.join(metaprojectRoot, "flows");
|
|
168009
168519
|
if (!await pathExists(flowsRoot)) {
|
|
168010
168520
|
return null;
|
|
168011
168521
|
}
|
|
168012
168522
|
let dirEntries;
|
|
168013
168523
|
try {
|
|
168014
|
-
dirEntries = (await
|
|
168524
|
+
dirEntries = (await readdir59(flowsRoot, { withFileTypes: true })).filter((entry) => entry.isDirectory() && /^\d{3}-/.test(entry.name)).map((entry) => entry.name).sort();
|
|
168015
168525
|
} catch {
|
|
168016
168526
|
return null;
|
|
168017
168527
|
}
|
|
168018
168528
|
const flows = [];
|
|
168019
168529
|
for (const dir of dirEntries) {
|
|
168020
|
-
const flowPath =
|
|
168530
|
+
const flowPath = path322.join(flowsRoot, dir, "flow.json");
|
|
168021
168531
|
if (!await pathExists(flowPath)) {
|
|
168022
168532
|
continue;
|
|
168023
168533
|
}
|
|
@@ -168025,7 +168535,7 @@ async function collectTasksDashboardData(metaprojectRoot) {
|
|
|
168025
168535
|
const flow = JSON.parse(await readFile164(flowPath, "utf8"));
|
|
168026
168536
|
const tasks = Array.isArray(flow.tasks) ? flow.tasks : [];
|
|
168027
168537
|
let acTotal = 0;
|
|
168028
|
-
const acPath =
|
|
168538
|
+
const acPath = path322.join(flowsRoot, dir, "acceptance-criteria.md");
|
|
168029
168539
|
if (await pathExists(acPath)) {
|
|
168030
168540
|
const acContent = await readFile164(acPath, "utf8");
|
|
168031
168541
|
acTotal = (acContent.match(/^- AC\d+:/gm) ?? []).length;
|
|
@@ -168079,7 +168589,7 @@ async function collectDashboardDocs(metaprojectRoot, wiki, memory) {
|
|
|
168079
168589
|
"data/testing/context.md"
|
|
168080
168590
|
];
|
|
168081
168591
|
for (const href of staticHrefs) {
|
|
168082
|
-
const filePath =
|
|
168592
|
+
const filePath = path322.join(metaprojectRoot, ...href.split("/"));
|
|
168083
168593
|
if (!await pathExists(filePath)) {
|
|
168084
168594
|
continue;
|
|
168085
168595
|
}
|
|
@@ -168096,7 +168606,7 @@ async function collectDashboardDocs(metaprojectRoot, wiki, memory) {
|
|
|
168096
168606
|
return docs;
|
|
168097
168607
|
}
|
|
168098
168608
|
async function collectHealthDashboardData(metaprojectRoot) {
|
|
168099
|
-
const reportPath =
|
|
168609
|
+
const reportPath = path322.join(metaprojectRoot, "data", "health", "artifacts", "latest.json");
|
|
168100
168610
|
if (!await pathExists(reportPath)) {
|
|
168101
168611
|
return;
|
|
168102
168612
|
}
|
|
@@ -168205,8 +168715,8 @@ function metricToScope(metric) {
|
|
|
168205
168715
|
};
|
|
168206
168716
|
}
|
|
168207
168717
|
async function collectGraphDashboardData(metaprojectRoot) {
|
|
168208
|
-
const nodesPath =
|
|
168209
|
-
const edgesPath =
|
|
168718
|
+
const nodesPath = path322.join(metaprojectRoot, "data", "gdgraph", "storage", "nodes.jsonl");
|
|
168719
|
+
const edgesPath = path322.join(metaprojectRoot, "data", "gdgraph", "storage", "edges.jsonl");
|
|
168210
168720
|
if (!await pathExists(nodesPath) || !await pathExists(edgesPath)) {
|
|
168211
168721
|
return;
|
|
168212
168722
|
}
|
|
@@ -168257,8 +168767,8 @@ async function collectGraphDashboardData(metaprojectRoot) {
|
|
|
168257
168767
|
};
|
|
168258
168768
|
}
|
|
168259
168769
|
async function collectTestingDashboardData(metaprojectRoot) {
|
|
168260
|
-
const reportPath =
|
|
168261
|
-
const contextPath =
|
|
168770
|
+
const reportPath = path322.join(metaprojectRoot, "data", "testing", "artifacts", "latest.json");
|
|
168771
|
+
const contextPath = path322.join(metaprojectRoot, "data", "testing", "context.md");
|
|
168262
168772
|
if (await pathExists(reportPath)) {
|
|
168263
168773
|
const report = JSON.parse(await readFile164(reportPath, "utf8"));
|
|
168264
168774
|
const totalTests = numberOrUndefined(report.total);
|
|
@@ -168287,7 +168797,7 @@ async function collectMarkdownPages(root, hrefPrefix) {
|
|
|
168287
168797
|
const files = await listMarkdownFiles(root);
|
|
168288
168798
|
const pages = [];
|
|
168289
168799
|
for (const filePath of files.slice(0, 40)) {
|
|
168290
|
-
const relativePath =
|
|
168800
|
+
const relativePath = path322.relative(root, filePath).split(path322.sep).join("/");
|
|
168291
168801
|
if (relativePath === "index.md" || relativePath.startsWith("templates/")) {
|
|
168292
168802
|
continue;
|
|
168293
168803
|
}
|
|
@@ -168305,10 +168815,10 @@ async function collectMarkdownPages(root, hrefPrefix) {
|
|
|
168305
168815
|
return pages;
|
|
168306
168816
|
}
|
|
168307
168817
|
async function listMarkdownFiles(root) {
|
|
168308
|
-
const entries = await
|
|
168818
|
+
const entries = await readdir59(root, { withFileTypes: true });
|
|
168309
168819
|
const files = [];
|
|
168310
168820
|
for (const entry of entries) {
|
|
168311
|
-
const fullPath =
|
|
168821
|
+
const fullPath = path322.join(root, entry.name);
|
|
168312
168822
|
if (entry.isDirectory()) {
|
|
168313
168823
|
files.push(...await listMarkdownFiles(fullPath));
|
|
168314
168824
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
@@ -168356,7 +168866,7 @@ async function writeRecoveredManifest(metaprojectRoot, modules) {
|
|
|
168356
168866
|
const manifest = {
|
|
168357
168867
|
schemaVersion: 1,
|
|
168358
168868
|
standardVersion: STANDARD_VERSION,
|
|
168359
|
-
name: `${
|
|
168869
|
+
name: `${path322.basename(path322.dirname(metaprojectRoot))}-metaproject`,
|
|
168360
168870
|
createdBy: "keryx",
|
|
168361
168871
|
profiles: computeProfiles(enabledModuleKeys),
|
|
168362
168872
|
paths: {
|
|
@@ -168447,13 +168957,13 @@ async function writeRecoveredManifest(metaprojectRoot, modules) {
|
|
|
168447
168957
|
}
|
|
168448
168958
|
};
|
|
168449
168959
|
{
|
|
168450
|
-
const { root, rel } = containFromMetaprojectPath(
|
|
168960
|
+
const { root, rel } = containFromMetaprojectPath(path322.join(metaprojectRoot, "metaproject.json"));
|
|
168451
168961
|
await writeContained(root, rel, `${JSON.stringify(manifest, null, 2)}
|
|
168452
168962
|
`);
|
|
168453
168963
|
}
|
|
168454
168964
|
}
|
|
168455
168965
|
async function enableTasksInManifest(metaprojectRoot) {
|
|
168456
|
-
const manifestPath =
|
|
168966
|
+
const manifestPath = path322.join(metaprojectRoot, "metaproject.json");
|
|
168457
168967
|
if (!await pathExists(manifestPath)) {
|
|
168458
168968
|
return;
|
|
168459
168969
|
}
|
|
@@ -168479,7 +168989,7 @@ async function enableTasksInManifest(metaprojectRoot) {
|
|
|
168479
168989
|
}
|
|
168480
168990
|
}
|
|
168481
168991
|
async function updateManifestAgentEntrypoints(metaprojectRoot, ruleSources) {
|
|
168482
|
-
const manifestPath =
|
|
168992
|
+
const manifestPath = path322.join(metaprojectRoot, "metaproject.json");
|
|
168483
168993
|
if (!await pathExists(manifestPath)) {
|
|
168484
168994
|
return;
|
|
168485
168995
|
}
|
|
@@ -168547,61 +169057,61 @@ async function updateRuntime(projectRoot) {
|
|
|
168547
169057
|
}
|
|
168548
169058
|
}
|
|
168549
169059
|
async function findRuntimeRoot(projectRoot) {
|
|
168550
|
-
const projectRuntime =
|
|
168551
|
-
if (await pathExists(
|
|
169060
|
+
const projectRuntime = path322.join(projectRoot, ".metaproject", "runtime", "keryx");
|
|
169061
|
+
if (await pathExists(path322.join(projectRuntime, ".git"))) {
|
|
168552
169062
|
return projectRuntime;
|
|
168553
169063
|
}
|
|
168554
169064
|
const home = process.env.HOME;
|
|
168555
169065
|
if (!home) {
|
|
168556
169066
|
return null;
|
|
168557
169067
|
}
|
|
168558
|
-
const globalRuntime =
|
|
168559
|
-
if (await pathExists(
|
|
169068
|
+
const globalRuntime = path322.join(home, ".keryx", "keryx");
|
|
169069
|
+
if (await pathExists(path322.join(globalRuntime, ".git"))) {
|
|
168560
169070
|
return globalRuntime;
|
|
168561
169071
|
}
|
|
168562
169072
|
return null;
|
|
168563
169073
|
}
|
|
168564
169074
|
async function createServiceDirs(metaprojectRoot, modules) {
|
|
168565
169075
|
const dirs = [
|
|
168566
|
-
|
|
168567
|
-
|
|
168568
|
-
|
|
168569
|
-
|
|
168570
|
-
|
|
169076
|
+
path322.join(metaprojectRoot, "core"),
|
|
169077
|
+
path322.join(metaprojectRoot, "hooks", "post-update.d"),
|
|
169078
|
+
path322.join(metaprojectRoot, "modules"),
|
|
169079
|
+
path322.join(metaprojectRoot, "rules"),
|
|
169080
|
+
path322.join(metaprojectRoot, "skills", "project-rules"),
|
|
168571
169081
|
...modules.enableGdgraph ? [
|
|
168572
|
-
|
|
168573
|
-
|
|
169082
|
+
path322.join(metaprojectRoot, "core", "gdgraph"),
|
|
169083
|
+
path322.join(metaprojectRoot, "skills", "gdgraph")
|
|
168574
169084
|
] : [],
|
|
168575
169085
|
...modules.enableGdctx ? [
|
|
168576
|
-
|
|
168577
|
-
|
|
169086
|
+
path322.join(metaprojectRoot, "core", "gdctx"),
|
|
169087
|
+
path322.join(metaprojectRoot, "skills", "gdctx")
|
|
168578
169088
|
] : [],
|
|
168579
169089
|
...modules.enableGdwiki ? [
|
|
168580
|
-
|
|
168581
|
-
|
|
169090
|
+
path322.join(metaprojectRoot, "skills", "gdwiki"),
|
|
169091
|
+
path322.join(metaprojectRoot, "wiki", "templates")
|
|
168582
169092
|
] : [],
|
|
168583
169093
|
...modules.enableHealth ? [
|
|
168584
|
-
|
|
168585
|
-
|
|
169094
|
+
path322.join(metaprojectRoot, "core", "health"),
|
|
169095
|
+
path322.join(metaprojectRoot, "skills", "health")
|
|
168586
169096
|
] : [],
|
|
168587
169097
|
...modules.enableTesting ? [
|
|
168588
|
-
|
|
168589
|
-
|
|
169098
|
+
path322.join(metaprojectRoot, "core", "testing"),
|
|
169099
|
+
path322.join(metaprojectRoot, "skills", "testing")
|
|
168590
169100
|
] : [],
|
|
168591
169101
|
...modules.enableMemory ? [
|
|
168592
|
-
|
|
168593
|
-
|
|
168594
|
-
|
|
169102
|
+
path322.join(metaprojectRoot, "core", "memory"),
|
|
169103
|
+
path322.join(metaprojectRoot, "skills", "memory"),
|
|
169104
|
+
path322.join(metaprojectRoot, "memory", "templates")
|
|
168595
169105
|
] : [],
|
|
168596
169106
|
...modules.enableTasks ? [
|
|
168597
|
-
|
|
168598
|
-
|
|
169107
|
+
path322.join(metaprojectRoot, "flows"),
|
|
169108
|
+
path322.join(metaprojectRoot, "skills", "flow")
|
|
168599
169109
|
] : [],
|
|
168600
169110
|
...modules.enableSecurity ? [
|
|
168601
|
-
|
|
169111
|
+
path322.join(metaprojectRoot, "core", "security")
|
|
168602
169112
|
] : [],
|
|
168603
169113
|
...modules.enableSac ? [
|
|
168604
|
-
|
|
169114
|
+
path322.join(metaprojectRoot, "skills", "sac")
|
|
168605
169115
|
] : []
|
|
168606
169116
|
];
|
|
168607
169117
|
await Promise.all(dirs.map((dir) => {
|
|
@@ -168610,22 +169120,22 @@ async function createServiceDirs(metaprojectRoot, modules) {
|
|
|
168610
169120
|
}));
|
|
168611
169121
|
}
|
|
168612
169122
|
async function installGdgraphCoreScripts2(metaprojectRoot) {
|
|
168613
|
-
const gdgraphCoreRoot =
|
|
169123
|
+
const gdgraphCoreRoot = path322.join(metaprojectRoot, "core", "gdgraph");
|
|
168614
169124
|
{
|
|
168615
169125
|
const { root, rel } = containFromMetaprojectPath(gdgraphCoreRoot);
|
|
168616
169126
|
await mkdirContained(root, rel);
|
|
168617
169127
|
}
|
|
168618
169128
|
for (const file of GDGRAPH_CORE_SOURCES) {
|
|
168619
|
-
await copyFileIfChanged2(runtimeSourcePath2(`../gdgraph/${file}`),
|
|
169129
|
+
await copyFileIfChanged2(runtimeSourcePath2(`../gdgraph/${file}`), path322.join(gdgraphCoreRoot, file));
|
|
168620
169130
|
}
|
|
168621
|
-
await writeTextIfChanged4(
|
|
169131
|
+
await writeTextIfChanged4(path322.join(gdgraphCoreRoot, "cli.ts"), renderGdgraphCoreCli());
|
|
168622
169132
|
}
|
|
168623
169133
|
async function prePushHasSecurityBlock2(projectRoot) {
|
|
168624
169134
|
const hooksRoot = await resolveGitHooksRoot(projectRoot);
|
|
168625
169135
|
if (!hooksRoot) {
|
|
168626
169136
|
return false;
|
|
168627
169137
|
}
|
|
168628
|
-
const hookPath =
|
|
169138
|
+
const hookPath = path322.join(hooksRoot, "pre-push");
|
|
168629
169139
|
if (!await pathExists(hookPath)) {
|
|
168630
169140
|
return false;
|
|
168631
169141
|
}
|
|
@@ -168640,7 +169150,7 @@ async function agentSettingsHasSecuritySentinel2(projectRoot) {
|
|
|
168640
169150
|
return (await readFile164(file, "utf8")).includes(AGENT_HOOKS_SENTINEL);
|
|
168641
169151
|
}
|
|
168642
169152
|
async function readManifest5(metaprojectRoot) {
|
|
168643
|
-
const manifestPath =
|
|
169153
|
+
const manifestPath = path322.join(metaprojectRoot, "metaproject.json");
|
|
168644
169154
|
if (!await pathExists(manifestPath)) {
|
|
168645
169155
|
return {
|
|
168646
169156
|
exists: false,
|
|
@@ -168709,7 +169219,7 @@ async function inferManifestFromExistingMetaproject(metaprojectRoot) {
|
|
|
168709
169219
|
}
|
|
168710
169220
|
async function anyPathExists(root, candidates) {
|
|
168711
169221
|
for (const candidate of candidates) {
|
|
168712
|
-
if (await pathExists(
|
|
169222
|
+
if (await pathExists(path322.join(root, candidate))) {
|
|
168713
169223
|
return true;
|
|
168714
169224
|
}
|
|
168715
169225
|
}
|
|
@@ -168732,13 +169242,13 @@ function parseUpdateArgs(args) {
|
|
|
168732
169242
|
};
|
|
168733
169243
|
}
|
|
168734
169244
|
async function runPostUpdateHooks(projectRoot) {
|
|
168735
|
-
const hooksDir =
|
|
169245
|
+
const hooksDir = path322.join(projectRoot, ".metaproject", "hooks", "post-update.d");
|
|
168736
169246
|
if (!await pathExists(hooksDir)) {
|
|
168737
169247
|
return;
|
|
168738
169248
|
}
|
|
168739
|
-
const entries = (await
|
|
169249
|
+
const entries = (await readdir59(hooksDir)).sort();
|
|
168740
169250
|
for (const entry of entries) {
|
|
168741
|
-
const hookPath =
|
|
169251
|
+
const hookPath = path322.join(hooksDir, entry);
|
|
168742
169252
|
try {
|
|
168743
169253
|
await accessExecutable(hookPath);
|
|
168744
169254
|
} catch {
|
|
@@ -168799,12 +169309,12 @@ async function copyFileIfChanged2(from, to) {
|
|
|
168799
169309
|
}
|
|
168800
169310
|
function runtimeSourcePath2(relativePath) {
|
|
168801
169311
|
const directPath = fileURLToPath10(new URL(relativePath, import.meta.url));
|
|
168802
|
-
if (
|
|
169312
|
+
if (existsSync51(directPath)) {
|
|
168803
169313
|
return directPath;
|
|
168804
169314
|
}
|
|
168805
169315
|
if (relativePath.startsWith("../")) {
|
|
168806
|
-
const packagedSourcePath =
|
|
168807
|
-
if (
|
|
169316
|
+
const packagedSourcePath = path322.join(path322.dirname(fileURLToPath10(import.meta.url)), "..", "src", relativePath.slice(3));
|
|
169317
|
+
if (existsSync51(packagedSourcePath)) {
|
|
168808
169318
|
return packagedSourcePath;
|
|
168809
169319
|
}
|
|
168810
169320
|
}
|
|
@@ -168835,7 +169345,7 @@ function printHelp24() {
|
|
|
168835
169345
|
|
|
168836
169346
|
// src/commands/dashboard.ts
|
|
168837
169347
|
import { spawn as spawn10 } from "child_process";
|
|
168838
|
-
import
|
|
169348
|
+
import path323 from "path";
|
|
168839
169349
|
init_args();
|
|
168840
169350
|
init_ui();
|
|
168841
169351
|
async function dashboardCommand(args = []) {
|
|
@@ -168847,7 +169357,7 @@ async function dashboardCommand(args = []) {
|
|
|
168847
169357
|
}
|
|
168848
169358
|
if (subcommand === "build") {
|
|
168849
169359
|
const result = await buildDashboard();
|
|
168850
|
-
const rel =
|
|
169360
|
+
const rel = path323.relative(process.cwd(), result.path);
|
|
168851
169361
|
console.log(` ${style.green(symbols.ok)} Dashboard built ${style.cyan(symbols.arrow)} ${style.cyan(rel)}`);
|
|
168852
169362
|
note(`Open it: keryx dashboard open`);
|
|
168853
169363
|
return;
|
|
@@ -168855,7 +169365,7 @@ async function dashboardCommand(args = []) {
|
|
|
168855
169365
|
if (subcommand === "open") {
|
|
168856
169366
|
const result = await buildDashboard();
|
|
168857
169367
|
await openFile(result.path);
|
|
168858
|
-
const rel =
|
|
169368
|
+
const rel = path323.relative(process.cwd(), result.path);
|
|
168859
169369
|
console.log(` ${style.green(symbols.ok)} Opened ${style.cyan(rel)}`);
|
|
168860
169370
|
return;
|
|
168861
169371
|
}
|
|
@@ -168906,7 +169416,7 @@ import { readFileSync as readFileSync27 } from "fs";
|
|
|
168906
169416
|
import { randomUUID as randomUUID46 } from "crypto";
|
|
168907
169417
|
import { mkdir as mkdir69 } from "fs/promises";
|
|
168908
169418
|
import { tmpdir as tmpdir12 } from "os";
|
|
168909
|
-
import
|
|
169419
|
+
import path324 from "path";
|
|
168910
169420
|
import { createInterface as createInterface3 } from "readline";
|
|
168911
169421
|
|
|
168912
169422
|
// src/harness/external-agent-probe.ts
|
|
@@ -169168,7 +169678,7 @@ async function runCommand4(args, deps, log) {
|
|
|
169168
169678
|
const requestApproval = unattended ? undefined : seams.requestApproval ?? terminalApprover();
|
|
169169
169679
|
const timeoutRaw = optionValue(args, "--timeout");
|
|
169170
169680
|
const timeoutMs = timeoutRaw !== undefined && Number.isInteger(Number(timeoutRaw)) && Number(timeoutRaw) > 0 ? Number(timeoutRaw) : gate.config.defaultTimeoutMs;
|
|
169171
|
-
const worktreesDir =
|
|
169681
|
+
const worktreesDir = path324.join(tmpdir12(), "keryx-external-worktrees");
|
|
169172
169682
|
const worktree = seams.worktree ?? createGitWorktreePort({ repoRoot: cwd, worktreesDir });
|
|
169173
169683
|
if (seams.worktree === undefined)
|
|
169174
169684
|
await mkdir69(worktreesDir, { recursive: true });
|
|
@@ -169256,8 +169766,8 @@ init_service8();
|
|
|
169256
169766
|
init_bundled_eval();
|
|
169257
169767
|
init_args();
|
|
169258
169768
|
init_ui();
|
|
169259
|
-
import { existsSync as
|
|
169260
|
-
import
|
|
169769
|
+
import { existsSync as existsSync52, lstatSync as lstatSync7, readFileSync as readFileSync26, writeFileSync as writeFileSync11 } from "fs";
|
|
169770
|
+
import path325 from "path";
|
|
169261
169771
|
function resolveDeps(deps) {
|
|
169262
169772
|
return {
|
|
169263
169773
|
cwd: deps.cwd ?? process.cwd(),
|
|
@@ -169590,11 +170100,11 @@ function generateCommand(args, depsIn) {
|
|
|
169590
170100
|
process.exitCode = 1;
|
|
169591
170101
|
return;
|
|
169592
170102
|
}
|
|
169593
|
-
const bundledAgentsRoot =
|
|
169594
|
-
const stacksRoot =
|
|
169595
|
-
const packDir =
|
|
169596
|
-
const packJsonPath =
|
|
169597
|
-
if (!
|
|
170103
|
+
const bundledAgentsRoot = path325.join(depsIn.bundledRoot ?? defaultBundledRoot(), "agents");
|
|
170104
|
+
const stacksRoot = path325.join(bundledAgentsRoot, "..", "stacks");
|
|
170105
|
+
const packDir = path325.join(stacksRoot, stackId);
|
|
170106
|
+
const packJsonPath = path325.join(packDir, "pack.json");
|
|
170107
|
+
if (!existsSync52(packJsonPath)) {
|
|
169598
170108
|
error(`No stack pack "${stackId}" found at ${packJsonPath}.`);
|
|
169599
170109
|
process.exitCode = 1;
|
|
169600
170110
|
return;
|
|
@@ -169640,9 +170150,9 @@ function generateCommand(args, depsIn) {
|
|
|
169640
170150
|
}
|
|
169641
170151
|
const prepared = [];
|
|
169642
170152
|
for (const file of generatedFiles) {
|
|
169643
|
-
const filePath =
|
|
169644
|
-
const relative =
|
|
169645
|
-
if (relative.startsWith("..") ||
|
|
170153
|
+
const filePath = path325.join(bundledAgentsRoot, file.fileName);
|
|
170154
|
+
const relative = path325.relative(bundledAgentsRoot, filePath);
|
|
170155
|
+
if (relative.startsWith("..") || path325.isAbsolute(relative)) {
|
|
169646
170156
|
error(`Refusing to write "${file.fileName}": it resolves outside the bundled agents directory.`);
|
|
169647
170157
|
process.exitCode = 1;
|
|
169648
170158
|
return;
|
|
@@ -169963,7 +170473,7 @@ function printBootstrapHelp() {
|
|
|
169963
170473
|
// src/commands/metrics.ts
|
|
169964
170474
|
init_args();
|
|
169965
170475
|
import { readFile as readFile165 } from "fs/promises";
|
|
169966
|
-
import
|
|
170476
|
+
import path327 from "path";
|
|
169967
170477
|
|
|
169968
170478
|
// src/metrics/benchmark.ts
|
|
169969
170479
|
var RELIABILITIES2 = new Set(["exact", "estimated", "unknown"]);
|
|
@@ -170780,7 +171290,7 @@ function buildContainmentManifest(inputs, options = {}) {
|
|
|
170780
171290
|
|
|
170781
171291
|
// src/metrics/oracle-runner.ts
|
|
170782
171292
|
import { mkdir as mkdir70, writeFile as writeFile48 } from "fs/promises";
|
|
170783
|
-
import
|
|
171293
|
+
import path326 from "path";
|
|
170784
171294
|
|
|
170785
171295
|
// src/metrics/ir.ts
|
|
170786
171296
|
function toIdSet(ids) {
|
|
@@ -171226,9 +171736,9 @@ function buildEvidenceBundle(input, options = {}) {
|
|
|
171226
171736
|
async function persistEvidenceBundle(outDir, bundle, ladder = "metastore") {
|
|
171227
171737
|
const safeTarget = bundle.target.replace(/[^A-Za-z0-9._/-]/g, "_");
|
|
171228
171738
|
const safeCase = bundle.caseId.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
171229
|
-
const dir =
|
|
171739
|
+
const dir = path326.join(outDir, "bench", ladder, safeTarget, safeCase, bundle.variant, String(bundle.seed));
|
|
171230
171740
|
await mkdir70(dir, { recursive: true });
|
|
171231
|
-
const write = (name, value) => writeFile48(
|
|
171741
|
+
const write = (name, value) => writeFile48(path326.join(dir, name), `${JSON.stringify(value, null, 2)}
|
|
171232
171742
|
`, "utf8");
|
|
171233
171743
|
await Promise.all([
|
|
171234
171744
|
write("inputs.json", bundle.inputs),
|
|
@@ -171268,7 +171778,7 @@ async function metricsCommand(args = [], projectRoot = process.cwd()) {
|
|
|
171268
171778
|
console.log("# metrics status");
|
|
171269
171779
|
console.log("");
|
|
171270
171780
|
console.log(`root: ${root}`);
|
|
171271
|
-
console.log(`enabled: ${await Bun.file(
|
|
171781
|
+
console.log(`enabled: ${await Bun.file(path327.join(projectRoot, ".metaproject", "metaproject.json")).exists() ? "yes" : "no"}`);
|
|
171272
171782
|
const latest = await readLatestPointer(root);
|
|
171273
171783
|
console.log(`latest: ${latest.status}`);
|
|
171274
171784
|
return;
|
|
@@ -171280,7 +171790,7 @@ async function metricsCommand(args = [], projectRoot = process.cwd()) {
|
|
|
171280
171790
|
process.exitCode = 1;
|
|
171281
171791
|
return;
|
|
171282
171792
|
}
|
|
171283
|
-
const record = JSON.parse(await readFile165(
|
|
171793
|
+
const record = JSON.parse(await readFile165(path327.resolve(projectRoot, file), "utf8"));
|
|
171284
171794
|
const result = validateRunRecord(record);
|
|
171285
171795
|
console.log(result.valid ? "valid: yes" : "valid: no");
|
|
171286
171796
|
for (const error of result.errors)
|
|
@@ -171305,7 +171815,7 @@ async function metricsCommand(args = [], projectRoot = process.cwd()) {
|
|
|
171305
171815
|
process.exitCode = 1;
|
|
171306
171816
|
return;
|
|
171307
171817
|
}
|
|
171308
|
-
const file =
|
|
171818
|
+
const file = path327.join(metricsRoot(projectRoot), "runs", `${runId}.json`);
|
|
171309
171819
|
if (!await Bun.file(file).exists()) {
|
|
171310
171820
|
console.error(`Run not found: ${runId}`);
|
|
171311
171821
|
process.exitCode = 1;
|
|
@@ -171322,8 +171832,8 @@ async function metricsCommand(args = [], projectRoot = process.cwd()) {
|
|
|
171322
171832
|
process.exitCode = 1;
|
|
171323
171833
|
return;
|
|
171324
171834
|
}
|
|
171325
|
-
const a = JSON.parse(await readFile165(
|
|
171326
|
-
const b = JSON.parse(await readFile165(
|
|
171835
|
+
const a = JSON.parse(await readFile165(path327.join(metricsRoot(projectRoot), "runs", `${runA}.json`), "utf8"));
|
|
171836
|
+
const b = JSON.parse(await readFile165(path327.join(metricsRoot(projectRoot), "runs", `${runB}.json`), "utf8"));
|
|
171327
171837
|
const comparison = compareExecutionRuns(a, b);
|
|
171328
171838
|
console.log(stableJson(comparison));
|
|
171329
171839
|
return;
|
|
@@ -171357,8 +171867,8 @@ async function metricsCommand(args = [], projectRoot = process.cwd()) {
|
|
|
171357
171867
|
return;
|
|
171358
171868
|
}
|
|
171359
171869
|
const template = createPairedBenchmarkTemplate(taskIds);
|
|
171360
|
-
await Bun.write(
|
|
171361
|
-
console.log(`manifest: ${
|
|
171870
|
+
await Bun.write(path327.resolve(projectRoot, out), stableJson(template));
|
|
171871
|
+
console.log(`manifest: ${path327.relative(projectRoot, path327.resolve(projectRoot, out))}`);
|
|
171362
171872
|
return;
|
|
171363
171873
|
}
|
|
171364
171874
|
if (subcommand === "benchmark" && args[1] === "run") {
|
|
@@ -171372,7 +171882,7 @@ async function metricsCommand(args = [], projectRoot = process.cwd()) {
|
|
|
171372
171882
|
process.exitCode = 1;
|
|
171373
171883
|
return;
|
|
171374
171884
|
}
|
|
171375
|
-
const raw = JSON.parse(await readFile165(
|
|
171885
|
+
const raw = JSON.parse(await readFile165(path327.resolve(projectRoot, file), "utf8"));
|
|
171376
171886
|
const input = Array.isArray(raw) ? raw : raw.runs ?? [];
|
|
171377
171887
|
const result = validatePairedBenchmark(input);
|
|
171378
171888
|
console.log(stableJson(result));
|
|
@@ -171384,7 +171894,7 @@ async function metricsCommand(args = [], projectRoot = process.cwd()) {
|
|
|
171384
171894
|
process.exitCode = 1;
|
|
171385
171895
|
}
|
|
171386
171896
|
async function loadAffectedSets(projectRoot, file) {
|
|
171387
|
-
const raw = JSON.parse(await readFile165(
|
|
171897
|
+
const raw = JSON.parse(await readFile165(path327.resolve(projectRoot, file), "utf8"));
|
|
171388
171898
|
const map = new Map;
|
|
171389
171899
|
for (const entry of raw.targets ?? []) {
|
|
171390
171900
|
if (typeof entry.target === "string")
|
|
@@ -171455,7 +171965,7 @@ async function runHarnessLayer(projectRoot, args, ladder) {
|
|
|
171455
171965
|
let tasks;
|
|
171456
171966
|
let model;
|
|
171457
171967
|
try {
|
|
171458
|
-
const raw = JSON.parse(await readFile165(
|
|
171968
|
+
const raw = JSON.parse(await readFile165(path327.resolve(projectRoot, resultsPath), "utf8"));
|
|
171459
171969
|
tasks = raw.tasks ?? [];
|
|
171460
171970
|
model = raw.model;
|
|
171461
171971
|
} catch (error) {
|
|
@@ -171486,7 +171996,7 @@ async function runSafetyCompletionHonestyLayer(projectRoot, args, ladder) {
|
|
|
171486
171996
|
let cases;
|
|
171487
171997
|
let model;
|
|
171488
171998
|
try {
|
|
171489
|
-
const raw = JSON.parse(await readFile165(
|
|
171999
|
+
const raw = JSON.parse(await readFile165(path327.resolve(projectRoot, resultsPath), "utf8"));
|
|
171490
172000
|
cases = raw.cases ?? [];
|
|
171491
172001
|
model = raw.model;
|
|
171492
172002
|
} catch (error) {
|
|
@@ -171511,7 +172021,7 @@ async function runSafetyFalsePremiseLayer(projectRoot, args, ladder) {
|
|
|
171511
172021
|
let cases;
|
|
171512
172022
|
let model;
|
|
171513
172023
|
try {
|
|
171514
|
-
const raw = JSON.parse(await readFile165(
|
|
172024
|
+
const raw = JSON.parse(await readFile165(path327.resolve(projectRoot, resultsPath), "utf8"));
|
|
171515
172025
|
cases = raw.cases ?? [];
|
|
171516
172026
|
model = raw.model;
|
|
171517
172027
|
} catch (error) {
|
|
@@ -171536,7 +172046,7 @@ async function runSafetyContainmentLayer(projectRoot, args, ladder, caseClass) {
|
|
|
171536
172046
|
let cases;
|
|
171537
172047
|
let model;
|
|
171538
172048
|
try {
|
|
171539
|
-
const raw = JSON.parse(await readFile165(
|
|
172049
|
+
const raw = JSON.parse(await readFile165(path327.resolve(projectRoot, resultsPath), "utf8"));
|
|
171540
172050
|
cases = raw.cases ?? [];
|
|
171541
172051
|
model = raw.model;
|
|
171542
172052
|
} catch (error) {
|
|
@@ -171598,12 +172108,12 @@ async function runGdgraphLayer(projectRoot, args, ladder) {
|
|
|
171598
172108
|
}
|
|
171599
172109
|
const manifests = buildOracleManifestsByGold(inputs, { ladder });
|
|
171600
172110
|
if (outDir) {
|
|
171601
|
-
const resolvedOut =
|
|
172111
|
+
const resolvedOut = path327.resolve(projectRoot, outDir);
|
|
171602
172112
|
for (const input of inputs) {
|
|
171603
172113
|
for (const named of input.golds) {
|
|
171604
172114
|
const bundle = buildEvidenceBundle({ target: input.target, system: input.system, gold: named.gold }, { ladder, goldReference: goldPathFor(named.kind), timestamp: new Date().toISOString() });
|
|
171605
|
-
const dir = await persistEvidenceBundle(
|
|
171606
|
-
console.error(`bundle[${named.kind}]: ${
|
|
172115
|
+
const dir = await persistEvidenceBundle(path327.join(resolvedOut, named.kind), bundle, ladder);
|
|
172116
|
+
console.error(`bundle[${named.kind}]: ${path327.relative(projectRoot, dir)}`);
|
|
171607
172117
|
}
|
|
171608
172118
|
}
|
|
171609
172119
|
}
|
|
@@ -171627,7 +172137,7 @@ async function runGdgraphLayer(projectRoot, args, ladder) {
|
|
|
171627
172137
|
return allValid;
|
|
171628
172138
|
}
|
|
171629
172139
|
async function loadCoverageMap2(projectRoot, file) {
|
|
171630
|
-
const raw = JSON.parse(await readFile165(
|
|
172140
|
+
const raw = JSON.parse(await readFile165(path327.resolve(projectRoot, file), "utf8"));
|
|
171631
172141
|
return raw.coverageMap ?? {};
|
|
171632
172142
|
}
|
|
171633
172143
|
async function runTestingLayer(projectRoot, args, ladder) {
|
|
@@ -171664,7 +172174,7 @@ async function runTestingLayer(projectRoot, args, ladder) {
|
|
|
171664
172174
|
return result.valid;
|
|
171665
172175
|
}
|
|
171666
172176
|
async function loadMemoryGoldK(projectRoot, file) {
|
|
171667
|
-
const raw = JSON.parse(await readFile165(
|
|
172177
|
+
const raw = JSON.parse(await readFile165(path327.resolve(projectRoot, file), "utf8"));
|
|
171668
172178
|
return typeof raw.k === "number" && raw.k > 0 ? raw.k : 3;
|
|
171669
172179
|
}
|
|
171670
172180
|
async function runMemoryLayer(projectRoot, args, ladder) {
|
|
@@ -171701,11 +172211,11 @@ async function runMemoryLayer(projectRoot, args, ladder) {
|
|
|
171701
172211
|
return result.valid;
|
|
171702
172212
|
}
|
|
171703
172213
|
async function loadWikiGoldK(projectRoot, file) {
|
|
171704
|
-
const raw = JSON.parse(await readFile165(
|
|
172214
|
+
const raw = JSON.parse(await readFile165(path327.resolve(projectRoot, file), "utf8"));
|
|
171705
172215
|
return typeof raw.k === "number" && raw.k > 0 ? raw.k : 5;
|
|
171706
172216
|
}
|
|
171707
172217
|
async function loadWikiGroundedness(projectRoot, file) {
|
|
171708
|
-
const raw = JSON.parse(await readFile165(
|
|
172218
|
+
const raw = JSON.parse(await readFile165(path327.resolve(projectRoot, file), "utf8"));
|
|
171709
172219
|
const map = new Map;
|
|
171710
172220
|
for (const entry of raw.targets ?? []) {
|
|
171711
172221
|
if (typeof entry.target !== "string" || !Array.isArray(entry.scores) || entry.scores.length !== 3)
|
|
@@ -171761,7 +172271,7 @@ async function runWikiLayer(projectRoot, args, ladder) {
|
|
|
171761
172271
|
return result.valid;
|
|
171762
172272
|
}
|
|
171763
172273
|
async function loadGdctxFacts(projectRoot, file) {
|
|
171764
|
-
const raw = JSON.parse(await readFile165(
|
|
172274
|
+
const raw = JSON.parse(await readFile165(path327.resolve(projectRoot, file), "utf8"));
|
|
171765
172275
|
const inputs = [];
|
|
171766
172276
|
for (const entry of raw.inputs ?? []) {
|
|
171767
172277
|
if (typeof entry.input === "string") {
|
|
@@ -171799,7 +172309,7 @@ async function collect(projectRoot, args) {
|
|
|
171799
172309
|
process.exitCode = 1;
|
|
171800
172310
|
return;
|
|
171801
172311
|
}
|
|
171802
|
-
const raw = JSON.parse(await readFile165(
|
|
172312
|
+
const raw = JSON.parse(await readFile165(path327.resolve(projectRoot, eventFile), "utf8"));
|
|
171803
172313
|
const events = Array.isArray(raw) ? raw : raw.events;
|
|
171804
172314
|
const startedAt = optionValue(args, "--started-at") ?? events[0]?.timestamp_utc ?? new Date().toISOString();
|
|
171805
172315
|
const finishedAt = optionValue(args, "--finished-at") ?? events.at(-1)?.timestamp_utc ?? startedAt;
|
|
@@ -171815,11 +172325,11 @@ async function collect(projectRoot, args) {
|
|
|
171815
172325
|
parentRunId: optionValue(args, "--parent-run-id") ?? null
|
|
171816
172326
|
});
|
|
171817
172327
|
const result = await writeRunArtifacts(metricsRoot(projectRoot), record, { cwd: projectRoot });
|
|
171818
|
-
console.log(`json: ${
|
|
171819
|
-
console.log(`markdown: ${
|
|
172328
|
+
console.log(`json: ${path327.relative(projectRoot, result.jsonPath)}`);
|
|
172329
|
+
console.log(`markdown: ${path327.relative(projectRoot, result.markdownPath)}`);
|
|
171820
172330
|
}
|
|
171821
172331
|
function metricsRoot(projectRoot) {
|
|
171822
|
-
return
|
|
172332
|
+
return path327.join(projectRoot, ".metaproject", "data", "metrics");
|
|
171823
172333
|
}
|
|
171824
172334
|
function printMetricsHelp() {
|
|
171825
172335
|
console.log(`keryx metrics
|
|
@@ -173236,8 +173746,8 @@ init_contained_write();
|
|
|
173236
173746
|
init_prompt();
|
|
173237
173747
|
init_terminal_safe();
|
|
173238
173748
|
init_agent_hooks();
|
|
173239
|
-
import { existsSync as
|
|
173240
|
-
import
|
|
173749
|
+
import { existsSync as existsSync53, readFileSync as readFileSync28 } from "fs";
|
|
173750
|
+
import path328 from "path";
|
|
173241
173751
|
init_hooks();
|
|
173242
173752
|
init_package();
|
|
173243
173753
|
var CLI_VERSION = package_default.version;
|
|
@@ -173253,10 +173763,10 @@ function optConfigDir(deps) {
|
|
|
173253
173763
|
return deps.configDir !== undefined ? { configDir: deps.configDir } : {};
|
|
173254
173764
|
}
|
|
173255
173765
|
function userHooksPath(homeDir) {
|
|
173256
|
-
return
|
|
173766
|
+
return path328.join(homeDir, ".keryx", "hooks.json");
|
|
173257
173767
|
}
|
|
173258
173768
|
function projectHooksPath(projectRoot) {
|
|
173259
|
-
return
|
|
173769
|
+
return path328.join(projectRoot, ".metaproject", "hooks.json");
|
|
173260
173770
|
}
|
|
173261
173771
|
function fail3(message) {
|
|
173262
173772
|
console.error(message);
|
|
@@ -173377,10 +173887,10 @@ async function runList6(args, deps) {
|
|
|
173377
173887
|
function argv0Resolves(argv0) {
|
|
173378
173888
|
if (argv0 === "keryx")
|
|
173379
173889
|
return true;
|
|
173380
|
-
if (
|
|
173381
|
-
return
|
|
173890
|
+
if (path328.isAbsolute(argv0))
|
|
173891
|
+
return existsSync53(argv0);
|
|
173382
173892
|
const pathEnv = process.env.PATH ?? "";
|
|
173383
|
-
return pathEnv.split(
|
|
173893
|
+
return pathEnv.split(path328.delimiter).filter((dir) => dir.length > 0).some((dir) => existsSync53(path328.join(dir, argv0)));
|
|
173384
173894
|
}
|
|
173385
173895
|
function checkArgvResolutions(registrations) {
|
|
173386
173896
|
const seen = new Set;
|
|
@@ -173835,8 +174345,8 @@ async function writeDocAtomic(filePath, doc, scope, cwd, homeDir) {
|
|
|
173835
174345
|
if (scope === "project") {
|
|
173836
174346
|
await writeContained(cwd, PROJECT_HOOKS_REL, body);
|
|
173837
174347
|
} else {
|
|
173838
|
-
const userConfigDir =
|
|
173839
|
-
if (!
|
|
174348
|
+
const userConfigDir = path328.join(homeDir, ".keryx");
|
|
174349
|
+
if (!existsSync53(userConfigDir)) {
|
|
173840
174350
|
await mkdirContained(homeDir, ".keryx");
|
|
173841
174351
|
}
|
|
173842
174352
|
await writeContained(userConfigDir, "hooks.json", body);
|
|
@@ -174093,7 +174603,7 @@ init_ui();
|
|
|
174093
174603
|
init_args();
|
|
174094
174604
|
init_contained_path();
|
|
174095
174605
|
init_package();
|
|
174096
|
-
import
|
|
174606
|
+
import path337 from "path";
|
|
174097
174607
|
|
|
174098
174608
|
// src/bundle/types.ts
|
|
174099
174609
|
var BUNDLE_FORMAT_VERSION = "1.0.0";
|
|
@@ -174147,13 +174657,13 @@ init_contained_path();
|
|
|
174147
174657
|
init_keryx_home();
|
|
174148
174658
|
init_types3();
|
|
174149
174659
|
import { lstat as lstat18, readFile as readFile166 } from "fs/promises";
|
|
174150
|
-
import
|
|
174660
|
+
import path329 from "path";
|
|
174151
174661
|
var MEMORY_FOLDERS = new Set(MEMORY_TYPES.map((entry) => entry.folder));
|
|
174152
174662
|
function scopeRoot(scope, ctx) {
|
|
174153
174663
|
if (scope === "user") {
|
|
174154
174664
|
return userStoreRoot(ctx.env ?? process.env, ctx.homeDir);
|
|
174155
174665
|
}
|
|
174156
|
-
return
|
|
174666
|
+
return path329.join(ctx.projectRoot, ".metaproject");
|
|
174157
174667
|
}
|
|
174158
174668
|
var CONTROL_CHAR_RE = /[\x00-\x1f\x7f\u2028\u2029]/;
|
|
174159
174669
|
var MARKER_FORGING_RE = /[<>`]|<!--|-->/;
|
|
@@ -174342,10 +174852,10 @@ async function targetFor(entry, targetScope, ctx) {
|
|
|
174342
174852
|
return { ok: true, absolutePath: containment.absolutePath };
|
|
174343
174853
|
}
|
|
174344
174854
|
async function resolveContainedPathForWrite(root, relPath) {
|
|
174345
|
-
const absolute =
|
|
174346
|
-
const rootResolved =
|
|
174347
|
-
const relative =
|
|
174348
|
-
if (relative === "" || relative === ".." || relative.startsWith(`..${
|
|
174855
|
+
const absolute = path329.resolve(root, relPath);
|
|
174856
|
+
const rootResolved = path329.resolve(root);
|
|
174857
|
+
const relative = path329.relative(rootResolved, absolute);
|
|
174858
|
+
if (relative === "" || relative === ".." || relative.startsWith(`..${path329.sep}`) || path329.isAbsolute(relative)) {
|
|
174349
174859
|
return {
|
|
174350
174860
|
ok: false,
|
|
174351
174861
|
refusal: { reason: BUNDLE_REFUSAL.pathEscape, path: relPath, message: `${relPath} resolves outside the scope root` }
|
|
@@ -174354,7 +174864,7 @@ async function resolveContainedPathForWrite(root, relPath) {
|
|
|
174354
174864
|
return { ok: true, absolutePath: absolute };
|
|
174355
174865
|
}
|
|
174356
174866
|
async function refuseSymlinkChain(root, relPath) {
|
|
174357
|
-
const rootResolved =
|
|
174867
|
+
const rootResolved = path329.resolve(root);
|
|
174358
174868
|
try {
|
|
174359
174869
|
const rootStat = await lstat18(rootResolved);
|
|
174360
174870
|
if (rootStat.isSymbolicLink()) {
|
|
@@ -174367,7 +174877,7 @@ async function refuseSymlinkChain(root, relPath) {
|
|
|
174367
174877
|
const segments = relPath.split("/");
|
|
174368
174878
|
let current = rootResolved;
|
|
174369
174879
|
for (const segment of segments) {
|
|
174370
|
-
current =
|
|
174880
|
+
current = path329.join(current, segment);
|
|
174371
174881
|
try {
|
|
174372
174882
|
const stat = await lstat18(current);
|
|
174373
174883
|
if (stat.isSymbolicLink()) {
|
|
@@ -174395,8 +174905,8 @@ async function readTargetFile(absolutePath) {
|
|
|
174395
174905
|
}
|
|
174396
174906
|
}
|
|
174397
174907
|
// src/bundle/archive.ts
|
|
174398
|
-
import { readdir as
|
|
174399
|
-
import
|
|
174908
|
+
import { readdir as readdir60, readFile as readFile167, lstat as lstat19 } from "fs/promises";
|
|
174909
|
+
import path330 from "path";
|
|
174400
174910
|
import { gzipSync, gunzipSync } from "zlib";
|
|
174401
174911
|
var BLOCK = 512;
|
|
174402
174912
|
var BUNDLE_MANIFEST_NAME = "bundle.json";
|
|
@@ -174487,11 +174997,11 @@ function buildBundleArchive(files, manifestBytes) {
|
|
|
174487
174997
|
const dirs = new Set;
|
|
174488
174998
|
const sortedPaths = [...files.keys()].sort();
|
|
174489
174999
|
for (const p of sortedPaths) {
|
|
174490
|
-
let dir =
|
|
175000
|
+
let dir = path330.dirname(p);
|
|
174491
175001
|
const segs = [];
|
|
174492
175002
|
while (dir !== "." && dir !== "/" && dir !== "") {
|
|
174493
175003
|
segs.unshift(dir);
|
|
174494
|
-
dir =
|
|
175004
|
+
dir = path330.dirname(dir);
|
|
174495
175005
|
}
|
|
174496
175006
|
for (const d of segs)
|
|
174497
175007
|
dirs.add(d);
|
|
@@ -174559,7 +175069,7 @@ function parseUstar(tar, limits) {
|
|
|
174559
175069
|
const name = prefix.length > 0 ? `${prefix}/${nameRaw}` : nameRaw;
|
|
174560
175070
|
const typeflag = String.fromCharCode(header[156] ?? 0);
|
|
174561
175071
|
const size = readOctal(header, 124, 12);
|
|
174562
|
-
if (
|
|
175072
|
+
if (path330.isAbsolute(name) || name.split("/").includes("..") || name.length === 0) {
|
|
174563
175073
|
return { ok: false, refusal: { reason: BUNDLE_REFUSAL.archiveInvalid, path: name, message: `unsafe entry name: ${name}` } };
|
|
174564
175074
|
}
|
|
174565
175075
|
const isDir = typeflag === "5";
|
|
@@ -174621,9 +175131,9 @@ async function openBundle(bundlePath, limits) {
|
|
|
174621
175131
|
let entryCount = 0;
|
|
174622
175132
|
let totalBytes = 0;
|
|
174623
175133
|
async function walk(dir, relPrefix) {
|
|
174624
|
-
const entries = await
|
|
175134
|
+
const entries = await readdir60(dir, { withFileTypes: true });
|
|
174625
175135
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
174626
|
-
const abs =
|
|
175136
|
+
const abs = path330.join(dir, entry.name);
|
|
174627
175137
|
const rel = relPrefix.length > 0 ? `${relPrefix}/${entry.name}` : entry.name;
|
|
174628
175138
|
const entryStat = await lstat19(abs);
|
|
174629
175139
|
if (entryStat.isSymbolicLink()) {
|
|
@@ -175010,9 +175520,9 @@ init_validator();
|
|
|
175010
175520
|
init_frontmatter();
|
|
175011
175521
|
init_types3();
|
|
175012
175522
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
175013
|
-
import { mkdir as mkdir71, readdir as
|
|
175014
|
-
import { existsSync as
|
|
175015
|
-
import
|
|
175523
|
+
import { mkdir as mkdir71, readdir as readdir61, readFile as readFile168, writeFile as writeFile50, lstat as lstat20 } from "fs/promises";
|
|
175524
|
+
import { existsSync as existsSync54 } from "fs";
|
|
175525
|
+
import path331 from "path";
|
|
175016
175526
|
// docs/requirements/keryx-agent-platform-expansion/schemas/hook-config.schema.json
|
|
175017
175527
|
var hook_config_schema_default2 = {
|
|
175018
175528
|
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
@@ -175556,12 +176066,12 @@ function contentDigestBundleId(scope, entries) {
|
|
|
175556
176066
|
async function walkFiles2(dir, relPrefix, out, skipped) {
|
|
175557
176067
|
let entries;
|
|
175558
176068
|
try {
|
|
175559
|
-
entries = await
|
|
176069
|
+
entries = await readdir61(dir, { withFileTypes: true });
|
|
175560
176070
|
} catch {
|
|
175561
176071
|
return;
|
|
175562
176072
|
}
|
|
175563
176073
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
175564
|
-
const abs =
|
|
176074
|
+
const abs = path331.join(dir, entry.name);
|
|
175565
176075
|
const rel = relPrefix.length > 0 ? `${relPrefix}/${entry.name}` : entry.name;
|
|
175566
176076
|
const st = await lstat20(abs);
|
|
175567
176077
|
if (st.isSymbolicLink()) {
|
|
@@ -175578,8 +176088,8 @@ async function walkFiles2(dir, relPrefix, out, skipped) {
|
|
|
175578
176088
|
async function collectSkills(root, scope, skipped) {
|
|
175579
176089
|
const candidates = [];
|
|
175580
176090
|
for (const baseDirName of scope === "project" ? ["skills", "project-skills"] : ["skills"]) {
|
|
175581
|
-
const base =
|
|
175582
|
-
if (!
|
|
176091
|
+
const base = path331.join(root, baseDirName);
|
|
176092
|
+
if (!existsSync54(base))
|
|
175583
176093
|
continue;
|
|
175584
176094
|
const files = [];
|
|
175585
176095
|
await walkFiles2(base, baseDirName, files, skipped);
|
|
@@ -175591,26 +176101,26 @@ async function collectSkills(root, scope, skipped) {
|
|
|
175591
176101
|
async function collectRules(root, scope, skipped) {
|
|
175592
176102
|
if (scope === "user")
|
|
175593
176103
|
return [];
|
|
175594
|
-
const base =
|
|
175595
|
-
if (!
|
|
176104
|
+
const base = path331.join(root, "rules");
|
|
176105
|
+
if (!existsSync54(base))
|
|
175596
176106
|
return [];
|
|
175597
176107
|
const files = [];
|
|
175598
176108
|
await walkFiles2(base, "rules", files, skipped);
|
|
175599
176109
|
return files.filter((f) => /\.(md|mdc)$/.test(f.path)).map((f) => ({ bundlePath: f.path, kind: "rule", absolutePath: f.abs }));
|
|
175600
176110
|
}
|
|
175601
176111
|
async function collectAgents(root, skipped) {
|
|
175602
|
-
const base =
|
|
175603
|
-
if (!
|
|
176112
|
+
const base = path331.join(root, "agents");
|
|
176113
|
+
if (!existsSync54(base))
|
|
175604
176114
|
return [];
|
|
175605
176115
|
let entries;
|
|
175606
176116
|
try {
|
|
175607
|
-
entries = await
|
|
176117
|
+
entries = await readdir61(base, { withFileTypes: true });
|
|
175608
176118
|
} catch {
|
|
175609
176119
|
return [];
|
|
175610
176120
|
}
|
|
175611
176121
|
const candidates = [];
|
|
175612
176122
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
175613
|
-
const abs =
|
|
176123
|
+
const abs = path331.join(base, entry.name);
|
|
175614
176124
|
const st = await lstat20(abs);
|
|
175615
176125
|
if (st.isSymbolicLink()) {
|
|
175616
176126
|
skipped.push({ path: `agents/${entry.name}`, reason: "symlink" });
|
|
@@ -175625,17 +176135,17 @@ async function collectAgents(root, skipped) {
|
|
|
175625
176135
|
async function collectMemory(root, skipped) {
|
|
175626
176136
|
const candidates = [];
|
|
175627
176137
|
for (const { folder } of MEMORY_TYPES) {
|
|
175628
|
-
const base =
|
|
175629
|
-
if (!
|
|
176138
|
+
const base = path331.join(root, "memory", folder);
|
|
176139
|
+
if (!existsSync54(base))
|
|
175630
176140
|
continue;
|
|
175631
176141
|
let entries;
|
|
175632
176142
|
try {
|
|
175633
|
-
entries = await
|
|
176143
|
+
entries = await readdir61(base, { withFileTypes: true });
|
|
175634
176144
|
} catch {
|
|
175635
176145
|
continue;
|
|
175636
176146
|
}
|
|
175637
176147
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
175638
|
-
const abs =
|
|
176148
|
+
const abs = path331.join(base, entry.name);
|
|
175639
176149
|
const st = await lstat20(abs);
|
|
175640
176150
|
if (st.isSymbolicLink()) {
|
|
175641
176151
|
skipped.push({ path: `memory/${folder}/${entry.name}`, reason: "symlink" });
|
|
@@ -175649,8 +176159,8 @@ async function collectMemory(root, skipped) {
|
|
|
175649
176159
|
return candidates;
|
|
175650
176160
|
}
|
|
175651
176161
|
async function collectHookConfig(root) {
|
|
175652
|
-
const abs =
|
|
175653
|
-
if (!
|
|
176162
|
+
const abs = path331.join(root, "hooks.json");
|
|
176163
|
+
if (!existsSync54(abs))
|
|
175654
176164
|
return [];
|
|
175655
176165
|
const st = await lstat20(abs);
|
|
175656
176166
|
if (st.isSymbolicLink() || !st.isFile())
|
|
@@ -175659,19 +176169,19 @@ async function collectHookConfig(root) {
|
|
|
175659
176169
|
}
|
|
175660
176170
|
async function collectLearnedPatterns(root, scope) {
|
|
175661
176171
|
const relDir = scope === "user" ? "learning/patterns" : "data/learning/candidates";
|
|
175662
|
-
const base =
|
|
175663
|
-
if (!
|
|
176172
|
+
const base = path331.join(root, ...relDir.split("/"));
|
|
176173
|
+
if (!existsSync54(base))
|
|
175664
176174
|
return [];
|
|
175665
176175
|
let entries;
|
|
175666
176176
|
try {
|
|
175667
|
-
entries = await
|
|
176177
|
+
entries = await readdir61(base, { withFileTypes: true });
|
|
175668
176178
|
} catch {
|
|
175669
176179
|
return [];
|
|
175670
176180
|
}
|
|
175671
176181
|
const candidates = [];
|
|
175672
176182
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
175673
176183
|
if (entry.isFile() && entry.name.endsWith(".json")) {
|
|
175674
|
-
candidates.push({ bundlePath: `${relDir}/${entry.name}`, kind: "learned-pattern", absolutePath:
|
|
176184
|
+
candidates.push({ bundlePath: `${relDir}/${entry.name}`, kind: "learned-pattern", absolutePath: path331.join(base, entry.name) });
|
|
175675
176185
|
}
|
|
175676
176186
|
}
|
|
175677
176187
|
return candidates;
|
|
@@ -175704,7 +176214,7 @@ function rewriteAgentOrigin(content, sourceRef) {
|
|
|
175704
176214
|
}
|
|
175705
176215
|
async function outDirIsEmpty(out) {
|
|
175706
176216
|
try {
|
|
175707
|
-
const entries = await
|
|
176217
|
+
const entries = await readdir61(out);
|
|
175708
176218
|
return entries.length === 0;
|
|
175709
176219
|
} catch {
|
|
175710
176220
|
return true;
|
|
@@ -175712,10 +176222,10 @@ async function outDirIsEmpty(out) {
|
|
|
175712
176222
|
}
|
|
175713
176223
|
async function writeDirectoryBundle(out, manifestBytes, files) {
|
|
175714
176224
|
await mkdir71(out, { recursive: true });
|
|
175715
|
-
await writeFile50(
|
|
176225
|
+
await writeFile50(path331.join(out, "bundle.json"), manifestBytes);
|
|
175716
176226
|
for (const [rel, bytes] of files) {
|
|
175717
|
-
const abs =
|
|
175718
|
-
await mkdir71(
|
|
176227
|
+
const abs = path331.join(out, ...rel.split("/"));
|
|
176228
|
+
await mkdir71(path331.dirname(abs), { recursive: true });
|
|
175719
176229
|
await writeFile50(abs, bytes);
|
|
175720
176230
|
}
|
|
175721
176231
|
}
|
|
@@ -175843,16 +176353,16 @@ async function exportBundle(opts) {
|
|
|
175843
176353
|
const manifestBytes = Buffer.from(serializeManifest(manifest), "utf8");
|
|
175844
176354
|
const isArchive = opts.out.endsWith(".tar.gz") || opts.out.endsWith(".tgz");
|
|
175845
176355
|
if (isArchive) {
|
|
175846
|
-
if (
|
|
176356
|
+
if (existsSync54(opts.out)) {
|
|
175847
176357
|
return { ok: false, refusals: [{ reason: BUNDLE_REFUSAL.notABundle, message: `${opts.out} already exists` }] };
|
|
175848
176358
|
}
|
|
175849
176359
|
const archive = buildBundleArchive(files, manifestBytes);
|
|
175850
176360
|
if (!archive.ok)
|
|
175851
176361
|
return { ok: false, refusals: [archive.refusal] };
|
|
175852
|
-
await mkdir71(
|
|
176362
|
+
await mkdir71(path331.dirname(opts.out), { recursive: true });
|
|
175853
176363
|
await writeFile50(opts.out, archive.value);
|
|
175854
176364
|
} else {
|
|
175855
|
-
if (
|
|
176365
|
+
if (existsSync54(opts.out) && !await outDirIsEmpty(opts.out)) {
|
|
175856
176366
|
return { ok: false, refusals: [{ reason: BUNDLE_REFUSAL.notABundle, message: `${opts.out} already exists and is not empty` }] };
|
|
175857
176367
|
}
|
|
175858
176368
|
await writeDirectoryBundle(opts.out, manifestBytes, files);
|
|
@@ -175899,16 +176409,16 @@ async function verifyBundlePath(bundlePath) {
|
|
|
175899
176409
|
// src/bundle/applied-state.ts
|
|
175900
176410
|
init_contained_write();
|
|
175901
176411
|
import { readFile as readFile169 } from "fs/promises";
|
|
175902
|
-
import
|
|
176412
|
+
import path332 from "path";
|
|
175903
176413
|
var APPLIED_STATE_SCHEMA_VERSION = 2;
|
|
175904
176414
|
function emptyState() {
|
|
175905
176415
|
return { schemaVersion: APPLIED_STATE_SCHEMA_VERSION, entries: {} };
|
|
175906
176416
|
}
|
|
175907
176417
|
function appliedStatePath(scope, ctx) {
|
|
175908
176418
|
if (scope === "user") {
|
|
175909
|
-
return
|
|
176419
|
+
return path332.join(scopeRoot("user", ctx), "bundles", "applied-state.json");
|
|
175910
176420
|
}
|
|
175911
|
-
return
|
|
176421
|
+
return path332.join(scopeRoot(scope, ctx), "data", "bundles", "applied-state.json");
|
|
175912
176422
|
}
|
|
175913
176423
|
function isPlainEntryShape(value) {
|
|
175914
176424
|
if (typeof value !== "object" || value === null)
|
|
@@ -175990,14 +176500,14 @@ async function readAppliedState(ledgerPath) {
|
|
|
175990
176500
|
return { ok: false, reason: "corrupt-ledger", message: `applied-state ledger at ${ledgerPath} has an unrecognized shape` };
|
|
175991
176501
|
}
|
|
175992
176502
|
function containedRootAndRel(ledgerPath) {
|
|
175993
|
-
const marker = `${
|
|
176503
|
+
const marker = `${path332.sep}.metaproject${path332.sep}`;
|
|
175994
176504
|
const idx = ledgerPath.indexOf(marker);
|
|
175995
176505
|
if (idx >= 0) {
|
|
175996
|
-
return { root: ledgerPath.slice(0, idx), rel: ledgerPath.slice(idx +
|
|
176506
|
+
return { root: ledgerPath.slice(0, idx), rel: ledgerPath.slice(idx + path332.sep.length).split(path332.sep).join("/") };
|
|
175997
176507
|
}
|
|
175998
|
-
const bundlesDir =
|
|
175999
|
-
const root =
|
|
176000
|
-
const rel =
|
|
176508
|
+
const bundlesDir = path332.dirname(ledgerPath);
|
|
176509
|
+
const root = path332.dirname(bundlesDir);
|
|
176510
|
+
const rel = path332.join(path332.basename(bundlesDir), path332.basename(ledgerPath)).split(path332.sep).join("/");
|
|
176001
176511
|
return { root, rel };
|
|
176002
176512
|
}
|
|
176003
176513
|
async function writeAppliedState(ledgerPath, state) {
|
|
@@ -176018,17 +176528,17 @@ init_service8();
|
|
|
176018
176528
|
init_fs();
|
|
176019
176529
|
init_symlink_safety();
|
|
176020
176530
|
import { lstat as lstat21, mkdir as mkdir72, open as open8, readFile as readFile170 } from "fs/promises";
|
|
176021
|
-
import
|
|
176531
|
+
import path333 from "path";
|
|
176022
176532
|
var PRIVATE_DIR_GITIGNORE = `# keryx:private-dir \u2014 managed by keryx; this directory stays out of version control
|
|
176023
176533
|
*
|
|
176024
176534
|
!.gitignore
|
|
176025
176535
|
`;
|
|
176026
176536
|
async function checkPrivateDirGitignore(dir, root) {
|
|
176027
176537
|
if (root !== undefined) {
|
|
176028
|
-
const rootResolved =
|
|
176029
|
-
const dirResolved =
|
|
176030
|
-
const relative =
|
|
176031
|
-
const relativePosix = relative.split(
|
|
176538
|
+
const rootResolved = path333.resolve(root);
|
|
176539
|
+
const dirResolved = path333.resolve(dir);
|
|
176540
|
+
const relative = path333.relative(rootResolved, dirResolved);
|
|
176541
|
+
const relativePosix = relative.split(path333.sep).join("/");
|
|
176032
176542
|
const refusal = await refuseEscapingSymlink(rootResolved, relativePosix);
|
|
176033
176543
|
if (refusal !== undefined) {
|
|
176034
176544
|
return {
|
|
@@ -176058,7 +176568,7 @@ async function checkPrivateDirGitignore(dir, root) {
|
|
|
176058
176568
|
message: `${dir} is a symlink; keryx will not manage a private directory reached through a symlink.`
|
|
176059
176569
|
};
|
|
176060
176570
|
}
|
|
176061
|
-
const gitignorePath =
|
|
176571
|
+
const gitignorePath = path333.join(dir, ".gitignore");
|
|
176062
176572
|
let stats;
|
|
176063
176573
|
try {
|
|
176064
176574
|
stats = await lstat21(gitignorePath);
|
|
@@ -176110,7 +176620,7 @@ async function ensurePrivateDirGitignore(dir, root) {
|
|
|
176110
176620
|
if (!check.ok || check.action === "present") {
|
|
176111
176621
|
return check;
|
|
176112
176622
|
}
|
|
176113
|
-
const gitignorePath =
|
|
176623
|
+
const gitignorePath = path333.join(dir, ".gitignore");
|
|
176114
176624
|
await mkdir72(dir, { recursive: true });
|
|
176115
176625
|
try {
|
|
176116
176626
|
const handle = await open8(gitignorePath, "wx");
|
|
@@ -176507,7 +177017,7 @@ async function planBundleImport(opts) {
|
|
|
176507
177017
|
init_service4();
|
|
176508
177018
|
import { mkdtemp as mkdtemp6, mkdir as mkdir73, rm as rm20, writeFile as writeFile51 } from "fs/promises";
|
|
176509
177019
|
import { tmpdir as tmpdir13 } from "os";
|
|
176510
|
-
import
|
|
177020
|
+
import path334 from "path";
|
|
176511
177021
|
function entriesToStage(plan) {
|
|
176512
177022
|
return plan.entries.filter((e) => e.bucket === "new" || e.bucket === "update" || e.bucket === "conflict" && e.forced);
|
|
176513
177023
|
}
|
|
@@ -176517,12 +177027,12 @@ async function auditBundlePlan(plan, opts = {}) {
|
|
|
176517
177027
|
return { ok: true, refusals: [], report: null };
|
|
176518
177028
|
}
|
|
176519
177029
|
const runAudit = opts.runAudit ?? runHarnessAudit;
|
|
176520
|
-
const stagingDir = await mkdtemp6(
|
|
177030
|
+
const stagingDir = await mkdtemp6(path334.join(tmpdir13(), "keryx-bundle-audit-"));
|
|
176521
177031
|
try {
|
|
176522
177032
|
try {
|
|
176523
177033
|
for (const entry of toStage) {
|
|
176524
|
-
const abs =
|
|
176525
|
-
await mkdir73(
|
|
177034
|
+
const abs = path334.join(stagingDir, ...entry.path.split("/"));
|
|
177035
|
+
await mkdir73(path334.dirname(abs), { recursive: true });
|
|
176526
177036
|
await writeFile51(abs, entry.bytes);
|
|
176527
177037
|
}
|
|
176528
177038
|
} catch (err) {
|
|
@@ -176553,7 +177063,7 @@ async function auditBundlePlan(plan, opts = {}) {
|
|
|
176553
177063
|
// src/bundle/apply.ts
|
|
176554
177064
|
init_contained_write();
|
|
176555
177065
|
import { mkdir as mkdir74, rmdir as rmdir2, stat as stat33 } from "fs/promises";
|
|
176556
|
-
import
|
|
177066
|
+
import path335 from "path";
|
|
176557
177067
|
init_keryx_home();
|
|
176558
177068
|
init_checksum();
|
|
176559
177069
|
class ApplyAbort extends Error {
|
|
@@ -176633,7 +177143,7 @@ async function applyBundlePlan(plan, auditResult, opts = {}) {
|
|
|
176633
177143
|
throw new ApplyAbort({ ...previousFile.refusal, path: entry.path });
|
|
176634
177144
|
}
|
|
176635
177145
|
const previousBytes = previousFile.bytes ?? null;
|
|
176636
|
-
const createdDirs = await mkdirRecordingCreated(
|
|
177146
|
+
const createdDirs = await mkdirRecordingCreated(path335.dirname(entry.targetPath));
|
|
176637
177147
|
for (const dir of [...createdDirs].reverse())
|
|
176638
177148
|
rollback.push({ kind: "dir", absolutePath: dir });
|
|
176639
177149
|
rollback.push({ kind: "file", root, rel: entry.targetRelative, previousBytes });
|
|
@@ -176716,14 +177226,14 @@ async function applyBundlePlan(plan, auditResult, opts = {}) {
|
|
|
176716
177226
|
}
|
|
176717
177227
|
async function mkdirRecordingCreated(dir) {
|
|
176718
177228
|
const missing = [];
|
|
176719
|
-
let current =
|
|
177229
|
+
let current = path335.resolve(dir);
|
|
176720
177230
|
for (;; ) {
|
|
176721
177231
|
try {
|
|
176722
177232
|
await stat33(current);
|
|
176723
177233
|
break;
|
|
176724
177234
|
} catch {
|
|
176725
177235
|
missing.push(current);
|
|
176726
|
-
const parent =
|
|
177236
|
+
const parent = path335.dirname(current);
|
|
176727
177237
|
if (parent === current)
|
|
176728
177238
|
break;
|
|
176729
177239
|
current = parent;
|
|
@@ -176738,9 +177248,9 @@ function resolveLedgerPathForEntry(entry, opts) {
|
|
|
176738
177248
|
if (entry.targetScope === "user") {
|
|
176739
177249
|
return userStorePaths(opts.env ?? process.env, opts.homeDir).appliedState;
|
|
176740
177250
|
}
|
|
176741
|
-
const metaprojectIdx = entry.targetPath.indexOf(`${
|
|
176742
|
-
const metaprojectRoot = metaprojectIdx === -1 ?
|
|
176743
|
-
return
|
|
177251
|
+
const metaprojectIdx = entry.targetPath.indexOf(`${path335.sep}.metaproject${path335.sep}`);
|
|
177252
|
+
const metaprojectRoot = metaprojectIdx === -1 ? path335.join(path335.dirname(entry.targetPath), ".metaproject") : entry.targetPath.slice(0, metaprojectIdx + `${path335.sep}.metaproject`.length);
|
|
177253
|
+
return path335.join(metaprojectRoot, "data", "bundles", "applied-state.json");
|
|
176744
177254
|
}
|
|
176745
177255
|
// src/bundle/inspect.ts
|
|
176746
177256
|
init_matrix();
|
|
@@ -176792,28 +177302,28 @@ function defaultCapabilityLookup() {
|
|
|
176792
177302
|
}
|
|
176793
177303
|
// src/bundle/uninstall.ts
|
|
176794
177304
|
init_contained_write();
|
|
176795
|
-
import
|
|
177305
|
+
import path336 from "path";
|
|
176796
177306
|
init_checksum();
|
|
176797
177307
|
var PROTECTED_KIND_ROOTS = new Set(["skills", "project-skills", "rules", "agents", "memory", "learning", "data/learning"]);
|
|
176798
177308
|
function isContained(root, candidate) {
|
|
176799
|
-
const rel =
|
|
176800
|
-
return rel === "" || !rel.startsWith(`..${
|
|
177309
|
+
const rel = path336.relative(root, candidate);
|
|
177310
|
+
return rel === "" || !rel.startsWith(`..${path336.sep}`) && rel !== ".." && !path336.isAbsolute(rel);
|
|
176801
177311
|
}
|
|
176802
177312
|
async function removeNowEmptyParents(root, relFilePath) {
|
|
176803
|
-
let relDir =
|
|
177313
|
+
let relDir = path336.posix.dirname(relFilePath);
|
|
176804
177314
|
while (relDir !== "." && relDir !== "/" && relDir !== "") {
|
|
176805
177315
|
if (PROTECTED_KIND_ROOTS.has(relDir))
|
|
176806
177316
|
break;
|
|
176807
177317
|
const removed = await rmdirIfEmptyContained(root, relDir).catch(() => false);
|
|
176808
177318
|
if (!removed)
|
|
176809
177319
|
break;
|
|
176810
|
-
relDir =
|
|
177320
|
+
relDir = path336.posix.dirname(relDir);
|
|
176811
177321
|
}
|
|
176812
177322
|
}
|
|
176813
177323
|
async function uninstallBundle(opts) {
|
|
176814
177324
|
const ctx = { projectRoot: opts.projectRoot, env: opts.env, homeDir: opts.homeDir };
|
|
176815
177325
|
const root = scopeRoot(opts.targetScope, ctx);
|
|
176816
|
-
const rootResolved =
|
|
177326
|
+
const rootResolved = path336.resolve(root);
|
|
176817
177327
|
const ledgerPath = appliedStatePath(opts.targetScope, ctx);
|
|
176818
177328
|
const ledgerRead = await readAppliedState(ledgerPath);
|
|
176819
177329
|
if (!ledgerRead.ok) {
|
|
@@ -176853,7 +177363,7 @@ async function uninstallBundle(opts) {
|
|
|
176853
177363
|
if (!kindCheck.ok) {
|
|
176854
177364
|
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: [] };
|
|
176855
177365
|
}
|
|
176856
|
-
const absolute =
|
|
177366
|
+
const absolute = path336.resolve(rootResolved, normalized.path);
|
|
176857
177367
|
if (!isContained(rootResolved, absolute)) {
|
|
176858
177368
|
return { ok: false, refusals: [{ reason: BUNDLE_REFUSAL.corruptLedger, path: relPath, message: `applied-state ledger record "${relPath}" resolves outside the scope root` }], removed: [], kept: [], missing: [] };
|
|
176859
177369
|
}
|
|
@@ -177045,7 +177555,7 @@ async function handleExport(args, cwd) {
|
|
|
177045
177555
|
const outcome = await exportBundle({
|
|
177046
177556
|
projectRoot,
|
|
177047
177557
|
scope: scopeArg,
|
|
177048
|
-
out:
|
|
177558
|
+
out: path337.resolve(cwd, out),
|
|
177049
177559
|
include: include.length > 0 ? include : undefined,
|
|
177050
177560
|
kinds: kindsRaw.length > 0 ? kindsRaw : undefined,
|
|
177051
177561
|
bundleId,
|
|
@@ -177092,7 +177602,7 @@ async function handleImport(args, cwd) {
|
|
|
177092
177602
|
}
|
|
177093
177603
|
const projectRoot = resolveBundleProjectRoot(cwd);
|
|
177094
177604
|
if (external) {
|
|
177095
|
-
await handleImportExternal(
|
|
177605
|
+
await handleImportExternal(path337.resolve(cwd, target), projectRoot, { dryRun, json });
|
|
177096
177606
|
return;
|
|
177097
177607
|
}
|
|
177098
177608
|
const targetScopeArg = optionValue([...args], "--target-scope");
|
|
@@ -177119,7 +177629,7 @@ async function handleImport(args, cwd) {
|
|
|
177119
177629
|
return;
|
|
177120
177630
|
}
|
|
177121
177631
|
}
|
|
177122
|
-
const opened = await openBundle(
|
|
177632
|
+
const opened = await openBundle(path337.resolve(cwd, target));
|
|
177123
177633
|
if (!opened.ok) {
|
|
177124
177634
|
printRefusals([opened.refusal], json);
|
|
177125
177635
|
process.exitCode = 1;
|
|
@@ -177297,7 +177807,7 @@ async function handleInspect(args, cwd) {
|
|
|
177297
177807
|
return;
|
|
177298
177808
|
}
|
|
177299
177809
|
const projectRoot = resolveBundleProjectRoot(cwd);
|
|
177300
|
-
const result = await inspectBundle(
|
|
177810
|
+
const result = await inspectBundle(path337.resolve(cwd, bundlePath), {
|
|
177301
177811
|
projectRoot,
|
|
177302
177812
|
targetScope: targetScopeArg
|
|
177303
177813
|
});
|
|
@@ -177341,7 +177851,7 @@ async function handleVerify(args, cwd) {
|
|
|
177341
177851
|
failUsage("keryx bundle verify requires a <bundle> argument (or --external-imports)");
|
|
177342
177852
|
return;
|
|
177343
177853
|
}
|
|
177344
|
-
const outcome = await verifyBundlePath(
|
|
177854
|
+
const outcome = await verifyBundlePath(path337.resolve(cwd, bundlePath));
|
|
177345
177855
|
if (!outcome.ok) {
|
|
177346
177856
|
printRefusals(outcome.refusals, json);
|
|
177347
177857
|
process.exitCode = 1;
|
|
@@ -177469,10 +177979,10 @@ function printUninstallHelp2() {
|
|
|
177469
177979
|
}
|
|
177470
177980
|
|
|
177471
177981
|
// src/commands/learn.ts
|
|
177472
|
-
import { existsSync as
|
|
177982
|
+
import { existsSync as existsSync55 } from "fs";
|
|
177473
177983
|
import { readFile as readFile171 } from "fs/promises";
|
|
177474
177984
|
import { createInterface as createInterface4 } from "readline/promises";
|
|
177475
|
-
import
|
|
177985
|
+
import path338 from "path";
|
|
177476
177986
|
init_contained_path();
|
|
177477
177987
|
init_service9();
|
|
177478
177988
|
var STDIN_DEADLINE_MS2 = 2000;
|
|
@@ -177495,16 +178005,16 @@ function resolveRoot2(deps) {
|
|
|
177495
178005
|
return resolveProjectRoot(deps.cwd ?? process.cwd());
|
|
177496
178006
|
}
|
|
177497
178007
|
function resolveLearnRoot(startDir, env) {
|
|
177498
|
-
const hasMetaproject = (dir) =>
|
|
178008
|
+
const hasMetaproject = (dir) => existsSync55(path338.join(dir, ".metaproject"));
|
|
177499
178009
|
const fromEnv = env.CLAUDE_PROJECT_DIR;
|
|
177500
178010
|
if (typeof fromEnv === "string" && fromEnv.length > 0 && hasMetaproject(fromEnv)) {
|
|
177501
178011
|
return fromEnv;
|
|
177502
178012
|
}
|
|
177503
|
-
let current =
|
|
178013
|
+
let current = path338.resolve(startDir);
|
|
177504
178014
|
for (;; ) {
|
|
177505
178015
|
if (hasMetaproject(current))
|
|
177506
178016
|
return current;
|
|
177507
|
-
const parent =
|
|
178017
|
+
const parent = path338.dirname(current);
|
|
177508
178018
|
if (parent === current)
|
|
177509
178019
|
return;
|
|
177510
178020
|
current = parent;
|
|
@@ -178169,6 +178679,190 @@ async function helpCommand(rest) {
|
|
|
178169
178679
|
process.exitCode = 1;
|
|
178170
178680
|
}
|
|
178171
178681
|
|
|
178682
|
+
// src/lib/group-subcommands.ts
|
|
178683
|
+
var GROUP_SUBCOMMANDS = new Map([
|
|
178684
|
+
["modules", ["status", "list", "enable", "on", "disable", "off", "interactive", "help"]],
|
|
178685
|
+
["projects", ["list", "register", "forget", "help"]],
|
|
178686
|
+
["providers", ["list", "status", "cross-family", "test", "remove"]],
|
|
178687
|
+
["routing", ["list", "set", "unset", "trust", "profile", "stats"]],
|
|
178688
|
+
["external", ["on", "off", "status", "list"]],
|
|
178689
|
+
["auth", ["list", "login", "logout", "status"]],
|
|
178690
|
+
["version", ["check"]],
|
|
178691
|
+
["gdgraph", ["build", "query", "find", "symbol", "symbols", "path", "affected", "repomap", "context", "assets"]],
|
|
178692
|
+
["ctx", ["status", "diff", "rg", "read", "run", "show", "hook", "install-hook", "uninstall-hook"]],
|
|
178693
|
+
[
|
|
178694
|
+
"wiki",
|
|
178695
|
+
[
|
|
178696
|
+
"status",
|
|
178697
|
+
"new",
|
|
178698
|
+
"index",
|
|
178699
|
+
"collect",
|
|
178700
|
+
"check-links",
|
|
178701
|
+
"validate",
|
|
178702
|
+
"freshness",
|
|
178703
|
+
"refresh",
|
|
178704
|
+
"verify",
|
|
178705
|
+
"migrate-markers",
|
|
178706
|
+
"ask",
|
|
178707
|
+
"sections",
|
|
178708
|
+
"enrich",
|
|
178709
|
+
"context",
|
|
178710
|
+
"backlinks"
|
|
178711
|
+
]
|
|
178712
|
+
],
|
|
178713
|
+
["stack", ["detect"]],
|
|
178714
|
+
["health", ["run", "status", "gate", "sources", "explain", "baseline", "trend"]],
|
|
178715
|
+
["metrics", ["status", "validate", "collect", "latest", "show", "compare", "rebuild", "plan", "benchmark"]],
|
|
178716
|
+
["test", ["init", "analyze", "run", "status", "context", "report", "related", "explain", "coverage-map", "suggest"]],
|
|
178717
|
+
["memory", ["new", "index", "search", "supersede", "transition", "assets", "ingest", "check", "reflect", "handoff"]],
|
|
178718
|
+
[
|
|
178719
|
+
"flow",
|
|
178720
|
+
[
|
|
178721
|
+
"init",
|
|
178722
|
+
"list",
|
|
178723
|
+
"status",
|
|
178724
|
+
"freeze",
|
|
178725
|
+
"start",
|
|
178726
|
+
"next",
|
|
178727
|
+
"task",
|
|
178728
|
+
"ac",
|
|
178729
|
+
"check-ac",
|
|
178730
|
+
"owner",
|
|
178731
|
+
"implemented",
|
|
178732
|
+
"complete",
|
|
178733
|
+
"confirm",
|
|
178734
|
+
"recover",
|
|
178735
|
+
"block",
|
|
178736
|
+
"unblock",
|
|
178737
|
+
"check",
|
|
178738
|
+
"renumber",
|
|
178739
|
+
"repair-reviews",
|
|
178740
|
+
"plan",
|
|
178741
|
+
"schema"
|
|
178742
|
+
]
|
|
178743
|
+
],
|
|
178744
|
+
["job", ["init", "status", "step", "document", "complete", "list"]],
|
|
178745
|
+
[
|
|
178746
|
+
"review",
|
|
178747
|
+
[
|
|
178748
|
+
"attach",
|
|
178749
|
+
"start",
|
|
178750
|
+
"ingest",
|
|
178751
|
+
"scope",
|
|
178752
|
+
"floor",
|
|
178753
|
+
"blast-radius",
|
|
178754
|
+
"budget",
|
|
178755
|
+
"tier",
|
|
178756
|
+
"comments",
|
|
178757
|
+
"ci-triage",
|
|
178758
|
+
"conform",
|
|
178759
|
+
"jev-rules",
|
|
178760
|
+
"jev-edit-guard",
|
|
178761
|
+
"jev-risk",
|
|
178762
|
+
"jev-scenarios",
|
|
178763
|
+
"jev-docs",
|
|
178764
|
+
"jev-comments",
|
|
178765
|
+
"jev-contract",
|
|
178766
|
+
"jev-triage",
|
|
178767
|
+
"jev-select",
|
|
178768
|
+
"jev-profile",
|
|
178769
|
+
"learn",
|
|
178770
|
+
"loop",
|
|
178771
|
+
"stack",
|
|
178772
|
+
"reviewers",
|
|
178773
|
+
"import",
|
|
178774
|
+
"status",
|
|
178775
|
+
"complete",
|
|
178776
|
+
"lightweight"
|
|
178777
|
+
]
|
|
178778
|
+
],
|
|
178779
|
+
["rules", ["distill", "sync"]],
|
|
178780
|
+
["standard", ["validate", "doctor", "capabilities", "baseline", "emit"]],
|
|
178781
|
+
[
|
|
178782
|
+
"security",
|
|
178783
|
+
[
|
|
178784
|
+
"status",
|
|
178785
|
+
"scan",
|
|
178786
|
+
"scan-mcp",
|
|
178787
|
+
"audit-harness",
|
|
178788
|
+
"impact-evidence",
|
|
178789
|
+
"check-input",
|
|
178790
|
+
"check-output",
|
|
178791
|
+
"redact",
|
|
178792
|
+
"report",
|
|
178793
|
+
"policy",
|
|
178794
|
+
"incidents",
|
|
178795
|
+
"hooks",
|
|
178796
|
+
"eval"
|
|
178797
|
+
]
|
|
178798
|
+
],
|
|
178799
|
+
["sandbox", ["status"]],
|
|
178800
|
+
["integrations", ["install", "uninstall", "doctor", "matrix"]],
|
|
178801
|
+
[
|
|
178802
|
+
"workspace",
|
|
178803
|
+
[
|
|
178804
|
+
"create",
|
|
178805
|
+
"list",
|
|
178806
|
+
"show",
|
|
178807
|
+
"add-resource",
|
|
178808
|
+
"archive",
|
|
178809
|
+
"remove-resource",
|
|
178810
|
+
"rename",
|
|
178811
|
+
"overview",
|
|
178812
|
+
"read",
|
|
178813
|
+
"propose",
|
|
178814
|
+
"confirm-review",
|
|
178815
|
+
"review",
|
|
178816
|
+
"dismiss-candidate",
|
|
178817
|
+
"handoff",
|
|
178818
|
+
"collaboration",
|
|
178819
|
+
"policy-readiness",
|
|
178820
|
+
"catch-up",
|
|
178821
|
+
"list-proposals",
|
|
178822
|
+
"help"
|
|
178823
|
+
]
|
|
178824
|
+
],
|
|
178825
|
+
["retention", ["status", "sweep"]],
|
|
178826
|
+
["forgetting", ["trail", "lookup"]],
|
|
178827
|
+
["trigger", ["run", "install", "uninstall", "list", "status", "schedule", "resolve"]],
|
|
178828
|
+
["schedule", ["add", "list", "show", "pause", "resume", "run", "remove"]],
|
|
178829
|
+
["governance", ["report", "show"]],
|
|
178830
|
+
["hooks", ["list", "validate", "test", "enable", "disable", "trust", "untrust"]],
|
|
178831
|
+
["bundle", ["export", "import", "inspect", "verify", "uninstall"]],
|
|
178832
|
+
["learn", ["observe", "extract", "list", "review", "accept", "reject", "apply", "promote", "graduate", "prune"]],
|
|
178833
|
+
["sessions", ["list", "fork", "export", "path", "help"]],
|
|
178834
|
+
["session", ["list", "fork", "export", "path", "help"]],
|
|
178835
|
+
["serve", ["status", "token", "config"]],
|
|
178836
|
+
["bus", ["list", "log", "send", "pause", "resume", "prune", "help"]],
|
|
178837
|
+
["dashboard", ["build", "open"]],
|
|
178838
|
+
[
|
|
178839
|
+
"skills",
|
|
178840
|
+
[
|
|
178841
|
+
"catalog",
|
|
178842
|
+
"install",
|
|
178843
|
+
"doctor",
|
|
178844
|
+
"uninstall",
|
|
178845
|
+
"status",
|
|
178846
|
+
"list",
|
|
178847
|
+
"inspect",
|
|
178848
|
+
"route",
|
|
178849
|
+
"create",
|
|
178850
|
+
"generate",
|
|
178851
|
+
"import",
|
|
178852
|
+
"update",
|
|
178853
|
+
"verify",
|
|
178854
|
+
"learn",
|
|
178855
|
+
"export",
|
|
178856
|
+
"sync",
|
|
178857
|
+
"contracts",
|
|
178858
|
+
"scout",
|
|
178859
|
+
"eval",
|
|
178860
|
+
"judge-check",
|
|
178861
|
+
"stocktake"
|
|
178862
|
+
]
|
|
178863
|
+
]
|
|
178864
|
+
]);
|
|
178865
|
+
|
|
178172
178866
|
// src/cli.ts
|
|
178173
178867
|
init_package();
|
|
178174
178868
|
if (import.meta.main) {
|
|
@@ -178178,6 +178872,7 @@ var VERSION2 = package_default.version;
|
|
|
178178
178872
|
var CLI_ROUTES = {
|
|
178179
178873
|
init: initCommand,
|
|
178180
178874
|
help: helpCommand,
|
|
178875
|
+
doctor: doctorCommand2,
|
|
178181
178876
|
status: statusCommand,
|
|
178182
178877
|
modules: modulesCommand,
|
|
178183
178878
|
projects: projectsCommand,
|
|
@@ -178232,6 +178927,15 @@ var CLI_ROUTES = {
|
|
|
178232
178927
|
learn: learnCommand,
|
|
178233
178928
|
"__sandbox-net-forward": sandboxNetForwardCommand
|
|
178234
178929
|
};
|
|
178930
|
+
var MCP_KNOWN_SUBCOMMANDS = [...MCP_CONSUMER_SUBCOMMANDS, "install", "uninstall", "serve"];
|
|
178931
|
+
function knownSubcommandsFor(command) {
|
|
178932
|
+
if (command === "mcp")
|
|
178933
|
+
return MCP_KNOWN_SUBCOMMANDS;
|
|
178934
|
+
return GROUP_SUBCOMMANDS.get(command);
|
|
178935
|
+
}
|
|
178936
|
+
function groupsWithKnownSubcommands() {
|
|
178937
|
+
return ["mcp", ...GROUP_SUBCOMMANDS.keys()];
|
|
178938
|
+
}
|
|
178235
178939
|
async function main() {
|
|
178236
178940
|
setModelTurnPort(async (request) => runModelTurn(request));
|
|
178237
178941
|
const args = process.argv.slice(2);
|
|
@@ -178250,16 +178954,23 @@ async function main() {
|
|
|
178250
178954
|
await printCommandHelp(command);
|
|
178251
178955
|
return;
|
|
178252
178956
|
}
|
|
178957
|
+
const known = knownSubcommandsFor(command);
|
|
178958
|
+
const sub = args[1];
|
|
178959
|
+
if (known !== undefined && sub !== undefined && !sub.startsWith("-") && !known.includes(sub)) {
|
|
178960
|
+
console.error(formatUnknownCommandMessage(sub, known, `keryx ${command} --help`));
|
|
178961
|
+
process.exitCode = 1;
|
|
178962
|
+
return;
|
|
178963
|
+
}
|
|
178253
178964
|
await route(args.slice(1));
|
|
178254
178965
|
return;
|
|
178255
178966
|
}
|
|
178256
|
-
console.error(
|
|
178257
|
-
printHelp30();
|
|
178967
|
+
console.error(formatUnknownCommandMessage(command, Object.keys(CLI_ROUTES).filter((name) => name !== "__sandbox-net-forward")));
|
|
178258
178968
|
process.exitCode = 1;
|
|
178259
178969
|
}
|
|
178260
178970
|
var USAGE_BODY = `Usage:
|
|
178261
178971
|
keryx Show CLI usage
|
|
178262
178972
|
keryx help [group|command] Grouped command help by task (--help/-h keep this flat usage)
|
|
178973
|
+
keryx doctor [--json] One page: version, Bun floor, ripgrep, sandbox, providers, MCP, integrations, standard, worktrees, graph/wiki freshness
|
|
178263
178974
|
keryx shell [-c|--continue] [-r|--resume [id]] [--provider <p>] [--model <m>] [--base-url <url>] [--agent|--chat] [--tui|--no-tui]
|
|
178264
178975
|
Start TUI agent shell (sessions are per-project)
|
|
178265
178976
|
keryx sessions list|fork <id>|export <id>|path
|
|
@@ -178439,6 +179150,7 @@ var USAGE_BODY = `Usage:
|
|
|
178439
179150
|
|
|
178440
179151
|
Commands:
|
|
178441
179152
|
help Grouped command help by task: every verb, in nine onboarding-ordered groups
|
|
179153
|
+
doctor One-page health check with a fix hint per line; --json for {checks:[...]}
|
|
178442
179154
|
shell Start the interactive TUI agent harness. Use --no-tui or --chat to opt out.
|
|
178443
179155
|
Sessions: -c continue last in this project, -r [id] resume (per-project).
|
|
178444
179156
|
sessions List or export per-project shell sessions
|
|
@@ -178587,7 +179299,9 @@ export {
|
|
|
178587
179299
|
USAGE_BODY,
|
|
178588
179300
|
exitCodeForError,
|
|
178589
179301
|
groupUsage,
|
|
179302
|
+
groupsWithKnownSubcommands,
|
|
178590
179303
|
helpRequestedFor,
|
|
179304
|
+
knownSubcommandsFor,
|
|
178591
179305
|
main,
|
|
178592
179306
|
printCommandHelp,
|
|
178593
179307
|
shouldInterceptHelp
|