@mrciphersmith/keryx 0.3.52 → 0.3.54

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/core.js CHANGED
@@ -7414,6 +7414,7 @@ async function worktreeFileIsClean(projectRoot, relativePath) {
7414
7414
  }
7415
7415
 
7416
7416
  // src/lib/git-worktrees.ts
7417
+ import { readdir as readdir8, readFile as readFile15, realpath as realpath7, stat as stat7 } from "fs/promises";
7417
7418
  import path32 from "path";
7418
7419
  async function resolveGitCommonDir(cwd) {
7419
7420
  try {
@@ -7422,7 +7423,12 @@ async function resolveGitCommonDir(cwd) {
7422
7423
  if (await proc.exited !== 0 || out.length === 0) {
7423
7424
  return;
7424
7425
  }
7425
- return path32.isAbsolute(out) ? out : path32.resolve(cwd, out);
7426
+ const absolute = path32.isAbsolute(out) ? out : path32.resolve(cwd, out);
7427
+ try {
7428
+ return path32.join(await realpath7(path32.dirname(absolute)), path32.basename(absolute));
7429
+ } catch {
7430
+ return absolute;
7431
+ }
7426
7432
  } catch {
7427
7433
  return;
7428
7434
  }
@@ -7605,7 +7611,7 @@ var init_entrypoint_targets = __esm(() => {
7605
7611
  });
7606
7612
 
7607
7613
  // src/rules/export-render.ts
7608
- import { readFile as readFile15, readdir as readdir8 } from "fs/promises";
7614
+ import { readFile as readFile16, readdir as readdir9 } from "fs/promises";
7609
7615
  import path33 from "path";
7610
7616
  function isUnsafeRulePath(relativePath) {
7611
7617
  return UNSAFE_RULE_PATH_PATTERN.test(relativePath) || relativePath.includes("<!--") || relativePath.includes("-->");
@@ -7670,7 +7676,7 @@ async function collectCanonicalRules(root) {
7670
7676
  async function walk(dirAbsolute, dirRelative) {
7671
7677
  let dirents;
7672
7678
  try {
7673
- dirents = await readdir8(dirAbsolute, { withFileTypes: true });
7679
+ dirents = await readdir9(dirAbsolute, { withFileTypes: true });
7674
7680
  } catch {
7675
7681
  return;
7676
7682
  }
@@ -7698,7 +7704,7 @@ async function collectCanonicalRules(root) {
7698
7704
  }
7699
7705
  let content;
7700
7706
  try {
7701
- content = await readFile15(childAbsolute, "utf8");
7707
+ content = await readFile16(childAbsolute, "utf8");
7702
7708
  } catch {
7703
7709
  continue;
7704
7710
  }
@@ -8384,7 +8390,7 @@ var init_surfaces = __esm(() => {
8384
8390
  });
8385
8391
 
8386
8392
  // src/integrations/markdown-block.ts
8387
- import { readFile as readFile16 } from "fs/promises";
8393
+ import { readFile as readFile17 } from "fs/promises";
8388
8394
  import path36 from "path";
8389
8395
  function dominantEol(content) {
8390
8396
  const crlf = (content.match(/\r\n/g) ?? []).length;
@@ -8538,7 +8544,7 @@ async function installMarkdownBlock(root, relativePath, frontMatter, spec = INST
8538
8544
  await writeContained(root, relativePath, `${frontMatter ?? ""}${spec.render()}`);
8539
8545
  return [];
8540
8546
  }
8541
- const raw = await readFile16(file, "utf8");
8547
+ const raw = await readFile17(file, "utf8");
8542
8548
  const eol = dominantEol(raw);
8543
8549
  let blocks;
8544
8550
  try {
@@ -8563,7 +8569,7 @@ async function uninstallMarkdownBlock(root, relativePath, frontMatter, spec = IN
8563
8569
  const file = fileFor(root, relativePath);
8564
8570
  if (!await pathExists(file))
8565
8571
  return false;
8566
- const raw = await readFile16(file, "utf8");
8572
+ const raw = await readFile17(file, "utf8");
8567
8573
  const blocks = parseBlocks(raw, relativePath, spec);
8568
8574
  if (blocks.length === 0)
8569
8575
  return false;
@@ -8585,7 +8591,7 @@ async function inspectMarkdownBlock(root, relativePath, spec = INSTRUCTIONS_BLOC
8585
8591
  const file = fileFor(root, relativePath);
8586
8592
  if (!await pathExists(file))
8587
8593
  return { state: "absent-file" };
8588
- const raw = await readFile16(file, "utf8");
8594
+ const raw = await readFile17(file, "utf8");
8589
8595
  let blocks;
8590
8596
  try {
8591
8597
  blocks = parseBlocks(raw, relativePath, spec);
@@ -9780,6 +9786,7 @@ function isModelTier(value) {
9780
9786
  var MODEL_TIERS, TIER_ALIASES, SKILL_TIER_KEY = "model_tier", TIER_DECLARATION;
9781
9787
  var init_model_tier = __esm(() => {
9782
9788
  init_model_version();
9789
+ init_skill_frontmatter();
9783
9790
  MODEL_TIERS = ["light", "standard", "deep"];
9784
9791
  TIER_ALIASES = new Map([["cheap", "light"]]);
9785
9792
  TIER_DECLARATION = new RegExp(`^\\s*(?:[-*]\\s*)?"?(?:${SKILL_TIER_KEY}|model-tier|modelTier)"?\\s*[:=]\\s*(.+?)\\s*,?\\s*$`, "i");
@@ -9789,7 +9796,7 @@ var init_model_tier = __esm(() => {
9789
9796
  var CEILINGS_BY_KEY, SKILL_LENGTH_CEILINGS;
9790
9797
  var init_skill_length_ceilings = __esm(() => {
9791
9798
  CEILINGS_BY_KEY = {
9792
- "core/reviewer-skill-creator": 280,
9799
+ "core/reviewer-skill-creator": 279,
9793
9800
  "orchestration/code-verifier": 339,
9794
9801
  "orchestration/context-collector": 671,
9795
9802
  "orchestration/feature-analyzer": 447,
@@ -11260,7 +11267,7 @@ var init_compile = __esm(() => {
11260
11267
  });
11261
11268
 
11262
11269
  // src/agents/export.ts
11263
- import { readFile as readFile17, readdir as readdir9, lstat as lstat6, realpath as realpath7 } from "fs/promises";
11270
+ import { readFile as readFile18, readdir as readdir10, lstat as lstat6, realpath as realpath8 } from "fs/promises";
11264
11271
  import path41 from "path";
11265
11272
  function matrixStateToExportLevel(state) {
11266
11273
  return state === "native" || state === "adapter" ? state : "instruction-only";
@@ -11275,7 +11282,7 @@ function proseExportRelativePath(runtime, name) {
11275
11282
  async function readExistingFileContent(projectRoot, relativePath) {
11276
11283
  const absolute = path41.join(projectRoot, ...relativePath.split("/"));
11277
11284
  try {
11278
- return await readFile17(absolute, "utf8");
11285
+ return await readFile18(absolute, "utf8");
11279
11286
  } catch (error) {
11280
11287
  if (isNotFound(error))
11281
11288
  return;
@@ -11307,7 +11314,7 @@ async function checkExportPathSafety(projectRoot, relativePath) {
11307
11314
  ancestor = parent;
11308
11315
  }
11309
11316
  try {
11310
- const [resolvedRoot, resolvedAncestor] = await Promise.all([realpath7(projectRoot), realpath7(ancestor)]);
11317
+ const [resolvedRoot, resolvedAncestor] = await Promise.all([realpath8(projectRoot), realpath8(ancestor)]);
11311
11318
  if (!isPathInside(resolvedRoot, resolvedAncestor)) {
11312
11319
  return `refusing to write ${relativePath} \u2014 its resolved directory is outside the project root`;
11313
11320
  }
@@ -11487,7 +11494,7 @@ async function scanManagedAgentExports(projectRoot, runtime) {
11487
11494
  return { verified: [], handEdited: [] };
11488
11495
  let entries;
11489
11496
  try {
11490
- entries = await readdir9(dirAbsolute, { withFileTypes: true });
11497
+ entries = await readdir10(dirAbsolute, { withFileTypes: true });
11491
11498
  } catch {
11492
11499
  return { verified: [], handEdited: [] };
11493
11500
  }
@@ -11508,7 +11515,7 @@ async function scanManagedAgentExports(projectRoot, runtime) {
11508
11515
  continue;
11509
11516
  let content;
11510
11517
  try {
11511
- content = await readFile17(absolute, "utf8");
11518
+ content = await readFile18(absolute, "utf8");
11512
11519
  } catch {
11513
11520
  continue;
11514
11521
  }
@@ -11681,7 +11688,7 @@ var init_surfaces_agents = __esm(() => {
11681
11688
  });
11682
11689
 
11683
11690
  // src/lib/git-local-ignore.ts
11684
- import { lstat as lstat7, mkdir as mkdir9, readFile as readFile18, realpath as realpath8, writeFile as writeFile6 } from "fs/promises";
11691
+ import { lstat as lstat7, mkdir as mkdir9, readFile as readFile19, realpath as realpath9, writeFile as writeFile6 } from "fs/promises";
11685
11692
  import path42 from "path";
11686
11693
  async function isPathIgnored(projectRoot, relativePath) {
11687
11694
  if (await resolveGitCommonDir(projectRoot) === undefined)
@@ -11768,7 +11775,7 @@ async function explainIgnoredPaths(projectRoot, relativePaths) {
11768
11775
  return [];
11769
11776
  const excludePath = path42.join(commonDir, "info", "exclude");
11770
11777
  const block = findManagedBlock(await readExcludeFile(excludePath).catch(() => ""), location.prefix);
11771
- const excludeReal = await realpath8(excludePath).catch(() => excludePath);
11778
+ const excludeReal = await realpath9(excludePath).catch(() => excludePath);
11772
11779
  let fields;
11773
11780
  try {
11774
11781
  const proc = Bun.spawn(["git", "check-ignore", "--verbose", "--non-matching", "--no-index", "-z", "--stdin"], {
@@ -11799,7 +11806,7 @@ async function explainIgnoredPaths(projectRoot, relativePaths) {
11799
11806
  let sourcePath = sourcePaths.get(source);
11800
11807
  if (sourcePath === undefined) {
11801
11808
  const resolved = path42.resolve(location.toplevel, source);
11802
- sourcePath = await realpath8(resolved).catch(() => resolved);
11809
+ sourcePath = await realpath9(resolved).catch(() => resolved);
11803
11810
  sourcePaths.set(source, sourcePath);
11804
11811
  }
11805
11812
  const ignored = !pattern.startsWith("!");
@@ -11848,7 +11855,7 @@ async function resolveWorktreeLocation(projectRoot) {
11848
11855
  }
11849
11856
  }
11850
11857
  async function readExcludeFile(excludePath) {
11851
- return readFile18(excludePath, "utf8").catch((error) => {
11858
+ return readFile19(excludePath, "utf8").catch((error) => {
11852
11859
  if (error.code === "ENOENT" || error.code === "ENOTDIR")
11853
11860
  return "";
11854
11861
  throw error;
@@ -11868,7 +11875,7 @@ function refuseUnsafeLines(lines) {
11868
11875
  return;
11869
11876
  }
11870
11877
  async function refuseUnsafeExcludePath(commonDir, infoDir, excludePath) {
11871
- const commonDirReal = await realpath8(commonDir).catch(() => commonDir);
11878
+ const commonDirReal = await realpath9(commonDir).catch(() => commonDir);
11872
11879
  for (const [target, label] of [
11873
11880
  [infoDir, "the git info directory"],
11874
11881
  [excludePath, "the git exclude file"]
@@ -11877,7 +11884,7 @@ async function refuseUnsafeExcludePath(commonDir, infoDir, excludePath) {
11877
11884
  if (stats === null)
11878
11885
  continue;
11879
11886
  if (stats.isSymbolicLink()) {
11880
- const real = await realpath8(target).catch(() => {
11887
+ const real = await realpath9(target).catch(() => {
11881
11888
  return;
11882
11889
  });
11883
11890
  if (real === undefined)
@@ -11904,7 +11911,7 @@ var init_git_local_ignore = __esm(() => {
11904
11911
  });
11905
11912
 
11906
11913
  // src/lib/metaproject-gitignore.ts
11907
- import { readFile as readFile19 } from "fs/promises";
11914
+ import { readFile as readFile20 } from "fs/promises";
11908
11915
  import path43 from "path";
11909
11916
  async function syncMetaprojectIgnoreRules(projectRoot, options = {}) {
11910
11917
  const notice = options.onNotice ?? (() => {});
@@ -11958,7 +11965,7 @@ async function moveBlockOutOfGitignore(projectRoot, notice) {
11958
11965
  const gitignorePath = path43.join(projectRoot, GITIGNORE);
11959
11966
  if (!await pathExists(gitignorePath))
11960
11967
  return false;
11961
- const content = await readFile19(gitignorePath, "utf8");
11968
+ const content = await readFile20(gitignorePath, "utf8");
11962
11969
  if (!managedBlockPattern().test(content))
11963
11970
  return false;
11964
11971
  const head = await readHeadBlob(projectRoot, GITIGNORE);
@@ -12261,7 +12268,7 @@ var init_rules_export_target = __esm(() => {
12261
12268
 
12262
12269
  // src/integrations/surfaces-rules.ts
12263
12270
  import { readFileSync as readFileSync7 } from "fs";
12264
- import { readFile as readFile20 } from "fs/promises";
12271
+ import { readFile as readFile21 } from "fs/promises";
12265
12272
  import path45 from "path";
12266
12273
  async function rulesSpec(root) {
12267
12274
  const { rules, skipped } = await collectCanonicalRules(root);
@@ -12389,7 +12396,7 @@ async function installIntoOverride(root, relativePath) {
12389
12396
  const refusal = await refuseEscapingSymlink(root, relativePath);
12390
12397
  if (refusal !== undefined)
12391
12398
  return { errors: [refusal], warnings };
12392
- const content = await readFile20(path45.join(root, ...relativePath.split("/")), "utf8");
12399
+ const content = await readFile21(path45.join(root, ...relativePath.split("/")), "utf8");
12393
12400
  let next;
12394
12401
  try {
12395
12402
  next = withOverrideRulesSlot(content, spec.render());
@@ -12447,7 +12454,7 @@ async function inspectOverrideSlot(root, relativePath) {
12447
12454
  }
12448
12455
  async function readTextIfPresent(root, relativePath) {
12449
12456
  try {
12450
- return await readFile20(path45.join(root, ...relativePath.split("/")), "utf8");
12457
+ return await readFile21(path45.join(root, ...relativePath.split("/")), "utf8");
12451
12458
  } catch (error) {
12452
12459
  if (error.code === "ENOENT")
12453
12460
  return;
@@ -13118,11 +13125,11 @@ var init_integrations = __esm(() => {
13118
13125
 
13119
13126
  // src/security/audit-harness/surfaces.ts
13120
13127
  import path47 from "path";
13121
- import { lstat as lstat8, readdir as readdir10, realpath as realpath9, stat as stat7 } from "fs/promises";
13128
+ import { lstat as lstat8, readdir as readdir11, realpath as realpath10, stat as stat8 } from "fs/promises";
13122
13129
  async function resolvesInsideRoot(root, absolute) {
13123
13130
  try {
13124
- const rootReal = await realpath9(root).catch(() => path47.resolve(root));
13125
- const real = await realpath9(absolute);
13131
+ const rootReal = await realpath10(root).catch(() => path47.resolve(root));
13132
+ const real = await realpath10(absolute);
13126
13133
  return isPathInside(rootReal, real);
13127
13134
  } catch {
13128
13135
  return false;
@@ -13160,7 +13167,7 @@ async function listFilesByExtensions(root, dirRelative, extensions) {
13160
13167
  }
13161
13168
  let entries;
13162
13169
  try {
13163
- entries = await readdir10(dirAbsolute, { withFileTypes: true });
13170
+ entries = await readdir11(dirAbsolute, { withFileTypes: true });
13164
13171
  } catch {
13165
13172
  return { found: [], unreadable: [toPosix(dirRelative)] };
13166
13173
  }
@@ -13222,7 +13229,7 @@ async function walkScripts(root, dirRelative, depth, visited, acc) {
13222
13229
  acc.unreadable.push(toPosix(dirRelative));
13223
13230
  return;
13224
13231
  }
13225
- const dirReal = await realpath9(dirAbsolute).catch(() => {
13232
+ const dirReal = await realpath10(dirAbsolute).catch(() => {
13226
13233
  return;
13227
13234
  });
13228
13235
  if (dirReal !== undefined) {
@@ -13232,7 +13239,7 @@ async function walkScripts(root, dirRelative, depth, visited, acc) {
13232
13239
  }
13233
13240
  let entries;
13234
13241
  try {
13235
- entries = await readdir10(dirAbsolute, { withFileTypes: true });
13242
+ entries = await readdir11(dirAbsolute, { withFileTypes: true });
13236
13243
  } catch {
13237
13244
  acc.unreadable.push(toPosix(dirRelative));
13238
13245
  return;
@@ -13253,7 +13260,7 @@ async function walkScripts(root, dirRelative, depth, visited, acc) {
13253
13260
  acc.unreadable.push(toPosix(childRelative));
13254
13261
  continue;
13255
13262
  }
13256
- const stats = await stat7(absolute).catch(() => {
13263
+ const stats = await stat8(absolute).catch(() => {
13257
13264
  return;
13258
13265
  });
13259
13266
  if (stats?.isDirectory()) {
@@ -14787,7 +14794,7 @@ var init_checks = __esm(() => {
14787
14794
 
14788
14795
  // src/security/audit-harness/baseline.ts
14789
14796
  import path48 from "path";
14790
- import { readFile as readFile21 } from "fs/promises";
14797
+ import { readFile as readFile22 } from "fs/promises";
14791
14798
  function defaultBaselinePath(root) {
14792
14799
  return path48.join(root, ".metaproject", "security-audit-baseline.json");
14793
14800
  }
@@ -14862,7 +14869,7 @@ function indefiniteSuppressionFindings(applicableEntries) {
14862
14869
  }
14863
14870
  async function readRawBaselineFindingIds(filePath) {
14864
14871
  try {
14865
- const text = await readFile21(filePath, "utf8");
14872
+ const text = await readFile22(filePath, "utf8");
14866
14873
  const parsed = JSON.parse(text);
14867
14874
  if (!parsed || typeof parsed !== "object" || !Array.isArray(parsed.entries)) {
14868
14875
  return [];
@@ -14887,7 +14894,7 @@ async function addBaselineEntry(root, entry, options = {}) {
14887
14894
  }
14888
14895
  const now = options.now ? options.now() : new Date;
14889
14896
  backupPath = `${filePath}.bak-${now.toISOString().replace(/[:.]/g, "-")}`;
14890
- const preResealBytes = await readFile21(filePath);
14897
+ const preResealBytes = await readFile22(filePath);
14891
14898
  await writeContained(root, path48.relative(root, backupPath), preResealBytes);
14892
14899
  entries = loaded.state.entries;
14893
14900
  const rawIds = await readRawBaselineFindingIds(filePath);
@@ -14994,12 +15001,12 @@ var init_types2 = __esm(() => {
14994
15001
 
14995
15002
  // src/security/audit-harness/proposals.ts
14996
15003
  import path49 from "path";
14997
- import { readFile as readFile22, realpath as realpath10 } from "fs/promises";
15004
+ import { readFile as readFile23, realpath as realpath11 } from "fs/promises";
14998
15005
  async function assertContained2(rootReal, absolute, label) {
14999
15006
  if (!isPathInside(rootReal, absolute)) {
15000
15007
  throw new Error(`Refusing to write ${label}: path escapes project root ${rootReal}.`);
15001
15008
  }
15002
- const real = await realpath10(absolute).catch(() => {
15009
+ const real = await realpath11(absolute).catch(() => {
15003
15010
  return;
15004
15011
  });
15005
15012
  if (real !== undefined) {
@@ -15010,7 +15017,7 @@ async function assertContained2(rootReal, absolute, label) {
15010
15017
  }
15011
15018
  let dir = path49.dirname(absolute);
15012
15019
  for (;; ) {
15013
- const dirReal = await realpath10(dir).catch(() => {
15020
+ const dirReal = await realpath11(dir).catch(() => {
15014
15021
  return;
15015
15022
  });
15016
15023
  if (dirReal !== undefined) {
@@ -15108,7 +15115,7 @@ function countOccurrences(haystack, needle) {
15108
15115
  async function applyTextEdit(rootReal, edit) {
15109
15116
  const absolute = path49.resolve(rootReal, edit.path);
15110
15117
  await assertContained2(rootReal, absolute, `target file "${edit.path}"`);
15111
- const content = await readFile22(absolute, "utf8");
15118
+ const content = await readFile23(absolute, "utf8");
15112
15119
  const occurrences = countOccurrences(content, edit.from);
15113
15120
  if (occurrences === 0) {
15114
15121
  throw new Error(`Cannot apply proposal: expected text not found in ${edit.path}.`);
@@ -15133,7 +15140,7 @@ async function applyAuditProposal(root, proposalId, options = {}) {
15133
15140
  if (!PROPOSAL_ID_RE.test(proposalId)) {
15134
15141
  throw new Error(`Invalid proposal id: ${proposalId}`);
15135
15142
  }
15136
- const rootReal = await realpath10(root).catch(() => {
15143
+ const rootReal = await realpath11(root).catch(() => {
15137
15144
  return;
15138
15145
  }) ?? path49.resolve(root);
15139
15146
  return withFileLock(lockPath2(rootReal), async () => {
@@ -15189,7 +15196,7 @@ var init_proposals = __esm(() => {
15189
15196
  // src/security/audit-harness/index.ts
15190
15197
  import { createHash as createHash7 } from "crypto";
15191
15198
  import path50 from "path";
15192
- import { readFile as readFile23 } from "fs/promises";
15199
+ import { readFile as readFile24 } from "fs/promises";
15193
15200
  function findingId(f) {
15194
15201
  const pointerOrLine = f.location?.pointer ?? (f.location?.line !== undefined ? `line:${f.location.line}` : "");
15195
15202
  const policyId = f.evidence.policyId ?? "";
@@ -15214,14 +15221,14 @@ function compareFindings(a, b) {
15214
15221
  }
15215
15222
  async function safeReadText(absolute) {
15216
15223
  try {
15217
- return await readFile23(absolute, "utf8");
15224
+ return await readFile24(absolute, "utf8");
15218
15225
  } catch {
15219
15226
  return;
15220
15227
  }
15221
15228
  }
15222
15229
  async function safeReadBuffer(absolute) {
15223
15230
  try {
15224
- return await readFile23(absolute);
15231
+ return await readFile24(absolute);
15225
15232
  } catch {
15226
15233
  return;
15227
15234
  }
@@ -15819,7 +15826,7 @@ __export(exports_service, {
15819
15826
  verifyConfigChecksum: () => verifyConfigChecksum
15820
15827
  });
15821
15828
  import path51 from "path";
15822
- import { readFile as readFile24 } from "fs/promises";
15829
+ import { readFile as readFile25 } from "fs/promises";
15823
15830
  import { randomBytes as randomBytes4 } from "crypto";
15824
15831
  function validateSerializedOutput(content, exemptExfil) {
15825
15832
  return validateSerializedContentForTransport(content, exemptExfil);
@@ -15952,7 +15959,7 @@ async function readLatestReport(cwd) {
15952
15959
  }
15953
15960
  let parsed;
15954
15961
  try {
15955
- parsed = JSON.parse(await readFile24(file, "utf8"));
15962
+ parsed = JSON.parse(await readFile25(file, "utf8"));
15956
15963
  } catch {
15957
15964
  return { kind: "unusable" };
15958
15965
  }
@@ -16072,9 +16079,9 @@ var init_service2 = __esm(() => {
16072
16079
  });
16073
16080
 
16074
16081
  // src/gdgraph/config.ts
16075
- import path56 from "path";
16082
+ import path57 from "path";
16076
16083
  function gdgraphConfigPath(cwd) {
16077
- return path56.join(cwd, ".metaproject", "gdgraph.config.json");
16084
+ return path57.join(cwd, ".metaproject", "gdgraph.config.json");
16078
16085
  }
16079
16086
  function mergeGdgraphConfig(parsed) {
16080
16087
  const base = DEFAULT_GDGRAPH_CONFIG;
@@ -16679,7 +16686,7 @@ var init_extract = __esm(() => {
16679
16686
  });
16680
16687
 
16681
16688
  // src/gdgraph/treesitter/grammars.ts
16682
- import path57 from "path";
16689
+ import path58 from "path";
16683
16690
  function grammarAssetId(language) {
16684
16691
  return `tree-sitter-${language}`;
16685
16692
  }
@@ -16695,7 +16702,7 @@ function symbolLanguage(language) {
16695
16702
  async function resolveGrammar(cwd, language, grammarsPath) {
16696
16703
  const id = grammarAssetId(language);
16697
16704
  const lock = await loadAssetsLock(cwd);
16698
- const overrides = grammarsPath ? { [id]: { path: path57.join(grammarsPath, `${id}.wasm`) } } : undefined;
16705
+ const overrides = grammarsPath ? { [id]: { path: path58.join(grammarsPath, `${id}.wasm`) } } : undefined;
16699
16706
  const registry = registryFromLock(lock, overrides);
16700
16707
  const resolved = await resolveAsset(registry, id);
16701
16708
  if (!resolved) {
@@ -16725,7 +16732,7 @@ function toGrammarLanguages(languages) {
16725
16732
  return out;
16726
16733
  }
16727
16734
  function grammarForFile(file, available) {
16728
- const ext = path57.extname(file);
16735
+ const ext = path58.extname(file);
16729
16736
  const preference = ext === ".tsx" ? ["tsx", "typescript"] : ext === ".ts" ? ["typescript"] : ext === ".jsx" || ext === ".js" || ext === ".mjs" || ext === ".cjs" ? ["javascript"] : ext === ".java" ? ["java"] : ext === ".py" ? ["python"] : [];
16730
16737
  for (const language of preference) {
16731
16738
  if (available.includes(language)) {
@@ -16987,7 +16994,7 @@ var init_adapter = __esm(() => {
16987
16994
 
16988
16995
  // src/gdgraph/enrich.ts
16989
16996
  import { mkdir as mkdir13, writeFile as writeFile7 } from "fs/promises";
16990
- import path58 from "path";
16997
+ import path59 from "path";
16991
16998
  async function enrichBuildWithSymbols(cwd, files, resolve) {
16992
16999
  const config = await loadGdgraphConfig(cwd);
16993
17000
  const treesitterConfig = {
@@ -17003,12 +17010,12 @@ async function enrichBuildWithSymbols(cwd, files, resolve) {
17003
17010
  return { enriched: true, symbols: layer.symbols.length, calls: layer.calls.length };
17004
17011
  }
17005
17012
  async function writeSymbolLayer(cwd, layer) {
17006
- const storageDir = path58.join(cwd, ".metaproject", "data", "gdgraph", "storage");
17013
+ const storageDir = path59.join(cwd, ".metaproject", "data", "gdgraph", "storage");
17007
17014
  await mkdir13(storageDir, { recursive: true });
17008
- await writeFile7(path58.join(storageDir, "symbols.jsonl"), layer.symbols.map((symbol) => JSON.stringify(symbol)).join(`
17015
+ await writeFile7(path59.join(storageDir, "symbols.jsonl"), layer.symbols.map((symbol) => JSON.stringify(symbol)).join(`
17009
17016
  `) + `
17010
17017
  `, "utf8");
17011
- await writeFile7(path58.join(storageDir, "calls.jsonl"), layer.calls.map((call) => JSON.stringify(call)).join(`
17018
+ await writeFile7(path59.join(storageDir, "calls.jsonl"), layer.calls.map((call) => JSON.stringify(call)).join(`
17012
17019
  `) + `
17013
17020
  `, "utf8");
17014
17021
  }
@@ -17200,11 +17207,11 @@ var NOT_CODE_SCOPED = "none";
17200
17207
  var init_describes = () => {};
17201
17208
 
17202
17209
  // src/sync/provenance.ts
17203
- import { mkdir as mkdir14, readFile as readFile28, writeFile as writeFile8 } from "fs/promises";
17204
- import path59 from "path";
17210
+ import { mkdir as mkdir14, readFile as readFile29, writeFile as writeFile8 } from "fs/promises";
17211
+ import path60 from "path";
17205
17212
  import { spawn } from "child_process";
17206
17213
  function provenancePath(cwd, module) {
17207
- return path59.join(cwd, ".metaproject", "data", module, ".provenance.json");
17214
+ return path60.join(cwd, ".metaproject", "data", module, ".provenance.json");
17208
17215
  }
17209
17216
  function gitCmdResult(cwd, args) {
17210
17217
  return new Promise((resolve) => {
@@ -17249,7 +17256,7 @@ async function recordProvenance(cwd, module, at) {
17249
17256
  if (!head)
17250
17257
  return;
17251
17258
  const file = provenancePath(cwd, module);
17252
- await mkdir14(path59.dirname(file), { recursive: true });
17259
+ await mkdir14(path60.dirname(file), { recursive: true });
17253
17260
  const provenance = { commit: head.commit, branch: head.branch, builtAt: at };
17254
17261
  await writeFile8(file, `${JSON.stringify(provenance, null, 2)}
17255
17262
  `, "utf8");
@@ -17260,7 +17267,7 @@ async function readProvenance(cwd, module) {
17260
17267
  return null;
17261
17268
  }
17262
17269
  try {
17263
- const parsed = JSON.parse(await readFile28(file, "utf8"));
17270
+ const parsed = JSON.parse(await readFile29(file, "utf8"));
17264
17271
  if (parsed && typeof parsed === "object" && typeof parsed.commit === "string") {
17265
17272
  return parsed;
17266
17273
  }
@@ -17273,8 +17280,8 @@ var init_provenance = __esm(() => {
17273
17280
 
17274
17281
  // src/gdgraph/staleness.ts
17275
17282
  import { spawn as spawn2 } from "child_process";
17276
- import { stat as stat8 } from "fs/promises";
17277
- import path60 from "path";
17283
+ import { stat as stat9 } from "fs/promises";
17284
+ import path61 from "path";
17278
17285
  function gitStatusPorcelain(cwd) {
17279
17286
  return new Promise((resolve) => {
17280
17287
  try {
@@ -17297,10 +17304,10 @@ function gitStatusPorcelain(cwd) {
17297
17304
  });
17298
17305
  }
17299
17306
  function nodesJsonlPath(cwd) {
17300
- return path60.join(cwd, ".metaproject", "data", "gdgraph", "storage", "nodes.jsonl");
17307
+ return path61.join(cwd, ".metaproject", "data", "gdgraph", "storage", "nodes.jsonl");
17301
17308
  }
17302
17309
  function gdgraphConfigPath2(cwd) {
17303
- return path60.join(cwd, ".metaproject", "gdgraph.config.json");
17310
+ return path61.join(cwd, ".metaproject", "gdgraph.config.json");
17304
17311
  }
17305
17312
  function categorizeStatusEntries(entries, rootPrefix) {
17306
17313
  const metaprojectPrefix = `${rootPrefix}.metaproject/`;
@@ -17360,7 +17367,7 @@ async function committedChangedFiles(cwd, fromCommit, toCommit, rootPrefix) {
17360
17367
  return diff.split("\x00").filter((entry) => entry.length > 0 && !entry.startsWith(metaprojectPrefix));
17361
17368
  }
17362
17369
  async function checkGraphStaleness(cwd) {
17363
- const nodesStat = await stat8(nodesJsonlPath(cwd)).catch(() => null);
17370
+ const nodesStat = await stat9(nodesJsonlPath(cwd)).catch(() => null);
17364
17371
  if (!nodesStat) {
17365
17372
  return { status: "stale", reasons: ["graph has not been built yet (no nodes.jsonl)"] };
17366
17373
  }
@@ -17381,7 +17388,7 @@ async function checkGraphStaleness(cwd) {
17381
17388
  }
17382
17389
  } else {
17383
17390
  provenanceMissing = true;
17384
- const logsHeadStat = await stat8(path60.join(cwd, ".git", "logs", "HEAD")).catch(() => null);
17391
+ const logsHeadStat = await stat9(path61.join(cwd, ".git", "logs", "HEAD")).catch(() => null);
17385
17392
  if (logsHeadStat && logsHeadStat.mtimeMs > nodesStat.mtimeMs) {
17386
17393
  reasons.push("repo HEAD moved since the graph was built (no build provenance recorded; inferred from .git/logs/HEAD)");
17387
17394
  }
@@ -17410,7 +17417,7 @@ async function checkGraphStaleness(cwd) {
17410
17417
  if (projectRelative === null) {
17411
17418
  continue;
17412
17419
  }
17413
- const fileStat = await stat8(path60.join(cwd, projectRelative)).catch(() => null);
17420
+ const fileStat = await stat9(path61.join(cwd, projectRelative)).catch(() => null);
17414
17421
  if (fileStat && fileStat.mtimeMs > nodesStat.mtimeMs) {
17415
17422
  postBuildEdits.push(displayPath);
17416
17423
  }
@@ -17420,7 +17427,7 @@ async function checkGraphStaleness(cwd) {
17420
17427
  }
17421
17428
  }
17422
17429
  }
17423
- const configStat = await stat8(gdgraphConfigPath2(cwd)).catch(() => null);
17430
+ const configStat = await stat9(gdgraphConfigPath2(cwd)).catch(() => null);
17424
17431
  if (configStat && configStat.mtimeMs > nodesStat.mtimeMs) {
17425
17432
  reasons.push("gdgraph.config.json changed since the graph was built");
17426
17433
  }
@@ -17545,19 +17552,19 @@ var init_types3 = __esm(() => {
17545
17552
  });
17546
17553
 
17547
17554
  // src/wiki/collect.ts
17548
- import { readFile as readFile29, readdir as readdir11 } from "fs/promises";
17549
- import path61 from "path";
17555
+ import { readFile as readFile30, readdir as readdir12 } from "fs/promises";
17556
+ import path62 from "path";
17550
17557
  function wikiRootPath(cwd) {
17551
- return path61.join(cwd, ".metaproject", "wiki");
17558
+ return path62.join(cwd, ".metaproject", "wiki");
17552
17559
  }
17553
17560
  async function collectPages(cwd) {
17554
17561
  const root = wikiRootPath(cwd);
17555
17562
  const pages = [];
17556
17563
  for (const { type, folder } of WIKI_PAGE_TYPES) {
17557
- const dir = path61.join(root, folder);
17564
+ const dir = path62.join(root, folder);
17558
17565
  let names;
17559
17566
  try {
17560
- names = await readdir11(dir);
17567
+ names = await readdir12(dir);
17561
17568
  } catch (error) {
17562
17569
  if (isNotFound(error)) {
17563
17570
  continue;
@@ -17569,10 +17576,10 @@ async function collectPages(cwd) {
17569
17576
  if (!entry.endsWith(".md")) {
17570
17577
  continue;
17571
17578
  }
17572
- const absolutePath = path61.join(dir, entry);
17579
+ const absolutePath = path62.join(dir, entry);
17573
17580
  let content;
17574
17581
  try {
17575
- content = await readFile29(absolutePath, "utf8");
17582
+ content = await readFile30(absolutePath, "utf8");
17576
17583
  } catch (error) {
17577
17584
  const message = error instanceof Error ? error.message : String(error);
17578
17585
  throw new WikiCollectionError(absolutePath, `the wiki store could not be read (${message}). This is not the same as "no pages": ` + `${absolutePath} exists but could not be read.`);
@@ -18379,7 +18386,7 @@ var init_section_index = __esm(() => {
18379
18386
  });
18380
18387
 
18381
18388
  // src/security/guard.ts
18382
- import path62 from "path";
18389
+ import path63 from "path";
18383
18390
  function prepareOutputForPersistence(guard, original) {
18384
18391
  if (!guard.allowed) {
18385
18392
  return { allowed: false, reason: guard.reason ?? "security gate blocked" };
@@ -18397,7 +18404,7 @@ function prepareOutputForPersistence(guard, original) {
18397
18404
  };
18398
18405
  }
18399
18406
  async function resolveManifestSecurityState(cwd) {
18400
- const manifestPath = path62.join(securityProjectRoot(cwd), ".metaproject", "metaproject.json");
18407
+ const manifestPath = path63.join(securityProjectRoot(cwd), ".metaproject", "metaproject.json");
18401
18408
  if (!await pathExists(manifestPath)) {
18402
18409
  return { enabled: false, manifestUnreadable: false };
18403
18410
  }
@@ -18603,10 +18610,10 @@ var MEMORY_EMBEDDING_ID = "memory.embedding", DEFAULT_EMBED_DIMS = 96;
18603
18610
 
18604
18611
  // src/memory/embedding/index.ts
18605
18612
  import { createHash as createHash10 } from "crypto";
18606
- import { mkdir as mkdir15, readFile as readFile30, writeFile as writeFile9 } from "fs/promises";
18607
- import path63 from "path";
18613
+ import { mkdir as mkdir15, readFile as readFile31, writeFile as writeFile9 } from "fs/promises";
18614
+ import path64 from "path";
18608
18615
  function embeddingsDir(cwd) {
18609
- return path63.join(cwd, ".metaproject", "data", "memory", "embeddings");
18616
+ return path64.join(cwd, ".metaproject", "data", "memory", "embeddings");
18610
18617
  }
18611
18618
  function entryText(entry) {
18612
18619
  return `${entry.title}
@@ -18635,24 +18642,24 @@ async function buildEmbeddingIndex(cwd, entries, embedder, model, now) {
18635
18642
  };
18636
18643
  const dir = embeddingsDir(cwd);
18637
18644
  await mkdir15(dir, { recursive: true });
18638
- await writeFile9(path63.join(dir, "index.meta.json"), `${JSON.stringify(meta, null, 2)}
18645
+ await writeFile9(path64.join(dir, "index.meta.json"), `${JSON.stringify(meta, null, 2)}
18639
18646
  `, "utf8");
18640
- await writeFile9(path63.join(dir, "vectors.jsonl"), records.map((record) => JSON.stringify(record)).join(`
18647
+ await writeFile9(path64.join(dir, "vectors.jsonl"), records.map((record) => JSON.stringify(record)).join(`
18641
18648
  `) + (records.length > 0 ? `
18642
18649
  ` : ""), "utf8");
18643
18650
  return toIndex(meta, records);
18644
18651
  }
18645
18652
  async function loadEmbeddingIndex(cwd) {
18646
18653
  const dir = embeddingsDir(cwd);
18647
- const metaPath = path63.join(dir, "index.meta.json");
18648
- const vectorsPath = path63.join(dir, "vectors.jsonl");
18654
+ const metaPath = path64.join(dir, "index.meta.json");
18655
+ const vectorsPath = path64.join(dir, "vectors.jsonl");
18649
18656
  if (!await pathExists(metaPath) || !await pathExists(vectorsPath)) {
18650
18657
  return null;
18651
18658
  }
18652
18659
  try {
18653
- const meta = JSON.parse(await readFile30(metaPath, "utf8"));
18660
+ const meta = JSON.parse(await readFile31(metaPath, "utf8"));
18654
18661
  const records = [];
18655
- for (const line of (await readFile30(vectorsPath, "utf8")).split(`
18662
+ for (const line of (await readFile31(vectorsPath, "utf8")).split(`
18656
18663
  `)) {
18657
18664
  if (line.trim().length === 0) {
18658
18665
  continue;
@@ -18726,10 +18733,10 @@ var init_embedding = __esm(() => {
18726
18733
  });
18727
18734
 
18728
18735
  // src/wiki/section-tombstone.ts
18729
- import path64 from "path";
18730
- import { stat as stat9 } from "fs/promises";
18736
+ import path65 from "path";
18737
+ import { stat as stat10 } from "fs/promises";
18731
18738
  function sectionRegistryPath(cwd) {
18732
- return path64.join(cwd, ".metaproject", "wiki", ".sections.json");
18739
+ return path65.join(cwd, ".metaproject", "wiki", ".sections.json");
18733
18740
  }
18734
18741
  function emptySectionRegistry() {
18735
18742
  return { version: SECTION_REGISTRY_VERSION, entries: [], tombstones: [], lifted: [] };
@@ -18810,7 +18817,7 @@ function parseLifted(value) {
18810
18817
  async function readSectionRegistryState(cwd) {
18811
18818
  const file = sectionRegistryPath(cwd);
18812
18819
  try {
18813
- await stat9(file);
18820
+ await stat10(file);
18814
18821
  } catch (error) {
18815
18822
  if (isNotFound(error)) {
18816
18823
  return { state: "absent", path: file };
@@ -19030,11 +19037,11 @@ var init_section_tombstone = __esm(() => {
19030
19037
  });
19031
19038
 
19032
19039
  // src/memory/cross-layer.ts
19033
- import { readFile as readFile31 } from "fs/promises";
19034
- import path65 from "path";
19040
+ import { readFile as readFile32 } from "fs/promises";
19041
+ import path66 from "path";
19035
19042
  function extractWikiReferences(entryRelativePath, entryAbsolutePath, content, wikiRoot) {
19036
19043
  const references = [];
19037
- const entryDir = path65.dirname(entryAbsolutePath);
19044
+ const entryDir = path66.dirname(entryAbsolutePath);
19038
19045
  const lines = content.split(`
19039
19046
  `);
19040
19047
  for (let index = 0;index < lines.length; index += 1) {
@@ -19049,16 +19056,16 @@ function extractWikiReferences(entryRelativePath, entryAbsolutePath, content, wi
19049
19056
  if (withoutAnchor.length === 0) {
19050
19057
  continue;
19051
19058
  }
19052
- const absolute = path65.resolve(entryDir, withoutAnchor);
19053
- const relativeToWiki = path65.relative(wikiRoot, absolute);
19054
- if (relativeToWiki.startsWith("..") || path65.isAbsolute(relativeToWiki)) {
19059
+ const absolute = path66.resolve(entryDir, withoutAnchor);
19060
+ const relativeToWiki = path66.relative(wikiRoot, absolute);
19061
+ if (relativeToWiki.startsWith("..") || path66.isAbsolute(relativeToWiki)) {
19055
19062
  continue;
19056
19063
  }
19057
19064
  references.push({
19058
19065
  entry: entryRelativePath,
19059
19066
  kind: "page-path",
19060
19067
  raw: href,
19061
- target: relativeToWiki.split(path65.sep).join("/"),
19068
+ target: relativeToWiki.split(path66.sep).join("/"),
19062
19069
  line
19063
19070
  });
19064
19071
  }
@@ -19078,11 +19085,11 @@ function isDangling(finding) {
19078
19085
  return finding.state !== "intact";
19079
19086
  }
19080
19087
  async function loadWikiKnowledgeView(cwd) {
19081
- const wikiRoot = path65.join(cwd, ".metaproject", "wiki");
19088
+ const wikiRoot = path66.join(cwd, ".metaproject", "wiki");
19082
19089
  const pages = await collectPages(cwd);
19083
19090
  const index = buildSectionIndex(await Promise.all(pages.map(async (page) => ({
19084
19091
  page,
19085
- content: await readFile31(page.absolutePath, "utf8").catch(() => "")
19092
+ content: await readFile32(page.absolutePath, "utf8").catch(() => "")
19086
19093
  }))));
19087
19094
  return {
19088
19095
  index,
@@ -19195,7 +19202,7 @@ async function checkMemoryCrossLayer(cwd, entries, view) {
19195
19202
  const resolved = view ?? await loadWikiKnowledgeView(cwd);
19196
19203
  const findings = [];
19197
19204
  for (const entry of entries) {
19198
- const content = await readFile31(entry.absolutePath, "utf8").catch(() => null);
19205
+ const content = await readFile32(entry.absolutePath, "utf8").catch(() => null);
19199
19206
  if (content === null) {
19200
19207
  findings.push({
19201
19208
  reference: {
@@ -19296,7 +19303,7 @@ function round2(value) {
19296
19303
  var init_dedup = () => {};
19297
19304
 
19298
19305
  // src/memory/check.ts
19299
- import path66 from "path";
19306
+ import path67 from "path";
19300
19307
  async function checkMemory(cwd, config) {
19301
19308
  const entries = await collectEntries(cwd);
19302
19309
  const issues = [];
@@ -19312,7 +19319,7 @@ async function checkMemory(cwd, config) {
19312
19319
  }
19313
19320
  for (const file of entry.scopes.files) {
19314
19321
  const clean = file.replace(/^`|`$/g, "");
19315
- if (!await pathExists(path66.resolve(cwd, clean))) {
19322
+ if (!await pathExists(path67.resolve(cwd, clean))) {
19316
19323
  issues.push({ path: entry.relativePath, kind: "link", message: `related file not found: ${clean}` });
19317
19324
  }
19318
19325
  }
@@ -19366,13 +19373,13 @@ var init_check = __esm(() => {
19366
19373
  });
19367
19374
 
19368
19375
  // src/memory/write.ts
19369
- import { mkdir as mkdir16, open as open2, readFile as readFile32, rename as rename5, rm as rm4, writeFile as writeFile10 } from "fs/promises";
19370
- import path67 from "path";
19376
+ import { mkdir as mkdir16, open as open2, readFile as readFile33, rename as rename5, rm as rm4, writeFile as writeFile10 } from "fs/promises";
19377
+ import path68 from "path";
19371
19378
  async function resolveCanonicalEntryPath(cwd, relativePath) {
19372
- const root = path67.resolve(memoryRoot(cwd));
19373
- const absolutePath = path67.resolve(root, relativePath);
19374
- const normalized = toPosix2(path67.relative(root, absolutePath));
19375
- if (!normalized || normalized.startsWith("../") || path67.isAbsolute(normalized) || !normalized.endsWith(".md")) {
19379
+ const root = path68.resolve(memoryRoot(cwd));
19380
+ const absolutePath = path68.resolve(root, relativePath);
19381
+ const normalized = toPosix2(path68.relative(root, absolutePath));
19382
+ if (!normalized || normalized.startsWith("../") || path68.isAbsolute(normalized) || !normalized.endsWith(".md")) {
19376
19383
  return null;
19377
19384
  }
19378
19385
  return { absolutePath, relativePath: normalized };
@@ -19407,7 +19414,7 @@ async function writeCanonicalPair(input) {
19407
19414
  return asPair(secondGuard.result, [first.value.relativePath]);
19408
19415
  const prepared = [firstGuard.value, secondGuard.value];
19409
19416
  const warnings = prepared.flatMap((entry) => entry.warnings);
19410
- const [originalFirst, originalSecond] = await Promise.all(prepared.map((entry) => readFile32(entry.absolutePath, "utf8")));
19417
+ const [originalFirst, originalSecond] = await Promise.all(prepared.map((entry) => readFile33(entry.absolutePath, "utf8")));
19411
19418
  try {
19412
19419
  await replaceAtomically(prepared[0].absolutePath, prepared[0].content);
19413
19420
  if (input.failReplaceAt === 2)
@@ -19468,9 +19475,9 @@ function validateNextEntry(relativePath, content) {
19468
19475
  return null;
19469
19476
  }
19470
19477
  async function replaceAtomically(target, content) {
19471
- const dir = path67.dirname(target);
19478
+ const dir = path68.dirname(target);
19472
19479
  await mkdir16(dir, { recursive: true });
19473
- const tmp = path67.join(dir, `.${path67.basename(target)}.keryx-tmp-${process.pid}-${Math.random().toString(16).slice(2)}`);
19480
+ const tmp = path68.join(dir, `.${path68.basename(target)}.keryx-tmp-${process.pid}-${Math.random().toString(16).slice(2)}`);
19474
19481
  try {
19475
19482
  await writeFile10(tmp, content, "utf8");
19476
19483
  const file = await open2(tmp, "r");
@@ -19506,7 +19513,7 @@ function header(content, name) {
19506
19513
  return content.match(new RegExp(`^${name}:\\s*(.+)$`, "mi"))?.[1]?.trim() ?? null;
19507
19514
  }
19508
19515
  function toPosix2(value) {
19509
- return value.split(path67.sep).join("/");
19516
+ return value.split(path68.sep).join("/");
19510
19517
  }
19511
19518
  function message(cause) {
19512
19519
  return cause instanceof Error ? cause.message : String(cause);
@@ -19519,14 +19526,14 @@ var init_write = __esm(() => {
19519
19526
 
19520
19527
  // src/memory/ingest.ts
19521
19528
  import { existsSync as existsSync6 } from "fs";
19522
- import { readFile as readFile33 } from "fs/promises";
19523
- import path68 from "path";
19529
+ import { readFile as readFile34 } from "fs/promises";
19530
+ import path69 from "path";
19524
19531
  async function ingestMemory(cwd, source, filePath, config, now) {
19525
- const absolute = path68.resolve(cwd, filePath);
19532
+ const absolute = path69.resolve(cwd, filePath);
19526
19533
  if (!await pathExists(absolute)) {
19527
19534
  throw new Error(`Ingest source not found: ${filePath}`);
19528
19535
  }
19529
- const content = await readFile33(absolute, "utf8");
19536
+ const content = await readFile34(absolute, "utf8");
19530
19537
  const candidates = extractCandidates2(content);
19531
19538
  const type = SOURCE_TYPE[source] ?? "lesson";
19532
19539
  const confidence = SOURCE_CONFIDENCE[source] ?? "low";
@@ -19539,8 +19546,8 @@ async function ingestMemory(cwd, source, filePath, config, now) {
19539
19546
  const securityWarnings = [];
19540
19547
  const securitySkipped = [];
19541
19548
  let skippedDuplicates = 0;
19542
- const dir = path68.join(memoryRoot(cwd), folder);
19543
- const link = path68.relative(cwd, absolute);
19549
+ const dir = path69.join(memoryRoot(cwd), folder);
19550
+ const link = path69.relative(cwd, absolute);
19544
19551
  const date = dateString(now);
19545
19552
  for (const text of candidates) {
19546
19553
  const title = toTitle(text);
@@ -19606,7 +19613,7 @@ async function ingestMemory(cwd, source, filePath, config, now) {
19606
19613
  return result;
19607
19614
  }
19608
19615
  async function reconcileEntry(cwd, relativePath, absolutePath, source, link, date) {
19609
- const content = await readFile33(absolutePath, "utf8");
19616
+ const content = await readFile34(absolutePath, "utf8");
19610
19617
  const note = `- Reconciled: ${source} ${date}${link ? ` (${link})` : ""}`;
19611
19618
  if (content.includes(note)) {
19612
19619
  return { changed: false };
@@ -19721,7 +19728,7 @@ function uniqueSlug(dir, title) {
19721
19728
  const base = slugify2(title) || "entry";
19722
19729
  let slug = base;
19723
19730
  let counter = 2;
19724
- while (existsSync6(path68.join(dir, `${slug}.md`))) {
19731
+ while (existsSync6(path69.join(dir, `${slug}.md`))) {
19725
19732
  slug = `${base}-${counter}`;
19726
19733
  counter += 1;
19727
19734
  }
@@ -19755,8 +19762,8 @@ var init_ingest = __esm(() => {
19755
19762
  });
19756
19763
 
19757
19764
  // src/memory/supersede.ts
19758
- import { readFile as readFile34 } from "fs/promises";
19759
- import path69 from "path";
19765
+ import { readFile as readFile35 } from "fs/promises";
19766
+ import path70 from "path";
19760
19767
  async function supersedeEntry(input, now) {
19761
19768
  const date = input.date ?? now.toISOString().slice(0, 10);
19762
19769
  const today = now.toISOString().slice(0, 10);
@@ -19768,8 +19775,8 @@ async function supersedeEntry(input, now) {
19768
19775
  if (!newResolved) {
19769
19776
  throw new Error(`Superseding entry not found: ${input.newPath}`);
19770
19777
  }
19771
- const oldContent = await readFile34(oldResolved.absolute, "utf8");
19772
- const newContent = await readFile34(newResolved.absolute, "utf8");
19778
+ const oldContent = await readFile35(oldResolved.absolute, "utf8");
19779
+ const newContent = await readFile35(newResolved.absolute, "utf8");
19773
19780
  if (headerValue(oldContent, "Superseded-By") === newResolved.relative && headerValue(newContent, "Supersedes") === oldResolved.relative) {
19774
19781
  return {
19775
19782
  superseded: oldResolved.relative,
@@ -19816,12 +19823,12 @@ async function supersedeEntry(input, now) {
19816
19823
  async function resolveEntryPath(cwd, raw) {
19817
19824
  const root = memoryRoot(cwd);
19818
19825
  const candidates = [
19819
- path69.resolve(cwd, raw),
19820
- path69.resolve(root, raw),
19821
- path69.isAbsolute(raw) ? raw : path69.join(cwd, raw)
19826
+ path70.resolve(cwd, raw),
19827
+ path70.resolve(root, raw),
19828
+ path70.isAbsolute(raw) ? raw : path70.join(cwd, raw)
19822
19829
  ];
19823
19830
  for (const absolute of candidates) {
19824
- const confined = await resolveCanonicalEntryPath(cwd, path69.relative(root, absolute));
19831
+ const confined = await resolveCanonicalEntryPath(cwd, path70.relative(root, absolute));
19825
19832
  if (confined && await pathExists(confined.absolutePath)) {
19826
19833
  return { absolute: confined.absolutePath, relative: confined.relativePath };
19827
19834
  }
@@ -20016,10 +20023,10 @@ __export(exports_service3, {
20016
20023
  selectHandoffEntries: () => selectHandoffEntries
20017
20024
  });
20018
20025
  import { createHash as createHash11 } from "crypto";
20019
- import { mkdir as mkdir17, readFile as readFile35, writeFile as writeFile11 } from "fs/promises";
20020
- import path70 from "path";
20026
+ import { mkdir as mkdir17, readFile as readFile36, writeFile as writeFile11 } from "fs/promises";
20027
+ import path71 from "path";
20021
20028
  function dataRoot2(cwd) {
20022
- return path70.join(cwd, ".metaproject", "data", "memory");
20029
+ return path71.join(cwd, ".metaproject", "data", "memory");
20023
20030
  }
20024
20031
  function createMemoryService() {
20025
20032
  const reportStore = createMemoryReportStore();
@@ -20034,9 +20041,9 @@ function createMemoryService() {
20034
20041
  if (!/^[a-z0-9][a-z0-9-]*$/.test(slug)) {
20035
20042
  throw new Error(`Invalid slug: ${slug}. Use lowercase letters, digits, and hyphens.`);
20036
20043
  }
20037
- const dir = path70.join(memoryRoot(input.cwd), typeConfig.folder);
20038
- const filePath = path70.join(dir, `${slug}.md`);
20039
- const relativePath = path70.relative(input.cwd, filePath);
20044
+ const dir = path71.join(memoryRoot(input.cwd), typeConfig.folder);
20045
+ const filePath = path71.join(dir, `${slug}.md`);
20046
+ const relativePath = path71.relative(input.cwd, filePath);
20040
20047
  if (await pathExists(filePath) && !input.force) {
20041
20048
  throw new Error(`Entry already exists: ${relativePath}. Use --force to overwrite.`);
20042
20049
  }
@@ -20067,9 +20074,9 @@ function createMemoryService() {
20067
20074
  async index(input) {
20068
20075
  const entries = await collectEntries(input.cwd);
20069
20076
  const generatedAt = new Date().toISOString();
20070
- const indexDir = path70.join(dataRoot2(input.cwd), "index");
20077
+ const indexDir = path71.join(dataRoot2(input.cwd), "index");
20071
20078
  await mkdir17(indexDir, { recursive: true });
20072
- const indexPath = path70.join(indexDir, "index.json");
20079
+ const indexPath = path71.join(indexDir, "index.json");
20073
20080
  await writeFile11(indexPath, `${JSON.stringify({
20074
20081
  catalogVersion: 1,
20075
20082
  sourceFingerprint: createHash11("sha256").update(JSON.stringify(entries.map((e) => ({
@@ -20090,7 +20097,7 @@ function createMemoryService() {
20090
20097
  }, null, 2)}
20091
20098
  `, "utf8");
20092
20099
  const result = {
20093
- path: path70.relative(input.cwd, indexPath),
20100
+ path: path71.relative(input.cwd, indexPath),
20094
20101
  entryCount: entries.length,
20095
20102
  generatedAt
20096
20103
  };
@@ -20103,7 +20110,7 @@ function createMemoryService() {
20103
20110
  const built = await buildEmbeddingIndex(input.cwd, entries, embedder.embed, embedder.model, new Date);
20104
20111
  result.embeddings = {
20105
20112
  built: true,
20106
- path: path70.relative(input.cwd, embeddingsDir(input.cwd)),
20113
+ path: path71.relative(input.cwd, embeddingsDir(input.cwd)),
20107
20114
  vectorCount: built.meta.entryCount,
20108
20115
  model: built.meta.model
20109
20116
  };
@@ -20143,7 +20150,7 @@ function createMemoryService() {
20143
20150
  }
20144
20151
  let content;
20145
20152
  try {
20146
- content = await readFile35(resolved.absolutePath, "utf8");
20153
+ content = await readFile36(resolved.absolutePath, "utf8");
20147
20154
  } catch {
20148
20155
  return { path: resolved.relativePath, from: "draft", to: input.to, changed: false, error: { code: "not-found", message: `Memory entry not found: ${resolved.relativePath}` } };
20149
20156
  }
@@ -20334,7 +20341,7 @@ var init_service3 = __esm(() => {
20334
20341
  });
20335
20342
 
20336
20343
  // src/wiki/ask.ts
20337
- import { readFile as readFile36 } from "fs/promises";
20344
+ import { readFile as readFile37 } from "fs/promises";
20338
20345
  async function wikiAsk(input) {
20339
20346
  const k = input.k && input.k > 0 ? input.k : DEFAULT_K;
20340
20347
  const asOf = input.asOf ? validateAsOf(input.asOf, new Date) : undefined;
@@ -20501,7 +20508,7 @@ async function wikiCandidates(cwd, observedAt, historicalMode, asOf) {
20501
20508
  }
20502
20509
  const index = buildSectionIndex(await Promise.all(admitted.map(async (page) => ({
20503
20510
  page,
20504
- content: await readFile36(page.absolutePath, "utf8").catch(() => "")
20511
+ content: await readFile37(page.absolutePath, "utf8").catch(() => "")
20505
20512
  }))));
20506
20513
  const result = [];
20507
20514
  for (const section of index.sections) {
@@ -20705,7 +20712,7 @@ var init_ask = __esm(() => {
20705
20712
  });
20706
20713
 
20707
20714
  // src/wiki/backlinks.ts
20708
- import path71 from "path";
20715
+ import path72 from "path";
20709
20716
  function extractCodePaths(content) {
20710
20717
  const out = [];
20711
20718
  let match;
@@ -20735,8 +20742,8 @@ function resolveLink(fromRepoPath, raw) {
20735
20742
  const clean = (raw.split("#")[0] ?? "").trim();
20736
20743
  if (!clean)
20737
20744
  return "";
20738
- const fromDir = path71.posix.dirname(fromRepoPath.split(path71.sep).join("/"));
20739
- return path71.posix.normalize(path71.posix.join(fromDir, clean));
20745
+ const fromDir = path72.posix.dirname(fromRepoPath.split(path72.sep).join("/"));
20746
+ return path72.posix.normalize(path72.posix.join(fromDir, clean));
20740
20747
  }
20741
20748
  function buildBacklinkIndex(pages) {
20742
20749
  const index = new Map;
@@ -20750,18 +20757,18 @@ function buildBacklinkIndex(pages) {
20750
20757
  }
20751
20758
  };
20752
20759
  for (const page of pages) {
20753
- const from = page.repoPath.split(path71.sep).join("/");
20760
+ const from = page.repoPath.split(path72.sep).join("/");
20754
20761
  for (const raw of extractLinks(page.content))
20755
20762
  add(resolveLink(from, raw), from);
20756
20763
  for (const raw of extractCodePaths(page.content))
20757
- add(path71.posix.normalize(raw), from);
20764
+ add(path72.posix.normalize(raw), from);
20758
20765
  }
20759
20766
  for (const list of index.values())
20760
20767
  list.sort();
20761
20768
  return index;
20762
20769
  }
20763
20770
  function backlinksFor(index, targetRepoPath) {
20764
- const key = path71.posix.normalize(targetRepoPath.split(path71.sep).join("/"));
20771
+ const key = path72.posix.normalize(targetRepoPath.split(path72.sep).join("/"));
20765
20772
  return index.get(key) ?? [];
20766
20773
  }
20767
20774
  var LINK, CODE_SPAN, FILE_LIKE;
@@ -20774,7 +20781,7 @@ var init_backlinks = __esm(() => {
20774
20781
  // src/ctx/assembly.ts
20775
20782
  import { createHash as createHash12 } from "crypto";
20776
20783
  import { mkdir as mkdir18, rename as rename6, writeFile as writeFile12 } from "fs/promises";
20777
- import path72 from "path";
20784
+ import path73 from "path";
20778
20785
  function assembleContext(input) {
20779
20786
  let items = 0;
20780
20787
  let tokens = 0;
@@ -20818,9 +20825,9 @@ async function recordNoContentContext(input) {
20818
20825
  return assembly;
20819
20826
  }
20820
20827
  async function recordContextAssembly(input) {
20821
- const directory = path72.join(input.workspaceRoot, ".metaproject", "context-operations", "traces");
20828
+ const directory = path73.join(input.workspaceRoot, ".metaproject", "context-operations", "traces");
20822
20829
  await mkdir18(directory, { recursive: true });
20823
- const target = path72.join(directory, path72.basename(input.assembly.traceRef));
20830
+ const target = path73.join(directory, path73.basename(input.assembly.traceRef));
20824
20831
  const temporary = `${target}.${process.pid}.tmp`;
20825
20832
  await writeFile12(temporary, `${JSON.stringify({ schemaVersion: "1.0", correlationId: input.correlationId, outcome: input.outcome, configurationRevision: input.assembly.configurationRevision, policy: { ref: input.assembly.policyRef, revision: input.assembly.policyRevision }, selected: input.assembly.selected, omittedOptional: input.assembly.omittedOptional, partial: input.assembly.partial })}
20826
20833
  `, { mode: 384 });
@@ -21670,16 +21677,16 @@ __export(exports_service4, {
21670
21677
  });
21671
21678
  import { spawn as spawn3 } from "child_process";
21672
21679
  import { createHash as createHash14 } from "crypto";
21673
- import { mkdir as mkdir19, readFile as readFile37, readdir as readdir12, rm as rm5, writeFile as writeFile13 } from "fs/promises";
21674
- import path73 from "path";
21680
+ import { mkdir as mkdir19, readFile as readFile38, readdir as readdir13, rm as rm5, writeFile as writeFile13 } from "fs/promises";
21681
+ import path74 from "path";
21675
21682
  function wikiRootPath2(cwd) {
21676
- return path73.join(cwd, ".metaproject", "wiki");
21683
+ return path74.join(cwd, ".metaproject", "wiki");
21677
21684
  }
21678
21685
  function dataRootPath(cwd) {
21679
- return path73.join(cwd, ".metaproject", "data", "gdwiki");
21686
+ return path74.join(cwd, ".metaproject", "data", "gdwiki");
21680
21687
  }
21681
21688
  function linkCheckReportPath(cwd) {
21682
- return path73.join(dataRootPath(cwd), "link-check", "latest.md");
21689
+ return path74.join(dataRootPath(cwd), "link-check", "latest.md");
21683
21690
  }
21684
21691
  async function wikiStatus(cwd) {
21685
21692
  const root = wikiRootPath2(cwd);
@@ -21687,7 +21694,7 @@ async function wikiStatus(cwd) {
21687
21694
  const pages = enabled ? await collectPages(cwd) : [];
21688
21695
  return {
21689
21696
  enabled,
21690
- wikiRoot: path73.relative(cwd, root),
21697
+ wikiRoot: path74.relative(cwd, root),
21691
21698
  totalPages: pages.length,
21692
21699
  countsByType: WIKI_PAGE_TYPES.map(({ type }) => ({
21693
21700
  type,
@@ -21702,7 +21709,7 @@ async function findPagesWithThinkTags(pages) {
21702
21709
  const flagged = [];
21703
21710
  for (const page of pages) {
21704
21711
  try {
21705
- const content = await readFile37(page.absolutePath, "utf8");
21712
+ const content = await readFile38(page.absolutePath, "utf8");
21706
21713
  if (containsThinkTags(content)) {
21707
21714
  flagged.push(page.relativePath);
21708
21715
  }
@@ -21718,9 +21725,9 @@ async function wikiCreatePage(input) {
21718
21725
  if (!/^[a-z0-9][a-z0-9-]*$/.test(input.slug)) {
21719
21726
  throw new Error(`Invalid slug: ${input.slug}. Use lowercase letters, digits, and hyphens.`);
21720
21727
  }
21721
- const dir = path73.join(wikiRootPath2(input.cwd), typeConfig.folder);
21722
- const filePath = path73.join(dir, `${input.slug}.md`);
21723
- const relativePath = path73.relative(input.cwd, filePath);
21728
+ const dir = path74.join(wikiRootPath2(input.cwd), typeConfig.folder);
21729
+ const filePath = path74.join(dir, `${input.slug}.md`);
21730
+ const relativePath = path74.relative(input.cwd, filePath);
21724
21731
  if (await pathExists(filePath) && !input.force) {
21725
21732
  throw new Error(`Page already exists: ${relativePath}. Use --force to overwrite.`);
21726
21733
  }
@@ -21731,13 +21738,13 @@ async function wikiCreatePage(input) {
21731
21738
  }
21732
21739
  async function wikiGenerateIndex(cwd) {
21733
21740
  const root = wikiRootPath2(cwd);
21734
- const indexPath = path73.join(root, "index.md");
21741
+ const indexPath = path74.join(root, "index.md");
21735
21742
  const pages = await collectPages(cwd);
21736
21743
  const generatedAt = new Date().toISOString();
21737
21744
  const managedBlock = `${WIKI_INDEX_BEGIN}
21738
21745
  ${renderIndexBody(pages, generatedAt)}
21739
21746
  ${WIKI_INDEX_END}`;
21740
- const existing = await pathExists(indexPath) ? await readFile37(indexPath, "utf8") : renderWikiIndexScaffold();
21747
+ const existing = await pathExists(indexPath) ? await readFile38(indexPath, "utf8") : renderWikiIndexScaffold();
21741
21748
  const pattern = new RegExp(`${escapeRegExp3(WIKI_INDEX_BEGIN)}[\\s\\S]*?${escapeRegExp3(WIKI_INDEX_END)}`);
21742
21749
  const replaced = pattern.test(existing) ? existing.replace(pattern, managedBlock) : `${existing.trimEnd()}
21743
21750
 
@@ -21749,7 +21756,7 @@ ${managedBlock}
21749
21756
  await mkdir19(root, { recursive: true });
21750
21757
  await writeFile13(indexPath, next, "utf8");
21751
21758
  return {
21752
- path: path73.relative(cwd, indexPath),
21759
+ path: path74.relative(cwd, indexPath),
21753
21760
  pageCount: pages.length,
21754
21761
  generatedAt
21755
21762
  };
@@ -21757,13 +21764,13 @@ ${managedBlock}
21757
21764
  async function wikiCheckLinks(cwd) {
21758
21765
  const root = wikiRootPath2(cwd);
21759
21766
  const allFiles = await pathExists(root) ? await walkMarkdown(root) : [];
21760
- const files = allFiles.filter((absolutePath) => !path73.relative(root, absolutePath).startsWith(`templates${path73.sep}`));
21767
+ const files = allFiles.filter((absolutePath) => !path74.relative(root, absolutePath).startsWith(`templates${path74.sep}`));
21761
21768
  const broken = [];
21762
21769
  let checkedLinks = 0;
21763
21770
  let skippedExternal = 0;
21764
21771
  for (const absolutePath of files) {
21765
- const content = await readFile37(absolutePath, "utf8");
21766
- const pageRelative = path73.relative(cwd, absolutePath);
21772
+ const content = await readFile38(absolutePath, "utf8");
21773
+ const pageRelative = path74.relative(cwd, absolutePath);
21767
21774
  for (const target of extractLinkTargets(content)) {
21768
21775
  if (EXTERNAL_LINK.test(target)) {
21769
21776
  skippedExternal += 1;
@@ -21774,7 +21781,7 @@ async function wikiCheckLinks(cwd) {
21774
21781
  continue;
21775
21782
  }
21776
21783
  checkedLinks += 1;
21777
- const resolved = path73.resolve(path73.dirname(absolutePath), filePart);
21784
+ const resolved = path74.resolve(path74.dirname(absolutePath), filePart);
21778
21785
  if (!await pathExists(resolved)) {
21779
21786
  broken.push({
21780
21787
  page: pageRelative,
@@ -21786,7 +21793,7 @@ async function wikiCheckLinks(cwd) {
21786
21793
  }
21787
21794
  const generatedAt = new Date().toISOString();
21788
21795
  const reportPath = linkCheckReportPath(cwd);
21789
- await mkdir19(path73.dirname(reportPath), { recursive: true });
21796
+ await mkdir19(path74.dirname(reportPath), { recursive: true });
21790
21797
  await writeFile13(reportPath, renderLinkCheckReport({
21791
21798
  generatedAt,
21792
21799
  checkedPages: files.length,
@@ -21795,7 +21802,7 @@ async function wikiCheckLinks(cwd) {
21795
21802
  broken
21796
21803
  }), "utf8");
21797
21804
  return {
21798
- reportPath: path73.relative(cwd, reportPath),
21805
+ reportPath: path74.relative(cwd, reportPath),
21799
21806
  checkedPages: files.length,
21800
21807
  checkedLinks,
21801
21808
  skippedExternal,
@@ -21845,7 +21852,7 @@ async function wikiValidate(cwd) {
21845
21852
  }
21846
21853
  if (await isIndexStale(cwd, pages)) {
21847
21854
  issues.push({
21848
- page: path73.join(path73.relative(cwd, wikiRootPath2(cwd)), "index.md"),
21855
+ page: path74.join(path74.relative(cwd, wikiRootPath2(cwd)), "index.md"),
21849
21856
  kind: "index",
21850
21857
  message: "index out of date, run `keryx wiki index`"
21851
21858
  });
@@ -21882,7 +21889,7 @@ async function wikiCollect(input) {
21882
21889
  };
21883
21890
  }
21884
21891
  async function wikiPruneOrphans(cwd) {
21885
- const componentsDir = path73.join(wikiRootPath2(cwd), "components");
21892
+ const componentsDir = path74.join(wikiRootPath2(cwd), "components");
21886
21893
  if (!await pathExists(componentsDir)) {
21887
21894
  return { pruned: [], orphanedAccepted: [] };
21888
21895
  }
@@ -21891,7 +21898,7 @@ async function wikiPruneOrphans(cwd) {
21891
21898
  const validSlugs = new Set(candidates.filter((candidate) => candidate.type === "component").map((candidate) => candidate.slug));
21892
21899
  const pruned = [];
21893
21900
  const orphanedAccepted = [];
21894
- for (const entry of await readdir12(componentsDir)) {
21901
+ for (const entry of await readdir13(componentsDir)) {
21895
21902
  if (!entry.endsWith(".md")) {
21896
21903
  continue;
21897
21904
  }
@@ -21899,25 +21906,25 @@ async function wikiPruneOrphans(cwd) {
21899
21906
  if (validSlugs.has(slug)) {
21900
21907
  continue;
21901
21908
  }
21902
- const filePath = path73.join(componentsDir, entry);
21903
- const current = await readFile37(filePath, "utf8");
21909
+ const filePath = path74.join(componentsDir, entry);
21910
+ const current = await readFile38(filePath, "utf8");
21904
21911
  const isUnmodifiedDraft = /\nStatus:\s*draft\s*\n/.test(current) && current.includes("Generated by `keryx wiki collect`");
21905
21912
  if (isUnmodifiedDraft) {
21906
21913
  await rm5(filePath);
21907
- pruned.push(path73.relative(cwd, filePath));
21914
+ pruned.push(path74.relative(cwd, filePath));
21908
21915
  } else {
21909
- orphanedAccepted.push(path73.relative(cwd, filePath));
21916
+ orphanedAccepted.push(path74.relative(cwd, filePath));
21910
21917
  }
21911
21918
  }
21912
21919
  return { pruned, orphanedAccepted };
21913
21920
  }
21914
21921
  async function validModuleNames(cwd) {
21915
- const nodesPath = path73.join(cwd, ".metaproject", "data", "gdgraph", "storage", "nodes.jsonl");
21922
+ const nodesPath = path74.join(cwd, ".metaproject", "data", "gdgraph", "storage", "nodes.jsonl");
21916
21923
  if (!await pathExists(nodesPath)) {
21917
21924
  return;
21918
21925
  }
21919
21926
  const modules = new Set;
21920
- for (const node of parseJsonl(await readFile37(nodesPath, "utf8"))) {
21927
+ for (const node of parseJsonl(await readFile38(nodesPath, "utf8"))) {
21921
21928
  if (node.kind === "asset")
21922
21929
  continue;
21923
21930
  const nodePath = String(node.path ?? node.id ?? "unknown");
@@ -21948,7 +21955,7 @@ async function wikiEvidence(input) {
21948
21955
  const pages = await collectPages(input.cwd);
21949
21956
  const index = buildSectionIndex(await Promise.all(pages.map(async (page) => ({
21950
21957
  page,
21951
- content: await readFile37(page.absolutePath, "utf8").catch(() => "")
21958
+ content: await readFile38(page.absolutePath, "utf8").catch(() => "")
21952
21959
  }))));
21953
21960
  const registry = await readSectionRegistryState(input.cwd);
21954
21961
  const pageStatus = {};
@@ -21982,9 +21989,9 @@ async function wikiEvidence(input) {
21982
21989
  });
21983
21990
  }
21984
21991
  function resolveEvidenceScope(cwd, override) {
21985
- const absolute = path73.resolve(cwd);
21992
+ const absolute = path74.resolve(cwd);
21986
21993
  return {
21987
- projectId: override?.projectId ?? (path73.basename(absolute) || "project"),
21994
+ projectId: override?.projectId ?? (path74.basename(absolute) || "project"),
21988
21995
  checkoutId: override?.checkoutId ?? `checkout:${createHash14("sha256").update(absolute).digest("hex").slice(0, 16)}`,
21989
21996
  ...override?.workspaceId ? { workspaceId: override.workspaceId } : {},
21990
21997
  ...override?.taskId ? { taskId: override.taskId } : {}
@@ -21999,7 +22006,7 @@ function isMachineAuthoredPage(pageType, relativePath, content) {
21999
22006
  if (source === null) {
22000
22007
  return false;
22001
22008
  }
22002
- const normalised = relativePath.split(path73.sep).join("/").replace(/^wiki\//, "");
22009
+ const normalised = relativePath.split(path74.sep).join("/").replace(/^wiki\//, "");
22003
22010
  return WIKI_PAGE_PRODUCERS.some((producer) => producer.source === source && producer.pageType === pageType && producer.path.test(normalised) && /^-[ \t]+Link:.*\bsha256\b/m.test(content));
22004
22011
  }
22005
22012
  function createGdWikiService() {
@@ -22015,8 +22022,8 @@ function createGdWikiService() {
22015
22022
  };
22016
22023
  }
22017
22024
  async function collectGraphWikiCandidates(cwd, generatedAt, limit, onlyModules) {
22018
- const nodesPath = path73.join(cwd, ".metaproject", "data", "gdgraph", "storage", "nodes.jsonl");
22019
- const edgesPath = path73.join(cwd, ".metaproject", "data", "gdgraph", "storage", "edges.jsonl");
22025
+ const nodesPath = path74.join(cwd, ".metaproject", "data", "gdgraph", "storage", "nodes.jsonl");
22026
+ const edgesPath = path74.join(cwd, ".metaproject", "data", "gdgraph", "storage", "edges.jsonl");
22020
22027
  if (!await pathExists(nodesPath) || !await pathExists(edgesPath)) {
22021
22028
  return [];
22022
22029
  }
@@ -22025,7 +22032,7 @@ async function collectGraphWikiCandidates(cwd, generatedAt, limit, onlyModules)
22025
22032
  let nodes = 0;
22026
22033
  let files = 0;
22027
22034
  let assets = 0;
22028
- for (const node of parseJsonl(await readFile37(nodesPath, "utf8"))) {
22035
+ for (const node of parseJsonl(await readFile38(nodesPath, "utf8"))) {
22029
22036
  nodes += 1;
22030
22037
  const nodePath = String(node.path ?? node.id ?? "unknown");
22031
22038
  if (node.kind === "asset") {
@@ -22047,7 +22054,7 @@ async function collectGraphWikiCandidates(cwd, generatedAt, limit, onlyModules)
22047
22054
  let edges = 0;
22048
22055
  let imports = 0;
22049
22056
  let unresolved = 0;
22050
- for (const edge of parseJsonl(await readFile37(edgesPath, "utf8"))) {
22057
+ for (const edge of parseJsonl(await readFile38(edgesPath, "utf8"))) {
22051
22058
  edges += 1;
22052
22059
  const kind = String(edge.kind ?? "");
22053
22060
  if (kind === "unresolved") {
@@ -22200,12 +22207,12 @@ function topCounts(bucket, limit) {
22200
22207
  return [...bucket.entries()].sort((a, b) => b[1] - a[1]).slice(0, limit);
22201
22208
  }
22202
22209
  async function readModuleReadme(cwd, moduleName) {
22203
- const readmePath = path73.join(cwd, ...moduleName.split("/"), "README.md");
22210
+ const readmePath = path74.join(cwd, ...moduleName.split("/"), "README.md");
22204
22211
  if (!await pathExists(readmePath)) {
22205
22212
  return null;
22206
22213
  }
22207
22214
  try {
22208
- const content = await readFile37(readmePath, "utf8");
22215
+ const content = await readFile38(readmePath, "utf8");
22209
22216
  const paragraph = content.split(/\n\s*\n/).map((block) => block.trim()).find((block) => block.length > 0 && !block.startsWith("#"));
22210
22217
  if (!paragraph) {
22211
22218
  return null;
@@ -22221,12 +22228,12 @@ async function extractModuleExports(cwd, files) {
22221
22228
  const declRe = /export\s+(?:async\s+)?(?:default\s+)?(?:const|let|var|function|class|type|interface|enum)\s+([A-Za-z_$][\w$]*)/g;
22222
22229
  const braceRe = /export\s*\{([^}]+)\}/g;
22223
22230
  for (const file of files.slice(0, 4)) {
22224
- const filePath = path73.join(cwd, ...file.split("/"));
22231
+ const filePath = path74.join(cwd, ...file.split("/"));
22225
22232
  if (!await pathExists(filePath)) {
22226
22233
  continue;
22227
22234
  }
22228
22235
  try {
22229
- const content = (await readFile37(filePath, "utf8")).slice(0, 40000);
22236
+ const content = (await readFile38(filePath, "utf8")).slice(0, 40000);
22230
22237
  let match;
22231
22238
  while ((match = declRe.exec(content)) !== null) {
22232
22239
  if (match[1]) {
@@ -22252,14 +22259,14 @@ async function extractModuleExports(cwd, files) {
22252
22259
  }
22253
22260
  async function extractModuleApi(cwd, files) {
22254
22261
  const names = await extractModuleExports(cwd, files);
22255
- const symbolsPath = path73.join(cwd, ".metaproject", "data", "gdgraph", "storage", "symbols.jsonl");
22262
+ const symbolsPath = path74.join(cwd, ".metaproject", "data", "gdgraph", "storage", "symbols.jsonl");
22256
22263
  if (names.length === 0 || !await pathExists(symbolsPath)) {
22257
22264
  return names.map((name) => "`" + name + "`");
22258
22265
  }
22259
22266
  const fileSet = new Set(files);
22260
22267
  const kindByName = new Map;
22261
22268
  try {
22262
- for (const raw of parseJsonl(await readFile37(symbolsPath, "utf8"))) {
22269
+ for (const raw of parseJsonl(await readFile38(symbolsPath, "utf8"))) {
22263
22270
  const symbol = raw;
22264
22271
  if (!symbol.name || !symbol.path || symbol.container != null)
22265
22272
  continue;
@@ -22278,11 +22285,11 @@ async function extractModuleApi(cwd, files) {
22278
22285
  });
22279
22286
  }
22280
22287
  async function collectHealthWikiCandidates(cwd, generatedAt) {
22281
- const healthPath = path73.join(cwd, ".metaproject", "data", "health", "artifacts", "latest.json");
22288
+ const healthPath = path74.join(cwd, ".metaproject", "data", "health", "artifacts", "latest.json");
22282
22289
  if (!await pathExists(healthPath)) {
22283
22290
  return [];
22284
22291
  }
22285
- const report = JSON.parse(await readFile37(healthPath, "utf8"));
22292
+ const report = JSON.parse(await readFile38(healthPath, "utf8"));
22286
22293
  const metrics = Array.isArray(report.metrics) ? report.metrics : [];
22287
22294
  const project = metrics.find((metric) => metric.key === "project") ?? {};
22288
22295
  const counts = project.findingCounts ?? {};
@@ -22320,11 +22327,11 @@ async function collectHealthWikiCandidates(cwd, generatedAt) {
22320
22327
  }];
22321
22328
  }
22322
22329
  async function collectTestingWikiCandidates(cwd, generatedAt) {
22323
- const contextPath = path73.join(cwd, ".metaproject", "data", "testing", "context.md");
22330
+ const contextPath = path74.join(cwd, ".metaproject", "data", "testing", "context.md");
22324
22331
  if (!await pathExists(contextPath)) {
22325
22332
  return [];
22326
22333
  }
22327
- const context = await readFile37(contextPath, "utf8");
22334
+ const context = await readFile38(contextPath, "utf8");
22328
22335
  const summary = firstMeaningfulLine(context) ?? "Generated from testing context.";
22329
22336
  return [{
22330
22337
  type: "architecture",
@@ -22351,14 +22358,14 @@ async function writeCollectedPage(cwd, candidate, force) {
22351
22358
  if (!folder) {
22352
22359
  throw new Error(`Unsupported collected wiki type: ${candidate.type}`);
22353
22360
  }
22354
- const filePath = path73.join(wikiRootPath2(cwd), folder, `${candidate.slug}.md`);
22355
- const relativePath = path73.relative(cwd, filePath);
22361
+ const filePath = path74.join(wikiRootPath2(cwd), folder, `${candidate.slug}.md`);
22362
+ const relativePath = path74.relative(cwd, filePath);
22356
22363
  const exists = await pathExists(filePath);
22357
22364
  if (exists && !force) {
22358
22365
  return { path: relativePath, type: candidate.type, source: candidate.source, action: "skipped" };
22359
22366
  }
22360
22367
  if (exists && force) {
22361
- const current = await readFile37(filePath, "utf8");
22368
+ const current = await readFile38(filePath, "utf8");
22362
22369
  const isUnmodifiedDraft = /\nStatus:\s*draft\s*\n/.test(current) && current.includes("Generated by `keryx wiki collect`");
22363
22370
  if (!isUnmodifiedDraft) {
22364
22371
  return { path: relativePath, type: candidate.type, source: candidate.source, action: "skipped" };
@@ -22380,7 +22387,7 @@ async function writeCollectedPage(cwd, candidate, force) {
22380
22387
  securityReason: output.reason
22381
22388
  };
22382
22389
  }
22383
- await mkdir19(path73.dirname(filePath), { recursive: true });
22390
+ await mkdir19(path74.dirname(filePath), { recursive: true });
22384
22391
  await writeFile13(filePath, output.content, "utf8");
22385
22392
  return {
22386
22393
  path: relativePath,
@@ -22392,8 +22399,8 @@ async function writeCollectedPage(cwd, candidate, force) {
22392
22399
  async function wikiPagesForFile(cwd, targetRepoPath) {
22393
22400
  const pages = await collectPages(cwd);
22394
22401
  const refs = await Promise.all(pages.map(async (page) => ({
22395
- repoPath: path73.relative(cwd, page.absolutePath).split(path73.sep).join("/"),
22396
- content: await readFile37(page.absolutePath, "utf8")
22402
+ repoPath: path74.relative(cwd, page.absolutePath).split(path74.sep).join("/"),
22403
+ content: await readFile38(page.absolutePath, "utf8")
22397
22404
  })));
22398
22405
  return backlinksFor(buildBacklinkIndex(refs), targetRepoPath);
22399
22406
  }
@@ -22431,11 +22438,11 @@ function renderIndexBody(pages, generatedAt) {
22431
22438
  `).trimEnd();
22432
22439
  }
22433
22440
  async function isIndexStale(cwd, pages) {
22434
- const indexPath = path73.join(wikiRootPath2(cwd), "index.md");
22441
+ const indexPath = path74.join(wikiRootPath2(cwd), "index.md");
22435
22442
  if (!await pathExists(indexPath)) {
22436
22443
  return true;
22437
22444
  }
22438
- const content = await readFile37(indexPath, "utf8");
22445
+ const content = await readFile38(indexPath, "utf8");
22439
22446
  const managed = content.match(new RegExp(`${escapeRegExp3(WIKI_INDEX_BEGIN)}([\\s\\S]*?)${escapeRegExp3(WIKI_INDEX_END)}`));
22440
22447
  if (!managed?.[1]) {
22441
22448
  return true;
@@ -22447,9 +22454,9 @@ function stripStamp(body) {
22447
22454
  }
22448
22455
  async function walkMarkdown(root) {
22449
22456
  const results = [];
22450
- const entries = await readdir12(root, { withFileTypes: true });
22457
+ const entries = await readdir13(root, { withFileTypes: true });
22451
22458
  for (const entry of entries) {
22452
- const absolutePath = path73.join(root, entry.name);
22459
+ const absolutePath = path74.join(root, entry.name);
22453
22460
  if (entry.isDirectory()) {
22454
22461
  results.push(...await walkMarkdown(absolutePath));
22455
22462
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
@@ -22506,11 +22513,11 @@ ${JSON.stringify(state, null, 2)}
22506
22513
  `;
22507
22514
  }
22508
22515
  async function readIndexGeneratedAt(cwd) {
22509
- const indexPath = path73.join(wikiRootPath2(cwd), "index.md");
22516
+ const indexPath = path74.join(wikiRootPath2(cwd), "index.md");
22510
22517
  if (!await pathExists(indexPath)) {
22511
22518
  return null;
22512
22519
  }
22513
- const content = await readFile37(indexPath, "utf8");
22520
+ const content = await readFile38(indexPath, "utf8");
22514
22521
  const match = content.match(/<!--\s*generated:\s*([^|]+?)\s*\|/);
22515
22522
  const value = match?.[1]?.trim();
22516
22523
  return value && value !== "never" ? value : null;
@@ -22520,7 +22527,7 @@ async function readLinkCheckState(cwd) {
22520
22527
  if (!await pathExists(reportPath)) {
22521
22528
  return null;
22522
22529
  }
22523
- const content = await readFile37(reportPath, "utf8");
22530
+ const content = await readFile38(reportPath, "utf8");
22524
22531
  const matches = [...content.matchAll(/```json\n([\s\S]*?)```/g)];
22525
22532
  const last = matches.at(-1);
22526
22533
  if (!last?.[1]) {
@@ -22718,7 +22725,7 @@ async function validateStructure(cwd, pages, issues) {
22718
22725
  for (const page of pages) {
22719
22726
  let content;
22720
22727
  try {
22721
- content = await readFile37(page.absolutePath, "utf8");
22728
+ content = await readFile38(page.absolutePath, "utf8");
22722
22729
  } catch {
22723
22730
  continue;
22724
22731
  }
@@ -22743,7 +22750,7 @@ async function validateStructure(cwd, pages, issues) {
22743
22750
  if (pattern.includes("*")) {
22744
22751
  continue;
22745
22752
  }
22746
- if (!await pathExists(path73.join(cwd, pattern))) {
22753
+ if (!await pathExists(path74.join(cwd, pattern))) {
22747
22754
  issues.push({
22748
22755
  page: page.relativePath,
22749
22756
  kind: "describes",
@@ -22813,10 +22820,10 @@ var init_service4 = __esm(() => {
22813
22820
 
22814
22821
  // src/gdgraph/wiki-layer.ts
22815
22822
  import { createHash as createHash15 } from "crypto";
22816
- import { mkdir as mkdir20, stat as stat10, writeFile as writeFile14 } from "fs/promises";
22817
- import path74 from "path";
22823
+ import { mkdir as mkdir20, stat as stat11, writeFile as writeFile14 } from "fs/promises";
22824
+ import path75 from "path";
22818
22825
  function storageDir(projectRoot) {
22819
- return path74.join(projectRoot, ".metaproject", "data", "gdgraph", "storage");
22826
+ return path75.join(projectRoot, ".metaproject", "data", "gdgraph", "storage");
22820
22827
  }
22821
22828
  function wikiPageId(relativePath) {
22822
22829
  return `wiki:${relativePath}`;
@@ -22882,11 +22889,11 @@ async function enrichBuildWithWikiLayer(input) {
22882
22889
  const mtimes = new Map;
22883
22890
  for (const record of input.fileRecords) {
22884
22891
  try {
22885
- const info = await stat10(path74.join(input.projectRoot, record.path));
22892
+ const info = await stat11(path75.join(input.projectRoot, record.path));
22886
22893
  mtimes.set(record.path, info.mtimeMs);
22887
22894
  } catch {}
22888
22895
  }
22889
- await writeFile14(path74.join(dir, BUILD_MANIFEST_FILE), `${JSON.stringify({ version: 1, files: computeFingerprints(input.fileRecords, mtimes) }, null, 2)}
22896
+ await writeFile14(path75.join(dir, BUILD_MANIFEST_FILE), `${JSON.stringify({ version: 1, files: computeFingerprints(input.fileRecords, mtimes) }, null, 2)}
22890
22897
  `, "utf8");
22891
22898
  const validModules = input.validModules !== undefined ? input.validModules : await (input.loadValidModules ?? defaultLoadValidModules)(input.projectRoot);
22892
22899
  const wikiPages = await collectPages(input.projectRoot);
@@ -22911,8 +22918,8 @@ async function enrichBuildWithWikiLayer(input) {
22911
22918
  version: page.version
22912
22919
  }))
22913
22920
  });
22914
- await writeJsonl(path74.join(dir, WIKI_PAGES_FILE), layer.pages);
22915
- await writeJsonl(path74.join(dir, DESCRIBES_FILE), layer.describes);
22921
+ await writeJsonl(path75.join(dir, WIKI_PAGES_FILE), layer.pages);
22922
+ await writeJsonl(path75.join(dir, DESCRIBES_FILE), layer.describes);
22916
22923
  return layer;
22917
22924
  }
22918
22925
  async function defaultLoadValidModules(projectRoot) {
@@ -22928,23 +22935,23 @@ var init_wiki_layer = __esm(() => {
22928
22935
  });
22929
22936
 
22930
22937
  // src/gdskills/contracts.ts
22931
- import { readFile as readFile49 } from "fs/promises";
22938
+ import { readFile as readFile50 } from "fs/promises";
22932
22939
  import { existsSync as existsSync15 } from "fs";
22933
- import path102 from "path";
22940
+ import path103 from "path";
22934
22941
  import { fileURLToPath as fileURLToPath2 } from "url";
22935
22942
  async function loadSchema(name) {
22936
22943
  const contract = CONTRACTS.find((entry) => entry.name === name);
22937
22944
  if (!contract) {
22938
22945
  throw new Error(`Unknown contract schema: ${name}`);
22939
22946
  }
22940
- const raw = await readFile49(contractPath(contract), "utf8");
22947
+ const raw = await readFile50(contractPath(contract), "utf8");
22941
22948
  return JSON.parse(raw);
22942
22949
  }
22943
22950
  function contractPath(contract) {
22944
- const here = path102.dirname(fileURLToPath2(import.meta.url));
22951
+ const here = path103.dirname(fileURLToPath2(import.meta.url));
22945
22952
  if (contract.sourcePath) {
22946
- for (const root of [path102.join(here, "..", ".."), path102.join(here, ".."), here]) {
22947
- const candidate = path102.resolve(root, contract.sourcePath);
22953
+ for (const root of [path103.join(here, "..", ".."), path103.join(here, ".."), here]) {
22954
+ const candidate = path103.resolve(root, contract.sourcePath);
22948
22955
  if (existsSync15(candidate)) {
22949
22956
  return candidate;
22950
22957
  }
@@ -22954,7 +22961,7 @@ function contractPath(contract) {
22954
22961
  if (existsSync15(directPath)) {
22955
22962
  return directPath;
22956
22963
  }
22957
- const packagedSourcePath = path102.join(here, "..", "src", "gdskills", "contracts", contract.fileName);
22964
+ const packagedSourcePath = path103.join(here, "..", "src", "gdskills", "contracts", contract.fileName);
22958
22965
  if (existsSync15(packagedSourcePath)) {
22959
22966
  return packagedSourcePath;
22960
22967
  }
@@ -23185,8 +23192,8 @@ __export(exports_service2, {
23185
23192
  validateCriterionName: () => validateCriterionName,
23186
23193
  writeAcCheckCache: () => writeAcCheckCache
23187
23194
  });
23188
- import { mkdir as mkdir12, readFile as readFile27 } from "fs/promises";
23189
- import path55 from "path";
23195
+ import { mkdir as mkdir12, readFile as readFile28 } from "fs/promises";
23196
+ import path56 from "path";
23190
23197
 
23191
23198
  // src/flow/machine.ts
23192
23199
  var TRANSITIONS = {
@@ -24920,6 +24927,10 @@ function flowStateSchema() {
24920
24927
  type: "boolean",
24921
24928
  description: "Written by `flow init`. When true, `flow complete` fails the owner gate with a named reason while no owner is set, and passes it once one is. Absent on packages created before the gate existed, which report the gate `skipped` rather than `fail`."
24922
24929
  },
24930
+ folderCommitted: {
24931
+ type: "boolean",
24932
+ description: "flow 384: written by `flow init`. When true, `flow complete` fails the folder-committed gate while the flow folder's flow.json is not in HEAD, and passes it once it is. Absent on packages created before the gate existed, which report the gate `skipped` rather than `fail`."
24933
+ },
24923
24934
  confirmation: {
24924
24935
  type: "boolean",
24925
24936
  description: "flow 299: written by `flow init --require-confirmation`, or by `flow init` when `.metaproject/tasks.config.json` has `completion.require_confirmation: true`. When true, `flow complete` fails the confirmation gate unless `--confirm-token` carries a valid, unexpired, unspent token minted by `keryx flow confirm` for this flow and its current criteria checksum. Absent on every other flow, which reports the gate `skipped`."
@@ -25162,6 +25173,7 @@ function flowStateSchema() {
25162
25173
  "review",
25163
25174
  "base-branch",
25164
25175
  "owner",
25176
+ "folder-committed",
25165
25177
  "confirmation"
25166
25178
  ]
25167
25179
  },
@@ -25895,7 +25907,7 @@ async function intentNoteForNewFlow(cwd, dir) {
25895
25907
  }
25896
25908
  // src/flow/check-ac.ts
25897
25909
  import { createHash as createHash8 } from "crypto";
25898
- import { chmod as chmod4, mkdir as mkdir10, readFile as readFile25 } from "fs/promises";
25910
+ import { chmod as chmod4, mkdir as mkdir10, readFile as readFile26 } from "fs/promises";
25899
25911
  import path52 from "path";
25900
25912
 
25901
25913
  // src/review/cost.ts
@@ -26084,7 +26096,7 @@ function factsOnlyVerdict(item) {
26084
26096
  }
26085
26097
  async function readAcCheckEnabled(cwd) {
26086
26098
  try {
26087
- const parsed = JSON.parse(await readFile25(path52.join(cwd, REVIEW_GATE_CONFIG_PATH), "utf8"));
26099
+ const parsed = JSON.parse(await readFile26(path52.join(cwd, REVIEW_GATE_CONFIG_PATH), "utf8"));
26088
26100
  if (typeof parsed !== "object" || parsed === null)
26089
26101
  return false;
26090
26102
  const review = parsed["review"];
@@ -26111,7 +26123,7 @@ async function readAcCheckCache(cachePath) {
26111
26123
  if (!await pathExists(cachePath))
26112
26124
  return;
26113
26125
  try {
26114
- return JSON.parse(await readFile25(cachePath, "utf8"));
26126
+ return JSON.parse(await readFile26(cachePath, "utf8"));
26115
26127
  } catch {
26116
26128
  return;
26117
26129
  }
@@ -26174,7 +26186,7 @@ function renderAcCheckAdvisoryNotice(verdicts) {
26174
26186
  return `acceptance-criteria check (advisory): ${counts.likelyMet} likely met, ${counts.notEvident} not evident, ${counts.notCheckable} not checkable` + (inDoubt.length > 0 ? ` \u2014 in doubt: ${inDoubt.join(", ")}` : "") + ` (\`keryx flow check-ac\` for detail)`;
26175
26187
  }
26176
26188
  // src/flow/allocation.ts
26177
- import { appendFile as appendFile3, mkdir as mkdir11, readFile as readFile26 } from "fs/promises";
26189
+ import { appendFile as appendFile3, mkdir as mkdir11, readFile as readFile27 } from "fs/promises";
26178
26190
  import path54 from "path";
26179
26191
 
26180
26192
  // src/lib/clone-scope.ts
@@ -26239,7 +26251,7 @@ async function readAllocationLedger(scope) {
26239
26251
  if (!scope.ledgerPath || !await pathExists(scope.ledgerPath)) {
26240
26252
  return [];
26241
26253
  }
26242
- const content = await readFile26(scope.ledgerPath, "utf8");
26254
+ const content = await readFile27(scope.ledgerPath, "utf8");
26243
26255
  const records = [];
26244
26256
  for (const line of content.split(`
26245
26257
  `)) {
@@ -26269,6 +26281,179 @@ async function recordAllocation(scope, record) {
26269
26281
  `, "utf8");
26270
26282
  }
26271
26283
 
26284
+ // src/flow/remote-flows.ts
26285
+ import path55 from "path";
26286
+ var MAX_REFS = 500;
26287
+ var CONCURRENCY = 8;
26288
+ async function runGit2(cwd, args) {
26289
+ try {
26290
+ const proc = Bun.spawn(["git", ...args], { cwd, stdout: "pipe", stderr: "ignore" });
26291
+ const stdout = await new Response(proc.stdout).text();
26292
+ return { code: await proc.exited, stdout };
26293
+ } catch {
26294
+ return;
26295
+ }
26296
+ }
26297
+ function lines(text) {
26298
+ return text.split(`
26299
+ `).map((line) => line.trim()).filter((line) => line.length > 0);
26300
+ }
26301
+ function nulSplit(text) {
26302
+ return text.split("\x00").filter((entry) => entry.length > 0);
26303
+ }
26304
+ function safeDirName(dir) {
26305
+ let out = "";
26306
+ for (const char of dir) {
26307
+ const code = char.codePointAt(0) ?? 0;
26308
+ if (code > 31 && (code < 127 || code > 159)) {
26309
+ out += char;
26310
+ }
26311
+ }
26312
+ return out;
26313
+ }
26314
+ async function showPrefix(cwd) {
26315
+ const result = await runGit2(cwd, ["rev-parse", "--show-prefix"]);
26316
+ if (result === undefined || result.code !== 0) {
26317
+ return null;
26318
+ }
26319
+ return result.stdout.trim();
26320
+ }
26321
+ function rankOfRef(ref, headTargets) {
26322
+ if (/^refs\/remotes\/[^/]+\/(main|master)$/.test(ref)) {
26323
+ return 0;
26324
+ }
26325
+ return headTargets.has(ref) ? 1 : 2;
26326
+ }
26327
+ function orderRemoteRefs(entries, max = MAX_REFS) {
26328
+ const headTargets = new Set(entries.map((entry) => entry.symref).filter((symref) => symref.length > 0));
26329
+ const rank = (ref) => rankOfRef(ref, headTargets);
26330
+ const candidates = entries.filter((entry) => entry.ref.startsWith("refs/remotes/") && !entry.ref.endsWith("/HEAD") && entry.symref === "").sort((a, b) => rank(a.ref) - rank(b.ref) || (a.ref < b.ref ? -1 : a.ref > b.ref ? 1 : 0));
26331
+ const seenTips = new Set;
26332
+ const refs = [];
26333
+ for (const entry of candidates) {
26334
+ if (seenTips.has(entry.tip)) {
26335
+ continue;
26336
+ }
26337
+ seenTips.add(entry.tip);
26338
+ refs.push(entry.ref);
26339
+ if (refs.length >= max) {
26340
+ break;
26341
+ }
26342
+ }
26343
+ return refs;
26344
+ }
26345
+ async function remoteRefs(cwd) {
26346
+ const result = await runGit2(cwd, ["for-each-ref", "--format=%(objectname) %(refname) %(symref)", "refs/remotes/"]);
26347
+ if (result === undefined || result.code !== 0) {
26348
+ return [];
26349
+ }
26350
+ const entries = [];
26351
+ for (const line of lines(result.stdout)) {
26352
+ const [tip, ref, symref] = line.split(" ");
26353
+ if (tip === undefined || ref === undefined) {
26354
+ continue;
26355
+ }
26356
+ entries.push({ tip, ref, symref: symref ?? "" });
26357
+ }
26358
+ const headTargets = new Set(entries.map((entry) => entry.symref).filter((symref) => symref.length > 0));
26359
+ return orderRemoteRefs(entries).map((ref) => ({ ref, primary: rankOfRef(ref, headTargets) < 2 }));
26360
+ }
26361
+ async function flowDirsOnRef(cwd, ref, flowsPath) {
26362
+ const result = await runGit2(cwd, ["ls-tree", "-z", "-d", "--name-only", "--full-tree", ref, "--", `${flowsPath}/`]);
26363
+ if (result === undefined || result.code !== 0) {
26364
+ return [];
26365
+ }
26366
+ return nulSplit(result.stdout).map((entry) => path55.posix.basename(entry)).filter((name) => /^\d{3}-/.test(name));
26367
+ }
26368
+ async function knownRemoteFlowDirs(cwd) {
26369
+ try {
26370
+ const prefix = await showPrefix(cwd);
26371
+ if (prefix === null) {
26372
+ return [];
26373
+ }
26374
+ const refs = await remoteRefs(cwd);
26375
+ if (refs.length === 0) {
26376
+ return [];
26377
+ }
26378
+ const flowsPath = `${prefix}.metaproject/flows`;
26379
+ const found = new Array(refs.length).fill([]);
26380
+ let next = 0;
26381
+ const worker = async () => {
26382
+ while (next < refs.length) {
26383
+ const index = next;
26384
+ next += 1;
26385
+ const entry = refs[index];
26386
+ if (entry === undefined) {
26387
+ continue;
26388
+ }
26389
+ const short = entry.ref.slice("refs/remotes/".length);
26390
+ found[index] = (await flowDirsOnRef(cwd, entry.ref, flowsPath)).map((dir) => ({
26391
+ ref: short,
26392
+ dir,
26393
+ primary: entry.primary
26394
+ }));
26395
+ }
26396
+ };
26397
+ await Promise.all(Array.from({ length: Math.min(CONCURRENCY, refs.length) }, () => worker()));
26398
+ return found.flat();
26399
+ } catch {
26400
+ return [];
26401
+ }
26402
+ }
26403
+ function flowNumberOfDir(dir) {
26404
+ const dash = dir.indexOf("-");
26405
+ return dash > 0 ? Number(dir.slice(0, dash)) : Number.NaN;
26406
+ }
26407
+ async function remoteFlowNumbers(cwd) {
26408
+ const dirs = await knownRemoteFlowDirs(cwd);
26409
+ const numbers = new Set;
26410
+ for (const { dir } of dirs) {
26411
+ const value = flowNumberOfDir(dir);
26412
+ if (!Number.isNaN(value)) {
26413
+ numbers.add(value);
26414
+ }
26415
+ }
26416
+ return [...numbers].sort((a, b) => a - b);
26417
+ }
26418
+
26419
+ // src/flow/folder-committed.ts
26420
+ var BATCH = 100;
26421
+ async function flowFoldersInHead(cwd, dirs) {
26422
+ const prefix = await showPrefix(cwd);
26423
+ if (prefix === null) {
26424
+ return null;
26425
+ }
26426
+ const committed = new Set;
26427
+ if (dirs.length === 0) {
26428
+ return committed;
26429
+ }
26430
+ const head = await runGit2(cwd, ["rev-parse", "--verify", "-q", "HEAD"]);
26431
+ if (head === undefined) {
26432
+ return null;
26433
+ }
26434
+ if (head.code !== 0) {
26435
+ return committed;
26436
+ }
26437
+ for (let start = 0;start < dirs.length; start += BATCH) {
26438
+ const batch = dirs.slice(start, start + BATCH);
26439
+ const paths = batch.map((dir) => `${prefix}.metaproject/flows/${dir}/flow.json`);
26440
+ const result = await runGit2(cwd, ["ls-tree", "-z", "--name-only", "--full-tree", "HEAD", "--", ...paths]);
26441
+ if (result === undefined) {
26442
+ return null;
26443
+ }
26444
+ if (result.code !== 0) {
26445
+ throw new Error(`could not read HEAD tree (git ls-tree exited ${result.code}); not treating the flow folders as uncommitted`);
26446
+ }
26447
+ const found = new Set(nulSplit(result.stdout));
26448
+ for (const [index, dir] of batch.entries()) {
26449
+ if (found.has(paths[index] ?? "")) {
26450
+ committed.add(dir);
26451
+ }
26452
+ }
26453
+ }
26454
+ return committed;
26455
+ }
26456
+
26272
26457
  // src/flow/templates.ts
26273
26458
  function renderDescription(title, source) {
26274
26459
  return `# ${title}
@@ -26353,7 +26538,7 @@ function renderJournal(createdAt) {
26353
26538
 
26354
26539
  // src/flow/service.ts
26355
26540
  async function deriveAcKinds(cwd, dir, flowId) {
26356
- const { report } = buildAcKindReport(flowId, await readFile27(acPath(cwd, dir), "utf8"));
26541
+ const { report } = buildAcKindReport(flowId, await readFile28(acPath(cwd, dir), "utf8"));
26357
26542
  return { ...report.criteria };
26358
26543
  }
26359
26544
  function prMergeState(pr, gates) {
@@ -26384,6 +26569,7 @@ function prMergeState(pr, gates) {
26384
26569
  }
26385
26570
  var UNCONFIRMED_PREFIX = "unconfirmed: ";
26386
26571
  var NO_PR_DETAIL = "no PR recorded";
26572
+ var FOLDER_UNCOMMITTED_PREFIX = "flow folder ";
26387
26573
  function completionAdmitted(status, merged) {
26388
26574
  return canTransition(status, "completing") || merged && status === "in-progress";
26389
26575
  }
@@ -26409,6 +26595,10 @@ function completionFixHint(gate, flowId) {
26409
26595
  return "keryx health run";
26410
26596
  case "confirmation":
26411
26597
  return `keryx flow confirm ${flowId} (in a terminal)`;
26598
+ case "folder-committed": {
26599
+ const dir = gate.detail.startsWith(FOLDER_UNCOMMITTED_PREFIX) ? gate.detail.slice(FOLDER_UNCOMMITTED_PREFIX.length).split(" ")[0] : undefined;
26600
+ return dir ? `git add .metaproject/flows/${dir} && git commit` : undefined;
26601
+ }
26412
26602
  default:
26413
26603
  return;
26414
26604
  }
@@ -26541,6 +26731,11 @@ function createFlowService(deps) {
26541
26731
  }
26542
26732
  gates.push(taskGate(flow));
26543
26733
  gates.push(ownerGate(flow));
26734
+ try {
26735
+ gates.push(await folderCommittedGate(cwd, dir, flow));
26736
+ } catch {
26737
+ gates.push(unevaluableGate("folder-committed"));
26738
+ }
26544
26739
  try {
26545
26740
  gates.push(await reviewGate({
26546
26741
  cwd,
@@ -26612,11 +26807,14 @@ function createFlowService(deps) {
26612
26807
  const title = input.title ?? context.issueTitle ?? provisionalTitle;
26613
26808
  const scope = await resolveAllocationScope(input.cwd);
26614
26809
  return withFileLock(scope.lockPath, async () => {
26615
- const id = await nextFlowId(input.cwd, await reservedIds(scope));
26810
+ const id = await nextFlowId(input.cwd, [
26811
+ ...await reservedIds(scope),
26812
+ ...await remoteFlowNumbers(input.cwd)
26813
+ ]);
26616
26814
  const date = now().slice(0, 10);
26617
26815
  const slug = slugify(input.slug ?? title);
26618
26816
  const dir = `${id}-${date}-${slug}`;
26619
- const absolute = path55.join(flowsRoot(input.cwd), dir);
26817
+ const absolute = path56.join(flowsRoot(input.cwd), dir);
26620
26818
  if (await pathExists(absolute)) {
26621
26819
  throw new Error(`Flow directory already exists: ${dir}`);
26622
26820
  }
@@ -26628,6 +26826,7 @@ function createFlowService(deps) {
26628
26826
  tasks: true,
26629
26827
  review: true,
26630
26828
  owner: true,
26829
+ folderCommitted: true,
26631
26830
  ...input.requireConfirmation === true || await readRequireConfirmationDefault(input.cwd) ? { confirmation: true } : {}
26632
26831
  },
26633
26832
  id,
@@ -26650,15 +26849,15 @@ function createFlowService(deps) {
26650
26849
  history: [{ at: createdAt, event: "created" }]
26651
26850
  };
26652
26851
  const sourceLabel = input.issue ?? "user description";
26653
- await writeFileAtomic(path55.join(absolute, "description.md"), renderDescription(title, sourceLabel));
26654
- await writeFileAtomic(path55.join(absolute, "context.md"), context.markdown);
26655
- await writeFileAtomic(path55.join(absolute, "plan.md"), renderPlan());
26656
- await writeFileAtomic(path55.join(absolute, "tasks.md"), renderTasksDoc());
26657
- await writeFileAtomic(path55.join(absolute, "acceptance-criteria.md"), renderAcceptanceCriteria());
26658
- await writeFileAtomic(path55.join(absolute, "journal.md"), renderJournal(createdAt));
26852
+ await writeFileAtomic(path56.join(absolute, "description.md"), renderDescription(title, sourceLabel));
26853
+ await writeFileAtomic(path56.join(absolute, "context.md"), context.markdown);
26854
+ await writeFileAtomic(path56.join(absolute, "plan.md"), renderPlan());
26855
+ await writeFileAtomic(path56.join(absolute, "tasks.md"), renderTasksDoc());
26856
+ await writeFileAtomic(path56.join(absolute, "acceptance-criteria.md"), renderAcceptanceCriteria());
26857
+ await writeFileAtomic(path56.join(absolute, "journal.md"), renderJournal(createdAt));
26659
26858
  await writeFlow(input.cwd, dir, flow);
26660
26859
  await recordAllocation(scope, { id, dir, at: createdAt, project: scope.project });
26661
- return { flow, dir: path55.relative(input.cwd, absolute), contextNotes: context.notes };
26860
+ return { flow, dir: path56.relative(input.cwd, absolute), contextNotes: context.notes };
26662
26861
  });
26663
26862
  },
26664
26863
  async list({ cwd }) {
@@ -26883,7 +27082,7 @@ function createFlowService(deps) {
26883
27082
  },
26884
27083
  async acKinds({ cwd, id }) {
26885
27084
  const { dir, flow } = await load(cwd, id);
26886
- return buildAcKindReport(flow.id, await readFile27(acPath(cwd, dir), "utf8"));
27085
+ return buildAcKindReport(flow.id, await readFile28(acPath(cwd, dir), "utf8"));
26887
27086
  },
26888
27087
  async acReseal({ cwd, id, reason }) {
26889
27088
  if (!reason?.trim()) {
@@ -27141,6 +27340,10 @@ function createFlowService(deps) {
27141
27340
  if ((await reservedIds(scope)).includes(Number(to))) {
27142
27341
  throw new Error(`Flow id ${to} was already used in this repository and cannot be reused. ` + "Pick a fresh number (see .metaproject/flows/id-map.json).");
27143
27342
  }
27343
+ const remoteUse = (await knownRemoteFlowDirs(cwd)).find((entry) => flowNumberOfDir(entry.dir) === Number(to));
27344
+ if (remoteUse) {
27345
+ throw new Error(`Flow id ${to} is already used on ${remoteUse.ref} (${safeDirName(remoteUse.dir)}) and cannot be reused. ` + "Pick a fresh number.");
27346
+ }
27144
27347
  const toDir = `${to}${fromDir.slice(3)}`;
27145
27348
  const { flow, reviewRecords } = await withFileLock(flowLockPath(cwd, fromDir), async () => {
27146
27349
  const reviewRecords = await moveFlowDirWithReviewRecords({ cwd, from, to, fromDir, toDir });
@@ -27176,6 +27379,42 @@ function createFlowService(deps) {
27176
27379
  });
27177
27380
  }
27178
27381
  }
27382
+ const warnings = [];
27383
+ const remoteDirs = await knownRemoteFlowDirs(cwd);
27384
+ if (remoteDirs.length > 0) {
27385
+ for (const dir of allDirs) {
27386
+ const clashes = remoteDirs.filter((entry) => entry.dir !== dir && flowNumberOfDir(entry.dir) === Number(flowIdOf(dir)));
27387
+ const primary = clashes.find((entry) => entry.primary);
27388
+ const other = clashes[0];
27389
+ if (primary) {
27390
+ issues.push({
27391
+ flow: dir,
27392
+ kind: "duplicate-id",
27393
+ message: `flow id ${flowIdOf(dir)} is also used on ${primary.ref} by a different flow (${safeDirName(primary.dir)})` + ` \u2014 repair with: keryx flow renumber ${dir} --to <free id> --reason "<why>"`
27394
+ });
27395
+ } else if (other) {
27396
+ warnings.push({
27397
+ flow: dir,
27398
+ kind: "branch-duplicate-id",
27399
+ message: `flow id ${flowIdOf(dir)} is also used on ${other.ref} by a different flow (${safeDirName(other.dir)});` + ` ignore it if that branch is stale, otherwise renumber one of them before it merges`
27400
+ });
27401
+ }
27402
+ }
27403
+ }
27404
+ const inHead = await flowFoldersInHead(cwd, allDirs).catch(() => {
27405
+ return null;
27406
+ });
27407
+ if (inHead !== null) {
27408
+ for (const dir of allDirs) {
27409
+ if (!inHead.has(dir)) {
27410
+ warnings.push({
27411
+ flow: dir,
27412
+ kind: "untracked",
27413
+ message: `flow folder ${dir} is not committed: commit it in the same PR as the code`
27414
+ });
27415
+ }
27416
+ }
27417
+ }
27179
27418
  for (const dir of allDirs) {
27180
27419
  let flow;
27181
27420
  try {
@@ -27192,7 +27431,7 @@ function createFlowService(deps) {
27192
27431
  issues.push({ flow: dir, kind: "schema", message: `unknown schemaVersion ${flow.schemaVersion}` });
27193
27432
  }
27194
27433
  try {
27195
- const raw = JSON.parse(await Bun.file(path55.join(flowsRoot(cwd), dir, "flow.json")).text());
27434
+ const raw = JSON.parse(await Bun.file(path56.join(flowsRoot(cwd), dir, "flow.json")).text());
27196
27435
  const validation = validateAgainstSchemaObject(flowStateSchema(), raw);
27197
27436
  if (!validation.valid) {
27198
27437
  issues.push({
@@ -27203,7 +27442,7 @@ function createFlowService(deps) {
27203
27442
  }
27204
27443
  } catch {}
27205
27444
  for (const file of ["description.md", "context.md", "plan.md", "tasks.md", "acceptance-criteria.md", "journal.md"]) {
27206
- if (!await pathExists(path55.join(flowsRoot(cwd), dir, file))) {
27445
+ if (!await pathExists(path56.join(flowsRoot(cwd), dir, file))) {
27207
27446
  issues.push({ flow: dir, kind: "structure", message: `missing ${file}` });
27208
27447
  }
27209
27448
  }
@@ -27237,15 +27476,15 @@ function createFlowService(deps) {
27237
27476
  });
27238
27477
  }
27239
27478
  }
27240
- return { ok: issues.length === 0, issues };
27479
+ return { ok: issues.length === 0, issues, warnings };
27241
27480
  }
27242
27481
  };
27243
27482
  }
27244
27483
  async function appendIdMap(cwd, entry) {
27245
- const file = path55.join(flowsRoot(cwd), "id-map.json");
27484
+ const file = path56.join(flowsRoot(cwd), "id-map.json");
27246
27485
  let entries = [];
27247
27486
  if (await pathExists(file)) {
27248
- const raw = await readFile27(file, "utf8");
27487
+ const raw = await readFile28(file, "utf8");
27249
27488
  try {
27250
27489
  const parsed = JSON.parse(raw);
27251
27490
  if (!Array.isArray(parsed)) {
@@ -27253,7 +27492,7 @@ async function appendIdMap(cwd, entry) {
27253
27492
  }
27254
27493
  entries = parsed;
27255
27494
  } catch (error) {
27256
- throw new Error(`Cannot read ${path55.relative(cwd, file)}: ${error instanceof Error ? error.message : String(error)}`);
27495
+ throw new Error(`Cannot read ${path56.relative(cwd, file)}: ${error instanceof Error ? error.message : String(error)}`);
27257
27496
  }
27258
27497
  }
27259
27498
  entries.push(entry);
@@ -27347,6 +27586,27 @@ function ownerGate(flow) {
27347
27586
  }
27348
27587
  return { name: "owner", status: "pass", detail: `owner: ${flow.owner.value}` };
27349
27588
  }
27589
+ async function folderCommittedGate(cwd, dir, flow) {
27590
+ if (!flow.gates?.folderCommitted) {
27591
+ return {
27592
+ name: "folder-committed",
27593
+ status: "skipped",
27594
+ detail: "folder-committed gate not enabled for this package (created before the gate); " + "flows created by this keryx version opt in automatically"
27595
+ };
27596
+ }
27597
+ const committed = await flowFoldersInHead(cwd, [dir]);
27598
+ if (committed === null) {
27599
+ return { name: "folder-committed", status: "skipped", detail: "not a git repository; nothing to compare the flow folder with" };
27600
+ }
27601
+ if (!committed.has(dir)) {
27602
+ return {
27603
+ name: "folder-committed",
27604
+ status: "fail",
27605
+ detail: `${FOLDER_UNCOMMITTED_PREFIX}${dir} is not committed. Commit it (git add .metaproject/flows/${dir} && git commit) ` + "in the PR that carries the code, then run flow complete again"
27606
+ };
27607
+ }
27608
+ return { name: "folder-committed", status: "pass", detail: `${dir} is committed in HEAD` };
27609
+ }
27350
27610
  function confirmPreconditionError(flow, merged) {
27351
27611
  const confirmable = flow.status === "implemented" || flow.status === "in-progress" && merged;
27352
27612
  if (!confirmable) {
@@ -27504,9 +27764,9 @@ __export(exports_service5, {
27504
27764
  });
27505
27765
 
27506
27766
  // src/gdgraph/build.ts
27507
- import { mkdir as mkdir21, readdir as readdir13, readFile as readFile38, writeFile as writeFile15 } from "fs/promises";
27767
+ import { mkdir as mkdir21, readdir as readdir14, readFile as readFile39, writeFile as writeFile15 } from "fs/promises";
27508
27768
  import { existsSync as existsSync7 } from "fs";
27509
- import path75 from "path";
27769
+ import path76 from "path";
27510
27770
 
27511
27771
  // src/gdgraph/types.ts
27512
27772
  var UNKNOWN_IMPORT_KIND = "unknown-static";
@@ -27571,8 +27831,8 @@ async function buildGraph(projectRoot) {
27571
27831
  const assetNodes = new Map;
27572
27832
  const fileRecords = [];
27573
27833
  for (const file of files) {
27574
- const absolutePath = path75.join(projectRoot, file);
27575
- const content = await readFile38(absolutePath, "utf8");
27834
+ const absolutePath = path76.join(projectRoot, file);
27835
+ const content = await readFile39(absolutePath, "utf8");
27576
27836
  fileRecords.push({ path: file, content });
27577
27837
  const language = getLanguage(file);
27578
27838
  const resolver = pickResolver(resolvers, language);
@@ -27624,24 +27884,24 @@ async function collectSourceFiles(projectRoot) {
27624
27884
  const result = [];
27625
27885
  const skippedDirectories = [];
27626
27886
  async function walk(relativeDir) {
27627
- const absoluteDir = path75.join(projectRoot, relativeDir);
27628
- const entries = await readdir13(absoluteDir, { withFileTypes: true });
27887
+ const absoluteDir = path76.join(projectRoot, relativeDir);
27888
+ const entries = await readdir14(absoluteDir, { withFileTypes: true });
27629
27889
  for (const entry of entries) {
27630
27890
  if (entry.isDirectory()) {
27631
27891
  if (IGNORE_DIRS.has(entry.name)) {
27632
- skippedDirectories.push(normalizePath2(path75.posix.join(relativeDir, entry.name)).replace(/^\.\//, ""));
27892
+ skippedDirectories.push(normalizePath2(path76.posix.join(relativeDir, entry.name)).replace(/^\.\//, ""));
27633
27893
  continue;
27634
27894
  }
27635
- await walk(normalizePath2(path75.posix.join(relativeDir, entry.name)));
27895
+ await walk(normalizePath2(path76.posix.join(relativeDir, entry.name)));
27636
27896
  continue;
27637
27897
  }
27638
27898
  if (!entry.isFile()) {
27639
27899
  continue;
27640
27900
  }
27641
- if (!SOURCE_EXTENSIONS.includes(path75.extname(entry.name))) {
27901
+ if (!SOURCE_EXTENSIONS.includes(path76.extname(entry.name))) {
27642
27902
  continue;
27643
27903
  }
27644
- result.push(normalizePath2(path75.posix.join(relativeDir, entry.name)).replace(/^\.\//, ""));
27904
+ result.push(normalizePath2(path76.posix.join(relativeDir, entry.name)).replace(/^\.\//, ""));
27645
27905
  }
27646
27906
  }
27647
27907
  await walk(".");
@@ -27723,8 +27983,8 @@ function resolveImport(projectRoot, fromFile, specifier, fileSet, resolver) {
27723
27983
  }
27724
27984
  function resolveAssetImport(projectRoot, fromFile, specifier, resolver) {
27725
27985
  for (const candidate of importCandidateBases(projectRoot, fromFile, specifier, resolver)) {
27726
- const extension = path75.posix.extname(candidate);
27727
- if (ASSET_EXTENSIONS.includes(extension) && existsSync7(path75.join(projectRoot, candidate))) {
27986
+ const extension = path76.posix.extname(candidate);
27987
+ if (ASSET_EXTENSIONS.includes(extension) && existsSync7(path76.join(projectRoot, candidate))) {
27728
27988
  return candidate;
27729
27989
  }
27730
27990
  }
@@ -27733,17 +27993,17 @@ function resolveAssetImport(projectRoot, fromFile, specifier, resolver) {
27733
27993
  function importCandidateBases(projectRoot, fromFile, specifier, resolver) {
27734
27994
  const normalizedSpecifier = stripImportSuffix(specifier);
27735
27995
  if (normalizedSpecifier.startsWith(".") && getLanguage(fromFile) !== "python") {
27736
- const fromDir = path75.posix.dirname(fromFile);
27737
- return [normalizePath2(path75.posix.normalize(path75.posix.join(fromDir, normalizedSpecifier)))];
27996
+ const fromDir = path76.posix.dirname(fromFile);
27997
+ return [normalizePath2(path76.posix.normalize(path76.posix.join(fromDir, normalizedSpecifier)))];
27738
27998
  }
27739
- return resolver.candidateBases(normalizedSpecifier, fromFile).map((candidate) => normalizePath2(path75.relative(projectRoot, path75.join(projectRoot, candidate))));
27999
+ return resolver.candidateBases(normalizedSpecifier, fromFile).map((candidate) => normalizePath2(path76.relative(projectRoot, path76.join(projectRoot, candidate))));
27740
28000
  }
27741
28001
  function resolveSourceCandidate(base, fileSet) {
27742
28002
  const candidates = [
27743
28003
  base,
27744
28004
  ...SOURCE_RESOLUTION_EXTENSIONS.map((extension) => `${base}${extension}`),
27745
- ...SOURCE_RESOLUTION_EXTENSIONS.map((extension) => path75.posix.join(base, `index${extension}`)),
27746
- path75.posix.join(base, "__init__.py")
28005
+ ...SOURCE_RESOLUTION_EXTENSIONS.map((extension) => path76.posix.join(base, `index${extension}`)),
28006
+ path76.posix.join(base, "__init__.py")
27747
28007
  ];
27748
28008
  return candidates.find((candidate) => fileSet.has(candidate)) ?? null;
27749
28009
  }
@@ -27773,20 +28033,20 @@ async function loadJavaResolver(projectRoot) {
27773
28033
  return createJavaResolver(roots);
27774
28034
  }
27775
28035
  async function discoverJavaSourceRoots(projectRoot) {
27776
- const pomPath = path75.join(projectRoot, "pom.xml");
28036
+ const pomPath = path76.join(projectRoot, "pom.xml");
27777
28037
  if (existsSync7(pomPath)) {
27778
28038
  try {
27779
- const roots = parseMavenSourceRoots(await readFile38(pomPath, "utf8"));
28039
+ const roots = parseMavenSourceRoots(await readFile39(pomPath, "utf8"));
27780
28040
  if (roots.length > 0) {
27781
28041
  return roots;
27782
28042
  }
27783
28043
  } catch {}
27784
28044
  }
27785
28045
  for (const gradleName of ["build.gradle", "build.gradle.kts"]) {
27786
- const gradlePath = path75.join(projectRoot, gradleName);
28046
+ const gradlePath = path76.join(projectRoot, gradleName);
27787
28047
  if (existsSync7(gradlePath)) {
27788
28048
  try {
27789
- const roots = parseGradleSourceRoots(await readFile38(gradlePath, "utf8"));
28049
+ const roots = parseGradleSourceRoots(await readFile39(gradlePath, "utf8"));
27790
28050
  if (roots.length > 0) {
27791
28051
  return roots;
27792
28052
  }
@@ -27805,12 +28065,12 @@ function createJavaResolver(sourceRoots) {
27805
28065
  return [];
27806
28066
  }
27807
28067
  const relative = specifier.split(".").join("/");
27808
- return sourceRoots.map((root) => normalizePath2(path75.posix.join(root, relative)));
28068
+ return sourceRoots.map((root) => normalizePath2(path76.posix.join(root, relative)));
27809
28069
  }
27810
28070
  };
27811
28071
  }
27812
28072
  function loadPythonResolver(projectRoot) {
27813
- const hasSrc = existsSync7(path75.join(projectRoot, "src"));
28073
+ const hasSrc = existsSync7(path76.join(projectRoot, "src"));
27814
28074
  return createPythonResolver(hasSrc);
27815
28075
  }
27816
28076
  function createPythonResolver(hasSrc) {
@@ -27823,16 +28083,16 @@ function createPythonResolver(hasSrc) {
27823
28083
  if (specifier.startsWith(".")) {
27824
28084
  const dots = /^\.+/.exec(specifier)?.[0].length ?? 0;
27825
28085
  const rest = specifier.slice(dots);
27826
- let baseDir = path75.posix.dirname(fromFile);
28086
+ let baseDir = path76.posix.dirname(fromFile);
27827
28087
  for (let level = 1;level < dots; level += 1) {
27828
- baseDir = path75.posix.dirname(baseDir);
28088
+ baseDir = path76.posix.dirname(baseDir);
27829
28089
  }
27830
28090
  const suffix = rest ? rest.split(".").join("/") : "";
27831
- const base = suffix ? path75.posix.join(baseDir, suffix) : baseDir;
28091
+ const base = suffix ? path76.posix.join(baseDir, suffix) : baseDir;
27832
28092
  return [normalizePath2(base)];
27833
28093
  }
27834
28094
  const relative = specifier.split(".").join("/");
27835
- return roots.map((root) => normalizePath2(root ? path75.posix.join(root, relative) : relative));
28095
+ return roots.map((root) => normalizePath2(root ? path76.posix.join(root, relative) : relative));
27836
28096
  }
27837
28097
  };
27838
28098
  }
@@ -27841,8 +28101,8 @@ function parseMavenSourceRoots(pomXml) {
27841
28101
  for (const match of pomXml.matchAll(/<module>\s*([^<]+?)\s*<\/module>/g)) {
27842
28102
  const moduleDir = match[1]?.trim();
27843
28103
  if (moduleDir && !moduleDir.includes("${")) {
27844
- roots.add(normalizePath2(path75.posix.join(moduleDir, "src/main/java")));
27845
- roots.add(normalizePath2(path75.posix.join(moduleDir, "src/test/java")));
28104
+ roots.add(normalizePath2(path76.posix.join(moduleDir, "src/main/java")));
28105
+ roots.add(normalizePath2(path76.posix.join(moduleDir, "src/test/java")));
27846
28106
  }
27847
28107
  }
27848
28108
  for (const tag of ["sourceDirectory", "testSourceDirectory"]) {
@@ -27875,7 +28135,7 @@ function parseGradleSourceRoots(buildGradle) {
27875
28135
  var TSCONFIG_EXTENDS_MAX_DEPTH = 10;
27876
28136
  async function loadTsconfigResolver(projectRoot) {
27877
28137
  const empty = createTsconfigResolver(null, []);
27878
- const tsconfigPath = path75.join(projectRoot, "tsconfig.json");
28138
+ const tsconfigPath = path76.join(projectRoot, "tsconfig.json");
27879
28139
  if (!existsSync7(tsconfigPath)) {
27880
28140
  return empty;
27881
28141
  }
@@ -27888,12 +28148,12 @@ async function loadTsconfigResolver(projectRoot) {
27888
28148
  return createTsconfigResolver(resolved.baseUrl, paths);
27889
28149
  }
27890
28150
  function toProjectRelativeDir(projectRoot, absoluteDir) {
27891
- const relative = normalizePath2(path75.relative(projectRoot, absoluteDir)).replace(/^\.\//, "");
28151
+ const relative = normalizePath2(path76.relative(projectRoot, absoluteDir)).replace(/^\.\//, "");
27892
28152
  return relative === "." ? "" : relative;
27893
28153
  }
27894
28154
  async function readTsconfigJson(configPath) {
27895
28155
  try {
27896
- const raw = await readFile38(configPath, "utf8");
28156
+ const raw = await readFile39(configPath, "utf8");
27897
28157
  return JSON.parse(stripJsonComments(raw));
27898
28158
  } catch {
27899
28159
  return null;
@@ -27903,11 +28163,11 @@ function resolveTsconfigExtendsPath(configDir, extendsSpecifier) {
27903
28163
  if (!extendsSpecifier.startsWith(".") && !extendsSpecifier.startsWith("/")) {
27904
28164
  return null;
27905
28165
  }
27906
- const resolved = path75.resolve(configDir, extendsSpecifier);
28166
+ const resolved = path76.resolve(configDir, extendsSpecifier);
27907
28167
  return resolved.endsWith(".json") ? resolved : `${resolved}.json`;
27908
28168
  }
27909
28169
  async function resolveTsconfigOptions(configPath, visited, depth, projectRoot) {
27910
- const resolvedPath = path75.resolve(configPath);
28170
+ const resolvedPath = path76.resolve(configPath);
27911
28171
  if (depth > TSCONFIG_EXTENDS_MAX_DEPTH || visited.has(resolvedPath)) {
27912
28172
  return null;
27913
28173
  }
@@ -27918,15 +28178,15 @@ async function resolveTsconfigOptions(configPath, visited, depth, projectRoot) {
27918
28178
  }
27919
28179
  let inherited = null;
27920
28180
  if (typeof parsed.extends === "string") {
27921
- const basePath = resolveTsconfigExtendsPath(path75.dirname(resolvedPath), parsed.extends);
28181
+ const basePath = resolveTsconfigExtendsPath(path76.dirname(resolvedPath), parsed.extends);
27922
28182
  if (basePath) {
27923
28183
  inherited = await resolveTsconfigOptions(basePath, visited, depth + 1, projectRoot);
27924
28184
  }
27925
28185
  }
27926
- const configDir = path75.dirname(resolvedPath);
28186
+ const configDir = path76.dirname(resolvedPath);
27927
28187
  const declaringDir = toProjectRelativeDir(projectRoot, configDir);
27928
28188
  const options = parsed.compilerOptions ?? {};
27929
- const ownBaseUrl = typeof options.baseUrl === "string" ? toProjectRelativeDir(projectRoot, path75.resolve(configDir, options.baseUrl)) : null;
28189
+ const ownBaseUrl = typeof options.baseUrl === "string" ? toProjectRelativeDir(projectRoot, path76.resolve(configDir, options.baseUrl)) : null;
27930
28190
  const baseUrl = ownBaseUrl ?? inherited?.baseUrl ?? null;
27931
28191
  const ownPaths = isRecord4(options.paths) ? Object.entries(options.paths).filter((entry) => Array.isArray(entry[1])).map(([pattern, targets]) => ({
27932
28192
  pattern,
@@ -27955,7 +28215,7 @@ function createTsconfigResolver(baseUrl, mappings) {
27955
28215
  }
27956
28216
  }
27957
28217
  if (baseUrl !== null) {
27958
- candidates.push(normalizePath2(path75.posix.join(baseUrl, normalizedSpecifier)));
28218
+ candidates.push(normalizePath2(path76.posix.join(baseUrl, normalizedSpecifier)));
27959
28219
  }
27960
28220
  return [...new Set(candidates.map((candidate) => candidate.replace(/^\.\//, "")))];
27961
28221
  }
@@ -27975,7 +28235,7 @@ function matchPathPattern(pattern, specifier) {
27975
28235
  }
27976
28236
  function applyPathTarget(base, target, wildcard) {
27977
28237
  const replaced = target.includes("*") ? target.replace("*", wildcard) : target;
27978
- return normalizePath2(path75.posix.normalize(path75.posix.join(base, replaced)));
28238
+ return normalizePath2(path76.posix.normalize(path76.posix.join(base, replaced)));
27979
28239
  }
27980
28240
  function stripJsonComments(source) {
27981
28241
  let out = "";
@@ -28028,21 +28288,21 @@ function isRecord4(value) {
28028
28288
  return typeof value === "object" && value !== null && !Array.isArray(value);
28029
28289
  }
28030
28290
  async function writeGraph(projectRoot, graph) {
28031
- const storageDir = path75.join(projectRoot, ".metaproject", "data", "gdgraph", "storage");
28032
- const artifactsDir = path75.join(projectRoot, ".metaproject", "data", "gdgraph", "artifacts");
28291
+ const storageDir = path76.join(projectRoot, ".metaproject", "data", "gdgraph", "storage");
28292
+ const artifactsDir = path76.join(projectRoot, ".metaproject", "data", "gdgraph", "artifacts");
28033
28293
  await mkdir21(storageDir, { recursive: true });
28034
28294
  await mkdir21(artifactsDir, { recursive: true });
28035
- await writeFile15(path75.join(storageDir, "nodes.jsonl"), graph.nodes.map((node) => JSON.stringify(node)).join(`
28295
+ await writeFile15(path76.join(storageDir, "nodes.jsonl"), graph.nodes.map((node) => JSON.stringify(node)).join(`
28036
28296
  `) + `
28037
28297
  `, "utf8");
28038
- await writeFile15(path75.join(storageDir, "edges.jsonl"), graph.edges.map((edge) => JSON.stringify(edge)).join(`
28298
+ await writeFile15(path76.join(storageDir, "edges.jsonl"), graph.edges.map((edge) => JSON.stringify(edge)).join(`
28039
28299
  `) + `
28040
28300
  `, "utf8");
28041
- await writeFile15(path75.join(artifactsDir, "module-map.json"), JSON.stringify(buildModuleMap(graph), null, 2) + `
28301
+ await writeFile15(path76.join(artifactsDir, "module-map.json"), JSON.stringify(buildModuleMap(graph), null, 2) + `
28042
28302
  `, "utf8");
28043
28303
  }
28044
28304
  async function writeSummary(projectRoot, graph, collection) {
28045
- const artifactsDir = path75.join(projectRoot, ".metaproject", "data", "gdgraph", "artifacts");
28305
+ const artifactsDir = path76.join(projectRoot, ".metaproject", "data", "gdgraph", "artifacts");
28046
28306
  await mkdir21(artifactsDir, { recursive: true });
28047
28307
  const unresolved = graph.edges.filter((edge) => edge.kind === "unresolved");
28048
28308
  const imports = graph.edges.filter((edge) => edge.kind === "imports");
@@ -28057,7 +28317,7 @@ async function writeSummary(projectRoot, graph, collection) {
28057
28317
  `);
28058
28318
  const skippedList = collection.skippedDirectories.length > 0 ? collection.skippedDirectories.slice(0, 30).map((dir) => `- \`${dir}\``).join(`
28059
28319
  `) : "- none";
28060
- const summaryPath = path75.join(artifactsDir, "summary.md");
28320
+ const summaryPath = path76.join(artifactsDir, "summary.md");
28061
28321
  const content = `# gdgraph Summary
28062
28322
 
28063
28323
  ## Stats
@@ -28138,7 +28398,7 @@ function groupBy(items, getKey) {
28138
28398
  }
28139
28399
  function unresolvedType(specifier) {
28140
28400
  const stripped = stripImportSuffix(specifier);
28141
- const extension = path75.posix.extname(stripped);
28401
+ const extension = path76.posix.extname(stripped);
28142
28402
  if (extension) {
28143
28403
  return extension;
28144
28404
  }
@@ -28148,13 +28408,13 @@ function unresolvedType(specifier) {
28148
28408
  return "package";
28149
28409
  }
28150
28410
  function normalizePath2(value) {
28151
- return value.split(path75.sep).join("/");
28411
+ return value.split(path76.sep).join("/");
28152
28412
  }
28153
28413
 
28154
28414
  // src/gdgraph/target.ts
28155
- import path76 from "path";
28415
+ import path77 from "path";
28156
28416
  function normalizeTarget(target) {
28157
- return target.replace(/^\.\//, "").split(path76.sep).join("/");
28417
+ return target.replace(/^\.\//, "").split(path77.sep).join("/");
28158
28418
  }
28159
28419
  function resolveGraphTarget(graph, target) {
28160
28420
  const normalized = normalizeTarget(target);
@@ -28246,16 +28506,16 @@ function normalizeDepth(depth) {
28246
28506
  init_config3();
28247
28507
 
28248
28508
  // src/gdgraph/query.ts
28249
- import { readFile as readFile39 } from "fs/promises";
28250
- import path77 from "path";
28509
+ import { readFile as readFile40 } from "fs/promises";
28510
+ import path78 from "path";
28251
28511
  async function loadGraph(projectRoot) {
28252
- const storageDir = path77.join(projectRoot, ".metaproject", "data", "gdgraph", "storage");
28253
- const nodes = await readJsonl(path77.join(storageDir, "nodes.jsonl"));
28254
- const edges = await readJsonl(path77.join(storageDir, "edges.jsonl"));
28255
- const symbols = await readJsonl(path77.join(storageDir, "symbols.jsonl"));
28256
- const calls = await readJsonl(path77.join(storageDir, "calls.jsonl"));
28257
- const wikiPages = await readJsonl(path77.join(storageDir, "wiki-pages.jsonl"));
28258
- const describes = await readJsonl(path77.join(storageDir, "describes.jsonl"));
28512
+ const storageDir = path78.join(projectRoot, ".metaproject", "data", "gdgraph", "storage");
28513
+ const nodes = await readJsonl(path78.join(storageDir, "nodes.jsonl"));
28514
+ const edges = await readJsonl(path78.join(storageDir, "edges.jsonl"));
28515
+ const symbols = await readJsonl(path78.join(storageDir, "symbols.jsonl"));
28516
+ const calls = await readJsonl(path78.join(storageDir, "calls.jsonl"));
28517
+ const wikiPages = await readJsonl(path78.join(storageDir, "wiki-pages.jsonl"));
28518
+ const describes = await readJsonl(path78.join(storageDir, "describes.jsonl"));
28259
28519
  const graph = { nodes, edges };
28260
28520
  if (symbols.length > 0) {
28261
28521
  graph.symbols = symbols;
@@ -28315,7 +28575,7 @@ async function bunfigPreloadRoots(projectRoot) {
28315
28575
  const roots = new Set;
28316
28576
  let text;
28317
28577
  try {
28318
- text = await readFile39(path77.join(projectRoot, "bunfig.toml"), "utf8");
28578
+ text = await readFile40(path78.join(projectRoot, "bunfig.toml"), "utf8");
28319
28579
  } catch {
28320
28580
  return roots;
28321
28581
  }
@@ -28329,8 +28589,8 @@ async function bunfigPreloadRoots(projectRoot) {
28329
28589
  if (raw.length === 0) {
28330
28590
  continue;
28331
28591
  }
28332
- const absolute = path77.resolve(projectRoot, raw);
28333
- const relative = path77.relative(projectRoot, absolute).split(path77.sep).join("/");
28592
+ const absolute = path78.resolve(projectRoot, raw);
28593
+ const relative = path78.relative(projectRoot, absolute).split(path78.sep).join("/");
28334
28594
  roots.add(relative);
28335
28595
  }
28336
28596
  }
@@ -28379,7 +28639,7 @@ function getCycles(graph) {
28379
28639
  async function readJsonl(filePath) {
28380
28640
  let content;
28381
28641
  try {
28382
- content = await readFile39(filePath, "utf8");
28642
+ content = await readFile40(filePath, "utf8");
28383
28643
  } catch {
28384
28644
  return [];
28385
28645
  }
@@ -28403,7 +28663,7 @@ function canonicalCycle(cycle) {
28403
28663
 
28404
28664
  // src/gdgraph/repomap.ts
28405
28665
  import { mkdir as mkdir22, writeFile as writeFile16 } from "fs/promises";
28406
- import path78 from "path";
28666
+ import path79 from "path";
28407
28667
 
28408
28668
  // src/gdgraph/pagerank.ts
28409
28669
  function personalizedPageRank(nodes, edges, options) {
@@ -28514,7 +28774,7 @@ function overflowContent(required, missing, budget) {
28514
28774
  `);
28515
28775
  }
28516
28776
  function repomapArtifactPath(cwd) {
28517
- return path78.join(cwd, ".metaproject", "data", "gdgraph", "artifacts", "repomap.md");
28777
+ return path79.join(cwd, ".metaproject", "data", "gdgraph", "artifacts", "repomap.md");
28518
28778
  }
28519
28779
  function buildRankEdges(graph, config) {
28520
28780
  const edges = [];
@@ -28659,7 +28919,7 @@ function computeRepomap(graph, config, options = {}) {
28659
28919
  async function writeRepomap(cwd, graph, config, options = {}) {
28660
28920
  const result = computeRepomap(graph, config, options);
28661
28921
  const artifactPath = repomapArtifactPath(cwd);
28662
- await mkdir22(path78.dirname(artifactPath), { recursive: true });
28922
+ await mkdir22(path79.dirname(artifactPath), { recursive: true });
28663
28923
  await writeFile16(artifactPath, result.content, "utf8");
28664
28924
  return { ...result, path: artifactPath };
28665
28925
  }
@@ -28741,18 +29001,18 @@ init_section_tombstone();
28741
29001
 
28742
29002
  // src/forgetting/journal.ts
28743
29003
  init_fs();
28744
- import { appendFile as appendFile4, mkdir as mkdir23, readFile as readFile40, stat as stat11 } from "fs/promises";
28745
- import path79 from "path";
29004
+ import { appendFile as appendFile4, mkdir as mkdir23, readFile as readFile41, stat as stat12 } from "fs/promises";
29005
+ import path80 from "path";
28746
29006
  function forgettingDataDir(cwd) {
28747
- return path79.join(cwd, ".metaproject", "data", "forgetting");
29007
+ return path80.join(cwd, ".metaproject", "data", "forgetting");
28748
29008
  }
28749
29009
  function deletionJournalPath(cwd) {
28750
- return path79.join(forgettingDataDir(cwd), "journal.jsonl");
29010
+ return path80.join(forgettingDataDir(cwd), "journal.jsonl");
28751
29011
  }
28752
29012
  async function readDeletionJournal(cwd) {
28753
29013
  const file = deletionJournalPath(cwd);
28754
29014
  try {
28755
- await stat11(file);
29015
+ await stat12(file);
28756
29016
  } catch (error) {
28757
29017
  if (isNotFound(error)) {
28758
29018
  return { state: "absent", path: file };
@@ -28766,7 +29026,7 @@ async function readDeletionJournal(cwd) {
28766
29026
  }
28767
29027
  let content;
28768
29028
  try {
28769
- content = await readFile40(file, "utf8");
29029
+ content = await readFile41(file, "utf8");
28770
29030
  } catch (error) {
28771
29031
  const message = error instanceof Error ? error.message : String(error);
28772
29032
  return {
@@ -29166,12 +29426,12 @@ __export(exports_service7, {
29166
29426
  gateExitCode: () => gateExitCode,
29167
29427
  readWikiFreshnessMetric: () => readWikiFreshnessMetric
29168
29428
  });
29169
- import path99 from "path";
29429
+ import path100 from "path";
29170
29430
 
29171
29431
  // src/health/config.ts
29172
29432
  init_fs();
29173
29433
  init_json();
29174
- import path80 from "path";
29434
+ import path81 from "path";
29175
29435
  var DEFAULT_HEALTH_CONFIG = {
29176
29436
  schemaVersion: 2,
29177
29437
  ignore: {
@@ -29227,7 +29487,7 @@ var DEFAULT_HEALTH_CONFIG = {
29227
29487
  }
29228
29488
  };
29229
29489
  function configPath2(cwd) {
29230
- return path80.join(cwd, ".metaproject", "health.config.json");
29490
+ return path81.join(cwd, ".metaproject", "health.config.json");
29231
29491
  }
29232
29492
  var STRICTEST_GATE = {
29233
29493
  failOnPriorities: ["P0", "P1", "P2", "P3"],
@@ -29278,7 +29538,7 @@ async function loadHealthConfig(cwd) {
29278
29538
  // src/health/run.ts
29279
29539
  init_fs();
29280
29540
  import { mkdir as mkdir27, writeFile as writeFile20 } from "fs/promises";
29281
- import path98 from "path";
29541
+ import path99 from "path";
29282
29542
 
29283
29543
  // src/metrics/provenance.ts
29284
29544
  async function collectGitProvenance(cwd) {
@@ -29378,12 +29638,12 @@ function computeGate2(input) {
29378
29638
  }
29379
29639
 
29380
29640
  // src/health/scopes.ts
29381
- import path83 from "path";
29641
+ import path84 from "path";
29382
29642
 
29383
29643
  // src/health/util.ts
29384
29644
  init_fs();
29385
- import { mkdir as mkdir24, readFile as readFile41, readdir as readdir14, writeFile as writeFile17 } from "fs/promises";
29386
- import path81 from "path";
29645
+ import { mkdir as mkdir24, readFile as readFile42, readdir as readdir15, writeFile as writeFile17 } from "fs/promises";
29646
+ import path82 from "path";
29387
29647
  var IGNORED_DIRS = new Set([
29388
29648
  "node_modules",
29389
29649
  ".git",
@@ -29427,14 +29687,14 @@ async function toolVersion(command, cwd) {
29427
29687
  }
29428
29688
  }
29429
29689
  function dataRoot3(cwd) {
29430
- return path81.join(cwd, ".metaproject", "data", "health");
29690
+ return path82.join(cwd, ".metaproject", "data", "health");
29431
29691
  }
29432
29692
  async function writeRaw(cwd, source, content, stamp) {
29433
- const dir = path81.join(dataRoot3(cwd), "raw", source);
29693
+ const dir = path82.join(dataRoot3(cwd), "raw", source);
29434
29694
  await mkdir24(dir, { recursive: true });
29435
- const file = path81.join(dir, `${stamp}.log`);
29695
+ const file = path82.join(dir, `${stamp}.log`);
29436
29696
  await writeFile17(file, content, "utf8");
29437
- return path81.relative(cwd, file);
29697
+ return path82.relative(cwd, file);
29438
29698
  }
29439
29699
  async function listSourceFiles(cwd, ignorePaths = []) {
29440
29700
  const { files } = await listSourceFilesWithReasons(cwd, ignorePaths);
@@ -29452,9 +29712,9 @@ async function listSourceFilesWithReasons(cwd, ignorePaths = []) {
29452
29712
  async function walk2(root, dir, out, incompleteReasons) {
29453
29713
  let entries;
29454
29714
  try {
29455
- entries = await readdir14(dir, { withFileTypes: true });
29715
+ entries = await readdir15(dir, { withFileTypes: true });
29456
29716
  } catch (error) {
29457
- incompleteReasons.push(`${path81.relative(root, dir) || "."}: ${error instanceof Error ? error.message : String(error)}`);
29717
+ incompleteReasons.push(`${path82.relative(root, dir) || "."}: ${error instanceof Error ? error.message : String(error)}`);
29458
29718
  return;
29459
29719
  }
29460
29720
  for (const entry of entries) {
@@ -29462,14 +29722,14 @@ async function walk2(root, dir, out, incompleteReasons) {
29462
29722
  if (entry.isDirectory() && !IGNORED_DIRS.has(entry.name)) {}
29463
29723
  continue;
29464
29724
  }
29465
- const abs = path81.join(dir, entry.name);
29725
+ const abs = path82.join(dir, entry.name);
29466
29726
  if (entry.isDirectory()) {
29467
29727
  if (IGNORED_DIRS.has(entry.name)) {
29468
29728
  continue;
29469
29729
  }
29470
29730
  await walk2(root, abs, out, incompleteReasons);
29471
- } else if (entry.isFile() && SOURCE_EXT.has(path81.extname(entry.name))) {
29472
- out.push(path81.relative(root, abs));
29731
+ } else if (entry.isFile() && SOURCE_EXT.has(path82.extname(entry.name))) {
29732
+ out.push(path82.relative(root, abs));
29473
29733
  }
29474
29734
  }
29475
29735
  }
@@ -29484,7 +29744,7 @@ function moduleOfFile(file) {
29484
29744
  return null;
29485
29745
  }
29486
29746
  function isSourceFile(file) {
29487
- return SOURCE_EXT.has(path81.extname(file));
29747
+ return SOURCE_EXT.has(path82.extname(file));
29488
29748
  }
29489
29749
  function matchesAnyPattern(file, patterns) {
29490
29750
  const normalized = file.replace(/\\/g, "/").replace(/^\.\//, "");
@@ -29583,8 +29843,8 @@ function rankHotspots(files, churn, sourceAnalysis) {
29583
29843
 
29584
29844
  // src/health/source-analysis.ts
29585
29845
  init_fs();
29586
- import { readFile as readFile42 } from "fs/promises";
29587
- import path82 from "path";
29846
+ import { readFile as readFile43 } from "fs/promises";
29847
+ import path83 from "path";
29588
29848
 
29589
29849
  // src/health/metrics/complexity.ts
29590
29850
  var CONTROL_KEYWORDS = new Set([
@@ -29818,11 +30078,11 @@ async function analyzeSourceFiles(cwd, sourceFiles) {
29818
30078
  return new Map(entries.filter((entry) => entry !== null));
29819
30079
  }
29820
30080
  async function analyzeSourceFile(cwd, file) {
29821
- const abs = path82.join(cwd, file);
30081
+ const abs = path83.join(cwd, file);
29822
30082
  if (!await pathExists(abs)) {
29823
30083
  return null;
29824
30084
  }
29825
- const content = await readFile42(abs, "utf8");
30085
+ const content = await readFile43(abs, "utf8");
29826
30086
  return [
29827
30087
  file,
29828
30088
  {
@@ -29891,14 +30151,14 @@ async function computeMetrics(input) {
29891
30151
  }
29892
30152
  const components = new Map;
29893
30153
  for (const file of sourceFiles) {
29894
- const dir = path83.posix.dirname(file);
30154
+ const dir = path84.posix.dirname(file);
29895
30155
  if (dir === "." || dir === moduleOfFile(file)) {
29896
30156
  continue;
29897
30157
  }
29898
30158
  components.set(dir, [...components.get(dir) ?? [], file]);
29899
30159
  }
29900
30160
  for (const [name, files] of [...components.entries()].sort()) {
29901
- const compFindings = findings.filter((f) => f.file && path83.posix.dirname(f.file) === name);
30161
+ const compFindings = findings.filter((f) => f.file && path84.posix.dirname(f.file) === name);
29902
30162
  scopes.push(build("component", `component:${name}`, name, files, compFindings, averageCoverage(files, coverage)));
29903
30163
  }
29904
30164
  const findingFiles = findings.map((f) => f.file).filter((f) => Boolean(f));
@@ -29942,10 +30202,10 @@ function tally2(values) {
29942
30202
 
29943
30203
  // src/health/baseline.ts
29944
30204
  init_fs();
29945
- import { mkdir as mkdir25, readFile as readFile43, writeFile as writeFile18 } from "fs/promises";
29946
- import path84 from "path";
30205
+ import { mkdir as mkdir25, readFile as readFile44, writeFile as writeFile18 } from "fs/promises";
30206
+ import path85 from "path";
29947
30207
  function baselinePath(cwd) {
29948
- return path84.join(cwd, ".metaproject", "health", "baselines", "scores.json");
30208
+ return path85.join(cwd, ".metaproject", "health", "baselines", "scores.json");
29949
30209
  }
29950
30210
  async function loadBaseline(cwd) {
29951
30211
  const file = baselinePath(cwd);
@@ -29953,7 +30213,7 @@ async function loadBaseline(cwd) {
29953
30213
  return new Map;
29954
30214
  }
29955
30215
  try {
29956
- const data = JSON.parse(await readFile43(file, "utf8"));
30216
+ const data = JSON.parse(await readFile44(file, "utf8"));
29957
30217
  return new Map(Object.entries(data.scopes ?? {}));
29958
30218
  } catch {
29959
30219
  return new Map;
@@ -29977,7 +30237,7 @@ async function writeBaseline(cwd, metrics, generatedAt, selector) {
29977
30237
  scopes[key] = value;
29978
30238
  }
29979
30239
  const file = baselinePath(cwd);
29980
- await mkdir25(path84.dirname(file), { recursive: true });
30240
+ await mkdir25(path85.dirname(file), { recursive: true });
29981
30241
  await writeFile18(file, `${JSON.stringify({ generatedAt, scopes }, null, 2)}
29982
30242
  `, "utf8");
29983
30243
  return updated;
@@ -30030,11 +30290,11 @@ async function getChurn(cwd, windowDays) {
30030
30290
  }
30031
30291
 
30032
30292
  // src/health/metrics/wiki-freshness.ts
30033
- import { readFile as readFile44, stat as stat12 } from "fs/promises";
30034
- import path85 from "path";
30293
+ import { readFile as readFile45, stat as stat13 } from "fs/promises";
30294
+ import path86 from "path";
30035
30295
  var DEFAULT_STALE_EVIDENCE_DAYS = 7;
30036
30296
  function freshnessReportPath(cwd) {
30037
- return path85.join(cwd, ".metaproject", "data", "wiki", "freshness", "latest.json");
30297
+ return path86.join(cwd, ".metaproject", "data", "wiki", "freshness", "latest.json");
30038
30298
  }
30039
30299
  async function readWikiFreshnessMetric(cwd, options = {}) {
30040
30300
  const file = freshnessReportPath(cwd);
@@ -30042,7 +30302,7 @@ async function readWikiFreshnessMetric(cwd, options = {}) {
30042
30302
  const now = (options.now ?? (() => new Date))();
30043
30303
  let raw;
30044
30304
  try {
30045
- raw = await readFile44(file, "utf8");
30305
+ raw = await readFile45(file, "utf8");
30046
30306
  } catch {
30047
30307
  return {
30048
30308
  status: "no-report",
@@ -30055,7 +30315,7 @@ async function readWikiFreshnessMetric(cwd, options = {}) {
30055
30315
  } catch {
30056
30316
  return {
30057
30317
  status: "unreadable-report",
30058
- reason: `${path85.relative(cwd, file)} is not valid JSON; re-run \`keryx wiki freshness\`.`
30318
+ reason: `${path86.relative(cwd, file)} is not valid JSON; re-run \`keryx wiki freshness\`.`
30059
30319
  };
30060
30320
  }
30061
30321
  const report = parsed;
@@ -30065,7 +30325,7 @@ async function readWikiFreshnessMetric(cwd, options = {}) {
30065
30325
  if (pagesTotal === null || pagesFresh === null) {
30066
30326
  return {
30067
30327
  status: "unreadable-report",
30068
- reason: `${path85.relative(cwd, file)} is missing its totals; re-run \`keryx wiki freshness\`.`
30328
+ reason: `${path86.relative(cwd, file)} is missing its totals; re-run \`keryx wiki freshness\`.`
30069
30329
  };
30070
30330
  }
30071
30331
  const pagesUndecidable = numberOr2(totals.pagesUndecidable) ?? 0;
@@ -30102,7 +30362,7 @@ async function reportAgeDays(file, generatedAt, now) {
30102
30362
  return Math.floor((now.getTime() - stamped) / 86400000);
30103
30363
  }
30104
30364
  try {
30105
- const info = await stat12(file);
30365
+ const info = await stat13(file);
30106
30366
  return Math.floor((now.getTime() - info.mtimeMs) / 86400000);
30107
30367
  } catch {
30108
30368
  return null;
@@ -30119,12 +30379,12 @@ function renderWikiFreshnessLine(metric) {
30119
30379
  }
30120
30380
 
30121
30381
  // src/health/sources/helpers.ts
30122
- import path86 from "path";
30382
+ import path87 from "path";
30123
30383
  import { existsSync as existsSync8 } from "fs";
30124
30384
  class NoImportError extends Error {
30125
30385
  }
30126
30386
  function resolveBin(cwd, name) {
30127
- const local = path86.join(cwd, "node_modules", ".bin", name);
30387
+ const local = path87.join(cwd, "node_modules", ".bin", name);
30128
30388
  if (existsSync8(local)) {
30129
30389
  return local;
30130
30390
  }
@@ -30205,13 +30465,13 @@ async function getComplexityFindings(cwd, sourceFiles, config, sourceAnalysis) {
30205
30465
 
30206
30466
  // src/health/metrics/coverage.ts
30207
30467
  import { existsSync as existsSync9 } from "fs";
30208
- import path87 from "path";
30468
+ import path88 from "path";
30209
30469
  var SUMMARY_PATHS = [
30210
30470
  "coverage/coverage-summary.json",
30211
30471
  "coverage/coverage-final.json"
30212
30472
  ];
30213
30473
  async function getCoverage(cwd) {
30214
- const summary = SUMMARY_PATHS.map((rel) => path87.join(cwd, rel)).find((abs) => existsSync9(abs));
30474
+ const summary = SUMMARY_PATHS.map((rel) => path88.join(cwd, rel)).find((abs) => existsSync9(abs));
30215
30475
  if (!summary) {
30216
30476
  return { status: "missing", total: null, byFile: new Map };
30217
30477
  }
@@ -30232,7 +30492,7 @@ async function getCoverage(cwd) {
30232
30492
  total = pct;
30233
30493
  continue;
30234
30494
  }
30235
- const relative = path87.isAbsolute(key) ? path87.relative(cwd, key) : key;
30495
+ const relative = path88.isAbsolute(key) ? path88.relative(cwd, key) : key;
30236
30496
  byFile.set(relative.replace(/\\/g, "/"), pct);
30237
30497
  }
30238
30498
  return { status: "available", total, byFile };
@@ -30364,17 +30624,17 @@ function renderWikiFreshness(metric) {
30364
30624
 
30365
30625
  // src/health/skills.ts
30366
30626
  init_fs();
30367
- import { readFile as readFile45 } from "fs/promises";
30368
- import path88 from "path";
30627
+ import { readFile as readFile46 } from "fs/promises";
30628
+ import path89 from "path";
30369
30629
  var EMPTY = { skills: [], skillForFile: () => null };
30370
30630
  async function loadSkillOwnership(cwd) {
30371
- const manifestPath = path88.join(cwd, ".metaproject", "metaproject.json");
30631
+ const manifestPath = path89.join(cwd, ".metaproject", "metaproject.json");
30372
30632
  if (!await pathExists(manifestPath)) {
30373
30633
  return EMPTY;
30374
30634
  }
30375
30635
  let registry;
30376
30636
  try {
30377
- const manifest = JSON.parse(await readFile45(manifestPath, "utf8"));
30637
+ const manifest = JSON.parse(await readFile46(manifestPath, "utf8"));
30378
30638
  registry = manifest.modules?.gdskills?.projectSkillRegistry ?? [];
30379
30639
  } catch {
30380
30640
  return EMPTY;
@@ -30406,7 +30666,7 @@ function normalize(value) {
30406
30666
 
30407
30667
  // src/health/sources/eslint.ts
30408
30668
  import { existsSync as existsSync10 } from "fs";
30409
- import path89 from "path";
30669
+ import path90 from "path";
30410
30670
  var CONFIG_FILES = [
30411
30671
  ".eslintrc",
30412
30672
  ".eslintrc.js",
@@ -30420,7 +30680,7 @@ var CONFIG_FILES = [
30420
30680
  "eslint.config.ts"
30421
30681
  ];
30422
30682
  function hasConfig(cwd) {
30423
- return CONFIG_FILES.some((file) => existsSync10(path89.join(cwd, file)));
30683
+ return CONFIG_FILES.some((file) => existsSync10(path90.join(cwd, file)));
30424
30684
  }
30425
30685
  var eslintAdapter = {
30426
30686
  id: "eslint",
@@ -30445,7 +30705,7 @@ var eslintAdapter = {
30445
30705
  };
30446
30706
  },
30447
30707
  async import(ctx) {
30448
- const report = path89.join(ctx.cwd, "eslint-report.json");
30708
+ const report = path90.join(ctx.cwd, "eslint-report.json");
30449
30709
  if (!existsSync10(report)) {
30450
30710
  throw new NoImportError("no eslint-report.json");
30451
30711
  }
@@ -30472,7 +30732,7 @@ var eslintAdapter = {
30472
30732
  }
30473
30733
  const findings = [];
30474
30734
  for (const file of data) {
30475
- const relative = path89.isAbsolute(file.filePath) ? path89.relative(ctx.cwd, file.filePath) : file.filePath;
30735
+ const relative = path90.isAbsolute(file.filePath) ? path90.relative(ctx.cwd, file.filePath) : file.filePath;
30476
30736
  for (const message of file.messages ?? []) {
30477
30737
  const isError = message.severity === 2;
30478
30738
  findings.push(makeFinding({
@@ -30504,9 +30764,9 @@ var eslintAdapter = {
30504
30764
 
30505
30765
  // src/health/sources/typescript.ts
30506
30766
  import { existsSync as existsSync11 } from "fs";
30507
- import path90 from "path";
30767
+ import path91 from "path";
30508
30768
  function hasTsconfig(cwd) {
30509
- return existsSync11(path90.join(cwd, "tsconfig.json"));
30769
+ return existsSync11(path91.join(cwd, "tsconfig.json"));
30510
30770
  }
30511
30771
  var typescriptAdapter = {
30512
30772
  id: "typescript",
@@ -30581,8 +30841,8 @@ __export(exports_service6, {
30581
30841
  testingDataRoot: () => testingDataRoot
30582
30842
  });
30583
30843
  import { existsSync as existsSync12 } from "fs";
30584
- import { readFile as readFile48, readdir as readdir15 } from "fs/promises";
30585
- import path95 from "path";
30844
+ import { readFile as readFile49, readdir as readdir16 } from "fs/promises";
30845
+ import path96 from "path";
30586
30846
 
30587
30847
  // src/lib/git-env.ts
30588
30848
  var GIT_DISCOVERY_OVERRIDE_VARS = [
@@ -30606,8 +30866,8 @@ function withoutGitDiscoveryOverrides(env) {
30606
30866
  // src/metrics/lifecycle.ts
30607
30867
  init_fs();
30608
30868
  init_guard();
30609
- import { readFile as readFile46 } from "fs/promises";
30610
- import path91 from "path";
30869
+ import { readFile as readFile47 } from "fs/promises";
30870
+ import path92 from "path";
30611
30871
 
30612
30872
  // src/metrics/record.ts
30613
30873
  var RELIABILITIES = new Set(["exact", "estimated", "unknown"]);
@@ -30622,16 +30882,16 @@ var RETRY_TYPES = new Set([
30622
30882
 
30623
30883
  // src/metrics/lifecycle.ts
30624
30884
  async function readArtifactPointer(root, expected) {
30625
- const pointerFile = path91.join(root, "latest.json");
30885
+ const pointerFile = path92.join(root, "latest.json");
30626
30886
  if (!await pathExists(pointerFile))
30627
30887
  return { status: "missing", pointer: null };
30628
30888
  let pointer;
30629
30889
  try {
30630
- pointer = JSON.parse(await readFile46(pointerFile, "utf8"));
30890
+ pointer = JSON.parse(await readFile47(pointerFile, "utf8"));
30631
30891
  } catch {
30632
30892
  return { status: "stale", pointer: null, reason: "latest pointer is invalid JSON" };
30633
30893
  }
30634
- const recordFile = pointer.record ? path91.join(root, pointer.record) : null;
30894
+ const recordFile = pointer.record ? path92.join(root, pointer.record) : null;
30635
30895
  if (!recordFile || !isPathInside(root, recordFile) || !await pathExists(recordFile)) {
30636
30896
  return { status: "stale", pointer, reason: "pointer record is missing" };
30637
30897
  }
@@ -30647,9 +30907,9 @@ init_guard();
30647
30907
  // src/testing/capability.ts
30648
30908
  init_fs();
30649
30909
  init_json();
30650
- import path92 from "path";
30910
+ import path93 from "path";
30651
30911
  async function isTestingCapabilityEnabled(cwd, capability) {
30652
- const manifestPath = path92.join(cwd, ".metaproject", "metaproject.json");
30912
+ const manifestPath = path93.join(cwd, ".metaproject", "metaproject.json");
30653
30913
  if (!await pathExists(manifestPath)) {
30654
30914
  return false;
30655
30915
  }
@@ -30674,11 +30934,11 @@ async function isTestingCapabilityEnabled(cwd, capability) {
30674
30934
  // src/testing/coverage-map.ts
30675
30935
  init_fs();
30676
30936
  init_guard();
30677
- import { readFile as readFile47, mkdir as mkdir26, writeFile as writeFile19 } from "fs/promises";
30678
- import path93 from "path";
30937
+ import { readFile as readFile48, mkdir as mkdir26, writeFile as writeFile19 } from "fs/promises";
30938
+ import path94 from "path";
30679
30939
  var COVERAGE_MAP_SCHEMA_VERSION = 1;
30680
30940
  function coverageMapPath(cwd, cfg) {
30681
- return path93.isAbsolute(cfg.coverageMap.artifact) ? cfg.coverageMap.artifact : path93.join(cwd, cfg.coverageMap.artifact);
30941
+ return path94.isAbsolute(cfg.coverageMap.artifact) ? cfg.coverageMap.artifact : path94.join(cwd, cfg.coverageMap.artifact);
30682
30942
  }
30683
30943
  async function loadCoverageMap(cwd, cfg) {
30684
30944
  const file = coverageMapPath(cwd, cfg);
@@ -30686,7 +30946,7 @@ async function loadCoverageMap(cwd, cfg) {
30686
30946
  return null;
30687
30947
  }
30688
30948
  try {
30689
- const parsed = JSON.parse(await readFile47(file, "utf8"));
30949
+ const parsed = JSON.parse(await readFile48(file, "utf8"));
30690
30950
  if (!parsed || typeof parsed !== "object" || typeof parsed.map !== "object") {
30691
30951
  return null;
30692
30952
  }
@@ -30752,20 +31012,20 @@ function normalizePath4(file) {
30752
31012
  }
30753
31013
 
30754
31014
  // src/testing/selection.ts
30755
- import path94 from "path";
31015
+ import path95 from "path";
30756
31016
  var TEST_FILE_RE = /(^|\/)(__tests__\/.*|.*\.(test|spec)\.[cm]?[tj]sx?$|e2e\/.*\.[cm]?[tj]sx?$|tests\/.*\.[cm]?[tj]sx?$)/;
30757
31017
  function normalizePath5(file) {
30758
31018
  return file.replace(/\\/g, "/").replace(/^\.\//, "");
30759
31019
  }
30760
31020
  function relatedByNamingAndDirectory(target, testFiles) {
30761
31021
  const normalized = normalizePath5(target);
30762
- const ext = path94.extname(normalized);
31022
+ const ext = path95.extname(normalized);
30763
31023
  const withoutExt = ext ? normalized.slice(0, -ext.length) : normalized;
30764
- const base = path94.basename(withoutExt);
30765
- const dir = path94.dirname(normalized);
31024
+ const base = path95.basename(withoutExt);
31025
+ const dir = path95.dirname(normalized);
30766
31026
  return testFiles.filter((file) => {
30767
- const fileDir = path94.dirname(file);
30768
- const fileBase = path94.basename(file);
31027
+ const fileDir = path95.dirname(file);
31028
+ const fileBase = path95.basename(file);
30769
31029
  return file.startsWith(`${withoutExt}.`) || file.includes(`${withoutExt}.`) || fileDir === dir && fileBase.startsWith(`${base}.`) || fileDir.startsWith(dir) && fileBase.includes(base);
30770
31030
  }).sort();
30771
31031
  }
@@ -30895,7 +31155,7 @@ var DEFAULT_TESTING_CONFIG = {
30895
31155
  }
30896
31156
  };
30897
31157
  function testingDataRoot(cwd) {
30898
- return path95.join(cwd, ".metaproject", "data", "testing");
31158
+ return path96.join(cwd, ".metaproject", "data", "testing");
30899
31159
  }
30900
31160
  async function computeTestingContext(cwd) {
30901
31161
  const { files, incompleteReasons } = await listProjectFiles(cwd);
@@ -31070,33 +31330,33 @@ async function runTesting(input) {
31070
31330
  return runResult;
31071
31331
  }
31072
31332
  async function loadTestingContext(cwd) {
31073
- const file = path95.join(testingDataRoot(cwd), "context.json");
31333
+ const file = path96.join(testingDataRoot(cwd), "context.json");
31074
31334
  if (!await pathExists(file)) {
31075
31335
  return null;
31076
31336
  }
31077
31337
  try {
31078
- return JSON.parse(await readFile48(file, "utf8"));
31338
+ return JSON.parse(await readFile49(file, "utf8"));
31079
31339
  } catch {
31080
31340
  return null;
31081
31341
  }
31082
31342
  }
31083
31343
  async function loadTestingReport(cwd) {
31084
- const file = path95.join(testingDataRoot(cwd), "artifacts", "latest.json");
31344
+ const file = path96.join(testingDataRoot(cwd), "artifacts", "latest.json");
31085
31345
  if (!await pathExists(file)) {
31086
31346
  return null;
31087
31347
  }
31088
31348
  try {
31089
- const latest = JSON.parse(await readFile48(file, "utf8"));
31349
+ const latest = JSON.parse(await readFile49(file, "utf8"));
31090
31350
  if (typeof latest.record === "string") {
31091
- const pointer = await readArtifactPointer(path95.join(testingDataRoot(cwd), "artifacts"), await collectGitProvenance(cwd));
31351
+ const pointer = await readArtifactPointer(path96.join(testingDataRoot(cwd), "artifacts"), await collectGitProvenance(cwd));
31092
31352
  if (pointer.status !== "fresh")
31093
31353
  return null;
31094
- const recordFile = path95.join(testingDataRoot(cwd), "artifacts", latest.record);
31095
- if (!isPathInside(path95.join(testingDataRoot(cwd), "artifacts"), recordFile))
31354
+ const recordFile = path96.join(testingDataRoot(cwd), "artifacts", latest.record);
31355
+ if (!isPathInside(path96.join(testingDataRoot(cwd), "artifacts"), recordFile))
31096
31356
  return null;
31097
31357
  if (!await pathExists(recordFile))
31098
31358
  return null;
31099
- return JSON.parse(await readFile48(recordFile, "utf8"));
31359
+ return JSON.parse(await readFile49(recordFile, "utf8"));
31100
31360
  }
31101
31361
  return latest;
31102
31362
  } catch {
@@ -31139,28 +31399,28 @@ async function ensureContext(cwd) {
31139
31399
  }
31140
31400
  async function writeContext(cwd, context) {
31141
31401
  const root = testingDataRoot(cwd);
31142
- const rel = (p) => path95.relative(cwd, p);
31402
+ const rel = (p) => path96.relative(cwd, p);
31143
31403
  await mkdirContained(cwd, rel(root));
31144
- await writeContained(cwd, rel(path95.join(root, "context.json")), `${JSON.stringify(context, null, 2)}
31404
+ await writeContained(cwd, rel(path96.join(root, "context.json")), `${JSON.stringify(context, null, 2)}
31145
31405
  `);
31146
- await writeContained(cwd, rel(path95.join(root, "context.md")), renderContextMarkdown(context));
31147
- await writeContained(cwd, rel(path95.join(root, "recommendations.md")), renderRecommendationsMarkdown(context));
31406
+ await writeContained(cwd, rel(path96.join(root, "context.md")), renderContextMarkdown(context));
31407
+ await writeContained(cwd, rel(path96.join(root, "recommendations.md")), renderRecommendationsMarkdown(context));
31148
31408
  }
31149
31409
  async function writeReport(cwd, report) {
31150
31410
  const root = testingDataRoot(cwd);
31151
- const artifacts = path95.join(root, "artifacts");
31152
- const history = path95.join(root, "history");
31153
- const rel = (p) => path95.relative(cwd, p);
31411
+ const artifacts = path96.join(root, "artifacts");
31412
+ const history = path96.join(root, "history");
31413
+ const rel = (p) => path96.relative(cwd, p);
31154
31414
  await mkdirContained(cwd, rel(artifacts));
31155
31415
  await mkdirContained(cwd, rel(history));
31156
31416
  const stamp = report.generatedAt.replace(/[:.]/g, "-");
31157
- const json = path95.join(artifacts, "latest.json");
31158
- const markdown = path95.join(artifacts, "latest.md");
31417
+ const json = path96.join(artifacts, "latest.json");
31418
+ const markdown = path96.join(artifacts, "latest.md");
31159
31419
  const serialized = `${JSON.stringify(report, null, 2)}
31160
31420
  `;
31161
31421
  if (report.runId) {
31162
- const runJson = path95.join(artifacts, "runs", `${report.runId}.json`);
31163
- const runMarkdown = path95.join(artifacts, "runs", `${report.runId}.md`);
31422
+ const runJson = path96.join(artifacts, "runs", `${report.runId}.json`);
31423
+ const runMarkdown = path96.join(artifacts, "runs", `${report.runId}.md`);
31164
31424
  if (await pathExists(runJson))
31165
31425
  throw new Error(`immutable testing run already exists: ${report.runId}`);
31166
31426
  await writeContained(cwd, rel(runJson), serialized);
@@ -31171,26 +31431,26 @@ async function writeReport(cwd, report) {
31171
31431
  branch: report.provenance?.branch ?? null,
31172
31432
  worktree: report.provenance?.worktree ?? null,
31173
31433
  generated_at: report.generatedAt,
31174
- record: path95.posix.join("runs", `${report.runId}.json`)
31434
+ record: path96.posix.join("runs", `${report.runId}.json`)
31175
31435
  }, null, 2)}
31176
31436
  `);
31177
31437
  } else {
31178
31438
  await writeContained(cwd, rel(json), serialized);
31179
31439
  }
31180
31440
  await writeContained(cwd, rel(markdown), renderReportMarkdown3(report));
31181
- await writeContained(cwd, rel(path95.join(history, `${stamp}.json`)), serialized);
31441
+ await writeContained(cwd, rel(path96.join(history, `${stamp}.json`)), serialized);
31182
31442
  return {
31183
- markdownPath: path95.relative(cwd, markdown),
31184
- jsonPath: path95.relative(cwd, json)
31443
+ markdownPath: path96.relative(cwd, markdown),
31444
+ jsonPath: path96.relative(cwd, json)
31185
31445
  };
31186
31446
  }
31187
31447
  async function writeRawLog(cwd, raw) {
31188
- const logs = path95.join(testingDataRoot(cwd), "logs");
31189
- const rel = (p) => path95.relative(cwd, p);
31448
+ const logs = path96.join(testingDataRoot(cwd), "logs");
31449
+ const rel = (p) => path96.relative(cwd, p);
31190
31450
  await mkdirContained(cwd, rel(logs));
31191
- const latest = path95.join(logs, "latest.raw.log");
31451
+ const latest = path96.join(logs, "latest.raw.log");
31192
31452
  await writeContained(cwd, rel(latest), raw);
31193
- return path95.relative(cwd, latest);
31453
+ return path96.relative(cwd, latest);
31194
31454
  }
31195
31455
  async function listProjectFiles(cwd) {
31196
31456
  const out = [];
@@ -31201,13 +31461,13 @@ async function listProjectFiles(cwd) {
31201
31461
  async function walk3(root, dir, out, incompleteReasons) {
31202
31462
  let entries;
31203
31463
  try {
31204
- entries = await readdir15(dir, { withFileTypes: true });
31464
+ entries = await readdir16(dir, { withFileTypes: true });
31205
31465
  } catch (error) {
31206
- incompleteReasons.push(`${normalizePath6(path95.relative(root, dir)) || "."}: ${error instanceof Error ? error.message : String(error)}`);
31466
+ incompleteReasons.push(`${normalizePath6(path96.relative(root, dir)) || "."}: ${error instanceof Error ? error.message : String(error)}`);
31207
31467
  return;
31208
31468
  }
31209
31469
  for (const entry of entries) {
31210
- const abs = path95.join(dir, entry.name);
31470
+ const abs = path96.join(dir, entry.name);
31211
31471
  if (entry.isDirectory()) {
31212
31472
  if (IGNORED_DIRS2.has(entry.name) || entry.name.startsWith(".tmp-")) {
31213
31473
  continue;
@@ -31216,28 +31476,28 @@ async function walk3(root, dir, out, incompleteReasons) {
31216
31476
  continue;
31217
31477
  }
31218
31478
  if (entry.isFile()) {
31219
- out.push(normalizePath6(path95.relative(root, abs)));
31479
+ out.push(normalizePath6(path96.relative(root, abs)));
31220
31480
  }
31221
31481
  }
31222
31482
  }
31223
31483
  async function readPackageJson(cwd) {
31224
- const file = path95.join(cwd, "package.json");
31484
+ const file = path96.join(cwd, "package.json");
31225
31485
  if (!await pathExists(file)) {
31226
31486
  return null;
31227
31487
  }
31228
31488
  try {
31229
- return JSON.parse(await readFile48(file, "utf8"));
31489
+ return JSON.parse(await readFile49(file, "utf8"));
31230
31490
  } catch {
31231
31491
  return null;
31232
31492
  }
31233
31493
  }
31234
31494
  async function loadTestingConfig(cwd) {
31235
- const file = path95.join(cwd, ".metaproject", "testing.config.json");
31495
+ const file = path96.join(cwd, ".metaproject", "testing.config.json");
31236
31496
  if (!await pathExists(file)) {
31237
31497
  return DEFAULT_TESTING_CONFIG;
31238
31498
  }
31239
31499
  try {
31240
- const parsed = JSON.parse(await readFile48(file, "utf8"));
31500
+ const parsed = JSON.parse(await readFile49(file, "utf8"));
31241
31501
  return {
31242
31502
  schemaVersion: parsed.schemaVersion ?? DEFAULT_TESTING_CONFIG.schemaVersion,
31243
31503
  enabled: parsed.enabled ?? DEFAULT_TESTING_CONFIG.enabled,
@@ -31297,11 +31557,11 @@ function detectFrameworks(input) {
31297
31557
  async function extractConventions(cwd, files) {
31298
31558
  const conventions = new Set;
31299
31559
  for (const file of files.slice(0, 40)) {
31300
- const abs = path95.join(cwd, file);
31560
+ const abs = path96.join(cwd, file);
31301
31561
  if (!await pathExists(abs)) {
31302
31562
  continue;
31303
31563
  }
31304
- const text = await readFile48(abs, "utf8");
31564
+ const text = await readFile49(abs, "utf8");
31305
31565
  for (const line of text.split(`
31306
31566
  `)) {
31307
31567
  if (/test|testing|spec|coverage|playwright|vitest|jest|bun:test/i.test(line)) {
@@ -31427,11 +31687,11 @@ async function findTestsByImportedTargets(cwd, targets, testFiles) {
31427
31687
  const targetKeys = new Set(targets.map((target) => modulePathKey(normalizePath6(target))));
31428
31688
  const selected = new Set;
31429
31689
  for (const testFile of testFiles) {
31430
- const absoluteTest = path95.join(cwd, testFile);
31690
+ const absoluteTest = path96.join(cwd, testFile);
31431
31691
  if (!await pathExists(absoluteTest)) {
31432
31692
  continue;
31433
31693
  }
31434
- const content = await readFile48(absoluteTest, "utf8");
31694
+ const content = await readFile49(absoluteTest, "utf8");
31435
31695
  const imports = extractImportPaths(content);
31436
31696
  if (imports.length === 0) {
31437
31697
  continue;
@@ -31461,10 +31721,10 @@ function resolveImportPath(cwd, testFile, importPath) {
31461
31721
  if (!importPath.startsWith(".")) {
31462
31722
  return null;
31463
31723
  }
31464
- const importerDir = path95.dirname(testFile);
31465
- const absoluteResolved = path95.resolve(path95.join(cwd, importerDir), importPath);
31466
- const relative = path95.relative(cwd, absoluteResolved);
31467
- if (relative.startsWith(`..${path95.sep}`) || relative === "..") {
31724
+ const importerDir = path96.dirname(testFile);
31725
+ const absoluteResolved = path96.resolve(path96.join(cwd, importerDir), importPath);
31726
+ const relative = path96.relative(cwd, absoluteResolved);
31727
+ if (relative.startsWith(`..${path96.sep}`) || relative === "..") {
31468
31728
  return null;
31469
31729
  }
31470
31730
  const relativeNormalized = normalizePath6(relative);
@@ -31516,13 +31776,13 @@ function resolveTestCommand(cwd, context, input) {
31516
31776
  }
31517
31777
  var BUN_LOCKFILES = ["bun.lock", "bun.lockb"];
31518
31778
  function detectPackageManager(cwd) {
31519
- if (resolveBunBin() && BUN_LOCKFILES.some((name) => pathExistsSync(path95.join(cwd, name)))) {
31779
+ if (resolveBunBin() && BUN_LOCKFILES.some((name) => pathExistsSync(path96.join(cwd, name)))) {
31520
31780
  return "bun";
31521
31781
  }
31522
- if (Bun.which("pnpm") && pathExistsSync(path95.join(cwd, "pnpm-lock.yaml"))) {
31782
+ if (Bun.which("pnpm") && pathExistsSync(path96.join(cwd, "pnpm-lock.yaml"))) {
31523
31783
  return "pnpm";
31524
31784
  }
31525
- if (Bun.which("yarn") && pathExistsSync(path95.join(cwd, "yarn.lock"))) {
31785
+ if (Bun.which("yarn") && pathExistsSync(path96.join(cwd, "yarn.lock"))) {
31526
31786
  return "yarn";
31527
31787
  }
31528
31788
  return "npm";
@@ -31862,7 +32122,7 @@ async function compatibleReportForHealth(ctx) {
31862
32122
 
31863
32123
  // src/health/sources/dependency-audit.ts
31864
32124
  import { existsSync as existsSync13 } from "fs";
31865
- import path96 from "path";
32125
+ import path97 from "path";
31866
32126
  function auditSeverityToPriority(severity) {
31867
32127
  if (severity === "critical" || severity === "high")
31868
32128
  return "P0";
@@ -31981,7 +32241,7 @@ var LOCKFILE_COMMANDS = [
31981
32241
  ];
31982
32242
  function auditCommand(cwd) {
31983
32243
  for (const entry of LOCKFILE_COMMANDS) {
31984
- if (!entry.lockfiles.some((name) => existsSync13(path96.join(cwd, name))))
32244
+ if (!entry.lockfiles.some((name) => existsSync13(path97.join(cwd, name))))
31985
32245
  continue;
31986
32246
  const bin = resolveBin(cwd, entry.bin);
31987
32247
  if (bin)
@@ -32040,13 +32300,13 @@ var dependencyAuditAdapter = {
32040
32300
 
32041
32301
  // src/health/sources/sonarqube.ts
32042
32302
  import { existsSync as existsSync14 } from "fs";
32043
- import path97 from "path";
32303
+ import path98 from "path";
32044
32304
  var REPORT_FILES = ["sonar-issues.json", ".metaproject/data/health/sonar-issues.json"];
32045
32305
  function reportPath(cwd) {
32046
32306
  const fromEnv = process.env.SONAR_ISSUES_FILE;
32047
32307
  const candidates = fromEnv ? [fromEnv, ...REPORT_FILES] : REPORT_FILES;
32048
32308
  for (const rel of candidates) {
32049
- const abs = path97.isAbsolute(rel) ? rel : path97.join(cwd, rel);
32309
+ const abs = path98.isAbsolute(rel) ? rel : path98.join(cwd, rel);
32050
32310
  if (existsSync14(abs)) {
32051
32311
  return abs;
32052
32312
  }
@@ -32130,7 +32390,7 @@ var sonarqubeAdapter = {
32130
32390
  function relativizeComponent(component, cwd) {
32131
32391
  const colon = component.indexOf(":");
32132
32392
  const value = colon >= 0 ? component.slice(colon + 1) : component;
32133
- return path97.isAbsolute(value) ? path97.relative(cwd, value) : value;
32393
+ return path98.isAbsolute(value) ? path98.relative(cwd, value) : value;
32134
32394
  }
32135
32395
 
32136
32396
  // src/health/sources/index.ts
@@ -32467,19 +32727,19 @@ function filteredInfo(source, cfg) {
32467
32727
  };
32468
32728
  }
32469
32729
  async function writeOutputs(cwd, report, config, stamp) {
32470
- const artifacts = path98.join(dataRoot3(cwd), "artifacts");
32471
- const history = path98.join(dataRoot3(cwd), "history");
32730
+ const artifacts = path99.join(dataRoot3(cwd), "artifacts");
32731
+ const history = path99.join(dataRoot3(cwd), "history");
32472
32732
  await mkdir27(artifacts, { recursive: true });
32473
32733
  await mkdir27(history, { recursive: true });
32474
- const markdown = path98.join(artifacts, "latest.md");
32475
- const json = path98.join(artifacts, "latest.json");
32476
- const historyJson = path98.join(history, `${stamp}.json`);
32734
+ const markdown = path99.join(artifacts, "latest.md");
32735
+ const json = path99.join(artifacts, "latest.json");
32736
+ const historyJson = path99.join(history, `${stamp}.json`);
32477
32737
  const serialized = `${JSON.stringify(report, null, 2)}
32478
32738
  `;
32479
32739
  await writeFile20(markdown, renderReportMarkdown2(report, config), "utf8");
32480
32740
  if (report.runId) {
32481
- const runJson = path98.join(artifacts, "runs", `${report.runId}.json`);
32482
- const runMarkdown = path98.join(artifacts, "runs", `${report.runId}.md`);
32741
+ const runJson = path99.join(artifacts, "runs", `${report.runId}.json`);
32742
+ const runMarkdown = path99.join(artifacts, "runs", `${report.runId}.md`);
32483
32743
  if (await pathExists(runJson))
32484
32744
  throw new Error(`immutable health run already exists: ${report.runId}`);
32485
32745
  await writeFileAtomic(runJson, serialized);
@@ -32490,7 +32750,7 @@ async function writeOutputs(cwd, report, config, stamp) {
32490
32750
  branch: report.provenance?.branch ?? null,
32491
32751
  worktree: report.provenance?.worktree ?? null,
32492
32752
  generated_at: report.generatedAt,
32493
- record: path98.posix.join("runs", `${report.runId}.json`)
32753
+ record: path99.posix.join("runs", `${report.runId}.json`)
32494
32754
  }, null, 2)}
32495
32755
  `);
32496
32756
  } else {
@@ -32498,8 +32758,8 @@ async function writeOutputs(cwd, report, config, stamp) {
32498
32758
  }
32499
32759
  await writeFile20(historyJson, serialized, "utf8");
32500
32760
  return {
32501
- markdownPath: path98.relative(cwd, markdown),
32502
- jsonPath: path98.relative(cwd, json)
32761
+ markdownPath: path99.relative(cwd, markdown),
32762
+ jsonPath: path99.relative(cwd, json)
32503
32763
  };
32504
32764
  }
32505
32765
  async function resolveChanged(cwd, selector) {
@@ -32552,7 +32812,7 @@ function hasGateShape(value) {
32552
32812
  return Array.isArray(report.metrics) && Array.isArray(report.sources) && Array.isArray(report.findings);
32553
32813
  }
32554
32814
  async function readLatest(cwd) {
32555
- const file = path99.join(dataRoot3(cwd), "artifacts", "latest.json");
32815
+ const file = path100.join(dataRoot3(cwd), "artifacts", "latest.json");
32556
32816
  if (!await pathExists(file)) {
32557
32817
  return null;
32558
32818
  }
@@ -32563,11 +32823,11 @@ async function readLatest(cwd) {
32563
32823
  const latest = read.value;
32564
32824
  const record = latest.record;
32565
32825
  if (typeof record === "string") {
32566
- const pointer = await readArtifactPointer(path99.join(dataRoot3(cwd), "artifacts"), await collectGitProvenance(cwd));
32826
+ const pointer = await readArtifactPointer(path100.join(dataRoot3(cwd), "artifacts"), await collectGitProvenance(cwd));
32567
32827
  if (pointer.status !== "fresh")
32568
32828
  return null;
32569
- const recordFile = path99.join(dataRoot3(cwd), "artifacts", record);
32570
- if (!isPathInside(path99.join(dataRoot3(cwd), "artifacts"), recordFile))
32829
+ const recordFile = path100.join(dataRoot3(cwd), "artifacts", record);
32830
+ if (!isPathInside(path100.join(dataRoot3(cwd), "artifacts"), recordFile))
32571
32831
  return null;
32572
32832
  if (!await pathExists(recordFile))
32573
32833
  return null;
@@ -32640,7 +32900,7 @@ function createCodeHealthService() {
32640
32900
  return {
32641
32901
  run: (input) => runHealth(input),
32642
32902
  async status(input) {
32643
- const enabled = await pathExists(path99.join(input.cwd, ".metaproject", "health.config.json"));
32903
+ const enabled = await pathExists(path100.join(input.cwd, ".metaproject", "health.config.json"));
32644
32904
  const latest = await readLatest(input.cwd);
32645
32905
  const project = latest?.metrics.find((m) => m.key === "project") ?? null;
32646
32906
  const decliningScopes = latest ? latest.metrics.filter((m) => m.regression_score > 0).length : 0;
@@ -32798,10 +33058,10 @@ function renderEvidenceBlock(evidences, siblings) {
32798
33058
  init_fs();
32799
33059
  init_contained_write();
32800
33060
  init_json();
32801
- import path100 from "path";
33061
+ import path101 from "path";
32802
33062
  import { createHash as createHash16 } from "crypto";
32803
33063
  function impactEvidenceDataRoot(root) {
32804
- return path100.join(root, ".metaproject", "data", "security", "impact-evidence");
33064
+ return path101.join(root, ".metaproject", "data", "security", "impact-evidence");
32805
33065
  }
32806
33066
  function sanitizeSessionId(sessionId) {
32807
33067
  const cleaned = sessionId.replace(/[^A-Za-z0-9._-]/g, "_");
@@ -32813,7 +33073,7 @@ function sessionStateFilename(sessionId) {
32813
33073
  return `${sanitized}-${suffix}.json`;
32814
33074
  }
32815
33075
  function sessionStatePath(root, sessionId) {
32816
- return path100.join(impactEvidenceDataRoot(root), "sessions", sessionStateFilename(sessionId));
33076
+ return path101.join(impactEvidenceDataRoot(root), "sessions", sessionStateFilename(sessionId));
32817
33077
  }
32818
33078
  async function loadSessionState(root, sessionId) {
32819
33079
  const file = sessionStatePath(root, sessionId);
@@ -32832,11 +33092,11 @@ async function loadSessionState(root, sessionId) {
32832
33092
  }
32833
33093
  async function saveSessionState(root, sessionId, state) {
32834
33094
  const file = sessionStatePath(root, sessionId);
32835
- await writeContained(root, path100.relative(root, file), `${JSON.stringify(state, null, 2)}
33095
+ await writeContained(root, path101.relative(root, file), `${JSON.stringify(state, null, 2)}
32836
33096
  `);
32837
33097
  }
32838
33098
  function logPath(root) {
32839
- return path100.join(impactEvidenceDataRoot(root), "log.jsonl");
33099
+ return path101.join(impactEvidenceDataRoot(root), "log.jsonl");
32840
33100
  }
32841
33101
  async function appendLogRecord(root, record) {
32842
33102
  const full = {
@@ -32847,7 +33107,7 @@ async function appendLogRecord(root, record) {
32847
33107
  ...record.detail !== undefined ? { detail: record.detail } : {}
32848
33108
  };
32849
33109
  const file = logPath(root);
32850
- await appendContained(root, path100.relative(root, file), `${JSON.stringify(full)}
33110
+ await appendContained(root, path101.relative(root, file), `${JSON.stringify(full)}
32851
33111
  `);
32852
33112
  return full;
32853
33113
  }
@@ -32874,7 +33134,7 @@ init_command_risk();
32874
33134
  init_shell_syntax();
32875
33135
  init_fs();
32876
33136
  init_service2();
32877
- import path101 from "path";
33137
+ import path102 from "path";
32878
33138
  import { createHash as createHash17 } from "crypto";
32879
33139
  import { realpathSync as realpathSync2 } from "fs";
32880
33140
  function impactEvidenceHookClass(strict) {
@@ -32890,29 +33150,29 @@ function realpathNearestExisting(p) {
32890
33150
  for (;; ) {
32891
33151
  try {
32892
33152
  const real = realpathSync2(current);
32893
- return tail.length > 0 ? path101.join(real, ...tail) : real;
33153
+ return tail.length > 0 ? path102.join(real, ...tail) : real;
32894
33154
  } catch {
32895
- const parent = path101.dirname(current);
33155
+ const parent = path102.dirname(current);
32896
33156
  if (parent === current) {
32897
- return tail.length > 0 ? path101.join(current, ...tail) : current;
33157
+ return tail.length > 0 ? path102.join(current, ...tail) : current;
32898
33158
  }
32899
- tail.unshift(path101.basename(current));
33159
+ tail.unshift(path102.basename(current));
32900
33160
  current = parent;
32901
33161
  }
32902
33162
  }
32903
33163
  }
32904
33164
  function normalizeRequestFiles(root, files) {
32905
- const rootReal = realpathNearestExisting(path101.resolve(root));
33165
+ const rootReal = realpathNearestExisting(path102.resolve(root));
32906
33166
  const normalized = [];
32907
33167
  const rejected = [];
32908
33168
  for (const file of files) {
32909
- const lexicalAbsolute = path101.isAbsolute(file) ? path101.resolve(file) : path101.resolve(rootReal, toPosix(file).replace(/^\.\//, ""));
33169
+ const lexicalAbsolute = path102.isAbsolute(file) ? path102.resolve(file) : path102.resolve(rootReal, toPosix(file).replace(/^\.\//, ""));
32910
33170
  const effective = realpathNearestExisting(lexicalAbsolute);
32911
33171
  if (!isPathInside(rootReal, effective)) {
32912
33172
  rejected.push(file);
32913
33173
  continue;
32914
33174
  }
32915
- normalized.push(toPosix(path101.relative(rootReal, effective)));
33175
+ normalized.push(toPosix(path102.relative(rootReal, effective)));
32916
33176
  }
32917
33177
  return { files: [...new Set(normalized)], rejected };
32918
33178
  }
@@ -33198,7 +33458,7 @@ __export(exports_service8, {
33198
33458
  createJobService: () => createJobService
33199
33459
  });
33200
33460
  import { copyFile, mkdir as mkdir29 } from "fs/promises";
33201
- import path104 from "path";
33461
+ import path105 from "path";
33202
33462
 
33203
33463
  // src/job/types.ts
33204
33464
  var JOB_INTENTS = ["implement", "analyze", "review", "custom"];
@@ -33338,16 +33598,16 @@ function defaultPlan(intent) {
33338
33598
  init_validator();
33339
33599
  init_contracts();
33340
33600
  init_fs();
33341
- import { appendFile as appendFile5, mkdir as mkdir28, readFile as readFile50, readdir as readdir16 } from "fs/promises";
33342
- import path103 from "path";
33601
+ import { appendFile as appendFile5, mkdir as mkdir28, readFile as readFile51, readdir as readdir17 } from "fs/promises";
33602
+ import path104 from "path";
33343
33603
  function jobsRoot(cwd) {
33344
- return path103.join(cwd, ".metaproject", "jobs");
33604
+ return path104.join(cwd, ".metaproject", "jobs");
33345
33605
  }
33346
33606
  function jobDir(cwd, name) {
33347
- return path103.join(jobsRoot(cwd), name);
33607
+ return path104.join(jobsRoot(cwd), name);
33348
33608
  }
33349
33609
  function jobStatePath(cwd, name) {
33350
- return path103.join(jobDir(cwd, name), "state.json");
33610
+ return path104.join(jobDir(cwd, name), "state.json");
33351
33611
  }
33352
33612
  var JOB_NAME_PATTERN = /^[a-z0-9-]+$/;
33353
33613
  function assertJobName(name) {
@@ -33364,7 +33624,7 @@ async function listJobNames(cwd) {
33364
33624
  if (!await pathExists(root)) {
33365
33625
  return [];
33366
33626
  }
33367
- const entries = await readdir16(root, { withFileTypes: true });
33627
+ const entries = await readdir17(root, { withFileTypes: true });
33368
33628
  return entries.filter((entry) => entry.isDirectory() && JOB_NAME_PATTERN.test(entry.name)).map((entry) => entry.name).sort();
33369
33629
  }
33370
33630
  async function readJob(cwd, name) {
@@ -33373,7 +33633,7 @@ async function readJob(cwd, name) {
33373
33633
  const known = await listJobNames(cwd);
33374
33634
  throw new Error(`Job not found: ${name}.` + (known.length > 0 ? ` Known: ${known.join(", ")}` : " Run: keryx job list"));
33375
33635
  }
33376
- return JSON.parse(await readFile50(file, "utf8"));
33636
+ return JSON.parse(await readFile51(file, "utf8"));
33377
33637
  }
33378
33638
  async function writeJob(cwd, name, state) {
33379
33639
  const schema = await loadSchema("job-orchestrator-state");
@@ -33384,12 +33644,12 @@ async function writeJob(cwd, name, state) {
33384
33644
  `));
33385
33645
  }
33386
33646
  const file = jobStatePath(cwd, name);
33387
- await mkdir28(path103.dirname(file), { recursive: true });
33647
+ await mkdir28(path104.dirname(file), { recursive: true });
33388
33648
  await writeFileAtomic(file, `${JSON.stringify(state, null, 2)}
33389
33649
  `);
33390
33650
  }
33391
33651
  async function appendJournal2(cwd, name, at, line) {
33392
- await appendFile5(path103.join(jobDir(cwd, name), "journal.md"), `- ${at} - ${line}
33652
+ await appendFile5(path104.join(jobDir(cwd, name), "journal.md"), `- ${at} - ${line}
33393
33653
  `, "utf8");
33394
33654
  }
33395
33655
  function renderJournal2(name, at) {
@@ -33410,7 +33670,7 @@ function assertDocumentType(raw) {
33410
33670
  return raw;
33411
33671
  }
33412
33672
  function documentFileName(type, sourcePath) {
33413
- const extension = path103.extname(sourcePath) || ".md";
33673
+ const extension = path104.extname(sourcePath) || ".md";
33414
33674
  return `${type}${extension}`;
33415
33675
  }
33416
33676
 
@@ -33418,7 +33678,7 @@ function documentFileName(type, sourcePath) {
33418
33678
  function createJobService(deps) {
33419
33679
  const now = () => deps.now().toISOString();
33420
33680
  function lockPath(cwd, name) {
33421
- return path104.join(jobsRoot(cwd), `.job-lock-${name}`);
33681
+ return path105.join(jobsRoot(cwd), `.job-lock-${name}`);
33422
33682
  }
33423
33683
  async function mutate(cwd, name, run) {
33424
33684
  assertJobName(name);
@@ -33467,20 +33727,20 @@ function createJobService(deps) {
33467
33727
  },
33468
33728
  plan: { steps: defaultPlan(intent) },
33469
33729
  documentation: {
33470
- job_path: path104.join(".metaproject", "jobs", name),
33730
+ job_path: path105.join(".metaproject", "jobs", name),
33471
33731
  documents_created: []
33472
33732
  },
33473
33733
  metrics: { steps: [] },
33474
- jobs_root: path104.join(".metaproject", "jobs"),
33734
+ jobs_root: path105.join(".metaproject", "jobs"),
33475
33735
  updated_at: createdAt
33476
33736
  };
33477
33737
  const first = firstOpenStep(state.plan.steps);
33478
33738
  if (first) {
33479
33739
  state.plan.current_step = first.id;
33480
33740
  }
33481
- await writeFileAtomic(path104.join(absolute, "journal.md"), renderJournal2(name, createdAt));
33741
+ await writeFileAtomic(path105.join(absolute, "journal.md"), renderJournal2(name, createdAt));
33482
33742
  await writeJob(input.cwd, name, state);
33483
- return { state, dir: path104.relative(input.cwd, absolute) };
33743
+ return { state, dir: path105.relative(input.cwd, absolute) };
33484
33744
  },
33485
33745
  async status({ cwd, name }) {
33486
33746
  assertJobName(name);
@@ -33492,7 +33752,7 @@ function createJobService(deps) {
33492
33752
  }
33493
33753
  return {
33494
33754
  state,
33495
- dir: path104.join(".metaproject", "jobs", name),
33755
+ dir: path105.join(".metaproject", "jobs", name),
33496
33756
  stepsDone: state.plan.steps.filter((step) => isTerminalStep(step.status)).length,
33497
33757
  stepsTotal: state.plan.steps.length,
33498
33758
  nextStep: firstOpenStep(state.plan.steps),
@@ -33549,23 +33809,23 @@ function createJobService(deps) {
33549
33809
  if (!input.file) {
33550
33810
  throw new Error("Missing --file. Usage: keryx job document <name> --type <type> --file <path>");
33551
33811
  }
33552
- const source = path104.isAbsolute(input.file) ? input.file : path104.join(input.cwd, input.file);
33812
+ const source = path105.isAbsolute(input.file) ? input.file : path105.join(input.cwd, input.file);
33553
33813
  if (!await pathExists(source)) {
33554
33814
  throw new Error(`--file not found: ${input.file}. Write the document first, then record it.`);
33555
33815
  }
33556
33816
  let recorded;
33557
33817
  await mutate(input.cwd, input.name, async (state) => {
33558
33818
  const fileName = documentFileName(type, source);
33559
- const target = path104.join(jobDir(input.cwd, state.job_name), fileName);
33819
+ const target = path105.join(jobDir(input.cwd, state.job_name), fileName);
33560
33820
  await copyFile(source, target);
33561
33821
  state.documentation ??= {};
33562
- state.documentation.job_path ??= path104.join(".metaproject", "jobs", state.job_name);
33822
+ state.documentation.job_path ??= path105.join(".metaproject", "jobs", state.job_name);
33563
33823
  const created = state.documentation.documents_created ?? [];
33564
33824
  state.documentation.documents_created = created.includes(fileName) ? created : [...created, fileName];
33565
33825
  recorded = {
33566
33826
  state,
33567
33827
  document: fileName,
33568
- path: path104.join(".metaproject", "jobs", state.job_name, fileName)
33828
+ path: path105.join(".metaproject", "jobs", state.job_name, fileName)
33569
33829
  };
33570
33830
  return { state, event: "document", detail: `${type} -> ${fileName}` };
33571
33831
  });
@@ -33600,7 +33860,7 @@ function createJobService(deps) {
33600
33860
  name: state.job_name,
33601
33861
  phase: state.phase,
33602
33862
  intent: state.intent,
33603
- dir: path104.join(".metaproject", "jobs", name),
33863
+ dir: path105.join(".metaproject", "jobs", name),
33604
33864
  stepsDone: state.plan.steps.filter((step) => isTerminalStep(step.status)).length,
33605
33865
  stepsTotal: state.plan.steps.length,
33606
33866
  nextStep: firstOpenStep(state.plan.steps)?.id ?? null
@@ -33704,13 +33964,13 @@ function normalizeWorkspaceReference(raw) {
33704
33964
 
33705
33965
  // src/sac/fwk-service.ts
33706
33966
  init_assembly();
33707
- import { appendFile as appendFile6, mkdir as mkdir31, open as open3, readFile as readFile53, rename as rename7, rm as rm6, stat as stat13, writeFile as writeFile21 } from "fs/promises";
33708
- import path108 from "path";
33967
+ import { appendFile as appendFile6, mkdir as mkdir31, open as open3, readFile as readFile54, rename as rename7, rm as rm6, stat as stat14, writeFile as writeFile21 } from "fs/promises";
33968
+ import path109 from "path";
33709
33969
 
33710
33970
  // src/sac/index.ts
33711
- import { access as access3, readFile as readFile51, realpath as realpath11 } from "fs/promises";
33971
+ import { access as access3, readFile as readFile52, realpath as realpath12 } from "fs/promises";
33712
33972
  import { createHash as createHash18 } from "crypto";
33713
- import path105 from "path";
33973
+ import path106 from "path";
33714
33974
  import { fileURLToPath as fileURLToPath3 } from "url";
33715
33975
  var idPattern = /^[a-z][a-z0-9-]{2,63}$/;
33716
33976
  var subjectPattern = /^(?:user|team|service|agent):[a-z0-9][a-z0-9._-]{0,127}$/;
@@ -33728,21 +33988,21 @@ var normativeSchemaFiles = {
33728
33988
  "review-decision": "review-decision.schema.json"
33729
33989
  };
33730
33990
  var normativeSchemas = new Map;
33731
- var NORMATIVE_SCHEMA_DIR = path105.join("docs", "requirements", "shared-agent-context", "schemas");
33991
+ var NORMATIVE_SCHEMA_DIR = path106.join("docs", "requirements", "shared-agent-context", "schemas");
33732
33992
  async function resolveSacNormativeSchemaPath(fileName, searchFrom = [fileURLToPath3(new URL(".", import.meta.url)), process.cwd()]) {
33733
33993
  const seen = new Set;
33734
33994
  for (const start of searchFrom) {
33735
- let dir = path105.resolve(start);
33995
+ let dir = path106.resolve(start);
33736
33996
  for (let i = 0;i < 10; i++) {
33737
33997
  if (seen.has(dir))
33738
33998
  break;
33739
33999
  seen.add(dir);
33740
- const candidate = path105.join(dir, NORMATIVE_SCHEMA_DIR, fileName);
34000
+ const candidate = path106.join(dir, NORMATIVE_SCHEMA_DIR, fileName);
33741
34001
  try {
33742
34002
  await access3(candidate);
33743
34003
  return candidate;
33744
34004
  } catch {}
33745
- const parent = path105.dirname(dir);
34005
+ const parent = path106.dirname(dir);
33746
34006
  if (parent === dir)
33747
34007
  break;
33748
34008
  dir = parent;
@@ -33788,7 +34048,7 @@ function isRecord5(value) {
33788
34048
  async function loadNormativeSchema(schema) {
33789
34049
  let pending = normativeSchemas.get(schema);
33790
34050
  if (!pending) {
33791
- pending = resolveSacNormativeSchemaPath(normativeSchemaFiles[schema]).then((file) => readFile51(file, "utf8")).then((source) => JSON.parse(source));
34051
+ pending = resolveSacNormativeSchemaPath(normativeSchemaFiles[schema]).then((file) => readFile52(file, "utf8")).then((source) => JSON.parse(source));
33792
34052
  normativeSchemas.set(schema, pending);
33793
34053
  }
33794
34054
  return pending;
@@ -34411,20 +34671,20 @@ class SacReferenceError extends Error {
34411
34671
  code = "unsafe_workspace_reference";
34412
34672
  }
34413
34673
  async function resolveWorkspaceReference(input) {
34414
- if (!workspacePathPattern.test(input.uri) || path105.isAbsolute(input.uri) || /^[a-z][a-z0-9+.-]*:/i.test(input.uri) || input.uri.includes("\\"))
34674
+ if (!workspacePathPattern.test(input.uri) || path106.isAbsolute(input.uri) || /^[a-z][a-z0-9+.-]*:/i.test(input.uri) || input.uri.includes("\\"))
34415
34675
  throw new SacReferenceError("unsafe workspace reference");
34416
- const lexicalRoot = path105.resolve(input.workspaceRoot);
34417
- const root = await realpath11(lexicalRoot);
34418
- const candidate = path105.resolve(lexicalRoot, input.uri.slice(2));
34419
- if (candidate !== lexicalRoot && !candidate.startsWith(`${lexicalRoot}${path105.sep}`))
34676
+ const lexicalRoot = path106.resolve(input.workspaceRoot);
34677
+ const root = await realpath12(lexicalRoot);
34678
+ const candidate = path106.resolve(lexicalRoot, input.uri.slice(2));
34679
+ if (candidate !== lexicalRoot && !candidate.startsWith(`${lexicalRoot}${path106.sep}`))
34420
34680
  throw new SacReferenceError("workspace reference escapes root");
34421
34681
  let resolved;
34422
34682
  try {
34423
- resolved = await realpath11(candidate);
34683
+ resolved = await realpath12(candidate);
34424
34684
  } catch {
34425
34685
  throw new SacReferenceError("workspace reference is not resolvable");
34426
34686
  }
34427
- if (resolved !== root && !resolved.startsWith(`${root}${path105.sep}`))
34687
+ if (resolved !== root && !resolved.startsWith(`${root}${path106.sep}`))
34428
34688
  throw new SacReferenceError("workspace reference escapes root after realpath");
34429
34689
  return candidate;
34430
34690
  }
@@ -34478,18 +34738,18 @@ async function evaluateStrictSacGuard(input) {
34478
34738
 
34479
34739
  // src/sac/workspace-service.ts
34480
34740
  init_fs();
34481
- import { mkdir as mkdir30, readdir as readdir17, readFile as readFile52 } from "fs/promises";
34741
+ import { mkdir as mkdir30, readdir as readdir18, readFile as readFile53 } from "fs/promises";
34482
34742
  import { createHash as createHash19, randomUUID as randomUUID3 } from "crypto";
34483
- import path107 from "path";
34743
+ import path108 from "path";
34484
34744
 
34485
34745
  // src/sac/secure-resource-read.ts
34486
34746
  init_contained_read();
34487
34747
  init_descriptor_read();
34488
- import path106 from "path";
34748
+ import path107 from "path";
34489
34749
  function readWorkspaceFileNoFollow(workspaceRoot, absolutePath) {
34490
- const relativePath = path106.relative(workspaceRoot, absolutePath);
34491
- const components = relativePath.split(path106.sep);
34492
- if (!relativePath || path106.isAbsolute(relativePath) || components.some((component) => !component || component === "." || component === "..")) {
34750
+ const relativePath = path107.relative(workspaceRoot, absolutePath);
34751
+ const components = relativePath.split(path107.sep);
34752
+ if (!relativePath || path107.isAbsolute(relativePath) || components.some((component) => !component || component === "." || component === "..")) {
34493
34753
  throw new Error("safe source path is not workspace-relative");
34494
34754
  }
34495
34755
  return readDescriptorChain(workspaceRoot, absolutePath, {
@@ -34516,8 +34776,8 @@ class WorkspaceService {
34516
34776
  now;
34517
34777
  constructor(options) {
34518
34778
  this.options = options;
34519
- this.root = path107.resolve(options.workspaceRoot);
34520
- this.storageRoot = path107.resolve(options.storageRoot ?? path107.join(this.root, ".metaproject", "workspaces"));
34779
+ this.root = path108.resolve(options.workspaceRoot);
34780
+ this.storageRoot = path108.resolve(options.storageRoot ?? path108.join(this.root, ".metaproject", "workspaces"));
34521
34781
  this.now = options.now ?? (() => new Date);
34522
34782
  }
34523
34783
  async create(input) {
@@ -34540,7 +34800,7 @@ class WorkspaceService {
34540
34800
  await mkdir30(this.storageRoot, { recursive: true, mode: 448 });
34541
34801
  await withFileLock(this.lockPath(manifest.id), async () => {
34542
34802
  try {
34543
- await readFile52(this.manifestPath(manifest.id), "utf8");
34803
+ await readFile53(this.manifestPath(manifest.id), "utf8");
34544
34804
  throw new WorkspaceServiceError("conflict", "workspace already exists");
34545
34805
  } catch (error) {
34546
34806
  if (error instanceof WorkspaceServiceError || !isNotFound(error))
@@ -34569,7 +34829,7 @@ class WorkspaceService {
34569
34829
  } catch {
34570
34830
  return [];
34571
34831
  }
34572
- const entries = await readdir17(this.storageRoot, { withFileTypes: true });
34832
+ const entries = await readdir18(this.storageRoot, { withFileTypes: true });
34573
34833
  const visible = [];
34574
34834
  for (const entry of entries) {
34575
34835
  if (!entry.isDirectory())
@@ -34830,7 +35090,7 @@ class WorkspaceService {
34830
35090
  throw new WorkspaceServiceError("not_found", "workspace not found");
34831
35091
  let parsed;
34832
35092
  try {
34833
- parsed = JSON.parse(await readFile52(this.manifestPath(id), "utf8"));
35093
+ parsed = JSON.parse(await readFile53(this.manifestPath(id), "utf8"));
34834
35094
  } catch (error) {
34835
35095
  if (isNotFound(error))
34836
35096
  throw new WorkspaceServiceError("not_found", "workspace not found");
@@ -34842,13 +35102,13 @@ class WorkspaceService {
34842
35102
  return parsed;
34843
35103
  }
34844
35104
  workspaceDir(id) {
34845
- return path107.join(this.storageRoot, id);
35105
+ return path108.join(this.storageRoot, id);
34846
35106
  }
34847
35107
  manifestPath(id) {
34848
- return path107.join(this.workspaceDir(id), "workspace.json");
35108
+ return path108.join(this.workspaceDir(id), "workspace.json");
34849
35109
  }
34850
35110
  lockPath(id) {
34851
- return path107.join(this.storageRoot, `.${id}.lock`);
35111
+ return path108.join(this.storageRoot, `.${id}.lock`);
34852
35112
  }
34853
35113
  timestamp() {
34854
35114
  return this.now().toISOString();
@@ -35457,7 +35717,7 @@ var ledgerDigestChunkBytes = 64 * 1024;
35457
35717
  var isMissing = (error) => error instanceof Error && error.code === "ENOENT";
35458
35718
  var checkpointHash = (body) => createHash22("sha256").update(JSON.stringify(body), "utf8").digest("hex");
35459
35719
  async function ledgerByteLength(ledger) {
35460
- const value = await stat13(ledger, { bigint: true });
35720
+ const value = await stat14(ledger, { bigint: true });
35461
35721
  if (value.size > BigInt(Number.MAX_SAFE_INTEGER))
35462
35722
  throw new Error("invalid access receipt ledger: ledger-too-large");
35463
35723
  return Number(value.size);
@@ -35503,7 +35763,7 @@ function parseCheckpoint(value) {
35503
35763
  }
35504
35764
  async function readCheckpoint(checkpointPath) {
35505
35765
  try {
35506
- const raw = await readFile53(checkpointPath, "utf8");
35766
+ const raw = await readFile54(checkpointPath, "utf8");
35507
35767
  try {
35508
35768
  const checkpoint = parseCheckpoint(JSON.parse(raw));
35509
35769
  return checkpoint ? { present: true, checkpoint } : { present: true };
@@ -35571,7 +35831,7 @@ async function fastCheckpointState(ledger, checkpoint, ledgerBytes) {
35571
35831
  }
35572
35832
  }
35573
35833
  async function auditLedger(ledger, checkpointPath, verifier) {
35574
- const bytes = await readFile53(ledger);
35834
+ const bytes = await readFile54(ledger);
35575
35835
  const raw = bytes.toString("utf8");
35576
35836
  if (raw.length > 0 && !raw.endsWith(`
35577
35837
  `))
@@ -35621,7 +35881,7 @@ var isEvaluationReport = (report) => report.schemaVersion === "1.0" && asString2
35621
35881
  var isConfigRecord = (value) => typeof value.enabled === "boolean" && typeof value.killSwitch === "boolean";
35622
35882
  async function readPinnedJson(input) {
35623
35883
  const ref = await resolveWorkspaceReference({ workspaceRoot: input.workspaceRoot, kind: "artifact", uri: input.uri });
35624
- const raw = await readFile53(ref, "utf8");
35884
+ const raw = await readFile54(ref, "utf8");
35625
35885
  const digest = createHash22("sha256").update(raw).digest("hex");
35626
35886
  if (digest !== input.digest)
35627
35887
  throw new Error("policy experiment pinned artifact digest mismatch");
@@ -35629,7 +35889,7 @@ async function readPinnedJson(input) {
35629
35889
  }
35630
35890
  async function readWorkspaceJson(input) {
35631
35891
  const ref = await resolveWorkspaceReference({ workspaceRoot: input.workspaceRoot, kind: "artifact", uri: input.uri });
35632
- const raw = await readFile53(ref, "utf8");
35892
+ const raw = await readFile54(ref, "utf8");
35633
35893
  return { artifact: JSON.parse(raw), raw };
35634
35894
  }
35635
35895
  function hasReportIntegrity(report) {
@@ -35637,10 +35897,10 @@ function hasReportIntegrity(report) {
35637
35897
  return reportHashPattern.test(reportDigest) && sha2564(body) === reportDigest;
35638
35898
  }
35639
35899
  async function resolvePolicySelection(workspaceRoot, canonicalFallback) {
35640
- const configPath = path108.join(workspaceRoot, ...policyExperimentConfigPath);
35900
+ const configPath = path109.join(workspaceRoot, ...policyExperimentConfigPath);
35641
35901
  let configJson;
35642
35902
  try {
35643
- const raw = await readFile53(configPath, "utf8").catch((error) => {
35903
+ const raw = await readFile54(configPath, "utf8").catch((error) => {
35644
35904
  if (isMissing(error))
35645
35905
  return;
35646
35906
  throw error;
@@ -35835,9 +36095,9 @@ class FwkReadService {
35835
36095
  const recordedAt = nowIso(now);
35836
36096
  const id = `receipt-${randomUUID4().replace(/-/g, "").slice(0, 16)}`;
35837
36097
  const base = { schemaVersion: "1.0", id, workspaceId, actor, action, decision, recordedAt, cost: { tokens: 0, toolCalls: 1, elapsedMs: 0 }, contextAssembly: { traceRef: assembly.traceRef, configurationRevision: assembly.configurationRevision, selected: assembly.selected.map((id) => `./ids/${id}`), omittedOptional: assembly.omittedOptional.map((id) => `./ids/${id}`) }, policy: { ref: assembly.policyRef, revision: assembly.policyRevision }, ...action === "resource" ? { resourceRef: `./ids/${resourceId ?? "unknown"}` } : {} };
35838
- const ledger = path108.join(this.options.canonical.workspaceRoot, ".metaproject", "context-operations", "access-receipts.jsonl");
35839
- const checkpointPath = path108.join(path108.dirname(ledger), "access-receipts.checkpoint.json");
35840
- await mkdir31(path108.dirname(ledger), { recursive: true, mode: 448 });
36098
+ const ledger = path109.join(this.options.canonical.workspaceRoot, ".metaproject", "context-operations", "access-receipts.jsonl");
36099
+ const checkpointPath = path109.join(path109.dirname(ledger), "access-receipts.checkpoint.json");
36100
+ await mkdir31(path109.dirname(ledger), { recursive: true, mode: 448 });
35841
36101
  return withFileLock(`${ledger}.lock`, async () => {
35842
36102
  const state = await resolveLedgerState(ledger, checkpointPath, this.options.verifyReceiptLedger ?? verifyAccessReceiptLedger);
35843
36103
  const receipt = sealAccessReceipt(base, state.headHash);
@@ -35940,8 +36200,8 @@ function normalizeFwkResult(result) {
35940
36200
  // src/sac/proposal-lifecycle.ts
35941
36201
  init_fs();
35942
36202
  import { createHash as createHash29, randomUUID as randomUUID7 } from "crypto";
35943
- import { appendFile as appendFile7, mkdir as mkdir34, readdir as readdir19, readFile as readFile62 } from "fs/promises";
35944
- import path118 from "path";
36203
+ import { appendFile as appendFile7, mkdir as mkdir34, readdir as readdir20, readFile as readFile63 } from "fs/promises";
36204
+ import path119 from "path";
35945
36205
 
35946
36206
  // src/sac/trusted-wrap-up.ts
35947
36207
  import { createHash as createHash23, randomUUID as randomUUID5 } from "crypto";
@@ -36013,7 +36273,7 @@ function bindingHash(owner, intent) {
36013
36273
  // src/sac/session-wrap-up.ts
36014
36274
  import { createHash as createHash25 } from "crypto";
36015
36275
  import { mkdir as mkdir33, writeFile as writeFile22 } from "fs/promises";
36016
- import path112 from "path";
36276
+ import path113 from "path";
36017
36277
 
36018
36278
  // src/session/store.ts
36019
36279
  init_config_dir();
@@ -36025,12 +36285,12 @@ import {
36025
36285
  renameSync as renameSync2,
36026
36286
  writeFileSync as writeFileSync2
36027
36287
  } from "fs";
36028
- import path111 from "path";
36288
+ import path112 from "path";
36029
36289
 
36030
36290
  // src/session/paths.ts
36031
36291
  import { existsSync as existsSync16 } from "fs";
36032
36292
  import { homedir } from "os";
36033
- import path109 from "path";
36293
+ import path110 from "path";
36034
36294
  function keryxDataDir(override) {
36035
36295
  if (override !== undefined && override.length > 0) {
36036
36296
  return override;
@@ -36042,22 +36302,22 @@ function keryxDataDir(override) {
36042
36302
  const home = homedir();
36043
36303
  if (process.platform === "win32") {
36044
36304
  const appData = process.env.APPDATA;
36045
- const base = appData !== undefined && appData.length > 0 ? appData : path109.join(home, "AppData", "Roaming");
36046
- return path109.join(base, "keryx");
36305
+ const base = appData !== undefined && appData.length > 0 ? appData : path110.join(home, "AppData", "Roaming");
36306
+ return path110.join(base, "keryx");
36047
36307
  }
36048
36308
  const xdg = process.env.XDG_DATA_HOME;
36049
- const base = xdg !== undefined && xdg.length > 0 ? xdg : path109.join(home, ".local", "share");
36050
- return path109.join(base, "keryx");
36309
+ const base = xdg !== undefined && xdg.length > 0 ? xdg : path110.join(home, ".local", "share");
36310
+ return path110.join(base, "keryx");
36051
36311
  }
36052
36312
  function resolveProjectRoot2(cwd) {
36053
- const abs = path109.resolve(cwd);
36313
+ const abs = path110.resolve(cwd);
36054
36314
  let dir = abs;
36055
36315
  for (;; ) {
36056
- const gitPath = path109.join(dir, ".git");
36316
+ const gitPath = path110.join(dir, ".git");
36057
36317
  if (existsSync16(gitPath)) {
36058
36318
  return dir;
36059
36319
  }
36060
- const parent = path109.dirname(dir);
36320
+ const parent = path110.dirname(dir);
36061
36321
  if (parent === dir) {
36062
36322
  break;
36063
36323
  }
@@ -36066,12 +36326,12 @@ function resolveProjectRoot2(cwd) {
36066
36326
  return abs;
36067
36327
  }
36068
36328
  function projectKeyFromPath(projectPath) {
36069
- const abs = path109.resolve(projectPath);
36329
+ const abs = path110.resolve(projectPath);
36070
36330
  const encoded = encodeURIComponent(abs);
36071
36331
  if (encoded.length <= 200) {
36072
36332
  return encoded;
36073
36333
  }
36074
- const base = path109.basename(abs).replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 40);
36334
+ const base = path110.basename(abs).replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 40);
36075
36335
  let h = 0;
36076
36336
  for (let i = 0;i < abs.length; i++) {
36077
36337
  h = Math.imul(31, h) + abs.charCodeAt(i) | 0;
@@ -36081,17 +36341,17 @@ function projectKeyFromPath(projectPath) {
36081
36341
  }
36082
36342
  function projectSessionsDir(projectPath, dataDir) {
36083
36343
  const key = projectKeyFromPath(resolveProjectRoot2(projectPath));
36084
- return path109.join(keryxDataDir(dataDir), "sessions", key);
36344
+ return path110.join(keryxDataDir(dataDir), "sessions", key);
36085
36345
  }
36086
36346
  function sessionDir(projectPath, sessionId, dataDir) {
36087
- return path109.join(projectSessionsDir(projectPath, dataDir), sessionId);
36347
+ return path110.join(projectSessionsDir(projectPath, dataDir), sessionId);
36088
36348
  }
36089
36349
 
36090
36350
  // src/session/slate.ts
36091
36351
  init_fs();
36092
36352
  init_assembly();
36093
- import { mkdir as mkdir32, readFile as readFile54, rm as rm7 } from "fs/promises";
36094
- import path110 from "path";
36353
+ import { mkdir as mkdir32, readFile as readFile55, rm as rm7 } from "fs/promises";
36354
+ import path111 from "path";
36095
36355
  init_redact();
36096
36356
  var SLATE_SEED_KINDS = [
36097
36357
  "decision",
@@ -36106,14 +36366,14 @@ function isSlateSeedKind(value) {
36106
36366
  }
36107
36367
  var SEED_TEXT_MAX_LENGTH = 4000;
36108
36368
  function slatePath(dir) {
36109
- return path110.join(dir, "slate.json");
36369
+ return path111.join(dir, "slate.json");
36110
36370
  }
36111
36371
  function slateLockPath(dir) {
36112
36372
  return `${slatePath(dir)}.lock`;
36113
36373
  }
36114
36374
  async function readSlate(dir) {
36115
36375
  try {
36116
- const raw = await readFile54(slatePath(dir), "utf8");
36376
+ const raw = await readFile55(slatePath(dir), "utf8");
36117
36377
  return JSON.parse(raw);
36118
36378
  } catch (error) {
36119
36379
  if (isNotFound(error))
@@ -36329,11 +36589,11 @@ function listSessions(cwd, dataDir) {
36329
36589
  if (name.startsWith(".")) {
36330
36590
  continue;
36331
36591
  }
36332
- const summary = readSummaryFile(path111.join(root, name, "summary.json"));
36592
+ const summary = readSummaryFile(path112.join(root, name, "summary.json"));
36333
36593
  if (summary === undefined) {
36334
36594
  continue;
36335
36595
  }
36336
- if (path111.resolve(summary.projectPath) !== path111.resolve(projectPath)) {
36596
+ if (path112.resolve(summary.projectPath) !== path112.resolve(projectPath)) {
36337
36597
  continue;
36338
36598
  }
36339
36599
  out.push(summary);
@@ -36366,15 +36626,15 @@ async function readSessionSlate(cwd, sessionId, dataDir) {
36366
36626
  }
36367
36627
  function loadContext(cwd, sessionId, dataDir) {
36368
36628
  const dir = sessionDir(resolveProjectRoot2(cwd), sessionId, dataDir);
36369
- const contextPath = path111.join(dir, "context.jsonl");
36629
+ const contextPath = path112.join(dir, "context.jsonl");
36370
36630
  if (existsSync17(contextPath)) {
36371
36631
  return readJsonl2(contextPath);
36372
36632
  }
36373
- return readJsonl2(path111.join(dir, "transcript.jsonl"));
36633
+ return readJsonl2(path112.join(dir, "transcript.jsonl"));
36374
36634
  }
36375
36635
  function loadArchive(cwd, sessionId, dataDir, onDegraded) {
36376
36636
  const dir = sessionDir(resolveProjectRoot2(cwd), sessionId, dataDir);
36377
- const archivePath = path111.join(dir, "archive.jsonl");
36637
+ const archivePath = path112.join(dir, "archive.jsonl");
36378
36638
  if (existsSync17(archivePath)) {
36379
36639
  try {
36380
36640
  const archive = readJsonl2(archivePath);
@@ -36558,7 +36818,7 @@ function sessionEvidenceRef(workspaceId, sessionId) {
36558
36818
  }
36559
36819
  async function resolveSessionWrapUp(input) {
36560
36820
  const now = input.now ?? (() => new Date);
36561
- const sessionId = path112.posix.basename(input.sourceRef, ".md");
36821
+ const sessionId = path113.posix.basename(input.sourceRef, ".md");
36562
36822
  const summary = findSession(input.cwd, sessionId);
36563
36823
  if (summary === undefined || input.sourceRef !== sessionEvidenceRef(input.workspaceId, summary.id)) {
36564
36824
  throw new SessionWrapUpError("session_not_found", `no session matching "${input.sourceRef}" in this project \u2014 use \`keryx sessions list\``);
@@ -36575,7 +36835,7 @@ async function resolveSessionWrapUp(input) {
36575
36835
  throw new SessionWrapUpError("session_unreadable", `session "${summary.id}" could not be read: ${cause.message}`);
36576
36836
  }
36577
36837
  const relPath = sessionEvidenceRef(input.workspaceId, summary.id).slice(2);
36578
- const evidenceDir = path112.dirname(relPath);
36838
+ const evidenceDir = path113.dirname(relPath);
36579
36839
  const slate = await readSessionSlate(input.cwd, summary.id);
36580
36840
  const diff = await gitDiff(input.cwd);
36581
36841
  const diffBody = diff.kind === "measured" ? diff.text : unmeasurableDiffBody(diff.detail);
@@ -36597,23 +36857,23 @@ async function resolveSessionWrapUp(input) {
36597
36857
  ""
36598
36858
  ].join(`
36599
36859
  `);
36600
- const wrapUpRelPath = path112.join(evidenceDir, `${summary.id}.wrap-up.md`);
36601
- const diffRelPath = path112.join(evidenceDir, `${summary.id}.diff.txt`);
36602
- const noticeRelPath = path112.join(evidenceDir, `${summary.id}.redaction.md`);
36860
+ const wrapUpRelPath = path113.join(evidenceDir, `${summary.id}.wrap-up.md`);
36861
+ const diffRelPath = path113.join(evidenceDir, `${summary.id}.diff.txt`);
36862
+ const noticeRelPath = path113.join(evidenceDir, `${summary.id}.redaction.md`);
36603
36863
  const floor = await applyEvidenceRedactionFloor(input.cwd, [
36604
- { name: path112.basename(relPath), content: markdown, path: relPath, source: "generated" },
36605
- { name: path112.basename(wrapUpRelPath), content: wrapUpMarkdown, path: wrapUpRelPath, source: "generated" },
36606
- { name: path112.basename(diffRelPath), content: diffBody, path: diffRelPath, source: "tool-output" }
36864
+ { name: path113.basename(relPath), content: markdown, path: relPath, source: "generated" },
36865
+ { name: path113.basename(wrapUpRelPath), content: wrapUpMarkdown, path: wrapUpRelPath, source: "generated" },
36866
+ { name: path113.basename(diffRelPath), content: diffBody, path: diffRelPath, source: "tool-output" }
36607
36867
  ]);
36608
36868
  if (!floor.ok)
36609
36869
  throw new SessionWrapUpError("security_denied", floor.reason);
36610
36870
  const [safeSession, safeWrapUp, safeDiff] = floor.bodies;
36611
- await mkdir33(path112.join(input.cwd, evidenceDir), { recursive: true });
36612
- await writeFile22(path112.join(input.cwd, relPath), safeSession.content, "utf8");
36613
- await writeFile22(path112.join(input.cwd, wrapUpRelPath), safeWrapUp.content, "utf8");
36614
- await writeFile22(path112.join(input.cwd, diffRelPath), safeDiff.content, "utf8");
36871
+ await mkdir33(path113.join(input.cwd, evidenceDir), { recursive: true });
36872
+ await writeFile22(path113.join(input.cwd, relPath), safeSession.content, "utf8");
36873
+ await writeFile22(path113.join(input.cwd, wrapUpRelPath), safeWrapUp.content, "utf8");
36874
+ await writeFile22(path113.join(input.cwd, diffRelPath), safeDiff.content, "utf8");
36615
36875
  if (floor.notice !== undefined)
36616
- await writeFile22(path112.join(input.cwd, noticeRelPath), floor.notice, "utf8");
36876
+ await writeFile22(path113.join(input.cwd, noticeRelPath), floor.notice, "utf8");
36617
36877
  const observedAt = now().toISOString();
36618
36878
  const evidence = [
36619
36879
  { kind: "wrap-up", uri: `./${wrapUpRelPath}`, revision: createHash25("sha256").update(safeWrapUp.content).digest("hex"), observedAt },
@@ -36635,14 +36895,14 @@ async function resolveSessionWrapUp(input) {
36635
36895
  // src/sac/review-confirm-token.ts
36636
36896
  init_fs();
36637
36897
  import { createHash as createHash26, randomBytes as randomBytes5 } from "crypto";
36638
- import { readFile as readFile55 } from "fs/promises";
36639
- import path113 from "path";
36898
+ import { readFile as readFile56 } from "fs/promises";
36899
+ import path114 from "path";
36640
36900
  var CONFIRM_TOKEN_TTL_MS = 2 * 60000;
36641
36901
  function confirmTokenPath2(cwd, workspaceId, proposalId) {
36642
- return path113.join(cwd, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.confirm-token.json`);
36902
+ return path114.join(cwd, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.confirm-token.json`);
36643
36903
  }
36644
36904
  function confirmReceiptPath(cwd, workspaceId, proposalId, idempotencyKey) {
36645
- return path113.join(cwd, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.${sha2565(idempotencyKey)}.confirm-receipt.json`);
36905
+ return path114.join(cwd, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.${sha2565(idempotencyKey)}.confirm-receipt.json`);
36646
36906
  }
36647
36907
  function sha2565(text) {
36648
36908
  return createHash26("sha256").update(text).digest("hex");
@@ -36658,7 +36918,7 @@ async function consumeConfirmToken(cwd, workspaceId, proposalId, idempotencyKey,
36658
36918
  return { ok: false, reason: "token_required" };
36659
36919
  let stored;
36660
36920
  try {
36661
- stored = JSON.parse(await readFile55(file, "utf8"));
36921
+ stored = JSON.parse(await readFile56(file, "utf8"));
36662
36922
  } catch (error) {
36663
36923
  return { ok: false, reason: isNotFound(error) ? "token_required" : "token_invalid" };
36664
36924
  }
@@ -36681,28 +36941,28 @@ async function consumeConfirmToken(cwd, workspaceId, proposalId, idempotencyKey,
36681
36941
  init_dedup();
36682
36942
  init_store();
36683
36943
  init_config();
36684
- import { readFile as readFile57, readdir as readdir18 } from "fs/promises";
36944
+ import { readFile as readFile58, readdir as readdir19 } from "fs/promises";
36685
36945
  import { randomUUID as randomUUID6 } from "crypto";
36686
- import path115 from "path";
36946
+ import path116 from "path";
36687
36947
 
36688
36948
  // src/sac/proposal-evidence.ts
36689
36949
  init_fs();
36690
36950
  import { createHash as createHash27 } from "crypto";
36691
- import { readFile as readFile56, rm as rm8 } from "fs/promises";
36692
- import path114 from "path";
36951
+ import { readFile as readFile57, rm as rm8 } from "fs/promises";
36952
+ import path115 from "path";
36693
36953
  function proposalPath(cwd, workspaceId, proposalId) {
36694
- return path114.join(cwd, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.json`);
36954
+ return path115.join(cwd, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.json`);
36695
36955
  }
36696
36956
  function ownerReceiptPath(cwd, owner, workspaceId, idempotencyKey) {
36697
- return path114.join(cwd, ".metaproject", "workspaces", workspaceId, `${owner}-write-receipts`, `${idempotencyKey}.json`);
36957
+ return path115.join(cwd, ".metaproject", "workspaces", workspaceId, `${owner}-write-receipts`, `${idempotencyKey}.json`);
36698
36958
  }
36699
36959
  function proposalNotePath(cwd, workspaceId, proposalId) {
36700
- return path114.join(cwd, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.note.txt`);
36960
+ return path115.join(cwd, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.note.txt`);
36701
36961
  }
36702
36962
  async function readVerifiedProposalEvidence(cwd, workspaceId, proposalId) {
36703
36963
  let proposal;
36704
36964
  try {
36705
- proposal = JSON.parse(await readFile56(proposalPath(cwd, workspaceId, proposalId), "utf8"));
36965
+ proposal = JSON.parse(await readFile57(proposalPath(cwd, workspaceId, proposalId), "utf8"));
36706
36966
  } catch {
36707
36967
  return { ok: false, code: "proposal_record_unreadable" };
36708
36968
  }
@@ -36711,7 +36971,7 @@ async function readVerifiedProposalEvidence(cwd, workspaceId, proposalId) {
36711
36971
  return { ok: false, code: "no_evidence_to_write" };
36712
36972
  let content;
36713
36973
  try {
36714
- content = await readFile56(path114.join(cwd, evidence.uri), "utf8");
36974
+ content = await readFile57(path115.join(cwd, evidence.uri), "utf8");
36715
36975
  } catch {
36716
36976
  return { ok: false, code: "evidence_file_unreadable" };
36717
36977
  }
@@ -36721,7 +36981,7 @@ async function readVerifiedProposalEvidence(cwd, workspaceId, proposalId) {
36721
36981
  return { proposal, evidence, content };
36722
36982
  }
36723
36983
  async function readSidecarNote(cwd, workspaceId, proposalId) {
36724
- return readFile56(proposalNotePath(cwd, workspaceId, proposalId), "utf8").catch(() => {
36984
+ return readFile57(proposalNotePath(cwd, workspaceId, proposalId), "utf8").catch(() => {
36725
36985
  return;
36726
36986
  });
36727
36987
  }
@@ -36730,7 +36990,7 @@ function digestOf2(content) {
36730
36990
  }
36731
36991
  async function readTargetVersion(absolutePath) {
36732
36992
  try {
36733
- return digestOf2(await readFile56(absolutePath, "utf8"));
36993
+ return digestOf2(await readFile57(absolutePath, "utf8"));
36734
36994
  } catch (error) {
36735
36995
  if (isNotFound(error))
36736
36996
  return null;
@@ -36741,26 +37001,26 @@ function targetRelPath(targetRef) {
36741
37001
  return targetRef.replace(/^\.\//, "");
36742
37002
  }
36743
37003
  function targetAbsolutePath(cwd, targetRef) {
36744
- return path114.join(cwd, ".metaproject", targetRelPath(targetRef));
37004
+ return path115.join(cwd, ".metaproject", targetRelPath(targetRef));
36745
37005
  }
36746
37006
  function targetKey(targetRef) {
36747
37007
  return digestOf2(targetRelPath(targetRef)).slice(0, 32);
36748
37008
  }
36749
37009
  function ownerTargetVersionPath(cwd, owner, workspaceId, targetRef) {
36750
- return path114.join(cwd, ".metaproject", "workspaces", workspaceId, `${owner}-target-versions`, `${targetKey(targetRef)}.json`);
37010
+ return path115.join(cwd, ".metaproject", "workspaces", workspaceId, `${owner}-target-versions`, `${targetKey(targetRef)}.json`);
36751
37011
  }
36752
37012
  function ownerTargetLockPath(cwd, owner, targetRef) {
36753
- return path114.join(cwd, ".metaproject", "data", "sac", "target-locks", owner, `${targetKey(targetRef)}.lock`);
37013
+ return path115.join(cwd, ".metaproject", "data", "sac", "target-locks", owner, `${targetKey(targetRef)}.lock`);
36754
37014
  }
36755
37015
  function ownerStagingDir(cwd, owner, workspaceId, idempotencyKey) {
36756
- return path114.join(cwd, ".metaproject", "workspaces", workspaceId, `${owner}-write-staging`, digestOf2(idempotencyKey).slice(0, 32));
37016
+ return path115.join(cwd, ".metaproject", "workspaces", workspaceId, `${owner}-write-staging`, digestOf2(idempotencyKey).slice(0, 32));
36757
37017
  }
36758
37018
  function ownerConflictDir(cwd, owner, workspaceId, idempotencyKey) {
36759
- return path114.join(cwd, ".metaproject", "workspaces", workspaceId, `${owner}-write-conflicts`, digestOf2(idempotencyKey).slice(0, 32));
37019
+ return path115.join(cwd, ".metaproject", "workspaces", workspaceId, `${owner}-write-conflicts`, digestOf2(idempotencyKey).slice(0, 32));
36760
37020
  }
36761
37021
  async function readJson2(file) {
36762
37022
  try {
36763
- return JSON.parse(await readFile56(file, "utf8"));
37023
+ return JSON.parse(await readFile57(file, "utf8"));
36764
37024
  } catch {
36765
37025
  return;
36766
37026
  }
@@ -36827,7 +37087,7 @@ async function applyGuardedTargetWrite(input) {
36827
37087
  staged: input.staged,
36828
37088
  stagedAt: receipt.completedAt
36829
37089
  };
36830
- await writeFileAtomic(path114.join(ownerStagingDir(cwd, owner, intent.workspaceId, intent.idempotencyKey), "plan.json"), `${JSON.stringify(staged, null, 2)}
37090
+ await writeFileAtomic(path115.join(ownerStagingDir(cwd, owner, intent.workspaceId, intent.idempotencyKey), "plan.json"), `${JSON.stringify(staged, null, 2)}
36831
37091
  `);
36832
37092
  const applied = await input.apply(input.staged);
36833
37093
  if (!applied.ok) {
@@ -36853,15 +37113,15 @@ async function recoverStagedOwnerWrite(input) {
36853
37113
  });
36854
37114
  }
36855
37115
  async function readStagedOwnerWrite(cwd, owner, workspaceId, idempotencyKey) {
36856
- return readJson2(path114.join(ownerStagingDir(cwd, owner, workspaceId, idempotencyKey), "plan.json"));
37116
+ return readJson2(path115.join(ownerStagingDir(cwd, owner, workspaceId, idempotencyKey), "plan.json"));
36857
37117
  }
36858
37118
  async function recordConflict(input) {
36859
37119
  const base = { targetRef: input.targetRef, expectedVersion: input.expectedVersion, currentVersion: input.currentVersion };
36860
37120
  if (input.proposedContent === undefined)
36861
37121
  return base;
36862
37122
  const dir = ownerConflictDir(input.cwd, input.owner, input.intent.workspaceId, input.intent.idempotencyKey);
36863
- await writeFileAtomic(path114.join(dir, "proposed"), input.proposedContent);
36864
- const diffRef = `./workspaces/${input.intent.workspaceId}/${input.owner}-write-conflicts/${path114.basename(dir)}/proposed`;
37123
+ await writeFileAtomic(path115.join(dir, "proposed"), input.proposedContent);
37124
+ const diffRef = `./workspaces/${input.intent.workspaceId}/${input.owner}-write-conflicts/${path115.basename(dir)}/proposed`;
36865
37125
  return { ...base, diffRef };
36866
37126
  }
36867
37127
 
@@ -36911,21 +37171,21 @@ async function resolveWorkspaceModule(cwd, workspaceId) {
36911
37171
  }
36912
37172
  }
36913
37173
  async function collectWikiDecisionEntries(cwd) {
36914
- const dir = path115.join(cwd, ".metaproject", "wiki", "decisions");
37174
+ const dir = path116.join(cwd, ".metaproject", "wiki", "decisions");
36915
37175
  let files;
36916
37176
  try {
36917
- files = (await readdir18(dir)).filter((name) => name.endsWith(".md"));
37177
+ files = (await readdir19(dir)).filter((name) => name.endsWith(".md"));
36918
37178
  } catch {
36919
37179
  return [];
36920
37180
  }
36921
37181
  const entries = [];
36922
37182
  for (const file of files) {
36923
- const absolutePath = path115.join(dir, file);
37183
+ const absolutePath = path116.join(dir, file);
36924
37184
  try {
36925
- const content = await readFile57(absolutePath, "utf8");
37185
+ const content = await readFile58(absolutePath, "utf8");
36926
37186
  entries.push({
36927
37187
  absolutePath,
36928
- relativePath: path115.posix.join("decisions", file),
37188
+ relativePath: path116.posix.join("decisions", file),
36929
37189
  type: extractHeaderField(content, "Type") ?? "decision",
36930
37190
  title: extractTitle(content),
36931
37191
  version: extractHeaderField(content, "Version") ?? null,
@@ -37039,7 +37299,7 @@ ${candidates}`;
37039
37299
 
37040
37300
  // src/sac/memory-owner-writer.ts
37041
37301
  init_write();
37042
- import { readFile as readFile58 } from "fs/promises";
37302
+ import { readFile as readFile59 } from "fs/promises";
37043
37303
  function renderWrapUpMemoryEntry(input) {
37044
37304
  const note = input.note?.trim();
37045
37305
  return `# ${input.title}
@@ -37098,7 +37358,7 @@ function createRealMemoryOwnerWriter(cwd, opts) {
37098
37358
  },
37099
37359
  async recover(intent) {
37100
37360
  try {
37101
- const raw = await readFile58(ownerReceiptPath(cwd, "memory", intent.workspaceId, intent.idempotencyKey), "utf8");
37361
+ const raw = await readFile59(ownerReceiptPath(cwd, "memory", intent.workspaceId, intent.idempotencyKey), "utf8");
37102
37362
  return JSON.parse(raw);
37103
37363
  } catch {
37104
37364
  return;
@@ -37146,8 +37406,8 @@ function createRealMemoryOwnerWriter(cwd, opts) {
37146
37406
  // src/sac/wiki-owner-writer.ts
37147
37407
  init_fs();
37148
37408
  init_guard();
37149
- import { readFile as readFile59 } from "fs/promises";
37150
- import path116 from "path";
37409
+ import { readFile as readFile60 } from "fs/promises";
37410
+ import path117 from "path";
37151
37411
  function renderWrapUpDecisionPage(input) {
37152
37412
  const note = input.note?.trim();
37153
37413
  return `# ${input.title}
@@ -37188,14 +37448,14 @@ export is the source of truth for what actually happened.
37188
37448
  `;
37189
37449
  }
37190
37450
  function wikiPageRelativePath(proposalId) {
37191
- return path116.posix.join("decisions", `sac-${proposalId}.md`);
37451
+ return path117.posix.join("decisions", `sac-${proposalId}.md`);
37192
37452
  }
37193
37453
  function createRealWikiOwnerWriter(cwd, opts) {
37194
37454
  const now = opts?.now ?? (() => new Date);
37195
37455
  const applyStaged = async (staged) => {
37196
37456
  const relativePath = staged.relativePath;
37197
37457
  const content = staged.content;
37198
- await writeFileAtomic(path116.join(cwd, ".metaproject", "wiki", relativePath), content);
37458
+ await writeFileAtomic(path117.join(cwd, ".metaproject", "wiki", relativePath), content);
37199
37459
  return { ok: true };
37200
37460
  };
37201
37461
  return {
@@ -37204,7 +37464,7 @@ function createRealWikiOwnerWriter(cwd, opts) {
37204
37464
  },
37205
37465
  async recover(intent) {
37206
37466
  try {
37207
- const raw = await readFile59(ownerReceiptPath(cwd, "wiki", intent.workspaceId, intent.idempotencyKey), "utf8");
37467
+ const raw = await readFile60(ownerReceiptPath(cwd, "wiki", intent.workspaceId, intent.idempotencyKey), "utf8");
37208
37468
  return JSON.parse(raw);
37209
37469
  } catch {
37210
37470
  return;
@@ -37255,7 +37515,7 @@ function createRealWikiOwnerWriter(cwd, opts) {
37255
37515
  }
37256
37516
 
37257
37517
  // src/sac/skill-owner-writer.ts
37258
- import { readFile as readFile61 } from "fs/promises";
37518
+ import { readFile as readFile62 } from "fs/promises";
37259
37519
 
37260
37520
  // src/gdskills/project-skills.ts
37261
37521
  init_contained_write();
@@ -37264,8 +37524,8 @@ init_json();
37264
37524
  init_guard();
37265
37525
  import { createHash as createHash28 } from "crypto";
37266
37526
  import { homedir as homedir2 } from "os";
37267
- import { readFile as readFile60, stat as stat14 } from "fs/promises";
37268
- import path117 from "path";
37527
+ import { readFile as readFile61, stat as stat15 } from "fs/promises";
37528
+ import path118 from "path";
37269
37529
  var VERSION = "0.1.0";
37270
37530
  var PROJECT_SKILLS_DIR = ".metaproject/project-skills";
37271
37531
  var PROJECT_SKILLS_MANIFEST_PATH = ".metaproject/metaproject.json";
@@ -37295,7 +37555,7 @@ async function assertProjectWritesContained(projectRoot, paths) {
37295
37555
  }
37296
37556
  }
37297
37557
  async function createProjectSkill(projectRoot, options) {
37298
- const metaprojectRoot = path117.join(projectRoot, ".metaproject");
37558
+ const metaprojectRoot = path118.join(projectRoot, ".metaproject");
37299
37559
  if (!await pathExists(metaprojectRoot)) {
37300
37560
  throw new Error("Metaproject is not initialized. Run: keryx init");
37301
37561
  }
@@ -37306,7 +37566,7 @@ async function createProjectSkill(projectRoot, options) {
37306
37566
  const skillName = projectSkillSlug(options.name ?? inferSkillName(options.target));
37307
37567
  const format = options.format ?? "auto";
37308
37568
  const relativeSkillPath = projectSkillPackagePath(moduleName, skillName);
37309
- const packageRoot = path117.join(projectRoot, relativeSkillPath);
37569
+ const packageRoot = path118.join(projectRoot, relativeSkillPath);
37310
37570
  await assertProjectWritesContained(projectRoot, projectSkillWritePaths(moduleName, skillName, format));
37311
37571
  const origin = options.origin ? options.originContent !== undefined ? {
37312
37572
  ref: options.origin.trim(),
@@ -37317,7 +37577,7 @@ async function createProjectSkill(projectRoot, options) {
37317
37577
  const warnings = collectWarnings(evidence, format);
37318
37578
  const files = filesForPackage(packageRoot, format);
37319
37579
  if (!options.dryRun) {
37320
- await withFileLock(path117.join(projectRoot, PROJECT_SKILLS_LOCK_PATH), async () => {
37580
+ await withFileLock(path118.join(projectRoot, PROJECT_SKILLS_LOCK_PATH), async () => {
37321
37581
  await writeProjectSkillPackage({
37322
37582
  projectRoot,
37323
37583
  packageRoot,
@@ -37346,7 +37606,7 @@ async function createProjectSkill(projectRoot, options) {
37346
37606
  name: skillName,
37347
37607
  target: options.target,
37348
37608
  skillPath: relativeSkillPath,
37349
- files: files.map((filePath) => toPosix(path117.relative(projectRoot, filePath))),
37609
+ files: files.map((filePath) => toPosix(path118.relative(projectRoot, filePath))),
37350
37610
  warnings,
37351
37611
  dryRun: options.dryRun === true
37352
37612
  };
@@ -37355,9 +37615,9 @@ var MAX_SKILL_TARGET_LENGTH = 80;
37355
37615
  function resolveOriginPath(ref, projectRoot) {
37356
37616
  const trimmed = ref.trim();
37357
37617
  if (trimmed === "~" || trimmed.startsWith("~/")) {
37358
- return path117.join(homedir2(), trimmed.slice(1));
37618
+ return path118.join(homedir2(), trimmed.slice(1));
37359
37619
  }
37360
- return path117.resolve(projectRoot, trimmed);
37620
+ return path118.resolve(projectRoot, trimmed);
37361
37621
  }
37362
37622
  function hashOriginContent(content) {
37363
37623
  return `sha256:${createHash28("sha256").update(content).digest("hex")}`;
@@ -37366,7 +37626,7 @@ async function readSkillOrigin(projectRoot, ref, now = () => new Date) {
37366
37626
  const resolved = resolveOriginPath(ref, projectRoot);
37367
37627
  let content;
37368
37628
  try {
37369
- content = await readFile60(resolved, "utf8");
37629
+ content = await readFile61(resolved, "utf8");
37370
37630
  } catch (cause) {
37371
37631
  throw new Error(`Cannot read the origin file ${ref} (resolved to ${resolved}): ${cause instanceof Error ? cause.message : String(cause)}`);
37372
37632
  }
@@ -37395,16 +37655,16 @@ async function writeProjectSkillPackage({
37395
37655
  }) {
37396
37656
  const packageFormat = format === "single" ? "single" : "package";
37397
37657
  const skillContent = renderProjectSkill({ moduleName, skillName, target, note, origin, evidence, packageFormat });
37398
- const relativeSkillMdPath = toPosix(path117.join(path117.relative(projectRoot, packageRoot), "SKILL.md"));
37658
+ const relativeSkillMdPath = toPosix(path118.join(path118.relative(projectRoot, packageRoot), "SKILL.md"));
37399
37659
  const guard = await guardOutput({ cwd: projectRoot, content: skillContent, target: "skill", source: "generated", path: relativeSkillMdPath });
37400
37660
  const output = prepareOutputForPersistence(guard, skillContent);
37401
37661
  if (!output.allowed) {
37402
37662
  throw new Error(`Project skill blocked by the security gate: ${output.reason}`);
37403
37663
  }
37404
- const packageRel = toPosix(path117.relative(projectRoot, packageRoot));
37664
+ const packageRel = toPosix(path118.relative(projectRoot, packageRoot));
37405
37665
  const write = (file, content) => writeContained(projectRoot, `${packageRel}/${file}`, content);
37406
37666
  await write("SKILL.md", output.content);
37407
- if (!await pathExists(path117.join(packageRoot, "skill-changelog.md"))) {
37667
+ if (!await pathExists(path118.join(packageRoot, "skill-changelog.md"))) {
37408
37668
  await write("skill-changelog.md", renderSkillChangelog({ moduleName, skillName, target }));
37409
37669
  }
37410
37670
  if (packageFormat === "package") {
@@ -37414,10 +37674,10 @@ async function writeProjectSkillPackage({
37414
37674
  }
37415
37675
  }
37416
37676
  async function collectEvidence(projectRoot, target) {
37417
- const absoluteTarget = path117.resolve(projectRoot, target);
37677
+ const absoluteTarget = path118.resolve(projectRoot, target);
37418
37678
  const targetExists = await pathExists(absoluteTarget);
37419
37679
  const targetKind = await classifyTarget(absoluteTarget, targetExists);
37420
- const maybeRelativeTarget = targetExists ? toPosix(path117.relative(projectRoot, absoluteTarget)) : undefined;
37680
+ const maybeRelativeTarget = targetExists ? toPosix(path118.relative(projectRoot, absoluteTarget)) : undefined;
37421
37681
  const graphArtifacts = await existingRelativePaths(projectRoot, [
37422
37682
  ".metaproject/data/gdgraph/artifacts/summary.md",
37423
37683
  ".metaproject/data/gdgraph/artifacts/module-map.json"
@@ -37441,13 +37701,13 @@ async function classifyTarget(absoluteTarget, targetExists) {
37441
37701
  if (!targetExists) {
37442
37702
  return "symbol-or-concept";
37443
37703
  }
37444
- const stats = await stat14(absoluteTarget);
37704
+ const stats = await stat15(absoluteTarget);
37445
37705
  return stats.isDirectory() ? "directory" : "file";
37446
37706
  }
37447
37707
  async function existingRelativePaths(projectRoot, candidates) {
37448
37708
  const existing = [];
37449
37709
  for (const candidate of candidates) {
37450
- if (await pathExists(path117.join(projectRoot, candidate))) {
37710
+ if (await pathExists(path118.join(projectRoot, candidate))) {
37451
37711
  existing.push(candidate);
37452
37712
  }
37453
37713
  }
@@ -37474,17 +37734,17 @@ function collectWarnings(evidence, format) {
37474
37734
  }
37475
37735
  function filesForPackage(packageRoot, format) {
37476
37736
  const base = [
37477
- path117.join(packageRoot, "SKILL.md"),
37478
- path117.join(packageRoot, "skill-changelog.md")
37737
+ path118.join(packageRoot, "SKILL.md"),
37738
+ path118.join(packageRoot, "skill-changelog.md")
37479
37739
  ];
37480
37740
  if (format === "single") {
37481
37741
  return base;
37482
37742
  }
37483
37743
  return [
37484
37744
  ...base,
37485
- path117.join(packageRoot, "verification.md"),
37486
- path117.join(packageRoot, "references", "context.md"),
37487
- path117.join(packageRoot, "templates", "README.md")
37745
+ path118.join(packageRoot, "verification.md"),
37746
+ path118.join(packageRoot, "references", "context.md"),
37747
+ path118.join(packageRoot, "templates", "README.md")
37488
37748
  ];
37489
37749
  }
37490
37750
  function renderProjectSkill({
@@ -37712,7 +37972,7 @@ keryx skills verify ${moduleName}/${skillName}
37712
37972
  `;
37713
37973
  }
37714
37974
  async function updateManifest(projectRoot, entry) {
37715
- const manifestPath = path117.join(projectRoot, PROJECT_SKILLS_MANIFEST_PATH);
37975
+ const manifestPath = path118.join(projectRoot, PROJECT_SKILLS_MANIFEST_PATH);
37716
37976
  const manifest = await readJsonFileOr(manifestPath, {});
37717
37977
  manifest.modules ??= {};
37718
37978
  manifest.modules.gdskills ??= {};
@@ -37726,8 +37986,8 @@ async function updateManifest(projectRoot, entry) {
37726
37986
  `);
37727
37987
  }
37728
37988
  async function updateSkillsCatalog(projectRoot) {
37729
- const manifestPath = path117.join(projectRoot, PROJECT_SKILLS_MANIFEST_PATH);
37730
- const catalogPath = path117.join(projectRoot, PROJECT_SKILLS_CATALOG_PATH);
37989
+ const manifestPath = path118.join(projectRoot, PROJECT_SKILLS_MANIFEST_PATH);
37990
+ const catalogPath = path118.join(projectRoot, PROJECT_SKILLS_CATALOG_PATH);
37731
37991
  const manifest = await readJsonFileOr(manifestPath, {});
37732
37992
  const registry = manifest.modules?.gdskills?.projectSkillRegistry ?? [];
37733
37993
  const rows = registry.length > 0 ? registry.map(projectSkillCatalogRow).join(`
@@ -37739,7 +37999,7 @@ async function updateSkillsCatalog(projectRoot) {
37739
37999
  |---|---|---|---|
37740
38000
  ${rows}
37741
38001
  ${PROJECT_SKILLS_CATALOG_END}`;
37742
- const current = await pathExists(catalogPath) ? await readFile60(catalogPath, "utf8") : `# Metaproject Skills Catalog
38002
+ const current = await pathExists(catalogPath) ? await readFile61(catalogPath, "utf8") : `# Metaproject Skills Catalog
37743
38003
  `;
37744
38004
  const start = PROJECT_SKILLS_CATALOG_START;
37745
38005
  const end = PROJECT_SKILLS_CATALOG_END;
@@ -37767,7 +38027,7 @@ function inferModule(target) {
37767
38027
  }
37768
38028
  function inferSkillName(target) {
37769
38029
  const normalized = target.trim().replace(/[#:]+/g, "/");
37770
- const base = path117.basename(normalized).replace(/\.[^.]+$/, "");
38030
+ const base = path118.basename(normalized).replace(/\.[^.]+$/, "");
37771
38031
  return base || "entity";
37772
38032
  }
37773
38033
  function projectSkillSlug(value) {
@@ -37814,7 +38074,7 @@ function createRealSkillOwnerWriter(cwd, opts) {
37814
38074
  },
37815
38075
  async recover(intent) {
37816
38076
  try {
37817
- const raw = await readFile61(ownerReceiptPath(cwd, "skill", intent.workspaceId, intent.idempotencyKey), "utf8");
38077
+ const raw = await readFile62(ownerReceiptPath(cwd, "skill", intent.workspaceId, intent.idempotencyKey), "utf8");
37818
38078
  return JSON.parse(raw);
37819
38079
  } catch {
37820
38080
  return;
@@ -37872,7 +38132,7 @@ class ProposalLifecycleService {
37872
38132
  now;
37873
38133
  constructor(options) {
37874
38134
  this.options = options;
37875
- this.root = path118.resolve(options.workspaceRoot);
38135
+ this.root = path119.resolve(options.workspaceRoot);
37876
38136
  this.now = options.now ?? (() => new Date);
37877
38137
  }
37878
38138
  async create(input) {
@@ -37891,13 +38151,13 @@ class ProposalLifecycleService {
37891
38151
  if (manifest.status === "archived")
37892
38152
  throw new ProposalLifecycleError("guard_denied", "workspace is archived");
37893
38153
  const file = this.proposalPath(workspaceId, proposal.id);
37894
- await mkdir34(path118.dirname(file), { recursive: true, mode: 448 });
38154
+ await mkdir34(path119.dirname(file), { recursive: true, mode: 448 });
37895
38155
  return withFileLock(`${file}.lock`, async () => {
37896
38156
  const consume = this.options.wrapUpAuthority.consume(input.wrapUp, { actor, workspaceId });
37897
38157
  if (consume !== "ok")
37898
38158
  throw new ProposalLifecycleError("trusted_wrap_up_required", `trusted wrap-up ${consume}`);
37899
38159
  try {
37900
- await readFile62(file, "utf8");
38160
+ await readFile63(file, "utf8");
37901
38161
  throw new ProposalLifecycleError("conflict", "proposal already exists");
37902
38162
  } catch (error) {
37903
38163
  if (error instanceof ProposalLifecycleError)
@@ -37919,7 +38179,7 @@ class ProposalLifecycleService {
37919
38179
  return this.options.workspaces.withAuthorizedActor({ actorContext: actor, workspaceId: input.workspaceId, action: "review", execute: async (manifest) => {
37920
38180
  const proposal = await this.loadProposal(input.workspaceId, input.proposalId);
37921
38181
  const ledger = this.ledgerPath(input.workspaceId);
37922
- await mkdir34(path118.dirname(ledger), { recursive: true, mode: 448 });
38182
+ await mkdir34(path119.dirname(ledger), { recursive: true, mode: 448 });
37923
38183
  return withFileLock(`${ledger}.lock`, async () => {
37924
38184
  const records = (await this.records(ledger)).filter((record) => record.proposalId === proposal.id);
37925
38185
  const events = records.filter((record) => record.recordType === "proposal-transition");
@@ -37961,10 +38221,10 @@ class ProposalLifecycleService {
37961
38221
  } });
37962
38222
  }
37963
38223
  async listProposedProposals(workspaceId) {
37964
- const proposalsDir = path118.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals");
38224
+ const proposalsDir = path119.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals");
37965
38225
  let entries;
37966
38226
  try {
37967
- entries = (await readdir19(proposalsDir)).filter((name) => name.endsWith(".json"));
38227
+ entries = (await readdir20(proposalsDir)).filter((name) => name.endsWith(".json"));
37968
38228
  } catch (error) {
37969
38229
  if (isNotFound(error))
37970
38230
  return [];
@@ -37973,7 +38233,7 @@ class ProposalLifecycleService {
37973
38233
  const proposals = [];
37974
38234
  for (const entry of entries) {
37975
38235
  try {
37976
- const parsed = JSON.parse(await readFile62(path118.join(proposalsDir, entry), "utf8"));
38236
+ const parsed = JSON.parse(await readFile63(path119.join(proposalsDir, entry), "utf8"));
37977
38237
  if (parsed.recordType === "proposal-created")
37978
38238
  proposals.push(parsed);
37979
38239
  } catch {}
@@ -38058,7 +38318,7 @@ class ProposalLifecycleService {
38058
38318
  }
38059
38319
  async loadOwnerWriteAttempt(workspaceId, proposalId, key) {
38060
38320
  try {
38061
- return JSON.parse(await readFile62(this.attemptPath(workspaceId, proposalId, key), "utf8"));
38321
+ return JSON.parse(await readFile63(this.attemptPath(workspaceId, proposalId, key), "utf8"));
38062
38322
  } catch (error) {
38063
38323
  if (isNotFound(error))
38064
38324
  return;
@@ -38073,7 +38333,7 @@ class ProposalLifecycleService {
38073
38333
  async ensureReviewDecision(proposal, actor, reviewerAuthority, input, outcome, targetWrite, policyRevision) {
38074
38334
  const file = this.decisionPath(proposal.workspaceId, proposal.id, input.idempotencyKey);
38075
38335
  try {
38076
- const existing = JSON.parse(await readFile62(file, "utf8"));
38336
+ const existing = JSON.parse(await readFile63(file, "utf8"));
38077
38337
  const existingWrite = existing.targetWrite;
38078
38338
  if (existing.proposalId !== proposal.id || existing.proposalRevision !== proposal.proposalRevision || existing.workspaceId !== proposal.workspaceId || existing.correlationId !== input.requestCorrelationId || existing.idempotencyKey !== input.idempotencyKey || existing.decision !== outcome) {
38079
38339
  throw new ProposalLifecycleError("conflict", "review decision does not match the recovery request");
@@ -38106,7 +38366,7 @@ class ProposalLifecycleService {
38106
38366
  const approvalRef = this.approvalRef(proposal.id, input.idempotencyKey);
38107
38367
  const approvalPath = this.approvalPath(proposal.workspaceId, proposal.id, input.idempotencyKey);
38108
38368
  try {
38109
- const existing = JSON.parse(await readFile62(approvalPath, "utf8"));
38369
+ const existing = JSON.parse(await readFile63(approvalPath, "utf8"));
38110
38370
  if (existing.proposalId !== proposal.id || existing.proposalRevision !== proposal.proposalRevision || existing.workspaceId !== proposal.workspaceId || existing.correlationId !== input.requestCorrelationId || existing.idempotencyKey !== input.idempotencyKey || existing.policyRevision !== policyRevision || JSON.stringify(existing.reviewer) !== JSON.stringify({ subject: actor.subject, authority: reviewerAuthority }))
38111
38371
  throw new ProposalLifecycleError("conflict", "approval does not match the recovery request");
38112
38372
  return { approvalRef };
@@ -38126,7 +38386,7 @@ class ProposalLifecycleService {
38126
38386
  if (existing)
38127
38387
  return { intentRef };
38128
38388
  try {
38129
- const recovered = JSON.parse(await readFile62(this.intentPath(proposal.workspaceId, proposal.id, input.idempotencyKey), "utf8"));
38389
+ const recovered = JSON.parse(await readFile63(this.intentPath(proposal.workspaceId, proposal.id, input.idempotencyKey), "utf8"));
38130
38390
  await this.validateRecord(recovered);
38131
38391
  if (recovered.proposalId !== proposal.id || recovered.proposalRevision !== proposal.proposalRevision || recovered.correlationId !== input.requestCorrelationId || recovered.idempotencyKey !== input.idempotencyKey || recovered.workspaceId !== proposal.workspaceId)
38132
38392
  throw new ProposalLifecycleError("conflict", "write intent does not match the recovery request");
@@ -38219,7 +38479,7 @@ class ProposalLifecycleService {
38219
38479
  }
38220
38480
  async loadProposal(workspaceId, proposalId) {
38221
38481
  try {
38222
- const item = JSON.parse(await readFile62(this.proposalPath(workspaceId, proposalId), "utf8"));
38482
+ const item = JSON.parse(await readFile63(this.proposalPath(workspaceId, proposalId), "utf8"));
38223
38483
  await this.validateProposal(item);
38224
38484
  return item;
38225
38485
  } catch (error) {
@@ -38230,7 +38490,7 @@ class ProposalLifecycleService {
38230
38490
  }
38231
38491
  async records(ledger) {
38232
38492
  try {
38233
- return (await readFile62(ledger, "utf8")).trim().split(`
38493
+ return (await readFile63(ledger, "utf8")).trim().split(`
38234
38494
  `).filter(Boolean).map((line) => JSON.parse(line));
38235
38495
  } catch (error) {
38236
38496
  if (isNotFound(error))
@@ -38239,35 +38499,35 @@ class ProposalLifecycleService {
38239
38499
  }
38240
38500
  }
38241
38501
  proposalPath(workspaceId, proposalId) {
38242
- return path118.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.json`);
38502
+ return path119.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.json`);
38243
38503
  }
38244
38504
  decisionRef(proposalId, key) {
38245
38505
  return `./proposals/${proposalId}.${hash(key)}.decision.json`;
38246
38506
  }
38247
38507
  decisionPath(workspaceId, proposalId, key) {
38248
- return path118.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.${hash(key)}.decision.json`);
38508
+ return path119.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.${hash(key)}.decision.json`);
38249
38509
  }
38250
38510
  approvalRef(proposalId, key) {
38251
38511
  return `./proposals/${proposalId}.${hash(key)}.approval.json`;
38252
38512
  }
38253
38513
  approvalPath(workspaceId, proposalId, key) {
38254
- return path118.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.${hash(key)}.approval.json`);
38514
+ return path119.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.${hash(key)}.approval.json`);
38255
38515
  }
38256
38516
  writeResultPath(workspaceId, proposalId, key) {
38257
- return path118.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.${hash(key)}.write-result.json`);
38517
+ return path119.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.${hash(key)}.write-result.json`);
38258
38518
  }
38259
38519
  intentRef(proposalId, key) {
38260
38520
  return `./proposals/${proposalId}.${hash(key)}.write-intent.json`;
38261
38521
  }
38262
38522
  intentPath(workspaceId, proposalId, key) {
38263
- return path118.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.${hash(key)}.write-intent.json`);
38523
+ return path119.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.${hash(key)}.write-intent.json`);
38264
38524
  }
38265
38525
  attemptPath(workspaceId, proposalId, key) {
38266
- return path118.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.${hash(key)}.owner-write-attempt.json`);
38526
+ return path119.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.${hash(key)}.owner-write-attempt.json`);
38267
38527
  }
38268
38528
  async loadWriteResult(workspaceId, proposalId, key) {
38269
38529
  try {
38270
- return JSON.parse(await readFile62(this.writeResultPath(workspaceId, proposalId, key), "utf8"));
38530
+ return JSON.parse(await readFile63(this.writeResultPath(workspaceId, proposalId, key), "utf8"));
38271
38531
  } catch (error) {
38272
38532
  if (isNotFound(error))
38273
38533
  return;
@@ -38276,7 +38536,7 @@ class ProposalLifecycleService {
38276
38536
  }
38277
38537
  async writeImmutable(file, record) {
38278
38538
  try {
38279
- const existing = await readFile62(file, "utf8");
38539
+ const existing = await readFile63(file, "utf8");
38280
38540
  if (existing !== `${JSON.stringify(record)}
38281
38541
  `)
38282
38542
  throw new ProposalLifecycleError("conflict", "immutable lifecycle record already exists");
@@ -38290,7 +38550,7 @@ class ProposalLifecycleService {
38290
38550
  }
38291
38551
  }
38292
38552
  ledgerPath(workspaceId) {
38293
- return path118.join(this.root, ".metaproject", "workspaces", workspaceId, "activity.jsonl");
38553
+ return path119.join(this.root, ".metaproject", "workspaces", workspaceId, "activity.jsonl");
38294
38554
  }
38295
38555
  timestamp() {
38296
38556
  return this.now().toISOString();
@@ -38371,9 +38631,9 @@ function normalizeProposalLifecycleResult(value) {
38371
38631
  return JSON.parse(JSON.stringify(value));
38372
38632
  }
38373
38633
  // src/sac/collaboration-service.ts
38374
- import { appendFile as appendFile8, mkdir as mkdir35, readFile as readFile63 } from "fs/promises";
38634
+ import { appendFile as appendFile8, mkdir as mkdir35, readFile as readFile64 } from "fs/promises";
38375
38635
  import { randomUUID as randomUUID8 } from "crypto";
38376
- import path119 from "path";
38636
+ import path120 from "path";
38377
38637
  class CollaborationServiceError extends Error {
38378
38638
  code;
38379
38639
  constructor(code, message) {
@@ -38388,7 +38648,7 @@ class CollaborationService {
38388
38648
  this.input = input;
38389
38649
  }
38390
38650
  file(id) {
38391
- return path119.join(this.input.workspaceRoot, ".metaproject", "workspaces", id, "activity.jsonl");
38651
+ return path120.join(this.input.workspaceRoot, ".metaproject", "workspaces", id, "activity.jsonl");
38392
38652
  }
38393
38653
  async overview(input) {
38394
38654
  const manifest = await this.input.workspaces.show(input);
@@ -38397,7 +38657,7 @@ class CollaborationService {
38397
38657
  async activity(input) {
38398
38658
  await this.input.workspaces.show(input);
38399
38659
  try {
38400
- return (await readFile63(this.file(input.workspaceId), "utf8")).trim().split(`
38660
+ return (await readFile64(this.file(input.workspaceId), "utf8")).trim().split(`
38401
38661
  `).filter(Boolean).map((line) => this.validate(JSON.parse(line)));
38402
38662
  } catch (error) {
38403
38663
  if (typeof error === "object" && error && "code" in error && error.code === "ENOENT")
@@ -38425,7 +38685,7 @@ class CollaborationService {
38425
38685
  occurredAt: (this.input.now ?? (() => new Date))().toISOString(),
38426
38686
  ...suppliedHandoff ? { handoff: { ...suppliedHandoff, from: actor.subject } } : {}
38427
38687
  });
38428
- await mkdir35(path119.dirname(this.file(manifest.id)), { recursive: true, mode: 448 });
38688
+ await mkdir35(path120.dirname(this.file(manifest.id)), { recursive: true, mode: 448 });
38429
38689
  await appendFile8(this.file(manifest.id), `${JSON.stringify(activity)}
38430
38690
  `, { mode: 384 });
38431
38691
  return normalizeCollaborationResult(activity);
@@ -38474,14 +38734,14 @@ function normalizeCollaborationResult(value) {
38474
38734
  }
38475
38735
  // src/session/external-slate.ts
38476
38736
  init_fs();
38477
- import { mkdir as mkdir37, readdir as readdir20, readFile as readFile64 } from "fs/promises";
38478
- import path121 from "path";
38737
+ import { mkdir as mkdir37, readdir as readdir21, readFile as readFile65 } from "fs/promises";
38738
+ import path122 from "path";
38479
38739
 
38480
38740
  // src/sac/machine-wrap-up.ts
38481
38741
  init_fs();
38482
38742
  import { createHash as createHash30, randomUUID as randomUUID10 } from "crypto";
38483
38743
  import { mkdir as mkdir36 } from "fs/promises";
38484
- import path120 from "path";
38744
+ import path121 from "path";
38485
38745
 
38486
38746
  // src/sac/workspace-resolve.ts
38487
38747
  init_redact();
@@ -38622,11 +38882,11 @@ async function resolveMachineWrapUp(input) {
38622
38882
  `;
38623
38883
  const seedsJson = `${JSON.stringify(seedsForKind.map((seed) => ({ text: seed.text, source: describeSource(seed.source) })), null, 2)}
38624
38884
  `;
38625
- const evidenceRelBase = path120.posix.join(".metaproject", "workspaces", input.workspaceId, "machine-evidence");
38885
+ const evidenceRelBase = path121.posix.join(".metaproject", "workspaces", input.workspaceId, "machine-evidence");
38626
38886
  const floor = await applyEvidenceRedactionFloor(input.cwd, [
38627
- { name: `${input.kind}.diff.txt`, content: diffBody, path: path120.posix.join(evidenceRelBase, `${input.kind}.diff.txt`), source: "tool-output" },
38628
- { name: `${input.kind}.flow.json`, content: flowSnapshotJson, path: path120.posix.join(evidenceRelBase, `${input.kind}.flow.json`), source: "generated" },
38629
- { name: `${input.kind}.seeds.json`, content: seedsJson, path: path120.posix.join(evidenceRelBase, `${input.kind}.seeds.json`), source: "generated" }
38887
+ { name: `${input.kind}.diff.txt`, content: diffBody, path: path121.posix.join(evidenceRelBase, `${input.kind}.diff.txt`), source: "tool-output" },
38888
+ { name: `${input.kind}.flow.json`, content: flowSnapshotJson, path: path121.posix.join(evidenceRelBase, `${input.kind}.flow.json`), source: "generated" },
38889
+ { name: `${input.kind}.seeds.json`, content: seedsJson, path: path121.posix.join(evidenceRelBase, `${input.kind}.seeds.json`), source: "generated" }
38630
38890
  ]);
38631
38891
  if (!floor.ok)
38632
38892
  return { ok: false, code: "security_denied", detail: floor.reason };
@@ -38680,14 +38940,14 @@ ${safeSeeds.content}`;
38680
38940
  }
38681
38941
  summary = result.text.trim().length > 0 ? result.text.trim() : mechanicalSummary(summaryDiff, course);
38682
38942
  }
38683
- const evidenceDir = path120.join(input.cwd, ".metaproject", "workspaces", input.workspaceId, "machine-evidence");
38943
+ const evidenceDir = path121.join(input.cwd, ".metaproject", "workspaces", input.workspaceId, "machine-evidence");
38684
38944
  await mkdir36(evidenceDir, { recursive: true });
38685
38945
  const diffFile = `${input.kind}.${shortHash}.diff.txt`;
38686
38946
  const flowFile = `${input.kind}.${shortHash}.flow.json`;
38687
38947
  const seedsFile = `${input.kind}.${shortHash}.seeds.json`;
38688
- await writeFileAtomic(path120.join(evidenceDir, diffFile), safeDiff.content);
38689
- await writeFileAtomic(path120.join(evidenceDir, flowFile), safeFlow.content);
38690
- await writeFileAtomic(path120.join(evidenceDir, seedsFile), safeSeeds.content);
38948
+ await writeFileAtomic(path121.join(evidenceDir, diffFile), safeDiff.content);
38949
+ await writeFileAtomic(path121.join(evidenceDir, flowFile), safeFlow.content);
38950
+ await writeFileAtomic(path121.join(evidenceDir, seedsFile), safeSeeds.content);
38691
38951
  const observedAt = now().toISOString();
38692
38952
  const relBase = `./.metaproject/workspaces/${input.workspaceId}/machine-evidence`;
38693
38953
  const evidence = [
@@ -38697,7 +38957,7 @@ ${safeSeeds.content}`;
38697
38957
  ];
38698
38958
  if (floor.notice !== undefined) {
38699
38959
  const noticeFile = `${input.kind}.${shortHash}.redaction.md`;
38700
- await writeFileAtomic(path120.join(evidenceDir, noticeFile), floor.notice);
38960
+ await writeFileAtomic(path121.join(evidenceDir, noticeFile), floor.notice);
38701
38961
  evidence.push({ kind: REDACTION_NOTICE_KIND, uri: `${relBase}/${noticeFile}`, revision: sha2566(floor.notice), observedAt });
38702
38962
  }
38703
38963
  return {
@@ -38716,18 +38976,18 @@ async function writeFlooredArchiveArtifact(params) {
38716
38976
  {
38717
38977
  name: params.filename,
38718
38978
  content: params.content,
38719
- path: path120.posix.join("slate-archive", params.filename),
38979
+ path: path121.posix.join("slate-archive", params.filename),
38720
38980
  source: "generated"
38721
38981
  }
38722
38982
  ]);
38723
38983
  if (!floor.ok)
38724
38984
  return { ok: false, code: "security_denied", detail: floor.reason };
38725
38985
  const body = floor.bodies[0];
38726
- const archiveDir = path120.join(params.dir, "slate-archive");
38986
+ const archiveDir = path121.join(params.dir, "slate-archive");
38727
38987
  await mkdir36(archiveDir, { recursive: true });
38728
- await writeFileAtomic(path120.join(archiveDir, params.filename), body.content);
38988
+ await writeFileAtomic(path121.join(archiveDir, params.filename), body.content);
38729
38989
  if (floor.notice !== undefined) {
38730
- await writeFileAtomic(path120.join(archiveDir, `${params.filename}${ARCHIVE_REDACTION_NOTICE_SUFFIX}`), floor.notice);
38990
+ await writeFileAtomic(path121.join(archiveDir, `${params.filename}${ARCHIVE_REDACTION_NOTICE_SUFFIX}`), floor.notice);
38731
38991
  }
38732
38992
  return { ok: true, altered: body.altered };
38733
38993
  }
@@ -38763,9 +39023,9 @@ async function writeWrapUpOutcomeArtifact(cwd, dir, trigger, now, groups) {
38763
39023
  return;
38764
39024
  const refusalIso = now().toISOString();
38765
39025
  const refusalFilename = `${refusalIso.replace(/[:.]/g, "-")}-wrap-up-outcome.json`;
38766
- const archiveDir = path120.join(dir, "slate-archive");
39026
+ const archiveDir = path121.join(dir, "slate-archive");
38767
39027
  await mkdir36(archiveDir, { recursive: true });
38768
- await writeFileAtomic(path120.join(archiveDir, refusalFilename), `${JSON.stringify({
39028
+ await writeFileAtomic(path121.join(archiveDir, refusalFilename), `${JSON.stringify({
38769
39029
  recordType: "wrap-up-outcome",
38770
39030
  trigger,
38771
39031
  generatedAt: refusalIso,
@@ -38901,7 +39161,7 @@ async function runWrapUp(input) {
38901
39161
 
38902
39162
  // src/session/external-slate.ts
38903
39163
  function externalSlatesDir(cwd) {
38904
- return path121.join(cwd, ".keryx", "external-slates");
39164
+ return path122.join(cwd, ".keryx", "external-slates");
38905
39165
  }
38906
39166
  var EXTERNAL_SESSION_ID_PATTERN = /^[A-Za-z0-9_-]{1,128}$/;
38907
39167
  function assertValidExternalSessionId(externalSessionId) {
@@ -38911,18 +39171,18 @@ function assertValidExternalSessionId(externalSessionId) {
38911
39171
  }
38912
39172
  function externalSlatePath(cwd, externalSessionId) {
38913
39173
  assertValidExternalSessionId(externalSessionId);
38914
- return path121.join(externalSlatesDir(cwd), `${externalSessionId}.json`);
39174
+ return path122.join(externalSlatesDir(cwd), `${externalSessionId}.json`);
38915
39175
  }
38916
39176
  function externalSlateLockPath(cwd, externalSessionId) {
38917
39177
  return `${externalSlatePath(cwd, externalSessionId)}.lock`;
38918
39178
  }
38919
39179
  function externalSlateEvidenceDir(cwd, externalSessionId) {
38920
39180
  assertValidExternalSessionId(externalSessionId);
38921
- return path121.join(externalSlatesDir(cwd), externalSessionId);
39181
+ return path122.join(externalSlatesDir(cwd), externalSessionId);
38922
39182
  }
38923
39183
  async function readExternalSlate(cwd, externalSessionId) {
38924
39184
  try {
38925
- const raw = await readFile64(externalSlatePath(cwd, externalSessionId), "utf8");
39185
+ const raw = await readFile65(externalSlatePath(cwd, externalSessionId), "utf8");
38926
39186
  return JSON.parse(raw);
38927
39187
  } catch (error) {
38928
39188
  if (isNotFound(error))
@@ -38942,7 +39202,7 @@ async function writeExternalSlate(cwd, externalSessionId, update) {
38942
39202
  }
38943
39203
  async function listExternalSlateIds(cwd) {
38944
39204
  try {
38945
- const entries = await readdir20(externalSlatesDir(cwd));
39205
+ const entries = await readdir21(externalSlatesDir(cwd));
38946
39206
  return entries.filter((name) => name.endsWith(".json")).map((name) => name.slice(0, -".json".length));
38947
39207
  } catch (error) {
38948
39208
  if (isNotFound(error))
@@ -39024,13 +39284,13 @@ __export(exports_service10, {
39024
39284
  runDoctor: () => runDoctor,
39025
39285
  runValidate: () => runValidate
39026
39286
  });
39027
- import path124 from "path";
39028
- import { readFile as readFile67 } from "fs/promises";
39287
+ import path125 from "path";
39288
+ import { readFile as readFile68 } from "fs/promises";
39029
39289
 
39030
39290
  // src/standard/validate.ts
39031
39291
  init_fs();
39032
- import path123 from "path";
39033
- import { readFile as readFile66 } from "fs/promises";
39292
+ import path124 from "path";
39293
+ import { readFile as readFile67 } from "fs/promises";
39034
39294
 
39035
39295
  // src/standard/schemas.ts
39036
39296
  var MODULE_SCHEMA = {
@@ -39159,8 +39419,8 @@ var SCHEMA_REGISTRY2 = {
39159
39419
  // src/standard/profiles.ts
39160
39420
  init_fs();
39161
39421
  init_entrypoint_targets();
39162
- import path122 from "path";
39163
- import { readFile as readFile65 } from "fs/promises";
39422
+ import path123 from "path";
39423
+ import { readFile as readFile66 } from "fs/promises";
39164
39424
  var AGENT_MODULES = ["gdgraph", "gdctx", "gdskills", "gdwiki", "memory"];
39165
39425
  var CI_MODULES = ["health", "testing"];
39166
39426
  var INDEX_LINK = ".metaproject/index.md";
@@ -39184,11 +39444,11 @@ function enabledModuleKeys(manifest) {
39184
39444
  }
39185
39445
  async function rootEntrypointLinksIndex(cwd, manifest) {
39186
39446
  for (const { path: name } of namedEntrypoints(manifest)) {
39187
- const filePath = path122.join(cwd, name);
39447
+ const filePath = path123.join(cwd, name);
39188
39448
  if (!await pathExists(filePath)) {
39189
39449
  continue;
39190
39450
  }
39191
- const content = await readFile65(filePath, "utf8");
39451
+ const content = await readFile66(filePath, "utf8");
39192
39452
  if (content.includes(INDEX_LINK)) {
39193
39453
  return true;
39194
39454
  }
@@ -39196,16 +39456,16 @@ async function rootEntrypointLinksIndex(cwd, manifest) {
39196
39456
  return false;
39197
39457
  }
39198
39458
  async function minimalSatisfied(cwd) {
39199
- const metaprojectRoot = path122.join(cwd, ".metaproject");
39459
+ const metaprojectRoot = path123.join(cwd, ".metaproject");
39200
39460
  const requiredFiles = ["index.md", "README.md", "metaproject.json"];
39201
39461
  const requiredDirs = ["modules", "rules", "skills", "data"];
39202
39462
  for (const file of requiredFiles) {
39203
- if (!await pathExists(path122.join(metaprojectRoot, file))) {
39463
+ if (!await pathExists(path123.join(metaprojectRoot, file))) {
39204
39464
  return false;
39205
39465
  }
39206
39466
  }
39207
39467
  for (const dir of requiredDirs) {
39208
- if (!await pathExists(path122.join(metaprojectRoot, dir))) {
39468
+ if (!await pathExists(path123.join(metaprojectRoot, dir))) {
39209
39469
  return false;
39210
39470
  }
39211
39471
  }
@@ -39218,7 +39478,7 @@ async function ciSatisfied(cwd, manifest) {
39218
39478
  return false;
39219
39479
  }
39220
39480
  for (const key of ciModules) {
39221
- if (await pathExists(path122.join(cwd, ".metaproject", "data", key, "artifacts"))) {
39481
+ if (await pathExists(path123.join(cwd, ".metaproject", "data", key, "artifacts"))) {
39222
39482
  return true;
39223
39483
  }
39224
39484
  }
@@ -39231,7 +39491,7 @@ async function evaluateProfiles(cwd, manifest) {
39231
39491
  satisfied.push("minimal");
39232
39492
  }
39233
39493
  const hasAgentModule = AGENT_MODULES.some((key) => new Set(enabledModuleKeys(manifest)).has(key));
39234
- const agent = minimal && hasAgentModule && await rootEntrypointLinksIndex(cwd, manifest) && await pathExists(path122.join(cwd, ".metaproject", "rules"));
39494
+ const agent = minimal && hasAgentModule && await rootEntrypointLinksIndex(cwd, manifest) && await pathExists(path123.join(cwd, ".metaproject", "rules"));
39235
39495
  if (agent) {
39236
39496
  satisfied.push("agent");
39237
39497
  }
@@ -39400,26 +39660,26 @@ var MANIFEST_TOP_LEVEL_SCHEMA = {
39400
39660
  async function validateWorkspace2(cwd) {
39401
39661
  const errors = [];
39402
39662
  const warnings = [];
39403
- const metaprojectRoot = path123.join(cwd, ".metaproject");
39663
+ const metaprojectRoot = path124.join(cwd, ".metaproject");
39404
39664
  const requiredFiles = ["index.md", "README.md", "metaproject.json"];
39405
39665
  for (const file of requiredFiles) {
39406
- if (!await pathExists(path123.join(metaprojectRoot, file))) {
39666
+ if (!await pathExists(path124.join(metaprojectRoot, file))) {
39407
39667
  errors.push(issue("missing-required-file", `Required file .metaproject/${file} is missing`, `Run \`keryx init\` to scaffold .metaproject/${file}.`));
39408
39668
  }
39409
39669
  }
39410
39670
  const requiredDirs = ["modules", "rules", "skills", "data"];
39411
39671
  for (const dir of requiredDirs) {
39412
- if (!await pathExists(path123.join(metaprojectRoot, dir))) {
39672
+ if (!await pathExists(path124.join(metaprojectRoot, dir))) {
39413
39673
  errors.push(issue("missing-required-dir", `Required directory .metaproject/${dir}/ is missing`, `Run \`keryx init\` to create .metaproject/${dir}/.`));
39414
39674
  }
39415
39675
  }
39416
- const manifestPath = path123.join(metaprojectRoot, "metaproject.json");
39676
+ const manifestPath = path124.join(metaprojectRoot, "metaproject.json");
39417
39677
  if (!await pathExists(manifestPath)) {
39418
39678
  return { ok: errors.length === 0, errors, warnings };
39419
39679
  }
39420
39680
  let manifest;
39421
39681
  try {
39422
- manifest = JSON.parse(await readFile66(manifestPath, "utf8"));
39682
+ manifest = JSON.parse(await readFile67(manifestPath, "utf8"));
39423
39683
  } catch (error) {
39424
39684
  const detail = error instanceof Error ? error.message : String(error);
39425
39685
  errors.push(issue("invalid-manifest-json", `.metaproject/metaproject.json is not valid JSON: ${detail}`, "Fix the JSON syntax or regenerate it with `keryx init`."));
@@ -39445,7 +39705,7 @@ async function validateWorkspace2(cwd) {
39445
39705
  if (typeof value !== "string") {
39446
39706
  continue;
39447
39707
  }
39448
- if (!await pathExists(path123.join(cwd, value))) {
39708
+ if (!await pathExists(path124.join(cwd, value))) {
39449
39709
  errors.push(issue("missing-declared-path", `Declared path paths.${key} -> ${value} does not exist`, `Create ${value} or remove paths.${key} from metaproject.json.`));
39450
39710
  }
39451
39711
  }
@@ -39455,7 +39715,7 @@ async function validateWorkspace2(cwd) {
39455
39715
  continue;
39456
39716
  }
39457
39717
  if (typeof entry.manifest === "string") {
39458
- if (!await pathExists(path123.join(cwd, entry.manifest))) {
39718
+ if (!await pathExists(path124.join(cwd, entry.manifest))) {
39459
39719
  errors.push(issue("missing-module-manifest", `Enabled module "${key}" manifest ${entry.manifest} is missing`, `Create ${entry.manifest} or run \`keryx update\` to regenerate module manifests.`));
39460
39720
  }
39461
39721
  }
@@ -39464,18 +39724,18 @@ async function validateWorkspace2(cwd) {
39464
39724
  if (typeof value !== "string") {
39465
39725
  continue;
39466
39726
  }
39467
- if (!await pathExists(path123.join(cwd, value))) {
39727
+ if (!await pathExists(path124.join(cwd, value))) {
39468
39728
  const sink = field === "data" ? warnings : errors;
39469
39729
  sink.push(issue("missing-module-path", `Module "${key}" declares ${String(field)} ${value}, which does not exist`, field === "data" ? `Run the module (e.g. \`keryx ${key} ...\`) to generate ${value}, or update modules.${key}.data in metaproject.json.` : `Create ${value} or update modules.${key}.${String(field)} in metaproject.json.`));
39470
39730
  }
39471
39731
  }
39472
39732
  }
39473
39733
  for (const { path: name, scope } of namedEntrypoints(manifest)) {
39474
- const filePath = path123.join(cwd, name);
39734
+ const filePath = path124.join(cwd, name);
39475
39735
  if (!await pathExists(filePath)) {
39476
39736
  continue;
39477
39737
  }
39478
- const content = await readFile66(filePath, "utf8");
39738
+ const content = await readFile67(filePath, "utf8");
39479
39739
  if (!content.includes(INDEX_LINK2)) {
39480
39740
  errors.push(issue("entrypoint-missing-index-link", `Root entrypoint ${name} does not link ${INDEX_LINK2}`, scope === "local" ? `Run \`keryx update\` to put the managed block back into ${name}.` : `Add a reference to ${INDEX_LINK2} in ${name} (\`keryx rules sync\` does this).`));
39481
39741
  }
@@ -40381,12 +40641,12 @@ async function runDoctor(cwd) {
40381
40641
  return validateWorkspace2(cwd);
40382
40642
  }
40383
40643
  async function readManifest(cwd) {
40384
- const manifestPath = path124.join(cwd, ".metaproject", "metaproject.json");
40644
+ const manifestPath = path125.join(cwd, ".metaproject", "metaproject.json");
40385
40645
  if (!await pathExists(manifestPath)) {
40386
40646
  throw new Error("Metaproject is not initialized (missing .metaproject/metaproject.json). Run `keryx init` first.");
40387
40647
  }
40388
40648
  try {
40389
- return JSON.parse(await readFile67(manifestPath, "utf8"));
40649
+ return JSON.parse(await readFile68(manifestPath, "utf8"));
40390
40650
  } catch (error) {
40391
40651
  const detail = error instanceof Error ? error.message : String(error);
40392
40652
  throw new Error(`Invalid .metaproject/metaproject.json: ${detail}`);