@mrciphersmith/keryx 0.2.123 → 0.2.125

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/README.md +2 -2
  2. package/dist/cli.js +1938 -665
  3. package/dist/core.js +579 -546
  4. package/package.json +3 -3
package/dist/core.js CHANGED
@@ -27,7 +27,7 @@ var __esm = (fn, res, err) => () => {
27
27
 
28
28
  // src/lib/fs.ts
29
29
  import { randomUUID } from "crypto";
30
- import { access, mkdir, readFile, rename, rm, stat, utimes, writeFile } from "fs/promises";
30
+ import { access, chmod, mkdir, readFile, rename, rm, stat, utimes, writeFile } from "fs/promises";
31
31
  import path from "path";
32
32
  async function pathExists(filePath) {
33
33
  try {
@@ -47,12 +47,18 @@ function isPathInside(root, candidate) {
47
47
  const relative = path.relative(path.resolve(root), path.resolve(candidate));
48
48
  return relative === "" || relative.length > 0 && !relative.startsWith("..") && !path.isAbsolute(relative);
49
49
  }
50
- async function writeFileAtomic(filePath, content) {
50
+ async function writeFileAtomic(filePath, content, options = {}) {
51
51
  const dir = path.dirname(filePath);
52
52
  await mkdir(dir, { recursive: true });
53
53
  const tmp = path.join(dir, `.${path.basename(filePath)}.${process.pid}.${Date.now()}.${randomUUID()}.tmp`);
54
54
  try {
55
- await writeFile(tmp, content, "utf8");
55
+ if (options.mode === undefined) {
56
+ await writeFile(tmp, content, "utf8");
57
+ } else {
58
+ await writeFile(tmp, content, { encoding: "utf8", mode: options.mode });
59
+ if (process.platform !== "win32")
60
+ await chmod(tmp, options.mode);
61
+ }
56
62
  await rename(tmp, filePath);
57
63
  } catch (error) {
58
64
  await rm(tmp, { force: true }).catch(() => {});
@@ -71,10 +77,14 @@ async function withFileLock(lockPath, fn, options = {}) {
71
77
  while (true) {
72
78
  try {
73
79
  await mkdir(lockPath);
80
+ const createdIno = (await stat(lockPath)).ino;
81
+ await options.raceHook?.("created");
74
82
  try {
75
83
  await writeFile(ownerPath, JSON.stringify(owner), { encoding: "utf8", flag: "wx", mode: 384 });
76
84
  } catch (error) {
77
- await rm(lockPath, { recursive: true, force: true }).catch(() => {});
85
+ if (await isSameEmptyOrOwnerlessDir(lockPath, createdIno)) {
86
+ await rm(lockPath, { recursive: true, force: true }).catch(() => {});
87
+ }
78
88
  throw error;
79
89
  }
80
90
  break;
@@ -82,7 +92,7 @@ async function withFileLock(lockPath, fn, options = {}) {
82
92
  if (!isAlreadyExistsError(error)) {
83
93
  throw error;
84
94
  }
85
- await removeStaleLock(lockPath, staleMs);
95
+ await removeStaleLock(lockPath, staleMs, options.raceHook);
86
96
  if (Date.now() - startedAt >= timeoutMs) {
87
97
  throw new Error(`Timed out waiting for lock: ${lockPath}`);
88
98
  }
@@ -106,7 +116,16 @@ async function withFileLock(lockPath, fn, options = {}) {
106
116
  function isAlreadyExistsError(error) {
107
117
  return typeof error === "object" && error !== null && "code" in error && error.code === "EEXIST";
108
118
  }
109
- async function removeStaleLock(lockPath, staleMs) {
119
+ async function isSameEmptyOrOwnerlessDir(dir, ino) {
120
+ try {
121
+ if ((await stat(dir)).ino !== ino)
122
+ return false;
123
+ return await readLockOwner(path.join(dir, "owner.json")) === undefined;
124
+ } catch {
125
+ return false;
126
+ }
127
+ }
128
+ async function removeStaleLock(lockPath, staleMs, raceHook) {
110
129
  try {
111
130
  const stats = await stat(lockPath);
112
131
  if (Date.now() - stats.mtimeMs <= staleMs)
@@ -114,8 +133,17 @@ async function removeStaleLock(lockPath, staleMs) {
114
133
  const owner = await readLockOwner(path.join(lockPath, "owner.json"));
115
134
  if (owner && processIsAlive(owner.pid))
116
135
  return;
136
+ await raceHook?.("stale-judged");
117
137
  const stalePath = `${lockPath}.stale.${process.pid}.${randomUUID()}`;
118
138
  await rename(lockPath, stalePath);
139
+ await raceHook?.("moved-aside");
140
+ const movedIno = (await stat(stalePath)).ino;
141
+ const moved = await readLockOwner(path.join(stalePath, "owner.json"));
142
+ if (movedIno !== stats.ino || moved?.token !== owner?.token) {
143
+ await rename(stalePath, lockPath).catch(() => {});
144
+ await raceHook?.("restored");
145
+ return;
146
+ }
119
147
  await rm(stalePath, { recursive: true, force: true });
120
148
  } catch {}
121
149
  }
@@ -718,9 +746,9 @@ var init_lifecycle = __esm(() => {
718
746
  });
719
747
 
720
748
  // src/assets/lock.ts
721
- import path15 from "path";
749
+ import path16 from "path";
722
750
  function lockPath(cwd) {
723
- return path15.join(cwd, ".metaproject", "assets.lock.json");
751
+ return path16.join(cwd, ".metaproject", "assets.lock.json");
724
752
  }
725
753
  function normalizeLock(parsed) {
726
754
  const assets = {};
@@ -775,16 +803,16 @@ var init_lock = __esm(() => {
775
803
  import { createHash as createHash2 } from "crypto";
776
804
  import { readFile as readFile11 } from "fs/promises";
777
805
  import os from "os";
778
- import path16 from "path";
806
+ import path17 from "path";
779
807
  function assetCacheDir() {
780
808
  const override = process.env.KERYX_ASSET_CACHE;
781
809
  if (override && override.length > 0) {
782
810
  return override;
783
811
  }
784
- return path16.join(os.homedir(), ".cache", "keryx", "assets");
812
+ return path17.join(os.homedir(), ".cache", "keryx", "assets");
785
813
  }
786
814
  function cacheAssetPath(id) {
787
- return path16.join(assetCacheDir(), id);
815
+ return path17.join(assetCacheDir(), id);
788
816
  }
789
817
  async function sha256File(file) {
790
818
  const buffer = await readFile11(file);
@@ -836,9 +864,9 @@ var init_warn_once = __esm(() => {
836
864
  });
837
865
 
838
866
  // src/capability/seam.ts
839
- import path17 from "path";
867
+ import path18 from "path";
840
868
  async function isCapabilityEnabled(cwd, id) {
841
- const manifestPath = path17.join(cwd, ".metaproject", "metaproject.json");
869
+ const manifestPath = path18.join(cwd, ".metaproject", "metaproject.json");
842
870
  if (!await pathExists(manifestPath)) {
843
871
  return false;
844
872
  }
@@ -919,9 +947,9 @@ var init_seam = __esm(() => {
919
947
  });
920
948
 
921
949
  // src/gdgraph/config.ts
922
- import path18 from "path";
950
+ import path19 from "path";
923
951
  function gdgraphConfigPath(cwd) {
924
- return path18.join(cwd, ".metaproject", "gdgraph.config.json");
952
+ return path19.join(cwd, ".metaproject", "gdgraph.config.json");
925
953
  }
926
954
  function mergeGdgraphConfig(parsed) {
927
955
  const base = DEFAULT_GDGRAPH_CONFIG;
@@ -1526,7 +1554,7 @@ var init_extract = __esm(() => {
1526
1554
  });
1527
1555
 
1528
1556
  // src/gdgraph/treesitter/grammars.ts
1529
- import path19 from "path";
1557
+ import path20 from "path";
1530
1558
  function grammarAssetId(language) {
1531
1559
  return `tree-sitter-${language}`;
1532
1560
  }
@@ -1542,7 +1570,7 @@ function symbolLanguage(language) {
1542
1570
  async function resolveGrammar(cwd, language, grammarsPath) {
1543
1571
  const id = grammarAssetId(language);
1544
1572
  const lock = await loadAssetsLock(cwd);
1545
- const overrides = grammarsPath ? { [id]: { path: path19.join(grammarsPath, `${id}.wasm`) } } : undefined;
1573
+ const overrides = grammarsPath ? { [id]: { path: path20.join(grammarsPath, `${id}.wasm`) } } : undefined;
1546
1574
  const registry = registryFromLock(lock, overrides);
1547
1575
  const resolved = await resolveAsset(registry, id);
1548
1576
  if (!resolved) {
@@ -1572,7 +1600,7 @@ function toGrammarLanguages(languages) {
1572
1600
  return out;
1573
1601
  }
1574
1602
  function grammarForFile(file, available) {
1575
- const ext = path19.extname(file);
1603
+ const ext = path20.extname(file);
1576
1604
  const preference = ext === ".tsx" ? ["tsx", "typescript"] : ext === ".ts" ? ["typescript"] : ext === ".jsx" || ext === ".js" || ext === ".mjs" || ext === ".cjs" ? ["javascript"] : ext === ".java" ? ["java"] : ext === ".py" ? ["python"] : [];
1577
1605
  for (const language of preference) {
1578
1606
  if (available.includes(language)) {
@@ -1834,7 +1862,7 @@ var init_adapter = __esm(() => {
1834
1862
 
1835
1863
  // src/gdgraph/enrich.ts
1836
1864
  import { mkdir as mkdir6, writeFile as writeFile3 } from "fs/promises";
1837
- import path20 from "path";
1865
+ import path21 from "path";
1838
1866
  async function enrichBuildWithSymbols(cwd, files, resolve) {
1839
1867
  const config = await loadGdgraphConfig(cwd);
1840
1868
  const treesitterConfig = {
@@ -1850,12 +1878,12 @@ async function enrichBuildWithSymbols(cwd, files, resolve) {
1850
1878
  return { enriched: true, symbols: layer.symbols.length, calls: layer.calls.length };
1851
1879
  }
1852
1880
  async function writeSymbolLayer(cwd, layer) {
1853
- const storageDir = path20.join(cwd, ".metaproject", "data", "gdgraph", "storage");
1881
+ const storageDir = path21.join(cwd, ".metaproject", "data", "gdgraph", "storage");
1854
1882
  await mkdir6(storageDir, { recursive: true });
1855
- await writeFile3(path20.join(storageDir, "symbols.jsonl"), layer.symbols.map((symbol) => JSON.stringify(symbol)).join(`
1883
+ await writeFile3(path21.join(storageDir, "symbols.jsonl"), layer.symbols.map((symbol) => JSON.stringify(symbol)).join(`
1856
1884
  `) + `
1857
1885
  `, "utf8");
1858
- await writeFile3(path20.join(storageDir, "calls.jsonl"), layer.calls.map((call) => JSON.stringify(call)).join(`
1886
+ await writeFile3(path21.join(storageDir, "calls.jsonl"), layer.calls.map((call) => JSON.stringify(call)).join(`
1859
1887
  `) + `
1860
1888
  `, "utf8");
1861
1889
  }
@@ -2045,10 +2073,10 @@ var init_describes = __esm(() => {
2045
2073
 
2046
2074
  // src/sync/provenance.ts
2047
2075
  import { mkdir as mkdir7, readFile as readFile12, writeFile as writeFile4 } from "fs/promises";
2048
- import path21 from "path";
2076
+ import path22 from "path";
2049
2077
  import { spawn } from "child_process";
2050
2078
  function provenancePath(cwd, module) {
2051
- return path21.join(cwd, ".metaproject", "data", module, ".provenance.json");
2079
+ return path22.join(cwd, ".metaproject", "data", module, ".provenance.json");
2052
2080
  }
2053
2081
  function gitCmdResult(cwd, args) {
2054
2082
  return new Promise((resolve) => {
@@ -2093,7 +2121,7 @@ async function recordProvenance(cwd, module, at) {
2093
2121
  if (!head)
2094
2122
  return;
2095
2123
  const file = provenancePath(cwd, module);
2096
- await mkdir7(path21.dirname(file), { recursive: true });
2124
+ await mkdir7(path22.dirname(file), { recursive: true });
2097
2125
  const provenance = { commit: head.commit, branch: head.branch, builtAt: at };
2098
2126
  await writeFile4(file, `${JSON.stringify(provenance, null, 2)}
2099
2127
  `, "utf8");
@@ -2117,12 +2145,12 @@ var init_provenance = __esm(() => {
2117
2145
 
2118
2146
  // src/gdgraph/staleness.ts
2119
2147
  import { stat as stat3 } from "fs/promises";
2120
- import path22 from "path";
2148
+ import path23 from "path";
2121
2149
  function nodesJsonlPath(cwd) {
2122
- return path22.join(cwd, ".metaproject", "data", "gdgraph", "storage", "nodes.jsonl");
2150
+ return path23.join(cwd, ".metaproject", "data", "gdgraph", "storage", "nodes.jsonl");
2123
2151
  }
2124
2152
  function gdgraphConfigPath2(cwd) {
2125
- return path22.join(cwd, ".metaproject", "gdgraph.config.json");
2153
+ return path23.join(cwd, ".metaproject", "gdgraph.config.json");
2126
2154
  }
2127
2155
  function categorizeStatusLines(porcelain, rootPrefix) {
2128
2156
  const lines = porcelain.split(`
@@ -2169,7 +2197,7 @@ async function checkGraphStaleness(cwd) {
2169
2197
  reasons.push(`HEAD moved since the graph was built (built at ${provenance.commit.slice(0, 12)}, now ${head.commit.slice(0, 12)})`);
2170
2198
  }
2171
2199
  } else {
2172
- const logsHeadStat = await stat3(path22.join(cwd, ".git", "logs", "HEAD")).catch(() => null);
2200
+ const logsHeadStat = await stat3(path23.join(cwd, ".git", "logs", "HEAD")).catch(() => null);
2173
2201
  if (logsHeadStat && logsHeadStat.mtimeMs > nodesStat.mtimeMs) {
2174
2202
  reasons.push("repo HEAD moved since the graph was built (no build provenance recorded; inferred from .git/logs/HEAD)");
2175
2203
  }
@@ -2303,15 +2331,15 @@ var init_types2 = __esm(() => {
2303
2331
 
2304
2332
  // src/wiki/collect.ts
2305
2333
  import { readFile as readFile13, readdir as readdir6 } from "fs/promises";
2306
- import path23 from "path";
2334
+ import path24 from "path";
2307
2335
  function wikiRootPath(cwd) {
2308
- return path23.join(cwd, ".metaproject", "wiki");
2336
+ return path24.join(cwd, ".metaproject", "wiki");
2309
2337
  }
2310
2338
  async function collectPages(cwd) {
2311
2339
  const root = wikiRootPath(cwd);
2312
2340
  const pages = [];
2313
2341
  for (const { type, folder } of WIKI_PAGE_TYPES) {
2314
- const dir = path23.join(root, folder);
2342
+ const dir = path24.join(root, folder);
2315
2343
  let names;
2316
2344
  try {
2317
2345
  names = await readdir6(dir);
@@ -2326,7 +2354,7 @@ async function collectPages(cwd) {
2326
2354
  if (!entry.endsWith(".md")) {
2327
2355
  continue;
2328
2356
  }
2329
- const absolutePath = path23.join(dir, entry);
2357
+ const absolutePath = path24.join(dir, entry);
2330
2358
  let content;
2331
2359
  try {
2332
2360
  content = await readFile13(absolutePath, "utf8");
@@ -4634,16 +4662,16 @@ var init_exfil = __esm(() => {
4634
4662
 
4635
4663
  // src/lib/contained-path.ts
4636
4664
  import { existsSync, lstatSync, realpathSync } from "fs";
4637
- import path24 from "path";
4665
+ import path25 from "path";
4638
4666
  function resolveProjectRoot(startDir) {
4639
- let current = path24.resolve(startDir);
4667
+ let current = path25.resolve(startDir);
4640
4668
  for (;; ) {
4641
- if (existsSync(path24.join(current, ".metaproject")) || existsSync(path24.join(current, ".git"))) {
4669
+ if (existsSync(path25.join(current, ".metaproject")) || existsSync(path25.join(current, ".git"))) {
4642
4670
  return current;
4643
4671
  }
4644
- const parent = path24.dirname(current);
4672
+ const parent = path25.dirname(current);
4645
4673
  if (parent === current) {
4646
- return path24.resolve(startDir);
4674
+ return path25.resolve(startDir);
4647
4675
  }
4648
4676
  current = parent;
4649
4677
  }
@@ -4973,16 +5001,16 @@ var init_schemas = __esm(() => {
4973
5001
  });
4974
5002
 
4975
5003
  // src/security/config.ts
4976
- import path25 from "path";
5004
+ import path26 from "path";
4977
5005
  import { createHash as createHash4 } from "crypto";
4978
5006
  function securityProjectRoot(cwd) {
4979
5007
  return resolveProjectRoot(cwd);
4980
5008
  }
4981
5009
  function securityDataRoot(cwd) {
4982
- return path25.join(securityProjectRoot(cwd), ".metaproject", "data", "security");
5010
+ return path26.join(securityProjectRoot(cwd), ".metaproject", "data", "security");
4983
5011
  }
4984
5012
  function configPath(cwd) {
4985
- return path25.join(securityProjectRoot(cwd), ".metaproject", "security.config.json");
5013
+ return path26.join(securityProjectRoot(cwd), ".metaproject", "security.config.json");
4986
5014
  }
4987
5015
  function mergePolicy(base, override) {
4988
5016
  const merged = {
@@ -5146,9 +5174,9 @@ var init_config3 = __esm(() => {
5146
5174
  });
5147
5175
 
5148
5176
  // src/security/redact.ts
5149
- import path26 from "path";
5177
+ import path27 from "path";
5150
5178
  import { createHmac, randomBytes } from "crypto";
5151
- import { mkdir as mkdir8, readFile as readFile14, writeFile as writeFile5, chmod } from "fs/promises";
5179
+ import { mkdir as mkdir8, readFile as readFile14, writeFile as writeFile5, chmod as chmod2 } from "fs/promises";
5152
5180
  function maskFor(match) {
5153
5181
  return `[REDACTED:${match.mask ?? "sensitive"}]`;
5154
5182
  }
@@ -5221,11 +5249,11 @@ function redactSensitiveText(text) {
5221
5249
  return applyRedaction(text, matches);
5222
5250
  }
5223
5251
  function keyDir(cwd) {
5224
- return path26.join(securityDataRoot(cwd), "raw");
5252
+ return path27.join(securityDataRoot(cwd), "raw");
5225
5253
  }
5226
5254
  async function getHmacKey(cwd) {
5227
5255
  const dir = keyDir(cwd);
5228
- const file = path26.join(dir, KEY_FILE);
5256
+ const file = path27.join(dir, KEY_FILE);
5229
5257
  if (await pathExists(file)) {
5230
5258
  const existing = (await readFile14(file, "utf8")).trim();
5231
5259
  if (existing.length > 0) {
@@ -5237,7 +5265,7 @@ async function getHmacKey(cwd) {
5237
5265
  await writeFile5(file, `${key}
5238
5266
  `, "utf8");
5239
5267
  try {
5240
- await chmod(file, 384);
5268
+ await chmod2(file, 384);
5241
5269
  } catch {}
5242
5270
  return key;
5243
5271
  }
@@ -6270,7 +6298,7 @@ var init_resolve = __esm(() => {
6270
6298
  });
6271
6299
 
6272
6300
  // src/security/report.ts
6273
- import path27 from "path";
6301
+ import path28 from "path";
6274
6302
  import { mkdir as mkdir9, writeFile as writeFile6 } from "fs/promises";
6275
6303
  function tally(values) {
6276
6304
  const counts = {};
@@ -6387,26 +6415,26 @@ function renderFindings(findings) {
6387
6415
  `);
6388
6416
  }
6389
6417
  function artifactsDir(cwd) {
6390
- return path27.join(securityDataRoot(cwd), "artifacts");
6418
+ return path28.join(securityDataRoot(cwd), "artifacts");
6391
6419
  }
6392
6420
  async function writeSecurityArtifacts(cwd, report, config) {
6393
6421
  const dir = artifactsDir(cwd);
6394
6422
  await mkdir9(dir, { recursive: true });
6395
6423
  const committable = toCommittableReport(report);
6396
- const markdown = path27.join(dir, "latest.md");
6397
- const json = path27.join(dir, "latest.json");
6424
+ const markdown = path28.join(dir, "latest.md");
6425
+ const json = path28.join(dir, "latest.json");
6398
6426
  await writeFile6(markdown, renderReportMarkdown(committable), "utf8");
6399
6427
  await writeFile6(json, `${JSON.stringify(committable, null, 2)}
6400
6428
  `, "utf8");
6401
6429
  if (config.storeHashes) {
6402
- const rawDir = path27.join(securityDataRoot(cwd), "raw");
6430
+ const rawDir = path28.join(securityDataRoot(cwd), "raw");
6403
6431
  await mkdir9(rawDir, { recursive: true });
6404
- await writeFile6(path27.join(rawDir, "report.local.json"), `${JSON.stringify(report, null, 2)}
6432
+ await writeFile6(path28.join(rawDir, "report.local.json"), `${JSON.stringify(report, null, 2)}
6405
6433
  `, "utf8");
6406
6434
  }
6407
6435
  return {
6408
- markdownPath: path27.relative(cwd, markdown),
6409
- jsonPath: path27.relative(cwd, json)
6436
+ markdownPath: path28.relative(cwd, markdown),
6437
+ jsonPath: path28.relative(cwd, json)
6410
6438
  };
6411
6439
  }
6412
6440
  var SCHEMA_VERSION = 1;
@@ -6415,13 +6443,13 @@ var init_report = __esm(() => {
6415
6443
  });
6416
6444
 
6417
6445
  // src/security/incidents.ts
6418
- import path28 from "path";
6446
+ import path29 from "path";
6419
6447
  import { appendFile as appendFile3, mkdir as mkdir10, readFile as readFile15 } from "fs/promises";
6420
6448
  function incidentsDir(cwd) {
6421
- return path28.join(securityDataRoot(cwd), "incidents");
6449
+ return path29.join(securityDataRoot(cwd), "incidents");
6422
6450
  }
6423
6451
  function incidentsFile(cwd) {
6424
- return path28.join(incidentsDir(cwd), "incidents.jsonl");
6452
+ return path29.join(incidentsDir(cwd), "incidents.jsonl");
6425
6453
  }
6426
6454
  async function appendIncident(cwd, entry) {
6427
6455
  const dir = incidentsDir(cwd);
@@ -6440,7 +6468,7 @@ var init_incidents = __esm(() => {
6440
6468
  });
6441
6469
 
6442
6470
  // src/security/self-protect.ts
6443
- import path29 from "path";
6471
+ import path30 from "path";
6444
6472
  import { mkdir as mkdir11, readFile as readFile16, writeFile as writeFile7 } from "fs/promises";
6445
6473
  function currentState(config) {
6446
6474
  const policies = {};
@@ -6499,7 +6527,7 @@ function evaluateSelfProtection(config, previous, now = new Date().toISOString()
6499
6527
  return { warnings, incidents, findings, checksumMatch: checksum.match };
6500
6528
  }
6501
6529
  function stateFile(cwd) {
6502
- return path29.join(securityDataRoot(cwd), "raw", "state.json");
6530
+ return path30.join(securityDataRoot(cwd), "raw", "state.json");
6503
6531
  }
6504
6532
  async function readState(cwd) {
6505
6533
  const file = stateFile(cwd);
@@ -6514,7 +6542,7 @@ async function readState(cwd) {
6514
6542
  }
6515
6543
  async function writeState(cwd, state) {
6516
6544
  const file = stateFile(cwd);
6517
- await mkdir11(path29.dirname(file), { recursive: true });
6545
+ await mkdir11(path30.dirname(file), { recursive: true });
6518
6546
  await writeFile7(file, `${JSON.stringify(state, null, 2)}
6519
6547
  `, "utf8");
6520
6548
  }
@@ -6532,12 +6560,12 @@ var init_self_protect = __esm(() => {
6532
6560
 
6533
6561
  // src/lib/descriptor-read.ts
6534
6562
  import { constants, fstatSync, lstatSync as lstatSync2, statSync } from "fs";
6535
- import path30 from "path";
6563
+ import path31 from "path";
6536
6564
  import { dlopen, FFIType, ptr } from "bun:ffi";
6537
6565
  function readDescriptorChain(workspaceRoot, absolutePath, options = {}) {
6538
- const relativePath = path30.relative(workspaceRoot, absolutePath);
6539
- const components = relativePath.split(path30.sep);
6540
- if (!relativePath || path30.isAbsolute(relativePath) || components.some((component) => !component || component === "." || component === "..")) {
6566
+ const relativePath = path31.relative(workspaceRoot, absolutePath);
6567
+ const components = relativePath.split(path31.sep);
6568
+ if (!relativePath || path31.isAbsolute(relativePath) || components.some((component) => !component || component === "." || component === "..")) {
6541
6569
  throw new DescriptorReadError("invalid-path", "safe source path is not workspace-relative");
6542
6570
  }
6543
6571
  if (options.maxBytes !== undefined && (!Number.isSafeInteger(options.maxBytes) || options.maxBytes < 0)) {
@@ -6660,7 +6688,7 @@ var init_descriptor_read = __esm(() => {
6660
6688
 
6661
6689
  // src/lib/contained-read.ts
6662
6690
  import { lstat, realpath, stat as stat4 } from "fs/promises";
6663
- import path31 from "path";
6691
+ import path32 from "path";
6664
6692
  async function readContainedFile(ownerRoot, candidatePath, options = {}) {
6665
6693
  if (options.backend === "unsupported") {
6666
6694
  throw new ContainedReadError("CONTAINED_READ_UNAVAILABLE", "safe descriptor source reads are unavailable on this platform");
@@ -6709,8 +6737,8 @@ async function readContainedFile(ownerRoot, candidatePath, options = {}) {
6709
6737
  }
6710
6738
  }
6711
6739
  function isInside(root, candidate) {
6712
- const relative = path31.relative(root, candidate);
6713
- return relative === "" || !path31.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${path31.sep}`);
6740
+ const relative = path32.relative(root, candidate);
6741
+ return relative === "" || !path32.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${path32.sep}`);
6714
6742
  }
6715
6743
  function mapDescriptorError(error) {
6716
6744
  if (!(error instanceof DescriptorReadError))
@@ -6735,16 +6763,16 @@ var init_contained_read = __esm(() => {
6735
6763
 
6736
6764
  // src/security/path-scan.ts
6737
6765
  import { readdir as readdir7, realpath as realpath2, stat as stat5 } from "fs/promises";
6738
- import path32 from "path";
6766
+ import path33 from "path";
6739
6767
  function isInside2(root, candidate) {
6740
- const relative = path32.relative(root, candidate);
6741
- return relative === "" || !path32.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${path32.sep}`);
6768
+ const relative = path33.relative(root, candidate);
6769
+ return relative === "" || !path33.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${path33.sep}`);
6742
6770
  }
6743
6771
  function identityFor(value) {
6744
6772
  return `${String(value.dev)}:${String(value.ino)}`;
6745
6773
  }
6746
6774
  function relativePath(root, candidate) {
6747
- const relative = path32.relative(root, candidate);
6775
+ const relative = path33.relative(root, candidate);
6748
6776
  return relative === "" ? "." : relative;
6749
6777
  }
6750
6778
  function safeReason(error) {
@@ -6781,14 +6809,14 @@ async function scanContainedPath(input) {
6781
6809
  throw new Error("security scan target is outside the project root");
6782
6810
  }
6783
6811
  const exclusions = (input.exclusions ?? []).map((entry) => {
6784
- const absolute = path32.resolve(ownerRoot, entry);
6812
+ const absolute = path33.resolve(ownerRoot, entry);
6785
6813
  return isInside2(ownerRoot, absolute) ? absolute : null;
6786
6814
  }).filter((entry) => entry !== null);
6787
6815
  const scope = {
6788
6816
  path: relativePath(ownerRoot, targetReal),
6789
6817
  recursive: input.recursive ?? true,
6790
6818
  exclusions: (input.exclusions ?? []).map((entry) => {
6791
- const absolute = path32.resolve(ownerRoot, entry);
6819
+ const absolute = path33.resolve(ownerRoot, entry);
6792
6820
  return isInside2(ownerRoot, absolute) ? relativePath(ownerRoot, absolute) : "[external exclusion omitted]";
6793
6821
  }),
6794
6822
  limits
@@ -6806,7 +6834,7 @@ async function scanContainedPath(input) {
6806
6834
  if (!coverage.reasons.includes(reason))
6807
6835
  coverage.reasons.push(reason);
6808
6836
  };
6809
- const excluded = (candidate) => exclusions.some((entry) => candidate === entry || candidate.startsWith(`${entry}${path32.sep}`));
6837
+ const excluded = (candidate) => exclusions.some((entry) => candidate === entry || candidate.startsWith(`${entry}${path33.sep}`));
6810
6838
  const visit = async (candidate, depth) => {
6811
6839
  if (stoppedByLimit)
6812
6840
  return;
@@ -6869,7 +6897,7 @@ async function scanContainedPath(input) {
6869
6897
  return;
6870
6898
  }
6871
6899
  for (const entry of entries) {
6872
- await visit(path32.join(canonical, entry), depth + 1);
6900
+ await visit(path33.join(canonical, entry), depth + 1);
6873
6901
  if (stoppedByLimit)
6874
6902
  break;
6875
6903
  }
@@ -6933,7 +6961,7 @@ __export(exports_service2, {
6933
6961
  runScanPath: () => runScanPath,
6934
6962
  validateSerializedOutput: () => validateSerializedOutput
6935
6963
  });
6936
- import path33 from "path";
6964
+ import path34 from "path";
6937
6965
  import { readFile as readFile17 } from "fs/promises";
6938
6966
  function validateSerializedOutput(content) {
6939
6967
  return validateSerializedContentForTransport(content);
@@ -7035,7 +7063,7 @@ function hasRecognizedGate(value) {
7035
7063
  return typeof gate === "string" && RECOGNIZED_GATES.has(gate);
7036
7064
  }
7037
7065
  async function readLatestReport(cwd) {
7038
- const file = path33.join(artifactsDir(cwd), "latest.json");
7066
+ const file = path34.join(artifactsDir(cwd), "latest.json");
7039
7067
  if (!await pathExists(file)) {
7040
7068
  return { kind: "absent" };
7041
7069
  }
@@ -7152,7 +7180,7 @@ var init_service = __esm(() => {
7152
7180
  });
7153
7181
 
7154
7182
  // src/security/guard.ts
7155
- import path34 from "path";
7183
+ import path35 from "path";
7156
7184
  function prepareOutputForPersistence(guard, original) {
7157
7185
  if (!guard.allowed) {
7158
7186
  return { allowed: false, reason: guard.reason ?? "security gate blocked" };
@@ -7170,7 +7198,7 @@ function prepareOutputForPersistence(guard, original) {
7170
7198
  };
7171
7199
  }
7172
7200
  async function resolveManifestSecurityState(cwd) {
7173
- const manifestPath = path34.join(securityProjectRoot(cwd), ".metaproject", "metaproject.json");
7201
+ const manifestPath = path35.join(securityProjectRoot(cwd), ".metaproject", "metaproject.json");
7174
7202
  if (!await pathExists(manifestPath)) {
7175
7203
  return { enabled: false, manifestUnreadable: false };
7176
7204
  }
@@ -7368,9 +7396,9 @@ var MEMORY_EMBEDDING_ID = "memory.embedding", DEFAULT_EMBED_DIMS = 96;
7368
7396
  // src/memory/embedding/index.ts
7369
7397
  import { createHash as createHash5 } from "crypto";
7370
7398
  import { mkdir as mkdir12, readFile as readFile18, writeFile as writeFile8 } from "fs/promises";
7371
- import path35 from "path";
7399
+ import path36 from "path";
7372
7400
  function embeddingsDir(cwd) {
7373
- return path35.join(cwd, ".metaproject", "data", "memory", "embeddings");
7401
+ return path36.join(cwd, ".metaproject", "data", "memory", "embeddings");
7374
7402
  }
7375
7403
  function entryText(entry) {
7376
7404
  return `${entry.title}
@@ -7399,17 +7427,17 @@ async function buildEmbeddingIndex(cwd, entries, embedder, model, now) {
7399
7427
  };
7400
7428
  const dir = embeddingsDir(cwd);
7401
7429
  await mkdir12(dir, { recursive: true });
7402
- await writeFile8(path35.join(dir, "index.meta.json"), `${JSON.stringify(meta, null, 2)}
7430
+ await writeFile8(path36.join(dir, "index.meta.json"), `${JSON.stringify(meta, null, 2)}
7403
7431
  `, "utf8");
7404
- await writeFile8(path35.join(dir, "vectors.jsonl"), records.map((record) => JSON.stringify(record)).join(`
7432
+ await writeFile8(path36.join(dir, "vectors.jsonl"), records.map((record) => JSON.stringify(record)).join(`
7405
7433
  `) + (records.length > 0 ? `
7406
7434
  ` : ""), "utf8");
7407
7435
  return toIndex(meta, records);
7408
7436
  }
7409
7437
  async function loadEmbeddingIndex(cwd) {
7410
7438
  const dir = embeddingsDir(cwd);
7411
- const metaPath = path35.join(dir, "index.meta.json");
7412
- const vectorsPath = path35.join(dir, "vectors.jsonl");
7439
+ const metaPath = path36.join(dir, "index.meta.json");
7440
+ const vectorsPath = path36.join(dir, "vectors.jsonl");
7413
7441
  if (!await pathExists(metaPath) || !await pathExists(vectorsPath)) {
7414
7442
  return null;
7415
7443
  }
@@ -7860,7 +7888,7 @@ var init_ask = __esm(() => {
7860
7888
  });
7861
7889
 
7862
7890
  // src/wiki/backlinks.ts
7863
- import path36 from "path";
7891
+ import path37 from "path";
7864
7892
  function extractCodePaths(content) {
7865
7893
  const out = [];
7866
7894
  let match;
@@ -7890,8 +7918,8 @@ function resolveLink(fromRepoPath, raw) {
7890
7918
  const clean = (raw.split("#")[0] ?? "").trim();
7891
7919
  if (!clean)
7892
7920
  return "";
7893
- const fromDir = path36.posix.dirname(fromRepoPath.split(path36.sep).join("/"));
7894
- return path36.posix.normalize(path36.posix.join(fromDir, clean));
7921
+ const fromDir = path37.posix.dirname(fromRepoPath.split(path37.sep).join("/"));
7922
+ return path37.posix.normalize(path37.posix.join(fromDir, clean));
7895
7923
  }
7896
7924
  function buildBacklinkIndex(pages) {
7897
7925
  const index = new Map;
@@ -7905,18 +7933,18 @@ function buildBacklinkIndex(pages) {
7905
7933
  }
7906
7934
  };
7907
7935
  for (const page of pages) {
7908
- const from = page.repoPath.split(path36.sep).join("/");
7936
+ const from = page.repoPath.split(path37.sep).join("/");
7909
7937
  for (const raw of extractLinks(page.content))
7910
7938
  add(resolveLink(from, raw), from);
7911
7939
  for (const raw of extractCodePaths(page.content))
7912
- add(path36.posix.normalize(raw), from);
7940
+ add(path37.posix.normalize(raw), from);
7913
7941
  }
7914
7942
  for (const list of index.values())
7915
7943
  list.sort();
7916
7944
  return index;
7917
7945
  }
7918
7946
  function backlinksFor(index, targetRepoPath) {
7919
- const key = path36.posix.normalize(targetRepoPath.split(path36.sep).join("/"));
7947
+ const key = path37.posix.normalize(targetRepoPath.split(path37.sep).join("/"));
7920
7948
  return index.get(key) ?? [];
7921
7949
  }
7922
7950
  var LINK, CODE_SPAN, FILE_LIKE;
@@ -7929,7 +7957,7 @@ var init_backlinks = __esm(() => {
7929
7957
  // src/ctx/assembly.ts
7930
7958
  import { createHash as createHash6 } from "crypto";
7931
7959
  import { mkdir as mkdir13, rename as rename4, writeFile as writeFile9 } from "fs/promises";
7932
- import path37 from "path";
7960
+ import path38 from "path";
7933
7961
  function assembleContext(input) {
7934
7962
  let items = 0;
7935
7963
  let tokens = 0;
@@ -7973,9 +8001,9 @@ async function recordNoContentContext(input) {
7973
8001
  return assembly;
7974
8002
  }
7975
8003
  async function recordContextAssembly(input) {
7976
- const directory = path37.join(input.workspaceRoot, ".metaproject", "context-operations", "traces");
8004
+ const directory = path38.join(input.workspaceRoot, ".metaproject", "context-operations", "traces");
7977
8005
  await mkdir13(directory, { recursive: true });
7978
- const target = path37.join(directory, path37.basename(input.assembly.traceRef));
8006
+ const target = path38.join(directory, path38.basename(input.assembly.traceRef));
7979
8007
  const temporary = `${target}.${process.pid}.tmp`;
7980
8008
  await writeFile9(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 })}
7981
8009
  `, { mode: 384 });
@@ -7990,10 +8018,10 @@ function traceRefFor(traceId) {
7990
8018
  var init_assembly = () => {};
7991
8019
 
7992
8020
  // src/wiki/section-tombstone.ts
7993
- import path38 from "path";
8021
+ import path39 from "path";
7994
8022
  import { stat as stat6 } from "fs/promises";
7995
8023
  function sectionRegistryPath(cwd) {
7996
- return path38.join(cwd, ".metaproject", "wiki", ".sections.json");
8024
+ return path39.join(cwd, ".metaproject", "wiki", ".sections.json");
7997
8025
  }
7998
8026
  function emptySectionRegistry() {
7999
8027
  return { version: SECTION_REGISTRY_VERSION, entries: [], tombstones: [], lifted: [] };
@@ -9130,15 +9158,15 @@ __export(exports_service3, {
9130
9158
  import { spawn as spawn2 } from "child_process";
9131
9159
  import { createHash as createHash8 } from "crypto";
9132
9160
  import { mkdir as mkdir14, readFile as readFile20, readdir as readdir8, rm as rm3, writeFile as writeFile10 } from "fs/promises";
9133
- import path39 from "path";
9161
+ import path40 from "path";
9134
9162
  function wikiRootPath2(cwd) {
9135
- return path39.join(cwd, ".metaproject", "wiki");
9163
+ return path40.join(cwd, ".metaproject", "wiki");
9136
9164
  }
9137
9165
  function dataRootPath(cwd) {
9138
- return path39.join(cwd, ".metaproject", "data", "gdwiki");
9166
+ return path40.join(cwd, ".metaproject", "data", "gdwiki");
9139
9167
  }
9140
9168
  function linkCheckReportPath(cwd) {
9141
- return path39.join(dataRootPath(cwd), "link-check", "latest.md");
9169
+ return path40.join(dataRootPath(cwd), "link-check", "latest.md");
9142
9170
  }
9143
9171
  async function wikiStatus(cwd) {
9144
9172
  const root = wikiRootPath2(cwd);
@@ -9146,7 +9174,7 @@ async function wikiStatus(cwd) {
9146
9174
  const pages = enabled ? await collectPages(cwd) : [];
9147
9175
  return {
9148
9176
  enabled,
9149
- wikiRoot: path39.relative(cwd, root),
9177
+ wikiRoot: path40.relative(cwd, root),
9150
9178
  totalPages: pages.length,
9151
9179
  countsByType: WIKI_PAGE_TYPES.map(({ type }) => ({
9152
9180
  type,
@@ -9177,9 +9205,9 @@ async function wikiCreatePage(input) {
9177
9205
  if (!/^[a-z0-9][a-z0-9-]*$/.test(input.slug)) {
9178
9206
  throw new Error(`Invalid slug: ${input.slug}. Use lowercase letters, digits, and hyphens.`);
9179
9207
  }
9180
- const dir = path39.join(wikiRootPath2(input.cwd), typeConfig.folder);
9181
- const filePath = path39.join(dir, `${input.slug}.md`);
9182
- const relativePath = path39.relative(input.cwd, filePath);
9208
+ const dir = path40.join(wikiRootPath2(input.cwd), typeConfig.folder);
9209
+ const filePath = path40.join(dir, `${input.slug}.md`);
9210
+ const relativePath = path40.relative(input.cwd, filePath);
9183
9211
  if (await pathExists(filePath) && !input.force) {
9184
9212
  throw new Error(`Page already exists: ${relativePath}. Use --force to overwrite.`);
9185
9213
  }
@@ -9190,7 +9218,7 @@ async function wikiCreatePage(input) {
9190
9218
  }
9191
9219
  async function wikiGenerateIndex(cwd) {
9192
9220
  const root = wikiRootPath2(cwd);
9193
- const indexPath = path39.join(root, "index.md");
9221
+ const indexPath = path40.join(root, "index.md");
9194
9222
  const pages = await collectPages(cwd);
9195
9223
  const generatedAt = new Date().toISOString();
9196
9224
  const managedBlock = `${WIKI_INDEX_BEGIN}
@@ -9208,7 +9236,7 @@ ${managedBlock}
9208
9236
  await mkdir14(root, { recursive: true });
9209
9237
  await writeFile10(indexPath, next, "utf8");
9210
9238
  return {
9211
- path: path39.relative(cwd, indexPath),
9239
+ path: path40.relative(cwd, indexPath),
9212
9240
  pageCount: pages.length,
9213
9241
  generatedAt
9214
9242
  };
@@ -9216,13 +9244,13 @@ ${managedBlock}
9216
9244
  async function wikiCheckLinks(cwd) {
9217
9245
  const root = wikiRootPath2(cwd);
9218
9246
  const allFiles = await pathExists(root) ? await walkMarkdown(root) : [];
9219
- const files = allFiles.filter((absolutePath) => !path39.relative(root, absolutePath).startsWith(`templates${path39.sep}`));
9247
+ const files = allFiles.filter((absolutePath) => !path40.relative(root, absolutePath).startsWith(`templates${path40.sep}`));
9220
9248
  const broken = [];
9221
9249
  let checkedLinks = 0;
9222
9250
  let skippedExternal = 0;
9223
9251
  for (const absolutePath of files) {
9224
9252
  const content = await readFile20(absolutePath, "utf8");
9225
- const pageRelative = path39.relative(cwd, absolutePath);
9253
+ const pageRelative = path40.relative(cwd, absolutePath);
9226
9254
  for (const target of extractLinkTargets(content)) {
9227
9255
  if (EXTERNAL_LINK.test(target)) {
9228
9256
  skippedExternal += 1;
@@ -9233,7 +9261,7 @@ async function wikiCheckLinks(cwd) {
9233
9261
  continue;
9234
9262
  }
9235
9263
  checkedLinks += 1;
9236
- const resolved = path39.resolve(path39.dirname(absolutePath), filePart);
9264
+ const resolved = path40.resolve(path40.dirname(absolutePath), filePart);
9237
9265
  if (!await pathExists(resolved)) {
9238
9266
  broken.push({
9239
9267
  page: pageRelative,
@@ -9245,7 +9273,7 @@ async function wikiCheckLinks(cwd) {
9245
9273
  }
9246
9274
  const generatedAt = new Date().toISOString();
9247
9275
  const reportPath = linkCheckReportPath(cwd);
9248
- await mkdir14(path39.dirname(reportPath), { recursive: true });
9276
+ await mkdir14(path40.dirname(reportPath), { recursive: true });
9249
9277
  await writeFile10(reportPath, renderLinkCheckReport({
9250
9278
  generatedAt,
9251
9279
  checkedPages: files.length,
@@ -9254,7 +9282,7 @@ async function wikiCheckLinks(cwd) {
9254
9282
  broken
9255
9283
  }), "utf8");
9256
9284
  return {
9257
- reportPath: path39.relative(cwd, reportPath),
9285
+ reportPath: path40.relative(cwd, reportPath),
9258
9286
  checkedPages: files.length,
9259
9287
  checkedLinks,
9260
9288
  skippedExternal,
@@ -9304,7 +9332,7 @@ async function wikiValidate(cwd) {
9304
9332
  }
9305
9333
  if (await isIndexStale(cwd, pages)) {
9306
9334
  issues.push({
9307
- page: path39.join(path39.relative(cwd, wikiRootPath2(cwd)), "index.md"),
9335
+ page: path40.join(path40.relative(cwd, wikiRootPath2(cwd)), "index.md"),
9308
9336
  kind: "index",
9309
9337
  message: "index out of date, run `keryx wiki index`"
9310
9338
  });
@@ -9341,7 +9369,7 @@ async function wikiCollect(input) {
9341
9369
  };
9342
9370
  }
9343
9371
  async function wikiPruneOrphans(cwd) {
9344
- const componentsDir = path39.join(wikiRootPath2(cwd), "components");
9372
+ const componentsDir = path40.join(wikiRootPath2(cwd), "components");
9345
9373
  if (!await pathExists(componentsDir)) {
9346
9374
  return { pruned: [], orphanedAccepted: [] };
9347
9375
  }
@@ -9358,20 +9386,20 @@ async function wikiPruneOrphans(cwd) {
9358
9386
  if (validSlugs.has(slug)) {
9359
9387
  continue;
9360
9388
  }
9361
- const filePath = path39.join(componentsDir, entry);
9389
+ const filePath = path40.join(componentsDir, entry);
9362
9390
  const current = await readFile20(filePath, "utf8");
9363
9391
  const isUnmodifiedDraft = /\nStatus:\s*draft\s*\n/.test(current) && current.includes("Generated by `keryx wiki collect`");
9364
9392
  if (isUnmodifiedDraft) {
9365
9393
  await rm3(filePath);
9366
- pruned.push(path39.relative(cwd, filePath));
9394
+ pruned.push(path40.relative(cwd, filePath));
9367
9395
  } else {
9368
- orphanedAccepted.push(path39.relative(cwd, filePath));
9396
+ orphanedAccepted.push(path40.relative(cwd, filePath));
9369
9397
  }
9370
9398
  }
9371
9399
  return { pruned, orphanedAccepted };
9372
9400
  }
9373
9401
  async function validModuleNames(cwd) {
9374
- const nodesPath = path39.join(cwd, ".metaproject", "data", "gdgraph", "storage", "nodes.jsonl");
9402
+ const nodesPath = path40.join(cwd, ".metaproject", "data", "gdgraph", "storage", "nodes.jsonl");
9375
9403
  if (!await pathExists(nodesPath)) {
9376
9404
  return;
9377
9405
  }
@@ -9440,9 +9468,9 @@ async function wikiEvidence(input) {
9440
9468
  });
9441
9469
  }
9442
9470
  function resolveEvidenceScope(cwd, override) {
9443
- const absolute = path39.resolve(cwd);
9471
+ const absolute = path40.resolve(cwd);
9444
9472
  return {
9445
- projectId: override?.projectId ?? (path39.basename(absolute) || "project"),
9473
+ projectId: override?.projectId ?? (path40.basename(absolute) || "project"),
9446
9474
  checkoutId: override?.checkoutId ?? `checkout:${createHash8("sha256").update(absolute).digest("hex").slice(0, 16)}`,
9447
9475
  ...override?.workspaceId ? { workspaceId: override.workspaceId } : {},
9448
9476
  ...override?.taskId ? { taskId: override.taskId } : {}
@@ -9457,7 +9485,7 @@ function isMachineAuthoredPage(pageType, relativePath, content) {
9457
9485
  if (source === null) {
9458
9486
  return false;
9459
9487
  }
9460
- const normalised = relativePath.split(path39.sep).join("/").replace(/^wiki\//, "");
9488
+ const normalised = relativePath.split(path40.sep).join("/").replace(/^wiki\//, "");
9461
9489
  return WIKI_PAGE_PRODUCERS.some((producer) => producer.source === source && producer.pageType === pageType && producer.path.test(normalised) && /^-[ \t]+Link:.*\bsha256\b/m.test(content));
9462
9490
  }
9463
9491
  function createGdWikiService() {
@@ -9473,8 +9501,8 @@ function createGdWikiService() {
9473
9501
  };
9474
9502
  }
9475
9503
  async function collectGraphWikiCandidates(cwd, generatedAt, limit, onlyModules) {
9476
- const nodesPath = path39.join(cwd, ".metaproject", "data", "gdgraph", "storage", "nodes.jsonl");
9477
- const edgesPath = path39.join(cwd, ".metaproject", "data", "gdgraph", "storage", "edges.jsonl");
9504
+ const nodesPath = path40.join(cwd, ".metaproject", "data", "gdgraph", "storage", "nodes.jsonl");
9505
+ const edgesPath = path40.join(cwd, ".metaproject", "data", "gdgraph", "storage", "edges.jsonl");
9478
9506
  if (!await pathExists(nodesPath) || !await pathExists(edgesPath)) {
9479
9507
  return [];
9480
9508
  }
@@ -9658,7 +9686,7 @@ function topCounts(bucket, limit) {
9658
9686
  return [...bucket.entries()].sort((a, b) => b[1] - a[1]).slice(0, limit);
9659
9687
  }
9660
9688
  async function readModuleReadme(cwd, moduleName) {
9661
- const readmePath = path39.join(cwd, ...moduleName.split("/"), "README.md");
9689
+ const readmePath = path40.join(cwd, ...moduleName.split("/"), "README.md");
9662
9690
  if (!await pathExists(readmePath)) {
9663
9691
  return null;
9664
9692
  }
@@ -9679,7 +9707,7 @@ async function extractModuleExports(cwd, files) {
9679
9707
  const declRe = /export\s+(?:async\s+)?(?:default\s+)?(?:const|let|var|function|class|type|interface|enum)\s+([A-Za-z_$][\w$]*)/g;
9680
9708
  const braceRe = /export\s*\{([^}]+)\}/g;
9681
9709
  for (const file of files.slice(0, 4)) {
9682
- const filePath = path39.join(cwd, ...file.split("/"));
9710
+ const filePath = path40.join(cwd, ...file.split("/"));
9683
9711
  if (!await pathExists(filePath)) {
9684
9712
  continue;
9685
9713
  }
@@ -9710,7 +9738,7 @@ async function extractModuleExports(cwd, files) {
9710
9738
  }
9711
9739
  async function extractModuleApi(cwd, files) {
9712
9740
  const names = await extractModuleExports(cwd, files);
9713
- const symbolsPath = path39.join(cwd, ".metaproject", "data", "gdgraph", "storage", "symbols.jsonl");
9741
+ const symbolsPath = path40.join(cwd, ".metaproject", "data", "gdgraph", "storage", "symbols.jsonl");
9714
9742
  if (names.length === 0 || !await pathExists(symbolsPath)) {
9715
9743
  return names.map((name) => "`" + name + "`");
9716
9744
  }
@@ -9736,7 +9764,7 @@ async function extractModuleApi(cwd, files) {
9736
9764
  });
9737
9765
  }
9738
9766
  async function collectHealthWikiCandidates(cwd, generatedAt) {
9739
- const healthPath = path39.join(cwd, ".metaproject", "data", "health", "artifacts", "latest.json");
9767
+ const healthPath = path40.join(cwd, ".metaproject", "data", "health", "artifacts", "latest.json");
9740
9768
  if (!await pathExists(healthPath)) {
9741
9769
  return [];
9742
9770
  }
@@ -9778,7 +9806,7 @@ async function collectHealthWikiCandidates(cwd, generatedAt) {
9778
9806
  }];
9779
9807
  }
9780
9808
  async function collectTestingWikiCandidates(cwd, generatedAt) {
9781
- const contextPath = path39.join(cwd, ".metaproject", "data", "testing", "context.md");
9809
+ const contextPath = path40.join(cwd, ".metaproject", "data", "testing", "context.md");
9782
9810
  if (!await pathExists(contextPath)) {
9783
9811
  return [];
9784
9812
  }
@@ -9809,8 +9837,8 @@ async function writeCollectedPage(cwd, candidate, force) {
9809
9837
  if (!folder) {
9810
9838
  throw new Error(`Unsupported collected wiki type: ${candidate.type}`);
9811
9839
  }
9812
- const filePath = path39.join(wikiRootPath2(cwd), folder, `${candidate.slug}.md`);
9813
- const relativePath = path39.relative(cwd, filePath);
9840
+ const filePath = path40.join(wikiRootPath2(cwd), folder, `${candidate.slug}.md`);
9841
+ const relativePath = path40.relative(cwd, filePath);
9814
9842
  const exists = await pathExists(filePath);
9815
9843
  if (exists && !force) {
9816
9844
  return { path: relativePath, type: candidate.type, source: candidate.source, action: "skipped" };
@@ -9838,7 +9866,7 @@ async function writeCollectedPage(cwd, candidate, force) {
9838
9866
  securityReason: output.reason
9839
9867
  };
9840
9868
  }
9841
- await mkdir14(path39.dirname(filePath), { recursive: true });
9869
+ await mkdir14(path40.dirname(filePath), { recursive: true });
9842
9870
  await writeFile10(filePath, output.content, "utf8");
9843
9871
  return {
9844
9872
  path: relativePath,
@@ -9850,7 +9878,7 @@ async function writeCollectedPage(cwd, candidate, force) {
9850
9878
  async function wikiPagesForFile(cwd, targetRepoPath) {
9851
9879
  const pages = await collectPages(cwd);
9852
9880
  const refs = await Promise.all(pages.map(async (page) => ({
9853
- repoPath: path39.relative(cwd, page.absolutePath).split(path39.sep).join("/"),
9881
+ repoPath: path40.relative(cwd, page.absolutePath).split(path40.sep).join("/"),
9854
9882
  content: await readFile20(page.absolutePath, "utf8")
9855
9883
  })));
9856
9884
  return backlinksFor(buildBacklinkIndex(refs), targetRepoPath);
@@ -9889,7 +9917,7 @@ function renderIndexBody(pages, generatedAt) {
9889
9917
  `).trimEnd();
9890
9918
  }
9891
9919
  async function isIndexStale(cwd, pages) {
9892
- const indexPath = path39.join(wikiRootPath2(cwd), "index.md");
9920
+ const indexPath = path40.join(wikiRootPath2(cwd), "index.md");
9893
9921
  if (!await pathExists(indexPath)) {
9894
9922
  return true;
9895
9923
  }
@@ -9907,7 +9935,7 @@ async function walkMarkdown(root) {
9907
9935
  const results = [];
9908
9936
  const entries = await readdir8(root, { withFileTypes: true });
9909
9937
  for (const entry of entries) {
9910
- const absolutePath = path39.join(root, entry.name);
9938
+ const absolutePath = path40.join(root, entry.name);
9911
9939
  if (entry.isDirectory()) {
9912
9940
  results.push(...await walkMarkdown(absolutePath));
9913
9941
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
@@ -9964,7 +9992,7 @@ ${JSON.stringify(state, null, 2)}
9964
9992
  `;
9965
9993
  }
9966
9994
  async function readIndexGeneratedAt(cwd) {
9967
- const indexPath = path39.join(wikiRootPath2(cwd), "index.md");
9995
+ const indexPath = path40.join(wikiRootPath2(cwd), "index.md");
9968
9996
  if (!await pathExists(indexPath)) {
9969
9997
  return null;
9970
9998
  }
@@ -10201,7 +10229,7 @@ async function validateStructure(cwd, pages, issues) {
10201
10229
  if (pattern.includes("*")) {
10202
10230
  continue;
10203
10231
  }
10204
- if (!await pathExists(path39.join(cwd, pattern))) {
10232
+ if (!await pathExists(path40.join(cwd, pattern))) {
10205
10233
  issues.push({
10206
10234
  page: page.relativePath,
10207
10235
  kind: "describes",
@@ -10272,9 +10300,9 @@ var init_service2 = __esm(() => {
10272
10300
  // src/gdgraph/wiki-layer.ts
10273
10301
  import { createHash as createHash9 } from "crypto";
10274
10302
  import { mkdir as mkdir15, stat as stat7, writeFile as writeFile11 } from "fs/promises";
10275
- import path40 from "path";
10303
+ import path41 from "path";
10276
10304
  function storageDir(projectRoot) {
10277
- return path40.join(projectRoot, ".metaproject", "data", "gdgraph", "storage");
10305
+ return path41.join(projectRoot, ".metaproject", "data", "gdgraph", "storage");
10278
10306
  }
10279
10307
  function wikiPageId(relativePath) {
10280
10308
  return `wiki:${relativePath}`;
@@ -10340,11 +10368,11 @@ async function enrichBuildWithWikiLayer(input) {
10340
10368
  const mtimes = new Map;
10341
10369
  for (const record of input.fileRecords) {
10342
10370
  try {
10343
- const info = await stat7(path40.join(input.projectRoot, record.path));
10371
+ const info = await stat7(path41.join(input.projectRoot, record.path));
10344
10372
  mtimes.set(record.path, info.mtimeMs);
10345
10373
  } catch {}
10346
10374
  }
10347
- await writeFile11(path40.join(dir, BUILD_MANIFEST_FILE), `${JSON.stringify({ version: 1, files: computeFingerprints(input.fileRecords, mtimes) }, null, 2)}
10375
+ await writeFile11(path41.join(dir, BUILD_MANIFEST_FILE), `${JSON.stringify({ version: 1, files: computeFingerprints(input.fileRecords, mtimes) }, null, 2)}
10348
10376
  `, "utf8");
10349
10377
  const validModules = input.validModules !== undefined ? input.validModules : await (input.loadValidModules ?? defaultLoadValidModules)(input.projectRoot);
10350
10378
  const wikiPages = await collectPages(input.projectRoot);
@@ -10369,8 +10397,8 @@ async function enrichBuildWithWikiLayer(input) {
10369
10397
  version: page.version
10370
10398
  }))
10371
10399
  });
10372
- await writeJsonl(path40.join(dir, WIKI_PAGES_FILE), layer.pages);
10373
- await writeJsonl(path40.join(dir, DESCRIBES_FILE), layer.describes);
10400
+ await writeJsonl(path41.join(dir, WIKI_PAGES_FILE), layer.pages);
10401
+ await writeJsonl(path41.join(dir, DESCRIBES_FILE), layer.describes);
10374
10402
  return layer;
10375
10403
  }
10376
10404
  async function defaultLoadValidModules(projectRoot) {
@@ -10393,7 +10421,7 @@ __export(exports_service, {
10393
10421
  createFlowService: () => createFlowService
10394
10422
  });
10395
10423
  import { mkdir as mkdir5, readFile as readFile10 } from "fs/promises";
10396
- import path14 from "path";
10424
+ import path15 from "path";
10397
10425
 
10398
10426
  // src/contracts/resolver.ts
10399
10427
  import { readFileSync } from "fs";
@@ -13083,8 +13111,10 @@ var DEFAULT_TASKS = [
13083
13111
  ];
13084
13112
 
13085
13113
  // src/flow/allocation.ts
13086
- init_fs();
13087
13114
  import { appendFile as appendFile2, mkdir as mkdir4, readFile as readFile9 } from "fs/promises";
13115
+ import path14 from "path";
13116
+
13117
+ // src/lib/clone-scope.ts
13088
13118
  import path13 from "path";
13089
13119
  async function gitCommonDir(cwd) {
13090
13120
  try {
@@ -13115,27 +13145,30 @@ async function gitToplevel(cwd) {
13115
13145
  return null;
13116
13146
  }
13117
13147
  }
13148
+
13149
+ // src/flow/allocation.ts
13150
+ init_fs();
13118
13151
  function projectKey(toplevel, cwd) {
13119
13152
  if (!toplevel) {
13120
13153
  return "root";
13121
13154
  }
13122
- const relative = path13.relative(toplevel, cwd);
13155
+ const relative = path14.relative(toplevel, cwd);
13123
13156
  return relative === "" ? "root" : slugify(relative);
13124
13157
  }
13125
13158
  async function resolveAllocationScope(cwd) {
13126
13159
  const commonDir = await gitCommonDir(cwd);
13127
13160
  if (!commonDir) {
13128
13161
  return {
13129
- lockPath: path13.join(flowsRoot(cwd), ".flow-init.lock"),
13162
+ lockPath: path14.join(flowsRoot(cwd), ".flow-init.lock"),
13130
13163
  ledgerPath: null,
13131
13164
  project: "root"
13132
13165
  };
13133
13166
  }
13134
13167
  const key = projectKey(await gitToplevel(cwd), cwd);
13135
- const dir = path13.join(commonDir, "keryx", "flow-ids");
13168
+ const dir = path14.join(commonDir, "keryx", "flow-ids");
13136
13169
  return {
13137
- lockPath: path13.join(dir, `${key}.lock`),
13138
- ledgerPath: path13.join(dir, `${key}.jsonl`),
13170
+ lockPath: path14.join(dir, `${key}.lock`),
13171
+ ledgerPath: path14.join(dir, `${key}.jsonl`),
13139
13172
  project: key
13140
13173
  };
13141
13174
  }
@@ -13168,7 +13201,7 @@ async function recordAllocation(scope, record) {
13168
13201
  if (!scope.ledgerPath) {
13169
13202
  return;
13170
13203
  }
13171
- await mkdir4(path13.dirname(scope.ledgerPath), { recursive: true });
13204
+ await mkdir4(path14.dirname(scope.ledgerPath), { recursive: true });
13172
13205
  await appendFile2(scope.ledgerPath, `${JSON.stringify(record)}
13173
13206
  `, "utf8");
13174
13207
  }
@@ -13274,7 +13307,7 @@ function createFlowService(deps) {
13274
13307
  return flow;
13275
13308
  }
13276
13309
  function flowLockPath(cwd, dir) {
13277
- return path14.join(flowsRoot(cwd), `.flow-lock-${dir}`);
13310
+ return path15.join(flowsRoot(cwd), `.flow-lock-${dir}`);
13278
13311
  }
13279
13312
  async function mutate(cwd, id, run) {
13280
13313
  const dir = await resolveFlowDir(cwd, id);
@@ -13316,7 +13349,7 @@ function createFlowService(deps) {
13316
13349
  const date = now().slice(0, 10);
13317
13350
  const slug = slugify(input.slug ?? title);
13318
13351
  const dir = `${id}-${date}-${slug}`;
13319
- const absolute = path14.join(flowsRoot(input.cwd), dir);
13352
+ const absolute = path15.join(flowsRoot(input.cwd), dir);
13320
13353
  if (await pathExists(absolute)) {
13321
13354
  throw new Error(`Flow directory already exists: ${dir}`);
13322
13355
  }
@@ -13343,15 +13376,15 @@ function createFlowService(deps) {
13343
13376
  history: [{ at: createdAt, event: "created" }]
13344
13377
  };
13345
13378
  const sourceLabel = input.issue ?? "user description";
13346
- await writeFileAtomic(path14.join(absolute, "description.md"), renderDescription(title, sourceLabel));
13347
- await writeFileAtomic(path14.join(absolute, "context.md"), context.markdown);
13348
- await writeFileAtomic(path14.join(absolute, "plan.md"), renderPlan());
13349
- await writeFileAtomic(path14.join(absolute, "tasks.md"), renderTasksDoc());
13350
- await writeFileAtomic(path14.join(absolute, "acceptance-criteria.md"), renderAcceptanceCriteria());
13351
- await writeFileAtomic(path14.join(absolute, "journal.md"), renderJournal(createdAt));
13379
+ await writeFileAtomic(path15.join(absolute, "description.md"), renderDescription(title, sourceLabel));
13380
+ await writeFileAtomic(path15.join(absolute, "context.md"), context.markdown);
13381
+ await writeFileAtomic(path15.join(absolute, "plan.md"), renderPlan());
13382
+ await writeFileAtomic(path15.join(absolute, "tasks.md"), renderTasksDoc());
13383
+ await writeFileAtomic(path15.join(absolute, "acceptance-criteria.md"), renderAcceptanceCriteria());
13384
+ await writeFileAtomic(path15.join(absolute, "journal.md"), renderJournal(createdAt));
13352
13385
  await writeFlow(input.cwd, dir, flow);
13353
13386
  await recordAllocation(scope, { id, dir, at: createdAt, project: scope.project });
13354
- return { flow, dir: path14.relative(input.cwd, absolute), contextNotes: context.notes };
13387
+ return { flow, dir: path15.relative(input.cwd, absolute), contextNotes: context.notes };
13355
13388
  });
13356
13389
  },
13357
13390
  async list({ cwd }) {
@@ -13749,7 +13782,7 @@ function createFlowService(deps) {
13749
13782
  issues.push({ flow: dir, kind: "schema", message: `unknown schemaVersion ${flow.schemaVersion}` });
13750
13783
  }
13751
13784
  try {
13752
- const raw = JSON.parse(await Bun.file(path14.join(flowsRoot(cwd), dir, "flow.json")).text());
13785
+ const raw = JSON.parse(await Bun.file(path15.join(flowsRoot(cwd), dir, "flow.json")).text());
13753
13786
  const validation = validateAgainstSchemaObject(flowStateSchema(), raw);
13754
13787
  if (!validation.valid) {
13755
13788
  issues.push({
@@ -13760,7 +13793,7 @@ function createFlowService(deps) {
13760
13793
  }
13761
13794
  } catch {}
13762
13795
  for (const file of ["description.md", "context.md", "plan.md", "tasks.md", "acceptance-criteria.md", "journal.md"]) {
13763
- if (!await pathExists(path14.join(flowsRoot(cwd), dir, file))) {
13796
+ if (!await pathExists(path15.join(flowsRoot(cwd), dir, file))) {
13764
13797
  issues.push({ flow: dir, kind: "structure", message: `missing ${file}` });
13765
13798
  }
13766
13799
  }
@@ -13799,7 +13832,7 @@ function createFlowService(deps) {
13799
13832
  };
13800
13833
  }
13801
13834
  async function appendIdMap(cwd, entry) {
13802
- const file = path14.join(flowsRoot(cwd), "id-map.json");
13835
+ const file = path15.join(flowsRoot(cwd), "id-map.json");
13803
13836
  let entries = [];
13804
13837
  if (await pathExists(file)) {
13805
13838
  const raw = await readFile10(file, "utf8");
@@ -13810,7 +13843,7 @@ async function appendIdMap(cwd, entry) {
13810
13843
  }
13811
13844
  entries = parsed;
13812
13845
  } catch (error) {
13813
- throw new Error(`Cannot read ${path14.relative(cwd, file)}: ${error instanceof Error ? error.message : String(error)}`);
13846
+ throw new Error(`Cannot read ${path15.relative(cwd, file)}: ${error instanceof Error ? error.message : String(error)}`);
13814
13847
  }
13815
13848
  }
13816
13849
  entries.push(entry);
@@ -13992,7 +14025,7 @@ __export(exports_service4, {
13992
14025
  // src/gdgraph/build.ts
13993
14026
  import { mkdir as mkdir16, readdir as readdir9, readFile as readFile21, writeFile as writeFile12 } from "fs/promises";
13994
14027
  import { existsSync as existsSync2 } from "fs";
13995
- import path41 from "path";
14028
+ import path42 from "path";
13996
14029
 
13997
14030
  // src/gdgraph/types.ts
13998
14031
  var UNKNOWN_IMPORT_KIND = "unknown-static";
@@ -14057,7 +14090,7 @@ async function buildGraph(projectRoot) {
14057
14090
  const assetNodes = new Map;
14058
14091
  const fileRecords = [];
14059
14092
  for (const file of files) {
14060
- const absolutePath = path41.join(projectRoot, file);
14093
+ const absolutePath = path42.join(projectRoot, file);
14061
14094
  const content = await readFile21(absolutePath, "utf8");
14062
14095
  fileRecords.push({ path: file, content });
14063
14096
  const language = getLanguage(file);
@@ -14110,24 +14143,24 @@ async function collectSourceFiles(projectRoot) {
14110
14143
  const result = [];
14111
14144
  const skippedDirectories = [];
14112
14145
  async function walk(relativeDir) {
14113
- const absoluteDir = path41.join(projectRoot, relativeDir);
14146
+ const absoluteDir = path42.join(projectRoot, relativeDir);
14114
14147
  const entries = await readdir9(absoluteDir, { withFileTypes: true });
14115
14148
  for (const entry of entries) {
14116
14149
  if (entry.isDirectory()) {
14117
14150
  if (IGNORE_DIRS.has(entry.name)) {
14118
- skippedDirectories.push(normalizePath2(path41.posix.join(relativeDir, entry.name)).replace(/^\.\//, ""));
14151
+ skippedDirectories.push(normalizePath2(path42.posix.join(relativeDir, entry.name)).replace(/^\.\//, ""));
14119
14152
  continue;
14120
14153
  }
14121
- await walk(normalizePath2(path41.posix.join(relativeDir, entry.name)));
14154
+ await walk(normalizePath2(path42.posix.join(relativeDir, entry.name)));
14122
14155
  continue;
14123
14156
  }
14124
14157
  if (!entry.isFile()) {
14125
14158
  continue;
14126
14159
  }
14127
- if (!SOURCE_EXTENSIONS.includes(path41.extname(entry.name))) {
14160
+ if (!SOURCE_EXTENSIONS.includes(path42.extname(entry.name))) {
14128
14161
  continue;
14129
14162
  }
14130
- result.push(normalizePath2(path41.posix.join(relativeDir, entry.name)).replace(/^\.\//, ""));
14163
+ result.push(normalizePath2(path42.posix.join(relativeDir, entry.name)).replace(/^\.\//, ""));
14131
14164
  }
14132
14165
  }
14133
14166
  await walk(".");
@@ -14209,8 +14242,8 @@ function resolveImport(projectRoot, fromFile, specifier, fileSet, resolver) {
14209
14242
  }
14210
14243
  function resolveAssetImport(projectRoot, fromFile, specifier, resolver) {
14211
14244
  for (const candidate of importCandidateBases(projectRoot, fromFile, specifier, resolver)) {
14212
- const extension = path41.posix.extname(candidate);
14213
- if (ASSET_EXTENSIONS.includes(extension) && existsSync2(path41.join(projectRoot, candidate))) {
14245
+ const extension = path42.posix.extname(candidate);
14246
+ if (ASSET_EXTENSIONS.includes(extension) && existsSync2(path42.join(projectRoot, candidate))) {
14214
14247
  return candidate;
14215
14248
  }
14216
14249
  }
@@ -14219,17 +14252,17 @@ function resolveAssetImport(projectRoot, fromFile, specifier, resolver) {
14219
14252
  function importCandidateBases(projectRoot, fromFile, specifier, resolver) {
14220
14253
  const normalizedSpecifier = stripImportSuffix(specifier);
14221
14254
  if (normalizedSpecifier.startsWith(".") && getLanguage(fromFile) !== "python") {
14222
- const fromDir = path41.posix.dirname(fromFile);
14223
- return [normalizePath2(path41.posix.normalize(path41.posix.join(fromDir, normalizedSpecifier)))];
14255
+ const fromDir = path42.posix.dirname(fromFile);
14256
+ return [normalizePath2(path42.posix.normalize(path42.posix.join(fromDir, normalizedSpecifier)))];
14224
14257
  }
14225
- return resolver.candidateBases(normalizedSpecifier, fromFile).map((candidate) => normalizePath2(path41.relative(projectRoot, path41.join(projectRoot, candidate))));
14258
+ return resolver.candidateBases(normalizedSpecifier, fromFile).map((candidate) => normalizePath2(path42.relative(projectRoot, path42.join(projectRoot, candidate))));
14226
14259
  }
14227
14260
  function resolveSourceCandidate(base, fileSet) {
14228
14261
  const candidates = [
14229
14262
  base,
14230
14263
  ...SOURCE_RESOLUTION_EXTENSIONS.map((extension) => `${base}${extension}`),
14231
- ...SOURCE_RESOLUTION_EXTENSIONS.map((extension) => path41.posix.join(base, `index${extension}`)),
14232
- path41.posix.join(base, "__init__.py")
14264
+ ...SOURCE_RESOLUTION_EXTENSIONS.map((extension) => path42.posix.join(base, `index${extension}`)),
14265
+ path42.posix.join(base, "__init__.py")
14233
14266
  ];
14234
14267
  return candidates.find((candidate) => fileSet.has(candidate)) ?? null;
14235
14268
  }
@@ -14259,7 +14292,7 @@ async function loadJavaResolver(projectRoot) {
14259
14292
  return createJavaResolver(roots);
14260
14293
  }
14261
14294
  async function discoverJavaSourceRoots(projectRoot) {
14262
- const pomPath = path41.join(projectRoot, "pom.xml");
14295
+ const pomPath = path42.join(projectRoot, "pom.xml");
14263
14296
  if (existsSync2(pomPath)) {
14264
14297
  try {
14265
14298
  const roots = parseMavenSourceRoots(await readFile21(pomPath, "utf8"));
@@ -14269,7 +14302,7 @@ async function discoverJavaSourceRoots(projectRoot) {
14269
14302
  } catch {}
14270
14303
  }
14271
14304
  for (const gradleName of ["build.gradle", "build.gradle.kts"]) {
14272
- const gradlePath = path41.join(projectRoot, gradleName);
14305
+ const gradlePath = path42.join(projectRoot, gradleName);
14273
14306
  if (existsSync2(gradlePath)) {
14274
14307
  try {
14275
14308
  const roots = parseGradleSourceRoots(await readFile21(gradlePath, "utf8"));
@@ -14291,12 +14324,12 @@ function createJavaResolver(sourceRoots) {
14291
14324
  return [];
14292
14325
  }
14293
14326
  const relative = specifier.split(".").join("/");
14294
- return sourceRoots.map((root) => normalizePath2(path41.posix.join(root, relative)));
14327
+ return sourceRoots.map((root) => normalizePath2(path42.posix.join(root, relative)));
14295
14328
  }
14296
14329
  };
14297
14330
  }
14298
14331
  function loadPythonResolver(projectRoot) {
14299
- const hasSrc = existsSync2(path41.join(projectRoot, "src"));
14332
+ const hasSrc = existsSync2(path42.join(projectRoot, "src"));
14300
14333
  return createPythonResolver(hasSrc);
14301
14334
  }
14302
14335
  function createPythonResolver(hasSrc) {
@@ -14309,16 +14342,16 @@ function createPythonResolver(hasSrc) {
14309
14342
  if (specifier.startsWith(".")) {
14310
14343
  const dots = /^\.+/.exec(specifier)?.[0].length ?? 0;
14311
14344
  const rest = specifier.slice(dots);
14312
- let baseDir = path41.posix.dirname(fromFile);
14345
+ let baseDir = path42.posix.dirname(fromFile);
14313
14346
  for (let level = 1;level < dots; level += 1) {
14314
- baseDir = path41.posix.dirname(baseDir);
14347
+ baseDir = path42.posix.dirname(baseDir);
14315
14348
  }
14316
14349
  const suffix = rest ? rest.split(".").join("/") : "";
14317
- const base = suffix ? path41.posix.join(baseDir, suffix) : baseDir;
14350
+ const base = suffix ? path42.posix.join(baseDir, suffix) : baseDir;
14318
14351
  return [normalizePath2(base)];
14319
14352
  }
14320
14353
  const relative = specifier.split(".").join("/");
14321
- return roots.map((root) => normalizePath2(root ? path41.posix.join(root, relative) : relative));
14354
+ return roots.map((root) => normalizePath2(root ? path42.posix.join(root, relative) : relative));
14322
14355
  }
14323
14356
  };
14324
14357
  }
@@ -14327,8 +14360,8 @@ function parseMavenSourceRoots(pomXml) {
14327
14360
  for (const match of pomXml.matchAll(/<module>\s*([^<]+?)\s*<\/module>/g)) {
14328
14361
  const moduleDir = match[1]?.trim();
14329
14362
  if (moduleDir && !moduleDir.includes("${")) {
14330
- roots.add(normalizePath2(path41.posix.join(moduleDir, "src/main/java")));
14331
- roots.add(normalizePath2(path41.posix.join(moduleDir, "src/test/java")));
14363
+ roots.add(normalizePath2(path42.posix.join(moduleDir, "src/main/java")));
14364
+ roots.add(normalizePath2(path42.posix.join(moduleDir, "src/test/java")));
14332
14365
  }
14333
14366
  }
14334
14367
  for (const tag of ["sourceDirectory", "testSourceDirectory"]) {
@@ -14360,7 +14393,7 @@ function parseGradleSourceRoots(buildGradle) {
14360
14393
  }
14361
14394
  async function loadTsconfigResolver(projectRoot) {
14362
14395
  const empty = createTsconfigResolver(null, []);
14363
- const tsconfigPath = path41.join(projectRoot, "tsconfig.json");
14396
+ const tsconfigPath = path42.join(projectRoot, "tsconfig.json");
14364
14397
  if (!existsSync2(tsconfigPath)) {
14365
14398
  return empty;
14366
14399
  }
@@ -14368,7 +14401,7 @@ async function loadTsconfigResolver(projectRoot) {
14368
14401
  const raw = await readFile21(tsconfigPath, "utf8");
14369
14402
  const parsed = JSON.parse(stripJsonComments(raw));
14370
14403
  const options = parsed.compilerOptions ?? {};
14371
- const baseUrl = typeof options.baseUrl === "string" ? normalizePath2(path41.posix.normalize(options.baseUrl)).replace(/^\.\//, "") : null;
14404
+ const baseUrl = typeof options.baseUrl === "string" ? normalizePath2(path42.posix.normalize(options.baseUrl)).replace(/^\.\//, "") : null;
14372
14405
  const paths = isRecord2(options.paths) ? Object.entries(options.paths).filter((entry) => Array.isArray(entry[1])).map(([pattern, targets]) => ({
14373
14406
  pattern,
14374
14407
  targets: targets.filter((target) => typeof target === "string")
@@ -14397,7 +14430,7 @@ function createTsconfigResolver(baseUrl, mappings) {
14397
14430
  }
14398
14431
  }
14399
14432
  if (baseUrl !== null) {
14400
- candidates.push(normalizePath2(path41.posix.join(baseUrl, normalizedSpecifier)));
14433
+ candidates.push(normalizePath2(path42.posix.join(baseUrl, normalizedSpecifier)));
14401
14434
  }
14402
14435
  return [...new Set(candidates.map((candidate) => candidate.replace(/^\.\//, "")))];
14403
14436
  }
@@ -14417,7 +14450,7 @@ function matchPathPattern(pattern, specifier) {
14417
14450
  }
14418
14451
  function applyPathTarget(baseUrl, target, wildcard) {
14419
14452
  const replaced = target.includes("*") ? target.replace("*", wildcard) : target;
14420
- return normalizePath2(path41.posix.normalize(path41.posix.join(baseUrl ?? "", replaced)));
14453
+ return normalizePath2(path42.posix.normalize(path42.posix.join(baseUrl ?? "", replaced)));
14421
14454
  }
14422
14455
  function stripJsonComments(source) {
14423
14456
  let out = "";
@@ -14470,21 +14503,21 @@ function isRecord2(value) {
14470
14503
  return typeof value === "object" && value !== null && !Array.isArray(value);
14471
14504
  }
14472
14505
  async function writeGraph(projectRoot, graph) {
14473
- const storageDir = path41.join(projectRoot, ".metaproject", "data", "gdgraph", "storage");
14474
- const artifactsDir = path41.join(projectRoot, ".metaproject", "data", "gdgraph", "artifacts");
14506
+ const storageDir = path42.join(projectRoot, ".metaproject", "data", "gdgraph", "storage");
14507
+ const artifactsDir = path42.join(projectRoot, ".metaproject", "data", "gdgraph", "artifacts");
14475
14508
  await mkdir16(storageDir, { recursive: true });
14476
14509
  await mkdir16(artifactsDir, { recursive: true });
14477
- await writeFile12(path41.join(storageDir, "nodes.jsonl"), graph.nodes.map((node) => JSON.stringify(node)).join(`
14510
+ await writeFile12(path42.join(storageDir, "nodes.jsonl"), graph.nodes.map((node) => JSON.stringify(node)).join(`
14478
14511
  `) + `
14479
14512
  `, "utf8");
14480
- await writeFile12(path41.join(storageDir, "edges.jsonl"), graph.edges.map((edge) => JSON.stringify(edge)).join(`
14513
+ await writeFile12(path42.join(storageDir, "edges.jsonl"), graph.edges.map((edge) => JSON.stringify(edge)).join(`
14481
14514
  `) + `
14482
14515
  `, "utf8");
14483
- await writeFile12(path41.join(artifactsDir, "module-map.json"), JSON.stringify(buildModuleMap(graph), null, 2) + `
14516
+ await writeFile12(path42.join(artifactsDir, "module-map.json"), JSON.stringify(buildModuleMap(graph), null, 2) + `
14484
14517
  `, "utf8");
14485
14518
  }
14486
14519
  async function writeSummary(projectRoot, graph, collection) {
14487
- const artifactsDir = path41.join(projectRoot, ".metaproject", "data", "gdgraph", "artifacts");
14520
+ const artifactsDir = path42.join(projectRoot, ".metaproject", "data", "gdgraph", "artifacts");
14488
14521
  await mkdir16(artifactsDir, { recursive: true });
14489
14522
  const unresolved = graph.edges.filter((edge) => edge.kind === "unresolved");
14490
14523
  const imports = graph.edges.filter((edge) => edge.kind === "imports");
@@ -14499,7 +14532,7 @@ async function writeSummary(projectRoot, graph, collection) {
14499
14532
  `);
14500
14533
  const skippedList = collection.skippedDirectories.length > 0 ? collection.skippedDirectories.slice(0, 30).map((dir) => `- \`${dir}\``).join(`
14501
14534
  `) : "- none";
14502
- const summaryPath = path41.join(artifactsDir, "summary.md");
14535
+ const summaryPath = path42.join(artifactsDir, "summary.md");
14503
14536
  const content = `# gdgraph Summary
14504
14537
 
14505
14538
  ## Stats
@@ -14580,7 +14613,7 @@ function groupBy(items, getKey) {
14580
14613
  }
14581
14614
  function unresolvedType(specifier) {
14582
14615
  const stripped = stripImportSuffix(specifier);
14583
- const extension = path41.posix.extname(stripped);
14616
+ const extension = path42.posix.extname(stripped);
14584
14617
  if (extension) {
14585
14618
  return extension;
14586
14619
  }
@@ -14590,13 +14623,13 @@ function unresolvedType(specifier) {
14590
14623
  return "package";
14591
14624
  }
14592
14625
  function normalizePath2(value) {
14593
- return value.split(path41.sep).join("/");
14626
+ return value.split(path42.sep).join("/");
14594
14627
  }
14595
14628
 
14596
14629
  // src/gdgraph/target.ts
14597
- import path42 from "path";
14630
+ import path43 from "path";
14598
14631
  function normalizeTarget(target) {
14599
- return target.replace(/^\.\//, "").split(path42.sep).join("/");
14632
+ return target.replace(/^\.\//, "").split(path43.sep).join("/");
14600
14633
  }
14601
14634
  function resolveGraphTarget(graph, target) {
14602
14635
  const normalized = normalizeTarget(target);
@@ -14689,15 +14722,15 @@ init_config2();
14689
14722
 
14690
14723
  // src/gdgraph/query.ts
14691
14724
  import { readFile as readFile22 } from "fs/promises";
14692
- import path43 from "path";
14725
+ import path44 from "path";
14693
14726
  async function loadGraph(projectRoot) {
14694
- const storageDir = path43.join(projectRoot, ".metaproject", "data", "gdgraph", "storage");
14695
- const nodes = await readJsonl(path43.join(storageDir, "nodes.jsonl"));
14696
- const edges = await readJsonl(path43.join(storageDir, "edges.jsonl"));
14697
- const symbols = await readJsonl(path43.join(storageDir, "symbols.jsonl"));
14698
- const calls = await readJsonl(path43.join(storageDir, "calls.jsonl"));
14699
- const wikiPages = await readJsonl(path43.join(storageDir, "wiki-pages.jsonl"));
14700
- const describes = await readJsonl(path43.join(storageDir, "describes.jsonl"));
14727
+ const storageDir = path44.join(projectRoot, ".metaproject", "data", "gdgraph", "storage");
14728
+ const nodes = await readJsonl(path44.join(storageDir, "nodes.jsonl"));
14729
+ const edges = await readJsonl(path44.join(storageDir, "edges.jsonl"));
14730
+ const symbols = await readJsonl(path44.join(storageDir, "symbols.jsonl"));
14731
+ const calls = await readJsonl(path44.join(storageDir, "calls.jsonl"));
14732
+ const wikiPages = await readJsonl(path44.join(storageDir, "wiki-pages.jsonl"));
14733
+ const describes = await readJsonl(path44.join(storageDir, "describes.jsonl"));
14701
14734
  const graph = { nodes, edges };
14702
14735
  if (symbols.length > 0) {
14703
14736
  graph.symbols = symbols;
@@ -14785,7 +14818,7 @@ function canonicalCycle(cycle) {
14785
14818
 
14786
14819
  // src/gdgraph/repomap.ts
14787
14820
  import { mkdir as mkdir17, writeFile as writeFile13 } from "fs/promises";
14788
- import path44 from "path";
14821
+ import path45 from "path";
14789
14822
 
14790
14823
  // src/gdgraph/pagerank.ts
14791
14824
  function personalizedPageRank(nodes, edges, options) {
@@ -14896,7 +14929,7 @@ function overflowContent(required, missing, budget) {
14896
14929
  `);
14897
14930
  }
14898
14931
  function repomapArtifactPath(cwd) {
14899
- return path44.join(cwd, ".metaproject", "data", "gdgraph", "artifacts", "repomap.md");
14932
+ return path45.join(cwd, ".metaproject", "data", "gdgraph", "artifacts", "repomap.md");
14900
14933
  }
14901
14934
  function buildRankEdges(graph, config) {
14902
14935
  const edges = [];
@@ -15041,7 +15074,7 @@ function computeRepomap(graph, config, options = {}) {
15041
15074
  async function writeRepomap(cwd, graph, config, options = {}) {
15042
15075
  const result = computeRepomap(graph, config, options);
15043
15076
  const artifactPath = repomapArtifactPath(cwd);
15044
- await mkdir17(path44.dirname(artifactPath), { recursive: true });
15077
+ await mkdir17(path45.dirname(artifactPath), { recursive: true });
15045
15078
  await writeFile13(artifactPath, result.content, "utf8");
15046
15079
  return { ...result, path: artifactPath };
15047
15080
  }
@@ -15093,12 +15126,12 @@ __export(exports_service6, {
15093
15126
  createCodeHealthService: () => createCodeHealthService,
15094
15127
  gateExitCode: () => gateExitCode
15095
15128
  });
15096
- import path64 from "path";
15129
+ import path65 from "path";
15097
15130
 
15098
15131
  // src/health/config.ts
15099
15132
  init_fs();
15100
15133
  init_json();
15101
- import path45 from "path";
15134
+ import path46 from "path";
15102
15135
  var DEFAULT_HEALTH_CONFIG = {
15103
15136
  schemaVersion: 2,
15104
15137
  ignore: {
@@ -15154,7 +15187,7 @@ var DEFAULT_HEALTH_CONFIG = {
15154
15187
  }
15155
15188
  };
15156
15189
  function configPath2(cwd) {
15157
- return path45.join(cwd, ".metaproject", "health.config.json");
15190
+ return path46.join(cwd, ".metaproject", "health.config.json");
15158
15191
  }
15159
15192
  var STRICTEST_GATE = {
15160
15193
  failOnPriorities: ["P0", "P1", "P2", "P3"],
@@ -15205,7 +15238,7 @@ async function loadHealthConfig(cwd) {
15205
15238
  // src/health/run.ts
15206
15239
  init_fs();
15207
15240
  import { mkdir as mkdir22, writeFile as writeFile18 } from "fs/promises";
15208
- import path63 from "path";
15241
+ import path64 from "path";
15209
15242
 
15210
15243
  // src/metrics/provenance.ts
15211
15244
  async function collectGitProvenance(cwd) {
@@ -15304,12 +15337,12 @@ function computeGate2(input) {
15304
15337
  }
15305
15338
 
15306
15339
  // src/health/scopes.ts
15307
- import path48 from "path";
15340
+ import path49 from "path";
15308
15341
 
15309
15342
  // src/health/util.ts
15310
15343
  init_fs();
15311
15344
  import { mkdir as mkdir18, readFile as readFile23, readdir as readdir10, writeFile as writeFile14 } from "fs/promises";
15312
- import path46 from "path";
15345
+ import path47 from "path";
15313
15346
  var IGNORED_DIRS = new Set([
15314
15347
  "node_modules",
15315
15348
  ".git",
@@ -15353,14 +15386,14 @@ async function toolVersion(command, cwd) {
15353
15386
  }
15354
15387
  }
15355
15388
  function dataRoot(cwd) {
15356
- return path46.join(cwd, ".metaproject", "data", "health");
15389
+ return path47.join(cwd, ".metaproject", "data", "health");
15357
15390
  }
15358
15391
  async function writeRaw(cwd, source, content, stamp) {
15359
- const dir = path46.join(dataRoot(cwd), "raw", source);
15392
+ const dir = path47.join(dataRoot(cwd), "raw", source);
15360
15393
  await mkdir18(dir, { recursive: true });
15361
- const file = path46.join(dir, `${stamp}.log`);
15394
+ const file = path47.join(dir, `${stamp}.log`);
15362
15395
  await writeFile14(file, content, "utf8");
15363
- return path46.relative(cwd, file);
15396
+ return path47.relative(cwd, file);
15364
15397
  }
15365
15398
  async function listSourceFiles(cwd, ignorePaths = []) {
15366
15399
  const { files } = await listSourceFilesWithReasons(cwd, ignorePaths);
@@ -15380,7 +15413,7 @@ async function walk2(root, dir, out, incompleteReasons) {
15380
15413
  try {
15381
15414
  entries = await readdir10(dir, { withFileTypes: true });
15382
15415
  } catch (error) {
15383
- incompleteReasons.push(`${path46.relative(root, dir) || "."}: ${error instanceof Error ? error.message : String(error)}`);
15416
+ incompleteReasons.push(`${path47.relative(root, dir) || "."}: ${error instanceof Error ? error.message : String(error)}`);
15384
15417
  return;
15385
15418
  }
15386
15419
  for (const entry of entries) {
@@ -15388,14 +15421,14 @@ async function walk2(root, dir, out, incompleteReasons) {
15388
15421
  if (entry.isDirectory() && !IGNORED_DIRS.has(entry.name)) {}
15389
15422
  continue;
15390
15423
  }
15391
- const abs = path46.join(dir, entry.name);
15424
+ const abs = path47.join(dir, entry.name);
15392
15425
  if (entry.isDirectory()) {
15393
15426
  if (IGNORED_DIRS.has(entry.name)) {
15394
15427
  continue;
15395
15428
  }
15396
15429
  await walk2(root, abs, out, incompleteReasons);
15397
- } else if (entry.isFile() && SOURCE_EXT.has(path46.extname(entry.name))) {
15398
- out.push(path46.relative(root, abs));
15430
+ } else if (entry.isFile() && SOURCE_EXT.has(path47.extname(entry.name))) {
15431
+ out.push(path47.relative(root, abs));
15399
15432
  }
15400
15433
  }
15401
15434
  }
@@ -15410,7 +15443,7 @@ function moduleOfFile(file) {
15410
15443
  return null;
15411
15444
  }
15412
15445
  function isSourceFile(file) {
15413
- return SOURCE_EXT.has(path46.extname(file));
15446
+ return SOURCE_EXT.has(path47.extname(file));
15414
15447
  }
15415
15448
  function matchesAnyPattern(file, patterns) {
15416
15449
  const normalized = file.replace(/\\/g, "/").replace(/^\.\//, "");
@@ -15510,7 +15543,7 @@ function rankHotspots(files, churn, sourceAnalysis) {
15510
15543
  // src/health/source-analysis.ts
15511
15544
  init_fs();
15512
15545
  import { readFile as readFile24 } from "fs/promises";
15513
- import path47 from "path";
15546
+ import path48 from "path";
15514
15547
 
15515
15548
  // src/health/metrics/complexity.ts
15516
15549
  var CONTROL_KEYWORDS = new Set([
@@ -15744,7 +15777,7 @@ async function analyzeSourceFiles(cwd, sourceFiles) {
15744
15777
  return new Map(entries.filter((entry) => entry !== null));
15745
15778
  }
15746
15779
  async function analyzeSourceFile(cwd, file) {
15747
- const abs = path47.join(cwd, file);
15780
+ const abs = path48.join(cwd, file);
15748
15781
  if (!await pathExists(abs)) {
15749
15782
  return null;
15750
15783
  }
@@ -15817,14 +15850,14 @@ async function computeMetrics(input) {
15817
15850
  }
15818
15851
  const components = new Map;
15819
15852
  for (const file of sourceFiles) {
15820
- const dir = path48.posix.dirname(file);
15853
+ const dir = path49.posix.dirname(file);
15821
15854
  if (dir === "." || dir === moduleOfFile(file)) {
15822
15855
  continue;
15823
15856
  }
15824
15857
  components.set(dir, [...components.get(dir) ?? [], file]);
15825
15858
  }
15826
15859
  for (const [name, files] of [...components.entries()].sort()) {
15827
- const compFindings = findings.filter((f) => f.file && path48.posix.dirname(f.file) === name);
15860
+ const compFindings = findings.filter((f) => f.file && path49.posix.dirname(f.file) === name);
15828
15861
  scopes.push(build("component", `component:${name}`, name, files, compFindings, averageCoverage(files, coverage)));
15829
15862
  }
15830
15863
  const findingFiles = findings.map((f) => f.file).filter((f) => Boolean(f));
@@ -15869,9 +15902,9 @@ function tally2(values) {
15869
15902
  // src/health/baseline.ts
15870
15903
  init_fs();
15871
15904
  import { mkdir as mkdir19, readFile as readFile25, writeFile as writeFile15 } from "fs/promises";
15872
- import path49 from "path";
15905
+ import path50 from "path";
15873
15906
  function baselinePath(cwd) {
15874
- return path49.join(cwd, ".metaproject", "health", "baselines", "scores.json");
15907
+ return path50.join(cwd, ".metaproject", "health", "baselines", "scores.json");
15875
15908
  }
15876
15909
  async function loadBaseline(cwd) {
15877
15910
  const file = baselinePath(cwd);
@@ -15903,7 +15936,7 @@ async function writeBaseline(cwd, metrics, generatedAt, selector) {
15903
15936
  scopes[key] = value;
15904
15937
  }
15905
15938
  const file = baselinePath(cwd);
15906
- await mkdir19(path49.dirname(file), { recursive: true });
15939
+ await mkdir19(path50.dirname(file), { recursive: true });
15907
15940
  await writeFile15(file, `${JSON.stringify({ generatedAt, scopes }, null, 2)}
15908
15941
  `, "utf8");
15909
15942
  return updated;
@@ -15957,10 +15990,10 @@ async function getChurn(cwd, windowDays) {
15957
15990
 
15958
15991
  // src/health/metrics/wiki-freshness.ts
15959
15992
  import { readFile as readFile26, stat as stat8 } from "fs/promises";
15960
- import path50 from "path";
15993
+ import path51 from "path";
15961
15994
  var DEFAULT_STALE_EVIDENCE_DAYS = 7;
15962
15995
  function freshnessReportPath(cwd) {
15963
- return path50.join(cwd, ".metaproject", "data", "wiki", "freshness", "latest.json");
15996
+ return path51.join(cwd, ".metaproject", "data", "wiki", "freshness", "latest.json");
15964
15997
  }
15965
15998
  async function readWikiFreshnessMetric(cwd, options = {}) {
15966
15999
  const file = freshnessReportPath(cwd);
@@ -15981,7 +16014,7 @@ async function readWikiFreshnessMetric(cwd, options = {}) {
15981
16014
  } catch {
15982
16015
  return {
15983
16016
  status: "unreadable-report",
15984
- reason: `${path50.relative(cwd, file)} is not valid JSON; re-run \`keryx wiki freshness\`.`
16017
+ reason: `${path51.relative(cwd, file)} is not valid JSON; re-run \`keryx wiki freshness\`.`
15985
16018
  };
15986
16019
  }
15987
16020
  const report = parsed;
@@ -15991,7 +16024,7 @@ async function readWikiFreshnessMetric(cwd, options = {}) {
15991
16024
  if (pagesTotal === null || pagesFresh === null) {
15992
16025
  return {
15993
16026
  status: "unreadable-report",
15994
- reason: `${path50.relative(cwd, file)} is missing its totals; re-run \`keryx wiki freshness\`.`
16027
+ reason: `${path51.relative(cwd, file)} is missing its totals; re-run \`keryx wiki freshness\`.`
15995
16028
  };
15996
16029
  }
15997
16030
  const pagesUndecidable = numberOr2(totals.pagesUndecidable) ?? 0;
@@ -16045,12 +16078,12 @@ function renderWikiFreshnessLine(metric) {
16045
16078
  }
16046
16079
 
16047
16080
  // src/health/sources/helpers.ts
16048
- import path51 from "path";
16081
+ import path52 from "path";
16049
16082
  import { existsSync as existsSync3 } from "fs";
16050
16083
  class NoImportError extends Error {
16051
16084
  }
16052
16085
  function resolveBin(cwd, name) {
16053
- const local = path51.join(cwd, "node_modules", ".bin", name);
16086
+ const local = path52.join(cwd, "node_modules", ".bin", name);
16054
16087
  if (existsSync3(local)) {
16055
16088
  return local;
16056
16089
  }
@@ -16131,13 +16164,13 @@ async function getComplexityFindings(cwd, sourceFiles, config, sourceAnalysis) {
16131
16164
 
16132
16165
  // src/health/metrics/coverage.ts
16133
16166
  import { existsSync as existsSync4 } from "fs";
16134
- import path52 from "path";
16167
+ import path53 from "path";
16135
16168
  var SUMMARY_PATHS = [
16136
16169
  "coverage/coverage-summary.json",
16137
16170
  "coverage/coverage-final.json"
16138
16171
  ];
16139
16172
  async function getCoverage(cwd) {
16140
- const summary = SUMMARY_PATHS.map((rel) => path52.join(cwd, rel)).find((abs) => existsSync4(abs));
16173
+ const summary = SUMMARY_PATHS.map((rel) => path53.join(cwd, rel)).find((abs) => existsSync4(abs));
16141
16174
  if (!summary) {
16142
16175
  return { status: "missing", total: null, byFile: new Map };
16143
16176
  }
@@ -16158,7 +16191,7 @@ async function getCoverage(cwd) {
16158
16191
  total = pct;
16159
16192
  continue;
16160
16193
  }
16161
- const relative = path52.isAbsolute(key) ? path52.relative(cwd, key) : key;
16194
+ const relative = path53.isAbsolute(key) ? path53.relative(cwd, key) : key;
16162
16195
  byFile.set(relative.replace(/\\/g, "/"), pct);
16163
16196
  }
16164
16197
  return { status: "available", total, byFile };
@@ -16291,10 +16324,10 @@ function renderWikiFreshness(metric) {
16291
16324
  // src/health/skills.ts
16292
16325
  init_fs();
16293
16326
  import { readFile as readFile27 } from "fs/promises";
16294
- import path53 from "path";
16327
+ import path54 from "path";
16295
16328
  var EMPTY = { skills: [], skillForFile: () => null };
16296
16329
  async function loadSkillOwnership(cwd) {
16297
- const manifestPath = path53.join(cwd, ".metaproject", "metaproject.json");
16330
+ const manifestPath = path54.join(cwd, ".metaproject", "metaproject.json");
16298
16331
  if (!await pathExists(manifestPath)) {
16299
16332
  return EMPTY;
16300
16333
  }
@@ -16332,7 +16365,7 @@ function normalize(value) {
16332
16365
 
16333
16366
  // src/health/sources/eslint.ts
16334
16367
  import { existsSync as existsSync5 } from "fs";
16335
- import path54 from "path";
16368
+ import path55 from "path";
16336
16369
  var CONFIG_FILES = [
16337
16370
  ".eslintrc",
16338
16371
  ".eslintrc.js",
@@ -16346,7 +16379,7 @@ var CONFIG_FILES = [
16346
16379
  "eslint.config.ts"
16347
16380
  ];
16348
16381
  function hasConfig(cwd) {
16349
- return CONFIG_FILES.some((file) => existsSync5(path54.join(cwd, file)));
16382
+ return CONFIG_FILES.some((file) => existsSync5(path55.join(cwd, file)));
16350
16383
  }
16351
16384
  var eslintAdapter = {
16352
16385
  id: "eslint",
@@ -16371,7 +16404,7 @@ var eslintAdapter = {
16371
16404
  };
16372
16405
  },
16373
16406
  async import(ctx) {
16374
- const report = path54.join(ctx.cwd, "eslint-report.json");
16407
+ const report = path55.join(ctx.cwd, "eslint-report.json");
16375
16408
  if (!existsSync5(report)) {
16376
16409
  throw new NoImportError("no eslint-report.json");
16377
16410
  }
@@ -16398,7 +16431,7 @@ var eslintAdapter = {
16398
16431
  }
16399
16432
  const findings = [];
16400
16433
  for (const file of data) {
16401
- const relative = path54.isAbsolute(file.filePath) ? path54.relative(ctx.cwd, file.filePath) : file.filePath;
16434
+ const relative = path55.isAbsolute(file.filePath) ? path55.relative(ctx.cwd, file.filePath) : file.filePath;
16402
16435
  for (const message of file.messages ?? []) {
16403
16436
  const isError = message.severity === 2;
16404
16437
  findings.push(makeFinding({
@@ -16430,9 +16463,9 @@ var eslintAdapter = {
16430
16463
 
16431
16464
  // src/health/sources/typescript.ts
16432
16465
  import { existsSync as existsSync6 } from "fs";
16433
- import path55 from "path";
16466
+ import path56 from "path";
16434
16467
  function hasTsconfig(cwd) {
16435
- return existsSync6(path55.join(cwd, "tsconfig.json"));
16468
+ return existsSync6(path56.join(cwd, "tsconfig.json"));
16436
16469
  }
16437
16470
  var typescriptAdapter = {
16438
16471
  id: "typescript",
@@ -16506,7 +16539,7 @@ __export(exports_service5, {
16506
16539
  });
16507
16540
  import { existsSync as existsSync7 } from "fs";
16508
16541
  import { mkdir as mkdir21, readFile as readFile30, readdir as readdir11, writeFile as writeFile17 } from "fs/promises";
16509
- import path60 from "path";
16542
+ import path61 from "path";
16510
16543
 
16511
16544
  // src/lib/git-env.ts
16512
16545
  var GIT_DISCOVERY_OVERRIDE_VARS = [
@@ -16531,7 +16564,7 @@ function withoutGitDiscoveryOverrides(env) {
16531
16564
  init_fs();
16532
16565
  init_guard();
16533
16566
  import { readFile as readFile28 } from "fs/promises";
16534
- import path56 from "path";
16567
+ import path57 from "path";
16535
16568
 
16536
16569
  // src/metrics/record.ts
16537
16570
  var RELIABILITIES = new Set(["exact", "estimated", "unknown"]);
@@ -16546,7 +16579,7 @@ var RETRY_TYPES = new Set([
16546
16579
 
16547
16580
  // src/metrics/lifecycle.ts
16548
16581
  async function readArtifactPointer(root, expected) {
16549
- const pointerFile = path56.join(root, "latest.json");
16582
+ const pointerFile = path57.join(root, "latest.json");
16550
16583
  if (!await pathExists(pointerFile))
16551
16584
  return { status: "missing", pointer: null };
16552
16585
  let pointer;
@@ -16555,7 +16588,7 @@ async function readArtifactPointer(root, expected) {
16555
16588
  } catch {
16556
16589
  return { status: "stale", pointer: null, reason: "latest pointer is invalid JSON" };
16557
16590
  }
16558
- const recordFile = pointer.record ? path56.join(root, pointer.record) : null;
16591
+ const recordFile = pointer.record ? path57.join(root, pointer.record) : null;
16559
16592
  if (!recordFile || !isPathInside(root, recordFile) || !await pathExists(recordFile)) {
16560
16593
  return { status: "stale", pointer, reason: "pointer record is missing" };
16561
16594
  }
@@ -16571,9 +16604,9 @@ init_guard();
16571
16604
  // src/testing/capability.ts
16572
16605
  init_fs();
16573
16606
  init_json();
16574
- import path57 from "path";
16607
+ import path58 from "path";
16575
16608
  async function isTestingCapabilityEnabled(cwd, capability) {
16576
- const manifestPath = path57.join(cwd, ".metaproject", "metaproject.json");
16609
+ const manifestPath = path58.join(cwd, ".metaproject", "metaproject.json");
16577
16610
  if (!await pathExists(manifestPath)) {
16578
16611
  return false;
16579
16612
  }
@@ -16599,10 +16632,10 @@ async function isTestingCapabilityEnabled(cwd, capability) {
16599
16632
  init_fs();
16600
16633
  init_guard();
16601
16634
  import { readFile as readFile29, mkdir as mkdir20, writeFile as writeFile16 } from "fs/promises";
16602
- import path58 from "path";
16635
+ import path59 from "path";
16603
16636
  var COVERAGE_MAP_SCHEMA_VERSION = 1;
16604
16637
  function coverageMapPath(cwd, cfg) {
16605
- return path58.isAbsolute(cfg.coverageMap.artifact) ? cfg.coverageMap.artifact : path58.join(cwd, cfg.coverageMap.artifact);
16638
+ return path59.isAbsolute(cfg.coverageMap.artifact) ? cfg.coverageMap.artifact : path59.join(cwd, cfg.coverageMap.artifact);
16606
16639
  }
16607
16640
  async function loadCoverageMap(cwd, cfg) {
16608
16641
  const file = coverageMapPath(cwd, cfg);
@@ -16676,20 +16709,20 @@ function normalizePath4(file) {
16676
16709
  }
16677
16710
 
16678
16711
  // src/testing/selection.ts
16679
- import path59 from "path";
16712
+ import path60 from "path";
16680
16713
  var TEST_FILE_RE = /(^|\/)(__tests__\/.*|.*\.(test|spec)\.[cm]?[tj]sx?$|e2e\/.*\.[cm]?[tj]sx?$|tests\/.*\.[cm]?[tj]sx?$)/;
16681
16714
  function normalizePath5(file) {
16682
16715
  return file.replace(/\\/g, "/").replace(/^\.\//, "");
16683
16716
  }
16684
16717
  function relatedByNamingAndDirectory(target, testFiles) {
16685
16718
  const normalized = normalizePath5(target);
16686
- const ext = path59.extname(normalized);
16719
+ const ext = path60.extname(normalized);
16687
16720
  const withoutExt = ext ? normalized.slice(0, -ext.length) : normalized;
16688
- const base = path59.basename(withoutExt);
16689
- const dir = path59.dirname(normalized);
16721
+ const base = path60.basename(withoutExt);
16722
+ const dir = path60.dirname(normalized);
16690
16723
  return testFiles.filter((file) => {
16691
- const fileDir = path59.dirname(file);
16692
- const fileBase = path59.basename(file);
16724
+ const fileDir = path60.dirname(file);
16725
+ const fileBase = path60.basename(file);
16693
16726
  return file.startsWith(`${withoutExt}.`) || file.includes(`${withoutExt}.`) || fileDir === dir && fileBase.startsWith(`${base}.`) || fileDir.startsWith(dir) && fileBase.includes(base);
16694
16727
  }).sort();
16695
16728
  }
@@ -16804,7 +16837,7 @@ var DEFAULT_TESTING_CONFIG = {
16804
16837
  }
16805
16838
  };
16806
16839
  function testingDataRoot(cwd) {
16807
- return path60.join(cwd, ".metaproject", "data", "testing");
16840
+ return path61.join(cwd, ".metaproject", "data", "testing");
16808
16841
  }
16809
16842
  async function computeTestingContext(cwd) {
16810
16843
  const { files, incompleteReasons } = await listProjectFiles(cwd);
@@ -16979,7 +17012,7 @@ async function runTesting(input) {
16979
17012
  return runResult;
16980
17013
  }
16981
17014
  async function loadTestingContext(cwd) {
16982
- const file = path60.join(testingDataRoot(cwd), "context.json");
17015
+ const file = path61.join(testingDataRoot(cwd), "context.json");
16983
17016
  if (!await pathExists(file)) {
16984
17017
  return null;
16985
17018
  }
@@ -16990,18 +17023,18 @@ async function loadTestingContext(cwd) {
16990
17023
  }
16991
17024
  }
16992
17025
  async function loadTestingReport(cwd) {
16993
- const file = path60.join(testingDataRoot(cwd), "artifacts", "latest.json");
17026
+ const file = path61.join(testingDataRoot(cwd), "artifacts", "latest.json");
16994
17027
  if (!await pathExists(file)) {
16995
17028
  return null;
16996
17029
  }
16997
17030
  try {
16998
17031
  const latest = JSON.parse(await readFile30(file, "utf8"));
16999
17032
  if (typeof latest.record === "string") {
17000
- const pointer = await readArtifactPointer(path60.join(testingDataRoot(cwd), "artifacts"), await collectGitProvenance(cwd));
17033
+ const pointer = await readArtifactPointer(path61.join(testingDataRoot(cwd), "artifacts"), await collectGitProvenance(cwd));
17001
17034
  if (pointer.status !== "fresh")
17002
17035
  return null;
17003
- const recordFile = path60.join(testingDataRoot(cwd), "artifacts", latest.record);
17004
- if (!isPathInside(path60.join(testingDataRoot(cwd), "artifacts"), recordFile))
17036
+ const recordFile = path61.join(testingDataRoot(cwd), "artifacts", latest.record);
17037
+ if (!isPathInside(path61.join(testingDataRoot(cwd), "artifacts"), recordFile))
17005
17038
  return null;
17006
17039
  if (!await pathExists(recordFile))
17007
17040
  return null;
@@ -17049,25 +17082,25 @@ async function ensureContext(cwd) {
17049
17082
  async function writeContext(cwd, context) {
17050
17083
  const root = testingDataRoot(cwd);
17051
17084
  await mkdir21(root, { recursive: true });
17052
- await writeFile17(path60.join(root, "context.json"), `${JSON.stringify(context, null, 2)}
17085
+ await writeFile17(path61.join(root, "context.json"), `${JSON.stringify(context, null, 2)}
17053
17086
  `, "utf8");
17054
- await writeFile17(path60.join(root, "context.md"), renderContextMarkdown(context), "utf8");
17055
- await writeFile17(path60.join(root, "recommendations.md"), renderRecommendationsMarkdown(context), "utf8");
17087
+ await writeFile17(path61.join(root, "context.md"), renderContextMarkdown(context), "utf8");
17088
+ await writeFile17(path61.join(root, "recommendations.md"), renderRecommendationsMarkdown(context), "utf8");
17056
17089
  }
17057
17090
  async function writeReport(cwd, report) {
17058
17091
  const root = testingDataRoot(cwd);
17059
- const artifacts = path60.join(root, "artifacts");
17060
- const history = path60.join(root, "history");
17092
+ const artifacts = path61.join(root, "artifacts");
17093
+ const history = path61.join(root, "history");
17061
17094
  await mkdir21(artifacts, { recursive: true });
17062
17095
  await mkdir21(history, { recursive: true });
17063
17096
  const stamp = report.generatedAt.replace(/[:.]/g, "-");
17064
- const json = path60.join(artifacts, "latest.json");
17065
- const markdown = path60.join(artifacts, "latest.md");
17097
+ const json = path61.join(artifacts, "latest.json");
17098
+ const markdown = path61.join(artifacts, "latest.md");
17066
17099
  const serialized = `${JSON.stringify(report, null, 2)}
17067
17100
  `;
17068
17101
  if (report.runId) {
17069
- const runJson = path60.join(artifacts, "runs", `${report.runId}.json`);
17070
- const runMarkdown = path60.join(artifacts, "runs", `${report.runId}.md`);
17102
+ const runJson = path61.join(artifacts, "runs", `${report.runId}.json`);
17103
+ const runMarkdown = path61.join(artifacts, "runs", `${report.runId}.md`);
17071
17104
  if (await pathExists(runJson))
17072
17105
  throw new Error(`immutable testing run already exists: ${report.runId}`);
17073
17106
  await writeFileAtomic(runJson, serialized);
@@ -17078,25 +17111,25 @@ async function writeReport(cwd, report) {
17078
17111
  branch: report.provenance?.branch ?? null,
17079
17112
  worktree: report.provenance?.worktree ?? null,
17080
17113
  generated_at: report.generatedAt,
17081
- record: path60.posix.join("runs", `${report.runId}.json`)
17114
+ record: path61.posix.join("runs", `${report.runId}.json`)
17082
17115
  }, null, 2)}
17083
17116
  `);
17084
17117
  } else {
17085
17118
  await writeFile17(json, serialized, "utf8");
17086
17119
  }
17087
17120
  await writeFile17(markdown, renderReportMarkdown3(report), "utf8");
17088
- await writeFile17(path60.join(history, `${stamp}.json`), serialized, "utf8");
17121
+ await writeFile17(path61.join(history, `${stamp}.json`), serialized, "utf8");
17089
17122
  return {
17090
- markdownPath: path60.relative(cwd, markdown),
17091
- jsonPath: path60.relative(cwd, json)
17123
+ markdownPath: path61.relative(cwd, markdown),
17124
+ jsonPath: path61.relative(cwd, json)
17092
17125
  };
17093
17126
  }
17094
17127
  async function writeRawLog(cwd, raw) {
17095
- const logs = path60.join(testingDataRoot(cwd), "logs");
17128
+ const logs = path61.join(testingDataRoot(cwd), "logs");
17096
17129
  await mkdir21(logs, { recursive: true });
17097
- const latest = path60.join(logs, "latest.raw.log");
17130
+ const latest = path61.join(logs, "latest.raw.log");
17098
17131
  await writeFile17(latest, raw, "utf8");
17099
- return path60.relative(cwd, latest);
17132
+ return path61.relative(cwd, latest);
17100
17133
  }
17101
17134
  async function listProjectFiles(cwd) {
17102
17135
  const out = [];
@@ -17109,11 +17142,11 @@ async function walk3(root, dir, out, incompleteReasons) {
17109
17142
  try {
17110
17143
  entries = await readdir11(dir, { withFileTypes: true });
17111
17144
  } catch (error) {
17112
- incompleteReasons.push(`${normalizePath6(path60.relative(root, dir)) || "."}: ${error instanceof Error ? error.message : String(error)}`);
17145
+ incompleteReasons.push(`${normalizePath6(path61.relative(root, dir)) || "."}: ${error instanceof Error ? error.message : String(error)}`);
17113
17146
  return;
17114
17147
  }
17115
17148
  for (const entry of entries) {
17116
- const abs = path60.join(dir, entry.name);
17149
+ const abs = path61.join(dir, entry.name);
17117
17150
  if (entry.isDirectory()) {
17118
17151
  if (IGNORED_DIRS2.has(entry.name) || entry.name.startsWith(".tmp-")) {
17119
17152
  continue;
@@ -17122,12 +17155,12 @@ async function walk3(root, dir, out, incompleteReasons) {
17122
17155
  continue;
17123
17156
  }
17124
17157
  if (entry.isFile()) {
17125
- out.push(normalizePath6(path60.relative(root, abs)));
17158
+ out.push(normalizePath6(path61.relative(root, abs)));
17126
17159
  }
17127
17160
  }
17128
17161
  }
17129
17162
  async function readPackageJson(cwd) {
17130
- const file = path60.join(cwd, "package.json");
17163
+ const file = path61.join(cwd, "package.json");
17131
17164
  if (!await pathExists(file)) {
17132
17165
  return null;
17133
17166
  }
@@ -17138,7 +17171,7 @@ async function readPackageJson(cwd) {
17138
17171
  }
17139
17172
  }
17140
17173
  async function loadTestingConfig(cwd) {
17141
- const file = path60.join(cwd, ".metaproject", "testing.config.json");
17174
+ const file = path61.join(cwd, ".metaproject", "testing.config.json");
17142
17175
  if (!await pathExists(file)) {
17143
17176
  return DEFAULT_TESTING_CONFIG;
17144
17177
  }
@@ -17203,7 +17236,7 @@ function detectFrameworks(input) {
17203
17236
  async function extractConventions(cwd, files) {
17204
17237
  const conventions = new Set;
17205
17238
  for (const file of files.slice(0, 40)) {
17206
- const abs = path60.join(cwd, file);
17239
+ const abs = path61.join(cwd, file);
17207
17240
  if (!await pathExists(abs)) {
17208
17241
  continue;
17209
17242
  }
@@ -17333,7 +17366,7 @@ async function findTestsByImportedTargets(cwd, targets, testFiles) {
17333
17366
  const targetKeys = new Set(targets.map((target) => modulePathKey(normalizePath6(target))));
17334
17367
  const selected = new Set;
17335
17368
  for (const testFile of testFiles) {
17336
- const absoluteTest = path60.join(cwd, testFile);
17369
+ const absoluteTest = path61.join(cwd, testFile);
17337
17370
  if (!await pathExists(absoluteTest)) {
17338
17371
  continue;
17339
17372
  }
@@ -17367,10 +17400,10 @@ function resolveImportPath(cwd, testFile, importPath) {
17367
17400
  if (!importPath.startsWith(".")) {
17368
17401
  return null;
17369
17402
  }
17370
- const importerDir = path60.dirname(testFile);
17371
- const absoluteResolved = path60.resolve(path60.join(cwd, importerDir), importPath);
17372
- const relative = path60.relative(cwd, absoluteResolved);
17373
- if (relative.startsWith(`..${path60.sep}`) || relative === "..") {
17403
+ const importerDir = path61.dirname(testFile);
17404
+ const absoluteResolved = path61.resolve(path61.join(cwd, importerDir), importPath);
17405
+ const relative = path61.relative(cwd, absoluteResolved);
17406
+ if (relative.startsWith(`..${path61.sep}`) || relative === "..") {
17374
17407
  return null;
17375
17408
  }
17376
17409
  const relativeNormalized = normalizePath6(relative);
@@ -17422,13 +17455,13 @@ function resolveTestCommand(cwd, context, input) {
17422
17455
  }
17423
17456
  var BUN_LOCKFILES = ["bun.lock", "bun.lockb"];
17424
17457
  function detectPackageManager(cwd) {
17425
- if (resolveBunBin() && BUN_LOCKFILES.some((name) => pathExistsSync(path60.join(cwd, name)))) {
17458
+ if (resolveBunBin() && BUN_LOCKFILES.some((name) => pathExistsSync(path61.join(cwd, name)))) {
17426
17459
  return "bun";
17427
17460
  }
17428
- if (Bun.which("pnpm") && pathExistsSync(path60.join(cwd, "pnpm-lock.yaml"))) {
17461
+ if (Bun.which("pnpm") && pathExistsSync(path61.join(cwd, "pnpm-lock.yaml"))) {
17429
17462
  return "pnpm";
17430
17463
  }
17431
- if (Bun.which("yarn") && pathExistsSync(path60.join(cwd, "yarn.lock"))) {
17464
+ if (Bun.which("yarn") && pathExistsSync(path61.join(cwd, "yarn.lock"))) {
17432
17465
  return "yarn";
17433
17466
  }
17434
17467
  return "npm";
@@ -17768,7 +17801,7 @@ async function compatibleReportForHealth(ctx) {
17768
17801
 
17769
17802
  // src/health/sources/dependency-audit.ts
17770
17803
  import { existsSync as existsSync8 } from "fs";
17771
- import path61 from "path";
17804
+ import path62 from "path";
17772
17805
  function auditSeverityToPriority(severity) {
17773
17806
  if (severity === "critical" || severity === "high")
17774
17807
  return "P0";
@@ -17887,7 +17920,7 @@ var LOCKFILE_COMMANDS = [
17887
17920
  ];
17888
17921
  function auditCommand(cwd) {
17889
17922
  for (const entry of LOCKFILE_COMMANDS) {
17890
- if (!entry.lockfiles.some((name) => existsSync8(path61.join(cwd, name))))
17923
+ if (!entry.lockfiles.some((name) => existsSync8(path62.join(cwd, name))))
17891
17924
  continue;
17892
17925
  const bin = resolveBin(cwd, entry.bin);
17893
17926
  if (bin)
@@ -17946,13 +17979,13 @@ var dependencyAuditAdapter = {
17946
17979
 
17947
17980
  // src/health/sources/sonarqube.ts
17948
17981
  import { existsSync as existsSync9 } from "fs";
17949
- import path62 from "path";
17982
+ import path63 from "path";
17950
17983
  var REPORT_FILES = ["sonar-issues.json", ".metaproject/data/health/sonar-issues.json"];
17951
17984
  function reportPath(cwd) {
17952
17985
  const fromEnv = process.env.SONAR_ISSUES_FILE;
17953
17986
  const candidates = fromEnv ? [fromEnv, ...REPORT_FILES] : REPORT_FILES;
17954
17987
  for (const rel of candidates) {
17955
- const abs = path62.isAbsolute(rel) ? rel : path62.join(cwd, rel);
17988
+ const abs = path63.isAbsolute(rel) ? rel : path63.join(cwd, rel);
17956
17989
  if (existsSync9(abs)) {
17957
17990
  return abs;
17958
17991
  }
@@ -18036,7 +18069,7 @@ var sonarqubeAdapter = {
18036
18069
  function relativizeComponent(component, cwd) {
18037
18070
  const colon = component.indexOf(":");
18038
18071
  const value = colon >= 0 ? component.slice(colon + 1) : component;
18039
- return path62.isAbsolute(value) ? path62.relative(cwd, value) : value;
18072
+ return path63.isAbsolute(value) ? path63.relative(cwd, value) : value;
18040
18073
  }
18041
18074
 
18042
18075
  // src/health/sources/index.ts
@@ -18366,19 +18399,19 @@ function filteredInfo(source, cfg) {
18366
18399
  };
18367
18400
  }
18368
18401
  async function writeOutputs(cwd, report, config, stamp) {
18369
- const artifacts = path63.join(dataRoot(cwd), "artifacts");
18370
- const history = path63.join(dataRoot(cwd), "history");
18402
+ const artifacts = path64.join(dataRoot(cwd), "artifacts");
18403
+ const history = path64.join(dataRoot(cwd), "history");
18371
18404
  await mkdir22(artifacts, { recursive: true });
18372
18405
  await mkdir22(history, { recursive: true });
18373
- const markdown = path63.join(artifacts, "latest.md");
18374
- const json = path63.join(artifacts, "latest.json");
18375
- const historyJson = path63.join(history, `${stamp}.json`);
18406
+ const markdown = path64.join(artifacts, "latest.md");
18407
+ const json = path64.join(artifacts, "latest.json");
18408
+ const historyJson = path64.join(history, `${stamp}.json`);
18376
18409
  const serialized = `${JSON.stringify(report, null, 2)}
18377
18410
  `;
18378
18411
  await writeFile18(markdown, renderReportMarkdown2(report, config), "utf8");
18379
18412
  if (report.runId) {
18380
- const runJson = path63.join(artifacts, "runs", `${report.runId}.json`);
18381
- const runMarkdown = path63.join(artifacts, "runs", `${report.runId}.md`);
18413
+ const runJson = path64.join(artifacts, "runs", `${report.runId}.json`);
18414
+ const runMarkdown = path64.join(artifacts, "runs", `${report.runId}.md`);
18382
18415
  if (await pathExists(runJson))
18383
18416
  throw new Error(`immutable health run already exists: ${report.runId}`);
18384
18417
  await writeFileAtomic(runJson, serialized);
@@ -18389,7 +18422,7 @@ async function writeOutputs(cwd, report, config, stamp) {
18389
18422
  branch: report.provenance?.branch ?? null,
18390
18423
  worktree: report.provenance?.worktree ?? null,
18391
18424
  generated_at: report.generatedAt,
18392
- record: path63.posix.join("runs", `${report.runId}.json`)
18425
+ record: path64.posix.join("runs", `${report.runId}.json`)
18393
18426
  }, null, 2)}
18394
18427
  `);
18395
18428
  } else {
@@ -18397,8 +18430,8 @@ async function writeOutputs(cwd, report, config, stamp) {
18397
18430
  }
18398
18431
  await writeFile18(historyJson, serialized, "utf8");
18399
18432
  return {
18400
- markdownPath: path63.relative(cwd, markdown),
18401
- jsonPath: path63.relative(cwd, json)
18433
+ markdownPath: path64.relative(cwd, markdown),
18434
+ jsonPath: path64.relative(cwd, json)
18402
18435
  };
18403
18436
  }
18404
18437
  async function resolveChanged(cwd, selector) {
@@ -18451,7 +18484,7 @@ function hasGateShape(value) {
18451
18484
  return Array.isArray(report.metrics) && Array.isArray(report.sources) && Array.isArray(report.findings);
18452
18485
  }
18453
18486
  async function readLatest(cwd) {
18454
- const file = path64.join(dataRoot(cwd), "artifacts", "latest.json");
18487
+ const file = path65.join(dataRoot(cwd), "artifacts", "latest.json");
18455
18488
  if (!await pathExists(file)) {
18456
18489
  return null;
18457
18490
  }
@@ -18462,11 +18495,11 @@ async function readLatest(cwd) {
18462
18495
  const latest = read.value;
18463
18496
  const record = latest.record;
18464
18497
  if (typeof record === "string") {
18465
- const pointer = await readArtifactPointer(path64.join(dataRoot(cwd), "artifacts"), await collectGitProvenance(cwd));
18498
+ const pointer = await readArtifactPointer(path65.join(dataRoot(cwd), "artifacts"), await collectGitProvenance(cwd));
18466
18499
  if (pointer.status !== "fresh")
18467
18500
  return null;
18468
- const recordFile = path64.join(dataRoot(cwd), "artifacts", record);
18469
- if (!isPathInside(path64.join(dataRoot(cwd), "artifacts"), recordFile))
18501
+ const recordFile = path65.join(dataRoot(cwd), "artifacts", record);
18502
+ if (!isPathInside(path65.join(dataRoot(cwd), "artifacts"), recordFile))
18470
18503
  return null;
18471
18504
  if (!await pathExists(recordFile))
18472
18505
  return null;
@@ -18539,7 +18572,7 @@ function createCodeHealthService() {
18539
18572
  return {
18540
18573
  run: (input) => runHealth(input),
18541
18574
  async status(input) {
18542
- const enabled = await pathExists(path64.join(input.cwd, ".metaproject", "health.config.json"));
18575
+ const enabled = await pathExists(path65.join(input.cwd, ".metaproject", "health.config.json"));
18543
18576
  const latest = await readLatest(input.cwd);
18544
18577
  const project = latest?.metrics.find((m) => m.key === "project") ?? null;
18545
18578
  const decliningScopes = latest ? latest.metrics.filter((m) => m.regression_score > 0).length : 0;
@@ -18607,7 +18640,7 @@ __export(exports_service7, {
18607
18640
  createJobService: () => createJobService
18608
18641
  });
18609
18642
  import { copyFile, mkdir as mkdir24 } from "fs/promises";
18610
- import path67 from "path";
18643
+ import path68 from "path";
18611
18644
 
18612
18645
  // src/job/types.ts
18613
18646
  var JOB_INTENTS = ["implement", "analyze", "review", "custom"];
@@ -18745,12 +18778,12 @@ function defaultPlan(intent) {
18745
18778
 
18746
18779
  // src/job/store.ts
18747
18780
  import { appendFile as appendFile4, mkdir as mkdir23, readFile as readFile32, readdir as readdir12 } from "fs/promises";
18748
- import path66 from "path";
18781
+ import path67 from "path";
18749
18782
 
18750
18783
  // src/gdskills/contracts.ts
18751
18784
  import { readFile as readFile31 } from "fs/promises";
18752
18785
  import { existsSync as existsSync10 } from "fs";
18753
- import path65 from "path";
18786
+ import path66 from "path";
18754
18787
  import { fileURLToPath } from "url";
18755
18788
  var CONTRACTS = [
18756
18789
  {
@@ -18873,10 +18906,10 @@ async function loadSchema(name) {
18873
18906
  return JSON.parse(raw);
18874
18907
  }
18875
18908
  function contractPath(contract) {
18876
- const here = path65.dirname(fileURLToPath(import.meta.url));
18909
+ const here = path66.dirname(fileURLToPath(import.meta.url));
18877
18910
  if (contract.sourcePath) {
18878
- for (const root of [path65.join(here, "..", ".."), path65.join(here, ".."), here]) {
18879
- const candidate = path65.resolve(root, contract.sourcePath);
18911
+ for (const root of [path66.join(here, "..", ".."), path66.join(here, ".."), here]) {
18912
+ const candidate = path66.resolve(root, contract.sourcePath);
18880
18913
  if (existsSync10(candidate)) {
18881
18914
  return candidate;
18882
18915
  }
@@ -18886,7 +18919,7 @@ function contractPath(contract) {
18886
18919
  if (existsSync10(directPath)) {
18887
18920
  return directPath;
18888
18921
  }
18889
- const packagedSourcePath = path65.join(here, "..", "src", "gdskills", "contracts", contract.fileName);
18922
+ const packagedSourcePath = path66.join(here, "..", "src", "gdskills", "contracts", contract.fileName);
18890
18923
  if (existsSync10(packagedSourcePath)) {
18891
18924
  return packagedSourcePath;
18892
18925
  }
@@ -18900,13 +18933,13 @@ var SCHEMA_ROOTS = [
18900
18933
  // src/job/store.ts
18901
18934
  init_fs();
18902
18935
  function jobsRoot(cwd) {
18903
- return path66.join(cwd, ".metaproject", "jobs");
18936
+ return path67.join(cwd, ".metaproject", "jobs");
18904
18937
  }
18905
18938
  function jobDir(cwd, name) {
18906
- return path66.join(jobsRoot(cwd), name);
18939
+ return path67.join(jobsRoot(cwd), name);
18907
18940
  }
18908
18941
  function jobStatePath(cwd, name) {
18909
- return path66.join(jobDir(cwd, name), "state.json");
18942
+ return path67.join(jobDir(cwd, name), "state.json");
18910
18943
  }
18911
18944
  var JOB_NAME_PATTERN = /^[a-z0-9-]+$/;
18912
18945
  function assertJobName(name) {
@@ -18943,12 +18976,12 @@ async function writeJob(cwd, name, state) {
18943
18976
  `));
18944
18977
  }
18945
18978
  const file = jobStatePath(cwd, name);
18946
- await mkdir23(path66.dirname(file), { recursive: true });
18979
+ await mkdir23(path67.dirname(file), { recursive: true });
18947
18980
  await writeFileAtomic(file, `${JSON.stringify(state, null, 2)}
18948
18981
  `);
18949
18982
  }
18950
18983
  async function appendJournal2(cwd, name, at, line) {
18951
- await appendFile4(path66.join(jobDir(cwd, name), "journal.md"), `- ${at} - ${line}
18984
+ await appendFile4(path67.join(jobDir(cwd, name), "journal.md"), `- ${at} - ${line}
18952
18985
  `, "utf8");
18953
18986
  }
18954
18987
  function renderJournal2(name, at) {
@@ -18969,7 +19002,7 @@ function assertDocumentType(raw) {
18969
19002
  return raw;
18970
19003
  }
18971
19004
  function documentFileName(type, sourcePath) {
18972
- const extension = path66.extname(sourcePath) || ".md";
19005
+ const extension = path67.extname(sourcePath) || ".md";
18973
19006
  return `${type}${extension}`;
18974
19007
  }
18975
19008
 
@@ -18977,7 +19010,7 @@ function documentFileName(type, sourcePath) {
18977
19010
  function createJobService(deps) {
18978
19011
  const now = () => deps.now().toISOString();
18979
19012
  function lockPath(cwd, name) {
18980
- return path67.join(jobsRoot(cwd), `.job-lock-${name}`);
19013
+ return path68.join(jobsRoot(cwd), `.job-lock-${name}`);
18981
19014
  }
18982
19015
  async function mutate(cwd, name, run) {
18983
19016
  assertJobName(name);
@@ -19026,20 +19059,20 @@ function createJobService(deps) {
19026
19059
  },
19027
19060
  plan: { steps: defaultPlan(intent) },
19028
19061
  documentation: {
19029
- job_path: path67.join(".metaproject", "jobs", name),
19062
+ job_path: path68.join(".metaproject", "jobs", name),
19030
19063
  documents_created: []
19031
19064
  },
19032
19065
  metrics: { steps: [] },
19033
- jobs_root: path67.join(".metaproject", "jobs"),
19066
+ jobs_root: path68.join(".metaproject", "jobs"),
19034
19067
  updated_at: createdAt
19035
19068
  };
19036
19069
  const first = firstOpenStep(state.plan.steps);
19037
19070
  if (first) {
19038
19071
  state.plan.current_step = first.id;
19039
19072
  }
19040
- await writeFileAtomic(path67.join(absolute, "journal.md"), renderJournal2(name, createdAt));
19073
+ await writeFileAtomic(path68.join(absolute, "journal.md"), renderJournal2(name, createdAt));
19041
19074
  await writeJob(input.cwd, name, state);
19042
- return { state, dir: path67.relative(input.cwd, absolute) };
19075
+ return { state, dir: path68.relative(input.cwd, absolute) };
19043
19076
  },
19044
19077
  async status({ cwd, name }) {
19045
19078
  assertJobName(name);
@@ -19051,7 +19084,7 @@ function createJobService(deps) {
19051
19084
  }
19052
19085
  return {
19053
19086
  state,
19054
- dir: path67.join(".metaproject", "jobs", name),
19087
+ dir: path68.join(".metaproject", "jobs", name),
19055
19088
  stepsDone: state.plan.steps.filter((step) => isTerminalStep(step.status)).length,
19056
19089
  stepsTotal: state.plan.steps.length,
19057
19090
  nextStep: firstOpenStep(state.plan.steps),
@@ -19108,23 +19141,23 @@ function createJobService(deps) {
19108
19141
  if (!input.file) {
19109
19142
  throw new Error("Missing --file. Usage: keryx job document <name> --type <type> --file <path>");
19110
19143
  }
19111
- const source = path67.isAbsolute(input.file) ? input.file : path67.join(input.cwd, input.file);
19144
+ const source = path68.isAbsolute(input.file) ? input.file : path68.join(input.cwd, input.file);
19112
19145
  if (!await pathExists(source)) {
19113
19146
  throw new Error(`--file not found: ${input.file}. Write the document first, then record it.`);
19114
19147
  }
19115
19148
  let recorded;
19116
19149
  await mutate(input.cwd, input.name, async (state) => {
19117
19150
  const fileName = documentFileName(type, source);
19118
- const target = path67.join(jobDir(input.cwd, state.job_name), fileName);
19151
+ const target = path68.join(jobDir(input.cwd, state.job_name), fileName);
19119
19152
  await copyFile(source, target);
19120
19153
  state.documentation ??= {};
19121
- state.documentation.job_path ??= path67.join(".metaproject", "jobs", state.job_name);
19154
+ state.documentation.job_path ??= path68.join(".metaproject", "jobs", state.job_name);
19122
19155
  const created = state.documentation.documents_created ?? [];
19123
19156
  state.documentation.documents_created = created.includes(fileName) ? created : [...created, fileName];
19124
19157
  recorded = {
19125
19158
  state,
19126
19159
  document: fileName,
19127
- path: path67.join(".metaproject", "jobs", state.job_name, fileName)
19160
+ path: path68.join(".metaproject", "jobs", state.job_name, fileName)
19128
19161
  };
19129
19162
  return { state, event: "document", detail: `${type} -> ${fileName}` };
19130
19163
  });
@@ -19159,7 +19192,7 @@ function createJobService(deps) {
19159
19192
  name: state.job_name,
19160
19193
  phase: state.phase,
19161
19194
  intent: state.intent,
19162
- dir: path67.join(".metaproject", "jobs", name),
19195
+ dir: path68.join(".metaproject", "jobs", name),
19163
19196
  stepsDone: state.plan.steps.filter((step) => isTerminalStep(step.status)).length,
19164
19197
  stepsTotal: state.plan.steps.length,
19165
19198
  nextStep: firstOpenStep(state.plan.steps)?.id ?? null
@@ -19180,24 +19213,24 @@ __export(exports_service8, {
19180
19213
  });
19181
19214
  import { createHash as createHash10 } from "crypto";
19182
19215
  import { mkdir as mkdir26, readFile as readFile37, writeFile as writeFile20 } from "fs/promises";
19183
- import path73 from "path";
19216
+ import path74 from "path";
19184
19217
 
19185
19218
  // src/memory/check.ts
19186
19219
  init_fs();
19187
19220
  init_store();
19188
- import path69 from "path";
19221
+ import path70 from "path";
19189
19222
 
19190
19223
  // src/memory/cross-layer.ts
19191
19224
  init_collect();
19192
19225
  init_section_index();
19193
19226
  init_section_tombstone();
19194
19227
  import { readFile as readFile33 } from "fs/promises";
19195
- import path68 from "path";
19228
+ import path69 from "path";
19196
19229
  var MARKDOWN_LINK_RE = /\[[^\]]*\]\(([^)\s]+)\)/g;
19197
19230
  var SECTION_REF_RE = /keryx:page\/[a-z0-9][a-z0-9._-]*(?:#[a-z0-9][a-z0-9._-]*)?/gi;
19198
19231
  function extractWikiReferences(entryRelativePath, entryAbsolutePath, content, wikiRoot) {
19199
19232
  const references = [];
19200
- const entryDir = path68.dirname(entryAbsolutePath);
19233
+ const entryDir = path69.dirname(entryAbsolutePath);
19201
19234
  const lines = content.split(`
19202
19235
  `);
19203
19236
  for (let index = 0;index < lines.length; index += 1) {
@@ -19212,16 +19245,16 @@ function extractWikiReferences(entryRelativePath, entryAbsolutePath, content, wi
19212
19245
  if (withoutAnchor.length === 0) {
19213
19246
  continue;
19214
19247
  }
19215
- const absolute = path68.resolve(entryDir, withoutAnchor);
19216
- const relativeToWiki = path68.relative(wikiRoot, absolute);
19217
- if (relativeToWiki.startsWith("..") || path68.isAbsolute(relativeToWiki)) {
19248
+ const absolute = path69.resolve(entryDir, withoutAnchor);
19249
+ const relativeToWiki = path69.relative(wikiRoot, absolute);
19250
+ if (relativeToWiki.startsWith("..") || path69.isAbsolute(relativeToWiki)) {
19218
19251
  continue;
19219
19252
  }
19220
19253
  references.push({
19221
19254
  entry: entryRelativePath,
19222
19255
  kind: "page-path",
19223
19256
  raw: href,
19224
- target: relativeToWiki.split(path68.sep).join("/"),
19257
+ target: relativeToWiki.split(path69.sep).join("/"),
19225
19258
  line
19226
19259
  });
19227
19260
  }
@@ -19241,7 +19274,7 @@ function isDangling(finding) {
19241
19274
  return finding.state !== "intact";
19242
19275
  }
19243
19276
  async function loadWikiKnowledgeView(cwd) {
19244
- const wikiRoot = path68.join(cwd, ".metaproject", "wiki");
19277
+ const wikiRoot = path69.join(cwd, ".metaproject", "wiki");
19245
19278
  const pages = await collectPages(cwd);
19246
19279
  const index = buildSectionIndex(await Promise.all(pages.map(async (page) => ({
19247
19280
  page,
@@ -19466,7 +19499,7 @@ async function checkMemory(cwd, config) {
19466
19499
  }
19467
19500
  for (const file of entry.scopes.files) {
19468
19501
  const clean = file.replace(/^`|`$/g, "");
19469
- if (!await pathExists(path69.resolve(cwd, clean))) {
19502
+ if (!await pathExists(path70.resolve(cwd, clean))) {
19470
19503
  issues.push({ path: entry.relativePath, kind: "link", message: `related file not found: ${clean}` });
19471
19504
  }
19472
19505
  }
@@ -19518,19 +19551,19 @@ init_types();
19518
19551
  init_store();
19519
19552
  import { existsSync as existsSync11 } from "fs";
19520
19553
  import { readFile as readFile35 } from "fs/promises";
19521
- import path71 from "path";
19554
+ import path72 from "path";
19522
19555
 
19523
19556
  // src/memory/write.ts
19524
19557
  init_guard();
19525
19558
  init_store();
19526
19559
  init_types();
19527
19560
  import { mkdir as mkdir25, open, readFile as readFile34, rename as rename5, rm as rm4, writeFile as writeFile19 } from "fs/promises";
19528
- import path70 from "path";
19561
+ import path71 from "path";
19529
19562
  async function resolveCanonicalEntryPath(cwd, relativePath) {
19530
- const root = path70.resolve(memoryRoot(cwd));
19531
- const absolutePath = path70.resolve(root, relativePath);
19532
- const normalized = toPosix2(path70.relative(root, absolutePath));
19533
- if (!normalized || normalized.startsWith("../") || path70.isAbsolute(normalized) || !normalized.endsWith(".md")) {
19563
+ const root = path71.resolve(memoryRoot(cwd));
19564
+ const absolutePath = path71.resolve(root, relativePath);
19565
+ const normalized = toPosix2(path71.relative(root, absolutePath));
19566
+ if (!normalized || normalized.startsWith("../") || path71.isAbsolute(normalized) || !normalized.endsWith(".md")) {
19534
19567
  return null;
19535
19568
  }
19536
19569
  return { absolutePath, relativePath: normalized };
@@ -19626,9 +19659,9 @@ function validateNextEntry(relativePath, content) {
19626
19659
  return null;
19627
19660
  }
19628
19661
  async function replaceAtomically(target, content) {
19629
- const dir = path70.dirname(target);
19662
+ const dir = path71.dirname(target);
19630
19663
  await mkdir25(dir, { recursive: true });
19631
- const tmp = path70.join(dir, `.${path70.basename(target)}.keryx-tmp-${process.pid}-${Math.random().toString(16).slice(2)}`);
19664
+ const tmp = path71.join(dir, `.${path71.basename(target)}.keryx-tmp-${process.pid}-${Math.random().toString(16).slice(2)}`);
19632
19665
  try {
19633
19666
  await writeFile19(tmp, content, "utf8");
19634
19667
  const file = await open(tmp, "r");
@@ -19664,7 +19697,7 @@ function header(content, name) {
19664
19697
  return content.match(new RegExp(`^${name}:\\s*(.+)$`, "mi"))?.[1]?.trim() ?? null;
19665
19698
  }
19666
19699
  function toPosix2(value) {
19667
- return value.split(path70.sep).join("/");
19700
+ return value.split(path71.sep).join("/");
19668
19701
  }
19669
19702
  function message(cause) {
19670
19703
  return cause instanceof Error ? cause.message : String(cause);
@@ -19684,7 +19717,7 @@ var SOURCE_CONFIDENCE = {
19684
19717
  "skill-verifier": "medium"
19685
19718
  };
19686
19719
  async function ingestMemory(cwd, source, filePath, config, now) {
19687
- const absolute = path71.resolve(cwd, filePath);
19720
+ const absolute = path72.resolve(cwd, filePath);
19688
19721
  if (!await pathExists(absolute)) {
19689
19722
  throw new Error(`Ingest source not found: ${filePath}`);
19690
19723
  }
@@ -19701,8 +19734,8 @@ async function ingestMemory(cwd, source, filePath, config, now) {
19701
19734
  const securityWarnings = [];
19702
19735
  const securitySkipped = [];
19703
19736
  let skippedDuplicates = 0;
19704
- const dir = path71.join(memoryRoot(cwd), folder);
19705
- const link = path71.relative(cwd, absolute);
19737
+ const dir = path72.join(memoryRoot(cwd), folder);
19738
+ const link = path72.relative(cwd, absolute);
19706
19739
  const date = dateString(now);
19707
19740
  for (const text of candidates) {
19708
19741
  const title = toTitle(text);
@@ -19883,7 +19916,7 @@ function uniqueSlug(dir, title) {
19883
19916
  const base = slugify3(title) || "entry";
19884
19917
  let slug = base;
19885
19918
  let counter = 2;
19886
- while (existsSync11(path71.join(dir, `${slug}.md`))) {
19919
+ while (existsSync11(path72.join(dir, `${slug}.md`))) {
19887
19920
  slug = `${base}-${counter}`;
19888
19921
  counter += 1;
19889
19922
  }
@@ -19903,7 +19936,7 @@ init_store();
19903
19936
  init_fs();
19904
19937
  init_store();
19905
19938
  import { readFile as readFile36 } from "fs/promises";
19906
- import path72 from "path";
19939
+ import path73 from "path";
19907
19940
  async function supersedeEntry(input, now) {
19908
19941
  const date = input.date ?? now.toISOString().slice(0, 10);
19909
19942
  const today = now.toISOString().slice(0, 10);
@@ -19963,12 +19996,12 @@ async function supersedeEntry(input, now) {
19963
19996
  async function resolveEntryPath(cwd, raw) {
19964
19997
  const root = memoryRoot(cwd);
19965
19998
  const candidates = [
19966
- path72.resolve(cwd, raw),
19967
- path72.resolve(root, raw),
19968
- path72.isAbsolute(raw) ? raw : path72.join(cwd, raw)
19999
+ path73.resolve(cwd, raw),
20000
+ path73.resolve(root, raw),
20001
+ path73.isAbsolute(raw) ? raw : path73.join(cwd, raw)
19969
20002
  ];
19970
20003
  for (const absolute of candidates) {
19971
- const confined = await resolveCanonicalEntryPath(cwd, path72.relative(root, absolute));
20004
+ const confined = await resolveCanonicalEntryPath(cwd, path73.relative(root, absolute));
19972
20005
  if (confined && await pathExists(confined.absolutePath)) {
19973
20006
  return { absolute: confined.absolutePath, relative: confined.relativePath };
19974
20007
  }
@@ -20102,7 +20135,7 @@ Main memory content.
20102
20135
  init_embedding();
20103
20136
  init_types();
20104
20137
  function dataRoot2(cwd) {
20105
- return path73.join(cwd, ".metaproject", "data", "memory");
20138
+ return path74.join(cwd, ".metaproject", "data", "memory");
20106
20139
  }
20107
20140
  function createMemoryService() {
20108
20141
  const reportStore = createMemoryReportStore();
@@ -20117,9 +20150,9 @@ function createMemoryService() {
20117
20150
  if (!/^[a-z0-9][a-z0-9-]*$/.test(slug)) {
20118
20151
  throw new Error(`Invalid slug: ${slug}. Use lowercase letters, digits, and hyphens.`);
20119
20152
  }
20120
- const dir = path73.join(memoryRoot(input.cwd), typeConfig.folder);
20121
- const filePath = path73.join(dir, `${slug}.md`);
20122
- const relativePath = path73.relative(input.cwd, filePath);
20153
+ const dir = path74.join(memoryRoot(input.cwd), typeConfig.folder);
20154
+ const filePath = path74.join(dir, `${slug}.md`);
20155
+ const relativePath = path74.relative(input.cwd, filePath);
20123
20156
  if (await pathExists(filePath) && !input.force) {
20124
20157
  throw new Error(`Entry already exists: ${relativePath}. Use --force to overwrite.`);
20125
20158
  }
@@ -20150,9 +20183,9 @@ function createMemoryService() {
20150
20183
  async index(input) {
20151
20184
  const entries = await collectEntries(input.cwd);
20152
20185
  const generatedAt = new Date().toISOString();
20153
- const indexDir = path73.join(dataRoot2(input.cwd), "index");
20186
+ const indexDir = path74.join(dataRoot2(input.cwd), "index");
20154
20187
  await mkdir26(indexDir, { recursive: true });
20155
- const indexPath = path73.join(indexDir, "index.json");
20188
+ const indexPath = path74.join(indexDir, "index.json");
20156
20189
  await writeFile20(indexPath, `${JSON.stringify({
20157
20190
  catalogVersion: 1,
20158
20191
  sourceFingerprint: createHash10("sha256").update(JSON.stringify(entries.map((e) => ({
@@ -20173,7 +20206,7 @@ function createMemoryService() {
20173
20206
  }, null, 2)}
20174
20207
  `, "utf8");
20175
20208
  const result = {
20176
- path: path73.relative(input.cwd, indexPath),
20209
+ path: path74.relative(input.cwd, indexPath),
20177
20210
  entryCount: entries.length,
20178
20211
  generatedAt
20179
20212
  };
@@ -20186,7 +20219,7 @@ function createMemoryService() {
20186
20219
  const built = await buildEmbeddingIndex(input.cwd, entries, embedder.embed, embedder.model, new Date);
20187
20220
  result.embeddings = {
20188
20221
  built: true,
20189
- path: path73.relative(input.cwd, embeddingsDir(input.cwd)),
20222
+ path: path74.relative(input.cwd, embeddingsDir(input.cwd)),
20190
20223
  vectorCount: built.meta.entryCount,
20191
20224
  model: built.meta.model
20192
20225
  };
@@ -20371,12 +20404,12 @@ __export(exports_service9, {
20371
20404
  init_assembly();
20372
20405
  import { createHash as createHash15, randomUUID as randomUUID4 } from "crypto";
20373
20406
  import { appendFile as appendFile5, mkdir as mkdir28, open as open2, readFile as readFile40, rename as rename6, rm as rm5, stat as stat9, writeFile as writeFile21 } from "fs/promises";
20374
- import path77 from "path";
20407
+ import path78 from "path";
20375
20408
 
20376
20409
  // src/sac/index.ts
20377
20410
  import { access as access3, readFile as readFile38, realpath as realpath3 } from "fs/promises";
20378
20411
  import { createHash as createHash11 } from "crypto";
20379
- import path74 from "path";
20412
+ import path75 from "path";
20380
20413
  import { fileURLToPath as fileURLToPath2 } from "url";
20381
20414
  var idPattern = /^[a-z][a-z0-9-]{2,63}$/;
20382
20415
  var subjectPattern = /^(?:user|team|service|agent):[a-z0-9][a-z0-9._-]{0,127}$/;
@@ -20394,21 +20427,21 @@ var normativeSchemaFiles = {
20394
20427
  "review-decision": "review-decision.schema.json"
20395
20428
  };
20396
20429
  var normativeSchemas = new Map;
20397
- var NORMATIVE_SCHEMA_DIR = path74.join("docs", "requirements", "shared-agent-context", "schemas");
20430
+ var NORMATIVE_SCHEMA_DIR = path75.join("docs", "requirements", "shared-agent-context", "schemas");
20398
20431
  async function resolveSacNormativeSchemaPath(fileName, searchFrom = [fileURLToPath2(new URL(".", import.meta.url)), process.cwd()]) {
20399
20432
  const seen = new Set;
20400
20433
  for (const start of searchFrom) {
20401
- let dir = path74.resolve(start);
20434
+ let dir = path75.resolve(start);
20402
20435
  for (let i = 0;i < 10; i++) {
20403
20436
  if (seen.has(dir))
20404
20437
  break;
20405
20438
  seen.add(dir);
20406
- const candidate = path74.join(dir, NORMATIVE_SCHEMA_DIR, fileName);
20439
+ const candidate = path75.join(dir, NORMATIVE_SCHEMA_DIR, fileName);
20407
20440
  try {
20408
20441
  await access3(candidate);
20409
20442
  return candidate;
20410
20443
  } catch {}
20411
- const parent = path74.dirname(dir);
20444
+ const parent = path75.dirname(dir);
20412
20445
  if (parent === dir)
20413
20446
  break;
20414
20447
  dir = parent;
@@ -21077,12 +21110,12 @@ class SacReferenceError extends Error {
21077
21110
  code = "unsafe_workspace_reference";
21078
21111
  }
21079
21112
  async function resolveWorkspaceReference(input) {
21080
- if (!workspacePathPattern.test(input.uri) || path74.isAbsolute(input.uri) || /^[a-z][a-z0-9+.-]*:/i.test(input.uri) || input.uri.includes("\\"))
21113
+ if (!workspacePathPattern.test(input.uri) || path75.isAbsolute(input.uri) || /^[a-z][a-z0-9+.-]*:/i.test(input.uri) || input.uri.includes("\\"))
21081
21114
  throw new SacReferenceError("unsafe workspace reference");
21082
- const lexicalRoot = path74.resolve(input.workspaceRoot);
21115
+ const lexicalRoot = path75.resolve(input.workspaceRoot);
21083
21116
  const root = await realpath3(lexicalRoot);
21084
- const candidate = path74.resolve(lexicalRoot, input.uri.slice(2));
21085
- if (candidate !== lexicalRoot && !candidate.startsWith(`${lexicalRoot}${path74.sep}`))
21117
+ const candidate = path75.resolve(lexicalRoot, input.uri.slice(2));
21118
+ if (candidate !== lexicalRoot && !candidate.startsWith(`${lexicalRoot}${path75.sep}`))
21086
21119
  throw new SacReferenceError("workspace reference escapes root");
21087
21120
  let resolved;
21088
21121
  try {
@@ -21090,7 +21123,7 @@ async function resolveWorkspaceReference(input) {
21090
21123
  } catch {
21091
21124
  throw new SacReferenceError("workspace reference is not resolvable");
21092
21125
  }
21093
- if (resolved !== root && !resolved.startsWith(`${root}${path74.sep}`))
21126
+ if (resolved !== root && !resolved.startsWith(`${root}${path75.sep}`))
21094
21127
  throw new SacReferenceError("workspace reference escapes root after realpath");
21095
21128
  return candidate;
21096
21129
  }
@@ -21146,16 +21179,16 @@ async function evaluateStrictSacGuard(input) {
21146
21179
  init_fs();
21147
21180
  import { mkdir as mkdir27, readdir as readdir13, readFile as readFile39 } from "fs/promises";
21148
21181
  import { createHash as createHash12, randomUUID as randomUUID3 } from "crypto";
21149
- import path76 from "path";
21182
+ import path77 from "path";
21150
21183
 
21151
21184
  // src/sac/secure-resource-read.ts
21152
21185
  init_contained_read();
21153
21186
  init_descriptor_read();
21154
- import path75 from "path";
21187
+ import path76 from "path";
21155
21188
  function readWorkspaceFileNoFollow(workspaceRoot, absolutePath) {
21156
- const relativePath = path75.relative(workspaceRoot, absolutePath);
21157
- const components = relativePath.split(path75.sep);
21158
- if (!relativePath || path75.isAbsolute(relativePath) || components.some((component) => !component || component === "." || component === "..")) {
21189
+ const relativePath = path76.relative(workspaceRoot, absolutePath);
21190
+ const components = relativePath.split(path76.sep);
21191
+ if (!relativePath || path76.isAbsolute(relativePath) || components.some((component) => !component || component === "." || component === "..")) {
21159
21192
  throw new Error("safe source path is not workspace-relative");
21160
21193
  }
21161
21194
  return readDescriptorChain(workspaceRoot, absolutePath, {
@@ -21182,8 +21215,8 @@ class WorkspaceService {
21182
21215
  now;
21183
21216
  constructor(options) {
21184
21217
  this.options = options;
21185
- this.root = path76.resolve(options.workspaceRoot);
21186
- this.storageRoot = path76.resolve(options.storageRoot ?? path76.join(this.root, ".metaproject", "workspaces"));
21218
+ this.root = path77.resolve(options.workspaceRoot);
21219
+ this.storageRoot = path77.resolve(options.storageRoot ?? path77.join(this.root, ".metaproject", "workspaces"));
21187
21220
  this.now = options.now ?? (() => new Date);
21188
21221
  }
21189
21222
  async create(input) {
@@ -21508,13 +21541,13 @@ class WorkspaceService {
21508
21541
  return parsed;
21509
21542
  }
21510
21543
  workspaceDir(id) {
21511
- return path76.join(this.storageRoot, id);
21544
+ return path77.join(this.storageRoot, id);
21512
21545
  }
21513
21546
  manifestPath(id) {
21514
- return path76.join(this.workspaceDir(id), "workspace.json");
21547
+ return path77.join(this.workspaceDir(id), "workspace.json");
21515
21548
  }
21516
21549
  lockPath(id) {
21517
- return path76.join(this.storageRoot, `.${id}.lock`);
21550
+ return path77.join(this.storageRoot, `.${id}.lock`);
21518
21551
  }
21519
21552
  timestamp() {
21520
21553
  return this.now().toISOString();
@@ -22303,7 +22336,7 @@ function hasReportIntegrity(report) {
22303
22336
  return reportHashPattern.test(reportDigest) && sha2563(body) === reportDigest;
22304
22337
  }
22305
22338
  async function resolvePolicySelection(workspaceRoot, canonicalFallback) {
22306
- const configPath = path77.join(workspaceRoot, ...policyExperimentConfigPath);
22339
+ const configPath = path78.join(workspaceRoot, ...policyExperimentConfigPath);
22307
22340
  let configJson;
22308
22341
  try {
22309
22342
  const raw = await readFile40(configPath, "utf8").catch((error) => {
@@ -22501,9 +22534,9 @@ class FwkReadService {
22501
22534
  const recordedAt = nowIso(now);
22502
22535
  const id = `receipt-${randomUUID4().replace(/-/g, "").slice(0, 16)}`;
22503
22536
  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"}` } : {} };
22504
- const ledger = path77.join(this.options.canonical.workspaceRoot, ".metaproject", "context-operations", "access-receipts.jsonl");
22505
- const checkpointPath = path77.join(path77.dirname(ledger), "access-receipts.checkpoint.json");
22506
- await mkdir28(path77.dirname(ledger), { recursive: true, mode: 448 });
22537
+ const ledger = path78.join(this.options.canonical.workspaceRoot, ".metaproject", "context-operations", "access-receipts.jsonl");
22538
+ const checkpointPath = path78.join(path78.dirname(ledger), "access-receipts.checkpoint.json");
22539
+ await mkdir28(path78.dirname(ledger), { recursive: true, mode: 448 });
22507
22540
  return withFileLock(`${ledger}.lock`, async () => {
22508
22541
  const state = await resolveLedgerState(ledger, checkpointPath, this.options.verifyReceiptLedger ?? verifyAccessReceiptLedger);
22509
22542
  const receipt = sealAccessReceipt(base, state.headHash);
@@ -22607,7 +22640,7 @@ function normalizeFwkResult(result) {
22607
22640
  init_fs();
22608
22641
  import { createHash as createHash22, randomUUID as randomUUID7 } from "crypto";
22609
22642
  import { appendFile as appendFile6, mkdir as mkdir32, readdir as readdir15, readFile as readFile49 } from "fs/promises";
22610
- import path87 from "path";
22643
+ import path88 from "path";
22611
22644
 
22612
22645
  // src/sac/trusted-wrap-up.ts
22613
22646
  import { createHash as createHash16, randomUUID as randomUUID5 } from "crypto";
@@ -22679,7 +22712,7 @@ function bindingHash(owner, intent) {
22679
22712
  // src/sac/session-wrap-up.ts
22680
22713
  import { createHash as createHash18 } from "crypto";
22681
22714
  import { mkdir as mkdir30, writeFile as writeFile22 } from "fs/promises";
22682
- import path81 from "path";
22715
+ import path82 from "path";
22683
22716
 
22684
22717
  // src/session/store.ts
22685
22718
  import {
@@ -22690,7 +22723,7 @@ import {
22690
22723
  renameSync as renameSync2,
22691
22724
  writeFileSync as writeFileSync2
22692
22725
  } from "fs";
22693
- import path80 from "path";
22726
+ import path81 from "path";
22694
22727
 
22695
22728
  // src/lib/config-dir.ts
22696
22729
  import {
@@ -22735,7 +22768,7 @@ function readTranscriptFile(file) {
22735
22768
  // src/session/paths.ts
22736
22769
  import { existsSync as existsSync12 } from "fs";
22737
22770
  import { homedir } from "os";
22738
- import path78 from "path";
22771
+ import path79 from "path";
22739
22772
  function keryxDataDir(override) {
22740
22773
  if (override !== undefined && override.length > 0) {
22741
22774
  return override;
@@ -22747,22 +22780,22 @@ function keryxDataDir(override) {
22747
22780
  const home = homedir();
22748
22781
  if (process.platform === "win32") {
22749
22782
  const appData = process.env.APPDATA;
22750
- const base = appData !== undefined && appData.length > 0 ? appData : path78.join(home, "AppData", "Roaming");
22751
- return path78.join(base, "keryx");
22783
+ const base = appData !== undefined && appData.length > 0 ? appData : path79.join(home, "AppData", "Roaming");
22784
+ return path79.join(base, "keryx");
22752
22785
  }
22753
22786
  const xdg = process.env.XDG_DATA_HOME;
22754
- const base = xdg !== undefined && xdg.length > 0 ? xdg : path78.join(home, ".local", "share");
22755
- return path78.join(base, "keryx");
22787
+ const base = xdg !== undefined && xdg.length > 0 ? xdg : path79.join(home, ".local", "share");
22788
+ return path79.join(base, "keryx");
22756
22789
  }
22757
22790
  function resolveProjectRoot2(cwd) {
22758
- const abs = path78.resolve(cwd);
22791
+ const abs = path79.resolve(cwd);
22759
22792
  let dir = abs;
22760
22793
  for (;; ) {
22761
- const gitPath = path78.join(dir, ".git");
22794
+ const gitPath = path79.join(dir, ".git");
22762
22795
  if (existsSync12(gitPath)) {
22763
22796
  return dir;
22764
22797
  }
22765
- const parent = path78.dirname(dir);
22798
+ const parent = path79.dirname(dir);
22766
22799
  if (parent === dir) {
22767
22800
  break;
22768
22801
  }
@@ -22771,12 +22804,12 @@ function resolveProjectRoot2(cwd) {
22771
22804
  return abs;
22772
22805
  }
22773
22806
  function projectKeyFromPath(projectPath) {
22774
- const abs = path78.resolve(projectPath);
22807
+ const abs = path79.resolve(projectPath);
22775
22808
  const encoded = encodeURIComponent(abs);
22776
22809
  if (encoded.length <= 200) {
22777
22810
  return encoded;
22778
22811
  }
22779
- const base = path78.basename(abs).replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 40);
22812
+ const base = path79.basename(abs).replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 40);
22780
22813
  let h = 0;
22781
22814
  for (let i = 0;i < abs.length; i++) {
22782
22815
  h = Math.imul(31, h) + abs.charCodeAt(i) | 0;
@@ -22786,17 +22819,17 @@ function projectKeyFromPath(projectPath) {
22786
22819
  }
22787
22820
  function projectSessionsDir(projectPath, dataDir) {
22788
22821
  const key = projectKeyFromPath(resolveProjectRoot2(projectPath));
22789
- return path78.join(keryxDataDir(dataDir), "sessions", key);
22822
+ return path79.join(keryxDataDir(dataDir), "sessions", key);
22790
22823
  }
22791
22824
  function sessionDir(projectPath, sessionId, dataDir) {
22792
- return path78.join(projectSessionsDir(projectPath, dataDir), sessionId);
22825
+ return path79.join(projectSessionsDir(projectPath, dataDir), sessionId);
22793
22826
  }
22794
22827
 
22795
22828
  // src/session/slate.ts
22796
22829
  init_fs();
22797
22830
  init_assembly();
22798
22831
  import { mkdir as mkdir29, readFile as readFile41, rm as rm6 } from "fs/promises";
22799
- import path79 from "path";
22832
+ import path80 from "path";
22800
22833
  init_redact();
22801
22834
  var SLATE_SEED_KINDS = [
22802
22835
  "decision",
@@ -22811,7 +22844,7 @@ function isSlateSeedKind(value) {
22811
22844
  }
22812
22845
  var SEED_TEXT_MAX_LENGTH = 4000;
22813
22846
  function slatePath(dir) {
22814
- return path79.join(dir, "slate.json");
22847
+ return path80.join(dir, "slate.json");
22815
22848
  }
22816
22849
  function slateLockPath(dir) {
22817
22850
  return `${slatePath(dir)}.lock`;
@@ -23014,11 +23047,11 @@ function listSessions(cwd, dataDir) {
23014
23047
  if (name.startsWith(".")) {
23015
23048
  continue;
23016
23049
  }
23017
- const summary = readSummaryFile(path80.join(root, name, "summary.json"));
23050
+ const summary = readSummaryFile(path81.join(root, name, "summary.json"));
23018
23051
  if (summary === undefined) {
23019
23052
  continue;
23020
23053
  }
23021
- if (path80.resolve(summary.projectPath) !== path80.resolve(projectPath)) {
23054
+ if (path81.resolve(summary.projectPath) !== path81.resolve(projectPath)) {
23022
23055
  continue;
23023
23056
  }
23024
23057
  out.push(summary);
@@ -23051,15 +23084,15 @@ async function readSessionSlate(cwd, sessionId, dataDir) {
23051
23084
  }
23052
23085
  function loadContext(cwd, sessionId, dataDir) {
23053
23086
  const dir = sessionDir(resolveProjectRoot2(cwd), sessionId, dataDir);
23054
- const contextPath = path80.join(dir, "context.jsonl");
23087
+ const contextPath = path81.join(dir, "context.jsonl");
23055
23088
  if (existsSync13(contextPath)) {
23056
23089
  return readJsonl2(contextPath);
23057
23090
  }
23058
- return readJsonl2(path80.join(dir, "transcript.jsonl"));
23091
+ return readJsonl2(path81.join(dir, "transcript.jsonl"));
23059
23092
  }
23060
23093
  function loadArchive(cwd, sessionId, dataDir, onDegraded) {
23061
23094
  const dir = sessionDir(resolveProjectRoot2(cwd), sessionId, dataDir);
23062
- const archivePath = path80.join(dir, "archive.jsonl");
23095
+ const archivePath = path81.join(dir, "archive.jsonl");
23063
23096
  if (existsSync13(archivePath)) {
23064
23097
  try {
23065
23098
  const archive = readJsonl2(archivePath);
@@ -23243,7 +23276,7 @@ function sessionEvidenceRef(workspaceId, sessionId) {
23243
23276
  }
23244
23277
  async function resolveSessionWrapUp(input) {
23245
23278
  const now = input.now ?? (() => new Date);
23246
- const sessionId = path81.posix.basename(input.sourceRef, ".md");
23279
+ const sessionId = path82.posix.basename(input.sourceRef, ".md");
23247
23280
  const summary = findSession(input.cwd, sessionId);
23248
23281
  if (summary === undefined || input.sourceRef !== sessionEvidenceRef(input.workspaceId, summary.id)) {
23249
23282
  throw new SessionWrapUpError("session_not_found", `no session matching "${input.sourceRef}" in this project \u2014 use \`keryx sessions list\``);
@@ -23260,7 +23293,7 @@ async function resolveSessionWrapUp(input) {
23260
23293
  throw new SessionWrapUpError("session_unreadable", `session "${summary.id}" could not be read: ${cause.message}`);
23261
23294
  }
23262
23295
  const relPath = sessionEvidenceRef(input.workspaceId, summary.id).slice(2);
23263
- const evidenceDir = path81.dirname(relPath);
23296
+ const evidenceDir = path82.dirname(relPath);
23264
23297
  const slate = await readSessionSlate(input.cwd, summary.id);
23265
23298
  const diff = await gitDiff(input.cwd);
23266
23299
  const diffBody = diff.kind === "measured" ? diff.text : unmeasurableDiffBody(diff.detail);
@@ -23282,23 +23315,23 @@ async function resolveSessionWrapUp(input) {
23282
23315
  ""
23283
23316
  ].join(`
23284
23317
  `);
23285
- const wrapUpRelPath = path81.join(evidenceDir, `${summary.id}.wrap-up.md`);
23286
- const diffRelPath = path81.join(evidenceDir, `${summary.id}.diff.txt`);
23287
- const noticeRelPath = path81.join(evidenceDir, `${summary.id}.redaction.md`);
23318
+ const wrapUpRelPath = path82.join(evidenceDir, `${summary.id}.wrap-up.md`);
23319
+ const diffRelPath = path82.join(evidenceDir, `${summary.id}.diff.txt`);
23320
+ const noticeRelPath = path82.join(evidenceDir, `${summary.id}.redaction.md`);
23288
23321
  const floor = await applyEvidenceRedactionFloor(input.cwd, [
23289
- { name: path81.basename(relPath), content: markdown, path: relPath, source: "generated" },
23290
- { name: path81.basename(wrapUpRelPath), content: wrapUpMarkdown, path: wrapUpRelPath, source: "generated" },
23291
- { name: path81.basename(diffRelPath), content: diffBody, path: diffRelPath, source: "tool-output" }
23322
+ { name: path82.basename(relPath), content: markdown, path: relPath, source: "generated" },
23323
+ { name: path82.basename(wrapUpRelPath), content: wrapUpMarkdown, path: wrapUpRelPath, source: "generated" },
23324
+ { name: path82.basename(diffRelPath), content: diffBody, path: diffRelPath, source: "tool-output" }
23292
23325
  ]);
23293
23326
  if (!floor.ok)
23294
23327
  throw new SessionWrapUpError("security_denied", floor.reason);
23295
23328
  const [safeSession, safeWrapUp, safeDiff] = floor.bodies;
23296
- await mkdir30(path81.join(input.cwd, evidenceDir), { recursive: true });
23297
- await writeFile22(path81.join(input.cwd, relPath), safeSession.content, "utf8");
23298
- await writeFile22(path81.join(input.cwd, wrapUpRelPath), safeWrapUp.content, "utf8");
23299
- await writeFile22(path81.join(input.cwd, diffRelPath), safeDiff.content, "utf8");
23329
+ await mkdir30(path82.join(input.cwd, evidenceDir), { recursive: true });
23330
+ await writeFile22(path82.join(input.cwd, relPath), safeSession.content, "utf8");
23331
+ await writeFile22(path82.join(input.cwd, wrapUpRelPath), safeWrapUp.content, "utf8");
23332
+ await writeFile22(path82.join(input.cwd, diffRelPath), safeDiff.content, "utf8");
23300
23333
  if (floor.notice !== undefined)
23301
- await writeFile22(path81.join(input.cwd, noticeRelPath), floor.notice, "utf8");
23334
+ await writeFile22(path82.join(input.cwd, noticeRelPath), floor.notice, "utf8");
23302
23335
  const observedAt = now().toISOString();
23303
23336
  const evidence = [
23304
23337
  { kind: "wrap-up", uri: `./${wrapUpRelPath}`, revision: createHash18("sha256").update(safeWrapUp.content).digest("hex"), observedAt },
@@ -23321,13 +23354,13 @@ async function resolveSessionWrapUp(input) {
23321
23354
  init_fs();
23322
23355
  import { createHash as createHash19, randomBytes as randomBytes2 } from "crypto";
23323
23356
  import { readFile as readFile42 } from "fs/promises";
23324
- import path82 from "path";
23357
+ import path83 from "path";
23325
23358
  var CONFIRM_TOKEN_TTL_MS = 2 * 60000;
23326
23359
  function confirmTokenPath(cwd, workspaceId, proposalId) {
23327
- return path82.join(cwd, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.confirm-token.json`);
23360
+ return path83.join(cwd, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.confirm-token.json`);
23328
23361
  }
23329
23362
  function confirmReceiptPath(cwd, workspaceId, proposalId, idempotencyKey) {
23330
- return path82.join(cwd, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.${sha2564(idempotencyKey)}.confirm-receipt.json`);
23363
+ return path83.join(cwd, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.${sha2564(idempotencyKey)}.confirm-receipt.json`);
23331
23364
  }
23332
23365
  function sha2564(text) {
23333
23366
  return createHash19("sha256").update(text).digest("hex");
@@ -23365,7 +23398,7 @@ async function consumeConfirmToken(cwd, workspaceId, proposalId, idempotencyKey,
23365
23398
  // src/sac/decision-dedup.ts
23366
23399
  import { readFile as readFile44, readdir as readdir14 } from "fs/promises";
23367
23400
  import { randomUUID as randomUUID6 } from "crypto";
23368
- import path84 from "path";
23401
+ import path85 from "path";
23369
23402
  init_store();
23370
23403
  init_config();
23371
23404
 
@@ -23373,15 +23406,15 @@ init_config();
23373
23406
  init_fs();
23374
23407
  import { createHash as createHash20 } from "crypto";
23375
23408
  import { readFile as readFile43, rm as rm7 } from "fs/promises";
23376
- import path83 from "path";
23409
+ import path84 from "path";
23377
23410
  function proposalPath(cwd, workspaceId, proposalId) {
23378
- return path83.join(cwd, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.json`);
23411
+ return path84.join(cwd, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.json`);
23379
23412
  }
23380
23413
  function ownerReceiptPath(cwd, owner, workspaceId, idempotencyKey) {
23381
- return path83.join(cwd, ".metaproject", "workspaces", workspaceId, `${owner}-write-receipts`, `${idempotencyKey}.json`);
23414
+ return path84.join(cwd, ".metaproject", "workspaces", workspaceId, `${owner}-write-receipts`, `${idempotencyKey}.json`);
23382
23415
  }
23383
23416
  function proposalNotePath(cwd, workspaceId, proposalId) {
23384
- return path83.join(cwd, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.note.txt`);
23417
+ return path84.join(cwd, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.note.txt`);
23385
23418
  }
23386
23419
  async function readVerifiedProposalEvidence(cwd, workspaceId, proposalId) {
23387
23420
  let proposal;
@@ -23395,7 +23428,7 @@ async function readVerifiedProposalEvidence(cwd, workspaceId, proposalId) {
23395
23428
  return { ok: false, code: "no_evidence_to_write" };
23396
23429
  let content;
23397
23430
  try {
23398
- content = await readFile43(path83.join(cwd, evidence.uri), "utf8");
23431
+ content = await readFile43(path84.join(cwd, evidence.uri), "utf8");
23399
23432
  } catch {
23400
23433
  return { ok: false, code: "evidence_file_unreadable" };
23401
23434
  }
@@ -23425,22 +23458,22 @@ function targetRelPath(targetRef) {
23425
23458
  return targetRef.replace(/^\.\//, "");
23426
23459
  }
23427
23460
  function targetAbsolutePath(cwd, targetRef) {
23428
- return path83.join(cwd, ".metaproject", targetRelPath(targetRef));
23461
+ return path84.join(cwd, ".metaproject", targetRelPath(targetRef));
23429
23462
  }
23430
23463
  function targetKey(targetRef) {
23431
23464
  return digestOf2(targetRelPath(targetRef)).slice(0, 32);
23432
23465
  }
23433
23466
  function ownerTargetVersionPath(cwd, owner, workspaceId, targetRef) {
23434
- return path83.join(cwd, ".metaproject", "workspaces", workspaceId, `${owner}-target-versions`, `${targetKey(targetRef)}.json`);
23467
+ return path84.join(cwd, ".metaproject", "workspaces", workspaceId, `${owner}-target-versions`, `${targetKey(targetRef)}.json`);
23435
23468
  }
23436
23469
  function ownerTargetLockPath(cwd, owner, targetRef) {
23437
- return path83.join(cwd, ".metaproject", "data", "sac", "target-locks", owner, `${targetKey(targetRef)}.lock`);
23470
+ return path84.join(cwd, ".metaproject", "data", "sac", "target-locks", owner, `${targetKey(targetRef)}.lock`);
23438
23471
  }
23439
23472
  function ownerStagingDir(cwd, owner, workspaceId, idempotencyKey) {
23440
- return path83.join(cwd, ".metaproject", "workspaces", workspaceId, `${owner}-write-staging`, digestOf2(idempotencyKey).slice(0, 32));
23473
+ return path84.join(cwd, ".metaproject", "workspaces", workspaceId, `${owner}-write-staging`, digestOf2(idempotencyKey).slice(0, 32));
23441
23474
  }
23442
23475
  function ownerConflictDir(cwd, owner, workspaceId, idempotencyKey) {
23443
- return path83.join(cwd, ".metaproject", "workspaces", workspaceId, `${owner}-write-conflicts`, digestOf2(idempotencyKey).slice(0, 32));
23476
+ return path84.join(cwd, ".metaproject", "workspaces", workspaceId, `${owner}-write-conflicts`, digestOf2(idempotencyKey).slice(0, 32));
23444
23477
  }
23445
23478
  async function readJson2(file) {
23446
23479
  try {
@@ -23511,7 +23544,7 @@ async function applyGuardedTargetWrite(input) {
23511
23544
  staged: input.staged,
23512
23545
  stagedAt: receipt.completedAt
23513
23546
  };
23514
- await writeFileAtomic(path83.join(ownerStagingDir(cwd, owner, intent.workspaceId, intent.idempotencyKey), "plan.json"), `${JSON.stringify(staged, null, 2)}
23547
+ await writeFileAtomic(path84.join(ownerStagingDir(cwd, owner, intent.workspaceId, intent.idempotencyKey), "plan.json"), `${JSON.stringify(staged, null, 2)}
23515
23548
  `);
23516
23549
  const applied = await input.apply(input.staged);
23517
23550
  if (!applied.ok) {
@@ -23537,15 +23570,15 @@ async function recoverStagedOwnerWrite(input) {
23537
23570
  });
23538
23571
  }
23539
23572
  async function readStagedOwnerWrite(cwd, owner, workspaceId, idempotencyKey) {
23540
- return readJson2(path83.join(ownerStagingDir(cwd, owner, workspaceId, idempotencyKey), "plan.json"));
23573
+ return readJson2(path84.join(ownerStagingDir(cwd, owner, workspaceId, idempotencyKey), "plan.json"));
23541
23574
  }
23542
23575
  async function recordConflict(input) {
23543
23576
  const base = { targetRef: input.targetRef, expectedVersion: input.expectedVersion, currentVersion: input.currentVersion };
23544
23577
  if (input.proposedContent === undefined)
23545
23578
  return base;
23546
23579
  const dir = ownerConflictDir(input.cwd, input.owner, input.intent.workspaceId, input.intent.idempotencyKey);
23547
- await writeFileAtomic(path83.join(dir, "proposed"), input.proposedContent);
23548
- const diffRef = `./workspaces/${input.intent.workspaceId}/${input.owner}-write-conflicts/${path83.basename(dir)}/proposed`;
23580
+ await writeFileAtomic(path84.join(dir, "proposed"), input.proposedContent);
23581
+ const diffRef = `./workspaces/${input.intent.workspaceId}/${input.owner}-write-conflicts/${path84.basename(dir)}/proposed`;
23549
23582
  return { ...base, diffRef };
23550
23583
  }
23551
23584
 
@@ -23595,7 +23628,7 @@ async function resolveWorkspaceModule(cwd, workspaceId) {
23595
23628
  }
23596
23629
  }
23597
23630
  async function collectWikiDecisionEntries(cwd) {
23598
- const dir = path84.join(cwd, ".metaproject", "wiki", "decisions");
23631
+ const dir = path85.join(cwd, ".metaproject", "wiki", "decisions");
23599
23632
  let files;
23600
23633
  try {
23601
23634
  files = (await readdir14(dir)).filter((name) => name.endsWith(".md"));
@@ -23604,12 +23637,12 @@ async function collectWikiDecisionEntries(cwd) {
23604
23637
  }
23605
23638
  const entries = [];
23606
23639
  for (const file of files) {
23607
- const absolutePath = path84.join(dir, file);
23640
+ const absolutePath = path85.join(dir, file);
23608
23641
  try {
23609
23642
  const content = await readFile44(absolutePath, "utf8");
23610
23643
  entries.push({
23611
23644
  absolutePath,
23612
- relativePath: path84.posix.join("decisions", file),
23645
+ relativePath: path85.posix.join("decisions", file),
23613
23646
  type: extractHeaderField(content, "Type") ?? "decision",
23614
23647
  title: extractTitle(content),
23615
23648
  version: extractHeaderField(content, "Version") ?? null,
@@ -23830,7 +23863,7 @@ function createRealMemoryOwnerWriter(cwd, opts) {
23830
23863
  init_fs();
23831
23864
  init_guard();
23832
23865
  import { readFile as readFile46 } from "fs/promises";
23833
- import path85 from "path";
23866
+ import path86 from "path";
23834
23867
  function renderWrapUpDecisionPage(input) {
23835
23868
  const note = input.note?.trim();
23836
23869
  return `# ${input.title}
@@ -23871,14 +23904,14 @@ export is the source of truth for what actually happened.
23871
23904
  `;
23872
23905
  }
23873
23906
  function wikiPageRelativePath(proposalId) {
23874
- return path85.posix.join("decisions", `sac-${proposalId}.md`);
23907
+ return path86.posix.join("decisions", `sac-${proposalId}.md`);
23875
23908
  }
23876
23909
  function createRealWikiOwnerWriter(cwd, opts) {
23877
23910
  const now = opts?.now ?? (() => new Date);
23878
23911
  const applyStaged = async (staged) => {
23879
23912
  const relativePath = staged.relativePath;
23880
23913
  const content = staged.content;
23881
- await writeFileAtomic(path85.join(cwd, ".metaproject", "wiki", relativePath), content);
23914
+ await writeFileAtomic(path86.join(cwd, ".metaproject", "wiki", relativePath), content);
23882
23915
  return { ok: true };
23883
23916
  };
23884
23917
  return {
@@ -23947,10 +23980,10 @@ init_guard();
23947
23980
  import { createHash as createHash21 } from "crypto";
23948
23981
  import { homedir as homedir2 } from "os";
23949
23982
  import { mkdir as mkdir31, readFile as readFile47, stat as stat10 } from "fs/promises";
23950
- import path86 from "path";
23983
+ import path87 from "path";
23951
23984
  var VERSION = "0.1.0";
23952
23985
  async function createProjectSkill(projectRoot, options) {
23953
- const metaprojectRoot = path86.join(projectRoot, ".metaproject");
23986
+ const metaprojectRoot = path87.join(projectRoot, ".metaproject");
23954
23987
  if (!await pathExists(metaprojectRoot)) {
23955
23988
  throw new Error("Metaproject is not initialized. Run: keryx init");
23956
23989
  }
@@ -23960,8 +23993,8 @@ async function createProjectSkill(projectRoot, options) {
23960
23993
  const moduleName = slugify5(options.module ?? inferModule(options.target));
23961
23994
  const skillName = slugify5(options.name ?? inferSkillName(options.target));
23962
23995
  const format = options.format ?? "auto";
23963
- const packageRoot = path86.join(metaprojectRoot, "project-skills", moduleName, skillName);
23964
- const relativeSkillPath = toPosix(path86.relative(projectRoot, packageRoot));
23996
+ const packageRoot = path87.join(metaprojectRoot, "project-skills", moduleName, skillName);
23997
+ const relativeSkillPath = toPosix(path87.relative(projectRoot, packageRoot));
23965
23998
  const origin = options.origin ? options.originContent !== undefined ? {
23966
23999
  ref: options.origin.trim(),
23967
24000
  hash: hashOriginContent(options.originContent),
@@ -23971,7 +24004,7 @@ async function createProjectSkill(projectRoot, options) {
23971
24004
  const warnings = collectWarnings(evidence, format);
23972
24005
  const files = filesForPackage(packageRoot, format);
23973
24006
  if (!options.dryRun) {
23974
- await withFileLock(path86.join(metaprojectRoot, "data", "gdskills", "project-skills.lock"), async () => {
24007
+ await withFileLock(path87.join(metaprojectRoot, "data", "gdskills", "project-skills.lock"), async () => {
23975
24008
  await writeProjectSkillPackage({
23976
24009
  projectRoot,
23977
24010
  packageRoot,
@@ -24000,7 +24033,7 @@ async function createProjectSkill(projectRoot, options) {
24000
24033
  name: skillName,
24001
24034
  target: options.target,
24002
24035
  skillPath: relativeSkillPath,
24003
- files: files.map((filePath) => toPosix(path86.relative(projectRoot, filePath))),
24036
+ files: files.map((filePath) => toPosix(path87.relative(projectRoot, filePath))),
24004
24037
  warnings,
24005
24038
  dryRun: options.dryRun === true
24006
24039
  };
@@ -24009,9 +24042,9 @@ var MAX_SKILL_TARGET_LENGTH = 80;
24009
24042
  function resolveOriginPath(ref, projectRoot) {
24010
24043
  const trimmed = ref.trim();
24011
24044
  if (trimmed === "~" || trimmed.startsWith("~/")) {
24012
- return path86.join(homedir2(), trimmed.slice(1));
24045
+ return path87.join(homedir2(), trimmed.slice(1));
24013
24046
  }
24014
- return path86.resolve(projectRoot, trimmed);
24047
+ return path87.resolve(projectRoot, trimmed);
24015
24048
  }
24016
24049
  function hashOriginContent(content) {
24017
24050
  return `sha256:${createHash21("sha256").update(content).digest("hex")}`;
@@ -24049,32 +24082,32 @@ async function writeProjectSkillPackage({
24049
24082
  }) {
24050
24083
  const packageFormat = format === "single" ? "single" : "package";
24051
24084
  const skillContent = renderProjectSkill({ moduleName, skillName, target, note, origin, evidence, packageFormat });
24052
- const relativeSkillMdPath = toPosix(path86.join(path86.relative(projectRoot, packageRoot), "SKILL.md"));
24085
+ const relativeSkillMdPath = toPosix(path87.join(path87.relative(projectRoot, packageRoot), "SKILL.md"));
24053
24086
  const guard = await guardOutput({ cwd: projectRoot, content: skillContent, target: "skill", source: "generated", path: relativeSkillMdPath });
24054
24087
  const output = prepareOutputForPersistence(guard, skillContent);
24055
24088
  if (!output.allowed) {
24056
24089
  throw new Error(`Project skill blocked by the security gate: ${output.reason}`);
24057
24090
  }
24058
24091
  await mkdir31(packageRoot, { recursive: true });
24059
- const skillPath = path86.join(packageRoot, "SKILL.md");
24092
+ const skillPath = path87.join(packageRoot, "SKILL.md");
24060
24093
  await writeFileAtomic(skillPath, output.content);
24061
- const changelogPath = path86.join(packageRoot, "skill-changelog.md");
24094
+ const changelogPath = path87.join(packageRoot, "skill-changelog.md");
24062
24095
  if (!await pathExists(changelogPath)) {
24063
24096
  await writeFileAtomic(changelogPath, renderSkillChangelog({ moduleName, skillName, target }));
24064
24097
  }
24065
24098
  if (packageFormat === "package") {
24066
- await mkdir31(path86.join(packageRoot, "references"), { recursive: true });
24067
- await mkdir31(path86.join(packageRoot, "templates"), { recursive: true });
24068
- await writeFileAtomic(path86.join(packageRoot, "references", "context.md"), renderReferenceContext({ moduleName, skillName, target, evidence }));
24069
- await writeFileAtomic(path86.join(packageRoot, "templates", "README.md"), renderTemplatesReadme({ moduleName, skillName }));
24070
- await writeFileAtomic(path86.join(packageRoot, "verification.md"), renderVerification({ moduleName, skillName, evidence }));
24099
+ await mkdir31(path87.join(packageRoot, "references"), { recursive: true });
24100
+ await mkdir31(path87.join(packageRoot, "templates"), { recursive: true });
24101
+ await writeFileAtomic(path87.join(packageRoot, "references", "context.md"), renderReferenceContext({ moduleName, skillName, target, evidence }));
24102
+ await writeFileAtomic(path87.join(packageRoot, "templates", "README.md"), renderTemplatesReadme({ moduleName, skillName }));
24103
+ await writeFileAtomic(path87.join(packageRoot, "verification.md"), renderVerification({ moduleName, skillName, evidence }));
24071
24104
  }
24072
24105
  }
24073
24106
  async function collectEvidence(projectRoot, target) {
24074
- const absoluteTarget = path86.resolve(projectRoot, target);
24107
+ const absoluteTarget = path87.resolve(projectRoot, target);
24075
24108
  const targetExists = await pathExists(absoluteTarget);
24076
24109
  const targetKind = await classifyTarget(absoluteTarget, targetExists);
24077
- const maybeRelativeTarget = targetExists ? toPosix(path86.relative(projectRoot, absoluteTarget)) : undefined;
24110
+ const maybeRelativeTarget = targetExists ? toPosix(path87.relative(projectRoot, absoluteTarget)) : undefined;
24078
24111
  const graphArtifacts = await existingRelativePaths(projectRoot, [
24079
24112
  ".metaproject/data/gdgraph/artifacts/summary.md",
24080
24113
  ".metaproject/data/gdgraph/artifacts/module-map.json"
@@ -24104,7 +24137,7 @@ async function classifyTarget(absoluteTarget, targetExists) {
24104
24137
  async function existingRelativePaths(projectRoot, candidates) {
24105
24138
  const existing = [];
24106
24139
  for (const candidate of candidates) {
24107
- if (await pathExists(path86.join(projectRoot, candidate))) {
24140
+ if (await pathExists(path87.join(projectRoot, candidate))) {
24108
24141
  existing.push(candidate);
24109
24142
  }
24110
24143
  }
@@ -24131,17 +24164,17 @@ function collectWarnings(evidence, format) {
24131
24164
  }
24132
24165
  function filesForPackage(packageRoot, format) {
24133
24166
  const base = [
24134
- path86.join(packageRoot, "SKILL.md"),
24135
- path86.join(packageRoot, "skill-changelog.md")
24167
+ path87.join(packageRoot, "SKILL.md"),
24168
+ path87.join(packageRoot, "skill-changelog.md")
24136
24169
  ];
24137
24170
  if (format === "single") {
24138
24171
  return base;
24139
24172
  }
24140
24173
  return [
24141
24174
  ...base,
24142
- path86.join(packageRoot, "verification.md"),
24143
- path86.join(packageRoot, "references", "context.md"),
24144
- path86.join(packageRoot, "templates", "README.md")
24175
+ path87.join(packageRoot, "verification.md"),
24176
+ path87.join(packageRoot, "references", "context.md"),
24177
+ path87.join(packageRoot, "templates", "README.md")
24145
24178
  ];
24146
24179
  }
24147
24180
  function renderProjectSkill({
@@ -24369,7 +24402,7 @@ keryx skills verify ${moduleName}/${skillName}
24369
24402
  `;
24370
24403
  }
24371
24404
  async function updateManifest(projectRoot, entry) {
24372
- const manifestPath = path86.join(projectRoot, ".metaproject", "metaproject.json");
24405
+ const manifestPath = path87.join(projectRoot, ".metaproject", "metaproject.json");
24373
24406
  const manifest = await readJsonFileOr(manifestPath, {});
24374
24407
  manifest.modules ??= {};
24375
24408
  manifest.modules.gdskills ??= {};
@@ -24383,8 +24416,8 @@ async function updateManifest(projectRoot, entry) {
24383
24416
  `);
24384
24417
  }
24385
24418
  async function updateSkillsCatalog(projectRoot) {
24386
- const manifestPath = path86.join(projectRoot, ".metaproject", "metaproject.json");
24387
- const catalogPath = path86.join(projectRoot, ".metaproject", "skills", "catalog.md");
24419
+ const manifestPath = path87.join(projectRoot, ".metaproject", "metaproject.json");
24420
+ const catalogPath = path87.join(projectRoot, ".metaproject", "skills", "catalog.md");
24388
24421
  const manifest = await readJsonFileOr(manifestPath, {});
24389
24422
  const registry = manifest.modules?.gdskills?.projectSkillRegistry ?? [];
24390
24423
  const rows = registry.length > 0 ? registry.map((entry) => `| ${entry.module} | ${entry.name} | \`${entry.target}\` | ${entry.path}/SKILL.md |`).join(`
@@ -24424,7 +24457,7 @@ function inferModule(target) {
24424
24457
  }
24425
24458
  function inferSkillName(target) {
24426
24459
  const normalized = target.trim().replace(/[#:]+/g, "/");
24427
- const base = path86.basename(normalized).replace(/\.[^.]+$/, "");
24460
+ const base = path87.basename(normalized).replace(/\.[^.]+$/, "");
24428
24461
  return base || "entity";
24429
24462
  }
24430
24463
  function slugify5(value) {
@@ -24527,7 +24560,7 @@ class ProposalLifecycleService {
24527
24560
  now;
24528
24561
  constructor(options) {
24529
24562
  this.options = options;
24530
- this.root = path87.resolve(options.workspaceRoot);
24563
+ this.root = path88.resolve(options.workspaceRoot);
24531
24564
  this.now = options.now ?? (() => new Date);
24532
24565
  }
24533
24566
  async create(input) {
@@ -24546,7 +24579,7 @@ class ProposalLifecycleService {
24546
24579
  if (manifest.status === "archived")
24547
24580
  throw new ProposalLifecycleError("guard_denied", "workspace is archived");
24548
24581
  const file = this.proposalPath(workspaceId, proposal.id);
24549
- await mkdir32(path87.dirname(file), { recursive: true, mode: 448 });
24582
+ await mkdir32(path88.dirname(file), { recursive: true, mode: 448 });
24550
24583
  return withFileLock(`${file}.lock`, async () => {
24551
24584
  const consume = this.options.wrapUpAuthority.consume(input.wrapUp, { actor, workspaceId });
24552
24585
  if (consume !== "ok")
@@ -24574,7 +24607,7 @@ class ProposalLifecycleService {
24574
24607
  return this.options.workspaces.withAuthorizedActor({ actorContext: actor, workspaceId: input.workspaceId, action: "review", execute: async (manifest) => {
24575
24608
  const proposal = await this.loadProposal(input.workspaceId, input.proposalId);
24576
24609
  const ledger = this.ledgerPath(input.workspaceId);
24577
- await mkdir32(path87.dirname(ledger), { recursive: true, mode: 448 });
24610
+ await mkdir32(path88.dirname(ledger), { recursive: true, mode: 448 });
24578
24611
  return withFileLock(`${ledger}.lock`, async () => {
24579
24612
  const records = (await this.records(ledger)).filter((record) => record.proposalId === proposal.id);
24580
24613
  const events = records.filter((record) => record.recordType === "proposal-transition");
@@ -24615,7 +24648,7 @@ class ProposalLifecycleService {
24615
24648
  } });
24616
24649
  }
24617
24650
  async listProposedProposals(workspaceId) {
24618
- const proposalsDir = path87.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals");
24651
+ const proposalsDir = path88.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals");
24619
24652
  let entries;
24620
24653
  try {
24621
24654
  entries = (await readdir15(proposalsDir)).filter((name) => name.endsWith(".json"));
@@ -24627,7 +24660,7 @@ class ProposalLifecycleService {
24627
24660
  const proposals = [];
24628
24661
  for (const entry of entries) {
24629
24662
  try {
24630
- const parsed = JSON.parse(await readFile49(path87.join(proposalsDir, entry), "utf8"));
24663
+ const parsed = JSON.parse(await readFile49(path88.join(proposalsDir, entry), "utf8"));
24631
24664
  if (parsed.recordType === "proposal-created")
24632
24665
  proposals.push(parsed);
24633
24666
  } catch {}
@@ -24893,31 +24926,31 @@ class ProposalLifecycleService {
24893
24926
  }
24894
24927
  }
24895
24928
  proposalPath(workspaceId, proposalId) {
24896
- return path87.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.json`);
24929
+ return path88.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.json`);
24897
24930
  }
24898
24931
  decisionRef(proposalId, key) {
24899
24932
  return `./proposals/${proposalId}.${hash(key)}.decision.json`;
24900
24933
  }
24901
24934
  decisionPath(workspaceId, proposalId, key) {
24902
- return path87.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.${hash(key)}.decision.json`);
24935
+ return path88.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.${hash(key)}.decision.json`);
24903
24936
  }
24904
24937
  approvalRef(proposalId, key) {
24905
24938
  return `./proposals/${proposalId}.${hash(key)}.approval.json`;
24906
24939
  }
24907
24940
  approvalPath(workspaceId, proposalId, key) {
24908
- return path87.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.${hash(key)}.approval.json`);
24941
+ return path88.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.${hash(key)}.approval.json`);
24909
24942
  }
24910
24943
  writeResultPath(workspaceId, proposalId, key) {
24911
- return path87.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.${hash(key)}.write-result.json`);
24944
+ return path88.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.${hash(key)}.write-result.json`);
24912
24945
  }
24913
24946
  intentRef(proposalId, key) {
24914
24947
  return `./proposals/${proposalId}.${hash(key)}.write-intent.json`;
24915
24948
  }
24916
24949
  intentPath(workspaceId, proposalId, key) {
24917
- return path87.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.${hash(key)}.write-intent.json`);
24950
+ return path88.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.${hash(key)}.write-intent.json`);
24918
24951
  }
24919
24952
  attemptPath(workspaceId, proposalId, key) {
24920
- return path87.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.${hash(key)}.owner-write-attempt.json`);
24953
+ return path88.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.${hash(key)}.owner-write-attempt.json`);
24921
24954
  }
24922
24955
  async loadWriteResult(workspaceId, proposalId, key) {
24923
24956
  try {
@@ -24944,7 +24977,7 @@ class ProposalLifecycleService {
24944
24977
  }
24945
24978
  }
24946
24979
  ledgerPath(workspaceId) {
24947
- return path87.join(this.root, ".metaproject", "workspaces", workspaceId, "activity.jsonl");
24980
+ return path88.join(this.root, ".metaproject", "workspaces", workspaceId, "activity.jsonl");
24948
24981
  }
24949
24982
  timestamp() {
24950
24983
  return this.now().toISOString();
@@ -25027,7 +25060,7 @@ function normalizeProposalLifecycleResult(value) {
25027
25060
  // src/sac/collaboration-service.ts
25028
25061
  import { appendFile as appendFile7, mkdir as mkdir33, readFile as readFile50 } from "fs/promises";
25029
25062
  import { randomUUID as randomUUID8 } from "crypto";
25030
- import path88 from "path";
25063
+ import path89 from "path";
25031
25064
  class CollaborationServiceError extends Error {
25032
25065
  code;
25033
25066
  constructor(code, message) {
@@ -25042,7 +25075,7 @@ class CollaborationService {
25042
25075
  this.input = input;
25043
25076
  }
25044
25077
  file(id) {
25045
- return path88.join(this.input.workspaceRoot, ".metaproject", "workspaces", id, "activity.jsonl");
25078
+ return path89.join(this.input.workspaceRoot, ".metaproject", "workspaces", id, "activity.jsonl");
25046
25079
  }
25047
25080
  async overview(input) {
25048
25081
  const manifest = await this.input.workspaces.show(input);
@@ -25079,7 +25112,7 @@ class CollaborationService {
25079
25112
  occurredAt: (this.input.now ?? (() => new Date))().toISOString(),
25080
25113
  ...suppliedHandoff ? { handoff: { ...suppliedHandoff, from: actor.subject } } : {}
25081
25114
  });
25082
- await mkdir33(path88.dirname(this.file(manifest.id)), { recursive: true, mode: 448 });
25115
+ await mkdir33(path89.dirname(this.file(manifest.id)), { recursive: true, mode: 448 });
25083
25116
  await appendFile7(this.file(manifest.id), `${JSON.stringify(activity)}
25084
25117
  `, { mode: 384 });
25085
25118
  return normalizeCollaborationResult(activity);
@@ -25129,13 +25162,13 @@ function normalizeCollaborationResult(value) {
25129
25162
  // src/session/external-slate.ts
25130
25163
  init_fs();
25131
25164
  import { mkdir as mkdir35, readdir as readdir16, readFile as readFile51 } from "fs/promises";
25132
- import path90 from "path";
25165
+ import path91 from "path";
25133
25166
 
25134
25167
  // src/sac/machine-wrap-up.ts
25135
25168
  init_fs();
25136
25169
  import { createHash as createHash23, randomUUID as randomUUID10 } from "crypto";
25137
25170
  import { mkdir as mkdir34 } from "fs/promises";
25138
- import path89 from "path";
25171
+ import path90 from "path";
25139
25172
 
25140
25173
  // src/sac/workspace-resolve.ts
25141
25174
  init_redact();
@@ -25276,11 +25309,11 @@ async function resolveMachineWrapUp(input) {
25276
25309
  `;
25277
25310
  const seedsJson = `${JSON.stringify(seedsForKind.map((seed) => ({ text: seed.text, source: describeSource(seed.source) })), null, 2)}
25278
25311
  `;
25279
- const evidenceRelBase = path89.posix.join(".metaproject", "workspaces", input.workspaceId, "machine-evidence");
25312
+ const evidenceRelBase = path90.posix.join(".metaproject", "workspaces", input.workspaceId, "machine-evidence");
25280
25313
  const floor = await applyEvidenceRedactionFloor(input.cwd, [
25281
- { name: `${input.kind}.diff.txt`, content: diffBody, path: path89.posix.join(evidenceRelBase, `${input.kind}.diff.txt`), source: "tool-output" },
25282
- { name: `${input.kind}.flow.json`, content: flowSnapshotJson, path: path89.posix.join(evidenceRelBase, `${input.kind}.flow.json`), source: "generated" },
25283
- { name: `${input.kind}.seeds.json`, content: seedsJson, path: path89.posix.join(evidenceRelBase, `${input.kind}.seeds.json`), source: "generated" }
25314
+ { name: `${input.kind}.diff.txt`, content: diffBody, path: path90.posix.join(evidenceRelBase, `${input.kind}.diff.txt`), source: "tool-output" },
25315
+ { name: `${input.kind}.flow.json`, content: flowSnapshotJson, path: path90.posix.join(evidenceRelBase, `${input.kind}.flow.json`), source: "generated" },
25316
+ { name: `${input.kind}.seeds.json`, content: seedsJson, path: path90.posix.join(evidenceRelBase, `${input.kind}.seeds.json`), source: "generated" }
25284
25317
  ]);
25285
25318
  if (!floor.ok)
25286
25319
  return { ok: false, code: "security_denied", detail: floor.reason };
@@ -25334,14 +25367,14 @@ ${safeSeeds.content}`;
25334
25367
  }
25335
25368
  summary = result.text.trim().length > 0 ? result.text.trim() : mechanicalSummary(summaryDiff, course);
25336
25369
  }
25337
- const evidenceDir = path89.join(input.cwd, ".metaproject", "workspaces", input.workspaceId, "machine-evidence");
25370
+ const evidenceDir = path90.join(input.cwd, ".metaproject", "workspaces", input.workspaceId, "machine-evidence");
25338
25371
  await mkdir34(evidenceDir, { recursive: true });
25339
25372
  const diffFile = `${input.kind}.${shortHash}.diff.txt`;
25340
25373
  const flowFile = `${input.kind}.${shortHash}.flow.json`;
25341
25374
  const seedsFile = `${input.kind}.${shortHash}.seeds.json`;
25342
- await writeFileAtomic(path89.join(evidenceDir, diffFile), safeDiff.content);
25343
- await writeFileAtomic(path89.join(evidenceDir, flowFile), safeFlow.content);
25344
- await writeFileAtomic(path89.join(evidenceDir, seedsFile), safeSeeds.content);
25375
+ await writeFileAtomic(path90.join(evidenceDir, diffFile), safeDiff.content);
25376
+ await writeFileAtomic(path90.join(evidenceDir, flowFile), safeFlow.content);
25377
+ await writeFileAtomic(path90.join(evidenceDir, seedsFile), safeSeeds.content);
25345
25378
  const observedAt = now().toISOString();
25346
25379
  const relBase = `./.metaproject/workspaces/${input.workspaceId}/machine-evidence`;
25347
25380
  const evidence = [
@@ -25351,7 +25384,7 @@ ${safeSeeds.content}`;
25351
25384
  ];
25352
25385
  if (floor.notice !== undefined) {
25353
25386
  const noticeFile = `${input.kind}.${shortHash}.redaction.md`;
25354
- await writeFileAtomic(path89.join(evidenceDir, noticeFile), floor.notice);
25387
+ await writeFileAtomic(path90.join(evidenceDir, noticeFile), floor.notice);
25355
25388
  evidence.push({ kind: REDACTION_NOTICE_KIND, uri: `${relBase}/${noticeFile}`, revision: sha2565(floor.notice), observedAt });
25356
25389
  }
25357
25390
  return {
@@ -25370,18 +25403,18 @@ async function writeFlooredArchiveArtifact(params) {
25370
25403
  {
25371
25404
  name: params.filename,
25372
25405
  content: params.content,
25373
- path: path89.posix.join("slate-archive", params.filename),
25406
+ path: path90.posix.join("slate-archive", params.filename),
25374
25407
  source: "generated"
25375
25408
  }
25376
25409
  ]);
25377
25410
  if (!floor.ok)
25378
25411
  return { ok: false, code: "security_denied", detail: floor.reason };
25379
25412
  const body = floor.bodies[0];
25380
- const archiveDir = path89.join(params.dir, "slate-archive");
25413
+ const archiveDir = path90.join(params.dir, "slate-archive");
25381
25414
  await mkdir34(archiveDir, { recursive: true });
25382
- await writeFileAtomic(path89.join(archiveDir, params.filename), body.content);
25415
+ await writeFileAtomic(path90.join(archiveDir, params.filename), body.content);
25383
25416
  if (floor.notice !== undefined) {
25384
- await writeFileAtomic(path89.join(archiveDir, `${params.filename}${ARCHIVE_REDACTION_NOTICE_SUFFIX}`), floor.notice);
25417
+ await writeFileAtomic(path90.join(archiveDir, `${params.filename}${ARCHIVE_REDACTION_NOTICE_SUFFIX}`), floor.notice);
25385
25418
  }
25386
25419
  return { ok: true, altered: body.altered };
25387
25420
  }
@@ -25417,9 +25450,9 @@ async function writeWrapUpOutcomeArtifact(cwd, dir, trigger, now, groups) {
25417
25450
  return;
25418
25451
  const refusalIso = now().toISOString();
25419
25452
  const refusalFilename = `${refusalIso.replace(/[:.]/g, "-")}-wrap-up-outcome.json`;
25420
- const archiveDir = path89.join(dir, "slate-archive");
25453
+ const archiveDir = path90.join(dir, "slate-archive");
25421
25454
  await mkdir34(archiveDir, { recursive: true });
25422
- await writeFileAtomic(path89.join(archiveDir, refusalFilename), `${JSON.stringify({
25455
+ await writeFileAtomic(path90.join(archiveDir, refusalFilename), `${JSON.stringify({
25423
25456
  recordType: "wrap-up-outcome",
25424
25457
  trigger,
25425
25458
  generatedAt: refusalIso,
@@ -25555,7 +25588,7 @@ async function runWrapUp(input) {
25555
25588
 
25556
25589
  // src/session/external-slate.ts
25557
25590
  function externalSlatesDir(cwd) {
25558
- return path90.join(cwd, ".keryx", "external-slates");
25591
+ return path91.join(cwd, ".keryx", "external-slates");
25559
25592
  }
25560
25593
  var EXTERNAL_SESSION_ID_PATTERN = /^[A-Za-z0-9_-]{1,128}$/;
25561
25594
  function assertValidExternalSessionId(externalSessionId) {
@@ -25565,14 +25598,14 @@ function assertValidExternalSessionId(externalSessionId) {
25565
25598
  }
25566
25599
  function externalSlatePath(cwd, externalSessionId) {
25567
25600
  assertValidExternalSessionId(externalSessionId);
25568
- return path90.join(externalSlatesDir(cwd), `${externalSessionId}.json`);
25601
+ return path91.join(externalSlatesDir(cwd), `${externalSessionId}.json`);
25569
25602
  }
25570
25603
  function externalSlateLockPath(cwd, externalSessionId) {
25571
25604
  return `${externalSlatePath(cwd, externalSessionId)}.lock`;
25572
25605
  }
25573
25606
  function externalSlateEvidenceDir(cwd, externalSessionId) {
25574
25607
  assertValidExternalSessionId(externalSessionId);
25575
- return path90.join(externalSlatesDir(cwd), externalSessionId);
25608
+ return path91.join(externalSlatesDir(cwd), externalSessionId);
25576
25609
  }
25577
25610
  async function readExternalSlate(cwd, externalSessionId) {
25578
25611
  try {
@@ -25661,12 +25694,12 @@ __export(exports_service10, {
25661
25694
  runDoctor: () => runDoctor,
25662
25695
  runValidate: () => runValidate
25663
25696
  });
25664
- import path93 from "path";
25697
+ import path94 from "path";
25665
25698
  import { readFile as readFile54 } from "fs/promises";
25666
25699
 
25667
25700
  // src/standard/validate.ts
25668
25701
  init_fs();
25669
- import path92 from "path";
25702
+ import path93 from "path";
25670
25703
  import { readFile as readFile53 } from "fs/promises";
25671
25704
 
25672
25705
  // src/standard/schemas.ts
@@ -25795,7 +25828,7 @@ var SCHEMA_REGISTRY2 = {
25795
25828
 
25796
25829
  // src/standard/profiles.ts
25797
25830
  init_fs();
25798
- import path91 from "path";
25831
+ import path92 from "path";
25799
25832
  import { readFile as readFile52 } from "fs/promises";
25800
25833
  var AGENT_MODULES = ["gdgraph", "gdctx", "gdskills", "gdwiki", "memory"];
25801
25834
  var CI_MODULES = ["health", "testing"];
@@ -25807,7 +25840,7 @@ function enabledModuleKeys(manifest) {
25807
25840
  }
25808
25841
  async function rootEntrypointLinksIndex(cwd) {
25809
25842
  for (const name of ROOT_ENTRYPOINTS) {
25810
- const filePath = path91.join(cwd, name);
25843
+ const filePath = path92.join(cwd, name);
25811
25844
  if (!await pathExists(filePath)) {
25812
25845
  continue;
25813
25846
  }
@@ -25819,16 +25852,16 @@ async function rootEntrypointLinksIndex(cwd) {
25819
25852
  return false;
25820
25853
  }
25821
25854
  async function minimalSatisfied(cwd) {
25822
- const metaprojectRoot = path91.join(cwd, ".metaproject");
25855
+ const metaprojectRoot = path92.join(cwd, ".metaproject");
25823
25856
  const requiredFiles = ["index.md", "README.md", "metaproject.json"];
25824
25857
  const requiredDirs = ["modules", "rules", "skills", "data"];
25825
25858
  for (const file of requiredFiles) {
25826
- if (!await pathExists(path91.join(metaprojectRoot, file))) {
25859
+ if (!await pathExists(path92.join(metaprojectRoot, file))) {
25827
25860
  return false;
25828
25861
  }
25829
25862
  }
25830
25863
  for (const dir of requiredDirs) {
25831
- if (!await pathExists(path91.join(metaprojectRoot, dir))) {
25864
+ if (!await pathExists(path92.join(metaprojectRoot, dir))) {
25832
25865
  return false;
25833
25866
  }
25834
25867
  }
@@ -25841,7 +25874,7 @@ async function ciSatisfied(cwd, manifest) {
25841
25874
  return false;
25842
25875
  }
25843
25876
  for (const key of ciModules) {
25844
- if (await pathExists(path91.join(cwd, ".metaproject", "data", key, "artifacts"))) {
25877
+ if (await pathExists(path92.join(cwd, ".metaproject", "data", key, "artifacts"))) {
25845
25878
  return true;
25846
25879
  }
25847
25880
  }
@@ -25854,7 +25887,7 @@ async function evaluateProfiles(cwd, manifest) {
25854
25887
  satisfied.push("minimal");
25855
25888
  }
25856
25889
  const hasAgentModule = AGENT_MODULES.some((key) => new Set(enabledModuleKeys(manifest)).has(key));
25857
- const agent = minimal && hasAgentModule && await rootEntrypointLinksIndex(cwd) && await pathExists(path91.join(cwd, ".metaproject", "rules"));
25890
+ const agent = minimal && hasAgentModule && await rootEntrypointLinksIndex(cwd) && await pathExists(path92.join(cwd, ".metaproject", "rules"));
25858
25891
  if (agent) {
25859
25892
  satisfied.push("agent");
25860
25893
  }
@@ -26024,20 +26057,20 @@ var MANIFEST_TOP_LEVEL_SCHEMA = {
26024
26057
  async function validateWorkspace2(cwd) {
26025
26058
  const errors = [];
26026
26059
  const warnings = [];
26027
- const metaprojectRoot = path92.join(cwd, ".metaproject");
26060
+ const metaprojectRoot = path93.join(cwd, ".metaproject");
26028
26061
  const requiredFiles = ["index.md", "README.md", "metaproject.json"];
26029
26062
  for (const file of requiredFiles) {
26030
- if (!await pathExists(path92.join(metaprojectRoot, file))) {
26063
+ if (!await pathExists(path93.join(metaprojectRoot, file))) {
26031
26064
  errors.push(issue("missing-required-file", `Required file .metaproject/${file} is missing`, `Run \`keryx init\` to scaffold .metaproject/${file}.`));
26032
26065
  }
26033
26066
  }
26034
26067
  const requiredDirs = ["modules", "rules", "skills", "data"];
26035
26068
  for (const dir of requiredDirs) {
26036
- if (!await pathExists(path92.join(metaprojectRoot, dir))) {
26069
+ if (!await pathExists(path93.join(metaprojectRoot, dir))) {
26037
26070
  errors.push(issue("missing-required-dir", `Required directory .metaproject/${dir}/ is missing`, `Run \`keryx init\` to create .metaproject/${dir}/.`));
26038
26071
  }
26039
26072
  }
26040
- const manifestPath = path92.join(metaprojectRoot, "metaproject.json");
26073
+ const manifestPath = path93.join(metaprojectRoot, "metaproject.json");
26041
26074
  if (!await pathExists(manifestPath)) {
26042
26075
  return { ok: errors.length === 0, errors, warnings };
26043
26076
  }
@@ -26069,7 +26102,7 @@ async function validateWorkspace2(cwd) {
26069
26102
  if (typeof value !== "string") {
26070
26103
  continue;
26071
26104
  }
26072
- if (!await pathExists(path92.join(cwd, value))) {
26105
+ if (!await pathExists(path93.join(cwd, value))) {
26073
26106
  errors.push(issue("missing-declared-path", `Declared path paths.${key} -> ${value} does not exist`, `Create ${value} or remove paths.${key} from metaproject.json.`));
26074
26107
  }
26075
26108
  }
@@ -26079,7 +26112,7 @@ async function validateWorkspace2(cwd) {
26079
26112
  continue;
26080
26113
  }
26081
26114
  if (typeof entry.manifest === "string") {
26082
- if (!await pathExists(path92.join(cwd, entry.manifest))) {
26115
+ if (!await pathExists(path93.join(cwd, entry.manifest))) {
26083
26116
  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.`));
26084
26117
  }
26085
26118
  }
@@ -26088,14 +26121,14 @@ async function validateWorkspace2(cwd) {
26088
26121
  if (typeof value !== "string") {
26089
26122
  continue;
26090
26123
  }
26091
- if (!await pathExists(path92.join(cwd, value))) {
26124
+ if (!await pathExists(path93.join(cwd, value))) {
26092
26125
  const sink = field === "data" ? warnings : errors;
26093
26126
  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.`));
26094
26127
  }
26095
26128
  }
26096
26129
  }
26097
26130
  for (const name of ROOT_ENTRYPOINTS2) {
26098
- const filePath = path92.join(cwd, name);
26131
+ const filePath = path93.join(cwd, name);
26099
26132
  if (!await pathExists(filePath)) {
26100
26133
  continue;
26101
26134
  }
@@ -26149,7 +26182,7 @@ async function runDoctor(cwd) {
26149
26182
  return validateWorkspace2(cwd);
26150
26183
  }
26151
26184
  async function readManifest(cwd) {
26152
- const manifestPath = path93.join(cwd, ".metaproject", "metaproject.json");
26185
+ const manifestPath = path94.join(cwd, ".metaproject", "metaproject.json");
26153
26186
  if (!await pathExists(manifestPath)) {
26154
26187
  throw new Error("Metaproject is not initialized (missing .metaproject/metaproject.json). Run `keryx init` first.");
26155
26188
  }