@mrciphersmith/keryx 0.2.52 → 0.2.54
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 +819 -337
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -14032,6 +14032,9 @@ var init_assembly = () => {};
|
|
|
14032
14032
|
// src/session/slate.ts
|
|
14033
14033
|
import { mkdir as mkdir25, readFile as readFile31, rm as rm4 } from "fs/promises";
|
|
14034
14034
|
import path69 from "path";
|
|
14035
|
+
function isSlateSeedKind(value) {
|
|
14036
|
+
return typeof value === "string" && SLATE_SEED_KINDS.includes(value);
|
|
14037
|
+
}
|
|
14035
14038
|
function slatePath(dir) {
|
|
14036
14039
|
return path69.join(dir, "slate.json");
|
|
14037
14040
|
}
|
|
@@ -14171,12 +14174,20 @@ function renderAnchorsBlock(anchors, opts) {
|
|
|
14171
14174
|
return lines.join(`
|
|
14172
14175
|
`);
|
|
14173
14176
|
}
|
|
14174
|
-
var DEFAULT_RENDER_MAX_TOKENS = 2000;
|
|
14177
|
+
var SLATE_SEED_KINDS, SEED_TEXT_MAX_LENGTH = 4000, DEFAULT_RENDER_MAX_TOKENS = 2000;
|
|
14175
14178
|
var init_slate = __esm(() => {
|
|
14176
14179
|
init_fs();
|
|
14177
14180
|
init_assembly();
|
|
14178
14181
|
init_repomap();
|
|
14179
14182
|
init_redact();
|
|
14183
|
+
SLATE_SEED_KINDS = [
|
|
14184
|
+
"decision",
|
|
14185
|
+
"wiki-update",
|
|
14186
|
+
"memory-entry",
|
|
14187
|
+
"follow-up",
|
|
14188
|
+
"contract-change",
|
|
14189
|
+
"risk"
|
|
14190
|
+
];
|
|
14180
14191
|
});
|
|
14181
14192
|
|
|
14182
14193
|
// src/flow/store.ts
|
|
@@ -16372,6 +16383,7 @@ async function writeWrapUpOutcomeArtifact(dir, trigger, now, groups) {
|
|
|
16372
16383
|
} catch {}
|
|
16373
16384
|
}
|
|
16374
16385
|
async function proposeOneGroup(params) {
|
|
16386
|
+
const wrapUpSource = params.wrapUpSource ?? "flow";
|
|
16375
16387
|
try {
|
|
16376
16388
|
const resolved = await resolveMachineWrapUp({
|
|
16377
16389
|
cwd: params.cwd,
|
|
@@ -16393,8 +16405,8 @@ async function proposeOneGroup(params) {
|
|
|
16393
16405
|
const wrapUpAuthority = createTrustedWrapUpAuthority({
|
|
16394
16406
|
now: params.now,
|
|
16395
16407
|
resolveExplicitWrapUp: async (request) => {
|
|
16396
|
-
if (request.source !==
|
|
16397
|
-
throw new Error(`machine-wrap-up only resolves "
|
|
16408
|
+
if (request.source !== wrapUpSource) {
|
|
16409
|
+
throw new Error(`machine-wrap-up only resolves "${wrapUpSource}" wrap-ups, got "${request.source}"`);
|
|
16398
16410
|
}
|
|
16399
16411
|
return resolved.resolution;
|
|
16400
16412
|
}
|
|
@@ -16407,7 +16419,7 @@ async function proposeOneGroup(params) {
|
|
|
16407
16419
|
const actor = await authorizationServer.actorContextFor(undefined, requestCorrelationId);
|
|
16408
16420
|
if (!actor)
|
|
16409
16421
|
throw new Error("trusted ActorContext is required for a machine wrap-up propose");
|
|
16410
|
-
const provenance = await wrapUpAuthority.issue({ actor, source:
|
|
16422
|
+
const provenance = await wrapUpAuthority.issue({ actor, source: wrapUpSource, sourceRef });
|
|
16411
16423
|
try {
|
|
16412
16424
|
const proposal = await service.create({
|
|
16413
16425
|
request: undefined,
|
|
@@ -16450,6 +16462,7 @@ async function runWrapUp(input2) {
|
|
|
16450
16462
|
slate: input2.slate,
|
|
16451
16463
|
kind,
|
|
16452
16464
|
now,
|
|
16465
|
+
...input2.wrapUpSource !== undefined ? { wrapUpSource: input2.wrapUpSource } : {},
|
|
16453
16466
|
...input2.env !== undefined ? { env: input2.env } : {},
|
|
16454
16467
|
...input2.providerFactory !== undefined ? { providerFactory: input2.providerFactory } : {},
|
|
16455
16468
|
...input2.modelTurnTimeoutMs !== undefined ? { modelTurnTimeoutMs: input2.modelTurnTimeoutMs } : {}
|
|
@@ -33541,7 +33554,8 @@ function fileRuntime(id, relativePath) {
|
|
|
33541
33554
|
merge: mcpMerge,
|
|
33542
33555
|
strip: mcpStrip,
|
|
33543
33556
|
validate: mcpValidate(id),
|
|
33544
|
-
hasManaged: mcpHasManaged
|
|
33557
|
+
hasManaged: mcpHasManaged,
|
|
33558
|
+
listServers: (settings) => Object.keys(readServers(settings))
|
|
33545
33559
|
};
|
|
33546
33560
|
}
|
|
33547
33561
|
var CURSOR_RUNTIME = fileRuntime("cursor", ".cursor/mcp.json");
|
|
@@ -33607,7 +33621,8 @@ var OPENCODE_RUNTIME = {
|
|
|
33607
33621
|
merge: opencodeMerge,
|
|
33608
33622
|
strip: opencodeStrip,
|
|
33609
33623
|
validate: opencodeValidate,
|
|
33610
|
-
hasManaged: opencodeHasManaged
|
|
33624
|
+
hasManaged: opencodeHasManaged,
|
|
33625
|
+
listServers: (settings) => Object.keys(readOpencodeMcp(settings))
|
|
33611
33626
|
};
|
|
33612
33627
|
var GENERIC_RUNTIME = {
|
|
33613
33628
|
id: "generic",
|
|
@@ -33615,7 +33630,8 @@ var GENERIC_RUNTIME = {
|
|
|
33615
33630
|
merge: mcpMerge,
|
|
33616
33631
|
strip: mcpStrip,
|
|
33617
33632
|
validate: mcpValidate("generic"),
|
|
33618
|
-
hasManaged: mcpHasManaged
|
|
33633
|
+
hasManaged: mcpHasManaged,
|
|
33634
|
+
listServers: (settings) => Object.keys(readServers(settings))
|
|
33619
33635
|
};
|
|
33620
33636
|
function readVscodeServers(settings) {
|
|
33621
33637
|
return typeof settings.servers === "object" && settings.servers !== null && !Array.isArray(settings.servers) ? { ...settings.servers } : {};
|
|
@@ -33676,7 +33692,8 @@ var VSCODE_RUNTIME = {
|
|
|
33676
33692
|
merge: vscodeMerge,
|
|
33677
33693
|
strip: vscodeStrip,
|
|
33678
33694
|
validate: vscodeValidate,
|
|
33679
|
-
hasManaged: vscodeHasManaged
|
|
33695
|
+
hasManaged: vscodeHasManaged,
|
|
33696
|
+
listServers: (settings) => Object.keys(readVscodeServers(settings))
|
|
33680
33697
|
};
|
|
33681
33698
|
var MCP_CLIENT_RUNTIMES = [
|
|
33682
33699
|
CURSOR_RUNTIME,
|
|
@@ -33716,11 +33733,12 @@ async function mcpClientStatus(projectRoot, ids = mcpRuntimeIds()) {
|
|
|
33716
33733
|
for (const runtime of runtimes) {
|
|
33717
33734
|
const file = runtime.settingsPath(absoluteProjectRoot);
|
|
33718
33735
|
if (file === null) {
|
|
33719
|
-
statuses.push({ id: runtime.id, filePath: null, connected: false });
|
|
33736
|
+
statuses.push({ id: runtime.id, filePath: null, connected: false, otherServers: [] });
|
|
33720
33737
|
continue;
|
|
33721
33738
|
}
|
|
33722
33739
|
const settings = await readSettings2(file);
|
|
33723
|
-
|
|
33740
|
+
const otherServers = runtime.listServers(settings).filter((name) => name !== MCP_SERVER_NAME).sort();
|
|
33741
|
+
statuses.push({ id: runtime.id, filePath: file, connected: runtime.hasManaged(settings), otherServers });
|
|
33724
33742
|
}
|
|
33725
33743
|
return statuses;
|
|
33726
33744
|
}
|
|
@@ -33767,7 +33785,7 @@ function buildMcpModuleEntry() {
|
|
|
33767
33785
|
expose: {
|
|
33768
33786
|
tools: true,
|
|
33769
33787
|
resources: true,
|
|
33770
|
-
modules: ["gdgraph", "gdctx", "security", "flow", "memory", "health", "testing", "wiki", "standard", "sac", "gdskills"]
|
|
33788
|
+
modules: ["gdgraph", "gdctx", "security", "flow", "memory", "health", "testing", "wiki", "standard", "sac", "slate", "gdskills"]
|
|
33771
33789
|
}
|
|
33772
33790
|
};
|
|
33773
33791
|
}
|
|
@@ -43429,7 +43447,7 @@ function printSecurityHelp() {
|
|
|
43429
43447
|
|
|
43430
43448
|
// src/commands/mcp.ts
|
|
43431
43449
|
init_args();
|
|
43432
|
-
import
|
|
43450
|
+
import path137 from "path";
|
|
43433
43451
|
|
|
43434
43452
|
// src/mcp/discovery.ts
|
|
43435
43453
|
init_fs();
|
|
@@ -43444,7 +43462,8 @@ var MODULE_MANIFEST_KEY = {
|
|
|
43444
43462
|
wiki: "gdwiki",
|
|
43445
43463
|
standard: null,
|
|
43446
43464
|
mcp: null,
|
|
43447
|
-
sac: null
|
|
43465
|
+
sac: null,
|
|
43466
|
+
slate: null
|
|
43448
43467
|
};
|
|
43449
43468
|
function readMcpEntry(manifest) {
|
|
43450
43469
|
const entry = manifest.modules?.mcp;
|
|
@@ -43510,7 +43529,7 @@ init_metaproject_adapter();
|
|
|
43510
43529
|
init_service6();
|
|
43511
43530
|
init_service3();
|
|
43512
43531
|
init_service7();
|
|
43513
|
-
import { readFile as
|
|
43532
|
+
import { readFile as readFile76, writeFile as writeFile47 } from "fs/promises";
|
|
43514
43533
|
|
|
43515
43534
|
// src/mcp/metaproject-tools.ts
|
|
43516
43535
|
init_metaproject_adapter();
|
|
@@ -44401,12 +44420,116 @@ function normalizeCollaborationResult(value) {
|
|
|
44401
44420
|
// src/sac/service.ts
|
|
44402
44421
|
init_workspace_service();
|
|
44403
44422
|
|
|
44423
|
+
// src/session/external-slate.ts
|
|
44424
|
+
init_fs();
|
|
44425
|
+
init_machine_wrap_up();
|
|
44426
|
+
import { mkdir as mkdir54, readdir as readdir23, readFile as readFile75 } from "fs/promises";
|
|
44427
|
+
import path135 from "path";
|
|
44428
|
+
function externalSlatesDir(cwd) {
|
|
44429
|
+
return path135.join(cwd, ".keryx", "external-slates");
|
|
44430
|
+
}
|
|
44431
|
+
var EXTERNAL_SESSION_ID_PATTERN = /^[A-Za-z0-9_-]{1,128}$/;
|
|
44432
|
+
function assertValidExternalSessionId(externalSessionId) {
|
|
44433
|
+
if (!EXTERNAL_SESSION_ID_PATTERN.test(externalSessionId)) {
|
|
44434
|
+
throw new Error(`invalid externalSessionId ${JSON.stringify(externalSessionId)} \u2014 must match ${EXTERNAL_SESSION_ID_PATTERN.source} (letters, digits, "-", "_", 1-128 chars, no path separators)`);
|
|
44435
|
+
}
|
|
44436
|
+
}
|
|
44437
|
+
function externalSlatePath(cwd, externalSessionId) {
|
|
44438
|
+
assertValidExternalSessionId(externalSessionId);
|
|
44439
|
+
return path135.join(externalSlatesDir(cwd), `${externalSessionId}.json`);
|
|
44440
|
+
}
|
|
44441
|
+
function externalSlateLockPath(cwd, externalSessionId) {
|
|
44442
|
+
return `${externalSlatePath(cwd, externalSessionId)}.lock`;
|
|
44443
|
+
}
|
|
44444
|
+
function externalSlateEvidenceDir(cwd, externalSessionId) {
|
|
44445
|
+
assertValidExternalSessionId(externalSessionId);
|
|
44446
|
+
return path135.join(externalSlatesDir(cwd), externalSessionId);
|
|
44447
|
+
}
|
|
44448
|
+
async function readExternalSlate(cwd, externalSessionId) {
|
|
44449
|
+
try {
|
|
44450
|
+
const raw = await readFile75(externalSlatePath(cwd, externalSessionId), "utf8");
|
|
44451
|
+
return JSON.parse(raw);
|
|
44452
|
+
} catch (error2) {
|
|
44453
|
+
if (isNotFound(error2))
|
|
44454
|
+
return;
|
|
44455
|
+
throw error2;
|
|
44456
|
+
}
|
|
44457
|
+
}
|
|
44458
|
+
async function writeExternalSlate(cwd, externalSessionId, update) {
|
|
44459
|
+
await mkdir54(externalSlatesDir(cwd), { recursive: true });
|
|
44460
|
+
return withFileLock2(externalSlateLockPath(cwd, externalSessionId), async () => {
|
|
44461
|
+
const prev = await readExternalSlate(cwd, externalSessionId);
|
|
44462
|
+
const next = update(prev);
|
|
44463
|
+
await writeFileAtomic(externalSlatePath(cwd, externalSessionId), `${JSON.stringify(next, null, 2)}
|
|
44464
|
+
`);
|
|
44465
|
+
return next;
|
|
44466
|
+
});
|
|
44467
|
+
}
|
|
44468
|
+
async function listExternalSlateIds(cwd) {
|
|
44469
|
+
try {
|
|
44470
|
+
const entries = await readdir23(externalSlatesDir(cwd));
|
|
44471
|
+
return entries.filter((name) => name.endsWith(".json")).map((name) => name.slice(0, -".json".length));
|
|
44472
|
+
} catch (error2) {
|
|
44473
|
+
if (isNotFound(error2))
|
|
44474
|
+
return [];
|
|
44475
|
+
throw error2;
|
|
44476
|
+
}
|
|
44477
|
+
}
|
|
44478
|
+
function isExternalSlateStale(slate, now = () => new Date) {
|
|
44479
|
+
const lastWriteMs = new Date(slate.lastWriteAt).getTime();
|
|
44480
|
+
if (!Number.isFinite(lastWriteMs))
|
|
44481
|
+
return true;
|
|
44482
|
+
return now().getTime() - lastWriteMs > DEFAULT_LOCK_STALE_MS;
|
|
44483
|
+
}
|
|
44484
|
+
async function closeExternalSlate(cwd, externalSessionId, trigger, now = () => new Date) {
|
|
44485
|
+
await mkdir54(externalSlatesDir(cwd), { recursive: true });
|
|
44486
|
+
return withFileLock2(externalSlateLockPath(cwd, externalSessionId), async () => {
|
|
44487
|
+
const external = await readExternalSlate(cwd, externalSessionId);
|
|
44488
|
+
if (!external || external.closedAt !== undefined)
|
|
44489
|
+
return;
|
|
44490
|
+
const shimSlate = {
|
|
44491
|
+
...external.workspaceId !== undefined ? { workspaceId: external.workspaceId } : {},
|
|
44492
|
+
anchors: { root: external.anchors.root, touched: external.anchors.touched ?? [] },
|
|
44493
|
+
course: {},
|
|
44494
|
+
seeds: external.seeds
|
|
44495
|
+
};
|
|
44496
|
+
await runWrapUp({
|
|
44497
|
+
cwd,
|
|
44498
|
+
dir: externalSlateEvidenceDir(cwd, externalSessionId),
|
|
44499
|
+
slate: shimSlate,
|
|
44500
|
+
trigger,
|
|
44501
|
+
wrapUpSource: "external-slate",
|
|
44502
|
+
now
|
|
44503
|
+
});
|
|
44504
|
+
const next = { ...external, closedAt: now().toISOString() };
|
|
44505
|
+
await writeFileAtomic(externalSlatePath(cwd, externalSessionId), `${JSON.stringify(next, null, 2)}
|
|
44506
|
+
`);
|
|
44507
|
+
});
|
|
44508
|
+
}
|
|
44509
|
+
async function reclaimStaleExternalSlates(cwd, now = () => new Date) {
|
|
44510
|
+
const ids = await listExternalSlateIds(cwd);
|
|
44511
|
+
for (const id of ids) {
|
|
44512
|
+
try {
|
|
44513
|
+
const slate = await readExternalSlate(cwd, id);
|
|
44514
|
+
if (slate && isExternalSlateStale(slate, now)) {
|
|
44515
|
+
await closeExternalSlate(cwd, id, "external-slate-idle-reclaim", now);
|
|
44516
|
+
}
|
|
44517
|
+
} catch {}
|
|
44518
|
+
}
|
|
44519
|
+
}
|
|
44520
|
+
|
|
44521
|
+
// src/sac/service.ts
|
|
44522
|
+
init_slate();
|
|
44523
|
+
init_workspace_resolve();
|
|
44524
|
+
init_redact();
|
|
44525
|
+
|
|
44404
44526
|
// src/mcp/tools.ts
|
|
44405
44527
|
import { randomUUID as randomUUID17 } from "crypto";
|
|
44406
44528
|
function stringParam2(params, key) {
|
|
44407
44529
|
const value = params[key];
|
|
44408
44530
|
return typeof value === "string" ? value : undefined;
|
|
44409
44531
|
}
|
|
44532
|
+
var MAX_EXTERNAL_SLATE_SEEDS = 200;
|
|
44410
44533
|
async function loadGraphSafe(cwd) {
|
|
44411
44534
|
try {
|
|
44412
44535
|
return await loadGraph(cwd);
|
|
@@ -44427,6 +44550,38 @@ function readOnlyFlowService() {
|
|
|
44427
44550
|
now: () => new Date
|
|
44428
44551
|
});
|
|
44429
44552
|
}
|
|
44553
|
+
async function handleSlateOpen(params) {
|
|
44554
|
+
const { cwd, externalSessionId, resolveWorkspace } = params;
|
|
44555
|
+
if (externalSessionId.length === 0)
|
|
44556
|
+
throw new Error("slate.open requires a non-empty 'externalSessionId'");
|
|
44557
|
+
await reclaimStaleExternalSlates(cwd);
|
|
44558
|
+
const existing = await readExternalSlate(cwd, externalSessionId);
|
|
44559
|
+
if (existing)
|
|
44560
|
+
return existing;
|
|
44561
|
+
const rawAnchors = params.anchors && typeof params.anchors === "object" ? params.anchors : {};
|
|
44562
|
+
const anchors = {
|
|
44563
|
+
root: typeof rawAnchors.root === "string" ? rawAnchors.root : "",
|
|
44564
|
+
...Array.isArray(rawAnchors.touched) ? { touched: rawAnchors.touched.filter((t) => typeof t === "string") } : {},
|
|
44565
|
+
...typeof rawAnchors.note === "string" ? { note: rawAnchors.note } : {}
|
|
44566
|
+
};
|
|
44567
|
+
let workspaceId = params.workspaceId;
|
|
44568
|
+
if (workspaceId === undefined) {
|
|
44569
|
+
const resolver = resolveWorkspace ?? resolveOrCreateWorkspace;
|
|
44570
|
+
const topicHint = anchors.note ?? (anchors.root.length > 0 ? anchors.root : externalSessionId);
|
|
44571
|
+
try {
|
|
44572
|
+
const resolved = await resolver({ cwd, topicHint });
|
|
44573
|
+
if (resolved.ok)
|
|
44574
|
+
workspaceId = resolved.workspaceId;
|
|
44575
|
+
} catch {}
|
|
44576
|
+
}
|
|
44577
|
+
return writeExternalSlate(cwd, externalSessionId, () => ({
|
|
44578
|
+
externalSessionId,
|
|
44579
|
+
...workspaceId ? { workspaceId } : {},
|
|
44580
|
+
anchors,
|
|
44581
|
+
seeds: [],
|
|
44582
|
+
lastWriteAt: new Date().toISOString()
|
|
44583
|
+
}));
|
|
44584
|
+
}
|
|
44430
44585
|
function buildToolRegistry() {
|
|
44431
44586
|
return [
|
|
44432
44587
|
...toMcpTools(),
|
|
@@ -44558,6 +44713,102 @@ function buildToolRegistry() {
|
|
|
44558
44713
|
return workspace;
|
|
44559
44714
|
}
|
|
44560
44715
|
},
|
|
44716
|
+
{
|
|
44717
|
+
name: "slate.open",
|
|
44718
|
+
module: "slate",
|
|
44719
|
+
description: "Open (or idempotently re-open) this external hand's own private, task-local Slate \u2014 never readable/writable by a different externalSessionId. `anchors` is stored verbatim (root/touched/note), never harness-enriched.",
|
|
44720
|
+
inputSchema: OBJECT_SCHEMA({
|
|
44721
|
+
externalSessionId: { type: "string" },
|
|
44722
|
+
workspaceId: { type: "string", description: "Bind this slate to an already-known SAC workspace up front; omit to stay unbound (slate.close then preserves Seeds as a local unbound-candidate artifact)." },
|
|
44723
|
+
anchors: {
|
|
44724
|
+
type: "object",
|
|
44725
|
+
description: "{ root: string, touched?: string[], note?: string } \u2014 this hand's own self-report, stored exactly as given.",
|
|
44726
|
+
properties: { root: { type: "string" }, touched: { type: "array", items: { type: "string" } }, note: { type: "string" } }
|
|
44727
|
+
}
|
|
44728
|
+
}, ["externalSessionId"]),
|
|
44729
|
+
mutating: true,
|
|
44730
|
+
async invoke(cwd, params, context) {
|
|
44731
|
+
if (context?.transport === "http")
|
|
44732
|
+
return { code: "slate_transport_denied" };
|
|
44733
|
+
const externalSessionId = stringParam2(params, "externalSessionId") ?? "";
|
|
44734
|
+
const workspaceId = stringParam2(params, "workspaceId");
|
|
44735
|
+
return handleSlateOpen({
|
|
44736
|
+
cwd,
|
|
44737
|
+
externalSessionId,
|
|
44738
|
+
...workspaceId !== undefined ? { workspaceId } : {},
|
|
44739
|
+
anchors: params.anchors
|
|
44740
|
+
});
|
|
44741
|
+
}
|
|
44742
|
+
},
|
|
44743
|
+
{
|
|
44744
|
+
name: "slate.writeSeed",
|
|
44745
|
+
module: "slate",
|
|
44746
|
+
description: "Append a draft Seed (task-local hypothesis, not yet reviewed knowledge) to this external hand's own Slate. `origin`/`trust` are always server-set \u2014 a caller-supplied value for either is never used.",
|
|
44747
|
+
inputSchema: OBJECT_SCHEMA({ externalSessionId: { type: "string" }, text: { type: "string" }, kind: { type: "string", description: "decision | wiki-update | memory-entry | follow-up | contract-change | risk" } }, ["externalSessionId", "text"]),
|
|
44748
|
+
mutating: true,
|
|
44749
|
+
async invoke(cwd, params, context) {
|
|
44750
|
+
if (context?.transport === "http")
|
|
44751
|
+
return { code: "slate_transport_denied" };
|
|
44752
|
+
const externalSessionId = stringParam2(params, "externalSessionId") ?? "";
|
|
44753
|
+
const rawText = stringParam2(params, "text") ?? "";
|
|
44754
|
+
if (externalSessionId.length === 0)
|
|
44755
|
+
throw new Error("slate.writeSeed requires a non-empty 'externalSessionId'");
|
|
44756
|
+
if (rawText.length === 0)
|
|
44757
|
+
throw new Error("slate.writeSeed requires a non-empty 'text'");
|
|
44758
|
+
if (rawText.length > SEED_TEXT_MAX_LENGTH) {
|
|
44759
|
+
throw new Error(`slate.writeSeed: 'text' exceeds the ${SEED_TEXT_MAX_LENGTH}-character limit (got ${rawText.length})`);
|
|
44760
|
+
}
|
|
44761
|
+
await reclaimStaleExternalSlates(cwd);
|
|
44762
|
+
const rawKind = stringParam2(params, "kind");
|
|
44763
|
+
let kind;
|
|
44764
|
+
if (rawKind !== undefined) {
|
|
44765
|
+
if (!isSlateSeedKind(rawKind)) {
|
|
44766
|
+
throw new Error(`slate.writeSeed: unrecognized 'kind' "${rawKind}"`);
|
|
44767
|
+
}
|
|
44768
|
+
kind = rawKind;
|
|
44769
|
+
}
|
|
44770
|
+
const text = redactSensitiveText(rawText);
|
|
44771
|
+
const ts = new Date().toISOString();
|
|
44772
|
+
const seed = {
|
|
44773
|
+
id: `seed-${randomUUID17()}`,
|
|
44774
|
+
text,
|
|
44775
|
+
ts,
|
|
44776
|
+
...kind ? { kind } : {},
|
|
44777
|
+
origin: { harness: "mcp-external" },
|
|
44778
|
+
trust: "external-unverified"
|
|
44779
|
+
};
|
|
44780
|
+
return writeExternalSlate(cwd, externalSessionId, (prev) => {
|
|
44781
|
+
if (!prev)
|
|
44782
|
+
throw new Error(`slate.writeSeed: no open external slate for "${externalSessionId}" \u2014 call slate.open first`);
|
|
44783
|
+
if (prev.closedAt !== undefined)
|
|
44784
|
+
throw new Error(`slate.writeSeed: external slate "${externalSessionId}" is already closed`);
|
|
44785
|
+
if (prev.seeds.length >= MAX_EXTERNAL_SLATE_SEEDS) {
|
|
44786
|
+
throw new Error(`slate.writeSeed: external slate "${externalSessionId}" already has ${MAX_EXTERNAL_SLATE_SEEDS} seeds (the maximum) \u2014 close it and open a fresh one`);
|
|
44787
|
+
}
|
|
44788
|
+
return { ...prev, seeds: [...prev.seeds, seed], lastWriteAt: ts };
|
|
44789
|
+
});
|
|
44790
|
+
}
|
|
44791
|
+
},
|
|
44792
|
+
{
|
|
44793
|
+
name: "slate.close",
|
|
44794
|
+
module: "slate",
|
|
44795
|
+
description: "Close this external hand's Slate: dispatches into the existing SAC propose/review pipeline (mirrors SLATE-18's autonomous workspace_propose) when a workspaceId is bound, else preserves its Seeds as a local unbound-candidate artifact \u2014 never a proposal against a guessed workspaceId.",
|
|
44796
|
+
inputSchema: OBJECT_SCHEMA({ externalSessionId: { type: "string" } }, ["externalSessionId"]),
|
|
44797
|
+
mutating: true,
|
|
44798
|
+
async invoke(cwd, params, context) {
|
|
44799
|
+
if (context?.transport === "http")
|
|
44800
|
+
return { code: "slate_transport_denied" };
|
|
44801
|
+
const externalSessionId = stringParam2(params, "externalSessionId") ?? "";
|
|
44802
|
+
if (externalSessionId.length === 0)
|
|
44803
|
+
throw new Error("slate.close requires a non-empty 'externalSessionId'");
|
|
44804
|
+
await reclaimStaleExternalSlates(cwd);
|
|
44805
|
+
const existing = await readExternalSlate(cwd, externalSessionId);
|
|
44806
|
+
if (!existing)
|
|
44807
|
+
return { externalSessionId, closed: true, alreadyClosed: true };
|
|
44808
|
+
await closeExternalSlate(cwd, externalSessionId, "external-slate-close");
|
|
44809
|
+
return { externalSessionId, closed: true };
|
|
44810
|
+
}
|
|
44811
|
+
},
|
|
44561
44812
|
{
|
|
44562
44813
|
name: "gdgraph.affected",
|
|
44563
44814
|
module: "gdgraph",
|
|
@@ -44620,7 +44871,7 @@ function buildToolRegistry() {
|
|
|
44620
44871
|
async invoke(cwd, params) {
|
|
44621
44872
|
const filePath = stringParam2(params, "path");
|
|
44622
44873
|
const inline = stringParam2(params, "content");
|
|
44623
|
-
const content = inline ?? (filePath ? await
|
|
44874
|
+
const content = inline ?? (filePath ? await readFile76(filePath, "utf8") : "");
|
|
44624
44875
|
const result = await runScan(cwd, {
|
|
44625
44876
|
content,
|
|
44626
44877
|
source: "trusted-project",
|
|
@@ -44741,8 +44992,8 @@ function buildToolRegistry() {
|
|
|
44741
44992
|
|
|
44742
44993
|
// src/mcp/resources.ts
|
|
44743
44994
|
init_fs();
|
|
44744
|
-
import
|
|
44745
|
-
import { readdir as
|
|
44995
|
+
import path136 from "path";
|
|
44996
|
+
import { readdir as readdir24, readFile as readFile77, stat as stat7 } from "fs/promises";
|
|
44746
44997
|
var URI_PREFIX = "metaproject://";
|
|
44747
44998
|
function mimeForPath(filePath) {
|
|
44748
44999
|
if (filePath.endsWith(".json") || filePath.endsWith(".jsonl")) {
|
|
@@ -44754,13 +45005,13 @@ function mimeForPath(filePath) {
|
|
|
44754
45005
|
return "text/plain";
|
|
44755
45006
|
}
|
|
44756
45007
|
function dataRoot3(cwd) {
|
|
44757
|
-
return
|
|
45008
|
+
return path136.join(cwd, ".metaproject", "data");
|
|
44758
45009
|
}
|
|
44759
45010
|
function wikiRoot(cwd) {
|
|
44760
|
-
return
|
|
45011
|
+
return path136.join(cwd, ".metaproject", "wiki");
|
|
44761
45012
|
}
|
|
44762
45013
|
function memoryRoot2(cwd) {
|
|
44763
|
-
return
|
|
45014
|
+
return path136.join(cwd, ".metaproject", "memory");
|
|
44764
45015
|
}
|
|
44765
45016
|
async function walkFiles(root) {
|
|
44766
45017
|
if (!await pathExists(root)) {
|
|
@@ -44769,12 +45020,12 @@ async function walkFiles(root) {
|
|
|
44769
45020
|
const out = [];
|
|
44770
45021
|
let entries;
|
|
44771
45022
|
try {
|
|
44772
|
-
entries = await
|
|
45023
|
+
entries = await readdir24(root, { withFileTypes: true });
|
|
44773
45024
|
} catch {
|
|
44774
45025
|
return [];
|
|
44775
45026
|
}
|
|
44776
45027
|
for (const entry of entries) {
|
|
44777
|
-
const full =
|
|
45028
|
+
const full = path136.join(root, entry.name);
|
|
44778
45029
|
if (entry.isDirectory()) {
|
|
44779
45030
|
out.push(...await walkFiles(full));
|
|
44780
45031
|
} else if (entry.isFile()) {
|
|
@@ -44791,7 +45042,7 @@ async function listArtifacts(cwd) {
|
|
|
44791
45042
|
const listings = [];
|
|
44792
45043
|
let modules;
|
|
44793
45044
|
try {
|
|
44794
|
-
modules = await
|
|
45045
|
+
modules = await readdir24(base, { withFileTypes: true });
|
|
44795
45046
|
} catch {
|
|
44796
45047
|
return [];
|
|
44797
45048
|
}
|
|
@@ -44799,9 +45050,9 @@ async function listArtifacts(cwd) {
|
|
|
44799
45050
|
if (!moduleEntry.isDirectory()) {
|
|
44800
45051
|
continue;
|
|
44801
45052
|
}
|
|
44802
|
-
const artifactsDir2 =
|
|
45053
|
+
const artifactsDir2 = path136.join(base, moduleEntry.name, "artifacts");
|
|
44803
45054
|
for (const file of await walkFiles(artifactsDir2)) {
|
|
44804
|
-
const rel = toPosix(
|
|
45055
|
+
const rel = toPosix(path136.relative(artifactsDir2, file));
|
|
44805
45056
|
const relPath = `${moduleEntry.name}/${rel}`;
|
|
44806
45057
|
listings.push({
|
|
44807
45058
|
uri: `${URI_PREFIX}artifacts/${relPath}`,
|
|
@@ -44815,7 +45066,7 @@ async function listArtifacts(cwd) {
|
|
|
44815
45066
|
async function listUnderRoot(cwd, cls, root) {
|
|
44816
45067
|
const listings = [];
|
|
44817
45068
|
for (const file of await walkFiles(root)) {
|
|
44818
|
-
const rel = toPosix(
|
|
45069
|
+
const rel = toPosix(path136.relative(root, file));
|
|
44819
45070
|
listings.push({
|
|
44820
45071
|
uri: `${URI_PREFIX}${cls}/${rel}`,
|
|
44821
45072
|
name: rel,
|
|
@@ -44865,12 +45116,12 @@ function resolveConfined(cwd, cls, relPath) {
|
|
|
44865
45116
|
if (moduleName.includes("..") || moduleName.length === 0) {
|
|
44866
45117
|
return null;
|
|
44867
45118
|
}
|
|
44868
|
-
const root2 =
|
|
44869
|
-
const absolute2 =
|
|
45119
|
+
const root2 = path136.join(dataRoot3(cwd), moduleName, "artifacts");
|
|
45120
|
+
const absolute2 = path136.resolve(root2, rest);
|
|
44870
45121
|
return isPathInside(root2, absolute2) ? { root: root2, absolute: absolute2 } : null;
|
|
44871
45122
|
}
|
|
44872
45123
|
const root = cls === "wiki" ? wikiRoot(cwd) : memoryRoot2(cwd);
|
|
44873
|
-
const absolute =
|
|
45124
|
+
const absolute = path136.resolve(root, relPath);
|
|
44874
45125
|
return isPathInside(root, absolute) ? { root, absolute } : null;
|
|
44875
45126
|
}
|
|
44876
45127
|
async function readResource(cwd, roots, uri) {
|
|
@@ -44889,7 +45140,7 @@ async function readResource(cwd, roots, uri) {
|
|
|
44889
45140
|
if (!info || !info.isFile()) {
|
|
44890
45141
|
throw new Error(`Resource not found: ${uri}`);
|
|
44891
45142
|
}
|
|
44892
|
-
const text = await
|
|
45143
|
+
const text = await readFile77(resolved.absolute, "utf8");
|
|
44893
45144
|
return { uri, mimeType: mimeForPath(resolved.absolute), text };
|
|
44894
45145
|
}
|
|
44895
45146
|
|
|
@@ -45070,7 +45321,7 @@ async function mcpCommand(args2 = [], cwd = process.cwd()) {
|
|
|
45070
45321
|
}
|
|
45071
45322
|
if (!subcommand || subcommand === "serve") {
|
|
45072
45323
|
const http = args2.includes("--http");
|
|
45073
|
-
const projectRoot =
|
|
45324
|
+
const projectRoot = path137.resolve(optionValue(args2, "--cwd") ?? cwd);
|
|
45074
45325
|
try {
|
|
45075
45326
|
await serveMcp({ cwd: projectRoot, http });
|
|
45076
45327
|
} catch (error2) {
|
|
@@ -45104,7 +45355,7 @@ async function handleInstall2(cwd, args2) {
|
|
|
45104
45355
|
console.log(outcome.snippet ?? "");
|
|
45105
45356
|
continue;
|
|
45106
45357
|
}
|
|
45107
|
-
const rel =
|
|
45358
|
+
const rel = path137.relative(cwd, outcome.filePath);
|
|
45108
45359
|
if (outcome.errors.length > 0) {
|
|
45109
45360
|
for (const e of outcome.errors) {
|
|
45110
45361
|
console.log(` ${style.red(symbols.cross)} ${e}`);
|
|
@@ -45144,7 +45395,7 @@ async function handleUninstall2(cwd, args2) {
|
|
|
45144
45395
|
console.log(` ${style.gray(symbols.off)} ${outcome.id} ${style.dim("no file to change")}`);
|
|
45145
45396
|
continue;
|
|
45146
45397
|
}
|
|
45147
|
-
const rel =
|
|
45398
|
+
const rel = path137.relative(cwd, outcome.filePath);
|
|
45148
45399
|
console.log(` ${outcome.removed ? style.green(symbols.ok) : style.gray(symbols.off)} ${outcome.id} ${style.dim(outcome.removed ? `removed from ${rel}` : "nothing to remove")}`);
|
|
45149
45400
|
}
|
|
45150
45401
|
}
|
|
@@ -45174,14 +45425,14 @@ function printMcpHelp() {
|
|
|
45174
45425
|
// src/commands/status.ts
|
|
45175
45426
|
init_fs();
|
|
45176
45427
|
init_json();
|
|
45177
|
-
import
|
|
45428
|
+
import path138 from "path";
|
|
45178
45429
|
async function statusCommand(args2 = []) {
|
|
45179
45430
|
if (args2.includes("--help") || args2.includes("-h")) {
|
|
45180
45431
|
printHelp14();
|
|
45181
45432
|
return;
|
|
45182
45433
|
}
|
|
45183
|
-
const root =
|
|
45184
|
-
const manifestPath =
|
|
45434
|
+
const root = path138.join(process.cwd(), ".metaproject");
|
|
45435
|
+
const manifestPath = path138.join(root, "metaproject.json");
|
|
45185
45436
|
if (!await pathExists(root)) {
|
|
45186
45437
|
console.log("Metaproject: not initialized");
|
|
45187
45438
|
console.log("Run: keryx init");
|
|
@@ -45221,7 +45472,7 @@ Reports the workspace root and one enabled/disabled line per module. Use
|
|
|
45221
45472
|
|
|
45222
45473
|
// src/commands/harness.ts
|
|
45223
45474
|
import { readFileSync as readFileSync8, writeFileSync as writeFileSync7 } from "fs";
|
|
45224
|
-
import
|
|
45475
|
+
import path142 from "path";
|
|
45225
45476
|
import { randomUUID as randomUUID18 } from "crypto";
|
|
45226
45477
|
|
|
45227
45478
|
// src/security/harness-scan.ts
|
|
@@ -46294,7 +46545,7 @@ ${command.argv.join(" ")}`);
|
|
|
46294
46545
|
}
|
|
46295
46546
|
|
|
46296
46547
|
// src/harness/process/sandbox/profile.ts
|
|
46297
|
-
import
|
|
46548
|
+
import path139 from "path";
|
|
46298
46549
|
var DEFAULT_SECRET_SUBPATHS = [
|
|
46299
46550
|
".ssh",
|
|
46300
46551
|
".gnupg",
|
|
@@ -46319,7 +46570,7 @@ function defaultReadDenyList(home) {
|
|
|
46319
46570
|
if (!home) {
|
|
46320
46571
|
return [];
|
|
46321
46572
|
}
|
|
46322
|
-
return DEFAULT_SECRET_SUBPATHS.map((sub) =>
|
|
46573
|
+
return DEFAULT_SECRET_SUBPATHS.map((sub) => path139.join(home, sub));
|
|
46323
46574
|
}
|
|
46324
46575
|
function defaultSandboxProfile(cwd, tmpDir, home) {
|
|
46325
46576
|
return {
|
|
@@ -46337,7 +46588,7 @@ function dedupe2(values) {
|
|
|
46337
46588
|
|
|
46338
46589
|
// src/harness/process/sandbox/detect.ts
|
|
46339
46590
|
import { existsSync as realExistsSync } from "fs";
|
|
46340
|
-
import
|
|
46591
|
+
import path140 from "path";
|
|
46341
46592
|
|
|
46342
46593
|
// src/harness/process/sandbox/seatbelt.ts
|
|
46343
46594
|
var SANDBOX_EXEC_PATH = "/usr/bin/sandbox-exec";
|
|
@@ -46531,9 +46782,9 @@ function detectSandboxLauncher(opts = {}) {
|
|
|
46531
46782
|
}
|
|
46532
46783
|
if (platform === "linux") {
|
|
46533
46784
|
const env = opts.env ?? process.env;
|
|
46534
|
-
const dirs = (env.PATH ?? "").split(
|
|
46785
|
+
const dirs = (env.PATH ?? "").split(path140.delimiter).filter(Boolean);
|
|
46535
46786
|
for (const dir of dirs) {
|
|
46536
|
-
const candidate =
|
|
46787
|
+
const candidate = path140.join(dir, BWRAP_PROGRAM);
|
|
46537
46788
|
if (exists2(candidate)) {
|
|
46538
46789
|
return { available: true, platform, path: candidate };
|
|
46539
46790
|
}
|
|
@@ -46563,10 +46814,10 @@ function resolveSandboxAdapter(profile, inner, opts = {}) {
|
|
|
46563
46814
|
init_config_dir();
|
|
46564
46815
|
init_shell_config();
|
|
46565
46816
|
import { existsSync as existsSync22 } from "fs";
|
|
46566
|
-
import
|
|
46817
|
+
import path141 from "path";
|
|
46567
46818
|
var SECRET_KEY_PATTERN2 = /api[_-]?key|secret|token|password|credential/i;
|
|
46568
46819
|
function sandboxConfigPath(dir) {
|
|
46569
|
-
return
|
|
46820
|
+
return path141.join(path141.dirname(shellConfigPath(dir)), "sandbox.json");
|
|
46570
46821
|
}
|
|
46571
46822
|
function isShellDefault(v) {
|
|
46572
46823
|
return v === "off" || v === "workspace" || v === "strict" || v === "1";
|
|
@@ -47685,7 +47936,7 @@ async function harnessExec(args2, deps) {
|
|
|
47685
47936
|
env: commandEnv,
|
|
47686
47937
|
cwd
|
|
47687
47938
|
};
|
|
47688
|
-
const worktreeRoot =
|
|
47939
|
+
const worktreeRoot = path142.parse(path142.resolve(cwd, commandPath)).root || cwd;
|
|
47689
47940
|
const budget = {
|
|
47690
47941
|
reservationId: idSeq(),
|
|
47691
47942
|
maxRuntimeMs: maxRuntimeMs ?? EXEC_DEFAULT_RUNTIME_MS
|
|
@@ -47921,7 +48172,7 @@ async function buildApprovalContext(port, command) {
|
|
|
47921
48172
|
import { randomUUID as randomUUID20 } from "crypto";
|
|
47922
48173
|
|
|
47923
48174
|
// src/harness/tool/builtin/interactive-tools.ts
|
|
47924
|
-
import { readdir as
|
|
48175
|
+
import { readdir as readdir25 } from "fs/promises";
|
|
47925
48176
|
import { isAbsolute as isAbsolute2, relative as relative2, resolve as resolve2, sep } from "path";
|
|
47926
48177
|
import { realpathSync as realpathSync4 } from "fs";
|
|
47927
48178
|
var MAX_READ_BYTES = 20000;
|
|
@@ -47973,7 +48224,7 @@ function builtinReadOnlyTools(root) {
|
|
|
47973
48224
|
return { output: `path escapes the project root: ${requested}`, isError: true };
|
|
47974
48225
|
}
|
|
47975
48226
|
try {
|
|
47976
|
-
const entries = await
|
|
48227
|
+
const entries = await readdir25(target, { withFileTypes: true });
|
|
47977
48228
|
const lines = entries.map((e) => e.isDirectory() ? `${e.name}/` : e.name).sort();
|
|
47978
48229
|
return { output: lines.length > 0 ? lines.join(`
|
|
47979
48230
|
`) : "(empty)", isError: false };
|
|
@@ -48887,13 +49138,13 @@ function builtinMetaprojectTools(root, run = makeKeryxRunner(root), port) {
|
|
|
48887
49138
|
if ("error" in pattern) {
|
|
48888
49139
|
return pattern.error;
|
|
48889
49140
|
}
|
|
48890
|
-
const
|
|
49141
|
+
const path143 = typeof input2.path === "string" && input2.path.length > 0 ? input2.path : undefined;
|
|
48891
49142
|
const args2 = ["ctx", "rg", pattern.value];
|
|
48892
|
-
if (
|
|
48893
|
-
const confined = confineToRoot(root,
|
|
49143
|
+
if (path143 !== undefined) {
|
|
49144
|
+
const confined = confineToRoot(root, path143);
|
|
48894
49145
|
if (confined === null) {
|
|
48895
49146
|
return {
|
|
48896
|
-
output: `search_code: path escapes the project root: ${
|
|
49147
|
+
output: `search_code: path escapes the project root: ${path143}`,
|
|
48897
49148
|
isError: true
|
|
48898
49149
|
};
|
|
48899
49150
|
}
|
|
@@ -48949,18 +49200,6 @@ function builtinMetaprojectTools(root, run = makeKeryxRunner(root), port) {
|
|
|
48949
49200
|
init_slate();
|
|
48950
49201
|
init_slate_course();
|
|
48951
49202
|
init_redact();
|
|
48952
|
-
var SEED_TEXT_MAX_LENGTH = 4000;
|
|
48953
|
-
var SLATE_SEED_KINDS = [
|
|
48954
|
-
"decision",
|
|
48955
|
-
"wiki-update",
|
|
48956
|
-
"memory-entry",
|
|
48957
|
-
"follow-up",
|
|
48958
|
-
"contract-change",
|
|
48959
|
-
"risk"
|
|
48960
|
-
];
|
|
48961
|
-
function isSlateSeedKind(value) {
|
|
48962
|
-
return typeof value === "string" && SLATE_SEED_KINDS.includes(value);
|
|
48963
|
-
}
|
|
48964
49203
|
function slateReadTool(cwd, getSessionDir) {
|
|
48965
49204
|
return {
|
|
48966
49205
|
definition: {
|
|
@@ -49609,7 +49848,7 @@ init_shell_config();
|
|
|
49609
49848
|
init_command_risk();
|
|
49610
49849
|
init_shell_syntax();
|
|
49611
49850
|
import { existsSync as existsSync24 } from "fs";
|
|
49612
|
-
import
|
|
49851
|
+
import path143 from "path";
|
|
49613
49852
|
import { createHash as createHash31 } from "crypto";
|
|
49614
49853
|
var PREFIX_BANNED = new Set([
|
|
49615
49854
|
"sh",
|
|
@@ -49795,7 +50034,7 @@ function emptyShellPermissions() {
|
|
|
49795
50034
|
return { allow: [] };
|
|
49796
50035
|
}
|
|
49797
50036
|
function shellPermissionsPath(dir) {
|
|
49798
|
-
return
|
|
50037
|
+
return path143.join(path143.dirname(shellConfigPath(dir)), "permissions.json");
|
|
49799
50038
|
}
|
|
49800
50039
|
function loadShellPermissionsWithAudit(dir) {
|
|
49801
50040
|
try {
|
|
@@ -49833,7 +50072,7 @@ function loadShellPermissions(dir) {
|
|
|
49833
50072
|
function saveShellPermissions(perms, dir, options = {}) {
|
|
49834
50073
|
try {
|
|
49835
50074
|
const file = shellPermissionsPath(dir);
|
|
49836
|
-
ensureKeryxConfigDir(
|
|
50075
|
+
ensureKeryxConfigDir(path143.dirname(file));
|
|
49837
50076
|
const cleaned = Array.from(new Set(perms.allow.map((p) => p.trim()).filter((p) => p.length > 0)));
|
|
49838
50077
|
const body = {
|
|
49839
50078
|
allow: options.skipValidation === true ? cleaned : cleaned.filter((p) => validateShellPattern(p).ok)
|
|
@@ -50150,12 +50389,12 @@ function remoteRequest(providerId, endpoint, query, key) {
|
|
|
50150
50389
|
// src/lib/search-config.ts
|
|
50151
50390
|
init_config_dir();
|
|
50152
50391
|
import { existsSync as existsSync25 } from "fs";
|
|
50153
|
-
import
|
|
50392
|
+
import path144 from "path";
|
|
50154
50393
|
function searchConfigPath(dir) {
|
|
50155
|
-
return
|
|
50394
|
+
return path144.join(keryxConfigDir(dir), "search-providers.json");
|
|
50156
50395
|
}
|
|
50157
50396
|
function searchCredentialPath(dir) {
|
|
50158
|
-
return
|
|
50397
|
+
return path144.join(keryxConfigDir(dir), "search-credentials.json");
|
|
50159
50398
|
}
|
|
50160
50399
|
function readJson(file) {
|
|
50161
50400
|
try {
|
|
@@ -50284,7 +50523,7 @@ function createDefaultSearchProviderController(configDir) {
|
|
|
50284
50523
|
import { createHash as createHash32, randomUUID as randomUUID21 } from "crypto";
|
|
50285
50524
|
import { mkdtemp, rm as rm8 } from "fs/promises";
|
|
50286
50525
|
import { tmpdir as tmpdir4 } from "os";
|
|
50287
|
-
import
|
|
50526
|
+
import path145 from "path";
|
|
50288
50527
|
init_metaproject_adapter();
|
|
50289
50528
|
init_ledger();
|
|
50290
50529
|
init_orchestrate();
|
|
@@ -50535,8 +50774,8 @@ function createSpawnSubagentTool(deps) {
|
|
|
50535
50774
|
let dispatchId = "";
|
|
50536
50775
|
let closing = false;
|
|
50537
50776
|
try {
|
|
50538
|
-
ephemeralDir = await mkdtemp(
|
|
50539
|
-
dispatchId =
|
|
50777
|
+
ephemeralDir = await mkdtemp(path145.join(tmpdir4(), "keryx-subagent-slate-"));
|
|
50778
|
+
dispatchId = path145.basename(ephemeralDir);
|
|
50540
50779
|
openedChildSlate = await openSlate({
|
|
50541
50780
|
dir: ephemeralDir,
|
|
50542
50781
|
cwd,
|
|
@@ -50778,9 +51017,9 @@ ${boundSummary(folded.text)}`,
|
|
|
50778
51017
|
// src/harness/run-external-factory.ts
|
|
50779
51018
|
import { randomUUID as randomUUID22 } from "crypto";
|
|
50780
51019
|
import { execFile as execFile4 } from "child_process";
|
|
50781
|
-
import { mkdir as
|
|
51020
|
+
import { mkdir as mkdir55 } from "fs/promises";
|
|
50782
51021
|
import { tmpdir as tmpdir6 } from "os";
|
|
50783
|
-
import
|
|
51022
|
+
import path147 from "path";
|
|
50784
51023
|
import { promisify as promisify4 } from "util";
|
|
50785
51024
|
|
|
50786
51025
|
// src/harness/child/git-worktree-port.ts
|
|
@@ -50793,27 +51032,27 @@ function createGitWorktreePort(options) {
|
|
|
50793
51032
|
const paths = new Map;
|
|
50794
51033
|
return {
|
|
50795
51034
|
async create(worktreeId) {
|
|
50796
|
-
const
|
|
50797
|
-
await execFileAsync3("git", ["worktree", "add", "--detach",
|
|
50798
|
-
paths.set(worktreeId,
|
|
50799
|
-
return { worktreeId, path:
|
|
51035
|
+
const path146 = `${worktreesDir}/${worktreeId}`;
|
|
51036
|
+
await execFileAsync3("git", ["worktree", "add", "--detach", path146, ref], { cwd: repoRoot });
|
|
51037
|
+
paths.set(worktreeId, path146);
|
|
51038
|
+
return { worktreeId, path: path146 };
|
|
50800
51039
|
},
|
|
50801
51040
|
async remove(worktreeId) {
|
|
50802
|
-
const
|
|
50803
|
-
if (
|
|
51041
|
+
const path146 = paths.get(worktreeId);
|
|
51042
|
+
if (path146 === undefined)
|
|
50804
51043
|
return;
|
|
50805
|
-
await execFileAsync3("git", ["worktree", "remove", "--force",
|
|
51044
|
+
await execFileAsync3("git", ["worktree", "remove", "--force", path146], { cwd: repoRoot });
|
|
50806
51045
|
paths.delete(worktreeId);
|
|
50807
51046
|
await execFileAsync3("git", ["worktree", "prune"], { cwd: repoRoot }).catch(() => {
|
|
50808
51047
|
return;
|
|
50809
51048
|
});
|
|
50810
51049
|
},
|
|
50811
51050
|
async merge(worktreeId, into) {
|
|
50812
|
-
const
|
|
50813
|
-
if (
|
|
51051
|
+
const path146 = paths.get(worktreeId);
|
|
51052
|
+
if (path146 === undefined) {
|
|
50814
51053
|
return { worktreeId, ok: false, conflicts: [`worktree "${worktreeId}" was not created by this port`] };
|
|
50815
51054
|
}
|
|
50816
|
-
const status = await execFileAsync3("git", ["status", "--porcelain"], { cwd:
|
|
51055
|
+
const status = await execFileAsync3("git", ["status", "--porcelain"], { cwd: path146 });
|
|
50817
51056
|
if (status.stdout.trim().length === 0) {
|
|
50818
51057
|
return { worktreeId, ok: true };
|
|
50819
51058
|
}
|
|
@@ -51079,7 +51318,7 @@ function canNestExternalChild(env, maxDepth) {
|
|
|
51079
51318
|
// src/harness/external/runtime.ts
|
|
51080
51319
|
import { mkdtemp as mkdtemp2, rm as rm9, writeFile as writeFile48 } from "fs/promises";
|
|
51081
51320
|
import { tmpdir as tmpdir5 } from "os";
|
|
51082
|
-
import
|
|
51321
|
+
import path146 from "path";
|
|
51083
51322
|
|
|
51084
51323
|
// src/harness/external/prompt.ts
|
|
51085
51324
|
var EXTERNAL_RUNTIME_DIRECTIVE = [
|
|
@@ -52122,8 +52361,8 @@ async function prepareResultSchema() {
|
|
|
52122
52361
|
try {
|
|
52123
52362
|
const schema = await loadSchema("subagent-result");
|
|
52124
52363
|
const schemaText = JSON.stringify(schema, null, 2);
|
|
52125
|
-
schemaDir = await mkdtemp2(
|
|
52126
|
-
const schemaPath =
|
|
52364
|
+
schemaDir = await mkdtemp2(path146.join(tmpdir5(), "keryx-external-result-schema-"));
|
|
52365
|
+
const schemaPath = path146.join(schemaDir, "subagent-result.schema.json");
|
|
52127
52366
|
await writeFile48(schemaPath, schemaText, "utf8");
|
|
52128
52367
|
return { ok: true, schema, schemaText, schemaPath, schemaDir };
|
|
52129
52368
|
} catch (error2) {
|
|
@@ -52350,7 +52589,7 @@ async function defaultWorkingDiff(cwd) {
|
|
|
52350
52589
|
function ensuringParentDir(port, worktreesDir) {
|
|
52351
52590
|
return {
|
|
52352
52591
|
async create(worktreeId) {
|
|
52353
|
-
await
|
|
52592
|
+
await mkdir55(worktreesDir, { recursive: true });
|
|
52354
52593
|
return port.create(worktreeId);
|
|
52355
52594
|
},
|
|
52356
52595
|
remove: (worktreeId) => port.remove(worktreeId),
|
|
@@ -52380,7 +52619,7 @@ async function createRunExternal(options) {
|
|
|
52380
52619
|
}
|
|
52381
52620
|
const config = gate.config;
|
|
52382
52621
|
const idSeq = options.idSeq ?? (() => randomUUID22());
|
|
52383
|
-
const worktreesDir = options.worktreesDir ??
|
|
52622
|
+
const worktreesDir = options.worktreesDir ?? path147.join(tmpdir6(), "keryx-external-worktrees");
|
|
52384
52623
|
const spawn5 = options.spawn ?? createBunSpawnPort();
|
|
52385
52624
|
const worktree = options.worktree ?? ensuringParentDir(createGitWorktreePort({ repoRoot: options.cwd, worktreesDir }), worktreesDir);
|
|
52386
52625
|
const readWorkingDiff = options.readWorkingDiff ?? (() => defaultWorkingDiff(options.cwd));
|
|
@@ -52565,12 +52804,12 @@ async function approveExternalSpawn(request) {
|
|
|
52565
52804
|
import { homedir as homedir6 } from "os";
|
|
52566
52805
|
var ESC = "\x1B";
|
|
52567
52806
|
var CSI = `${ESC}[`;
|
|
52568
|
-
function collapseHome(
|
|
52807
|
+
function collapseHome(path148) {
|
|
52569
52808
|
const home = homedir6();
|
|
52570
|
-
if (home.length > 0 && (
|
|
52571
|
-
return `~${
|
|
52809
|
+
if (home.length > 0 && (path148 === home || path148.startsWith(`${home}/`))) {
|
|
52810
|
+
return `~${path148.slice(home.length)}`;
|
|
52572
52811
|
}
|
|
52573
|
-
return
|
|
52812
|
+
return path148;
|
|
52574
52813
|
}
|
|
52575
52814
|
|
|
52576
52815
|
// src/lib/live-render.ts
|
|
@@ -52676,7 +52915,7 @@ class LiveMarkdownBlock {
|
|
|
52676
52915
|
// src/tui/theme.ts
|
|
52677
52916
|
init_config_dir();
|
|
52678
52917
|
import { existsSync as existsSync26 } from "fs";
|
|
52679
|
-
import
|
|
52918
|
+
import path148 from "path";
|
|
52680
52919
|
var THEME_NAMES = ["groknight", "grokday", "tokyonight", "keryx"];
|
|
52681
52920
|
var THEME_IDS = ["auto", ...THEME_NAMES];
|
|
52682
52921
|
var DEFAULT_THEME_ID = "groknight";
|
|
@@ -52806,7 +53045,7 @@ function onThemeChange(listener4) {
|
|
|
52806
53045
|
};
|
|
52807
53046
|
}
|
|
52808
53047
|
function tuiConfigPath(dir) {
|
|
52809
|
-
return
|
|
53048
|
+
return path148.join(keryxConfigDir(dir), "tui.json");
|
|
52810
53049
|
}
|
|
52811
53050
|
function loadPersistedThemeId(dir) {
|
|
52812
53051
|
try {
|
|
@@ -52860,28 +53099,63 @@ init_slate_lifecycle();
|
|
|
52860
53099
|
init_slate();
|
|
52861
53100
|
init_workspace_service();
|
|
52862
53101
|
init_workspace_resolve();
|
|
53102
|
+
init_service7();
|
|
53103
|
+
init_fs();
|
|
53104
|
+
import path149 from "path";
|
|
53105
|
+
var POSITIVE_INTEGER = /^[1-9][0-9]*$/;
|
|
53106
|
+
var DEFAULT_AUTO_GOAL_ROUNDS = 8;
|
|
52863
53107
|
function parseGoalArgs(rest) {
|
|
52864
53108
|
const trimmed = rest.trim();
|
|
52865
53109
|
if (trimmed.length === 0) {
|
|
52866
|
-
return {
|
|
53110
|
+
return {
|
|
53111
|
+
error: "a goal <text> is required, e.g. /goal implement the login flow [--workspace <id>] [--auto [N]]"
|
|
53112
|
+
};
|
|
52867
53113
|
}
|
|
52868
|
-
|
|
52869
|
-
const lastToken = tokens[tokens.length - 1];
|
|
52870
|
-
const secondLastToken = tokens[tokens.length - 2];
|
|
53114
|
+
let tokens = trimmed.split(/\s+/);
|
|
52871
53115
|
let workspaceId;
|
|
52872
|
-
let
|
|
52873
|
-
|
|
52874
|
-
|
|
52875
|
-
|
|
52876
|
-
|
|
52877
|
-
|
|
52878
|
-
|
|
53116
|
+
let auto;
|
|
53117
|
+
let sawWorkspace = false;
|
|
53118
|
+
let sawAuto = false;
|
|
53119
|
+
for (let i = 0;i < 2; i++) {
|
|
53120
|
+
const last = tokens[tokens.length - 1];
|
|
53121
|
+
const secondLast = tokens[tokens.length - 2];
|
|
53122
|
+
if (!sawAuto && secondLast === "--auto" && last !== undefined && POSITIVE_INTEGER.test(last)) {
|
|
53123
|
+
auto = { rounds: Number(last) };
|
|
53124
|
+
sawAuto = true;
|
|
53125
|
+
tokens = tokens.slice(0, tokens.length - 2);
|
|
53126
|
+
continue;
|
|
53127
|
+
}
|
|
53128
|
+
if (!sawAuto && last === "--auto") {
|
|
53129
|
+
auto = {};
|
|
53130
|
+
sawAuto = true;
|
|
53131
|
+
tokens = tokens.slice(0, tokens.length - 1);
|
|
53132
|
+
continue;
|
|
53133
|
+
}
|
|
53134
|
+
if (!sawWorkspace && last === "--workspace") {
|
|
53135
|
+
return { error: "--workspace requires a value, e.g. /goal <text> --workspace <id>" };
|
|
53136
|
+
}
|
|
53137
|
+
if (!sawWorkspace && secondLast === "--workspace") {
|
|
53138
|
+
workspaceId = last;
|
|
53139
|
+
sawWorkspace = true;
|
|
53140
|
+
tokens = tokens.slice(0, tokens.length - 2);
|
|
53141
|
+
continue;
|
|
53142
|
+
}
|
|
53143
|
+
break;
|
|
52879
53144
|
}
|
|
52880
|
-
const text =
|
|
53145
|
+
const text = tokens.join(" ").trim();
|
|
52881
53146
|
if (text.length === 0) {
|
|
52882
|
-
return {
|
|
53147
|
+
return {
|
|
53148
|
+
error: "a goal <text> is required, e.g. /goal implement the login flow [--workspace <id>] [--auto [N]]"
|
|
53149
|
+
};
|
|
53150
|
+
}
|
|
53151
|
+
const parsed = { text };
|
|
53152
|
+
if (workspaceId !== undefined) {
|
|
53153
|
+
parsed.workspaceId = workspaceId;
|
|
52883
53154
|
}
|
|
52884
|
-
|
|
53155
|
+
if (auto !== undefined) {
|
|
53156
|
+
parsed.auto = auto;
|
|
53157
|
+
}
|
|
53158
|
+
return parsed;
|
|
52885
53159
|
}
|
|
52886
53160
|
function systemLine(io, text) {
|
|
52887
53161
|
if (io.onSystem !== undefined) {
|
|
@@ -52890,6 +53164,113 @@ function systemLine(io, text) {
|
|
|
52890
53164
|
io.write(text);
|
|
52891
53165
|
}
|
|
52892
53166
|
}
|
|
53167
|
+
var flowService;
|
|
53168
|
+
function getFlowService() {
|
|
53169
|
+
flowService ??= createFlowService({
|
|
53170
|
+
tracker: null,
|
|
53171
|
+
healthGate: async () => ({ status: "skipped", reasons: [] }),
|
|
53172
|
+
now: () => new Date
|
|
53173
|
+
});
|
|
53174
|
+
return flowService;
|
|
53175
|
+
}
|
|
53176
|
+
async function autoProvisionFlow(cwd, goalText) {
|
|
53177
|
+
const service5 = getFlowService();
|
|
53178
|
+
const result = await service5.init({ cwd, title: goalText });
|
|
53179
|
+
const acFile = path149.join(cwd, result.dir, "acceptance-criteria.md");
|
|
53180
|
+
await writeFileAtomic(acFile, [
|
|
53181
|
+
"# Acceptance Criteria",
|
|
53182
|
+
"",
|
|
53183
|
+
"Rules:",
|
|
53184
|
+
"",
|
|
53185
|
+
"- Criteria lines use the exact format `- ACn: <criterion>`.",
|
|
53186
|
+
"- After `flow freeze` this file is checksum-protected: any edit outside",
|
|
53187
|
+
" `keryx flow ac update` fails every gate and status transition.",
|
|
53188
|
+
"- Completion requires every ACn to be confirmed via",
|
|
53189
|
+
" `keryx flow ac confirm <id> <ACn>`.",
|
|
53190
|
+
"",
|
|
53191
|
+
"Source: auto-provisioned by `/goal --auto` (SLATE-27, flow 186) \u2014 the",
|
|
53192
|
+
"goal text itself is the spec; no separate description/plan pair exists.",
|
|
53193
|
+
"",
|
|
53194
|
+
"## Criteria",
|
|
53195
|
+
"",
|
|
53196
|
+
`- AC1: The stated goal \u2014 "${goalText}" \u2014 is achieved, judged by the`,
|
|
53197
|
+
" verifier subagent this session's continuation loop runs before",
|
|
53198
|
+
" stopping (flow 186 T10).",
|
|
53199
|
+
""
|
|
53200
|
+
].join(`
|
|
53201
|
+
`));
|
|
53202
|
+
await service5.freeze({ cwd, id: result.flow.id });
|
|
53203
|
+
await service5.start({ cwd, id: result.flow.id });
|
|
53204
|
+
return result.flow.id;
|
|
53205
|
+
}
|
|
53206
|
+
async function buildContinuationMessage(cwd, slateSession, round4, roundsCap) {
|
|
53207
|
+
const totalRounds = roundsCap + 1;
|
|
53208
|
+
const generic = `Continue working toward the stated goal (round ${round4} of ${totalRounds}).`;
|
|
53209
|
+
const slate = await readSlate(slateSession.dir).catch(() => {
|
|
53210
|
+
return;
|
|
53211
|
+
});
|
|
53212
|
+
const flowId = slate?.course.flowRef;
|
|
53213
|
+
if (flowId === undefined) {
|
|
53214
|
+
return generic;
|
|
53215
|
+
}
|
|
53216
|
+
try {
|
|
53217
|
+
const flow = await getFlowService().get({ cwd, id: flowId });
|
|
53218
|
+
const remaining = flow.tasks.filter((task) => task.status !== "done");
|
|
53219
|
+
const remainingList = remaining.length > 0 ? remaining.map((task) => `${task.id}: ${task.title}`).join("; ") : "(no open tasks recorded)";
|
|
53220
|
+
return `${generic} Flow ${flowId} tasks remaining: ${remainingList}.`;
|
|
53221
|
+
} catch {
|
|
53222
|
+
return generic;
|
|
53223
|
+
}
|
|
53224
|
+
}
|
|
53225
|
+
function parseVerifierVerdict(output2) {
|
|
53226
|
+
const match = output2.match(/\{[\s\S]*\}/);
|
|
53227
|
+
if (match === null) {
|
|
53228
|
+
return;
|
|
53229
|
+
}
|
|
53230
|
+
try {
|
|
53231
|
+
const parsed = JSON.parse(match[0]);
|
|
53232
|
+
if (typeof parsed !== "object" || parsed === null || !("achieved" in parsed)) {
|
|
53233
|
+
return;
|
|
53234
|
+
}
|
|
53235
|
+
const achieved = parsed.achieved;
|
|
53236
|
+
if (typeof achieved !== "boolean") {
|
|
53237
|
+
return;
|
|
53238
|
+
}
|
|
53239
|
+
const gapsRaw = parsed.gaps;
|
|
53240
|
+
const gaps = Array.isArray(gapsRaw) ? gapsRaw.filter((g) => typeof g === "string") : [];
|
|
53241
|
+
return { achieved, gaps };
|
|
53242
|
+
} catch {
|
|
53243
|
+
return;
|
|
53244
|
+
}
|
|
53245
|
+
}
|
|
53246
|
+
async function runGoalVerifier(deps, goalText) {
|
|
53247
|
+
const tool = deps.tools.find((candidate) => candidate.definition.name === "spawn_subagent");
|
|
53248
|
+
if (tool === undefined) {
|
|
53249
|
+
return;
|
|
53250
|
+
}
|
|
53251
|
+
const task = [
|
|
53252
|
+
"Independently verify whether the following goal has ACTUALLY been achieved, based on the",
|
|
53253
|
+
"current, real state of the repository (read the real files/tests \u2014 never trust a prior",
|
|
53254
|
+
"claim in conversation history without checking it yourself).",
|
|
53255
|
+
"",
|
|
53256
|
+
`Goal: "${goalText}"`,
|
|
53257
|
+
"",
|
|
53258
|
+
"Reply with EXACTLY one JSON object and nothing else, no prose before or after it:",
|
|
53259
|
+
'{"achieved": true or false, "gaps": ["specific reason it is not fully achieved", ...]}',
|
|
53260
|
+
'"gaps" must be empty when "achieved" is true.'
|
|
53261
|
+
].join(`
|
|
53262
|
+
`);
|
|
53263
|
+
let result;
|
|
53264
|
+
try {
|
|
53265
|
+
result = await tool.invoke({ task, mode: "read_only", label: "goal-verifier" });
|
|
53266
|
+
} catch {
|
|
53267
|
+
return;
|
|
53268
|
+
}
|
|
53269
|
+
if (result.isError) {
|
|
53270
|
+
return;
|
|
53271
|
+
}
|
|
53272
|
+
return parseVerifierVerdict(result.output);
|
|
53273
|
+
}
|
|
52893
53274
|
async function runGoalCommand(params) {
|
|
52894
53275
|
const { raw, cwd, io, deps, history, slateSession, mintAttemptId, resolveWorkspace } = params;
|
|
52895
53276
|
const parsed = parseGoalArgs(raw);
|
|
@@ -52898,6 +53279,8 @@ async function runGoalCommand(params) {
|
|
|
52898
53279
|
`);
|
|
52899
53280
|
return;
|
|
52900
53281
|
}
|
|
53282
|
+
let boundFlowRef;
|
|
53283
|
+
let boundWorkspaceId;
|
|
52901
53284
|
if (parsed.workspaceId !== undefined) {
|
|
52902
53285
|
const resolved2 = await resolveWorkspaceForActor(cwd, parsed.workspaceId);
|
|
52903
53286
|
if (!resolved2.ok) {
|
|
@@ -52937,12 +53320,84 @@ async function runGoalCommand(params) {
|
|
|
52937
53320
|
}
|
|
52938
53321
|
}
|
|
52939
53322
|
}
|
|
53323
|
+
if (parsed.auto !== undefined) {
|
|
53324
|
+
const forCourse = await readSlate(slateSession.dir);
|
|
53325
|
+
let flowRefForBinding = forCourse?.course.flowRef;
|
|
53326
|
+
if (forCourse !== undefined && forCourse.course.flowRef === undefined) {
|
|
53327
|
+
const flowId = await autoProvisionFlow(cwd, parsed.text);
|
|
53328
|
+
await writeSlate(slateSession.dir, (prev) => {
|
|
53329
|
+
if (!prev)
|
|
53330
|
+
throw new Error(`SLATE-27 bind: no open slate in ${slateSession.dir}`);
|
|
53331
|
+
return { ...prev, course: { ...prev.course, flowRef: flowId } };
|
|
53332
|
+
});
|
|
53333
|
+
flowRefForBinding = flowId;
|
|
53334
|
+
}
|
|
53335
|
+
slateSession.autoGoalRounds = parsed.auto.rounds ?? DEFAULT_AUTO_GOAL_ROUNDS;
|
|
53336
|
+
boundFlowRef = flowRefForBinding;
|
|
53337
|
+
boundWorkspaceId = forCourse?.workspaceId;
|
|
53338
|
+
}
|
|
52940
53339
|
} catch (err) {
|
|
52941
53340
|
systemLine(io, `/goal: slate bookkeeping failed (ignored): ${err instanceof Error ? err.message : String(err)}
|
|
52942
53341
|
`);
|
|
52943
53342
|
}
|
|
52944
53343
|
}
|
|
52945
|
-
|
|
53344
|
+
const turnOptions = slateSession !== undefined ? { slateSession, skipCloseTrigger: true } : {};
|
|
53345
|
+
await runAgentTurn(io, deps, history, parsed.text, turnOptions);
|
|
53346
|
+
if (slateSession !== undefined && slateSession.autoGoalRounds !== undefined) {
|
|
53347
|
+
const roundsCap = slateSession.autoGoalRounds;
|
|
53348
|
+
delete slateSession.autoGoalRounds;
|
|
53349
|
+
let roundsLeft = roundsCap;
|
|
53350
|
+
let round4 = 1;
|
|
53351
|
+
while (roundsLeft > 0 && slateSession.opened) {
|
|
53352
|
+
roundsLeft -= 1;
|
|
53353
|
+
round4 += 1;
|
|
53354
|
+
const continuationText = await buildContinuationMessage(cwd, slateSession, round4, roundsCap);
|
|
53355
|
+
systemLine(io, `/goal --auto: round ${round4}/${roundsCap + 1} \u2014 continuing toward the goal.
|
|
53356
|
+
`);
|
|
53357
|
+
await runAgentTurn(io, deps, history, continuationText, turnOptions);
|
|
53358
|
+
}
|
|
53359
|
+
const wasOpenBeforeVerifier = slateSession.opened;
|
|
53360
|
+
const verdict = await runGoalVerifier(deps, parsed.text);
|
|
53361
|
+
if (verdict !== undefined && !verdict.achieved) {
|
|
53362
|
+
systemLine(io, `/goal --auto: verifier found the goal not fully achieved${verdict.gaps.length > 0 ? ` \u2014 ${verdict.gaps.join("; ")}` : " (no specific gaps reported)"}
|
|
53363
|
+
`);
|
|
53364
|
+
if (roundsLeft > 0) {
|
|
53365
|
+
let reopenOk = true;
|
|
53366
|
+
if (!wasOpenBeforeVerifier) {
|
|
53367
|
+
try {
|
|
53368
|
+
await ensureSlateOpened(slateSession, mintAttemptId, { provider: deps.providerId, model: deps.modelId });
|
|
53369
|
+
const reopened = await readSlate(slateSession.dir);
|
|
53370
|
+
if (reopened !== undefined) {
|
|
53371
|
+
history.push({ role: "user", content: renderAnchorsBlock(reopened.anchors), provenance: "project" });
|
|
53372
|
+
io.onHistoryChange?.("tool");
|
|
53373
|
+
}
|
|
53374
|
+
await writeSlate(slateSession.dir, (prev) => {
|
|
53375
|
+
if (!prev)
|
|
53376
|
+
throw new Error(`SLATE-27 verifier-reopen: no open slate in ${slateSession.dir}`);
|
|
53377
|
+
return {
|
|
53378
|
+
...prev,
|
|
53379
|
+
course: { ...prev.course, ...boundFlowRef !== undefined ? { flowRef: boundFlowRef } : {} },
|
|
53380
|
+
...boundWorkspaceId !== undefined ? { workspaceId: boundWorkspaceId } : {}
|
|
53381
|
+
};
|
|
53382
|
+
});
|
|
53383
|
+
} catch (err) {
|
|
53384
|
+
reopenOk = false;
|
|
53385
|
+
systemLine(io, `/goal --auto: could not reopen the slate for one more round (ignored): ${err instanceof Error ? err.message : String(err)}
|
|
53386
|
+
`);
|
|
53387
|
+
}
|
|
53388
|
+
}
|
|
53389
|
+
if (!reopenOk) {
|
|
53390
|
+
return;
|
|
53391
|
+
}
|
|
53392
|
+
roundsLeft -= 1;
|
|
53393
|
+
round4 += 1;
|
|
53394
|
+
const continuationText = await buildContinuationMessage(cwd, slateSession, round4, roundsCap);
|
|
53395
|
+
systemLine(io, `/goal --auto: round ${round4}/${roundsCap + 1} \u2014 one more round after the verifier found gaps.
|
|
53396
|
+
`);
|
|
53397
|
+
await runAgentTurn(io, deps, history, continuationText, turnOptions);
|
|
53398
|
+
}
|
|
53399
|
+
}
|
|
53400
|
+
}
|
|
52946
53401
|
}
|
|
52947
53402
|
|
|
52948
53403
|
// src/tui/tui-shell.ts
|
|
@@ -52951,7 +53406,7 @@ import { spawnSync as spawnSync2 } from "child_process";
|
|
|
52951
53406
|
// package.json
|
|
52952
53407
|
var package_default = {
|
|
52953
53408
|
name: "@mrciphersmith/keryx",
|
|
52954
|
-
version: "0.2.
|
|
53409
|
+
version: "0.2.54",
|
|
52955
53410
|
description: "Version-controlled project context for AI coding agents: code graph, architecture wiki, project memory, relevant tests, quality signals, and task flows.",
|
|
52956
53411
|
private: false,
|
|
52957
53412
|
publishConfig: {
|
|
@@ -54211,8 +54666,8 @@ init_store3();
|
|
|
54211
54666
|
init_proposal_lifecycle();
|
|
54212
54667
|
init_workspace_service();
|
|
54213
54668
|
import { randomUUID as randomUUID24 } from "crypto";
|
|
54214
|
-
import { readdir as
|
|
54215
|
-
import
|
|
54669
|
+
import { readdir as readdir26 } from "fs/promises";
|
|
54670
|
+
import path150 from "path";
|
|
54216
54671
|
|
|
54217
54672
|
// src/sac/lifecycle-flag.ts
|
|
54218
54673
|
init_store();
|
|
@@ -54350,12 +54805,12 @@ async function collectSessionCategories(cwd) {
|
|
|
54350
54805
|
return { blocked: blocked2, unboundCandidates, unknown };
|
|
54351
54806
|
}
|
|
54352
54807
|
async function isSlateEngaged(dir) {
|
|
54353
|
-
if (await pathExists(
|
|
54808
|
+
if (await pathExists(path150.join(dir, "slate.json")))
|
|
54354
54809
|
return true;
|
|
54355
|
-
if (await pathExists(
|
|
54810
|
+
if (await pathExists(path150.join(dir, "terminal-state.json")))
|
|
54356
54811
|
return true;
|
|
54357
54812
|
try {
|
|
54358
|
-
const entries = await
|
|
54813
|
+
const entries = await readdir26(path150.join(dir, "slate-archive"));
|
|
54359
54814
|
return entries.length > 0;
|
|
54360
54815
|
} catch {
|
|
54361
54816
|
return false;
|
|
@@ -54369,7 +54824,7 @@ async function safeReadSlate(dir) {
|
|
|
54369
54824
|
}
|
|
54370
54825
|
}
|
|
54371
54826
|
async function readTerminalState(dir) {
|
|
54372
|
-
const result = readConfigFile(
|
|
54827
|
+
const result = readConfigFile(path150.join(dir, "terminal-state.json"));
|
|
54373
54828
|
if (!result.ok) {
|
|
54374
54829
|
return;
|
|
54375
54830
|
}
|
|
@@ -54380,16 +54835,16 @@ async function readTerminalState(dir) {
|
|
|
54380
54835
|
}
|
|
54381
54836
|
}
|
|
54382
54837
|
async function readNewestUnboundCandidate(dir) {
|
|
54383
|
-
const archiveDir =
|
|
54838
|
+
const archiveDir = path150.join(dir, "slate-archive");
|
|
54384
54839
|
let entries;
|
|
54385
54840
|
try {
|
|
54386
|
-
entries = (await
|
|
54841
|
+
entries = (await readdir26(archiveDir)).filter((name) => name.endsWith("-unbound-candidate.json"));
|
|
54387
54842
|
} catch {
|
|
54388
54843
|
return;
|
|
54389
54844
|
}
|
|
54390
54845
|
entries.sort();
|
|
54391
54846
|
for (let i = entries.length - 1;i >= 0; i--) {
|
|
54392
|
-
const evidencePath =
|
|
54847
|
+
const evidencePath = path150.join(archiveDir, entries[i]);
|
|
54393
54848
|
const result = readConfigFile(evidencePath);
|
|
54394
54849
|
if (!result.ok) {
|
|
54395
54850
|
continue;
|
|
@@ -54417,16 +54872,16 @@ function isFailureOutcome(g) {
|
|
|
54417
54872
|
return g.outcome === "error" || g.outcome === "no_credential" || g.outcome === "conflict";
|
|
54418
54873
|
}
|
|
54419
54874
|
async function readNewestWrapUpOutcome(dir) {
|
|
54420
|
-
const archiveDir =
|
|
54875
|
+
const archiveDir = path150.join(dir, "slate-archive");
|
|
54421
54876
|
let entries;
|
|
54422
54877
|
try {
|
|
54423
|
-
entries = (await
|
|
54878
|
+
entries = (await readdir26(archiveDir)).filter((name) => name.endsWith("-wrap-up-outcome.json"));
|
|
54424
54879
|
} catch {
|
|
54425
54880
|
return;
|
|
54426
54881
|
}
|
|
54427
54882
|
entries.sort();
|
|
54428
54883
|
for (let i = entries.length - 1;i >= 0; i--) {
|
|
54429
|
-
const evidencePath =
|
|
54884
|
+
const evidencePath = path150.join(archiveDir, entries[i]);
|
|
54430
54885
|
const result = readConfigFile(evidencePath);
|
|
54431
54886
|
if (!result.ok) {
|
|
54432
54887
|
continue;
|
|
@@ -55542,6 +55997,9 @@ function isMcpToolsCommand(line) {
|
|
|
55542
55997
|
const token = line.trim().split(/\s+/)[0] ?? "";
|
|
55543
55998
|
return token === MCP_TOOLS_COMMAND;
|
|
55544
55999
|
}
|
|
56000
|
+
var TOOLS_TAB_HEADER = "Built into keryx \u2014 not from an external MCP server (keryx doesn't consume MCP servers as a client yet).";
|
|
56001
|
+
var MCP_TAB_HEADER_1 = "Connects/disconnects ONLY keryx's own MCP server, one editor config at a time.";
|
|
56002
|
+
var MCP_TAB_HEADER_2 = "Other MCP servers already configured there (context7, playwright, \u2026) show per row, read-only.";
|
|
55545
56003
|
var RUNTIME_LABELS = {
|
|
55546
56004
|
cursor: "Cursor",
|
|
55547
56005
|
claude: "Claude Code",
|
|
@@ -55560,10 +56018,20 @@ function formatToolRowLine(tool) {
|
|
|
55560
56018
|
function isActionable(id) {
|
|
55561
56019
|
return id !== "generic";
|
|
55562
56020
|
}
|
|
56021
|
+
var MAX_OTHER_SERVERS_SHOWN = 4;
|
|
56022
|
+
function formatOtherServers(otherServers) {
|
|
56023
|
+
if (otherServers.length === 0) {
|
|
56024
|
+
return "";
|
|
56025
|
+
}
|
|
56026
|
+
const shown = otherServers.slice(0, MAX_OTHER_SERVERS_SHOWN);
|
|
56027
|
+
const rest = otherServers.length - shown.length;
|
|
56028
|
+
const list2 = rest > 0 ? `${shown.join(", ")}, +${rest} more` : shown.join(", ");
|
|
56029
|
+
return ` \xB7 also has: ${list2}`;
|
|
56030
|
+
}
|
|
55563
56031
|
function formatMcpRowLine(runtime, isSelected, status) {
|
|
55564
56032
|
const mark = isSelected ? ">" : " ";
|
|
55565
56033
|
const label = runtimeLabel(runtime.id).padEnd(20);
|
|
55566
|
-
const statusText = runtime.connected ? "\u25CF connected" : "\u25CB not connected";
|
|
56034
|
+
const statusText = runtime.connected ? "\u25CF keryx connected" : "\u25CB keryx not connected";
|
|
55567
56035
|
let action = "";
|
|
55568
56036
|
if (!isActionable(runtime.id)) {
|
|
55569
56037
|
action = " (copy snippet manually)";
|
|
@@ -55576,7 +56044,7 @@ function formatMcpRowLine(runtime, isSelected, status) {
|
|
|
55576
56044
|
} else {
|
|
55577
56045
|
action = runtime.connected ? " [d] disconnect" : " [c] connect";
|
|
55578
56046
|
}
|
|
55579
|
-
return `${mark} ${label} ${statusText}${action}`;
|
|
56047
|
+
return `${mark} ${label} ${statusText}${action}${formatOtherServers(runtime.otherServers)}`;
|
|
55580
56048
|
}
|
|
55581
56049
|
function asRowTarget(body) {
|
|
55582
56050
|
const parent = body;
|
|
@@ -55607,6 +56075,7 @@ function presentMcpTools(openModal2, otui, chrome, options) {
|
|
|
55607
56075
|
return;
|
|
55608
56076
|
}
|
|
55609
56077
|
clearTranscriptChildren(toolsBody);
|
|
56078
|
+
toolsBody.add(new rowCtor(activeRenderer, { id: "mcp-tools-header", content: TOOLS_TAB_HEADER }));
|
|
55610
56079
|
if (options.tools.length === 0) {
|
|
55611
56080
|
toolsBody.add(new rowCtor(activeRenderer, { id: "mcp-tools-empty", content: "No tools available." }));
|
|
55612
56081
|
return;
|
|
@@ -55621,6 +56090,8 @@ function presentMcpTools(openModal2, otui, chrome, options) {
|
|
|
55621
56090
|
return;
|
|
55622
56091
|
}
|
|
55623
56092
|
clearTranscriptChildren(mcpBody);
|
|
56093
|
+
mcpBody.add(new rowCtor(activeRenderer, { id: "mcp-mcp-header-1", content: MCP_TAB_HEADER_1 }));
|
|
56094
|
+
mcpBody.add(new rowCtor(activeRenderer, { id: "mcp-mcp-header-2", content: MCP_TAB_HEADER_2 }));
|
|
55624
56095
|
if (runtimes.length === 0) {
|
|
55625
56096
|
mcpBody.add(new rowCtor(activeRenderer, { id: "mcp-mcp-empty", content: "No MCP client runtimes registered." }));
|
|
55626
56097
|
return;
|
|
@@ -55706,7 +56177,7 @@ function presentMcpTools(openModal2, otui, chrome, options) {
|
|
|
55706
56177
|
title: "Tools & MCP",
|
|
55707
56178
|
tabs: [
|
|
55708
56179
|
{ id: "tools", label: "Tools" },
|
|
55709
|
-
{ id: "mcp", label: "MCP" }
|
|
56180
|
+
{ id: "mcp", label: "MCP Clients" }
|
|
55710
56181
|
],
|
|
55711
56182
|
initialTab: "tools",
|
|
55712
56183
|
footer: MCP_INSPECTOR_FOOTER,
|
|
@@ -56148,7 +56619,7 @@ var AGENT_SLASH_COMMANDS = [
|
|
|
56148
56619
|
{ name: "/new", description: "Start a new session (old kept on disk)", modes: BOTH },
|
|
56149
56620
|
{
|
|
56150
56621
|
name: "/goal",
|
|
56151
|
-
description: "Deterministically start a goal \u2014 /goal <text> [--workspace <id>]",
|
|
56622
|
+
description: "Deterministically start a goal \u2014 /goal <text> [--workspace <id>] [--auto [N]]",
|
|
56152
56623
|
modes: AGENT_ONLY
|
|
56153
56624
|
},
|
|
56154
56625
|
{ name: "/resume", description: "Resume a prior session in this project", modes: AGENT_ONLY },
|
|
@@ -56240,7 +56711,7 @@ function commandsForMode(mode) {
|
|
|
56240
56711
|
}));
|
|
56241
56712
|
}
|
|
56242
56713
|
function filterCommands(query, mode) {
|
|
56243
|
-
const q = query.
|
|
56714
|
+
const q = query.toLowerCase();
|
|
56244
56715
|
if (!q.startsWith("/")) {
|
|
56245
56716
|
return [];
|
|
56246
56717
|
}
|
|
@@ -56598,10 +57069,10 @@ function describeElicitationPrompt(tool, inputJson) {
|
|
|
56598
57069
|
// src/lib/permission-mode-config.ts
|
|
56599
57070
|
init_permission_mode();
|
|
56600
57071
|
init_config_dir();
|
|
56601
|
-
import
|
|
57072
|
+
import path151 from "path";
|
|
56602
57073
|
var EMPTY3 = { schemaVersion: 1, projects: {} };
|
|
56603
57074
|
function permissionModeConfigPath(dir) {
|
|
56604
|
-
return
|
|
57075
|
+
return path151.join(keryxConfigDir(dir), "permission-mode.json");
|
|
56605
57076
|
}
|
|
56606
57077
|
function withRegistryLock2(dir, fn) {
|
|
56607
57078
|
return withFileLock(`${permissionModeConfigPath(dir)}.lock`, fn, {
|
|
@@ -56950,7 +57421,7 @@ function showComposerChoice(otui, r, dock, request) {
|
|
|
56950
57421
|
// src/lib/version-check.ts
|
|
56951
57422
|
init_config_dir();
|
|
56952
57423
|
init_fs();
|
|
56953
|
-
import
|
|
57424
|
+
import path152 from "path";
|
|
56954
57425
|
var REGISTRY_URL = "https://registry.npmjs.org/@mrciphersmith%2Fkeryx/latest";
|
|
56955
57426
|
var FIXED_INSTALL_COMMAND = "npm install -g @mrciphersmith/keryx@latest";
|
|
56956
57427
|
var RESPONSE_BODY_LIMIT_BYTES = 64 * 1024;
|
|
@@ -57152,7 +57623,7 @@ async function checkVersion(options) {
|
|
|
57152
57623
|
const now = options.now ?? Date.now;
|
|
57153
57624
|
const timestamp = now();
|
|
57154
57625
|
const configDir = ensureKeryxConfigDir(options.cacheDir);
|
|
57155
|
-
const cacheFile =
|
|
57626
|
+
const cacheFile = path152.join(configDir, "version-check.json");
|
|
57156
57627
|
const cache = parseCache(cacheFile);
|
|
57157
57628
|
if (cache?.latestVersion !== undefined && cache.successAt !== undefined && timestamp - cache.successAt >= 0 && timestamp - cache.successAt < SUCCESS_CACHE_TTL_MS) {
|
|
57158
57629
|
return resultFor(options.currentVersion, current, cache.latestVersion, "cache");
|
|
@@ -57270,7 +57741,7 @@ function wrappedLineCount(text, width) {
|
|
|
57270
57741
|
return total;
|
|
57271
57742
|
}
|
|
57272
57743
|
function prefixFilter(commands, query) {
|
|
57273
|
-
const q = query.
|
|
57744
|
+
const q = query.toLowerCase();
|
|
57274
57745
|
if (!q.startsWith("/")) {
|
|
57275
57746
|
return [];
|
|
57276
57747
|
}
|
|
@@ -57688,6 +58159,17 @@ async function createShellChrome(otui, renderer, opts) {
|
|
|
57688
58159
|
key.stopPropagation();
|
|
57689
58160
|
return;
|
|
57690
58161
|
}
|
|
58162
|
+
if (key.name === "tab") {
|
|
58163
|
+
const opt = menu.getSelectedOption();
|
|
58164
|
+
if (opt !== null) {
|
|
58165
|
+
input2.value = `${opt.name} `;
|
|
58166
|
+
}
|
|
58167
|
+
hideMenu();
|
|
58168
|
+
input2.focus();
|
|
58169
|
+
key.preventDefault();
|
|
58170
|
+
key.stopPropagation();
|
|
58171
|
+
return;
|
|
58172
|
+
}
|
|
57691
58173
|
if (key.name === "backspace") {
|
|
57692
58174
|
input2.value = input2.value.slice(0, -1);
|
|
57693
58175
|
refilter();
|
|
@@ -65193,9 +65675,9 @@ Shell:
|
|
|
65193
65675
|
|
|
65194
65676
|
// src/commands/modules.ts
|
|
65195
65677
|
init_fs();
|
|
65196
|
-
import { readFile as
|
|
65678
|
+
import { readFile as readFile79 } from "fs/promises";
|
|
65197
65679
|
import { stdin } from "process";
|
|
65198
|
-
import
|
|
65680
|
+
import path153 from "path";
|
|
65199
65681
|
var MODULES = [
|
|
65200
65682
|
{ name: "gdgraph", flag: "--no-gdgraph", desc: "code graph, symbols, affected context", defaultEnabled: true },
|
|
65201
65683
|
{ name: "gdctx", flag: "--no-gdctx", desc: "token-aware command/read output", defaultEnabled: true },
|
|
@@ -65241,8 +65723,8 @@ async function modulesCommand(args2 = []) {
|
|
|
65241
65723
|
return;
|
|
65242
65724
|
}
|
|
65243
65725
|
const wantsJson = args2.includes("--json") && (sub === undefined || sub === "status" || sub === "list" || sub === "--json");
|
|
65244
|
-
const metaprojectRoot =
|
|
65245
|
-
const manifestPath =
|
|
65726
|
+
const metaprojectRoot = path153.join(process.cwd(), ".metaproject");
|
|
65727
|
+
const manifestPath = path153.join(metaprojectRoot, "metaproject.json");
|
|
65246
65728
|
if (!await pathExists(manifestPath)) {
|
|
65247
65729
|
if (wantsJson) {
|
|
65248
65730
|
console.log(JSON.stringify({ schemaVersion: 1, error: "not-initialized", modules: [] }, null, 2));
|
|
@@ -65255,7 +65737,7 @@ async function modulesCommand(args2 = []) {
|
|
|
65255
65737
|
}
|
|
65256
65738
|
let manifest = {};
|
|
65257
65739
|
try {
|
|
65258
|
-
manifest = JSON.parse(await
|
|
65740
|
+
manifest = JSON.parse(await readFile79(manifestPath, "utf8"));
|
|
65259
65741
|
} catch {}
|
|
65260
65742
|
const enabled = new Set(MODULES.filter((module) => manifest.modules?.[module.name]?.enabled === true).map((module) => module.name));
|
|
65261
65743
|
if (wantsJson) {
|
|
@@ -65361,13 +65843,13 @@ import { randomUUID as randomUUID29 } from "crypto";
|
|
|
65361
65843
|
// src/lib/serve-config.ts
|
|
65362
65844
|
init_config_dir();
|
|
65363
65845
|
import { existsSync as existsSync27 } from "fs";
|
|
65364
|
-
import
|
|
65846
|
+
import path154 from "path";
|
|
65365
65847
|
var SERVE_CONFIG_SCHEMA_VERSION = "1.0.0";
|
|
65366
65848
|
var DEFAULT_SERVE_BIND_ADDRESS = "127.0.0.1";
|
|
65367
65849
|
var DEFAULT_SERVE_PORT = 7377;
|
|
65368
65850
|
var DEFAULT_SERVE_PROFILE = "remote-restricted";
|
|
65369
65851
|
function serveConfigPath(dir) {
|
|
65370
|
-
return
|
|
65852
|
+
return path154.join(keryxConfigDir(dir), "serve.json");
|
|
65371
65853
|
}
|
|
65372
65854
|
function parseIpv4(value) {
|
|
65373
65855
|
const parts = value.split(".");
|
|
@@ -65695,9 +66177,9 @@ import {
|
|
|
65695
66177
|
unlinkSync as unlinkSync3,
|
|
65696
66178
|
writeFileSync as writeFileSync8
|
|
65697
66179
|
} from "fs";
|
|
65698
|
-
import
|
|
66180
|
+
import path155 from "path";
|
|
65699
66181
|
function serveCredentialPath(dir) {
|
|
65700
|
-
return
|
|
66182
|
+
return path155.join(keryxConfigDir(dir), "serve-credentials.json");
|
|
65701
66183
|
}
|
|
65702
66184
|
function constantTimeEqual(a, b) {
|
|
65703
66185
|
const width = Math.max(a.length, b.length);
|
|
@@ -65931,22 +66413,22 @@ class AuthFailureThrottle {
|
|
|
65931
66413
|
init_config_dir();
|
|
65932
66414
|
import { createHash as createHash34 } from "crypto";
|
|
65933
66415
|
import { existsSync as existsSync29, readdirSync as readdirSync2, rmSync as rmSync2 } from "fs";
|
|
65934
|
-
import
|
|
66416
|
+
import path156 from "path";
|
|
65935
66417
|
var MAX_TURN_EVENTS = 1e4;
|
|
65936
66418
|
function turnsRoot(dir) {
|
|
65937
|
-
return
|
|
66419
|
+
return path156.join(keryxConfigDir(dir), "turns");
|
|
65938
66420
|
}
|
|
65939
66421
|
function turnDir(turnId, dir) {
|
|
65940
|
-
return
|
|
66422
|
+
return path156.join(turnsRoot(dir), turnId);
|
|
65941
66423
|
}
|
|
65942
66424
|
function keyPath(project, idempotencyKey, dir) {
|
|
65943
66425
|
const projectBytes = Buffer.byteLength(project, "utf8");
|
|
65944
66426
|
const digest2 = createHash34("sha256").update(`${projectBytes}:${project}\x00${idempotencyKey}`, "utf8").digest("hex");
|
|
65945
|
-
return
|
|
66427
|
+
return path156.join(turnsRoot(dir), "keys", `${digest2}.json`);
|
|
65946
66428
|
}
|
|
65947
66429
|
function legacyKeyPath(idempotencyKey, dir) {
|
|
65948
66430
|
const digest2 = createHash34("sha256").update(idempotencyKey, "utf8").digest("hex");
|
|
65949
|
-
return
|
|
66431
|
+
return path156.join(turnsRoot(dir), "keys", `${digest2}.json`);
|
|
65950
66432
|
}
|
|
65951
66433
|
function adoptLegacyClaim(project, idempotencyKey, dir) {
|
|
65952
66434
|
const legacy = legacyKeyPath(idempotencyKey, dir);
|
|
@@ -66010,7 +66492,7 @@ function ensureTurnDir(turnId, dir) {
|
|
|
66010
66492
|
}
|
|
66011
66493
|
function createTurnRecord(record, dir) {
|
|
66012
66494
|
ensureTurnDir(record.turnId, dir);
|
|
66013
|
-
writeOwnerOnlyFile(
|
|
66495
|
+
writeOwnerOnlyFile(path156.join(turnDir(record.turnId, dir), "turn.json"), `${JSON.stringify(record, null, 2)}
|
|
66014
66496
|
`);
|
|
66015
66497
|
}
|
|
66016
66498
|
function appendTurnEvent(event, dir, opts) {
|
|
@@ -66019,12 +66501,12 @@ function appendTurnEvent(event, dir, opts) {
|
|
|
66019
66501
|
}
|
|
66020
66502
|
const line = JSON.stringify(event);
|
|
66021
66503
|
try {
|
|
66022
|
-
appendOwnerOnlyLine(
|
|
66504
|
+
appendOwnerOnlyLine(path156.join(turnDir(event.turnId, dir), "events.jsonl"), line);
|
|
66023
66505
|
} catch (error2) {
|
|
66024
66506
|
if (error2?.code !== "ENOENT") {
|
|
66025
66507
|
throw error2;
|
|
66026
66508
|
}
|
|
66027
|
-
appendOwnerOnlyLine(
|
|
66509
|
+
appendOwnerOnlyLine(path156.join(ensureTurnDir(event.turnId, dir), "events.jsonl"), line);
|
|
66028
66510
|
}
|
|
66029
66511
|
return true;
|
|
66030
66512
|
}
|
|
@@ -66032,7 +66514,7 @@ function readTurnEvents(turnId, after = -1, dir) {
|
|
|
66032
66514
|
if (!isTurnId(turnId)) {
|
|
66033
66515
|
return { ok: false, reason: "not-a-turn-id" };
|
|
66034
66516
|
}
|
|
66035
|
-
const read = readTurnFile(
|
|
66517
|
+
const read = readTurnFile(path156.join(turnDir(turnId, dir), "events.jsonl"));
|
|
66036
66518
|
if (!read.ok) {
|
|
66037
66519
|
if (isDefiniteAbsence2(read.reason)) {
|
|
66038
66520
|
return { ok: true, value: [] };
|
|
@@ -66060,7 +66542,7 @@ function readTurnRecord(turnId, dir) {
|
|
|
66060
66542
|
if (!isTurnId(turnId)) {
|
|
66061
66543
|
return { ok: false, reason: "not-a-turn-id" };
|
|
66062
66544
|
}
|
|
66063
|
-
const read = readTurnFile(
|
|
66545
|
+
const read = readTurnFile(path156.join(turnDir(turnId, dir), "turn.json"));
|
|
66064
66546
|
if (!read.ok) {
|
|
66065
66547
|
return { ok: false, reason: read.reason };
|
|
66066
66548
|
}
|
|
@@ -66079,7 +66561,7 @@ function finishTurn(turnId, result, dir) {
|
|
|
66079
66561
|
if (!record.ok) {
|
|
66080
66562
|
return false;
|
|
66081
66563
|
}
|
|
66082
|
-
writeOwnerOnlyFile(
|
|
66564
|
+
writeOwnerOnlyFile(path156.join(turnDir(turnId, dir), "turn.json"), `${JSON.stringify({ ...record.value, result }, null, 2)}
|
|
66083
66565
|
`);
|
|
66084
66566
|
return true;
|
|
66085
66567
|
}
|
|
@@ -66125,7 +66607,7 @@ function releaseIdempotencyKey(project, idempotencyKey, turnId, dir) {
|
|
|
66125
66607
|
|
|
66126
66608
|
// src/lib/serve-turn.ts
|
|
66127
66609
|
import { randomUUID as randomUUID28 } from "crypto";
|
|
66128
|
-
import
|
|
66610
|
+
import path157 from "path";
|
|
66129
66611
|
init_service();
|
|
66130
66612
|
var REMOTE_ORIGIN = "remote:http";
|
|
66131
66613
|
var MAX_PROMPT_CHARS = 32000;
|
|
@@ -66194,9 +66676,9 @@ function isUuid(value) {
|
|
|
66194
66676
|
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);
|
|
66195
66677
|
}
|
|
66196
66678
|
function resolveProject(declared, dir) {
|
|
66197
|
-
const wanted =
|
|
66679
|
+
const wanted = path157.resolve(declared);
|
|
66198
66680
|
for (const entry of listProjects(dir, () => {})) {
|
|
66199
|
-
if (
|
|
66681
|
+
if (path157.resolve(entry.path) === wanted) {
|
|
66200
66682
|
return { ok: true, project: entry.path };
|
|
66201
66683
|
}
|
|
66202
66684
|
}
|
|
@@ -67229,9 +67711,9 @@ function printHelp17() {
|
|
|
67229
67711
|
|
|
67230
67712
|
// src/commands/update.ts
|
|
67231
67713
|
import { spawn as spawn5 } from "child_process";
|
|
67232
|
-
import { chmod as chmod4, mkdir as
|
|
67714
|
+
import { chmod as chmod4, mkdir as mkdir56, readFile as readFile80, readdir as readdir27, writeFile as writeFile49 } from "fs/promises";
|
|
67233
67715
|
import { access as access4, constants as constants2, existsSync as existsSync30 } from "fs";
|
|
67234
|
-
import
|
|
67716
|
+
import path158 from "path";
|
|
67235
67717
|
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
67236
67718
|
init_config();
|
|
67237
67719
|
init_config2();
|
|
@@ -67247,8 +67729,8 @@ async function updateCommand(args2 = []) {
|
|
|
67247
67729
|
return;
|
|
67248
67730
|
}
|
|
67249
67731
|
const projectRoot = process.cwd();
|
|
67250
|
-
const metaprojectRoot =
|
|
67251
|
-
banner("keryx update", `Refreshing the .metaproject workspace in ${
|
|
67732
|
+
const metaprojectRoot = path158.join(projectRoot, ".metaproject");
|
|
67733
|
+
banner("keryx update", `Refreshing the .metaproject workspace in ${path158.basename(projectRoot)}/`);
|
|
67252
67734
|
if (!await pathExists(metaprojectRoot)) {
|
|
67253
67735
|
console.log(` ${style.red(symbols.cross)} Metaproject is not initialized.`);
|
|
67254
67736
|
console.log(` ${style.cyan(symbols.arrow)} Run ${style.cyan("keryx init")} first.`);
|
|
@@ -67294,12 +67776,12 @@ async function updateCommand(args2 = []) {
|
|
|
67294
67776
|
nextSteps(steps);
|
|
67295
67777
|
}
|
|
67296
67778
|
async function refreshServiceFiles(projectRoot, options) {
|
|
67297
|
-
const metaprojectRoot =
|
|
67779
|
+
const metaprojectRoot = path158.join(projectRoot, ".metaproject");
|
|
67298
67780
|
const manifestState = await readManifest5(metaprojectRoot);
|
|
67299
67781
|
const manifest = manifestState.manifest;
|
|
67300
67782
|
const recoveredManifest = !manifestState.exists || !manifestState.valid;
|
|
67301
67783
|
if (manifestState.migrated) {
|
|
67302
|
-
await writeFile49(
|
|
67784
|
+
await writeFile49(path158.join(metaprojectRoot, "metaproject.json"), `${JSON.stringify(manifest, null, 2)}
|
|
67303
67785
|
`, "utf8");
|
|
67304
67786
|
}
|
|
67305
67787
|
const enableGdgraph = moduleEnabled2(manifest, "gdgraph");
|
|
@@ -67336,11 +67818,11 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
67336
67818
|
enableSecurity,
|
|
67337
67819
|
enableSac
|
|
67338
67820
|
});
|
|
67339
|
-
await writeTextIfChanged4(
|
|
67340
|
-
await writeTextIfChanged4(
|
|
67341
|
-
await writeTextIfChanged4(
|
|
67342
|
-
await writeTextIfChanged4(
|
|
67343
|
-
await writeTextIfChanged4(
|
|
67821
|
+
await writeTextIfChanged4(path158.join(metaprojectRoot, "core", "README.md"), renderMetaprojectCoreReadme());
|
|
67822
|
+
await writeTextIfChanged4(path158.join(metaprojectRoot, "hooks", "README.md"), renderHooksReadme());
|
|
67823
|
+
await writeTextIfChanged4(path158.join(metaprojectRoot, "rules", "README.md"), renderProjectRulesReadme());
|
|
67824
|
+
await writeTextIfChanged4(path158.join(metaprojectRoot, "skills", "project-rules", "README.md"), renderProjectRulesSkillReadme({ sources: ruleSources }));
|
|
67825
|
+
await writeTextIfChanged4(path158.join(metaprojectRoot, "index.md"), renderIndexMarkdown({
|
|
67344
67826
|
enableGdgraph,
|
|
67345
67827
|
enableGdctx,
|
|
67346
67828
|
enableGdwiki,
|
|
@@ -67353,7 +67835,7 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
67353
67835
|
ruleSources,
|
|
67354
67836
|
hasDistilledEntrypoints: await hasDistilledEntrypoints(metaprojectRoot)
|
|
67355
67837
|
}));
|
|
67356
|
-
await writeTextIfChanged4(
|
|
67838
|
+
await writeTextIfChanged4(path158.join(metaprojectRoot, "keryx-dashboard.html"), renderMetaprojectDashboardHtml({
|
|
67357
67839
|
enableGdgraph,
|
|
67358
67840
|
enableGdctx,
|
|
67359
67841
|
enableGdwiki,
|
|
@@ -67365,7 +67847,7 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
67365
67847
|
enableSecurity,
|
|
67366
67848
|
data: dashboardData
|
|
67367
67849
|
}));
|
|
67368
|
-
await writeTextIfMissing4(
|
|
67850
|
+
await writeTextIfMissing4(path158.join(metaprojectRoot, "README.md"), renderMetaprojectReadme({
|
|
67369
67851
|
enableGdgraph,
|
|
67370
67852
|
enableGdctx,
|
|
67371
67853
|
enableGdwiki,
|
|
@@ -67378,31 +67860,31 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
67378
67860
|
}));
|
|
67379
67861
|
if (enableGdgraph) {
|
|
67380
67862
|
await installGdgraphCoreScripts2(metaprojectRoot);
|
|
67381
|
-
await writeTextIfChanged4(
|
|
67382
|
-
await writeTextIfChanged4(
|
|
67383
|
-
await writeTextIfChanged4(
|
|
67863
|
+
await writeTextIfChanged4(path158.join(metaprojectRoot, "modules", "gdgraph.md"), renderGdgraphManifest());
|
|
67864
|
+
await writeTextIfChanged4(path158.join(metaprojectRoot, "core", "gdgraph", "README.md"), renderGdgraphCoreReadme());
|
|
67865
|
+
await writeTextIfChanged4(path158.join(metaprojectRoot, "skills", "gdgraph", "SKILL.md"), renderGdgraphSkillReadme());
|
|
67384
67866
|
await seedAssetsLock(metaprojectRoot);
|
|
67385
67867
|
if (manifest.modules?.gdgraph?.hooks?.gitPostCommit) {
|
|
67386
67868
|
await installManagedHook2(projectRoot, "post-commit", "gdgraph-post-commit", renderGdgraphPostCommitHook());
|
|
67387
67869
|
}
|
|
67388
67870
|
}
|
|
67389
67871
|
if (enableGdctx) {
|
|
67390
|
-
await writeTextIfMissing4(
|
|
67391
|
-
await writeTextIfChanged4(
|
|
67392
|
-
await writeTextIfChanged4(
|
|
67393
|
-
await writeTextIfChanged4(
|
|
67872
|
+
await writeTextIfMissing4(path158.join(metaprojectRoot, "gdctx.config.json"), renderGdctxConfig());
|
|
67873
|
+
await writeTextIfChanged4(path158.join(metaprojectRoot, "modules", "gdctx.md"), renderGdctxManifest());
|
|
67874
|
+
await writeTextIfChanged4(path158.join(metaprojectRoot, "core", "gdctx", "README.md"), renderGdctxCoreReadme());
|
|
67875
|
+
await writeTextIfChanged4(path158.join(metaprojectRoot, "skills", "gdctx", "SKILL.md"), renderGdctxSkillReadme());
|
|
67394
67876
|
}
|
|
67395
67877
|
if (enableGdwiki) {
|
|
67396
|
-
await writeTextIfMissing4(
|
|
67397
|
-
await writeTextIfChanged4(
|
|
67398
|
-
await writeTextIfChanged4(
|
|
67878
|
+
await writeTextIfMissing4(path158.join(metaprojectRoot, "wiki", "templates", "page.md"), renderWikiPageTemplate());
|
|
67879
|
+
await writeTextIfChanged4(path158.join(metaprojectRoot, "modules", "gdwiki.md"), renderGdwikiManifest());
|
|
67880
|
+
await writeTextIfChanged4(path158.join(metaprojectRoot, "skills", "gdwiki", "SKILL.md"), renderGdwikiSkillReadme());
|
|
67399
67881
|
if (manifest.modules?.gdgraph?.hooks?.gitPostCommit) {
|
|
67400
67882
|
await installManagedHook2(projectRoot, "post-commit", "gdwiki-post-commit", renderGdwikiPostCommitHook());
|
|
67401
67883
|
}
|
|
67402
67884
|
}
|
|
67403
67885
|
if (enableSac) {
|
|
67404
|
-
await writeTextIfMissing4(
|
|
67405
|
-
await writeTextIfChanged4(
|
|
67886
|
+
await writeTextIfMissing4(path158.join(metaprojectRoot, "modules", "sac.md"), renderSacManifest());
|
|
67887
|
+
await writeTextIfChanged4(path158.join(metaprojectRoot, "skills", "sac", "SKILL.md"), renderSacSkillReadme());
|
|
67406
67888
|
}
|
|
67407
67889
|
if (enableGdskills) {
|
|
67408
67890
|
await installGdskills(metaprojectRoot, gdskillsProfile, { createDataDirs: false });
|
|
@@ -67411,25 +67893,25 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
67411
67893
|
}
|
|
67412
67894
|
}
|
|
67413
67895
|
if (enableHealth) {
|
|
67414
|
-
await writeTextIfMissing4(
|
|
67415
|
-
await writeTextIfChanged4(
|
|
67416
|
-
await writeTextIfChanged4(
|
|
67417
|
-
await writeTextIfChanged4(
|
|
67896
|
+
await writeTextIfMissing4(path158.join(metaprojectRoot, "health.config.json"), renderHealthConfig());
|
|
67897
|
+
await writeTextIfChanged4(path158.join(metaprojectRoot, "modules", "health.md"), renderHealthManifest());
|
|
67898
|
+
await writeTextIfChanged4(path158.join(metaprojectRoot, "core", "health", "README.md"), renderHealthCoreReadme());
|
|
67899
|
+
await writeTextIfChanged4(path158.join(metaprojectRoot, "skills", "health", "SKILL.md"), renderHealthSkillReadme());
|
|
67418
67900
|
if (manifest.modules?.health?.hooks?.gitPostCommit) {
|
|
67419
67901
|
await installManagedHook2(projectRoot, "post-commit", "health-post-commit", renderHealthPostCommitHook());
|
|
67420
67902
|
}
|
|
67421
67903
|
}
|
|
67422
67904
|
if (enableTesting) {
|
|
67423
|
-
await writeTextIfMissing4(
|
|
67905
|
+
await writeTextIfMissing4(path158.join(metaprojectRoot, "testing.config.json"), renderTestingConfig({
|
|
67424
67906
|
postCommitRefresh: Boolean(manifest.modules?.testing?.hooks?.gitPostCommit),
|
|
67425
67907
|
prePushGate: Boolean(manifest.modules?.testing?.hooks?.prePush)
|
|
67426
67908
|
}));
|
|
67427
|
-
await writeTextIfChanged4(
|
|
67428
|
-
await writeTextIfChanged4(
|
|
67429
|
-
await writeTextIfChanged4(
|
|
67909
|
+
await writeTextIfChanged4(path158.join(metaprojectRoot, "modules", "testing.md"), renderTestingManifest());
|
|
67910
|
+
await writeTextIfChanged4(path158.join(metaprojectRoot, "core", "testing", "README.md"), renderTestingCoreReadme());
|
|
67911
|
+
await writeTextIfChanged4(path158.join(metaprojectRoot, "skills", "testing", "SKILL.md"), renderTestingSkillReadme());
|
|
67430
67912
|
if (enableGdwiki) {
|
|
67431
|
-
await writeTextIfMissing4(
|
|
67432
|
-
await writeTextIfMissing4(
|
|
67913
|
+
await writeTextIfMissing4(path158.join(metaprojectRoot, "wiki", "testing", "README.md"), renderTestingWikiReadme());
|
|
67914
|
+
await writeTextIfMissing4(path158.join(metaprojectRoot, "wiki", "testing", "conventions.md"), renderTestingWikiConventions());
|
|
67433
67915
|
}
|
|
67434
67916
|
if (manifest.modules?.testing?.hooks?.gitPostCommit) {
|
|
67435
67917
|
await installManagedHook2(projectRoot, "post-commit", "testing-post-commit", renderTestingPostCommitHook());
|
|
@@ -67442,24 +67924,24 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
67442
67924
|
await installManagedHook2(projectRoot, "post-commit", "metaproject-dashboard-post-commit", renderMetaprojectDashboardPostCommitHook());
|
|
67443
67925
|
}
|
|
67444
67926
|
if (enableMemory) {
|
|
67445
|
-
await writeTextIfMissing4(
|
|
67446
|
-
await writeTextIfMissing4(
|
|
67447
|
-
await writeTextIfChanged4(
|
|
67448
|
-
await writeTextIfChanged4(
|
|
67449
|
-
await writeTextIfChanged4(
|
|
67927
|
+
await writeTextIfMissing4(path158.join(metaprojectRoot, "memory.config.json"), renderMemoryConfig());
|
|
67928
|
+
await writeTextIfMissing4(path158.join(metaprojectRoot, "memory", "templates", "entry.md"), renderMemoryEntryTemplate());
|
|
67929
|
+
await writeTextIfChanged4(path158.join(metaprojectRoot, "modules", "memory.md"), renderMemoryManifest());
|
|
67930
|
+
await writeTextIfChanged4(path158.join(metaprojectRoot, "core", "memory", "README.md"), renderMemoryCoreReadme());
|
|
67931
|
+
await writeTextIfChanged4(path158.join(metaprojectRoot, "skills", "memory", "SKILL.md"), renderMemorySkillReadme());
|
|
67450
67932
|
}
|
|
67451
67933
|
if (enableTasks) {
|
|
67452
|
-
await writeTextIfChanged4(
|
|
67453
|
-
await writeTextIfChanged4(
|
|
67454
|
-
await writeTextIfChanged4(
|
|
67455
|
-
await writeTextIfChanged4(
|
|
67456
|
-
await writeTextIfChanged4(
|
|
67457
|
-
await writeTextIfChanged4(
|
|
67934
|
+
await writeTextIfChanged4(path158.join(metaprojectRoot, "flows", "README.md"), renderFlowsReadme());
|
|
67935
|
+
await writeTextIfChanged4(path158.join(metaprojectRoot, "modules", "tasks.md"), renderTasksManifest());
|
|
67936
|
+
await writeTextIfChanged4(path158.join(metaprojectRoot, "skills", "flow", "SKILL.md"), renderFlowSkillRouter());
|
|
67937
|
+
await writeTextIfChanged4(path158.join(metaprojectRoot, "skills", "flow", "init.md"), renderFlowInitSkill());
|
|
67938
|
+
await writeTextIfChanged4(path158.join(metaprojectRoot, "skills", "flow", "manage.md"), renderFlowManageSkill());
|
|
67939
|
+
await writeTextIfChanged4(path158.join(metaprojectRoot, "skills", "flow", "complete.md"), renderFlowCompleteSkill());
|
|
67458
67940
|
}
|
|
67459
67941
|
if (enableSecurity) {
|
|
67460
|
-
await writeTextIfMissing4(
|
|
67461
|
-
await writeTextIfChanged4(
|
|
67462
|
-
await writeTextIfChanged4(
|
|
67942
|
+
await writeTextIfMissing4(path158.join(metaprojectRoot, "security.config.json"), renderSecurityConfig());
|
|
67943
|
+
await writeTextIfChanged4(path158.join(metaprojectRoot, "modules", "security.md"), renderSecurityManifest());
|
|
67944
|
+
await writeTextIfChanged4(path158.join(metaprojectRoot, "core", "security", "README.md"), renderSecurityCoreReadme());
|
|
67463
67945
|
if (manifest.modules?.security?.hooks?.prePush) {
|
|
67464
67946
|
await installManagedHook2(projectRoot, "pre-push", "security-pre-push", renderSecurityPrePushHook());
|
|
67465
67947
|
}
|
|
@@ -67510,13 +67992,13 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
67510
67992
|
};
|
|
67511
67993
|
}
|
|
67512
67994
|
async function buildDashboard(projectRoot = process.cwd()) {
|
|
67513
|
-
const metaprojectRoot =
|
|
67995
|
+
const metaprojectRoot = path158.join(projectRoot, ".metaproject");
|
|
67514
67996
|
if (!await pathExists(metaprojectRoot)) {
|
|
67515
67997
|
throw new Error("Metaproject is not initialized. Run: keryx init");
|
|
67516
67998
|
}
|
|
67517
67999
|
const manifest = (await readManifest5(metaprojectRoot)).manifest;
|
|
67518
68000
|
const data = await collectDashboardData(metaprojectRoot);
|
|
67519
|
-
const dashboardPath =
|
|
68001
|
+
const dashboardPath = path158.join(metaprojectRoot, "keryx-dashboard.html");
|
|
67520
68002
|
await writeTextIfChanged4(dashboardPath, renderMetaprojectDashboardHtml({
|
|
67521
68003
|
enableGdgraph: moduleEnabled2(manifest, "gdgraph"),
|
|
67522
68004
|
enableGdctx: moduleEnabled2(manifest, "gdctx"),
|
|
@@ -67536,11 +68018,11 @@ async function shouldInstallDashboardPostCommitHook(projectRoot, manifest) {
|
|
|
67536
68018
|
if (Object.values(modules).some((module) => Boolean(module.hooks?.gitPostCommit))) {
|
|
67537
68019
|
return true;
|
|
67538
68020
|
}
|
|
67539
|
-
const hookPath =
|
|
68021
|
+
const hookPath = path158.join(projectRoot, ".git", "hooks", "post-commit");
|
|
67540
68022
|
if (!await pathExists(hookPath)) {
|
|
67541
68023
|
return false;
|
|
67542
68024
|
}
|
|
67543
|
-
return (await
|
|
68025
|
+
return (await readFile80(hookPath, "utf8")).includes("# keryx:");
|
|
67544
68026
|
}
|
|
67545
68027
|
async function collectDashboardData(metaprojectRoot) {
|
|
67546
68028
|
const data = {};
|
|
@@ -67556,11 +68038,11 @@ async function collectDashboardData(metaprojectRoot) {
|
|
|
67556
68038
|
if (testing) {
|
|
67557
68039
|
data.testing = testing;
|
|
67558
68040
|
}
|
|
67559
|
-
const wiki = await collectMarkdownPages(
|
|
68041
|
+
const wiki = await collectMarkdownPages(path158.join(metaprojectRoot, "wiki"), "wiki");
|
|
67560
68042
|
if (wiki.length > 0) {
|
|
67561
68043
|
data.wiki = { pages: wiki };
|
|
67562
68044
|
}
|
|
67563
|
-
const memory = await collectMarkdownPages(
|
|
68045
|
+
const memory = await collectMarkdownPages(path158.join(metaprojectRoot, "memory"), "memory");
|
|
67564
68046
|
if (memory.length > 0) {
|
|
67565
68047
|
data.memory = { entries: memory };
|
|
67566
68048
|
}
|
|
@@ -67575,29 +68057,29 @@ async function collectDashboardData(metaprojectRoot) {
|
|
|
67575
68057
|
return data;
|
|
67576
68058
|
}
|
|
67577
68059
|
async function collectTasksDashboardData(metaprojectRoot) {
|
|
67578
|
-
const flowsRoot2 =
|
|
68060
|
+
const flowsRoot2 = path158.join(metaprojectRoot, "flows");
|
|
67579
68061
|
if (!await pathExists(flowsRoot2)) {
|
|
67580
68062
|
return null;
|
|
67581
68063
|
}
|
|
67582
68064
|
let dirEntries;
|
|
67583
68065
|
try {
|
|
67584
|
-
dirEntries = (await
|
|
68066
|
+
dirEntries = (await readdir27(flowsRoot2, { withFileTypes: true })).filter((entry) => entry.isDirectory() && /^\d{3}-/.test(entry.name)).map((entry) => entry.name).sort();
|
|
67585
68067
|
} catch {
|
|
67586
68068
|
return null;
|
|
67587
68069
|
}
|
|
67588
68070
|
const flows = [];
|
|
67589
68071
|
for (const dir of dirEntries) {
|
|
67590
|
-
const flowPath =
|
|
68072
|
+
const flowPath = path158.join(flowsRoot2, dir, "flow.json");
|
|
67591
68073
|
if (!await pathExists(flowPath)) {
|
|
67592
68074
|
continue;
|
|
67593
68075
|
}
|
|
67594
68076
|
try {
|
|
67595
|
-
const flow = JSON.parse(await
|
|
68077
|
+
const flow = JSON.parse(await readFile80(flowPath, "utf8"));
|
|
67596
68078
|
const tasks = Array.isArray(flow.tasks) ? flow.tasks : [];
|
|
67597
68079
|
let acTotal = 0;
|
|
67598
|
-
const acPath2 =
|
|
68080
|
+
const acPath2 = path158.join(flowsRoot2, dir, "acceptance-criteria.md");
|
|
67599
68081
|
if (await pathExists(acPath2)) {
|
|
67600
|
-
const acContent = await
|
|
68082
|
+
const acContent = await readFile80(acPath2, "utf8");
|
|
67601
68083
|
acTotal = (acContent.match(/^- AC\d+:/gm) ?? []).length;
|
|
67602
68084
|
}
|
|
67603
68085
|
flows.push({
|
|
@@ -67649,11 +68131,11 @@ async function collectDashboardDocs(metaprojectRoot, wiki, memory) {
|
|
|
67649
68131
|
"data/testing/context.md"
|
|
67650
68132
|
];
|
|
67651
68133
|
for (const href of staticHrefs) {
|
|
67652
|
-
const filePath =
|
|
68134
|
+
const filePath = path158.join(metaprojectRoot, ...href.split("/"));
|
|
67653
68135
|
if (!await pathExists(filePath)) {
|
|
67654
68136
|
continue;
|
|
67655
68137
|
}
|
|
67656
|
-
const content = await
|
|
68138
|
+
const content = await readFile80(filePath, "utf8");
|
|
67657
68139
|
docs[href] = content.length > 40000 ? `${content.slice(0, 40000)}
|
|
67658
68140
|
|
|
67659
68141
|
\u2026truncated\u2026` : content;
|
|
@@ -67666,11 +68148,11 @@ async function collectDashboardDocs(metaprojectRoot, wiki, memory) {
|
|
|
67666
68148
|
return docs;
|
|
67667
68149
|
}
|
|
67668
68150
|
async function collectHealthDashboardData(metaprojectRoot) {
|
|
67669
|
-
const reportPath2 =
|
|
68151
|
+
const reportPath2 = path158.join(metaprojectRoot, "data", "health", "artifacts", "latest.json");
|
|
67670
68152
|
if (!await pathExists(reportPath2)) {
|
|
67671
68153
|
return;
|
|
67672
68154
|
}
|
|
67673
|
-
const report = JSON.parse(await
|
|
68155
|
+
const report = JSON.parse(await readFile80(reportPath2, "utf8"));
|
|
67674
68156
|
const metrics = Array.isArray(report.metrics) ? report.metrics : [];
|
|
67675
68157
|
const findings = Array.isArray(report.findings) ? report.findings : [];
|
|
67676
68158
|
const project = metrics.find((metric) => metric.key === "project") ?? {};
|
|
@@ -67775,8 +68257,8 @@ function metricToScope(metric) {
|
|
|
67775
68257
|
};
|
|
67776
68258
|
}
|
|
67777
68259
|
async function collectGraphDashboardData(metaprojectRoot) {
|
|
67778
|
-
const nodesPath =
|
|
67779
|
-
const edgesPath =
|
|
68260
|
+
const nodesPath = path158.join(metaprojectRoot, "data", "gdgraph", "storage", "nodes.jsonl");
|
|
68261
|
+
const edgesPath = path158.join(metaprojectRoot, "data", "gdgraph", "storage", "edges.jsonl");
|
|
67780
68262
|
if (!await pathExists(nodesPath) || !await pathExists(edgesPath)) {
|
|
67781
68263
|
return;
|
|
67782
68264
|
}
|
|
@@ -67784,7 +68266,7 @@ async function collectGraphDashboardData(metaprojectRoot) {
|
|
|
67784
68266
|
let nodes = 0;
|
|
67785
68267
|
let files = 0;
|
|
67786
68268
|
let assets = 0;
|
|
67787
|
-
for (const node of parseJsonl2(await
|
|
68269
|
+
for (const node of parseJsonl2(await readFile80(nodesPath, "utf8"))) {
|
|
67788
68270
|
nodes += 1;
|
|
67789
68271
|
if (node.kind === "asset") {
|
|
67790
68272
|
assets += 1;
|
|
@@ -67800,7 +68282,7 @@ async function collectGraphDashboardData(metaprojectRoot) {
|
|
|
67800
68282
|
let imports = 0;
|
|
67801
68283
|
let assetEdges = 0;
|
|
67802
68284
|
let unresolved = 0;
|
|
67803
|
-
for (const edge of parseJsonl2(await
|
|
68285
|
+
for (const edge of parseJsonl2(await readFile80(edgesPath, "utf8"))) {
|
|
67804
68286
|
edges += 1;
|
|
67805
68287
|
if (edge.kind === "imports") {
|
|
67806
68288
|
imports += 1;
|
|
@@ -67827,10 +68309,10 @@ async function collectGraphDashboardData(metaprojectRoot) {
|
|
|
67827
68309
|
};
|
|
67828
68310
|
}
|
|
67829
68311
|
async function collectTestingDashboardData(metaprojectRoot) {
|
|
67830
|
-
const reportPath2 =
|
|
67831
|
-
const contextPath =
|
|
68312
|
+
const reportPath2 = path158.join(metaprojectRoot, "data", "testing", "artifacts", "latest.json");
|
|
68313
|
+
const contextPath = path158.join(metaprojectRoot, "data", "testing", "context.md");
|
|
67832
68314
|
if (await pathExists(reportPath2)) {
|
|
67833
|
-
const report = JSON.parse(await
|
|
68315
|
+
const report = JSON.parse(await readFile80(reportPath2, "utf8"));
|
|
67834
68316
|
const totalTests = numberOrUndefined(report.total);
|
|
67835
68317
|
const failedTests = Array.isArray(report.failures) ? report.failures.length : numberOrUndefined(report.failed);
|
|
67836
68318
|
return {
|
|
@@ -67857,11 +68339,11 @@ async function collectMarkdownPages(root, hrefPrefix) {
|
|
|
67857
68339
|
const files = await listMarkdownFiles(root);
|
|
67858
68340
|
const pages = [];
|
|
67859
68341
|
for (const filePath of files.slice(0, 40)) {
|
|
67860
|
-
const relativePath =
|
|
68342
|
+
const relativePath = path158.relative(root, filePath).split(path158.sep).join("/");
|
|
67861
68343
|
if (relativePath === "index.md" || relativePath.startsWith("templates/")) {
|
|
67862
68344
|
continue;
|
|
67863
68345
|
}
|
|
67864
|
-
const content = await
|
|
68346
|
+
const content = await readFile80(filePath, "utf8");
|
|
67865
68347
|
const embedded = content.length > 24000 ? `${content.slice(0, 24000)}
|
|
67866
68348
|
|
|
67867
68349
|
\u2026truncated\u2026` : content;
|
|
@@ -67875,10 +68357,10 @@ async function collectMarkdownPages(root, hrefPrefix) {
|
|
|
67875
68357
|
return pages;
|
|
67876
68358
|
}
|
|
67877
68359
|
async function listMarkdownFiles(root) {
|
|
67878
|
-
const entries = await
|
|
68360
|
+
const entries = await readdir27(root, { withFileTypes: true });
|
|
67879
68361
|
const files = [];
|
|
67880
68362
|
for (const entry of entries) {
|
|
67881
|
-
const fullPath =
|
|
68363
|
+
const fullPath = path158.join(root, entry.name);
|
|
67882
68364
|
if (entry.isDirectory()) {
|
|
67883
68365
|
files.push(...await listMarkdownFiles(fullPath));
|
|
67884
68366
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
@@ -67926,7 +68408,7 @@ async function writeRecoveredManifest(metaprojectRoot, modules) {
|
|
|
67926
68408
|
const manifest = {
|
|
67927
68409
|
schemaVersion: 1,
|
|
67928
68410
|
standardVersion: STANDARD_VERSION,
|
|
67929
|
-
name: `${
|
|
68411
|
+
name: `${path158.basename(path158.dirname(metaprojectRoot))}-metaproject`,
|
|
67930
68412
|
createdBy: "keryx",
|
|
67931
68413
|
profiles: computeProfiles(enabledModuleKeys2),
|
|
67932
68414
|
paths: {
|
|
@@ -68027,17 +68509,17 @@ async function writeRecoveredManifest(metaprojectRoot, modules) {
|
|
|
68027
68509
|
metaproject: ".metaproject/index.md"
|
|
68028
68510
|
}
|
|
68029
68511
|
};
|
|
68030
|
-
await writeFile49(
|
|
68512
|
+
await writeFile49(path158.join(metaprojectRoot, "metaproject.json"), `${JSON.stringify(manifest, null, 2)}
|
|
68031
68513
|
`, "utf8");
|
|
68032
68514
|
}
|
|
68033
68515
|
async function enableTasksInManifest(metaprojectRoot) {
|
|
68034
|
-
const manifestPath =
|
|
68516
|
+
const manifestPath = path158.join(metaprojectRoot, "metaproject.json");
|
|
68035
68517
|
if (!await pathExists(manifestPath)) {
|
|
68036
68518
|
return;
|
|
68037
68519
|
}
|
|
68038
68520
|
let raw;
|
|
68039
68521
|
try {
|
|
68040
|
-
raw = JSON.parse(await
|
|
68522
|
+
raw = JSON.parse(await readFile80(manifestPath, "utf8"));
|
|
68041
68523
|
} catch {
|
|
68042
68524
|
return;
|
|
68043
68525
|
}
|
|
@@ -68054,13 +68536,13 @@ async function enableTasksInManifest(metaprojectRoot) {
|
|
|
68054
68536
|
`, "utf8");
|
|
68055
68537
|
}
|
|
68056
68538
|
async function updateManifestAgentEntrypoints(metaprojectRoot, ruleSources) {
|
|
68057
|
-
const manifestPath =
|
|
68539
|
+
const manifestPath = path158.join(metaprojectRoot, "metaproject.json");
|
|
68058
68540
|
if (!await pathExists(manifestPath)) {
|
|
68059
68541
|
return;
|
|
68060
68542
|
}
|
|
68061
68543
|
let raw;
|
|
68062
68544
|
try {
|
|
68063
|
-
raw = JSON.parse(await
|
|
68545
|
+
raw = JSON.parse(await readFile80(manifestPath, "utf8"));
|
|
68064
68546
|
} catch {
|
|
68065
68547
|
return;
|
|
68066
68548
|
}
|
|
@@ -68090,86 +68572,86 @@ async function updateRuntime(projectRoot) {
|
|
|
68090
68572
|
}
|
|
68091
68573
|
}
|
|
68092
68574
|
async function findRuntimeRoot(projectRoot) {
|
|
68093
|
-
const projectRuntime =
|
|
68094
|
-
if (await pathExists(
|
|
68575
|
+
const projectRuntime = path158.join(projectRoot, ".metaproject", "runtime", "keryx");
|
|
68576
|
+
if (await pathExists(path158.join(projectRuntime, ".git"))) {
|
|
68095
68577
|
return projectRuntime;
|
|
68096
68578
|
}
|
|
68097
68579
|
const home = process.env.HOME;
|
|
68098
68580
|
if (!home) {
|
|
68099
68581
|
return null;
|
|
68100
68582
|
}
|
|
68101
|
-
const globalRuntime =
|
|
68102
|
-
if (await pathExists(
|
|
68583
|
+
const globalRuntime = path158.join(home, ".keryx", "keryx");
|
|
68584
|
+
if (await pathExists(path158.join(globalRuntime, ".git"))) {
|
|
68103
68585
|
return globalRuntime;
|
|
68104
68586
|
}
|
|
68105
68587
|
return null;
|
|
68106
68588
|
}
|
|
68107
68589
|
async function createServiceDirs(metaprojectRoot, modules) {
|
|
68108
68590
|
const dirs = [
|
|
68109
|
-
|
|
68110
|
-
|
|
68111
|
-
|
|
68112
|
-
|
|
68113
|
-
|
|
68591
|
+
path158.join(metaprojectRoot, "core"),
|
|
68592
|
+
path158.join(metaprojectRoot, "hooks", "post-update.d"),
|
|
68593
|
+
path158.join(metaprojectRoot, "modules"),
|
|
68594
|
+
path158.join(metaprojectRoot, "rules"),
|
|
68595
|
+
path158.join(metaprojectRoot, "skills", "project-rules"),
|
|
68114
68596
|
...modules.enableGdgraph ? [
|
|
68115
|
-
|
|
68116
|
-
|
|
68597
|
+
path158.join(metaprojectRoot, "core", "gdgraph"),
|
|
68598
|
+
path158.join(metaprojectRoot, "skills", "gdgraph")
|
|
68117
68599
|
] : [],
|
|
68118
68600
|
...modules.enableGdctx ? [
|
|
68119
|
-
|
|
68120
|
-
|
|
68601
|
+
path158.join(metaprojectRoot, "core", "gdctx"),
|
|
68602
|
+
path158.join(metaprojectRoot, "skills", "gdctx")
|
|
68121
68603
|
] : [],
|
|
68122
68604
|
...modules.enableGdwiki ? [
|
|
68123
|
-
|
|
68124
|
-
|
|
68605
|
+
path158.join(metaprojectRoot, "skills", "gdwiki"),
|
|
68606
|
+
path158.join(metaprojectRoot, "wiki", "templates")
|
|
68125
68607
|
] : [],
|
|
68126
68608
|
...modules.enableHealth ? [
|
|
68127
|
-
|
|
68128
|
-
|
|
68609
|
+
path158.join(metaprojectRoot, "core", "health"),
|
|
68610
|
+
path158.join(metaprojectRoot, "skills", "health")
|
|
68129
68611
|
] : [],
|
|
68130
68612
|
...modules.enableTesting ? [
|
|
68131
|
-
|
|
68132
|
-
|
|
68613
|
+
path158.join(metaprojectRoot, "core", "testing"),
|
|
68614
|
+
path158.join(metaprojectRoot, "skills", "testing")
|
|
68133
68615
|
] : [],
|
|
68134
68616
|
...modules.enableMemory ? [
|
|
68135
|
-
|
|
68136
|
-
|
|
68137
|
-
|
|
68617
|
+
path158.join(metaprojectRoot, "core", "memory"),
|
|
68618
|
+
path158.join(metaprojectRoot, "skills", "memory"),
|
|
68619
|
+
path158.join(metaprojectRoot, "memory", "templates")
|
|
68138
68620
|
] : [],
|
|
68139
68621
|
...modules.enableTasks ? [
|
|
68140
|
-
|
|
68141
|
-
|
|
68622
|
+
path158.join(metaprojectRoot, "flows"),
|
|
68623
|
+
path158.join(metaprojectRoot, "skills", "flow")
|
|
68142
68624
|
] : [],
|
|
68143
68625
|
...modules.enableSecurity ? [
|
|
68144
|
-
|
|
68626
|
+
path158.join(metaprojectRoot, "core", "security")
|
|
68145
68627
|
] : [],
|
|
68146
68628
|
...modules.enableSac ? [
|
|
68147
|
-
|
|
68629
|
+
path158.join(metaprojectRoot, "skills", "sac")
|
|
68148
68630
|
] : []
|
|
68149
68631
|
];
|
|
68150
|
-
await Promise.all(dirs.map((dir) =>
|
|
68632
|
+
await Promise.all(dirs.map((dir) => mkdir56(dir, { recursive: true })));
|
|
68151
68633
|
}
|
|
68152
68634
|
async function installGdgraphCoreScripts2(metaprojectRoot) {
|
|
68153
|
-
const gdgraphCoreRoot =
|
|
68154
|
-
await
|
|
68635
|
+
const gdgraphCoreRoot = path158.join(metaprojectRoot, "core", "gdgraph");
|
|
68636
|
+
await mkdir56(gdgraphCoreRoot, { recursive: true });
|
|
68155
68637
|
for (const file of GDGRAPH_CORE_SOURCES) {
|
|
68156
|
-
await copyFileIfChanged2(runtimeSourcePath2(`../gdgraph/${file}`),
|
|
68638
|
+
await copyFileIfChanged2(runtimeSourcePath2(`../gdgraph/${file}`), path158.join(gdgraphCoreRoot, file));
|
|
68157
68639
|
}
|
|
68158
|
-
await writeTextIfChanged4(
|
|
68640
|
+
await writeTextIfChanged4(path158.join(gdgraphCoreRoot, "cli.ts"), renderGdgraphCoreCli());
|
|
68159
68641
|
}
|
|
68160
68642
|
async function installManagedHook2(projectRoot, hookName, blockId, content) {
|
|
68161
68643
|
const hooksRoot = await resolveGitHooksRoot(projectRoot);
|
|
68162
68644
|
if (!hooksRoot) {
|
|
68163
68645
|
return;
|
|
68164
68646
|
}
|
|
68165
|
-
await
|
|
68166
|
-
const hookPath =
|
|
68647
|
+
await mkdir56(hooksRoot, { recursive: true });
|
|
68648
|
+
const hookPath = path158.join(hooksRoot, hookName);
|
|
68167
68649
|
const blockStart = `# keryx:${blockId}:begin`;
|
|
68168
68650
|
const blockEnd = `# keryx:${blockId}:end`;
|
|
68169
68651
|
const managedBlock = `${blockStart}
|
|
68170
68652
|
${content.trim()}
|
|
68171
68653
|
${blockEnd}`;
|
|
68172
|
-
const existing = await pathExists(hookPath) ? await
|
|
68654
|
+
const existing = await pathExists(hookPath) ? await readFile80(hookPath, "utf8") : `#!/usr/bin/env sh
|
|
68173
68655
|
`;
|
|
68174
68656
|
const blockPattern = new RegExp(`${escapeRegExp6(blockStart)}[\\s\\S]*?${escapeRegExp6(blockEnd)}`);
|
|
68175
68657
|
const next = blockPattern.test(existing) ? existing.replace(blockPattern, managedBlock) : `${existing.trimEnd()}
|
|
@@ -68184,11 +68666,11 @@ async function removeManagedHook2(projectRoot, hookName, blockId) {
|
|
|
68184
68666
|
if (!hooksRoot) {
|
|
68185
68667
|
return;
|
|
68186
68668
|
}
|
|
68187
|
-
const hookPath =
|
|
68669
|
+
const hookPath = path158.join(hooksRoot, hookName);
|
|
68188
68670
|
if (!await pathExists(hookPath)) {
|
|
68189
68671
|
return;
|
|
68190
68672
|
}
|
|
68191
|
-
const existing = await
|
|
68673
|
+
const existing = await readFile80(hookPath, "utf8");
|
|
68192
68674
|
const blockStart = `# keryx:${blockId}:begin`;
|
|
68193
68675
|
const blockEnd = `# keryx:${blockId}:end`;
|
|
68194
68676
|
const blockPattern = new RegExp(`\\n*${escapeRegExp6(blockStart)}[\\s\\S]*?${escapeRegExp6(blockEnd)}\\n*`);
|
|
@@ -68206,11 +68688,11 @@ async function prePushHasSecurityBlock2(projectRoot) {
|
|
|
68206
68688
|
if (!hooksRoot) {
|
|
68207
68689
|
return false;
|
|
68208
68690
|
}
|
|
68209
|
-
const hookPath =
|
|
68691
|
+
const hookPath = path158.join(hooksRoot, "pre-push");
|
|
68210
68692
|
if (!await pathExists(hookPath)) {
|
|
68211
68693
|
return false;
|
|
68212
68694
|
}
|
|
68213
|
-
const hook = await
|
|
68695
|
+
const hook = await readFile80(hookPath, "utf8");
|
|
68214
68696
|
return hook.includes("# keryx:security-pre-push:begin");
|
|
68215
68697
|
}
|
|
68216
68698
|
async function agentSettingsHasSecuritySentinel2(projectRoot) {
|
|
@@ -68218,10 +68700,10 @@ async function agentSettingsHasSecuritySentinel2(projectRoot) {
|
|
|
68218
68700
|
if (!await pathExists(file)) {
|
|
68219
68701
|
return false;
|
|
68220
68702
|
}
|
|
68221
|
-
return (await
|
|
68703
|
+
return (await readFile80(file, "utf8")).includes(AGENT_HOOKS_SENTINEL);
|
|
68222
68704
|
}
|
|
68223
68705
|
async function readManifest5(metaprojectRoot) {
|
|
68224
|
-
const manifestPath =
|
|
68706
|
+
const manifestPath = path158.join(metaprojectRoot, "metaproject.json");
|
|
68225
68707
|
if (!await pathExists(manifestPath)) {
|
|
68226
68708
|
return {
|
|
68227
68709
|
exists: false,
|
|
@@ -68231,7 +68713,7 @@ async function readManifest5(metaprojectRoot) {
|
|
|
68231
68713
|
};
|
|
68232
68714
|
}
|
|
68233
68715
|
try {
|
|
68234
|
-
const manifest = JSON.parse(await
|
|
68716
|
+
const manifest = JSON.parse(await readFile80(manifestPath, "utf8"));
|
|
68235
68717
|
const normalized = normalizeManifest(manifest);
|
|
68236
68718
|
return {
|
|
68237
68719
|
exists: true,
|
|
@@ -68290,7 +68772,7 @@ async function inferManifestFromExistingMetaproject(metaprojectRoot) {
|
|
|
68290
68772
|
}
|
|
68291
68773
|
async function anyPathExists(root, candidates) {
|
|
68292
68774
|
for (const candidate of candidates) {
|
|
68293
|
-
if (await pathExists(
|
|
68775
|
+
if (await pathExists(path158.join(root, candidate))) {
|
|
68294
68776
|
return true;
|
|
68295
68777
|
}
|
|
68296
68778
|
}
|
|
@@ -68311,13 +68793,13 @@ function parseUpdateArgs(args2) {
|
|
|
68311
68793
|
};
|
|
68312
68794
|
}
|
|
68313
68795
|
async function runPostUpdateHooks(projectRoot) {
|
|
68314
|
-
const hooksDir =
|
|
68796
|
+
const hooksDir = path158.join(projectRoot, ".metaproject", "hooks", "post-update.d");
|
|
68315
68797
|
if (!await pathExists(hooksDir)) {
|
|
68316
68798
|
return;
|
|
68317
68799
|
}
|
|
68318
|
-
const entries = (await
|
|
68800
|
+
const entries = (await readdir27(hooksDir)).sort();
|
|
68319
68801
|
for (const entry of entries) {
|
|
68320
|
-
const hookPath =
|
|
68802
|
+
const hookPath = path158.join(hooksDir, entry);
|
|
68321
68803
|
try {
|
|
68322
68804
|
await accessExecutable(hookPath);
|
|
68323
68805
|
} catch {
|
|
@@ -68355,25 +68837,25 @@ async function run(command, args2, cwd) {
|
|
|
68355
68837
|
});
|
|
68356
68838
|
}
|
|
68357
68839
|
async function writeTextIfChanged4(filePath, content) {
|
|
68358
|
-
if (await pathExists(filePath) && await
|
|
68840
|
+
if (await pathExists(filePath) && await readFile80(filePath, "utf8") === content) {
|
|
68359
68841
|
return;
|
|
68360
68842
|
}
|
|
68361
|
-
await
|
|
68843
|
+
await mkdir56(path158.dirname(filePath), { recursive: true });
|
|
68362
68844
|
await writeFile49(filePath, content, "utf8");
|
|
68363
68845
|
}
|
|
68364
68846
|
async function writeTextIfMissing4(filePath, content) {
|
|
68365
68847
|
if (await pathExists(filePath)) {
|
|
68366
68848
|
return;
|
|
68367
68849
|
}
|
|
68368
|
-
await
|
|
68850
|
+
await mkdir56(path158.dirname(filePath), { recursive: true });
|
|
68369
68851
|
await writeFile49(filePath, content, "utf8");
|
|
68370
68852
|
}
|
|
68371
68853
|
async function copyFileIfChanged2(from, to) {
|
|
68372
|
-
const next = await
|
|
68373
|
-
if (await pathExists(to) && await
|
|
68854
|
+
const next = await readFile80(from, "utf8");
|
|
68855
|
+
if (await pathExists(to) && await readFile80(to, "utf8") === next) {
|
|
68374
68856
|
return;
|
|
68375
68857
|
}
|
|
68376
|
-
await
|
|
68858
|
+
await mkdir56(path158.dirname(to), { recursive: true });
|
|
68377
68859
|
await writeFile49(to, next, "utf8");
|
|
68378
68860
|
}
|
|
68379
68861
|
function runtimeSourcePath2(relativePath) {
|
|
@@ -68382,7 +68864,7 @@ function runtimeSourcePath2(relativePath) {
|
|
|
68382
68864
|
return directPath;
|
|
68383
68865
|
}
|
|
68384
68866
|
if (relativePath.startsWith("../")) {
|
|
68385
|
-
const packagedSourcePath =
|
|
68867
|
+
const packagedSourcePath = path158.join(path158.dirname(fileURLToPath7(import.meta.url)), "..", "src", relativePath.slice(3));
|
|
68386
68868
|
if (existsSync30(packagedSourcePath)) {
|
|
68387
68869
|
return packagedSourcePath;
|
|
68388
68870
|
}
|
|
@@ -68414,7 +68896,7 @@ function printHelp18() {
|
|
|
68414
68896
|
|
|
68415
68897
|
// src/commands/dashboard.ts
|
|
68416
68898
|
import { spawn as spawn6 } from "child_process";
|
|
68417
|
-
import
|
|
68899
|
+
import path159 from "path";
|
|
68418
68900
|
init_args();
|
|
68419
68901
|
async function dashboardCommand(args2 = []) {
|
|
68420
68902
|
const options = parseOptions(args2);
|
|
@@ -68425,7 +68907,7 @@ async function dashboardCommand(args2 = []) {
|
|
|
68425
68907
|
}
|
|
68426
68908
|
if (subcommand === "build") {
|
|
68427
68909
|
const result = await buildDashboard();
|
|
68428
|
-
const rel =
|
|
68910
|
+
const rel = path159.relative(process.cwd(), result.path);
|
|
68429
68911
|
console.log(` ${style.green(symbols.ok)} Dashboard built ${style.cyan(symbols.arrow)} ${style.cyan(rel)}`);
|
|
68430
68912
|
note(`Open it: keryx dashboard open`);
|
|
68431
68913
|
return;
|
|
@@ -68433,7 +68915,7 @@ async function dashboardCommand(args2 = []) {
|
|
|
68433
68915
|
if (subcommand === "open") {
|
|
68434
68916
|
const result = await buildDashboard();
|
|
68435
68917
|
await openFile(result.path);
|
|
68436
|
-
const rel =
|
|
68918
|
+
const rel = path159.relative(process.cwd(), result.path);
|
|
68437
68919
|
console.log(` ${style.green(symbols.ok)} Opened ${style.cyan(rel)}`);
|
|
68438
68920
|
return;
|
|
68439
68921
|
}
|
|
@@ -68480,9 +68962,9 @@ function printHelp19() {
|
|
|
68480
68962
|
import { readFileSync as readFileSync10 } from "fs";
|
|
68481
68963
|
|
|
68482
68964
|
// src/agents/bootstrap.ts
|
|
68483
|
-
import { mkdir as
|
|
68965
|
+
import { mkdir as mkdir57, readFile as readFile81, writeFile as writeFile50 } from "fs/promises";
|
|
68484
68966
|
import { homedir as homedir7 } from "os";
|
|
68485
|
-
import
|
|
68967
|
+
import path160 from "path";
|
|
68486
68968
|
init_fs();
|
|
68487
68969
|
var AGENT_BOOTSTRAP_START = "<!-- keryx:global-bootstrap -->";
|
|
68488
68970
|
var AGENT_BOOTSTRAP_END = "<!-- /keryx:global-bootstrap -->";
|
|
@@ -68492,35 +68974,35 @@ var AGENT_BOOTSTRAP_RUNTIMES = [
|
|
|
68492
68974
|
aliases: ["claude-code"],
|
|
68493
68975
|
label: "Claude Code",
|
|
68494
68976
|
fileName: "CLAUDE.md",
|
|
68495
|
-
filePath: (homeRoot) =>
|
|
68977
|
+
filePath: (homeRoot) => path160.join(homeRoot, ".claude", "CLAUDE.md")
|
|
68496
68978
|
},
|
|
68497
68979
|
{
|
|
68498
68980
|
id: "opencode",
|
|
68499
68981
|
aliases: ["open-code"],
|
|
68500
68982
|
label: "OpenCode",
|
|
68501
68983
|
fileName: "AGENTS.md",
|
|
68502
|
-
filePath: (homeRoot) =>
|
|
68984
|
+
filePath: (homeRoot) => path160.join(homeRoot, ".config", "opencode", "AGENTS.md")
|
|
68503
68985
|
},
|
|
68504
68986
|
{
|
|
68505
68987
|
id: "zcode",
|
|
68506
68988
|
aliases: ["zed", "zed-code"],
|
|
68507
68989
|
label: "ZCode",
|
|
68508
68990
|
fileName: "AGENTS.md",
|
|
68509
|
-
filePath: (homeRoot) =>
|
|
68991
|
+
filePath: (homeRoot) => path160.join(homeRoot, ".zcode", "AGENTS.md")
|
|
68510
68992
|
},
|
|
68511
68993
|
{
|
|
68512
68994
|
id: "codex",
|
|
68513
68995
|
aliases: [],
|
|
68514
68996
|
label: "Codex",
|
|
68515
68997
|
fileName: "AGENTS.md",
|
|
68516
|
-
filePath: (homeRoot) =>
|
|
68998
|
+
filePath: (homeRoot) => path160.join(homeRoot, ".codex", "AGENTS.md")
|
|
68517
68999
|
},
|
|
68518
69000
|
{
|
|
68519
69001
|
id: "antigravity",
|
|
68520
69002
|
aliases: ["antigravuty", "antigravity-code"],
|
|
68521
69003
|
label: "Antigravity",
|
|
68522
69004
|
fileName: "AGENTS.md",
|
|
68523
|
-
filePath: (homeRoot) =>
|
|
69005
|
+
filePath: (homeRoot) => path160.join(homeRoot, ".config", "antigravity", "AGENTS.md")
|
|
68524
69006
|
}
|
|
68525
69007
|
];
|
|
68526
69008
|
function agentBootstrapRuntimeIds() {
|
|
@@ -68553,7 +69035,7 @@ function resolveAgentBootstrapRuntimes(ids) {
|
|
|
68553
69035
|
async function agentBootstrapStatus(runtime, homeRoot = homedir7()) {
|
|
68554
69036
|
const filePath = runtime.filePath(homeRoot);
|
|
68555
69037
|
const exists2 = await pathExists(filePath);
|
|
68556
|
-
const content = exists2 ? await
|
|
69038
|
+
const content = exists2 ? await readFile81(filePath, "utf8") : "";
|
|
68557
69039
|
const expected = renderAgentBootstrapBlock(runtime.fileName).trim();
|
|
68558
69040
|
const installed = content.includes(AGENT_BOOTSTRAP_START);
|
|
68559
69041
|
const current = installed && extractManagedBlock(content)?.trim() === expected;
|
|
@@ -68563,12 +69045,12 @@ async function installAgentBootstrap(runtime, options = {}) {
|
|
|
68563
69045
|
const homeRoot = options.homeRoot ?? homedir7();
|
|
68564
69046
|
const filePath = runtime.filePath(homeRoot);
|
|
68565
69047
|
const exists2 = await pathExists(filePath);
|
|
68566
|
-
const current = exists2 ? await
|
|
69048
|
+
const current = exists2 ? await readFile81(filePath, "utf8") : "";
|
|
68567
69049
|
const next = upsertManagedBlock(current || defaultAgentFile(runtime), renderAgentBootstrapBlock(runtime.fileName));
|
|
68568
69050
|
const dryRun = options.dryRun === true;
|
|
68569
69051
|
const wrote = next !== current;
|
|
68570
69052
|
if (wrote && !dryRun) {
|
|
68571
|
-
await
|
|
69053
|
+
await mkdir57(path160.dirname(filePath), { recursive: true });
|
|
68572
69054
|
await writeFile50(filePath, next, "utf8");
|
|
68573
69055
|
}
|
|
68574
69056
|
const status = dryRun ? statusFromContent(runtime, filePath, exists2, next) : await agentBootstrapStatus(runtime, homeRoot);
|
|
@@ -68578,7 +69060,7 @@ async function uninstallAgentBootstrap(runtime, options = {}) {
|
|
|
68578
69060
|
const homeRoot = options.homeRoot ?? homedir7();
|
|
68579
69061
|
const filePath = runtime.filePath(homeRoot);
|
|
68580
69062
|
const exists2 = await pathExists(filePath);
|
|
68581
|
-
const current = exists2 ? await
|
|
69063
|
+
const current = exists2 ? await readFile81(filePath, "utf8") : "";
|
|
68582
69064
|
const next = removeManagedBlock(current);
|
|
68583
69065
|
const dryRun = options.dryRun === true;
|
|
68584
69066
|
const removed = next !== current;
|
|
@@ -69104,8 +69586,8 @@ function printBootstrapHelp() {
|
|
|
69104
69586
|
|
|
69105
69587
|
// src/commands/metrics.ts
|
|
69106
69588
|
init_args();
|
|
69107
|
-
import { readFile as
|
|
69108
|
-
import
|
|
69589
|
+
import { readFile as readFile82 } from "fs/promises";
|
|
69590
|
+
import path162 from "path";
|
|
69109
69591
|
|
|
69110
69592
|
// src/metrics/benchmark.ts
|
|
69111
69593
|
var RELIABILITIES2 = new Set(["exact", "estimated", "unknown"]);
|
|
@@ -69883,8 +70365,8 @@ function buildContainmentManifest(inputs, options = {}) {
|
|
|
69883
70365
|
}
|
|
69884
70366
|
|
|
69885
70367
|
// src/metrics/oracle-runner.ts
|
|
69886
|
-
import { mkdir as
|
|
69887
|
-
import
|
|
70368
|
+
import { mkdir as mkdir58, writeFile as writeFile51 } from "fs/promises";
|
|
70369
|
+
import path161 from "path";
|
|
69888
70370
|
|
|
69889
70371
|
// src/metrics/ir.ts
|
|
69890
70372
|
function toIdSet(ids) {
|
|
@@ -70326,9 +70808,9 @@ function buildEvidenceBundle(input2, options = {}) {
|
|
|
70326
70808
|
async function persistEvidenceBundle(outDir, bundle, ladder = "metastore") {
|
|
70327
70809
|
const safeTarget = bundle.target.replace(/[^A-Za-z0-9._/-]/g, "_");
|
|
70328
70810
|
const safeCase = bundle.caseId.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
70329
|
-
const dir =
|
|
70330
|
-
await
|
|
70331
|
-
const write = (name, value) => writeFile51(
|
|
70811
|
+
const dir = path161.join(outDir, "bench", ladder, safeTarget, safeCase, bundle.variant, String(bundle.seed));
|
|
70812
|
+
await mkdir58(dir, { recursive: true });
|
|
70813
|
+
const write = (name, value) => writeFile51(path161.join(dir, name), `${JSON.stringify(value, null, 2)}
|
|
70332
70814
|
`, "utf8");
|
|
70333
70815
|
await Promise.all([
|
|
70334
70816
|
write("inputs.json", bundle.inputs),
|
|
@@ -70368,7 +70850,7 @@ async function metricsCommand(args2 = [], projectRoot = process.cwd()) {
|
|
|
70368
70850
|
console.log("# metrics status");
|
|
70369
70851
|
console.log("");
|
|
70370
70852
|
console.log(`root: ${root}`);
|
|
70371
|
-
console.log(`enabled: ${await Bun.file(
|
|
70853
|
+
console.log(`enabled: ${await Bun.file(path162.join(projectRoot, ".metaproject", "metaproject.json")).exists() ? "yes" : "no"}`);
|
|
70372
70854
|
const latest2 = await readLatestPointer(root);
|
|
70373
70855
|
console.log(`latest: ${latest2.status}`);
|
|
70374
70856
|
return;
|
|
@@ -70380,7 +70862,7 @@ async function metricsCommand(args2 = [], projectRoot = process.cwd()) {
|
|
|
70380
70862
|
process.exitCode = 1;
|
|
70381
70863
|
return;
|
|
70382
70864
|
}
|
|
70383
|
-
const record2 = JSON.parse(await
|
|
70865
|
+
const record2 = JSON.parse(await readFile82(path162.resolve(projectRoot, file), "utf8"));
|
|
70384
70866
|
const result = validateRunRecord(record2);
|
|
70385
70867
|
console.log(result.valid ? "valid: yes" : "valid: no");
|
|
70386
70868
|
for (const error2 of result.errors)
|
|
@@ -70405,13 +70887,13 @@ async function metricsCommand(args2 = [], projectRoot = process.cwd()) {
|
|
|
70405
70887
|
process.exitCode = 1;
|
|
70406
70888
|
return;
|
|
70407
70889
|
}
|
|
70408
|
-
const file =
|
|
70890
|
+
const file = path162.join(metricsRoot(projectRoot), "runs", `${runId}.json`);
|
|
70409
70891
|
if (!await Bun.file(file).exists()) {
|
|
70410
70892
|
console.error(`Run not found: ${runId}`);
|
|
70411
70893
|
process.exitCode = 1;
|
|
70412
70894
|
return;
|
|
70413
70895
|
}
|
|
70414
|
-
console.log(await
|
|
70896
|
+
console.log(await readFile82(file, "utf8"));
|
|
70415
70897
|
return;
|
|
70416
70898
|
}
|
|
70417
70899
|
if (subcommand === "compare") {
|
|
@@ -70422,8 +70904,8 @@ async function metricsCommand(args2 = [], projectRoot = process.cwd()) {
|
|
|
70422
70904
|
process.exitCode = 1;
|
|
70423
70905
|
return;
|
|
70424
70906
|
}
|
|
70425
|
-
const a = JSON.parse(await
|
|
70426
|
-
const b = JSON.parse(await
|
|
70907
|
+
const a = JSON.parse(await readFile82(path162.join(metricsRoot(projectRoot), "runs", `${runA}.json`), "utf8"));
|
|
70908
|
+
const b = JSON.parse(await readFile82(path162.join(metricsRoot(projectRoot), "runs", `${runB}.json`), "utf8"));
|
|
70427
70909
|
const comparison = compareExecutionRuns(a, b);
|
|
70428
70910
|
console.log(stableJson(comparison));
|
|
70429
70911
|
return;
|
|
@@ -70457,8 +70939,8 @@ async function metricsCommand(args2 = [], projectRoot = process.cwd()) {
|
|
|
70457
70939
|
return;
|
|
70458
70940
|
}
|
|
70459
70941
|
const template = createPairedBenchmarkTemplate(taskIds);
|
|
70460
|
-
await Bun.write(
|
|
70461
|
-
console.log(`manifest: ${
|
|
70942
|
+
await Bun.write(path162.resolve(projectRoot, out), stableJson(template));
|
|
70943
|
+
console.log(`manifest: ${path162.relative(projectRoot, path162.resolve(projectRoot, out))}`);
|
|
70462
70944
|
return;
|
|
70463
70945
|
}
|
|
70464
70946
|
if (subcommand === "benchmark" && args2[1] === "run") {
|
|
@@ -70472,7 +70954,7 @@ async function metricsCommand(args2 = [], projectRoot = process.cwd()) {
|
|
|
70472
70954
|
process.exitCode = 1;
|
|
70473
70955
|
return;
|
|
70474
70956
|
}
|
|
70475
|
-
const raw = JSON.parse(await
|
|
70957
|
+
const raw = JSON.parse(await readFile82(path162.resolve(projectRoot, file), "utf8"));
|
|
70476
70958
|
const input2 = Array.isArray(raw) ? raw : raw.runs ?? [];
|
|
70477
70959
|
const result = validatePairedBenchmark(input2);
|
|
70478
70960
|
console.log(stableJson(result));
|
|
@@ -70484,7 +70966,7 @@ async function metricsCommand(args2 = [], projectRoot = process.cwd()) {
|
|
|
70484
70966
|
process.exitCode = 1;
|
|
70485
70967
|
}
|
|
70486
70968
|
async function loadAffectedSets(projectRoot, file) {
|
|
70487
|
-
const raw = JSON.parse(await
|
|
70969
|
+
const raw = JSON.parse(await readFile82(path162.resolve(projectRoot, file), "utf8"));
|
|
70488
70970
|
const map = new Map;
|
|
70489
70971
|
for (const entry of raw.targets ?? []) {
|
|
70490
70972
|
if (typeof entry.target === "string")
|
|
@@ -70555,7 +71037,7 @@ async function runHarnessLayer(projectRoot, args2, ladder) {
|
|
|
70555
71037
|
let tasks;
|
|
70556
71038
|
let model;
|
|
70557
71039
|
try {
|
|
70558
|
-
const raw = JSON.parse(await
|
|
71040
|
+
const raw = JSON.parse(await readFile82(path162.resolve(projectRoot, resultsPath), "utf8"));
|
|
70559
71041
|
tasks = raw.tasks ?? [];
|
|
70560
71042
|
model = raw.model;
|
|
70561
71043
|
} catch (error2) {
|
|
@@ -70586,7 +71068,7 @@ async function runSafetyCompletionHonestyLayer(projectRoot, args2, ladder) {
|
|
|
70586
71068
|
let cases;
|
|
70587
71069
|
let model;
|
|
70588
71070
|
try {
|
|
70589
|
-
const raw = JSON.parse(await
|
|
71071
|
+
const raw = JSON.parse(await readFile82(path162.resolve(projectRoot, resultsPath), "utf8"));
|
|
70590
71072
|
cases = raw.cases ?? [];
|
|
70591
71073
|
model = raw.model;
|
|
70592
71074
|
} catch (error2) {
|
|
@@ -70611,7 +71093,7 @@ async function runSafetyFalsePremiseLayer(projectRoot, args2, ladder) {
|
|
|
70611
71093
|
let cases;
|
|
70612
71094
|
let model;
|
|
70613
71095
|
try {
|
|
70614
|
-
const raw = JSON.parse(await
|
|
71096
|
+
const raw = JSON.parse(await readFile82(path162.resolve(projectRoot, resultsPath), "utf8"));
|
|
70615
71097
|
cases = raw.cases ?? [];
|
|
70616
71098
|
model = raw.model;
|
|
70617
71099
|
} catch (error2) {
|
|
@@ -70636,7 +71118,7 @@ async function runSafetyContainmentLayer(projectRoot, args2, ladder, caseClass)
|
|
|
70636
71118
|
let cases;
|
|
70637
71119
|
let model;
|
|
70638
71120
|
try {
|
|
70639
|
-
const raw = JSON.parse(await
|
|
71121
|
+
const raw = JSON.parse(await readFile82(path162.resolve(projectRoot, resultsPath), "utf8"));
|
|
70640
71122
|
cases = raw.cases ?? [];
|
|
70641
71123
|
model = raw.model;
|
|
70642
71124
|
} catch (error2) {
|
|
@@ -70698,12 +71180,12 @@ async function runGdgraphLayer(projectRoot, args2, ladder) {
|
|
|
70698
71180
|
}
|
|
70699
71181
|
const manifests = buildOracleManifestsByGold(inputs, { ladder });
|
|
70700
71182
|
if (outDir) {
|
|
70701
|
-
const resolvedOut =
|
|
71183
|
+
const resolvedOut = path162.resolve(projectRoot, outDir);
|
|
70702
71184
|
for (const input2 of inputs) {
|
|
70703
71185
|
for (const named of input2.golds) {
|
|
70704
71186
|
const bundle = buildEvidenceBundle({ target: input2.target, system: input2.system, gold: named.gold }, { ladder, goldReference: goldPathFor(named.kind), timestamp: new Date().toISOString() });
|
|
70705
|
-
const dir = await persistEvidenceBundle(
|
|
70706
|
-
console.error(`bundle[${named.kind}]: ${
|
|
71187
|
+
const dir = await persistEvidenceBundle(path162.join(resolvedOut, named.kind), bundle, ladder);
|
|
71188
|
+
console.error(`bundle[${named.kind}]: ${path162.relative(projectRoot, dir)}`);
|
|
70707
71189
|
}
|
|
70708
71190
|
}
|
|
70709
71191
|
}
|
|
@@ -70727,7 +71209,7 @@ async function runGdgraphLayer(projectRoot, args2, ladder) {
|
|
|
70727
71209
|
return allValid;
|
|
70728
71210
|
}
|
|
70729
71211
|
async function loadCoverageMap2(projectRoot, file) {
|
|
70730
|
-
const raw = JSON.parse(await
|
|
71212
|
+
const raw = JSON.parse(await readFile82(path162.resolve(projectRoot, file), "utf8"));
|
|
70731
71213
|
return raw.coverageMap ?? {};
|
|
70732
71214
|
}
|
|
70733
71215
|
async function runTestingLayer(projectRoot, args2, ladder) {
|
|
@@ -70764,7 +71246,7 @@ async function runTestingLayer(projectRoot, args2, ladder) {
|
|
|
70764
71246
|
return result.valid;
|
|
70765
71247
|
}
|
|
70766
71248
|
async function loadMemoryGoldK(projectRoot, file) {
|
|
70767
|
-
const raw = JSON.parse(await
|
|
71249
|
+
const raw = JSON.parse(await readFile82(path162.resolve(projectRoot, file), "utf8"));
|
|
70768
71250
|
return typeof raw.k === "number" && raw.k > 0 ? raw.k : 3;
|
|
70769
71251
|
}
|
|
70770
71252
|
async function runMemoryLayer(projectRoot, args2, ladder) {
|
|
@@ -70801,11 +71283,11 @@ async function runMemoryLayer(projectRoot, args2, ladder) {
|
|
|
70801
71283
|
return result.valid;
|
|
70802
71284
|
}
|
|
70803
71285
|
async function loadWikiGoldK(projectRoot, file) {
|
|
70804
|
-
const raw = JSON.parse(await
|
|
71286
|
+
const raw = JSON.parse(await readFile82(path162.resolve(projectRoot, file), "utf8"));
|
|
70805
71287
|
return typeof raw.k === "number" && raw.k > 0 ? raw.k : 5;
|
|
70806
71288
|
}
|
|
70807
71289
|
async function loadWikiGroundedness(projectRoot, file) {
|
|
70808
|
-
const raw = JSON.parse(await
|
|
71290
|
+
const raw = JSON.parse(await readFile82(path162.resolve(projectRoot, file), "utf8"));
|
|
70809
71291
|
const map = new Map;
|
|
70810
71292
|
for (const entry of raw.targets ?? []) {
|
|
70811
71293
|
if (typeof entry.target !== "string" || !Array.isArray(entry.scores) || entry.scores.length !== 3)
|
|
@@ -70861,7 +71343,7 @@ async function runWikiLayer(projectRoot, args2, ladder) {
|
|
|
70861
71343
|
return result.valid;
|
|
70862
71344
|
}
|
|
70863
71345
|
async function loadGdctxFacts(projectRoot, file) {
|
|
70864
|
-
const raw = JSON.parse(await
|
|
71346
|
+
const raw = JSON.parse(await readFile82(path162.resolve(projectRoot, file), "utf8"));
|
|
70865
71347
|
const inputs = [];
|
|
70866
71348
|
for (const entry of raw.inputs ?? []) {
|
|
70867
71349
|
if (typeof entry.input === "string") {
|
|
@@ -70899,7 +71381,7 @@ async function collect(projectRoot, args2) {
|
|
|
70899
71381
|
process.exitCode = 1;
|
|
70900
71382
|
return;
|
|
70901
71383
|
}
|
|
70902
|
-
const raw = JSON.parse(await
|
|
71384
|
+
const raw = JSON.parse(await readFile82(path162.resolve(projectRoot, eventFile), "utf8"));
|
|
70903
71385
|
const events2 = Array.isArray(raw) ? raw : raw.events;
|
|
70904
71386
|
const startedAt = optionValue(args2, "--started-at") ?? events2[0]?.timestamp_utc ?? new Date().toISOString();
|
|
70905
71387
|
const finishedAt = optionValue(args2, "--finished-at") ?? events2.at(-1)?.timestamp_utc ?? startedAt;
|
|
@@ -70915,11 +71397,11 @@ async function collect(projectRoot, args2) {
|
|
|
70915
71397
|
parentRunId: optionValue(args2, "--parent-run-id") ?? null
|
|
70916
71398
|
});
|
|
70917
71399
|
const result = await writeRunArtifacts(metricsRoot(projectRoot), record2, { cwd: projectRoot });
|
|
70918
|
-
console.log(`json: ${
|
|
70919
|
-
console.log(`markdown: ${
|
|
71400
|
+
console.log(`json: ${path162.relative(projectRoot, result.jsonPath)}`);
|
|
71401
|
+
console.log(`markdown: ${path162.relative(projectRoot, result.markdownPath)}`);
|
|
70920
71402
|
}
|
|
70921
71403
|
function metricsRoot(projectRoot) {
|
|
70922
|
-
return
|
|
71404
|
+
return path162.join(projectRoot, ".metaproject", "data", "metrics");
|
|
70923
71405
|
}
|
|
70924
71406
|
function printMetricsHelp() {
|
|
70925
71407
|
console.log(`keryx metrics
|