@mrciphersmith/keryx 0.2.52 → 0.2.53

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