cleargate 0.6.2 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.cjs CHANGED
@@ -627,7 +627,7 @@ var import_commander = require("commander");
627
627
  // package.json
628
628
  var package_default = {
629
629
  name: "cleargate",
630
- version: "0.6.2",
630
+ version: "0.8.0",
631
631
  private: false,
632
632
  type: "module",
633
633
  description: "Planning framework for Claude Code agents \u2014 sprint/epic/story protocol, four-agent loop (architect/developer/qa/reporter), Karpathy-style awareness wiki.",
@@ -1897,8 +1897,8 @@ async function stampHandler(file, opts, cli) {
1897
1897
 
1898
1898
  // src/commands/init.ts
1899
1899
  init_cjs_shims();
1900
- var fs15 = __toESM(require("fs"), 1);
1901
- var path16 = __toESM(require("path"), 1);
1900
+ var fs16 = __toESM(require("fs"), 1);
1901
+ var path17 = __toESM(require("path"), 1);
1902
1902
  var import_node_url5 = require("url");
1903
1903
  var import_node_child_process3 = require("child_process");
1904
1904
 
@@ -1945,9 +1945,14 @@ function copyPayload(payloadDir, targetCwd, opts) {
1945
1945
  srcContent = text;
1946
1946
  }
1947
1947
  const srcBuffer = typeof srcContent === "string" ? Buffer.from(srcContent, "utf8") : srcContent;
1948
+ const srcMode = fs7.statSync(srcPath).mode;
1949
+ const needsExec = (srcMode & 73) !== 0 || relPath.endsWith(".sh");
1948
1950
  if (fs7.existsSync(dstPath)) {
1949
1951
  const dstContent = fs7.readFileSync(dstPath);
1950
1952
  if (srcBuffer.equals(dstContent)) {
1953
+ if (needsExec && process.platform !== "win32") {
1954
+ fs7.chmodSync(dstPath, 493);
1955
+ }
1951
1956
  report.skipped++;
1952
1957
  report.actions.push({ action: "skipped", relPath });
1953
1958
  continue;
@@ -1958,10 +1963,16 @@ function copyPayload(payloadDir, targetCwd, opts) {
1958
1963
  continue;
1959
1964
  }
1960
1965
  fs7.writeFileSync(dstPath, srcBuffer);
1966
+ if (needsExec && process.platform !== "win32") {
1967
+ fs7.chmodSync(dstPath, 493);
1968
+ }
1961
1969
  report.overwritten++;
1962
1970
  report.actions.push({ action: "overwritten", relPath });
1963
1971
  } else {
1964
1972
  fs7.writeFileSync(dstPath, srcBuffer);
1973
+ if (needsExec && process.platform !== "win32") {
1974
+ fs7.chmodSync(dstPath, 493);
1975
+ }
1965
1976
  report.created++;
1966
1977
  report.actions.push({ action: "created", relPath });
1967
1978
  }
@@ -2030,15 +2041,53 @@ function injectClaudeMd(existing, block) {
2030
2041
  return existing.trimEnd() + "\n\n" + block + "\n";
2031
2042
  }
2032
2043
 
2044
+ // src/init/inject-mcp-json.ts
2045
+ init_cjs_shims();
2046
+ var fs8 = __toESM(require("fs"), 1);
2047
+ var path8 = __toESM(require("path"), 1);
2048
+ function mergeMcpJson(existing, entry) {
2049
+ const next = existing ? { ...existing } : {};
2050
+ const servers = { ...next.mcpServers ?? {} };
2051
+ servers.cleargate = entry;
2052
+ next.mcpServers = servers;
2053
+ return JSON.stringify(next, null, 2) + "\n";
2054
+ }
2055
+ var STDIO_ENTRY = {
2056
+ command: "cleargate",
2057
+ args: ["mcp", "serve"]
2058
+ };
2059
+ function injectMcpJson(cwd, _unusedUrl) {
2060
+ const dst = path8.join(cwd, ".mcp.json");
2061
+ const entry = STDIO_ENTRY;
2062
+ let existing = null;
2063
+ let existingRaw = null;
2064
+ if (fs8.existsSync(dst)) {
2065
+ existingRaw = fs8.readFileSync(dst, "utf8");
2066
+ try {
2067
+ existing = JSON.parse(existingRaw);
2068
+ } catch {
2069
+ throw new Error(
2070
+ `inject-mcp-json: ${dst} is not valid JSON; refusing to overwrite. Fix or remove the file and re-run init.`
2071
+ );
2072
+ }
2073
+ }
2074
+ const next = mergeMcpJson(existing, entry);
2075
+ if (existingRaw !== null && existingRaw === next) {
2076
+ return "unchanged";
2077
+ }
2078
+ fs8.writeFileSync(dst, next);
2079
+ return existingRaw === null ? "created" : "updated";
2080
+ }
2081
+
2033
2082
  // src/commands/wiki-build.ts
2034
2083
  init_cjs_shims();
2035
- var fs13 = __toESM(require("fs"), 1);
2036
- var path13 = __toESM(require("path"), 1);
2084
+ var fs14 = __toESM(require("fs"), 1);
2085
+ var path14 = __toESM(require("path"), 1);
2037
2086
 
2038
2087
  // src/wiki/scan.ts
2039
2088
  init_cjs_shims();
2040
- var fs8 = __toESM(require("fs"), 1);
2041
- var path8 = __toESM(require("path"), 1);
2089
+ var fs9 = __toESM(require("fs"), 1);
2090
+ var path9 = __toESM(require("path"), 1);
2042
2091
 
2043
2092
  // src/wiki/derive-bucket.ts
2044
2093
  init_cjs_shims();
@@ -2083,19 +2132,19 @@ var EXCLUDED_SUFFIXES = [
2083
2132
  function scanRawItems(deliveryRoot, repoRoot) {
2084
2133
  const results = [];
2085
2134
  for (const subdir of ["pending-sync", "archive"]) {
2086
- const dir = path8.join(deliveryRoot, subdir);
2087
- if (!fs8.existsSync(dir)) continue;
2088
- const entries = fs8.readdirSync(dir, { recursive: true, encoding: "utf8" });
2135
+ const dir = path9.join(deliveryRoot, subdir);
2136
+ if (!fs9.existsSync(dir)) continue;
2137
+ const entries = fs9.readdirSync(dir, { recursive: true, encoding: "utf8" });
2089
2138
  for (const rel of entries) {
2090
2139
  if (!rel.endsWith(".md")) continue;
2091
2140
  if (rel.includes("~") || rel.startsWith(".")) continue;
2092
- const absPath = path8.join(dir, rel);
2093
- const stat = fs8.statSync(absPath);
2141
+ const absPath = path9.join(dir, rel);
2142
+ const stat = fs9.statSync(absPath);
2094
2143
  if (!stat.isFile()) continue;
2095
- const rawPath = path8.relative(repoRoot, absPath).replace(/\\/g, "/");
2144
+ const rawPath = path9.relative(repoRoot, absPath).replace(/\\/g, "/");
2096
2145
  const isExcluded = EXCLUDED_SUFFIXES.some((excl) => rawPath.startsWith(excl));
2097
2146
  if (isExcluded) continue;
2098
- const filename = path8.basename(absPath);
2147
+ const filename = path9.basename(absPath);
2099
2148
  let bucketInfo;
2100
2149
  try {
2101
2150
  bucketInfo = deriveBucket(filename);
@@ -2108,7 +2157,7 @@ function scanRawItems(deliveryRoot, repoRoot) {
2108
2157
  } catch {
2109
2158
  continue;
2110
2159
  }
2111
- const raw = fs8.readFileSync(absPath, "utf8");
2160
+ const raw = fs9.readFileSync(absPath, "utf8");
2112
2161
  let fm;
2113
2162
  let body;
2114
2163
  try {
@@ -2223,8 +2272,8 @@ function parseFmRaw(raw) {
2223
2272
 
2224
2273
  // src/wiki/synthesis/active-sprint.ts
2225
2274
  init_cjs_shims();
2226
- var fs9 = __toESM(require("fs"), 1);
2227
- var path9 = __toESM(require("path"), 1);
2275
+ var fs10 = __toESM(require("fs"), 1);
2276
+ var path10 = __toESM(require("path"), 1);
2228
2277
  var import_node_url = require("url");
2229
2278
 
2230
2279
  // src/wiki/synthesis/render.ts
@@ -2264,7 +2313,7 @@ function renderSection(template, ctx) {
2264
2313
  // src/wiki/synthesis/active-sprint.ts
2265
2314
  function compile(state2, templateDir) {
2266
2315
  const tplDir = templateDir ?? resolveDefaultTemplateDir();
2267
- const tpl = fs9.readFileSync(path9.join(tplDir, "active-sprint.md"), "utf8");
2316
+ const tpl = fs10.readFileSync(path10.join(tplDir, "active-sprint.md"), "utf8");
2268
2317
  const sprints = state2.filter((i) => i.bucket === "sprints");
2269
2318
  const active = sprints.filter((s) => isSet(s.fm["activated_at"]) && !isSet(s.fm["completed_at"]));
2270
2319
  const completed = sprints.filter((s) => isSet(s.fm["completed_at"]));
@@ -2288,18 +2337,18 @@ function isSet(val) {
2288
2337
  return s !== "" && s !== "null";
2289
2338
  }
2290
2339
  function resolveDefaultTemplateDir() {
2291
- const __dirname = path9.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
2292
- return path9.resolve(__dirname, "..", "templates", "synthesis");
2340
+ const __dirname = path10.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
2341
+ return path10.resolve(__dirname, "..", "templates", "synthesis");
2293
2342
  }
2294
2343
 
2295
2344
  // src/wiki/synthesis/open-gates.ts
2296
2345
  init_cjs_shims();
2297
- var fs10 = __toESM(require("fs"), 1);
2298
- var path10 = __toESM(require("path"), 1);
2346
+ var fs11 = __toESM(require("fs"), 1);
2347
+ var path11 = __toESM(require("path"), 1);
2299
2348
  var import_node_url2 = require("url");
2300
2349
  function compile2(state2, templateDir) {
2301
2350
  const tplDir = templateDir ?? resolveDefaultTemplateDir2();
2302
- const tpl = fs10.readFileSync(path10.join(tplDir, "open-gates.md"), "utf8");
2351
+ const tpl = fs11.readFileSync(path11.join(tplDir, "open-gates.md"), "utf8");
2303
2352
  const gate1 = state2.filter((i) => {
2304
2353
  if (i.bucket !== "proposals") return false;
2305
2354
  const status = String(i.fm["status"] ?? "");
@@ -2328,18 +2377,18 @@ function compile2(state2, templateDir) {
2328
2377
  return renderTemplate(tpl, data);
2329
2378
  }
2330
2379
  function resolveDefaultTemplateDir2() {
2331
- const __dirname = path10.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
2332
- return path10.resolve(__dirname, "..", "templates", "synthesis");
2380
+ const __dirname = path11.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
2381
+ return path11.resolve(__dirname, "..", "templates", "synthesis");
2333
2382
  }
2334
2383
 
2335
2384
  // src/wiki/synthesis/product-state.ts
2336
2385
  init_cjs_shims();
2337
- var fs11 = __toESM(require("fs"), 1);
2338
- var path11 = __toESM(require("path"), 1);
2386
+ var fs12 = __toESM(require("fs"), 1);
2387
+ var path12 = __toESM(require("path"), 1);
2339
2388
  var import_node_url3 = require("url");
2340
2389
  function compile3(state2, templateDir) {
2341
2390
  const tplDir = templateDir ?? resolveDefaultTemplateDir3();
2342
- const tpl = fs11.readFileSync(path11.join(tplDir, "product-state.md"), "utf8");
2391
+ const tpl = fs12.readFileSync(path12.join(tplDir, "product-state.md"), "utf8");
2343
2392
  function countBucket(bucket) {
2344
2393
  return state2.filter((i) => i.bucket === bucket);
2345
2394
  }
@@ -2386,18 +2435,18 @@ function compile3(state2, templateDir) {
2386
2435
  return renderTemplate(tpl, data);
2387
2436
  }
2388
2437
  function resolveDefaultTemplateDir3() {
2389
- const __dirname = path11.dirname((0, import_node_url3.fileURLToPath)(importMetaUrl));
2390
- return path11.resolve(__dirname, "..", "templates", "synthesis");
2438
+ const __dirname = path12.dirname((0, import_node_url3.fileURLToPath)(importMetaUrl));
2439
+ return path12.resolve(__dirname, "..", "templates", "synthesis");
2391
2440
  }
2392
2441
 
2393
2442
  // src/wiki/synthesis/roadmap.ts
2394
2443
  init_cjs_shims();
2395
- var fs12 = __toESM(require("fs"), 1);
2396
- var path12 = __toESM(require("path"), 1);
2444
+ var fs13 = __toESM(require("fs"), 1);
2445
+ var path13 = __toESM(require("path"), 1);
2397
2446
  var import_node_url4 = require("url");
2398
2447
  function compile4(state2, templateDir) {
2399
2448
  const tplDir = templateDir ?? resolveDefaultTemplateDir4();
2400
- const tpl = fs12.readFileSync(path12.join(tplDir, "roadmap.md"), "utf8");
2449
+ const tpl = fs13.readFileSync(path13.join(tplDir, "roadmap.md"), "utf8");
2401
2450
  const sprints = state2.filter((i) => i.bucket === "sprints");
2402
2451
  const epics = state2.filter((i) => i.bucket === "epics");
2403
2452
  const inFlightSprints = sprints.filter(
@@ -2450,8 +2499,8 @@ function isShippedStatus(status) {
2450
2499
  return status === "Completed" || status === "Approved";
2451
2500
  }
2452
2501
  function resolveDefaultTemplateDir4() {
2453
- const __dirname = path12.dirname((0, import_node_url4.fileURLToPath)(importMetaUrl));
2454
- return path12.resolve(__dirname, "..", "templates", "synthesis");
2502
+ const __dirname = path13.dirname((0, import_node_url4.fileURLToPath)(importMetaUrl));
2503
+ return path13.resolve(__dirname, "..", "templates", "synthesis");
2455
2504
  }
2456
2505
 
2457
2506
  // src/commands/wiki-build.ts
@@ -2476,16 +2525,16 @@ async function wikiBuildHandler(opts = {}) {
2476
2525
  const exit = opts.exit ?? ((c) => process.exit(c));
2477
2526
  const gitRunner = opts.gitRunner;
2478
2527
  const templateDir = opts.templateDir;
2479
- const deliveryRoot = path13.join(cwd, ".cleargate", "delivery");
2480
- const wikiRoot = path13.join(cwd, ".cleargate", "wiki");
2481
- if (!fs13.existsSync(deliveryRoot)) {
2528
+ const deliveryRoot = path14.join(cwd, ".cleargate", "delivery");
2529
+ const wikiRoot = path14.join(cwd, ".cleargate", "wiki");
2530
+ if (!fs14.existsSync(deliveryRoot)) {
2482
2531
  stderr(`wiki build: .cleargate/delivery/ not found at ${deliveryRoot}
2483
2532
  `);
2484
2533
  exit(1);
2485
2534
  return;
2486
2535
  }
2487
2536
  for (const bucket of BUCKET_ORDER) {
2488
- fs13.mkdirSync(path13.join(wikiRoot, bucket), { recursive: true });
2537
+ fs14.mkdirSync(path14.join(wikiRoot, bucket), { recursive: true });
2489
2538
  }
2490
2539
  const items = scanRawItems(deliveryRoot, cwd);
2491
2540
  const timestamp = now();
@@ -2508,19 +2557,19 @@ async function wikiBuildHandler(opts = {}) {
2508
2557
  };
2509
2558
  const body = buildPageBody(item, wikiPage);
2510
2559
  const content = serializePage(wikiPage, body);
2511
- const pageDir = path13.join(wikiRoot, item.bucket);
2512
- fs13.mkdirSync(pageDir, { recursive: true });
2513
- fs13.writeFileSync(path13.join(pageDir, `${item.id}.md`), content, "utf8");
2560
+ const pageDir = path14.join(wikiRoot, item.bucket);
2561
+ fs14.mkdirSync(pageDir, { recursive: true });
2562
+ fs14.writeFileSync(path14.join(pageDir, `${item.id}.md`), content, "utf8");
2514
2563
  pagesWritten++;
2515
2564
  }
2516
2565
  const indexContent = buildIndex(items);
2517
- fs13.writeFileSync(path13.join(wikiRoot, "index.md"), indexContent, "utf8");
2566
+ fs14.writeFileSync(path14.join(wikiRoot, "index.md"), indexContent, "utf8");
2518
2567
  const logContent = buildLog(items, timestamp);
2519
- fs13.writeFileSync(path13.join(wikiRoot, "log.md"), logContent, "utf8");
2520
- fs13.writeFileSync(path13.join(wikiRoot, "active-sprint.md"), compile(items, templateDir), "utf8");
2521
- fs13.writeFileSync(path13.join(wikiRoot, "open-gates.md"), compile2(items, templateDir), "utf8");
2522
- fs13.writeFileSync(path13.join(wikiRoot, "product-state.md"), compile3(items, templateDir), "utf8");
2523
- fs13.writeFileSync(path13.join(wikiRoot, "roadmap.md"), compile4(items, templateDir), "utf8");
2568
+ fs14.writeFileSync(path14.join(wikiRoot, "log.md"), logContent, "utf8");
2569
+ fs14.writeFileSync(path14.join(wikiRoot, "active-sprint.md"), compile(items, templateDir), "utf8");
2570
+ fs14.writeFileSync(path14.join(wikiRoot, "open-gates.md"), compile2(items, templateDir), "utf8");
2571
+ fs14.writeFileSync(path14.join(wikiRoot, "product-state.md"), compile3(items, templateDir), "utf8");
2572
+ fs14.writeFileSync(path14.join(wikiRoot, "roadmap.md"), compile4(items, templateDir), "utf8");
2524
2573
  stdout(`wiki build: OK (${pagesWritten} pages written)
2525
2574
  `);
2526
2575
  }
@@ -2687,7 +2736,7 @@ function buildLog(items, timestamp) {
2687
2736
  init_cjs_shims();
2688
2737
  var import_promises2 = require("fs/promises");
2689
2738
  var import_node_fs = require("fs");
2690
- var path14 = __toESM(require("path"), 1);
2739
+ var path15 = __toESM(require("path"), 1);
2691
2740
 
2692
2741
  // src/lib/sha256.ts
2693
2742
  init_cjs_shims();
@@ -2711,23 +2760,23 @@ function shortHash(full) {
2711
2760
  // src/lib/manifest.ts
2712
2761
  function resolveDefaultPackageRoot() {
2713
2762
  const here = new URL(".", importMetaUrl).pathname;
2714
- const distCandidate = path14.join(here, "MANIFEST.json");
2763
+ const distCandidate = path15.join(here, "MANIFEST.json");
2715
2764
  if ((0, import_node_fs.existsSync)(distCandidate)) {
2716
2765
  return here;
2717
2766
  }
2718
- const oneLevelUp = path14.join(here, "..", "MANIFEST.json");
2767
+ const oneLevelUp = path15.join(here, "..", "MANIFEST.json");
2719
2768
  if ((0, import_node_fs.existsSync)(oneLevelUp)) {
2720
- return path14.join(here, "..");
2769
+ return path15.join(here, "..");
2721
2770
  }
2722
- const devCandidate = path14.join(here, "..", "..", "..", "cleargate-planning", "MANIFEST.json");
2771
+ const devCandidate = path15.join(here, "..", "..", "..", "cleargate-planning", "MANIFEST.json");
2723
2772
  if ((0, import_node_fs.existsSync)(devCandidate)) {
2724
- return path14.join(here, "..", "..", "..", "cleargate-planning");
2773
+ return path15.join(here, "..", "..", "..", "cleargate-planning");
2725
2774
  }
2726
2775
  return here;
2727
2776
  }
2728
2777
  function loadPackageManifest(opts) {
2729
2778
  const packageRoot = opts?.packageRoot ?? resolveDefaultPackageRoot();
2730
- const manifestPath = path14.join(packageRoot, "MANIFEST.json");
2779
+ const manifestPath = path15.join(packageRoot, "MANIFEST.json");
2731
2780
  if (!(0, import_node_fs.existsSync)(manifestPath)) {
2732
2781
  throw new Error(
2733
2782
  `MANIFEST.json not found at ${manifestPath}; run 'npm run build' to generate it.`
@@ -2744,7 +2793,7 @@ function loadPackageManifest(opts) {
2744
2793
  return JSON.parse(raw);
2745
2794
  }
2746
2795
  async function loadInstallSnapshot(projectRoot) {
2747
- const snapshotPath = path14.join(projectRoot, ".cleargate", ".install-manifest.json");
2796
+ const snapshotPath = path15.join(projectRoot, ".cleargate", ".install-manifest.json");
2748
2797
  try {
2749
2798
  const raw = await (0, import_promises2.readFile)(snapshotPath, "utf-8");
2750
2799
  return JSON.parse(raw);
@@ -2753,7 +2802,7 @@ async function loadInstallSnapshot(projectRoot) {
2753
2802
  }
2754
2803
  }
2755
2804
  async function computeCurrentSha(file, projectRoot) {
2756
- const filePath = path14.join(projectRoot, file.path);
2805
+ const filePath = path15.join(projectRoot, file.path);
2757
2806
  try {
2758
2807
  const raw = await (0, import_promises2.readFile)(filePath);
2759
2808
  return hashNormalized(raw);
@@ -2782,8 +2831,8 @@ function classify(pkgSha, installSha, currentSha, tier) {
2782
2831
  return "both-changed";
2783
2832
  }
2784
2833
  async function writeDriftState(projectRoot, state2, opts) {
2785
- const cleargatDir = path14.join(projectRoot, ".cleargate");
2786
- const finalPath = path14.join(cleargatDir, ".drift-state.json");
2834
+ const cleargatDir = path15.join(projectRoot, ".cleargate");
2835
+ const finalPath = path15.join(cleargatDir, ".drift-state.json");
2787
2836
  const tmpPath = `${finalPath}.tmp`;
2788
2837
  const lastRefreshed = opts?.lastRefreshed ?? (/* @__PURE__ */ new Date()).toISOString();
2789
2838
  const fileContent = { last_refreshed: lastRefreshed, drift: state2 };
@@ -2792,7 +2841,7 @@ async function writeDriftState(projectRoot, state2, opts) {
2792
2841
  await (0, import_promises2.rename)(tmpPath, finalPath);
2793
2842
  }
2794
2843
  async function readDriftState(projectRoot) {
2795
- const driftPath = path14.join(projectRoot, ".cleargate", ".drift-state.json");
2844
+ const driftPath = path15.join(projectRoot, ".cleargate", ".drift-state.json");
2796
2845
  try {
2797
2846
  const raw = await (0, import_promises2.readFile)(driftPath, "utf-8");
2798
2847
  const parsed = JSON.parse(raw);
@@ -2867,24 +2916,24 @@ async function promptEmail(question, defaultValue, opts) {
2867
2916
 
2868
2917
  // src/lib/identity.ts
2869
2918
  init_cjs_shims();
2870
- var fs14 = __toESM(require("fs"), 1);
2871
- var path15 = __toESM(require("path"), 1);
2919
+ var fs15 = __toESM(require("fs"), 1);
2920
+ var path16 = __toESM(require("path"), 1);
2872
2921
  var fsPromises = __toESM(require("fs/promises"), 1);
2873
2922
  var os5 = __toESM(require("os"), 1);
2874
2923
  var import_node_child_process2 = require("child_process");
2875
2924
  function readParticipant(projectRoot) {
2876
- const filePath = path15.join(projectRoot, ".cleargate", ".participant.json");
2925
+ const filePath = path16.join(projectRoot, ".cleargate", ".participant.json");
2877
2926
  try {
2878
- const raw = fs14.readFileSync(filePath, "utf8");
2927
+ const raw = fs15.readFileSync(filePath, "utf8");
2879
2928
  return JSON.parse(raw);
2880
2929
  } catch {
2881
2930
  return null;
2882
2931
  }
2883
2932
  }
2884
2933
  async function writeParticipant(projectRoot, email, source, now = () => (/* @__PURE__ */ new Date()).toISOString()) {
2885
- const cleargateDir = path15.join(projectRoot, ".cleargate");
2934
+ const cleargateDir = path16.join(projectRoot, ".cleargate");
2886
2935
  await fsPromises.mkdir(cleargateDir, { recursive: true });
2887
- const filePath = path15.join(cleargateDir, ".participant.json");
2936
+ const filePath = path16.join(cleargateDir, ".participant.json");
2888
2937
  const tmpPath = filePath + ".tmp." + Date.now();
2889
2938
  const content = {
2890
2939
  email,
@@ -2960,16 +3009,16 @@ var HOOK_ADDITION = {
2960
3009
  };
2961
3010
  function resolveDefaultPayloadDir() {
2962
3011
  const thisFile = (0, import_node_url5.fileURLToPath)(importMetaUrl);
2963
- const pkgRoot = path16.resolve(path16.dirname(thisFile), "..");
2964
- return path16.join(pkgRoot, "templates", "cleargate-planning");
3012
+ const pkgRoot = path17.resolve(path17.dirname(thisFile), "..");
3013
+ return path17.join(pkgRoot, "templates", "cleargate-planning");
2965
3014
  }
2966
3015
  function countDeliveryItems(cwd) {
2967
- const pendingSync = path16.join(cwd, ".cleargate", "delivery", "pending-sync");
2968
- const archive = path16.join(cwd, ".cleargate", "delivery", "archive");
3016
+ const pendingSync = path17.join(cwd, ".cleargate", "delivery", "pending-sync");
3017
+ const archive = path17.join(cwd, ".cleargate", "delivery", "archive");
2969
3018
  let count = 0;
2970
3019
  for (const dir of [pendingSync, archive]) {
2971
- if (!fs15.existsSync(dir)) continue;
2972
- const entries = fs15.readdirSync(dir);
3020
+ if (!fs16.existsSync(dir)) continue;
3021
+ const entries = fs16.readdirSync(dir);
2973
3022
  for (const f of entries) {
2974
3023
  if (f.endsWith(".md") && f !== ".gitkeep") count++;
2975
3024
  }
@@ -2978,12 +3027,12 @@ function countDeliveryItems(cwd) {
2978
3027
  }
2979
3028
  function writeAtomic(filePath, content) {
2980
3029
  const tmpPath = filePath + ".tmp." + Date.now();
2981
- fs15.writeFileSync(tmpPath, content, "utf8");
2982
- fs15.renameSync(tmpPath, filePath);
3030
+ fs16.writeFileSync(tmpPath, content, "utf8");
3031
+ fs16.renameSync(tmpPath, filePath);
2983
3032
  }
2984
3033
  function readPackageVersion(packageJsonPath) {
2985
3034
  try {
2986
- const raw = fs15.readFileSync(packageJsonPath, "utf8");
3035
+ const raw = fs16.readFileSync(packageJsonPath, "utf8");
2987
3036
  const pkg = JSON.parse(raw);
2988
3037
  if (typeof pkg.version === "string" && pkg.version.length > 0) {
2989
3038
  return pkg.version;
@@ -3003,16 +3052,16 @@ async function initHandler(opts = {}) {
3003
3052
  const promptYesNoFn = opts.promptYesNo ?? promptYesNo;
3004
3053
  const promptEmailFn = opts.promptEmail ?? promptEmail;
3005
3054
  const spawnSyncFn = opts.spawnSyncFn ?? import_node_child_process3.spawnSync;
3006
- if (!fs15.existsSync(cwd)) {
3055
+ if (!fs16.existsSync(cwd)) {
3007
3056
  stderr(`[cleargate init] ERROR: target directory does not exist: ${cwd}
3008
3057
  `);
3009
3058
  exit(1);
3010
3059
  return;
3011
3060
  }
3012
- const testWritePath = path16.join(cwd, `.cleargate-init-write-test-${Date.now()}`);
3061
+ const testWritePath = path17.join(cwd, `.cleargate-init-write-test-${Date.now()}`);
3013
3062
  try {
3014
- fs15.writeFileSync(testWritePath, "");
3015
- fs15.unlinkSync(testWritePath);
3063
+ fs16.writeFileSync(testWritePath, "");
3064
+ fs16.unlinkSync(testWritePath);
3016
3065
  } catch {
3017
3066
  stderr(`[cleargate init] ERROR: target directory is not writable: ${cwd}
3018
3067
  `);
@@ -3022,7 +3071,7 @@ async function initHandler(opts = {}) {
3022
3071
  stdout(`[cleargate init] Target: ${cwd}
3023
3072
  `);
3024
3073
  const payloadDir = opts.payloadDir ?? resolveDefaultPayloadDir();
3025
- if (!fs15.existsSync(payloadDir)) {
3074
+ if (!fs16.existsSync(payloadDir)) {
3026
3075
  stderr(`[cleargate init] ERROR: payload directory not found: ${payloadDir}
3027
3076
  `);
3028
3077
  stderr(`[cleargate init] Run \`npm run prebuild\` to copy the payload first.
@@ -3030,12 +3079,12 @@ async function initHandler(opts = {}) {
3030
3079
  exit(1);
3031
3080
  return;
3032
3081
  }
3033
- const uninstalledMarkerPath = path16.join(cwd, ".cleargate", ".uninstalled");
3082
+ const uninstalledMarkerPath = path17.join(cwd, ".cleargate", ".uninstalled");
3034
3083
  let uninstalledMarker = null;
3035
3084
  let userChoseRestore = false;
3036
- if (fs15.existsSync(uninstalledMarkerPath)) {
3085
+ if (fs16.existsSync(uninstalledMarkerPath)) {
3037
3086
  try {
3038
- const raw = fs15.readFileSync(uninstalledMarkerPath, "utf8");
3087
+ const raw = fs16.readFileSync(uninstalledMarkerPath, "utf8");
3039
3088
  uninstalledMarker = JSON.parse(raw);
3040
3089
  } catch {
3041
3090
  stderr(`[cleargate init] WARNING: .uninstalled marker is malformed; ignoring it.
@@ -3047,8 +3096,8 @@ async function initHandler(opts = {}) {
3047
3096
  userChoseRestore = await promptYesNoFn(question, true);
3048
3097
  if (userChoseRestore) {
3049
3098
  for (const preservedPath of preserved) {
3050
- const absPreserved = path16.isAbsolute(preservedPath) ? preservedPath : path16.join(cwd, preservedPath);
3051
- if (fs15.existsSync(absPreserved)) {
3099
+ const absPreserved = path17.isAbsolute(preservedPath) ? preservedPath : path17.join(cwd, preservedPath);
3100
+ if (fs16.existsSync(absPreserved)) {
3052
3101
  stdout(`[cleargate init] [preserved] ${preservedPath}
3053
3102
  `);
3054
3103
  } else {
@@ -3068,8 +3117,8 @@ async function initHandler(opts = {}) {
3068
3117
  if (opts.pin) {
3069
3118
  pinVersion = opts.pin;
3070
3119
  } else {
3071
- const payloadParent = path16.resolve(payloadDir, "..", "..");
3072
- pinVersion = readPackageVersion(path16.join(payloadParent, "package.json")) ?? readPackageVersion(path16.join(path16.dirname((0, import_node_url5.fileURLToPath)(importMetaUrl)), "..", "package.json")) ?? "latest";
3120
+ const payloadParent = path17.resolve(payloadDir, "..", "..");
3121
+ pinVersion = readPackageVersion(path17.join(payloadParent, "package.json")) ?? readPackageVersion(path17.join(path17.dirname((0, import_node_url5.fileURLToPath)(importMetaUrl)), "..", "package.json")) ?? "latest";
3073
3122
  }
3074
3123
  const copyReport = copyPayload(payloadDir, cwd, { force, pinVersion });
3075
3124
  for (const action of copyReport.actions) {
@@ -3077,33 +3126,33 @@ async function initHandler(opts = {}) {
3077
3126
  stdout(`[cleargate init] ${verb} ${action.relPath}
3078
3127
  `);
3079
3128
  }
3080
- const settingsPath = path16.join(cwd, ".claude", "settings.json");
3129
+ const settingsPath = path17.join(cwd, ".claude", "settings.json");
3081
3130
  let existingSettings = null;
3082
- if (fs15.existsSync(settingsPath)) {
3131
+ if (fs16.existsSync(settingsPath)) {
3083
3132
  try {
3084
- existingSettings = JSON.parse(fs15.readFileSync(settingsPath, "utf8"));
3133
+ existingSettings = JSON.parse(fs16.readFileSync(settingsPath, "utf8"));
3085
3134
  } catch {
3086
3135
  stderr(`[cleargate init] WARNING: could not parse ${settingsPath}; treating as empty.
3087
3136
  `);
3088
3137
  }
3089
3138
  }
3090
3139
  const mergedSettings = mergeSettings(existingSettings, HOOK_ADDITION);
3091
- fs15.mkdirSync(path16.dirname(settingsPath), { recursive: true });
3140
+ fs16.mkdirSync(path17.dirname(settingsPath), { recursive: true });
3092
3141
  writeAtomic(settingsPath, JSON.stringify(mergedSettings, null, 2) + "\n");
3093
3142
  stdout(`[cleargate init] Updated .claude/settings.json: merged PostToolUse hook
3094
3143
  `);
3095
- const claudeMdPath = path16.join(cwd, "CLAUDE.md");
3096
- const claudeMdSrcPath = path16.join(payloadDir, "CLAUDE.md");
3144
+ const claudeMdPath = path17.join(cwd, "CLAUDE.md");
3145
+ const claudeMdSrcPath = path17.join(payloadDir, "CLAUDE.md");
3097
3146
  let claudeMdBlock;
3098
3147
  try {
3099
- const claudeMdSrc = fs15.readFileSync(claudeMdSrcPath, "utf8");
3148
+ const claudeMdSrc = fs16.readFileSync(claudeMdSrcPath, "utf8");
3100
3149
  claudeMdBlock = extractBlock(claudeMdSrc);
3101
3150
  } catch (e) {
3102
3151
  stderr(`[cleargate init] WARNING: could not read CLAUDE.md block from payload: ${String(e)}
3103
3152
  `);
3104
3153
  claudeMdBlock = "<!-- CLEARGATE:START -->\n<!-- CLEARGATE:END -->";
3105
3154
  }
3106
- const existingClaudeMd = fs15.existsSync(claudeMdPath) ? fs15.readFileSync(claudeMdPath, "utf8") : null;
3155
+ const existingClaudeMd = fs16.existsSync(claudeMdPath) ? fs16.readFileSync(claudeMdPath, "utf8") : null;
3107
3156
  const newClaudeMd = injectClaudeMd(existingClaudeMd, claudeMdBlock);
3108
3157
  writeAtomic(claudeMdPath, newClaudeMd);
3109
3158
  if (existingClaudeMd === null) {
@@ -3114,6 +3163,26 @@ async function initHandler(opts = {}) {
3114
3163
  `);
3115
3164
  } else {
3116
3165
  stdout(`[cleargate init] CLAUDE.md unchanged (block already up to date)
3166
+ `);
3167
+ }
3168
+ try {
3169
+ const action = injectMcpJson(cwd);
3170
+ if (action === "created") {
3171
+ stdout(
3172
+ `[cleargate init] Created .mcp.json (cleargate MCP server registered) \u2014 restart Claude Code to load it.
3173
+ `
3174
+ );
3175
+ } else if (action === "updated") {
3176
+ stdout(
3177
+ `[cleargate init] Updated .mcp.json (cleargate MCP server entry merged) \u2014 restart Claude Code to pick up changes.
3178
+ `
3179
+ );
3180
+ } else {
3181
+ stdout(`[cleargate init] .mcp.json unchanged (cleargate entry already present)
3182
+ `);
3183
+ }
3184
+ } catch (e) {
3185
+ stderr(`[cleargate init] WARNING: ${String(e instanceof Error ? e.message : e)}
3117
3186
  `);
3118
3187
  }
3119
3188
  const itemCount = countDeliveryItems(cwd);
@@ -3127,9 +3196,9 @@ async function initHandler(opts = {}) {
3127
3196
  stdout(`[cleargate init] Bootstrap: no items to ingest, skipping build
3128
3197
  `);
3129
3198
  }
3130
- const cleargateDir = path16.join(cwd, ".cleargate");
3131
- fs15.mkdirSync(cleargateDir, { recursive: true });
3132
- const snapshotPath = path16.join(cleargateDir, ".install-manifest.json");
3199
+ const cleargateDir = path17.join(cwd, ".cleargate");
3200
+ fs16.mkdirSync(cleargateDir, { recursive: true });
3201
+ const snapshotPath = path17.join(cleargateDir, ".install-manifest.json");
3133
3202
  try {
3134
3203
  const readManifest = opts.readInstallManifest ?? (() => loadPackageManifest({ packageRoot: payloadDir }));
3135
3204
  const pkgManifest = readManifest();
@@ -3144,19 +3213,19 @@ async function initHandler(opts = {}) {
3144
3213
  stderr(`[cleargate init] WARNING: could not write install snapshot: ${String(e)}
3145
3214
  `);
3146
3215
  }
3147
- if (uninstalledMarker !== null && fs15.existsSync(uninstalledMarkerPath)) {
3216
+ if (uninstalledMarker !== null && fs16.existsSync(uninstalledMarkerPath)) {
3148
3217
  try {
3149
- fs15.unlinkSync(uninstalledMarkerPath);
3218
+ fs16.unlinkSync(uninstalledMarkerPath);
3150
3219
  } catch (e) {
3151
3220
  stderr(`[cleargate init] WARNING: could not remove .uninstalled marker: ${String(e)}
3152
3221
  `);
3153
3222
  }
3154
3223
  }
3155
3224
  {
3156
- const distCliPath = path16.join(cwd, "cleargate-cli", "dist", "cli.js");
3225
+ const distCliPath = path17.join(cwd, "cleargate-cli", "dist", "cli.js");
3157
3226
  let branch = null;
3158
3227
  let branchLabel = "";
3159
- if (fs15.existsSync(distCliPath)) {
3228
+ if (fs16.existsSync(distCliPath)) {
3160
3229
  branch = { cmd: "node", args: [distCliPath, "--version"] };
3161
3230
  branchLabel = `local dist (${distCliPath})`;
3162
3231
  } else {
@@ -3228,8 +3297,8 @@ async function initHandler(opts = {}) {
3228
3297
 
3229
3298
  // src/commands/wiki-ingest.ts
3230
3299
  init_cjs_shims();
3231
- var fs16 = __toESM(require("fs"), 1);
3232
- var path17 = __toESM(require("path"), 1);
3300
+ var fs17 = __toESM(require("fs"), 1);
3301
+ var path18 = __toESM(require("path"), 1);
3233
3302
  var import_node_child_process4 = require("child_process");
3234
3303
  var EXCLUDED_SUFFIXES2 = [
3235
3304
  ".cleargate/knowledge/",
@@ -3255,16 +3324,16 @@ async function wikiIngestHandler(opts) {
3255
3324
  const stderr = opts.stderr ?? ((s) => process.stderr.write(s));
3256
3325
  const exit = opts.exit ?? ((c) => process.exit(c));
3257
3326
  const gitRunner = opts.gitRunner;
3258
- const rename12 = opts.rename ?? fs16.renameSync;
3327
+ const rename12 = opts.rename ?? fs17.renameSync;
3259
3328
  const templateDir = opts.templateDir;
3260
3329
  const rawPath = opts.rawPath;
3261
- const absRawPath = path17.isAbsolute(rawPath) ? rawPath : path17.resolve(cwd, rawPath);
3262
- const relRawPath = path17.relative(cwd, absRawPath).replace(/\\/g, "/");
3263
- const deliveryRoot = path17.join(cwd, ".cleargate", "delivery");
3330
+ const absRawPath = path18.isAbsolute(rawPath) ? rawPath : path18.resolve(cwd, rawPath);
3331
+ const relRawPath = path18.relative(cwd, absRawPath).replace(/\\/g, "/");
3332
+ const deliveryRoot = path18.join(cwd, ".cleargate", "delivery");
3264
3333
  const deliveryRootNorm = deliveryRoot.replace(/\\/g, "/");
3265
3334
  const absDeliveryRoot = deliveryRoot;
3266
- const relToDelivery = path17.relative(absDeliveryRoot, absRawPath);
3267
- if (relToDelivery.startsWith("..") || path17.isAbsolute(relToDelivery)) {
3335
+ const relToDelivery = path18.relative(absDeliveryRoot, absRawPath);
3336
+ if (relToDelivery.startsWith("..") || path18.isAbsolute(relToDelivery)) {
3268
3337
  stderr(`wiki ingest: ${rawPath} not under .cleargate/delivery/
3269
3338
  `);
3270
3339
  exit(2);
@@ -3278,7 +3347,7 @@ async function wikiIngestHandler(opts) {
3278
3347
  exit(0);
3279
3348
  return;
3280
3349
  }
3281
- const filename = path17.basename(absRawPath);
3350
+ const filename = path18.basename(absRawPath);
3282
3351
  let bucketInfo;
3283
3352
  try {
3284
3353
  bucketInfo = deriveBucket(filename);
@@ -3298,12 +3367,12 @@ async function wikiIngestHandler(opts) {
3298
3367
  return;
3299
3368
  }
3300
3369
  const { type, id, bucket } = bucketInfo;
3301
- const wikiRoot = path17.join(cwd, ".cleargate", "wiki");
3302
- const pageDir = path17.join(wikiRoot, bucket);
3303
- const pagePath = path17.join(pageDir, `${id}.md`);
3370
+ const wikiRoot = path18.join(cwd, ".cleargate", "wiki");
3371
+ const pageDir = path18.join(wikiRoot, bucket);
3372
+ const pagePath = path18.join(pageDir, `${id}.md`);
3304
3373
  let rawContent;
3305
3374
  try {
3306
- rawContent = fs16.readFileSync(absRawPath, "utf8");
3375
+ rawContent = fs17.readFileSync(absRawPath, "utf8");
3307
3376
  } catch (e) {
3308
3377
  stderr(`wiki ingest: cannot read ${rawPath}: ${e.message}
3309
3378
  `);
@@ -3323,11 +3392,11 @@ async function wikiIngestHandler(opts) {
3323
3392
  return;
3324
3393
  }
3325
3394
  const currentSha = getGitSha(absRawPath, gitRunner) ?? "";
3326
- const pageExists = fs16.existsSync(pagePath);
3395
+ const pageExists = fs17.existsSync(pagePath);
3327
3396
  if (pageExists && currentSha !== "") {
3328
3397
  let isNoOp = false;
3329
3398
  try {
3330
- const existingPageContent = fs16.readFileSync(pagePath, "utf8");
3399
+ const existingPageContent = fs17.readFileSync(pagePath, "utf8");
3331
3400
  const existingPage = parsePage(existingPageContent);
3332
3401
  if (existingPage.last_ingest_commit === currentSha) {
3333
3402
  const contentUnchanged = checkContentUnchanged(absRawPath, currentSha, relRawPath, gitRunner);
@@ -3362,8 +3431,8 @@ async function wikiIngestHandler(opts) {
3362
3431
  };
3363
3432
  const pageBody = buildPageBody2({ id, fm, body });
3364
3433
  const pageContent = serializePage(wikiPage, pageBody);
3365
- fs16.mkdirSync(pageDir, { recursive: true });
3366
- fs16.writeFileSync(pagePath, pageContent, "utf8");
3434
+ fs17.mkdirSync(pageDir, { recursive: true });
3435
+ fs17.writeFileSync(pagePath, pageContent, "utf8");
3367
3436
  appendLogEntry(wikiRoot, { timestamp, action, id, relRawPath });
3368
3437
  updateIndex(wikiRoot, { id, type, status: wikiPage.status, relRawPath, rename: rename12 });
3369
3438
  recompileSynthesis(wikiRoot, cwd, templateDir);
@@ -3375,7 +3444,7 @@ function checkContentUnchanged(absRawPath, sha, relRawPath, gitRunner) {
3375
3444
  const run = gitRunner ?? defaultGitRunner;
3376
3445
  const gitContent = run("git", ["show", `${sha}:${relRawPath}`]);
3377
3446
  if (!gitContent && gitContent !== "") return false;
3378
- const currentContent = fs16.readFileSync(absRawPath, "utf8");
3447
+ const currentContent = fs17.readFileSync(absRawPath, "utf8");
3379
3448
  return gitContent === currentContent;
3380
3449
  } catch {
3381
3450
  return false;
@@ -3428,7 +3497,7 @@ function buildPageBody2(item) {
3428
3497
  ].join("\n");
3429
3498
  }
3430
3499
  function appendLogEntry(wikiRoot, entry) {
3431
- const logPath = path17.join(wikiRoot, "log.md");
3500
+ const logPath = path18.join(wikiRoot, "log.md");
3432
3501
  const logEntry = [
3433
3502
  `- timestamp: "${entry.timestamp}"`,
3434
3503
  ` actor: "cleargate wiki ingest"`,
@@ -3436,25 +3505,25 @@ function appendLogEntry(wikiRoot, entry) {
3436
3505
  ` target: "${entry.id}"`,
3437
3506
  ` path: "${entry.relRawPath}"`
3438
3507
  ].join("\n");
3439
- if (fs16.existsSync(logPath)) {
3440
- const existing = fs16.readFileSync(logPath, "utf8");
3508
+ if (fs17.existsSync(logPath)) {
3509
+ const existing = fs17.readFileSync(logPath, "utf8");
3441
3510
  const newContent = existing.trimEnd() + "\n" + logEntry + "\n";
3442
- fs16.writeFileSync(logPath, newContent, "utf8");
3511
+ fs17.writeFileSync(logPath, newContent, "utf8");
3443
3512
  } else {
3444
- fs16.mkdirSync(wikiRoot, { recursive: true });
3445
- fs16.writeFileSync(logPath, `# Wiki Event Log
3513
+ fs17.mkdirSync(wikiRoot, { recursive: true });
3514
+ fs17.writeFileSync(logPath, `# Wiki Event Log
3446
3515
 
3447
3516
  ${logEntry}
3448
3517
  `, "utf8");
3449
3518
  }
3450
3519
  }
3451
3520
  function updateIndex(wikiRoot, opts) {
3452
- const indexPath = path17.join(wikiRoot, "index.md");
3521
+ const indexPath = path18.join(wikiRoot, "index.md");
3453
3522
  const tmpPath = `${indexPath}.tmp`;
3454
3523
  const newRow = `| [[${opts.id}]] | ${opts.type} | ${opts.status} | ${opts.relRawPath} |`;
3455
3524
  let content;
3456
- if (fs16.existsSync(indexPath)) {
3457
- content = fs16.readFileSync(indexPath, "utf8");
3525
+ if (fs17.existsSync(indexPath)) {
3526
+ content = fs17.readFileSync(indexPath, "utf8");
3458
3527
  const idPattern = `[[${opts.id}]]`;
3459
3528
  const lines = content.split("\n");
3460
3529
  let replaced = false;
@@ -3473,7 +3542,7 @@ function updateIndex(wikiRoot, opts) {
3473
3542
  } else {
3474
3543
  content = buildMinimalIndex(opts.id, opts.type, opts.status, opts.relRawPath);
3475
3544
  }
3476
- fs16.writeFileSync(tmpPath, content, "utf8");
3545
+ fs17.writeFileSync(tmpPath, content, "utf8");
3477
3546
  opts.rename(tmpPath, indexPath);
3478
3547
  }
3479
3548
  function insertIntoSection(content, id, newRow) {
@@ -3568,41 +3637,41 @@ function buildMinimalIndex(id, type, status, relRawPath) {
3568
3637
  return lines.join("\n");
3569
3638
  }
3570
3639
  function recompileSynthesis(wikiRoot, cwd, templateDir) {
3571
- const deliveryRoot = path17.join(cwd, ".cleargate", "delivery");
3640
+ const deliveryRoot = path18.join(cwd, ".cleargate", "delivery");
3572
3641
  let items = [];
3573
- if (fs16.existsSync(deliveryRoot)) {
3642
+ if (fs17.existsSync(deliveryRoot)) {
3574
3643
  try {
3575
3644
  items = scanRawItems(deliveryRoot, cwd);
3576
3645
  } catch {
3577
3646
  }
3578
3647
  }
3579
- fs16.writeFileSync(path17.join(wikiRoot, "active-sprint.md"), compile(items, templateDir), "utf8");
3580
- fs16.writeFileSync(path17.join(wikiRoot, "open-gates.md"), compile2(items, templateDir), "utf8");
3581
- fs16.writeFileSync(path17.join(wikiRoot, "product-state.md"), compile3(items, templateDir), "utf8");
3582
- fs16.writeFileSync(path17.join(wikiRoot, "roadmap.md"), compile4(items, templateDir), "utf8");
3648
+ fs17.writeFileSync(path18.join(wikiRoot, "active-sprint.md"), compile(items, templateDir), "utf8");
3649
+ fs17.writeFileSync(path18.join(wikiRoot, "open-gates.md"), compile2(items, templateDir), "utf8");
3650
+ fs17.writeFileSync(path18.join(wikiRoot, "product-state.md"), compile3(items, templateDir), "utf8");
3651
+ fs17.writeFileSync(path18.join(wikiRoot, "roadmap.md"), compile4(items, templateDir), "utf8");
3583
3652
  }
3584
3653
 
3585
3654
  // src/commands/wiki-lint.ts
3586
3655
  init_cjs_shims();
3587
- var path21 = __toESM(require("path"), 1);
3656
+ var path22 = __toESM(require("path"), 1);
3588
3657
 
3589
3658
  // src/wiki/load-wiki.ts
3590
3659
  init_cjs_shims();
3591
- var fs17 = __toESM(require("fs"), 1);
3592
- var path18 = __toESM(require("path"), 1);
3660
+ var fs18 = __toESM(require("fs"), 1);
3661
+ var path19 = __toESM(require("path"), 1);
3593
3662
  var BUCKET_DIRS = ["epics", "stories", "sprints", "proposals", "crs", "bugs", "topics"];
3594
3663
  function loadWikiPages(wikiRoot) {
3595
3664
  const results = [];
3596
3665
  for (const bucket of BUCKET_DIRS) {
3597
- const dir = path18.join(wikiRoot, bucket);
3598
- if (!fs17.existsSync(dir)) continue;
3599
- const entries = fs17.readdirSync(dir, { encoding: "utf8" });
3666
+ const dir = path19.join(wikiRoot, bucket);
3667
+ if (!fs18.existsSync(dir)) continue;
3668
+ const entries = fs18.readdirSync(dir, { encoding: "utf8" });
3600
3669
  for (const filename of entries) {
3601
3670
  if (!filename.endsWith(".md")) continue;
3602
- const absPath = path18.join(dir, filename);
3603
- const stat = fs17.statSync(absPath);
3671
+ const absPath = path19.join(dir, filename);
3672
+ const stat = fs18.statSync(absPath);
3604
3673
  if (!stat.isFile()) continue;
3605
- const raw = fs17.readFileSync(absPath, "utf8");
3674
+ const raw = fs18.readFileSync(absPath, "utf8");
3606
3675
  let fm;
3607
3676
  let body;
3608
3677
  try {
@@ -3632,8 +3701,8 @@ function loadWikiPages(wikiRoot) {
3632
3701
 
3633
3702
  // src/wiki/lint-checks.ts
3634
3703
  init_cjs_shims();
3635
- var fs18 = __toESM(require("fs"), 1);
3636
- var path19 = __toESM(require("path"), 1);
3704
+ var fs19 = __toESM(require("fs"), 1);
3705
+ var path20 = __toESM(require("path"), 1);
3637
3706
  var import_node_child_process5 = require("child_process");
3638
3707
  var import_js_yaml3 = __toESM(require("js-yaml"), 1);
3639
3708
 
@@ -3693,9 +3762,9 @@ function checkOrphan(page, repoRoot) {
3693
3762
  if (!rawPath) return null;
3694
3763
  const isExcluded = EXCLUDED_DIRS.some((excl) => rawPath.startsWith(excl));
3695
3764
  if (isExcluded) return null;
3696
- const absRaw = path19.join(repoRoot, rawPath);
3697
- if (!fs18.existsSync(absRaw)) {
3698
- const relPage = path19.relative(path19.join(repoRoot, ".cleargate", "wiki"), page.absPath).replace(/\\/g, "/");
3765
+ const absRaw = path20.join(repoRoot, rawPath);
3766
+ if (!fs19.existsSync(absRaw)) {
3767
+ const relPage = path20.relative(path20.join(repoRoot, ".cleargate", "wiki"), page.absPath).replace(/\\/g, "/");
3699
3768
  return {
3700
3769
  category: "orphan",
3701
3770
  line: `orphan: ${relPage} -> missing ${rawPath} (raw missing)`
@@ -3713,7 +3782,7 @@ function checkRepoMismatch(page, repoRoot) {
3713
3782
  return null;
3714
3783
  }
3715
3784
  if (page.page.repo !== derivedRepo) {
3716
- const relPage = path19.relative(path19.join(repoRoot, ".cleargate", "wiki"), page.absPath).replace(/\\/g, "/");
3785
+ const relPage = path20.relative(path20.join(repoRoot, ".cleargate", "wiki"), page.absPath).replace(/\\/g, "/");
3717
3786
  return {
3718
3787
  category: "repo-mismatch",
3719
3788
  line: `repo-mismatch: ${relPage} declares repo:${page.page.repo} but raw_path implies repo:${derivedRepo}`
@@ -3738,7 +3807,7 @@ function checkStaleCommit(page, repoRoot, gitRunner) {
3738
3807
  }
3739
3808
  if (!currentSha) return null;
3740
3809
  if (storedSha !== currentSha) {
3741
- const relPage = path19.relative(path19.join(repoRoot, ".cleargate", "wiki"), page.absPath).replace(/\\/g, "/");
3810
+ const relPage = path20.relative(path20.join(repoRoot, ".cleargate", "wiki"), page.absPath).replace(/\\/g, "/");
3742
3811
  return {
3743
3812
  category: "stale-commit",
3744
3813
  line: `stale-commit: ${relPage} at ${storedSha}, current ${currentSha}`
@@ -3749,14 +3818,14 @@ function checkStaleCommit(page, repoRoot, gitRunner) {
3749
3818
  function checkMissingIngest(page, repoRoot) {
3750
3819
  const rawPath = page.page.raw_path;
3751
3820
  if (!rawPath) return null;
3752
- const absRaw = path19.join(repoRoot, rawPath);
3753
- if (!fs18.existsSync(absRaw)) return null;
3754
- const rawStat = fs18.statSync(absRaw);
3755
- const pageStat = fs18.statSync(page.absPath);
3821
+ const absRaw = path20.join(repoRoot, rawPath);
3822
+ if (!fs19.existsSync(absRaw)) return null;
3823
+ const rawStat = fs19.statSync(absRaw);
3824
+ const pageStat = fs19.statSync(page.absPath);
3756
3825
  const rawMtimeMs = rawStat.mtimeMs;
3757
3826
  const pageMtimeMs = pageStat.mtimeMs;
3758
3827
  if (rawMtimeMs - pageMtimeMs > 2e3) {
3759
- const relPage = path19.relative(path19.join(repoRoot, ".cleargate", "wiki"), page.absPath).replace(/\\/g, "/");
3828
+ const relPage = path20.relative(path20.join(repoRoot, ".cleargate", "wiki"), page.absPath).replace(/\\/g, "/");
3760
3829
  const rawMtime = rawStat.mtime.toISOString();
3761
3830
  const pageMtime = pageStat.mtime.toISOString();
3762
3831
  return {
@@ -3767,7 +3836,7 @@ function checkMissingIngest(page, repoRoot) {
3767
3836
  return null;
3768
3837
  }
3769
3838
  function checkBrokenBacklinks(pages, repoRoot) {
3770
- const wikiRoot = path19.join(repoRoot, ".cleargate", "wiki");
3839
+ const wikiRoot = path20.join(repoRoot, ".cleargate", "wiki");
3771
3840
  const byId = /* @__PURE__ */ new Map();
3772
3841
  for (const p of pages) {
3773
3842
  if (p.page.id) byId.set(p.page.id, p);
@@ -3781,7 +3850,7 @@ function checkBrokenBacklinks(pages, repoRoot) {
3781
3850
  const parentId = match[1];
3782
3851
  const parentPage = byId.get(parentId);
3783
3852
  if (!parentPage) {
3784
- const relChild = path19.relative(wikiRoot, childPage.absPath).replace(/\\/g, "/");
3853
+ const relChild = path20.relative(wikiRoot, childPage.absPath).replace(/\\/g, "/");
3785
3854
  findings.push({
3786
3855
  category: "broken-backlink",
3787
3856
  line: `broken-backlink: ${relChild} -> ${parentId} (parent missing child entry)`
@@ -3794,7 +3863,7 @@ function checkBrokenBacklinks(pages, repoRoot) {
3794
3863
  (c) => c === childRef || c === childId
3795
3864
  );
3796
3865
  if (!parentHasChild) {
3797
- const relChild = path19.relative(wikiRoot, childPage.absPath).replace(/\\/g, "/");
3866
+ const relChild = path20.relative(wikiRoot, childPage.absPath).replace(/\\/g, "/");
3798
3867
  findings.push({
3799
3868
  category: "broken-backlink",
3800
3869
  line: `broken-backlink: ${relChild} -> ${parentId} (parent missing child entry)`
@@ -3804,7 +3873,7 @@ function checkBrokenBacklinks(pages, repoRoot) {
3804
3873
  return findings;
3805
3874
  }
3806
3875
  function checkInvalidatedCitations(pages, repoRoot) {
3807
- const wikiRoot = path19.join(repoRoot, ".cleargate", "wiki");
3876
+ const wikiRoot = path20.join(repoRoot, ".cleargate", "wiki");
3808
3877
  const byId = /* @__PURE__ */ new Map();
3809
3878
  for (const p of pages) {
3810
3879
  if (p.page.id) byId.set(p.page.id, p);
@@ -3812,10 +3881,10 @@ function checkInvalidatedCitations(pages, repoRoot) {
3812
3881
  const findings = [];
3813
3882
  const topicPages = pages.filter((p) => p.page.type === "topic");
3814
3883
  for (const topicPage of topicPages) {
3815
- const relTopic = path19.relative(wikiRoot, topicPage.absPath).replace(/\\/g, "/");
3884
+ const relTopic = path20.relative(wikiRoot, topicPage.absPath).replace(/\\/g, "/");
3816
3885
  let citesList = [];
3817
3886
  try {
3818
- const raw = fs18.readFileSync(topicPage.absPath, "utf8");
3887
+ const raw = fs19.readFileSync(topicPage.absPath, "utf8");
3819
3888
  const { fm } = parseFrontmatter(raw);
3820
3889
  const rawCites = fm["cites"];
3821
3890
  if (Array.isArray(rawCites)) {
@@ -3851,7 +3920,7 @@ function checkExcludedPathIngested(page, repoRoot) {
3851
3920
  if (!rawPath) return null;
3852
3921
  const isExcluded = EXCLUDED_DIRS.some((excl) => rawPath.startsWith(excl));
3853
3922
  if (isExcluded) {
3854
- const relPage = path19.relative(path19.join(repoRoot, ".cleargate", "wiki"), page.absPath).replace(/\\/g, "/");
3923
+ const relPage = path20.relative(path20.join(repoRoot, ".cleargate", "wiki"), page.absPath).replace(/\\/g, "/");
3855
3924
  return {
3856
3925
  category: "excluded-path-ingested",
3857
3926
  line: `excluded-path-ingested: ${relPage} (raw_path ${rawPath} is under an excluded directory)`
@@ -3862,7 +3931,7 @@ function checkExcludedPathIngested(page, repoRoot) {
3862
3931
  function checkPaginationNeeded(pages) {
3863
3932
  const bucketCounts = /* @__PURE__ */ new Map();
3864
3933
  for (const p of pages) {
3865
- const bucket = path19.basename(path19.dirname(p.absPath));
3934
+ const bucket = path20.basename(path20.dirname(p.absPath));
3866
3935
  bucketCounts.set(bucket, (bucketCounts.get(bucket) ?? 0) + 1);
3867
3936
  }
3868
3937
  const findings = [];
@@ -3900,11 +3969,11 @@ function parseCachedGateResult(raw) {
3900
3969
  function checkGateFailure(page, repoRoot) {
3901
3970
  const rawPath = page.page.raw_path;
3902
3971
  if (!rawPath) return null;
3903
- const absRaw = path19.join(repoRoot, rawPath);
3904
- if (!fs18.existsSync(absRaw)) return null;
3972
+ const absRaw = path20.join(repoRoot, rawPath);
3973
+ if (!fs19.existsSync(absRaw)) return null;
3905
3974
  let rawFm;
3906
3975
  try {
3907
- const raw = fs18.readFileSync(absRaw, "utf8");
3976
+ const raw = fs19.readFileSync(absRaw, "utf8");
3908
3977
  const { fm } = parseFrontmatter(raw);
3909
3978
  rawFm = fm;
3910
3979
  } catch {
@@ -3938,11 +4007,11 @@ function checkGateFailure(page, repoRoot) {
3938
4007
  function checkGateStaleness(page, repoRoot) {
3939
4008
  const rawPath = page.page.raw_path;
3940
4009
  if (!rawPath) return null;
3941
- const absRaw = path19.join(repoRoot, rawPath);
3942
- if (!fs18.existsSync(absRaw)) return null;
4010
+ const absRaw = path20.join(repoRoot, rawPath);
4011
+ if (!fs19.existsSync(absRaw)) return null;
3943
4012
  let rawFm;
3944
4013
  try {
3945
- const raw = fs18.readFileSync(absRaw, "utf8");
4014
+ const raw = fs19.readFileSync(absRaw, "utf8");
3946
4015
  const { fm } = parseFrontmatter(raw);
3947
4016
  rawFm = fm;
3948
4017
  } catch {
@@ -3965,7 +4034,7 @@ function checkGateStaleness(page, repoRoot) {
3965
4034
  return null;
3966
4035
  }
3967
4036
  function discoverPlainTextMentions(pages, repoRoot) {
3968
- const wikiRoot = path19.join(repoRoot, ".cleargate", "wiki");
4037
+ const wikiRoot = path20.join(repoRoot, ".cleargate", "wiki");
3969
4038
  const byId = /* @__PURE__ */ new Map();
3970
4039
  for (const p of pages) {
3971
4040
  if (p.page.id) byId.set(p.page.id, true);
@@ -3974,7 +4043,7 @@ function discoverPlainTextMentions(pages, repoRoot) {
3974
4043
  const ID_PATTERN = /\b((?:EPIC|STORY|SPRINT|PROPOSAL|CR|BUG)-[\w-]+)\b/g;
3975
4044
  const LINK_PATTERN = /\[\[[\w-]+\]\]/g;
3976
4045
  for (const page of pages) {
3977
- const relPage = path19.relative(wikiRoot, page.absPath).replace(/\\/g, "/");
4046
+ const relPage = path20.relative(wikiRoot, page.absPath).replace(/\\/g, "/");
3978
4047
  const wrappedRefs = /* @__PURE__ */ new Set();
3979
4048
  for (const m of page.body.matchAll(LINK_PATTERN)) {
3980
4049
  const inner = m[0].slice(2, -2);
@@ -3991,11 +4060,11 @@ function discoverPlainTextMentions(pages, repoRoot) {
3991
4060
  return suggestions;
3992
4061
  }
3993
4062
  function checkIndexBudget(repoRoot, indexTokenCeiling) {
3994
- const indexPath = path19.join(repoRoot, ".cleargate", "wiki", "index.md");
3995
- if (!fs18.existsSync(indexPath)) {
4063
+ const indexPath = path20.join(repoRoot, ".cleargate", "wiki", "index.md");
4064
+ if (!fs19.existsSync(indexPath)) {
3996
4065
  return { finding: null };
3997
4066
  }
3998
- const bytes = fs18.statSync(indexPath).size;
4067
+ const bytes = fs19.statSync(indexPath).size;
3999
4068
  const tokens = Math.round(bytes / 4);
4000
4069
  const ceiling = indexTokenCeiling;
4001
4070
  if (tokens > ceiling) {
@@ -4013,18 +4082,18 @@ function checkIndexBudget(repoRoot, indexTokenCeiling) {
4013
4082
 
4014
4083
  // src/lib/wiki-config.ts
4015
4084
  init_cjs_shims();
4016
- var fs19 = __toESM(require("fs"), 1);
4017
- var path20 = __toESM(require("path"), 1);
4085
+ var fs20 = __toESM(require("fs"), 1);
4086
+ var path21 = __toESM(require("path"), 1);
4018
4087
  var import_js_yaml4 = __toESM(require("js-yaml"), 1);
4019
4088
  var DEFAULT_INDEX_TOKEN_CEILING = 8e3;
4020
4089
  function loadWikiConfig(repoRoot) {
4021
- const configPath = path20.join(repoRoot, ".cleargate", "config.yml");
4022
- if (!fs19.existsSync(configPath)) {
4090
+ const configPath = path21.join(repoRoot, ".cleargate", "config.yml");
4091
+ if (!fs20.existsSync(configPath)) {
4023
4092
  return { wiki: { index_token_ceiling: DEFAULT_INDEX_TOKEN_CEILING }, gates: {} };
4024
4093
  }
4025
4094
  let raw;
4026
4095
  try {
4027
- raw = fs19.readFileSync(configPath, "utf8");
4096
+ raw = fs20.readFileSync(configPath, "utf8");
4028
4097
  } catch (err) {
4029
4098
  throw new Error(`Failed to read ${configPath}: ${String(err)}`);
4030
4099
  }
@@ -4085,7 +4154,7 @@ async function wikiLintHandler(opts = {}) {
4085
4154
  const exit = opts.exit ?? ((c) => process.exit(c));
4086
4155
  const gitRunner = opts.gitRunner;
4087
4156
  const mode = opts.mode ?? "enforce";
4088
- const wikiRoot = path21.join(cwd, ".cleargate", "wiki");
4157
+ const wikiRoot = path22.join(cwd, ".cleargate", "wiki");
4089
4158
  const repoRoot = cwd;
4090
4159
  let pages = loadWikiPages(wikiRoot);
4091
4160
  const findings = [];
@@ -4157,8 +4226,8 @@ async function wikiLintHandler(opts = {}) {
4157
4226
 
4158
4227
  // src/commands/wiki-query.ts
4159
4228
  init_cjs_shims();
4160
- var fs20 = __toESM(require("fs"), 1);
4161
- var path22 = __toESM(require("path"), 1);
4229
+ var fs21 = __toESM(require("fs"), 1);
4230
+ var path23 = __toESM(require("path"), 1);
4162
4231
  function computeSlug(query) {
4163
4232
  return query.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").replace(/-{2,}/g, "-").slice(0, 40).replace(/-+$/, "");
4164
4233
  }
@@ -4188,9 +4257,9 @@ async function wikiQueryHandler(opts) {
4188
4257
  const query = opts.query;
4189
4258
  const persist = opts.persist ?? false;
4190
4259
  void stderr;
4191
- const wikiRoot = path22.join(cwd, ".cleargate", "wiki");
4192
- const indexPath = path22.join(wikiRoot, "index.md");
4193
- if (!fs20.existsSync(indexPath)) {
4260
+ const wikiRoot = path23.join(cwd, ".cleargate", "wiki");
4261
+ const indexPath = path23.join(wikiRoot, "index.md");
4262
+ if (!fs21.existsSync(indexPath)) {
4194
4263
  stdout(`wiki query: no index.md found at ${indexPath}
4195
4264
  `);
4196
4265
  stdout(`Run \`cleargate wiki build\` first.
@@ -4198,7 +4267,7 @@ async function wikiQueryHandler(opts) {
4198
4267
  exit(1);
4199
4268
  return;
4200
4269
  }
4201
- const indexContent = fs20.readFileSync(indexPath, "utf8");
4270
+ const indexContent = fs21.readFileSync(indexPath, "utf8");
4202
4271
  const matches = searchIndex(indexContent, query);
4203
4272
  if (matches.length === 0) {
4204
4273
  stdout(`wiki query: no matches for "${query}"
@@ -4223,8 +4292,8 @@ async function wikiQueryHandler(opts) {
4223
4292
  return;
4224
4293
  }
4225
4294
  const slug = computeSlug(query);
4226
- const topicsDir = path22.join(wikiRoot, "topics");
4227
- fs20.mkdirSync(topicsDir, { recursive: true });
4295
+ const topicsDir = path23.join(wikiRoot, "topics");
4296
+ fs21.mkdirSync(topicsDir, { recursive: true });
4228
4297
  const citesArray = matches.map(({ id }) => `"[[${id}]]"`);
4229
4298
  const createdAt = now();
4230
4299
  const frontmatter = [
@@ -4239,13 +4308,13 @@ async function wikiQueryHandler(opts) {
4239
4308
  const topicContent = `${frontmatter}
4240
4309
 
4241
4310
  ${body}`;
4242
- const topicPath = path22.join(topicsDir, `${slug}.md`);
4243
- fs20.writeFileSync(topicPath, topicContent, "utf8");
4311
+ const topicPath = path23.join(topicsDir, `${slug}.md`);
4312
+ fs21.writeFileSync(topicPath, topicContent, "utf8");
4244
4313
  updateIndexTopicsSection(indexPath, slug, query, createdAt);
4245
4314
  exit(0);
4246
4315
  }
4247
4316
  function updateIndexTopicsSection(indexPath, slug, query, createdAt) {
4248
- let content = fs20.readFileSync(indexPath, "utf8");
4317
+ let content = fs21.readFileSync(indexPath, "utf8");
4249
4318
  const row = `| ${slug} | ${query} | ${createdAt} |`;
4250
4319
  if (content.includes("## Topics")) {
4251
4320
  const topicsIdx = content.indexOf("## Topics");
@@ -4268,13 +4337,13 @@ ${row}
4268
4337
  ${row}
4269
4338
  `;
4270
4339
  }
4271
- fs20.writeFileSync(indexPath, content, "utf8");
4340
+ fs21.writeFileSync(indexPath, content, "utf8");
4272
4341
  }
4273
4342
 
4274
4343
  // src/commands/wiki-audit-status.ts
4275
4344
  init_cjs_shims();
4276
- var fs21 = __toESM(require("fs"), 1);
4277
- var path23 = __toESM(require("path"), 1);
4345
+ var fs22 = __toESM(require("fs"), 1);
4346
+ var path24 = __toESM(require("path"), 1);
4278
4347
  var readline4 = __toESM(require("readline"), 1);
4279
4348
  var TERMINAL = /* @__PURE__ */ new Set(["Completed", "Done", "Abandoned", "Closed", "Resolved"]);
4280
4349
  async function wikiAuditStatusHandler(opts = {}) {
@@ -4287,8 +4356,8 @@ async function wikiAuditStatusHandler(opts = {}) {
4287
4356
  });
4288
4357
  const exit = opts.exit ?? ((c) => process.exit(c));
4289
4358
  const isTTY = opts.isTTY ?? Boolean(process.stdout.isTTY);
4290
- const deliveryRoot = path23.join(cwd, ".cleargate", "delivery");
4291
- if (!fs21.existsSync(deliveryRoot)) {
4359
+ const deliveryRoot = path24.join(cwd, ".cleargate", "delivery");
4360
+ if (!fs22.existsSync(deliveryRoot)) {
4292
4361
  stderr(`audit-status: .cleargate/delivery/ not found at ${deliveryRoot}
4293
4362
  `);
4294
4363
  exit(1);
@@ -4428,7 +4497,7 @@ async function wikiAuditStatusHandler(opts = {}) {
4428
4497
  }
4429
4498
  }
4430
4499
  for (const d of fixable) {
4431
- const rawText = fs21.readFileSync(d.absPath, "utf8");
4500
+ const rawText = fs22.readFileSync(d.absPath, "utf8");
4432
4501
  const updated = applyStatusFix(rawText, d.suggestedStatus);
4433
4502
  if (!opts.quiet) {
4434
4503
  stdout(`--- ${d.rawPath}
@@ -4444,7 +4513,7 @@ async function wikiAuditStatusHandler(opts = {}) {
4444
4513
  stdout(`+${newLine}
4445
4514
  `);
4446
4515
  }
4447
- fs21.writeFileSync(d.absPath, updated, "utf8");
4516
+ fs22.writeFileSync(d.absPath, updated, "utf8");
4448
4517
  }
4449
4518
  stdout(`audit-status: applied ${fixable.length} fix(es)
4450
4519
  `);
@@ -4473,8 +4542,8 @@ function applyStatusFix(rawText, newStatus) {
4473
4542
 
4474
4543
  // src/commands/doctor.ts
4475
4544
  init_cjs_shims();
4476
- var fs22 = __toESM(require("fs"), 1);
4477
- var path24 = __toESM(require("path"), 1);
4545
+ var fs23 = __toESM(require("fs"), 1);
4546
+ var path25 = __toESM(require("path"), 1);
4478
4547
  var import_node_child_process6 = require("child_process");
4479
4548
 
4480
4549
  // src/lib/pricing.ts
@@ -4551,24 +4620,24 @@ function parseHookLogLine(line) {
4551
4620
  };
4552
4621
  }
4553
4622
  function runHookHealth(stdout, cwd, now, outcome) {
4554
- const cleargateDir = path24.join(cwd, ".cleargate");
4555
- if (!fs22.existsSync(cleargateDir)) {
4623
+ const cleargateDir = path25.join(cwd, ".cleargate");
4624
+ if (!fs23.existsSync(cleargateDir)) {
4556
4625
  stdout("cleargate misconfigured: no .cleargate/ found. Run: cleargate init");
4557
4626
  if (outcome) outcome.configError = true;
4558
4627
  return;
4559
4628
  }
4560
- const manifestPath = path24.join(cwd, "cleargate-planning", "MANIFEST.json");
4561
- if (!fs22.existsSync(manifestPath)) {
4629
+ const manifestPath = path25.join(cwd, "cleargate-planning", "MANIFEST.json");
4630
+ if (!fs23.existsSync(manifestPath)) {
4562
4631
  stdout(`cleargate misconfigured: cleargate-planning/MANIFEST.json not found. Run: cleargate init`);
4563
4632
  if (outcome) outcome.configError = true;
4564
4633
  }
4565
- const settingsPath = path24.join(cwd, ".claude", "settings.json");
4566
- if (!fs22.existsSync(settingsPath)) {
4634
+ const settingsPath = path25.join(cwd, ".claude", "settings.json");
4635
+ if (!fs23.existsSync(settingsPath)) {
4567
4636
  stdout("[doctor] No .claude/settings.json found \u2014 hook config unavailable.");
4568
4637
  return;
4569
4638
  }
4570
4639
  try {
4571
- const raw = fs22.readFileSync(settingsPath, "utf-8");
4640
+ const raw = fs23.readFileSync(settingsPath, "utf-8");
4572
4641
  const settings = JSON.parse(raw);
4573
4642
  const hasHooks = typeof settings === "object" && settings !== null && "hooks" in settings;
4574
4643
  if (hasHooks) {
@@ -4579,13 +4648,13 @@ function runHookHealth(stdout, cwd, now, outcome) {
4579
4648
  } catch {
4580
4649
  stdout("[doctor] .claude/settings.json is not valid JSON \u2014 cannot verify hook config.");
4581
4650
  }
4582
- const logPath = path24.join(cwd, ".cleargate", "hook-log", "gate-check.log");
4583
- if (!fs22.existsSync(logPath)) {
4651
+ const logPath = path25.join(cwd, ".cleargate", "hook-log", "gate-check.log");
4652
+ if (!fs23.existsSync(logPath)) {
4584
4653
  return;
4585
4654
  }
4586
4655
  let logContent;
4587
4656
  try {
4588
- logContent = fs22.readFileSync(logPath, "utf-8");
4657
+ logContent = fs23.readFileSync(logPath, "utf-8");
4589
4658
  } catch {
4590
4659
  return;
4591
4660
  }
@@ -4699,8 +4768,8 @@ function parseCachedGateResult2(raw) {
4699
4768
  };
4700
4769
  }
4701
4770
  function emitResolverStatusLine(cwd, stdout) {
4702
- const distCliPath = path24.join(cwd, "cleargate-cli", "dist", "cli.js");
4703
- if (fs22.existsSync(distCliPath)) {
4771
+ const distCliPath = path25.join(cwd, "cleargate-cli", "dist", "cli.js");
4772
+ if (fs23.existsSync(distCliPath)) {
4704
4773
  stdout(`cleargate CLI: local dist \u2014 ${distCliPath}`);
4705
4774
  return;
4706
4775
  }
@@ -4714,10 +4783,10 @@ function emitResolverStatusLine(cwd, stdout) {
4714
4783
  return;
4715
4784
  }
4716
4785
  let pinVersion = "unknown";
4717
- const hookPath = path24.join(cwd, ".claude", "hooks", "stamp-and-gate.sh");
4718
- if (fs22.existsSync(hookPath)) {
4786
+ const hookPath = path25.join(cwd, ".claude", "hooks", "stamp-and-gate.sh");
4787
+ if (fs23.existsSync(hookPath)) {
4719
4788
  try {
4720
- const hookContent = fs22.readFileSync(hookPath, "utf-8");
4789
+ const hookContent = fs23.readFileSync(hookPath, "utf-8");
4721
4790
  const pinMatch = hookContent.match(/^#\s*cleargate-pin:\s*(\S+)\s*$/m);
4722
4791
  if (pinMatch?.[1]) {
4723
4792
  pinVersion = pinMatch[1];
@@ -4749,10 +4818,10 @@ async function runSessionStart(cwd, stdout, outcome) {
4749
4818
  if (outcome && resolverLines.some((l) => l.includes("\u{1F534}"))) {
4750
4819
  outcome.configError = true;
4751
4820
  }
4752
- const pendingSyncDir = path24.join(cwd, ".cleargate", "delivery", "pending-sync");
4821
+ const pendingSyncDir = path25.join(cwd, ".cleargate", "delivery", "pending-sync");
4753
4822
  let files;
4754
4823
  try {
4755
- files = fs22.readdirSync(pendingSyncDir).filter((f) => f.endsWith(".md")).map((f) => path24.join(pendingSyncDir, f));
4824
+ files = fs23.readdirSync(pendingSyncDir).filter((f) => f.endsWith(".md")).map((f) => path25.join(pendingSyncDir, f));
4756
4825
  } catch {
4757
4826
  return;
4758
4827
  }
@@ -4761,7 +4830,7 @@ async function runSessionStart(cwd, stdout, outcome) {
4761
4830
  for (const filePath of files) {
4762
4831
  let raw;
4763
4832
  try {
4764
- raw = fs22.readFileSync(filePath, "utf-8");
4833
+ raw = fs23.readFileSync(filePath, "utf-8");
4765
4834
  } catch {
4766
4835
  continue;
4767
4836
  }
@@ -4787,13 +4856,13 @@ async function runSessionStart(cwd, stdout, outcome) {
4787
4856
  }
4788
4857
  }
4789
4858
  if (!itemId) {
4790
- itemId = path24.basename(filePath, ".md");
4859
+ itemId = path25.basename(filePath, ".md");
4791
4860
  }
4792
4861
  const firstCriterionId = gate2.failing_criteria.length > 0 ? gate2.failing_criteria[0]?.id ?? "" : "";
4793
4862
  blocked.push({ id: itemId, firstCriterionId });
4794
4863
  }
4795
- const activesentinel = path24.join(cwd, ".cleargate", "sprint-runs", ".active");
4796
- const sprintActive = fs22.existsSync(activesentinel);
4864
+ const activesentinel = path25.join(cwd, ".cleargate", "sprint-runs", ".active");
4865
+ const sprintActive = fs23.existsSync(activesentinel);
4797
4866
  const shouldRemind = !hasApprovedStory && !sprintActive;
4798
4867
  if (shouldRemind) {
4799
4868
  stdout(PLANNING_FIRST_REMINDER);
@@ -4828,10 +4897,10 @@ async function runPricing(filePath, cwd, stdout, stderr, exit, outcome) {
4828
4897
  exit(2);
4829
4898
  return;
4830
4899
  }
4831
- const absPath = path24.isAbsolute(filePath) ? filePath : path24.resolve(cwd, filePath);
4900
+ const absPath = path25.isAbsolute(filePath) ? filePath : path25.resolve(cwd, filePath);
4832
4901
  let raw;
4833
4902
  try {
4834
- raw = fs22.readFileSync(absPath, "utf-8");
4903
+ raw = fs23.readFileSync(absPath, "utf-8");
4835
4904
  } catch {
4836
4905
  stderr(`cleargate doctor --pricing: cannot read file: ${absPath}`);
4837
4906
  if (outcome) outcome.configError = true;
@@ -4893,7 +4962,7 @@ async function runPricing(filePath, cwd, stdout, stderr, exit, outcome) {
4893
4962
  const output = draftTokens.output ?? 0;
4894
4963
  const cacheRead = draftTokens.cache_read ?? 0;
4895
4964
  const cacheCreation = draftTokens.cache_creation ?? 0;
4896
- const fileName = path24.basename(absPath);
4965
+ const fileName = path25.basename(absPath);
4897
4966
  stdout(
4898
4967
  `${fileName}: ${model} \u2014 input:${input} output:${output} cache_read:${cacheRead} cache_creation:${cacheCreation} \u2248 $${usd.toFixed(4)}`
4899
4968
  );
@@ -4906,15 +4975,15 @@ function globMatch(pattern, filePath) {
4906
4975
  return re.test(normalFile);
4907
4976
  }
4908
4977
  async function runCanEdit(filePath, cwd, stdout, exit, outcome) {
4909
- const activeSentinel = path24.join(cwd, ".cleargate", "sprint-runs", ".active");
4910
- if (fs22.existsSync(activeSentinel)) {
4978
+ const activeSentinel = path25.join(cwd, ".cleargate", "sprint-runs", ".active");
4979
+ if (fs23.existsSync(activeSentinel)) {
4911
4980
  stdout("allowed: sprint active");
4912
4981
  return;
4913
4982
  }
4914
- const pendingSyncDir = path24.join(cwd, ".cleargate", "delivery", "pending-sync");
4983
+ const pendingSyncDir = path25.join(cwd, ".cleargate", "delivery", "pending-sync");
4915
4984
  let files;
4916
4985
  try {
4917
- files = fs22.readdirSync(pendingSyncDir).filter((f) => f.endsWith(".md")).map((f) => path24.join(pendingSyncDir, f));
4986
+ files = fs23.readdirSync(pendingSyncDir).filter((f) => f.endsWith(".md")).map((f) => path25.join(pendingSyncDir, f));
4918
4987
  } catch {
4919
4988
  stdout("blocked: no_approved_stories");
4920
4989
  if (outcome) outcome.blocker = true;
@@ -4926,7 +4995,7 @@ async function runCanEdit(filePath, cwd, stdout, exit, outcome) {
4926
4995
  for (const storyPath of files) {
4927
4996
  let raw;
4928
4997
  try {
4929
- raw = fs22.readFileSync(storyPath, "utf-8");
4998
+ raw = fs23.readFileSync(storyPath, "utf-8");
4930
4999
  } catch {
4931
5000
  continue;
4932
5001
  }
@@ -5024,14 +5093,14 @@ async function doctorHandler(flags, cli) {
5024
5093
 
5025
5094
  // src/commands/gate.ts
5026
5095
  init_cjs_shims();
5027
- var fs26 = __toESM(require("fs"), 1);
5028
- var path27 = __toESM(require("path"), 1);
5096
+ var fs27 = __toESM(require("fs"), 1);
5097
+ var path28 = __toESM(require("path"), 1);
5029
5098
  var import_node_child_process7 = require("child_process");
5030
5099
 
5031
5100
  // src/commands/execution-mode.ts
5032
5101
  init_cjs_shims();
5033
- var fs23 = __toESM(require("fs"), 1);
5034
- var path25 = __toESM(require("path"), 1);
5102
+ var fs24 = __toESM(require("fs"), 1);
5103
+ var path26 = __toESM(require("path"), 1);
5035
5104
  var V1_INERT_MESSAGE = "v1 mode active \u2014 command inert. Set execution_mode: v2 in sprint frontmatter to enable.";
5036
5105
  function parseFrontmatterSimple(raw) {
5037
5106
  const match = /^---\r?\n([\s\S]*?)\r?\n---/.exec(raw);
@@ -5049,24 +5118,24 @@ function parseFrontmatterSimple(raw) {
5049
5118
  }
5050
5119
  function discoverSprintFile(sprintId, cwd) {
5051
5120
  const searchDirs = [
5052
- path25.join(cwd, ".cleargate", "delivery", "pending-sync"),
5053
- path25.join(cwd, ".cleargate", "delivery", "archive")
5121
+ path26.join(cwd, ".cleargate", "delivery", "pending-sync"),
5122
+ path26.join(cwd, ".cleargate", "delivery", "archive")
5054
5123
  ];
5055
5124
  for (const dir of searchDirs) {
5056
- if (!fs23.existsSync(dir)) continue;
5125
+ if (!fs24.existsSync(dir)) continue;
5057
5126
  let entries;
5058
5127
  try {
5059
- entries = fs23.readdirSync(dir);
5128
+ entries = fs24.readdirSync(dir);
5060
5129
  } catch {
5061
5130
  continue;
5062
5131
  }
5063
5132
  const prefix = `${sprintId}_`;
5064
5133
  for (const entry of entries) {
5065
5134
  if (entry.startsWith(prefix) && entry.endsWith(".md")) {
5066
- return path25.join(dir, entry);
5135
+ return path26.join(dir, entry);
5067
5136
  }
5068
5137
  if (entry === `${sprintId}.md`) {
5069
- return path25.join(dir, entry);
5138
+ return path26.join(dir, entry);
5070
5139
  }
5071
5140
  }
5072
5141
  }
@@ -5074,9 +5143,9 @@ function discoverSprintFile(sprintId, cwd) {
5074
5143
  }
5075
5144
  function resolveSprintIdFromSentinel(cwd) {
5076
5145
  const resolvedCwd = cwd ?? process.cwd();
5077
- const sentinelPath = path25.join(resolvedCwd, ".cleargate", "sprint-runs", ".active");
5146
+ const sentinelPath = path26.join(resolvedCwd, ".cleargate", "sprint-runs", ".active");
5078
5147
  try {
5079
- const content = fs23.readFileSync(sentinelPath, "utf8").trim();
5148
+ const content = fs24.readFileSync(sentinelPath, "utf8").trim();
5080
5149
  return content.length > 0 ? content : null;
5081
5150
  } catch {
5082
5151
  return null;
@@ -5095,12 +5164,12 @@ function readSprintExecutionMode(sprintId, opts = {}) {
5095
5164
  if (!filePath) {
5096
5165
  filePath = discoverSprintFile(resolvedSprintId, cwd);
5097
5166
  }
5098
- if (!filePath || !fs23.existsSync(filePath)) {
5167
+ if (!filePath || !fs24.existsSync(filePath)) {
5099
5168
  return "v1";
5100
5169
  }
5101
5170
  let raw;
5102
5171
  try {
5103
- raw = fs23.readFileSync(filePath, "utf8");
5172
+ raw = fs24.readFileSync(filePath, "utf8");
5104
5173
  } catch {
5105
5174
  return "v1";
5106
5175
  }
@@ -5119,8 +5188,8 @@ var import_js_yaml6 = __toESM(require("js-yaml"), 1);
5119
5188
 
5120
5189
  // src/lib/readiness-predicates.ts
5121
5190
  init_cjs_shims();
5122
- var fs24 = __toESM(require("fs"), 1);
5123
- var path26 = __toESM(require("path"), 1);
5191
+ var fs25 = __toESM(require("fs"), 1);
5192
+ var path27 = __toESM(require("path"), 1);
5124
5193
  function parsePredicate(src) {
5125
5194
  const s = src.trim();
5126
5195
  const fmMatch = s.match(
@@ -5284,18 +5353,18 @@ function compareValues(actual, op, expected) {
5284
5353
  }
5285
5354
  function resolveLinkedPath(ref, docAbsPath, projectRoot) {
5286
5355
  const candidates = [
5287
- path26.resolve(path26.dirname(docAbsPath), ref),
5288
- path26.resolve(projectRoot, ref)
5356
+ path27.resolve(path27.dirname(docAbsPath), ref),
5357
+ path27.resolve(projectRoot, ref)
5289
5358
  ];
5290
5359
  for (const candidate of candidates) {
5291
5360
  if (!candidate.startsWith(projectRoot)) continue;
5292
- if (fs24.existsSync(candidate)) return candidate;
5361
+ if (fs25.existsSync(candidate)) return candidate;
5293
5362
  }
5294
5363
  return null;
5295
5364
  }
5296
5365
  function readFrontmatterFromFile(absPath) {
5297
5366
  try {
5298
- const raw = fs24.readFileSync(absPath, "utf8");
5367
+ const raw = fs25.readFileSync(absPath, "utf8");
5299
5368
  const lines = raw.split("\n");
5300
5369
  if (lines[0] !== "---") return {};
5301
5370
  let closeIdx = -1;
@@ -5439,14 +5508,14 @@ function applyCountOp(actual, op, n) {
5439
5508
  }
5440
5509
  }
5441
5510
  function evalFileExists(parsed, projectRoot) {
5442
- const resolved = path26.resolve(projectRoot, parsed.path);
5443
- if (!resolved.startsWith(projectRoot + path26.sep) && resolved !== projectRoot) {
5511
+ const resolved = path27.resolve(projectRoot, parsed.path);
5512
+ if (!resolved.startsWith(projectRoot + path27.sep) && resolved !== projectRoot) {
5444
5513
  return {
5445
5514
  pass: false,
5446
5515
  detail: `path '${parsed.path}' resolves outside project root (sandbox violation)`
5447
5516
  };
5448
5517
  }
5449
- const exists = fs24.existsSync(resolved);
5518
+ const exists = fs25.existsSync(resolved);
5450
5519
  return {
5451
5520
  pass: exists,
5452
5521
  detail: exists ? `${parsed.path} exists` : `${parsed.path} not found`
@@ -5454,13 +5523,13 @@ function evalFileExists(parsed, projectRoot) {
5454
5523
  }
5455
5524
  function evalLinkTargetExists(parsed, opts) {
5456
5525
  const projectRoot = opts?.projectRoot ?? process.cwd();
5457
- const wikiIndexPath = opts?.wikiIndexPath ?? path26.join(projectRoot, ".cleargate", "wiki", "index.md");
5526
+ const wikiIndexPath = opts?.wikiIndexPath ?? path27.join(projectRoot, ".cleargate", "wiki", "index.md");
5458
5527
  if (!wikiIndexPath.startsWith(projectRoot)) {
5459
5528
  return { pass: false, detail: "wikiIndexPath resolves outside project root" };
5460
5529
  }
5461
5530
  let indexContent;
5462
5531
  try {
5463
- indexContent = fs24.readFileSync(wikiIndexPath, "utf8");
5532
+ indexContent = fs25.readFileSync(wikiIndexPath, "utf8");
5464
5533
  } catch {
5465
5534
  return { pass: false, detail: `wiki index not found at ${wikiIndexPath}` };
5466
5535
  }
@@ -5471,13 +5540,13 @@ function evalLinkTargetExists(parsed, opts) {
5471
5540
  };
5472
5541
  }
5473
5542
  function evalStatusOf(parsed, opts, projectRoot) {
5474
- const wikiIndexPath = opts?.wikiIndexPath ?? path26.join(projectRoot, ".cleargate", "wiki", "index.md");
5543
+ const wikiIndexPath = opts?.wikiIndexPath ?? path27.join(projectRoot, ".cleargate", "wiki", "index.md");
5475
5544
  if (!wikiIndexPath.startsWith(projectRoot)) {
5476
5545
  return { pass: false, detail: "wikiIndexPath resolves outside project root" };
5477
5546
  }
5478
5547
  let indexContent;
5479
5548
  try {
5480
- indexContent = fs24.readFileSync(wikiIndexPath, "utf8");
5549
+ indexContent = fs25.readFileSync(wikiIndexPath, "utf8");
5481
5550
  } catch {
5482
5551
  return { pass: false, detail: `wiki index not found at ${wikiIndexPath}` };
5483
5552
  }
@@ -5488,7 +5557,7 @@ function evalStatusOf(parsed, opts, projectRoot) {
5488
5557
  return { pass: false, detail: `[[${parsed.id}]] not found in wiki index` };
5489
5558
  }
5490
5559
  const rawPath = rowMatch[1].trim();
5491
- const fullPath = path26.resolve(projectRoot, rawPath);
5560
+ const fullPath = path27.resolve(projectRoot, rawPath);
5492
5561
  if (!fullPath.startsWith(projectRoot)) {
5493
5562
  return { pass: false, detail: `wiki path for ${parsed.id} resolves outside project root` };
5494
5563
  }
@@ -5506,12 +5575,12 @@ function evalStatusOf(parsed, opts, projectRoot) {
5506
5575
 
5507
5576
  // src/lib/frontmatter-cache.ts
5508
5577
  init_cjs_shims();
5509
- var fs25 = __toESM(require("fs/promises"), 1);
5578
+ var fs26 = __toESM(require("fs/promises"), 1);
5510
5579
  var import_js_yaml5 = __toESM(require("js-yaml"), 1);
5511
5580
  async function readCachedGate(absPath) {
5512
5581
  let raw;
5513
5582
  try {
5514
- raw = await fs25.readFile(absPath, "utf8");
5583
+ raw = await fs26.readFile(absPath, "utf8");
5515
5584
  } catch {
5516
5585
  return null;
5517
5586
  }
@@ -5531,7 +5600,7 @@ async function writeCachedGate(absPath, result, opts) {
5531
5600
  failing_criteria: result.failing_criteria,
5532
5601
  last_gate_check: lastGateCheck
5533
5602
  };
5534
- const raw = await fs25.readFile(absPath, "utf8");
5603
+ const raw = await fs26.readFile(absPath, "utf8");
5535
5604
  let fm;
5536
5605
  let body;
5537
5606
  try {
@@ -5561,7 +5630,7 @@ async function writeCachedGate(absPath, result, opts) {
5561
5630
 
5562
5631
  ${body}` : `${fmBlock}
5563
5632
  `;
5564
- await fs25.writeFile(absPath, newContent, "utf8");
5633
+ await fs26.writeFile(absPath, newContent, "utf8");
5565
5634
  }
5566
5635
  function coerceCachedGate(val) {
5567
5636
  if (val === void 0 || val === null) return null;
@@ -5592,7 +5661,7 @@ function coerceCachedGate(val) {
5592
5661
 
5593
5662
  // src/commands/gate.ts
5594
5663
  function loadGateBlocks(gatesDocPath) {
5595
- const raw = fs26.readFileSync(gatesDocPath, "utf8");
5664
+ const raw = fs27.readFileSync(gatesDocPath, "utf8");
5596
5665
  const blocks = [];
5597
5666
  const fenceRe = /^```yaml\n([\s\S]*?)^```/gm;
5598
5667
  let match;
@@ -5627,14 +5696,14 @@ async function gateCheckHandler(file, opts, cli) {
5627
5696
  const exitFn = cli?.exit ?? ((code) => process.exit(code));
5628
5697
  const cwd = cli?.cwd ?? process.cwd();
5629
5698
  const nowFn = cli?.now ?? (() => /* @__PURE__ */ new Date());
5630
- const absPath = path27.isAbsolute(file) ? file : path27.resolve(cwd, file);
5631
- if (!fs26.existsSync(absPath)) {
5699
+ const absPath = path28.isAbsolute(file) ? file : path28.resolve(cwd, file);
5700
+ if (!fs27.existsSync(absPath)) {
5632
5701
  stderrFn(`[cleargate gate] error: file not found: ${absPath}`);
5633
5702
  return exitFn(1);
5634
5703
  }
5635
5704
  let raw;
5636
5705
  try {
5637
- raw = fs26.readFileSync(absPath, "utf8");
5706
+ raw = fs27.readFileSync(absPath, "utf8");
5638
5707
  } catch (err) {
5639
5708
  stderrFn(`[cleargate gate] error: cannot read file: ${absPath}`);
5640
5709
  return exitFn(1);
@@ -5653,8 +5722,8 @@ async function gateCheckHandler(file, opts, cli) {
5653
5722
  return exitFn(1);
5654
5723
  }
5655
5724
  const projectRoot = cwd;
5656
- const gatesDocPath = cli?.gatesDocPath ?? path27.join(projectRoot, ".cleargate", "knowledge", "readiness-gates.md");
5657
- if (!fs26.existsSync(gatesDocPath)) {
5725
+ const gatesDocPath = cli?.gatesDocPath ?? path28.join(projectRoot, ".cleargate", "knowledge", "readiness-gates.md");
5726
+ if (!fs27.existsSync(gatesDocPath)) {
5658
5727
  stderrFn(`[cleargate gate] error: readiness-gates.md not found at: ${gatesDocPath}`);
5659
5728
  return exitFn(1);
5660
5729
  }
@@ -5727,8 +5796,8 @@ async function gateExplainHandler(file, cli) {
5727
5796
  const stderrFn = cli?.stderr ?? ((s) => process.stderr.write(s + "\n"));
5728
5797
  const exitFn = cli?.exit ?? ((code) => process.exit(code));
5729
5798
  const cwd = cli?.cwd ?? process.cwd();
5730
- const absPath = path27.isAbsolute(file) ? file : path27.resolve(cwd, file);
5731
- if (!fs26.existsSync(absPath)) {
5799
+ const absPath = path28.isAbsolute(file) ? file : path28.resolve(cwd, file);
5800
+ if (!fs27.existsSync(absPath)) {
5732
5801
  stderrFn(`[cleargate gate] error: file not found: ${absPath}`);
5733
5802
  return exitFn(1);
5734
5803
  }
@@ -5739,7 +5808,7 @@ async function gateExplainHandler(file, cli) {
5739
5808
  }
5740
5809
  let raw;
5741
5810
  try {
5742
- raw = fs26.readFileSync(absPath, "utf8");
5811
+ raw = fs27.readFileSync(absPath, "utf8");
5743
5812
  } catch {
5744
5813
  stderrFn(`[cleargate gate] error: cannot read file: ${absPath}`);
5745
5814
  return exitFn(1);
@@ -5760,7 +5829,7 @@ async function gateExplainHandler(file, cli) {
5760
5829
  function resolveRunScriptForGate(opts) {
5761
5830
  if (opts.runScriptPath) return opts.runScriptPath;
5762
5831
  const cwd = opts.cwd ?? process.cwd();
5763
- return path27.join(cwd, ".cleargate", "scripts", "run_script.sh");
5832
+ return path28.join(cwd, ".cleargate", "scripts", "run_script.sh");
5764
5833
  }
5765
5834
  function gateQaHandler(opts, cli) {
5766
5835
  const stdoutFn = cli?.stdout ?? ((s) => process.stdout.write(s + "\n"));
@@ -5854,15 +5923,15 @@ function gateRunHandler(name, opts, cli) {
5854
5923
 
5855
5924
  // src/commands/sprint.ts
5856
5925
  init_cjs_shims();
5857
- var fs27 = __toESM(require("fs"), 1);
5858
- var path28 = __toESM(require("path"), 1);
5926
+ var fs28 = __toESM(require("fs"), 1);
5927
+ var path29 = __toESM(require("path"), 1);
5859
5928
  var import_node_child_process9 = require("child_process");
5860
5929
  var import_js_yaml7 = __toESM(require("js-yaml"), 1);
5861
5930
  var TERMINAL_STATUSES2 = /* @__PURE__ */ new Set(["Completed", "Done", "Abandoned", "Closed", "Resolved"]);
5862
5931
  function resolveRunScript(opts) {
5863
5932
  if (opts.runScriptPath) return opts.runScriptPath;
5864
5933
  const cwd = opts.cwd ?? process.cwd();
5865
- return path28.join(cwd, ".cleargate", "scripts", "run_script.sh");
5934
+ return path29.join(cwd, ".cleargate", "scripts", "run_script.sh");
5866
5935
  }
5867
5936
  function defaultExit(code) {
5868
5937
  return process.exit(code);
@@ -5956,8 +6025,8 @@ ${body}`;
5956
6025
  }
5957
6026
  function atomicWriteStr(filePath, content) {
5958
6027
  const tmp = `${filePath}.tmp.${process.pid}`;
5959
- fs27.writeFileSync(tmp, content, "utf8");
5960
- fs27.renameSync(tmp, filePath);
6028
+ fs28.writeFileSync(tmp, content, "utf8");
6029
+ fs28.renameSync(tmp, filePath);
5961
6030
  }
5962
6031
  function deriveSprintBranchForArchive(sprintId) {
5963
6032
  const match = /^SPRINT-(\d+)/.exec(sprintId);
@@ -5971,7 +6040,7 @@ function stampFile(raw, status, completedAt) {
5971
6040
  return serializeFileContent(fm, body);
5972
6041
  }
5973
6042
  function stampSprintClose(sprintPath, now) {
5974
- const previousContent = fs27.readFileSync(sprintPath, "utf8");
6043
+ const previousContent = fs28.readFileSync(sprintPath, "utf8");
5975
6044
  const { fm, body } = parseFileFrontmatter(previousContent);
5976
6045
  const currentStatus = typeof fm["status"] === "string" ? fm["status"] : "";
5977
6046
  const alreadyTerminal = TERMINAL_STATUSES2.has(currentStatus);
@@ -6031,14 +6100,14 @@ async function sprintArchiveHandler(opts, cli) {
6031
6100
  if (mode === "v1") {
6032
6101
  return printInertAndExit(stdoutFn, exitFn);
6033
6102
  }
6034
- const stateFile = path28.join(cwd, ".cleargate", "sprint-runs", opts.sprintId, "state.json");
6035
- if (!fs27.existsSync(stateFile)) {
6103
+ const stateFile = path29.join(cwd, ".cleargate", "sprint-runs", opts.sprintId, "state.json");
6104
+ if (!fs28.existsSync(stateFile)) {
6036
6105
  stderrFn(`[cleargate sprint archive] state.json not found at ${stateFile}`);
6037
6106
  return exitFn(1);
6038
6107
  }
6039
6108
  let state2;
6040
6109
  try {
6041
- state2 = JSON.parse(fs27.readFileSync(stateFile, "utf8"));
6110
+ state2 = JSON.parse(fs28.readFileSync(stateFile, "utf8"));
6042
6111
  } catch (err) {
6043
6112
  stderrFn(`[cleargate sprint archive] failed to parse state.json: ${err.message}`);
6044
6113
  return exitFn(1);
@@ -6050,18 +6119,18 @@ async function sprintArchiveHandler(opts, cli) {
6050
6119
  return exitFn(1);
6051
6120
  }
6052
6121
  const stateStories = state2.stories ?? {};
6053
- const pendingDir = path28.join(cwd, ".cleargate", "delivery", "pending-sync");
6054
- const archiveDir = path28.join(cwd, ".cleargate", "delivery", "archive");
6122
+ const pendingDir = path29.join(cwd, ".cleargate", "delivery", "pending-sync");
6123
+ const archiveDir = path29.join(cwd, ".cleargate", "delivery", "archive");
6055
6124
  let sprintFile = null;
6056
- for (const entry of fs27.readdirSync(pendingDir)) {
6125
+ for (const entry of fs28.readdirSync(pendingDir)) {
6057
6126
  if ((entry.startsWith(`${opts.sprintId}_`) || entry === `${opts.sprintId}.md`) && entry.endsWith(".md")) {
6058
- sprintFile = path28.join(pendingDir, entry);
6127
+ sprintFile = path29.join(pendingDir, entry);
6059
6128
  break;
6060
6129
  }
6061
6130
  }
6062
6131
  let epicIds = [];
6063
- if (sprintFile && fs27.existsSync(sprintFile)) {
6064
- const { fm } = parseFileFrontmatter(fs27.readFileSync(sprintFile, "utf8"));
6132
+ if (sprintFile && fs28.existsSync(sprintFile)) {
6133
+ const { fm } = parseFileFrontmatter(fs28.readFileSync(sprintFile, "utf8"));
6065
6134
  const epics = fm["epics"];
6066
6135
  if (Array.isArray(epics)) {
6067
6136
  epicIds = epics.map(String);
@@ -6071,15 +6140,15 @@ async function sprintArchiveHandler(opts, cli) {
6071
6140
  if (sprintFile) {
6072
6141
  plan.push({
6073
6142
  src: sprintFile,
6074
- destName: path28.basename(sprintFile),
6143
+ destName: path29.basename(sprintFile),
6075
6144
  status: "Completed"
6076
6145
  });
6077
6146
  }
6078
6147
  for (const epicId of epicIds) {
6079
- for (const entry of fs27.readdirSync(pendingDir)) {
6148
+ for (const entry of fs28.readdirSync(pendingDir)) {
6080
6149
  if ((entry.startsWith(`${epicId}_`) || entry === `${epicId}.md`) && entry.endsWith(".md")) {
6081
6150
  plan.push({
6082
- src: path28.join(pendingDir, entry),
6151
+ src: path29.join(pendingDir, entry),
6083
6152
  destName: entry,
6084
6153
  status: "Approved"
6085
6154
  });
@@ -6088,10 +6157,10 @@ async function sprintArchiveHandler(opts, cli) {
6088
6157
  }
6089
6158
  const storyKeys = storyKeysForEpic(stateStories, epicId);
6090
6159
  for (const storyId of storyKeys) {
6091
- for (const entry of fs27.readdirSync(pendingDir)) {
6160
+ for (const entry of fs28.readdirSync(pendingDir)) {
6092
6161
  if ((entry.startsWith(`${storyId}_`) || entry === `${storyId}.md`) && entry.endsWith(".md")) {
6093
6162
  plan.push({
6094
- src: path28.join(pendingDir, entry),
6163
+ src: path29.join(pendingDir, entry),
6095
6164
  destName: entry,
6096
6165
  status: "Done"
6097
6166
  });
@@ -6103,13 +6172,13 @@ async function sprintArchiveHandler(opts, cli) {
6103
6172
  const storyIdsInState = new Set(Object.keys(stateStories));
6104
6173
  const planSrcs = new Set(plan.map((p) => p.src));
6105
6174
  const orphans = [];
6106
- for (const entry of fs27.readdirSync(pendingDir)) {
6175
+ for (const entry of fs28.readdirSync(pendingDir)) {
6107
6176
  if (!entry.startsWith("STORY-") || !entry.endsWith(".md")) continue;
6108
- const candidate = path28.join(pendingDir, entry);
6177
+ const candidate = path29.join(pendingDir, entry);
6109
6178
  if (planSrcs.has(candidate)) continue;
6110
6179
  let raw;
6111
6180
  try {
6112
- raw = fs27.readFileSync(candidate, "utf8");
6181
+ raw = fs28.readFileSync(candidate, "utf8");
6113
6182
  } catch {
6114
6183
  continue;
6115
6184
  }
@@ -6126,18 +6195,18 @@ async function sprintArchiveHandler(opts, cli) {
6126
6195
  }
6127
6196
  const completedAt = (/* @__PURE__ */ new Date()).toISOString();
6128
6197
  const sprintBranch = deriveSprintBranchForArchive(opts.sprintId);
6129
- const activePath = path28.join(cwd, ".cleargate", "sprint-runs", ".active");
6198
+ const activePath = path29.join(cwd, ".cleargate", "sprint-runs", ".active");
6130
6199
  if (opts.dryRun) {
6131
6200
  stdoutFn(`[dry-run] Sprint archive plan for ${opts.sprintId}:`);
6132
6201
  stdoutFn(` Sprint branch: ${sprintBranch}`);
6133
6202
  stdoutFn(` Files to archive (${plan.length}):`);
6134
6203
  for (const entry of plan) {
6135
6204
  stdoutFn(
6136
- ` ${path28.basename(entry.src)} \u2192 archive/${entry.destName} [stamp: status=${entry.status}, completed_at=<now>]`
6205
+ ` ${path29.basename(entry.src)} \u2192 archive/${entry.destName} [stamp: status=${entry.status}, completed_at=<now>]`
6137
6206
  );
6138
6207
  }
6139
6208
  if (orphans.length > 0) {
6140
- stdoutFn(` Orphan files (${orphans.length}): ${orphans.map((o) => path28.basename(o)).join(", ")}`);
6209
+ stdoutFn(` Orphan files (${orphans.length}): ${orphans.map((o) => path29.basename(o)).join(", ")}`);
6141
6210
  }
6142
6211
  stdoutFn(` .active \u2192 "" (truncate)`);
6143
6212
  stdoutFn(` git checkout main`);
@@ -6146,9 +6215,9 @@ async function sprintArchiveHandler(opts, cli) {
6146
6215
  return exitFn(0);
6147
6216
  }
6148
6217
  let sprintFileSnapshot = null;
6149
- const wikiRoot = path28.join(cwd, ".cleargate", "wiki");
6150
- const wikiInitialised = fs27.existsSync(wikiRoot);
6151
- if (sprintFile && fs27.existsSync(sprintFile)) {
6218
+ const wikiRoot = path29.join(cwd, ".cleargate", "wiki");
6219
+ const wikiInitialised = fs28.existsSync(wikiRoot);
6220
+ if (sprintFile && fs28.existsSync(sprintFile)) {
6152
6221
  const { previousContent } = stampSprintClose(sprintFile, () => completedAt);
6153
6222
  sprintFileSnapshot = previousContent;
6154
6223
  if (wikiInitialised) {
@@ -6170,15 +6239,15 @@ async function sprintArchiveHandler(opts, cli) {
6170
6239
  }
6171
6240
  }
6172
6241
  for (const entry of plan) {
6173
- if (!fs27.existsSync(entry.src)) {
6242
+ if (!fs28.existsSync(entry.src)) {
6174
6243
  stderrFn(`[cleargate sprint archive] source not found: ${entry.src} \u2014 skipping`);
6175
6244
  continue;
6176
6245
  }
6177
- const raw = fs27.readFileSync(entry.src, "utf8");
6246
+ const raw = fs28.readFileSync(entry.src, "utf8");
6178
6247
  const stamped = stampFile(raw, entry.status, completedAt);
6179
- const dest = path28.join(archiveDir, entry.destName);
6248
+ const dest = path29.join(archiveDir, entry.destName);
6180
6249
  atomicWriteStr(entry.src, stamped);
6181
- fs27.renameSync(entry.src, dest);
6250
+ fs28.renameSync(entry.src, dest);
6182
6251
  stdoutFn(`archived: ${entry.destName}`);
6183
6252
  }
6184
6253
  try {
@@ -6221,8 +6290,8 @@ async function sprintArchiveHandler(opts, cli) {
6221
6290
 
6222
6291
  // src/commands/story.ts
6223
6292
  init_cjs_shims();
6224
- var fs28 = __toESM(require("fs"), 1);
6225
- var path29 = __toESM(require("path"), 1);
6293
+ var fs29 = __toESM(require("fs"), 1);
6294
+ var path30 = __toESM(require("path"), 1);
6226
6295
  var import_node_child_process10 = require("child_process");
6227
6296
  function defaultExit2(code) {
6228
6297
  return process.exit(code);
@@ -6230,7 +6299,7 @@ function defaultExit2(code) {
6230
6299
  function resolveRunScript2(opts) {
6231
6300
  if (opts.runScriptPath) return opts.runScriptPath;
6232
6301
  const cwd = opts.cwd ?? process.cwd();
6233
- return path29.join(cwd, ".cleargate", "scripts", "run_script.sh");
6302
+ return path30.join(cwd, ".cleargate", "scripts", "run_script.sh");
6234
6303
  }
6235
6304
  function deriveSprintBranch(sprintId) {
6236
6305
  const match = /^SPRINT-(\d+)/.exec(sprintId);
@@ -6239,11 +6308,11 @@ function deriveSprintBranch(sprintId) {
6239
6308
  }
6240
6309
  function atomicWriteString(filePath, text) {
6241
6310
  const tmpFile = `${filePath}.tmp.${process.pid}`;
6242
- fs28.writeFileSync(tmpFile, text, "utf8");
6243
- fs28.renameSync(tmpFile, filePath);
6311
+ fs29.writeFileSync(tmpFile, text, "utf8");
6312
+ fs29.renameSync(tmpFile, filePath);
6244
6313
  }
6245
6314
  function stateJsonPath(cwd, sprintId) {
6246
- return path29.join(cwd, ".cleargate", "sprint-runs", sprintId, "state.json");
6315
+ return path30.join(cwd, ".cleargate", "sprint-runs", sprintId, "state.json");
6247
6316
  }
6248
6317
  function storyStartHandler(opts, cli) {
6249
6318
  const stdoutFn = cli?.stdout ?? ((s) => process.stdout.write(s + "\n"));
@@ -6260,7 +6329,7 @@ function storyStartHandler(opts, cli) {
6260
6329
  return printInertAndExit(stdoutFn, exitFn);
6261
6330
  }
6262
6331
  const sprintBranch = deriveSprintBranch(sprintId);
6263
- const worktreePath = path29.join(cwd, ".worktrees", opts.storyId);
6332
+ const worktreePath = path30.join(cwd, ".worktrees", opts.storyId);
6264
6333
  const storyBranch = `story/${opts.storyId}`;
6265
6334
  const step1 = spawnFn(
6266
6335
  "git",
@@ -6292,13 +6361,13 @@ function storyStartHandler(opts, cli) {
6292
6361
  return exitFn(step2.status ?? 1);
6293
6362
  }
6294
6363
  const stateFile = stateJsonPath(cwd, sprintId);
6295
- if (!fs28.existsSync(stateFile)) {
6364
+ if (!fs29.existsSync(stateFile)) {
6296
6365
  stderrFn(`[cleargate story start] step 3: state.json not found at ${stateFile}`);
6297
6366
  return exitFn(1);
6298
6367
  }
6299
6368
  let state2;
6300
6369
  try {
6301
- state2 = JSON.parse(fs28.readFileSync(stateFile, "utf8"));
6370
+ state2 = JSON.parse(fs29.readFileSync(stateFile, "utf8"));
6302
6371
  } catch (err) {
6303
6372
  stderrFn(`[cleargate story start] step 3: failed to parse state.json: ${err.message}`);
6304
6373
  return exitFn(1);
@@ -6339,7 +6408,7 @@ function storyCompleteHandler(opts, cli) {
6339
6408
  }
6340
6409
  const sprintBranch = deriveSprintBranch(sprintId);
6341
6410
  const storyBranch = `story/${opts.storyId}`;
6342
- const worktreeRel = path29.join(".worktrees", opts.storyId);
6411
+ const worktreeRel = path30.join(".worktrees", opts.storyId);
6343
6412
  const step1 = spawnFn(
6344
6413
  "git",
6345
6414
  ["rev-list", "--count", `${sprintBranch}..${storyBranch}`],
@@ -6437,7 +6506,7 @@ function storyCompleteHandler(opts, cli) {
6437
6506
 
6438
6507
  // src/commands/state.ts
6439
6508
  init_cjs_shims();
6440
- var path30 = __toESM(require("path"), 1);
6509
+ var path31 = __toESM(require("path"), 1);
6441
6510
  var import_node_child_process11 = require("child_process");
6442
6511
  function defaultExit3(code) {
6443
6512
  return process.exit(code);
@@ -6445,7 +6514,7 @@ function defaultExit3(code) {
6445
6514
  function resolveRunScript3(opts) {
6446
6515
  if (opts.runScriptPath) return opts.runScriptPath;
6447
6516
  const cwd = opts.cwd ?? process.cwd();
6448
- return path30.join(cwd, ".cleargate", "scripts", "run_script.sh");
6517
+ return path31.join(cwd, ".cleargate", "scripts", "run_script.sh");
6449
6518
  }
6450
6519
  function stateUpdateHandler(opts, cli) {
6451
6520
  const stdoutFn = cli?.stdout ?? ((s) => process.stdout.write(s + "\n"));
@@ -6502,21 +6571,21 @@ function stateValidateHandler(opts, cli) {
6502
6571
 
6503
6572
  // src/commands/stamp-tokens.ts
6504
6573
  init_cjs_shims();
6505
- var fs30 = __toESM(require("fs"), 1);
6506
- var path32 = __toESM(require("path"), 1);
6574
+ var fs31 = __toESM(require("fs"), 1);
6575
+ var path33 = __toESM(require("path"), 1);
6507
6576
 
6508
6577
  // src/lib/ledger-reader.ts
6509
6578
  init_cjs_shims();
6510
- var fs29 = __toESM(require("fs"), 1);
6511
- var path31 = __toESM(require("path"), 1);
6579
+ var fs30 = __toESM(require("fs"), 1);
6580
+ var path32 = __toESM(require("path"), 1);
6512
6581
  function findSprintRunsRoot(startDir) {
6513
6582
  let dir = startDir;
6514
6583
  while (true) {
6515
- const candidate = path31.join(dir, ".cleargate", "sprint-runs");
6516
- if (fs29.existsSync(candidate)) {
6584
+ const candidate = path32.join(dir, ".cleargate", "sprint-runs");
6585
+ if (fs30.existsSync(candidate)) {
6517
6586
  return candidate;
6518
6587
  }
6519
- const parent = path31.dirname(dir);
6588
+ const parent = path32.dirname(dir);
6520
6589
  if (parent === dir) {
6521
6590
  return null;
6522
6591
  }
@@ -6569,13 +6638,13 @@ function readLedgerForWorkItem(workItemId, opts = {}) {
6569
6638
  }
6570
6639
  sprintRunsRoot = found;
6571
6640
  }
6572
- if (!fs29.existsSync(sprintRunsRoot)) {
6641
+ if (!fs30.existsSync(sprintRunsRoot)) {
6573
6642
  return [];
6574
6643
  }
6575
6644
  let ledgerFiles;
6576
6645
  try {
6577
- const entries = fs29.readdirSync(sprintRunsRoot, { withFileTypes: true });
6578
- ledgerFiles = entries.filter((e) => e.isDirectory()).map((e) => path31.join(sprintRunsRoot, e.name, "token-ledger.jsonl")).filter((f) => fs29.existsSync(f));
6646
+ const entries = fs30.readdirSync(sprintRunsRoot, { withFileTypes: true });
6647
+ ledgerFiles = entries.filter((e) => e.isDirectory()).map((e) => path32.join(sprintRunsRoot, e.name, "token-ledger.jsonl")).filter((f) => fs30.existsSync(f));
6579
6648
  } catch {
6580
6649
  return [];
6581
6650
  }
@@ -6583,7 +6652,7 @@ function readLedgerForWorkItem(workItemId, opts = {}) {
6583
6652
  for (const ledgerFile of ledgerFiles) {
6584
6653
  let content;
6585
6654
  try {
6586
- content = fs29.readFileSync(ledgerFile, "utf-8");
6655
+ content = fs30.readFileSync(ledgerFile, "utf-8");
6587
6656
  } catch {
6588
6657
  continue;
6589
6658
  }
@@ -6634,7 +6703,7 @@ async function stampTokensHandler(file, opts, cli) {
6634
6703
  });
6635
6704
  const nowFn = cli?.now ?? (() => /* @__PURE__ */ new Date());
6636
6705
  const cwd = cli?.cwd ?? process.cwd();
6637
- const absPath = path32.isAbsolute(file) ? file : path32.resolve(cwd, file);
6706
+ const absPath = path33.isAbsolute(file) ? file : path33.resolve(cwd, file);
6638
6707
  if (/\/\.cleargate\/delivery\/archive\//.test(absPath)) {
6639
6708
  stdoutFn(`[frozen] ${absPath}`);
6640
6709
  exitFn(0);
@@ -6642,7 +6711,7 @@ async function stampTokensHandler(file, opts, cli) {
6642
6711
  }
6643
6712
  let rawContent;
6644
6713
  try {
6645
- rawContent = fs30.readFileSync(absPath, "utf-8");
6714
+ rawContent = fs31.readFileSync(absPath, "utf-8");
6646
6715
  } catch {
6647
6716
  stdoutFn(`[stamp-tokens] error: cannot read file: ${absPath}`);
6648
6717
  exitFn(1);
@@ -6714,7 +6783,7 @@ async function stampTokensHandler(file, opts, cli) {
6714
6783
  return;
6715
6784
  }
6716
6785
  try {
6717
- fs30.writeFileSync(absPath, serialized, "utf-8");
6786
+ fs31.writeFileSync(absPath, serialized, "utf-8");
6718
6787
  } catch {
6719
6788
  stdoutFn(`[stamp-tokens] error: cannot write file: ${absPath}`);
6720
6789
  exitFn(1);
@@ -6731,7 +6800,7 @@ function extractWorkItemId(fm, absPath) {
6731
6800
  return val.trim();
6732
6801
  }
6733
6802
  }
6734
- const basename12 = path32.basename(absPath);
6803
+ const basename12 = path33.basename(absPath);
6735
6804
  const match = basename12.match(/^(STORY|EPIC|PROPOSAL|CR|BUG)-\d+(-\d+)?/i);
6736
6805
  if (match) {
6737
6806
  return match[0].toUpperCase();
@@ -6837,7 +6906,7 @@ ${body}`;
6837
6906
  // src/commands/upgrade.ts
6838
6907
  init_cjs_shims();
6839
6908
  var fsp = __toESM(require("fs/promises"), 1);
6840
- var path33 = __toESM(require("path"), 1);
6909
+ var path34 = __toESM(require("path"), 1);
6841
6910
 
6842
6911
  // src/lib/claude-md-surgery.ts
6843
6912
  init_cjs_shims();
@@ -6987,7 +7056,7 @@ async function writeAtomic2(filePath, content) {
6987
7056
  await fsp.rename(tmpPath, filePath);
6988
7057
  }
6989
7058
  async function updateSnapshotEntry(projectRoot, filePath, newSha) {
6990
- const snapshotPath = path33.join(projectRoot, ".cleargate", ".install-manifest.json");
7059
+ const snapshotPath = path34.join(projectRoot, ".cleargate", ".install-manifest.json");
6991
7060
  let snapshot;
6992
7061
  try {
6993
7062
  const raw = await fsp.readFile(snapshotPath, "utf-8");
@@ -7004,17 +7073,17 @@ async function updateSnapshotEntry(projectRoot, filePath, newSha) {
7004
7073
  await writeAtomic2(snapshotPath, JSON.stringify(updated, null, 2) + "\n");
7005
7074
  }
7006
7075
  function isClaudeMd(filePath) {
7007
- return path33.basename(filePath) === "CLAUDE.md";
7076
+ return path34.basename(filePath) === "CLAUDE.md";
7008
7077
  }
7009
7078
  function isSettingsJson(filePath) {
7010
- return path33.basename(filePath) === "settings.json" && filePath.includes(".claude");
7079
+ return path34.basename(filePath) === "settings.json" && filePath.includes(".claude");
7011
7080
  }
7012
7081
  async function applyAlwaysOverwrite(entry, projectRoot, packageRoot, stdout) {
7013
- const targetPath = path33.join(projectRoot, entry.path);
7014
- const sourcePath = path33.join(packageRoot, entry.path);
7082
+ const targetPath = path34.join(projectRoot, entry.path);
7083
+ const sourcePath = path34.join(packageRoot, entry.path);
7015
7084
  try {
7016
7085
  const pkgContent = await fsp.readFile(sourcePath, "utf-8");
7017
- await fsp.mkdir(path33.dirname(targetPath), { recursive: true });
7086
+ await fsp.mkdir(path34.dirname(targetPath), { recursive: true });
7018
7087
  await writeAtomic2(targetPath, pkgContent);
7019
7088
  await updateSnapshotEntry(projectRoot, entry.path, entry.sha256);
7020
7089
  stdout(`[always] overwritten: ${entry.path}`);
@@ -7024,8 +7093,8 @@ async function applyAlwaysOverwrite(entry, projectRoot, packageRoot, stdout) {
7024
7093
  }
7025
7094
  async function applyMerge3Way(entry, projectRoot, packageRoot, installSha, currentSha, flags, opts) {
7026
7095
  const { stdout, stderr, promptMergeChoiceFn, openInEditorFn, stdin } = opts;
7027
- const targetPath = path33.join(projectRoot, entry.path);
7028
- const sourcePath = path33.join(packageRoot, entry.path);
7096
+ const targetPath = path34.join(projectRoot, entry.path);
7097
+ const sourcePath = path34.join(packageRoot, entry.path);
7029
7098
  let ours = "";
7030
7099
  let theirs = "";
7031
7100
  try {
@@ -7088,7 +7157,7 @@ async function applyMerge3Way(entry, projectRoot, packageRoot, installSha, curre
7088
7157
  mergedContent = theirs;
7089
7158
  }
7090
7159
  }
7091
- await fsp.mkdir(path33.dirname(targetPath), { recursive: true });
7160
+ await fsp.mkdir(path34.dirname(targetPath), { recursive: true });
7092
7161
  await writeAtomic2(targetPath, mergedContent);
7093
7162
  const newSha2 = hashNormalized(mergedContent);
7094
7163
  await updateSnapshotEntry(projectRoot, entry.path, newSha2);
@@ -7100,7 +7169,7 @@ async function applyMerge3Way(entry, projectRoot, packageRoot, installSha, curre
7100
7169
  ${ours}=======
7101
7170
  ${theirs}>>>>>>> theirs (upstream)
7102
7171
  `;
7103
- await fsp.mkdir(path33.dirname(mergeFilePath), { recursive: true });
7172
+ await fsp.mkdir(path34.dirname(mergeFilePath), { recursive: true });
7104
7173
  await writeAtomic2(mergeFilePath, conflictContent);
7105
7174
  try {
7106
7175
  const result = await openInEditorFn(mergeFilePath);
@@ -7235,9 +7304,9 @@ async function upgradeHandler(flags, cli) {
7235
7304
 
7236
7305
  // src/commands/uninstall.ts
7237
7306
  init_cjs_shims();
7238
- var fs31 = __toESM(require("fs"), 1);
7307
+ var fs32 = __toESM(require("fs"), 1);
7239
7308
  var fsp2 = __toESM(require("fs/promises"), 1);
7240
- var path34 = __toESM(require("path"), 1);
7309
+ var path35 = __toESM(require("path"), 1);
7241
7310
  var import_node_child_process13 = require("child_process");
7242
7311
  var USER_ARTIFACT_TIERS = ["user-artifact"];
7243
7312
  var FRAMEWORK_TIERS = ["protocol", "template", "agent", "hook", "skill", "cli-config", "derived"];
@@ -7263,10 +7332,10 @@ function shouldPreserve(entry, preserveSet, removeSet) {
7263
7332
  return false;
7264
7333
  }
7265
7334
  function resolveProjectName(target) {
7266
- const pkgPath = path34.join(target, "package.json");
7267
- if (fs31.existsSync(pkgPath)) {
7335
+ const pkgPath = path35.join(target, "package.json");
7336
+ if (fs32.existsSync(pkgPath)) {
7268
7337
  try {
7269
- const raw = fs31.readFileSync(pkgPath, "utf-8");
7338
+ const raw = fs32.readFileSync(pkgPath, "utf-8");
7270
7339
  const parsed = JSON.parse(raw);
7271
7340
  if (parsed.name && typeof parsed.name === "string") {
7272
7341
  return parsed.name;
@@ -7274,7 +7343,7 @@ function resolveProjectName(target) {
7274
7343
  } catch {
7275
7344
  }
7276
7345
  }
7277
- return path34.basename(target);
7346
+ return path35.basename(target);
7278
7347
  }
7279
7348
  function detectUncommittedChanges(target, manifestPaths, gitRunner) {
7280
7349
  const run = gitRunner ?? ((args) => {
@@ -7303,8 +7372,8 @@ function detectUncommittedChanges(target, manifestPaths, gitRunner) {
7303
7372
  return changedFiles.filter((f) => manifestSet.has(f));
7304
7373
  }
7305
7374
  async function removeFromPackageJson(target, dryRun) {
7306
- const pkgPath = path34.join(target, "package.json");
7307
- if (!fs31.existsSync(pkgPath)) return false;
7375
+ const pkgPath = path35.join(target, "package.json");
7376
+ if (!fs32.existsSync(pkgPath)) return false;
7308
7377
  let raw;
7309
7378
  try {
7310
7379
  raw = await fsp2.readFile(pkgPath, "utf-8");
@@ -7345,7 +7414,7 @@ async function removeFile(filePath) {
7345
7414
  }
7346
7415
  async function removeDir(dirPath) {
7347
7416
  try {
7348
- fs31.rmSync(dirPath, { recursive: true, force: true });
7417
+ fs32.rmSync(dirPath, { recursive: true, force: true });
7349
7418
  } catch {
7350
7419
  }
7351
7420
  }
@@ -7365,12 +7434,12 @@ async function uninstallHandler(opts) {
7365
7434
  for (const t of FRAMEWORK_TIERS) removeSet.add(t);
7366
7435
  for (const u of USER_ARTIFACT_TIERS) removeSet.add(u);
7367
7436
  }
7368
- const target = opts.path ? path34.resolve(opts.path) : cwd;
7369
- const cleargateDir = path34.join(target, ".cleargate");
7370
- const manifestPath = path34.join(cleargateDir, ".install-manifest.json");
7371
- const uninstalledPath = path34.join(cleargateDir, ".uninstalled");
7372
- if (!fs31.existsSync(manifestPath)) {
7373
- if (fs31.existsSync(uninstalledPath)) {
7437
+ const target = opts.path ? path35.resolve(opts.path) : cwd;
7438
+ const cleargateDir = path35.join(target, ".cleargate");
7439
+ const manifestPath = path35.join(cleargateDir, ".install-manifest.json");
7440
+ const uninstalledPath = path35.join(cleargateDir, ".uninstalled");
7441
+ if (!fs32.existsSync(manifestPath)) {
7442
+ if (fs32.existsSync(uninstalledPath)) {
7374
7443
  stdout("already uninstalled");
7375
7444
  exit(0);
7376
7445
  return;
@@ -7379,7 +7448,7 @@ async function uninstallHandler(opts) {
7379
7448
  exit(0);
7380
7449
  return;
7381
7450
  }
7382
- if (fs31.existsSync(uninstalledPath) && !fs31.existsSync(manifestPath)) {
7451
+ if (fs32.existsSync(uninstalledPath) && !fs32.existsSync(manifestPath)) {
7383
7452
  stdout("already uninstalled");
7384
7453
  exit(0);
7385
7454
  return;
@@ -7401,10 +7470,10 @@ async function uninstallHandler(opts) {
7401
7470
  return;
7402
7471
  }
7403
7472
  }
7404
- const claudeMdPath = path34.join(target, "CLAUDE.md");
7473
+ const claudeMdPath = path35.join(target, "CLAUDE.md");
7405
7474
  let claudeMdContent = null;
7406
- if (fs31.existsSync(claudeMdPath)) {
7407
- claudeMdContent = fs31.readFileSync(claudeMdPath, "utf-8");
7475
+ if (fs32.existsSync(claudeMdPath)) {
7476
+ claudeMdContent = fs32.readFileSync(claudeMdPath, "utf-8");
7408
7477
  if (!claudeMdContent.includes(CLEARGATE_START)) {
7409
7478
  stderr("CLAUDE.md is missing <!-- CLEARGATE:START --> marker");
7410
7479
  exit(1);
@@ -7420,8 +7489,8 @@ async function uninstallHandler(opts) {
7420
7489
  const toPreserve = [];
7421
7490
  const toSkip = [];
7422
7491
  for (const entry of snapshot.files) {
7423
- const filePath = path34.join(target, entry.path);
7424
- if (!fs31.existsSync(filePath)) {
7492
+ const filePath = path35.join(target, entry.path);
7493
+ if (!fs32.existsSync(filePath)) {
7425
7494
  toSkip.push(entry);
7426
7495
  continue;
7427
7496
  }
@@ -7478,7 +7547,7 @@ async function uninstallHandler(opts) {
7478
7547
  const removedPaths = [];
7479
7548
  const preservedPaths = [];
7480
7549
  for (const entry of toRemove) {
7481
- const filePath = path34.join(target, entry.path);
7550
+ const filePath = path35.join(target, entry.path);
7482
7551
  await removeFile(filePath);
7483
7552
  removedPaths.push(entry.path);
7484
7553
  }
@@ -7494,10 +7563,10 @@ async function uninstallHandler(opts) {
7494
7563
  stderr(`Warning: could not strip CLAUDE.md block: ${err.message}`);
7495
7564
  }
7496
7565
  }
7497
- const settingsPath = path34.join(target, ".claude", "settings.json");
7498
- if (fs31.existsSync(settingsPath)) {
7566
+ const settingsPath = path35.join(target, ".claude", "settings.json");
7567
+ if (fs32.existsSync(settingsPath)) {
7499
7568
  try {
7500
- const raw = fs31.readFileSync(settingsPath, "utf-8");
7569
+ const raw = fs32.readFileSync(settingsPath, "utf-8");
7501
7570
  const settings = JSON.parse(raw);
7502
7571
  const cleaned = removeClearGateHooks(settings);
7503
7572
  await writeAtomic3(settingsPath, JSON.stringify(cleaned, null, 2) + "\n");
@@ -7512,7 +7581,7 @@ async function uninstallHandler(opts) {
7512
7581
  stdout("Removed @cleargate/cli from package.json. Run `npm install` to update package-lock.json.");
7513
7582
  }
7514
7583
  await removeFile(manifestPath);
7515
- await removeFile(path34.join(cleargateDir, ".drift-state.json"));
7584
+ await removeFile(path35.join(cleargateDir, ".drift-state.json"));
7516
7585
  const marker = {
7517
7586
  uninstalled_at: now().toISOString(),
7518
7587
  prior_version: snapshot.cleargate_version,
@@ -7537,30 +7606,30 @@ async function uninstallHandler(opts) {
7537
7606
  // src/commands/sync.ts
7538
7607
  init_cjs_shims();
7539
7608
  var fsPromises8 = __toESM(require("fs/promises"), 1);
7540
- var path42 = __toESM(require("path"), 1);
7609
+ var path43 = __toESM(require("path"), 1);
7541
7610
 
7542
7611
  // src/lib/sync-log.ts
7543
7612
  init_cjs_shims();
7544
- var fs32 = __toESM(require("fs"), 1);
7613
+ var fs33 = __toESM(require("fs"), 1);
7545
7614
  var fsPromises2 = __toESM(require("fs/promises"), 1);
7546
- var path35 = __toESM(require("path"), 1);
7615
+ var path36 = __toESM(require("path"), 1);
7547
7616
  function resolveActiveSprintDir(projectRoot, _opts) {
7548
- const sprintRunsRoot = path35.join(projectRoot, ".cleargate", "sprint-runs");
7549
- const offSprint = path35.join(sprintRunsRoot, "_off-sprint");
7550
- if (!fs32.existsSync(sprintRunsRoot)) {
7551
- fs32.mkdirSync(sprintRunsRoot, { recursive: true });
7552
- fs32.mkdirSync(offSprint, { recursive: true });
7617
+ const sprintRunsRoot = path36.join(projectRoot, ".cleargate", "sprint-runs");
7618
+ const offSprint = path36.join(sprintRunsRoot, "_off-sprint");
7619
+ if (!fs33.existsSync(sprintRunsRoot)) {
7620
+ fs33.mkdirSync(sprintRunsRoot, { recursive: true });
7621
+ fs33.mkdirSync(offSprint, { recursive: true });
7553
7622
  return offSprint;
7554
7623
  }
7555
- const entries = fs32.readdirSync(sprintRunsRoot, { withFileTypes: true });
7624
+ const entries = fs33.readdirSync(sprintRunsRoot, { withFileTypes: true });
7556
7625
  const sprintDirs = entries.filter((e) => e.isDirectory() && e.name !== "_off-sprint").map((e) => {
7557
- const fullPath = path35.join(sprintRunsRoot, e.name);
7558
- const stat = fs32.statSync(fullPath);
7626
+ const fullPath = path36.join(sprintRunsRoot, e.name);
7627
+ const stat = fs33.statSync(fullPath);
7559
7628
  return { name: e.name, fullPath, mtimeMs: stat.mtimeMs };
7560
7629
  }).sort((a, b) => b.mtimeMs - a.mtimeMs);
7561
7630
  if (sprintDirs.length === 0) {
7562
- if (!fs32.existsSync(offSprint)) {
7563
- fs32.mkdirSync(offSprint, { recursive: true });
7631
+ if (!fs33.existsSync(offSprint)) {
7632
+ fs33.mkdirSync(offSprint, { recursive: true });
7564
7633
  }
7565
7634
  return offSprint;
7566
7635
  }
@@ -7571,7 +7640,7 @@ function redactDetail(detail) {
7571
7640
  return detail.replace(/eyJ[A-Za-z0-9._-]+/g, "[REDACTED]");
7572
7641
  }
7573
7642
  async function appendSyncLog(sprintRoot, entry) {
7574
- const logPath = path35.join(sprintRoot, "sync-log.jsonl");
7643
+ const logPath = path36.join(sprintRoot, "sync-log.jsonl");
7575
7644
  await fsPromises2.mkdir(sprintRoot, { recursive: true });
7576
7645
  const safeEntry = {
7577
7646
  ...entry,
@@ -7581,7 +7650,7 @@ async function appendSyncLog(sprintRoot, entry) {
7581
7650
  await fsPromises2.appendFile(logPath, line, { encoding: "utf8" });
7582
7651
  }
7583
7652
  async function readSyncLog(sprintRoot, filters) {
7584
- const logPath = path35.join(sprintRoot, "sync-log.jsonl");
7653
+ const logPath = path36.join(sprintRoot, "sync-log.jsonl");
7585
7654
  let raw;
7586
7655
  try {
7587
7656
  raw = await fsPromises2.readFile(logPath, "utf8");
@@ -7687,7 +7756,7 @@ function classify2(local, remote, since) {
7687
7756
  init_cjs_shims();
7688
7757
  var import_node_fs2 = require("fs");
7689
7758
  var os6 = __toESM(require("os"), 1);
7690
- var path36 = __toESM(require("path"), 1);
7759
+ var path37 = __toESM(require("path"), 1);
7691
7760
  function promptFourChoice(opts) {
7692
7761
  const { stdin, stdout } = opts;
7693
7762
  stdout("[k]eep mine / [t]ake theirs / [e]dit in $EDITOR / [a]bort: ");
@@ -7757,7 +7826,7 @@ async function promptThreeWayMerge(opts) {
7757
7826
  case "a":
7758
7827
  return { resolution: "aborted", body: local };
7759
7828
  case "e": {
7760
- const tmpFile = path36.join(os6.tmpdir(), `cleargate-merge-${itemId}-${now()}.md`);
7829
+ const tmpFile = path37.join(os6.tmpdir(), `cleargate-merge-${itemId}-${now()}.md`);
7761
7830
  const markerContent = `<<<<<<< local
7762
7831
  ${local}
7763
7832
  =======
@@ -7857,12 +7926,12 @@ init_config();
7857
7926
  // src/lib/intake.ts
7858
7927
  init_cjs_shims();
7859
7928
  var fsPromises4 = __toESM(require("fs/promises"), 1);
7860
- var path38 = __toESM(require("path"), 1);
7929
+ var path39 = __toESM(require("path"), 1);
7861
7930
 
7862
7931
  // src/lib/slug.ts
7863
7932
  init_cjs_shims();
7864
7933
  var fsPromises3 = __toESM(require("fs/promises"), 1);
7865
- var path37 = __toESM(require("path"), 1);
7934
+ var path38 = __toESM(require("path"), 1);
7866
7935
  function slugify(title, max = 40) {
7867
7936
  const normalized = title.normalize("NFKD").replace(new RegExp("\\p{M}", "gu"), "");
7868
7937
  const lowered = normalized.toLowerCase();
@@ -7877,8 +7946,8 @@ function slugify(title, max = 40) {
7877
7946
  var PROPOSAL_ID_RE = /^proposal_id:\s*"?PROP-(\d+)"?/m;
7878
7947
  async function nextProposalId(projectRoot) {
7879
7948
  const dirs = [
7880
- path37.join(projectRoot, ".cleargate", "delivery", "pending-sync"),
7881
- path37.join(projectRoot, ".cleargate", "delivery", "archive")
7949
+ path38.join(projectRoot, ".cleargate", "delivery", "pending-sync"),
7950
+ path38.join(projectRoot, ".cleargate", "delivery", "archive")
7882
7951
  ];
7883
7952
  let maxN = 0;
7884
7953
  for (const dir of dirs) {
@@ -7890,7 +7959,7 @@ async function nextProposalId(projectRoot) {
7890
7959
  }
7891
7960
  for (const entry of entries) {
7892
7961
  if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
7893
- const fullPath = path37.join(dir, entry.name);
7962
+ const fullPath = path38.join(dir, entry.name);
7894
7963
  try {
7895
7964
  const raw = await fsPromises3.readFile(fullPath, "utf8");
7896
7965
  const fmEnd = extractFrontmatterBlock(raw);
@@ -7908,8 +7977,8 @@ async function nextProposalId(projectRoot) {
7908
7977
  }
7909
7978
  async function findByRemoteId(projectRoot, remoteId) {
7910
7979
  const dirs = [
7911
- path37.join(projectRoot, ".cleargate", "delivery", "pending-sync"),
7912
- path37.join(projectRoot, ".cleargate", "delivery", "archive")
7980
+ path38.join(projectRoot, ".cleargate", "delivery", "pending-sync"),
7981
+ path38.join(projectRoot, ".cleargate", "delivery", "archive")
7913
7982
  ];
7914
7983
  const escaped = remoteId.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
7915
7984
  const re = new RegExp(`^remote_id:\\s*"?${escaped}"?\\s*$`, "m");
@@ -7922,7 +7991,7 @@ async function findByRemoteId(projectRoot, remoteId) {
7922
7991
  }
7923
7992
  for (const entry of entries) {
7924
7993
  if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
7925
- const fullPath = path37.join(dir, entry.name);
7994
+ const fullPath = path38.join(dir, entry.name);
7926
7995
  try {
7927
7996
  const raw = await fsPromises3.readFile(fullPath, "utf8");
7928
7997
  const fm = extractFrontmatterBlock(raw);
@@ -7951,7 +8020,7 @@ function extractFrontmatterBlock(raw) {
7951
8020
  // src/lib/intake.ts
7952
8021
  async function runIntakeBranch(opts) {
7953
8022
  const {
7954
- mcp,
8023
+ mcp: mcp2,
7955
8024
  identity,
7956
8025
  sprintRoot,
7957
8026
  projectRoot,
@@ -7959,10 +8028,10 @@ async function runIntakeBranch(opts) {
7959
8028
  labelFilter = "cleargate:proposal",
7960
8029
  now = () => (/* @__PURE__ */ new Date()).toISOString()
7961
8030
  } = opts;
7962
- const pendingSyncDir = path38.join(projectRoot, ".cleargate", "delivery", "pending-sync");
8031
+ const pendingSyncDir = path39.join(projectRoot, ".cleargate", "delivery", "pending-sync");
7963
8032
  let remoteItems = [];
7964
8033
  try {
7965
- remoteItems = await mcp.call(
8034
+ remoteItems = await mcp2.call(
7966
8035
  "cleargate_detect_new_items",
7967
8036
  { label: labelFilter }
7968
8037
  );
@@ -7990,7 +8059,7 @@ async function runIntakeBranch(opts) {
7990
8059
  const slug2 = slugify(item.title ?? "untitled");
7991
8060
  const num2 = proposalId2.replace("PROP-", "");
7992
8061
  const filename2 = `PROPOSAL-${num2}-remote-${slug2}.md`;
7993
- const targetPath2 = path38.join(pendingSyncDir, filename2);
8062
+ const targetPath2 = path39.join(pendingSyncDir, filename2);
7994
8063
  createdItems.push({
7995
8064
  proposalId: proposalId2,
7996
8065
  remoteId: item.remote_id,
@@ -8003,7 +8072,7 @@ async function runIntakeBranch(opts) {
8003
8072
  const num = proposalId.replace("PROP-", "");
8004
8073
  const slug = slugify(item.title ?? "untitled");
8005
8074
  const filename = `PROPOSAL-${num}-remote-${slug}.md`;
8006
- const targetPath = path38.join(pendingSyncDir, filename);
8075
+ const targetPath = path39.join(pendingSyncDir, filename);
8007
8076
  const nowTs = now();
8008
8077
  const fm = {
8009
8078
  proposal_id: proposalId,
@@ -8095,8 +8164,8 @@ path/to/new/file.ext - {Explanation of purpose}
8095
8164
  }
8096
8165
  async function hasAnyRemoteAuthored(projectRoot) {
8097
8166
  const dirs = [
8098
- path38.join(projectRoot, ".cleargate", "delivery", "pending-sync"),
8099
- path38.join(projectRoot, ".cleargate", "delivery", "archive")
8167
+ path39.join(projectRoot, ".cleargate", "delivery", "pending-sync"),
8168
+ path39.join(projectRoot, ".cleargate", "delivery", "archive")
8100
8169
  ];
8101
8170
  for (const dir of dirs) {
8102
8171
  let entries;
@@ -8107,7 +8176,7 @@ async function hasAnyRemoteAuthored(projectRoot) {
8107
8176
  }
8108
8177
  for (const entry of entries) {
8109
8178
  if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
8110
- const fullPath = path38.join(dir, entry.name);
8179
+ const fullPath = path39.join(dir, entry.name);
8111
8180
  try {
8112
8181
  const raw = await fsPromises4.readFile(fullPath, "utf8");
8113
8182
  const fmEnd = raw.indexOf("\n---", 4);
@@ -8125,9 +8194,9 @@ async function hasAnyRemoteAuthored(projectRoot) {
8125
8194
 
8126
8195
  // src/lib/active-criteria.ts
8127
8196
  init_cjs_shims();
8128
- var fs34 = __toESM(require("fs"), 1);
8197
+ var fs35 = __toESM(require("fs"), 1);
8129
8198
  var fsPromises5 = __toESM(require("fs/promises"), 1);
8130
- var path39 = __toESM(require("path"), 1);
8199
+ var path40 = __toESM(require("path"), 1);
8131
8200
  async function resolveActiveItems(projectRoot, localItems, nowFn = () => (/* @__PURE__ */ new Date()).toISOString()) {
8132
8201
  const active = /* @__PURE__ */ new Set();
8133
8202
  const now = Date.parse(nowFn());
@@ -8152,7 +8221,7 @@ async function resolveInSprintIds(projectRoot) {
8152
8221
  const ids = /* @__PURE__ */ new Set();
8153
8222
  try {
8154
8223
  const sprintDir = resolveActiveSprintDir(projectRoot);
8155
- const sprintId = path39.basename(sprintDir);
8224
+ const sprintId = path40.basename(sprintDir);
8156
8225
  if (sprintId === "_off-sprint") return ids;
8157
8226
  const sprintFile = await findSprintFile(projectRoot, sprintId);
8158
8227
  if (!sprintFile) return ids;
@@ -8167,14 +8236,14 @@ async function resolveInSprintIds(projectRoot) {
8167
8236
  return ids;
8168
8237
  }
8169
8238
  async function findSprintFile(projectRoot, sprintId) {
8170
- const pendingSync = path39.join(projectRoot, ".cleargate", "delivery", "pending-sync");
8171
- const archive = path39.join(projectRoot, ".cleargate", "delivery", "archive");
8239
+ const pendingSync = path40.join(projectRoot, ".cleargate", "delivery", "pending-sync");
8240
+ const archive = path40.join(projectRoot, ".cleargate", "delivery", "archive");
8172
8241
  for (const dir of [pendingSync, archive]) {
8173
8242
  try {
8174
- const entries = fs34.readdirSync(dir, { withFileTypes: true });
8243
+ const entries = fs35.readdirSync(dir, { withFileTypes: true });
8175
8244
  for (const entry of entries) {
8176
8245
  if (entry.isFile() && entry.name.startsWith(sprintId) && entry.name.endsWith(".md")) {
8177
- return path39.join(dir, entry.name);
8246
+ return path40.join(dir, entry.name);
8178
8247
  }
8179
8248
  }
8180
8249
  } catch {
@@ -8186,12 +8255,12 @@ async function findSprintFile(projectRoot, sprintId) {
8186
8255
  // src/lib/comments-cache.ts
8187
8256
  init_cjs_shims();
8188
8257
  var fsPromises6 = __toESM(require("fs/promises"), 1);
8189
- var path40 = __toESM(require("path"), 1);
8258
+ var path41 = __toESM(require("path"), 1);
8190
8259
  function cacheDir(projectRoot) {
8191
- return path40.join(projectRoot, ".cleargate", ".comments-cache");
8260
+ return path41.join(projectRoot, ".cleargate", ".comments-cache");
8192
8261
  }
8193
8262
  function cachePath(projectRoot, remoteId) {
8194
- return path40.join(cacheDir(projectRoot), `${remoteId}.json`);
8263
+ return path41.join(cacheDir(projectRoot), `${remoteId}.json`);
8195
8264
  }
8196
8265
  async function writeCommentCache(projectRoot, remoteId, comments) {
8197
8266
  const dir = cacheDir(projectRoot);
@@ -8206,7 +8275,7 @@ async function writeCommentCache(projectRoot, remoteId, comments) {
8206
8275
  // src/lib/wiki-comments-render.ts
8207
8276
  init_cjs_shims();
8208
8277
  var fsPromises7 = __toESM(require("fs/promises"), 1);
8209
- var path41 = __toESM(require("path"), 1);
8278
+ var path42 = __toESM(require("path"), 1);
8210
8279
  var START = "<!-- cleargate:comments:start -->";
8211
8280
  var END = "<!-- cleargate:comments:end -->";
8212
8281
  function resolveBucket(fm) {
@@ -8251,7 +8320,7 @@ async function renderCommentsSection(opts) {
8251
8320
  const bucket = resolveBucket(localItem.fm);
8252
8321
  const primaryId = getPrimaryId(localItem.fm);
8253
8322
  if (!bucket || !primaryId) return;
8254
- const wikiPath = path41.join(
8323
+ const wikiPath = path42.join(
8255
8324
  projectRoot,
8256
8325
  ".cleargate",
8257
8326
  "wiki",
@@ -8287,7 +8356,7 @@ async function renderCommentsSection(opts) {
8287
8356
  await writeAtomic4(wikiPath, updated);
8288
8357
  }
8289
8358
  async function writeAtomic4(filePath, content) {
8290
- await fsPromises7.mkdir(path41.dirname(filePath), { recursive: true });
8359
+ await fsPromises7.mkdir(path42.dirname(filePath), { recursive: true });
8291
8360
  const tmpPath = `${filePath}.tmp.${Date.now()}`;
8292
8361
  await fsPromises7.writeFile(tmpPath, content, "utf8");
8293
8362
  await fsPromises7.rename(tmpPath, filePath);
@@ -8299,11 +8368,11 @@ async function syncCheckHandler(opts = {}) {
8299
8368
  const env = opts.env ?? process.env;
8300
8369
  const stdout = opts.stdout ?? ((s) => process.stdout.write(s));
8301
8370
  const nowFn = opts.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
8302
- const markerPath = path42.join(projectRoot, ".cleargate", ".sync-marker.json");
8371
+ const markerPath = path43.join(projectRoot, ".cleargate", ".sync-marker.json");
8303
8372
  const updateMarker = async (nowIso2) => {
8304
8373
  try {
8305
8374
  const content = JSON.stringify({ last_check: nowIso2 });
8306
- await fsPromises8.mkdir(path42.dirname(markerPath), { recursive: true });
8375
+ await fsPromises8.mkdir(path43.dirname(markerPath), { recursive: true });
8307
8376
  const tmpPath = `${markerPath}.tmp.${Date.now()}`;
8308
8377
  await fsPromises8.writeFile(tmpPath, content, "utf8");
8309
8378
  await fsPromises8.rename(tmpPath, markerPath);
@@ -8324,9 +8393,9 @@ async function syncCheckHandler(opts = {}) {
8324
8393
  }
8325
8394
  } catch {
8326
8395
  }
8327
- let mcp;
8396
+ let mcp2;
8328
8397
  if (opts.mcp) {
8329
- mcp = opts.mcp;
8398
+ mcp2 = opts.mcp;
8330
8399
  } else {
8331
8400
  let baseUrl = env["CLEARGATE_MCP_URL"];
8332
8401
  if (!baseUrl || !baseUrl.trim()) {
@@ -8355,10 +8424,10 @@ async function syncCheckHandler(opts = {}) {
8355
8424
  await emitError("adapter-not-configured", nowIso);
8356
8425
  return;
8357
8426
  }
8358
- mcp = createMcpClient({ baseUrl: baseUrl.trim(), token: accessToken });
8427
+ mcp2 = createMcpClient({ baseUrl: baseUrl.trim(), token: accessToken });
8359
8428
  }
8360
8429
  try {
8361
- const adapterInfo = await mcp.adapterInfo();
8430
+ const adapterInfo = await mcp2.adapterInfo();
8362
8431
  if (!adapterInfo.configured || adapterInfo.name === "no-adapter-configured") {
8363
8432
  await emitError("adapter-not-configured", nowIso);
8364
8433
  return;
@@ -8367,7 +8436,7 @@ async function syncCheckHandler(opts = {}) {
8367
8436
  }
8368
8437
  let refs;
8369
8438
  try {
8370
- refs = await mcp.call("cleargate_list_remote_updates", { since });
8439
+ refs = await mcp2.call("cleargate_list_remote_updates", { since });
8371
8440
  } catch (err) {
8372
8441
  const msg = err instanceof Error ? err.message : String(err);
8373
8442
  await emitError(msg, nowIso);
@@ -8386,10 +8455,10 @@ async function syncHandler(opts = {}) {
8386
8455
  const nowFn = opts.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
8387
8456
  const identity = resolveIdentity(projectRoot);
8388
8457
  const sprintRoot = resolveActiveSprintDir(projectRoot);
8389
- const sprintId = path42.basename(sprintRoot);
8390
- let mcp;
8458
+ const sprintId = path43.basename(sprintRoot);
8459
+ let mcp2;
8391
8460
  if (opts.mcp) {
8392
- mcp = opts.mcp;
8461
+ mcp2 = opts.mcp;
8393
8462
  } else {
8394
8463
  let baseUrl = env["CLEARGATE_MCP_URL"];
8395
8464
  if (!baseUrl || !baseUrl.trim()) {
@@ -8432,11 +8501,11 @@ async function syncHandler(opts = {}) {
8432
8501
  exit(2);
8433
8502
  return;
8434
8503
  }
8435
- mcp = createMcpClient({ baseUrl: baseUrl.trim(), token: accessToken });
8504
+ mcp2 = createMcpClient({ baseUrl: baseUrl.trim(), token: accessToken });
8436
8505
  }
8437
8506
  let adapterInfo;
8438
8507
  try {
8439
- adapterInfo = await mcp.adapterInfo();
8508
+ adapterInfo = await mcp2.adapterInfo();
8440
8509
  } catch {
8441
8510
  adapterInfo = { configured: true, name: "unknown" };
8442
8511
  }
@@ -8447,7 +8516,7 @@ async function syncHandler(opts = {}) {
8447
8516
  exit(2);
8448
8517
  return;
8449
8518
  }
8450
- const wikiMetaPath = path42.join(projectRoot, ".cleargate", "wiki", "meta.json");
8519
+ const wikiMetaPath = path43.join(projectRoot, ".cleargate", "wiki", "meta.json");
8451
8520
  let lastRemoteSync = "1970-01-01T00:00:00.000Z";
8452
8521
  try {
8453
8522
  const metaRaw = await fsPromises8.readFile(wikiMetaPath, "utf8");
@@ -8457,13 +8526,13 @@ async function syncHandler(opts = {}) {
8457
8526
  }
8458
8527
  } catch {
8459
8528
  }
8460
- const remoteRefs = await mcp.call(
8529
+ const remoteRefs = await mcp2.call(
8461
8530
  "cleargate_list_remote_updates",
8462
8531
  { since: lastRemoteSync }
8463
8532
  );
8464
8533
  const pulled = [];
8465
8534
  for (const ref of remoteRefs) {
8466
- const item = await mcp.call(
8535
+ const item = await mcp2.call(
8467
8536
  "cleargate_pull_item",
8468
8537
  { remote_id: ref.remote_id }
8469
8538
  );
@@ -8475,7 +8544,7 @@ async function syncHandler(opts = {}) {
8475
8544
  let intakeResult = { created: 0, items: [] };
8476
8545
  try {
8477
8546
  intakeResult = await runIntakeBranch({
8478
- mcp,
8547
+ mcp: mcp2,
8479
8548
  identity,
8480
8549
  sprintRoot,
8481
8550
  projectRoot,
@@ -8501,7 +8570,7 @@ async function syncHandler(opts = {}) {
8501
8570
  const activeSet = await resolveActiveItems(projectRoot, localRefs, nowFn);
8502
8571
  for (const remoteId of activeSet) {
8503
8572
  try {
8504
- const comments = await mcp.call(
8573
+ const comments = await mcp2.call(
8505
8574
  "cleargate_pull_comments",
8506
8575
  { remote_id: remoteId }
8507
8576
  );
@@ -8655,7 +8724,7 @@ async function syncHandler(opts = {}) {
8655
8724
  await appendSyncLog(sprintRoot, entry);
8656
8725
  }
8657
8726
  for (const { localPath, fm, body, itemId } of pushQueue) {
8658
- await mcp.call("push_item", {
8727
+ await mcp2.call("push_item", {
8659
8728
  cleargate_id: itemId,
8660
8729
  type: typeof fm["story_id"] === "string" ? "story" : typeof fm["epic_id"] === "string" ? "epic" : typeof fm["proposal_id"] === "string" ? "proposal" : "story",
8661
8730
  payload: fm
@@ -8688,7 +8757,7 @@ async function syncHandler(opts = {}) {
8688
8757
  };
8689
8758
  await appendSyncLog(sprintRoot, entry);
8690
8759
  }
8691
- const conflictsFile = path42.join(projectRoot, ".cleargate", ".conflicts.json");
8760
+ const conflictsFile = path43.join(projectRoot, ".cleargate", ".conflicts.json");
8692
8761
  const conflictsContent = {
8693
8762
  generated_at: nowFn(),
8694
8763
  sprint_id: sprintId,
@@ -8696,7 +8765,7 @@ async function syncHandler(opts = {}) {
8696
8765
  };
8697
8766
  await writeAtomic5(conflictsFile, JSON.stringify(conflictsContent, null, 2) + "\n");
8698
8767
  try {
8699
- await fsPromises8.mkdir(path42.dirname(wikiMetaPath), { recursive: true });
8768
+ await fsPromises8.mkdir(path43.dirname(wikiMetaPath), { recursive: true });
8700
8769
  let meta = {};
8701
8770
  try {
8702
8771
  const raw = await fsPromises8.readFile(wikiMetaPath, "utf8");
@@ -8737,13 +8806,13 @@ async function applyPull(item, localPath, fm, actorEmail, nowFn) {
8737
8806
  await writeAtomic5(localPath, newContent);
8738
8807
  }
8739
8808
  async function writeAtomic5(filePath, content) {
8740
- await fsPromises8.mkdir(path42.dirname(filePath), { recursive: true });
8809
+ await fsPromises8.mkdir(path43.dirname(filePath), { recursive: true });
8741
8810
  const tmpPath = `${filePath}.tmp.${Date.now()}`;
8742
8811
  await fsPromises8.writeFile(tmpPath, content, "utf8");
8743
8812
  await fsPromises8.rename(tmpPath, filePath);
8744
8813
  }
8745
8814
  async function scanLocalItems(projectRoot) {
8746
- const pendingSync = path42.join(projectRoot, ".cleargate", "delivery", "pending-sync");
8815
+ const pendingSync = path43.join(projectRoot, ".cleargate", "delivery", "pending-sync");
8747
8816
  const results = [];
8748
8817
  let entries;
8749
8818
  try {
@@ -8753,7 +8822,7 @@ async function scanLocalItems(projectRoot) {
8753
8822
  }
8754
8823
  for (const entry of entries) {
8755
8824
  if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
8756
- const fullPath = path42.join(pendingSync, entry.name);
8825
+ const fullPath = path43.join(pendingSync, entry.name);
8757
8826
  try {
8758
8827
  const raw = await fsPromises8.readFile(fullPath, "utf8");
8759
8828
  const { fm, body } = parseFrontmatter(raw);
@@ -8776,7 +8845,7 @@ function getItemId(fm) {
8776
8845
  // src/commands/pull.ts
8777
8846
  init_cjs_shims();
8778
8847
  var fsPromises9 = __toESM(require("fs/promises"), 1);
8779
- var path43 = __toESM(require("path"), 1);
8848
+ var path44 = __toESM(require("path"), 1);
8780
8849
  init_acquire();
8781
8850
  init_config();
8782
8851
  async function pullHandler(idOrRemoteId, opts = {}) {
@@ -8788,9 +8857,9 @@ async function pullHandler(idOrRemoteId, opts = {}) {
8788
8857
  const nowFn = opts.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
8789
8858
  const identity = resolveIdentity(projectRoot);
8790
8859
  const sprintRoot = resolveActiveSprintDir(projectRoot);
8791
- let mcp;
8860
+ let mcp2;
8792
8861
  if (opts.mcp) {
8793
- mcp = opts.mcp;
8862
+ mcp2 = opts.mcp;
8794
8863
  } else {
8795
8864
  let baseUrl = env["CLEARGATE_MCP_URL"];
8796
8865
  if (!baseUrl || !baseUrl.trim()) {
@@ -8825,7 +8894,7 @@ async function pullHandler(idOrRemoteId, opts = {}) {
8825
8894
  exit(2);
8826
8895
  return;
8827
8896
  }
8828
- mcp = createMcpClient({ baseUrl: baseUrl.trim(), token: accessToken });
8897
+ mcp2 = createMcpClient({ baseUrl: baseUrl.trim(), token: accessToken });
8829
8898
  }
8830
8899
  const remoteId = await resolveRemoteId(idOrRemoteId, projectRoot);
8831
8900
  if (!remoteId) {
@@ -8834,7 +8903,7 @@ async function pullHandler(idOrRemoteId, opts = {}) {
8834
8903
  exit(1);
8835
8904
  return;
8836
8905
  }
8837
- const remoteItem = await mcp.call("cleargate_pull_item", { remote_id: remoteId });
8906
+ const remoteItem = await mcp2.call("cleargate_pull_item", { remote_id: remoteId });
8838
8907
  if (!remoteItem) {
8839
8908
  stderr(`Error: item ${remoteId} not found on MCP server.
8840
8909
  `);
@@ -8891,10 +8960,10 @@ async function pullHandler(idOrRemoteId, opts = {}) {
8891
8960
  result: "ok"
8892
8961
  };
8893
8962
  await appendSyncLog(sprintRoot, entry);
8894
- stdout(`pull: ${remoteId} applied to ${path43.relative(projectRoot, localPath)}
8963
+ stdout(`pull: ${remoteId} applied to ${path44.relative(projectRoot, localPath)}
8895
8964
  `);
8896
8965
  if (opts.comments) {
8897
- const comments = await mcp.call(
8966
+ const comments = await mcp2.call(
8898
8967
  "cleargate_pull_comments",
8899
8968
  { remote_id: remoteId }
8900
8969
  );
@@ -8914,7 +8983,7 @@ async function resolveRemoteId(idOrRemoteId, projectRoot) {
8914
8983
  if (/^[A-Z]+-\d+/.test(idOrRemoteId)) {
8915
8984
  return idOrRemoteId;
8916
8985
  }
8917
- const pendingSync = path43.join(projectRoot, ".cleargate", "delivery", "pending-sync");
8986
+ const pendingSync = path44.join(projectRoot, ".cleargate", "delivery", "pending-sync");
8918
8987
  let entries;
8919
8988
  try {
8920
8989
  entries = await fsPromises9.readdir(pendingSync, { withFileTypes: true });
@@ -8924,7 +8993,7 @@ async function resolveRemoteId(idOrRemoteId, projectRoot) {
8924
8993
  for (const entry of entries) {
8925
8994
  if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
8926
8995
  try {
8927
- const raw = await fsPromises9.readFile(path43.join(pendingSync, entry.name), "utf8");
8996
+ const raw = await fsPromises9.readFile(path44.join(pendingSync, entry.name), "utf8");
8928
8997
  const { fm } = parseFrontmatter(raw);
8929
8998
  for (const key of ["story_id", "epic_id", "proposal_id", "cr_id", "bug_id"]) {
8930
8999
  if (fm[key] === idOrRemoteId && typeof fm["remote_id"] === "string") {
@@ -8937,7 +9006,7 @@ async function resolveRemoteId(idOrRemoteId, projectRoot) {
8937
9006
  return null;
8938
9007
  }
8939
9008
  async function findLocalFile(remoteId, projectRoot) {
8940
- const pendingSync = path43.join(projectRoot, ".cleargate", "delivery", "pending-sync");
9009
+ const pendingSync = path44.join(projectRoot, ".cleargate", "delivery", "pending-sync");
8941
9010
  let entries;
8942
9011
  try {
8943
9012
  entries = await fsPromises9.readdir(pendingSync, { withFileTypes: true });
@@ -8946,7 +9015,7 @@ async function findLocalFile(remoteId, projectRoot) {
8946
9015
  }
8947
9016
  for (const entry of entries) {
8948
9017
  if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
8949
- const fullPath = path43.join(pendingSync, entry.name);
9018
+ const fullPath = path44.join(pendingSync, entry.name);
8950
9019
  try {
8951
9020
  const raw = await fsPromises9.readFile(fullPath, "utf8");
8952
9021
  const { fm } = parseFrontmatter(raw);
@@ -8957,7 +9026,7 @@ async function findLocalFile(remoteId, projectRoot) {
8957
9026
  return null;
8958
9027
  }
8959
9028
  async function writeAtomic6(filePath, content) {
8960
- await fsPromises9.mkdir(path43.dirname(filePath), { recursive: true });
9029
+ await fsPromises9.mkdir(path44.dirname(filePath), { recursive: true });
8961
9030
  const tmpPath = `${filePath}.tmp.${Date.now()}`;
8962
9031
  await fsPromises9.writeFile(tmpPath, content, "utf8");
8963
9032
  await fsPromises9.rename(tmpPath, filePath);
@@ -8973,7 +9042,7 @@ function getItemId2(fm) {
8973
9042
  // src/commands/push.ts
8974
9043
  init_cjs_shims();
8975
9044
  var fsPromises10 = __toESM(require("fs/promises"), 1);
8976
- var path44 = __toESM(require("path"), 1);
9045
+ var path45 = __toESM(require("path"), 1);
8977
9046
  init_acquire();
8978
9047
  init_config();
8979
9048
  async function pushHandler(fileOrId, opts = {}) {
@@ -9049,7 +9118,7 @@ async function pushHandler(fileOrId, opts = {}) {
9049
9118
  }
9050
9119
  async function handlePush(filePath, ctx) {
9051
9120
  const { projectRoot, identity, sprintRoot, nowFn, resolveMcp, stdout, stderr, exit } = ctx;
9052
- const resolvedPath = path44.isAbsolute(filePath) ? filePath : path44.resolve(projectRoot, filePath);
9121
+ const resolvedPath = path45.isAbsolute(filePath) ? filePath : path45.resolve(projectRoot, filePath);
9053
9122
  let rawContent;
9054
9123
  try {
9055
9124
  rawContent = await fsPromises10.readFile(resolvedPath, "utf8");
@@ -9092,10 +9161,10 @@ async function handlePush(filePath, ctx) {
9092
9161
  if (h1) payloadForPush["title"] = h1;
9093
9162
  }
9094
9163
  payloadForPush["body"] = body;
9095
- const mcp = await resolveMcp();
9164
+ const mcp2 = await resolveMcp();
9096
9165
  let result;
9097
9166
  try {
9098
- result = await mcp.call("push_item", {
9167
+ result = await mcp2.call("push_item", {
9099
9168
  cleargate_id: itemId,
9100
9169
  type,
9101
9170
  payload: payloadForPush,
@@ -9147,9 +9216,9 @@ async function handleRevert(idOrRemoteId, ctx) {
9147
9216
  exit(1);
9148
9217
  return;
9149
9218
  }
9150
- const mcp = await resolveMcp();
9219
+ const mcp2 = await resolveMcp();
9151
9220
  try {
9152
- await mcp.call("sync_status", {
9221
+ await mcp2.call("sync_status", {
9153
9222
  cleargate_id: itemId,
9154
9223
  new_status: "archived-without-shipping"
9155
9224
  });
@@ -9175,8 +9244,8 @@ async function handleRevert(idOrRemoteId, ctx) {
9175
9244
  void localPath;
9176
9245
  }
9177
9246
  async function resolveLocalItem(idOrRemoteId, projectRoot) {
9178
- const pendingSync = path44.join(projectRoot, ".cleargate", "delivery", "pending-sync");
9179
- const archive = path44.join(projectRoot, ".cleargate", "delivery", "archive");
9247
+ const pendingSync = path45.join(projectRoot, ".cleargate", "delivery", "pending-sync");
9248
+ const archive = path45.join(projectRoot, ".cleargate", "delivery", "archive");
9180
9249
  for (const dir of [pendingSync, archive]) {
9181
9250
  let entries;
9182
9251
  try {
@@ -9186,7 +9255,7 @@ async function resolveLocalItem(idOrRemoteId, projectRoot) {
9186
9255
  }
9187
9256
  for (const entry of entries) {
9188
9257
  if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
9189
- const fullPath = path44.join(dir, entry.name);
9258
+ const fullPath = path45.join(dir, entry.name);
9190
9259
  try {
9191
9260
  const raw = await fsPromises10.readFile(fullPath, "utf8");
9192
9261
  const { fm } = parseFrontmatter(raw);
@@ -9205,7 +9274,7 @@ async function resolveLocalItem(idOrRemoteId, projectRoot) {
9205
9274
  return null;
9206
9275
  }
9207
9276
  async function writeAtomic7(filePath, content) {
9208
- await fsPromises10.mkdir(path44.dirname(filePath), { recursive: true });
9277
+ await fsPromises10.mkdir(path45.dirname(filePath), { recursive: true });
9209
9278
  const tmpPath = `${filePath}.tmp.${Date.now()}`;
9210
9279
  await fsPromises10.writeFile(tmpPath, content, "utf8");
9211
9280
  await fsPromises10.rename(tmpPath, filePath);
@@ -9234,7 +9303,7 @@ function getItemType(fm) {
9234
9303
  // src/commands/conflicts.ts
9235
9304
  init_cjs_shims();
9236
9305
  var fsPromises11 = __toESM(require("fs/promises"), 1);
9237
- var path45 = __toESM(require("path"), 1);
9306
+ var path46 = __toESM(require("path"), 1);
9238
9307
  init_acquire();
9239
9308
  init_config();
9240
9309
  var RESOLUTION_HINTS = {
@@ -9272,7 +9341,7 @@ async function conflictsHandler(opts = {}) {
9272
9341
  }
9273
9342
  }
9274
9343
  }
9275
- const conflictsFile = path45.join(projectRoot, ".cleargate", ".conflicts.json");
9344
+ const conflictsFile = path46.join(projectRoot, ".cleargate", ".conflicts.json");
9276
9345
  let data;
9277
9346
  try {
9278
9347
  const raw = await fsPromises11.readFile(conflictsFile, "utf8");
@@ -9360,8 +9429,8 @@ function formatEntry(entry) {
9360
9429
 
9361
9430
  // src/commands/admin-login.ts
9362
9431
  init_cjs_shims();
9363
- var fs35 = __toESM(require("fs"), 1);
9364
- var path46 = __toESM(require("path"), 1);
9432
+ var fs36 = __toESM(require("fs"), 1);
9433
+ var path47 = __toESM(require("path"), 1);
9365
9434
  var os7 = __toESM(require("os"), 1);
9366
9435
  var DEFAULT_MCP_URL = "http://localhost:3000";
9367
9436
  function resolveMcpUrl(mcpUrlFlag, env) {
@@ -9370,14 +9439,14 @@ function resolveMcpUrl(mcpUrlFlag, env) {
9370
9439
  function resolveAuthFilePath(opts) {
9371
9440
  if (opts.authFilePath) return opts.authFilePath;
9372
9441
  const homedirFn = opts.homedir ?? os7.homedir;
9373
- return path46.join(homedirFn(), ".cleargate", "admin-auth.json");
9442
+ return path47.join(homedirFn(), ".cleargate", "admin-auth.json");
9374
9443
  }
9375
9444
  function writeAdminAuth(filePath, token) {
9376
- const dir = path46.dirname(filePath);
9377
- fs35.mkdirSync(dir, { recursive: true });
9445
+ const dir = path47.dirname(filePath);
9446
+ fs36.mkdirSync(dir, { recursive: true });
9378
9447
  const payload = JSON.stringify({ version: 1, token }, null, 2);
9379
- fs35.writeFileSync(filePath, payload, { encoding: "utf8", mode: 384 });
9380
- fs35.chmodSync(filePath, 384);
9448
+ fs36.writeFileSync(filePath, payload, { encoding: "utf8", mode: 384 });
9449
+ fs36.chmodSync(filePath, 384);
9381
9450
  }
9382
9451
  async function adminLoginHandler(opts = {}) {
9383
9452
  const fetchFn = opts.fetch ?? globalThis.fetch;
@@ -9487,8 +9556,8 @@ async function adminLoginHandler(opts = {}) {
9487
9556
 
9488
9557
  // src/commands/hotfix.ts
9489
9558
  init_cjs_shims();
9490
- var fs36 = __toESM(require("fs"), 1);
9491
- var path47 = __toESM(require("path"), 1);
9559
+ var fs37 = __toESM(require("fs"), 1);
9560
+ var path48 = __toESM(require("path"), 1);
9492
9561
  function defaultExit4(code) {
9493
9562
  return process.exit(code);
9494
9563
  }
@@ -9498,7 +9567,7 @@ function maxHotfixId(pendingDir) {
9498
9567
  let max = 0;
9499
9568
  let entries;
9500
9569
  try {
9501
- entries = fs36.readdirSync(pendingDir);
9570
+ entries = fs37.readdirSync(pendingDir);
9502
9571
  } catch {
9503
9572
  return 0;
9504
9573
  }
@@ -9512,13 +9581,13 @@ function maxHotfixId(pendingDir) {
9512
9581
  return max;
9513
9582
  }
9514
9583
  function countActiveHotfixes(repoRoot) {
9515
- const pendingDir = path47.join(repoRoot, ".cleargate", "delivery", "pending-sync");
9516
- const archiveDir = path47.join(repoRoot, ".cleargate", "delivery", "archive");
9584
+ const pendingDir = path48.join(repoRoot, ".cleargate", "delivery", "pending-sync");
9585
+ const archiveDir = path48.join(repoRoot, ".cleargate", "delivery", "archive");
9517
9586
  const sevenDaysAgo = Date.now() - 7 * 24 * 60 * 60 * 1e3;
9518
9587
  let count = 0;
9519
9588
  let pendingEntries = [];
9520
9589
  try {
9521
- pendingEntries = fs36.readdirSync(pendingDir);
9590
+ pendingEntries = fs37.readdirSync(pendingDir);
9522
9591
  } catch {
9523
9592
  }
9524
9593
  for (const entry of pendingEntries) {
@@ -9526,13 +9595,13 @@ function countActiveHotfixes(repoRoot) {
9526
9595
  }
9527
9596
  let archiveEntries = [];
9528
9597
  try {
9529
- archiveEntries = fs36.readdirSync(archiveDir);
9598
+ archiveEntries = fs37.readdirSync(archiveDir);
9530
9599
  } catch {
9531
9600
  }
9532
9601
  for (const entry of archiveEntries) {
9533
9602
  if (entry.startsWith("HOTFIX-") && entry.endsWith(".md")) {
9534
9603
  try {
9535
- const stat = fs36.statSync(path47.join(archiveDir, entry));
9604
+ const stat = fs37.statSync(path48.join(archiveDir, entry));
9536
9605
  if (stat.mtimeMs >= sevenDaysAgo) count++;
9537
9606
  } catch {
9538
9607
  }
@@ -9541,7 +9610,7 @@ function countActiveHotfixes(repoRoot) {
9541
9610
  return count;
9542
9611
  }
9543
9612
  function resolveTemplatePath(repoRoot) {
9544
- return path47.join(repoRoot, ".cleargate", "templates", "hotfix.md");
9613
+ return path48.join(repoRoot, ".cleargate", "templates", "hotfix.md");
9545
9614
  }
9546
9615
  function hotfixNewHandler(opts, cli) {
9547
9616
  const stdoutFn = cli?.stdout ?? ((s) => process.stdout.write(s + "\n"));
@@ -9560,14 +9629,14 @@ function hotfixNewHandler(opts, cli) {
9560
9629
  );
9561
9630
  return exitFn(1);
9562
9631
  }
9563
- const pendingDir = path47.join(repoRoot, ".cleargate", "delivery", "pending-sync");
9632
+ const pendingDir = path48.join(repoRoot, ".cleargate", "delivery", "pending-sync");
9564
9633
  const maxId = maxHotfixId(pendingDir);
9565
9634
  const nextId = maxId + 1;
9566
9635
  const idStr = `HOTFIX-${String(nextId).padStart(3, "0")}`;
9567
9636
  const templatePath = resolveTemplatePath(repoRoot);
9568
9637
  let templateContent;
9569
9638
  try {
9570
- templateContent = fs36.readFileSync(templatePath, "utf8");
9639
+ templateContent = fs37.readFileSync(templatePath, "utf8");
9571
9640
  } catch {
9572
9641
  stderrFn(`[cleargate hotfix new] template not found: ${templatePath}`);
9573
9642
  return exitFn(2);
@@ -9575,10 +9644,10 @@ function hotfixNewHandler(opts, cli) {
9575
9644
  const content = templateContent.replace(/\{ID\}/g, idStr).replace(/\{SLUG\}/g, opts.slug).replace(/\{ISO\}/g, now);
9576
9645
  const fileSlug = opts.slug.replace(/-/g, "_");
9577
9646
  const fileName = `${idStr}_${fileSlug}.md`;
9578
- const outPath = path47.join(pendingDir, fileName);
9647
+ const outPath = path48.join(pendingDir, fileName);
9579
9648
  try {
9580
- fs36.mkdirSync(pendingDir, { recursive: true });
9581
- fs36.writeFileSync(outPath, content, "utf8");
9649
+ fs37.mkdirSync(pendingDir, { recursive: true });
9650
+ fs37.writeFileSync(outPath, content, "utf8");
9582
9651
  } catch (err) {
9583
9652
  const msg = err instanceof Error ? err.message : String(err);
9584
9653
  stderrFn(`[cleargate hotfix new] write failed: ${msg}`);
@@ -9588,6 +9657,218 @@ function hotfixNewHandler(opts, cli) {
9588
9657
  return exitFn(0);
9589
9658
  }
9590
9659
 
9660
+ // src/commands/mcp-serve.ts
9661
+ init_cjs_shims();
9662
+ var readline5 = __toESM(require("readline"), 1);
9663
+ init_config();
9664
+ init_factory();
9665
+
9666
+ // src/auth/refresh.ts
9667
+ init_cjs_shims();
9668
+ async function refreshAccessToken(baseUrl, refreshToken, deps = {}) {
9669
+ const fetchFn = deps.fetch ?? globalThis.fetch;
9670
+ const res = await fetchFn(`${baseUrl}/auth/refresh`, {
9671
+ method: "POST",
9672
+ headers: { "Content-Type": "application/json", Accept: "application/json" },
9673
+ body: JSON.stringify({ refresh_token: refreshToken })
9674
+ });
9675
+ if (!res.ok) {
9676
+ const body = await res.json().catch(() => ({}));
9677
+ throw new RefreshError(res.status, body.error ?? "unknown_error");
9678
+ }
9679
+ const json = await res.json();
9680
+ if (typeof json.access_token !== "string" || typeof json.refresh_token !== "string" || typeof json.expires_in !== "number") {
9681
+ throw new RefreshError(500, "malformed_response");
9682
+ }
9683
+ return json;
9684
+ }
9685
+ var RefreshError = class extends Error {
9686
+ constructor(status, code) {
9687
+ super(`refresh failed: ${status} ${code}`);
9688
+ this.status = status;
9689
+ this.code = code;
9690
+ this.name = "RefreshError";
9691
+ }
9692
+ status;
9693
+ code;
9694
+ };
9695
+ var AuthFetcher = class {
9696
+ constructor(opts) {
9697
+ this.opts = opts;
9698
+ }
9699
+ opts;
9700
+ accessToken = null;
9701
+ accessExpiresAt = 0;
9702
+ inflight = null;
9703
+ /** Returns a fresh access token, refreshing if needed. */
9704
+ async getAccessToken() {
9705
+ const now = (this.opts.now ?? (() => Date.now()))();
9706
+ const skewMs = (this.opts.skewSeconds ?? 60) * 1e3;
9707
+ if (this.accessToken && now < this.accessExpiresAt - skewMs) {
9708
+ return this.accessToken;
9709
+ }
9710
+ if (this.inflight) return this.inflight;
9711
+ this.inflight = this.refreshNow().finally(() => {
9712
+ this.inflight = null;
9713
+ });
9714
+ return this.inflight;
9715
+ }
9716
+ /** Force the next call to refresh. Used after a 401. */
9717
+ invalidate() {
9718
+ this.accessToken = null;
9719
+ this.accessExpiresAt = 0;
9720
+ }
9721
+ async refreshNow() {
9722
+ const stored = await this.opts.loadRefresh();
9723
+ if (!stored) {
9724
+ throw new RefreshError(401, "no_refresh_token");
9725
+ }
9726
+ const exchanged = await refreshAccessToken(this.opts.baseUrl, stored, {
9727
+ ...this.opts.fetch ? { fetch: this.opts.fetch } : {},
9728
+ ...this.opts.now ? { now: this.opts.now } : {}
9729
+ });
9730
+ await this.opts.saveRefresh(exchanged.refresh_token);
9731
+ const now = (this.opts.now ?? (() => Date.now()))();
9732
+ this.accessToken = exchanged.access_token;
9733
+ this.accessExpiresAt = now + exchanged.expires_in * 1e3;
9734
+ return exchanged.access_token;
9735
+ }
9736
+ };
9737
+
9738
+ // src/commands/mcp-serve.ts
9739
+ var DEFAULT_BASE_URL = "https://cleargate-mcp.soula.ge";
9740
+ async function mcpServeHandler(opts) {
9741
+ const fetchFn = opts.fetch ?? globalThis.fetch;
9742
+ const stdout = opts.stdout ?? ((s) => process.stdout.write(s));
9743
+ const stderr = opts.stderr ?? ((s) => process.stderr.write(s));
9744
+ const exit = opts.exit ?? ((c) => process.exit(c));
9745
+ const cfg = loadConfig({
9746
+ flags: { profile: opts.profile, mcpUrl: opts.mcpUrlFlag }
9747
+ });
9748
+ const baseUrl = cfg.mcpUrl ?? DEFAULT_BASE_URL;
9749
+ const store = await (opts.createStore ?? createTokenStore)({
9750
+ ...opts.keychainService !== void 0 ? { keychainService: opts.keychainService } : {},
9751
+ ...opts.forceBackend !== void 0 ? { forceBackend: opts.forceBackend } : {}
9752
+ });
9753
+ const fetcher = new AuthFetcher({
9754
+ baseUrl,
9755
+ loadRefresh: () => store.load(opts.profile),
9756
+ saveRefresh: (t) => store.save(opts.profile, t),
9757
+ ...opts.fetch !== void 0 ? { fetch: opts.fetch } : {},
9758
+ ...opts.now !== void 0 ? { now: opts.now } : {}
9759
+ });
9760
+ try {
9761
+ await fetcher.getAccessToken();
9762
+ } catch (err) {
9763
+ if (err instanceof RefreshError) {
9764
+ stderr(
9765
+ `cleargate mcp serve: refresh failed (${err.status} ${err.code}). Run \`cleargate join <invite-url>\` to re-authenticate.
9766
+ `
9767
+ );
9768
+ } else {
9769
+ stderr(
9770
+ `cleargate mcp serve: ${err instanceof Error ? err.message : String(err)}
9771
+ `
9772
+ );
9773
+ }
9774
+ return exit(1);
9775
+ }
9776
+ const inputStream = opts.stdin ?? process.stdin;
9777
+ const rl = readline5.createInterface({
9778
+ input: inputStream,
9779
+ output: void 0,
9780
+ terminal: false
9781
+ });
9782
+ for await (const line of rl) {
9783
+ if (!line.trim()) continue;
9784
+ try {
9785
+ await proxyOne(line, baseUrl, fetcher, fetchFn, stdout, stderr);
9786
+ } catch (err) {
9787
+ const errMsg = err instanceof Error ? err.message : String(err);
9788
+ stderr(`cleargate mcp serve: proxy error: ${errMsg}
9789
+ `);
9790
+ const id = extractId(line);
9791
+ if (id !== void 0) {
9792
+ stdout(
9793
+ JSON.stringify({
9794
+ jsonrpc: "2.0",
9795
+ id,
9796
+ error: { code: -32603, message: `proxy error: ${errMsg}` }
9797
+ }) + "\n"
9798
+ );
9799
+ }
9800
+ }
9801
+ }
9802
+ }
9803
+ async function proxyOne(line, baseUrl, fetcher, fetchFn, stdout, stderr) {
9804
+ let parsed;
9805
+ try {
9806
+ parsed = JSON.parse(line);
9807
+ } catch {
9808
+ stderr(`cleargate mcp serve: ignoring non-JSON line: ${line.slice(0, 80)}
9809
+ `);
9810
+ return;
9811
+ }
9812
+ const isNotification = !("id" in parsed) || parsed.id === void 0 || parsed.id === null;
9813
+ let access = await fetcher.getAccessToken();
9814
+ let res = await postFrame(baseUrl, line, access, fetchFn);
9815
+ if (res.status === 401) {
9816
+ fetcher.invalidate();
9817
+ access = await fetcher.getAccessToken();
9818
+ res = await postFrame(baseUrl, line, access, fetchFn);
9819
+ }
9820
+ if (isNotification) {
9821
+ await res.arrayBuffer().catch(() => void 0);
9822
+ return;
9823
+ }
9824
+ const ct = res.headers.get("content-type") ?? "";
9825
+ if (ct.includes("text/event-stream")) {
9826
+ await streamSse(res, stdout);
9827
+ } else {
9828
+ const text = await res.text();
9829
+ if (text.length > 0) stdout(text + "\n");
9830
+ }
9831
+ }
9832
+ async function postFrame(baseUrl, body, accessToken, fetchFn) {
9833
+ return fetchFn(`${baseUrl}/mcp`, {
9834
+ method: "POST",
9835
+ headers: {
9836
+ "Content-Type": "application/json",
9837
+ Accept: "application/json, text/event-stream",
9838
+ Authorization: `Bearer ${accessToken}`
9839
+ },
9840
+ body
9841
+ });
9842
+ }
9843
+ async function streamSse(res, stdout) {
9844
+ if (!res.body) return;
9845
+ const reader = res.body.getReader();
9846
+ const decoder = new TextDecoder("utf-8");
9847
+ let buf = "";
9848
+ for (; ; ) {
9849
+ const { value, done } = await reader.read();
9850
+ if (done) break;
9851
+ buf += decoder.decode(value, { stream: true });
9852
+ let nl;
9853
+ while ((nl = buf.indexOf("\n")) !== -1) {
9854
+ const ln = buf.slice(0, nl);
9855
+ buf = buf.slice(nl + 1);
9856
+ if (ln.startsWith("data:")) {
9857
+ const payload = ln.slice(5).trim();
9858
+ if (payload) stdout(payload + "\n");
9859
+ }
9860
+ }
9861
+ }
9862
+ }
9863
+ function extractId(line) {
9864
+ try {
9865
+ const obj = JSON.parse(line);
9866
+ return "id" in obj ? obj.id : void 0;
9867
+ } catch {
9868
+ return void 0;
9869
+ }
9870
+ }
9871
+
9591
9872
  // src/cli.ts
9592
9873
  var program = new import_commander.Command();
9593
9874
  program.name("cleargate").description("ClearGate CLI \u2014 connects AI agent teams to the ClearGate MCP server").version(package_default.version, "-V, --version").option("--profile <name>", "configuration profile to use", "default").option("--mcp-url <url>", "MCP server URL (overrides config file and env)").showHelpAfterError("(use `cleargate --help`)");
@@ -9830,5 +10111,13 @@ var hotfix = program.command("hotfix").description("hotfix lane commands (off-sp
9830
10111
  hotfix.command("new <slug>").description("scaffold a new HOTFIX-NNN_<slug>.md in pending-sync/").action((slug) => {
9831
10112
  hotfixNewHandler({ slug });
9832
10113
  });
10114
+ var mcp = program.command("mcp").description("MCP-server bridge commands (stdio shim, registration helpers)");
10115
+ mcp.command("serve").description("run a stdio MCP server that proxies to the cleargate HTTP /mcp endpoint with auto-refresh Bearer auth").action(async (_opts, command) => {
10116
+ const globals = command.parent.parent.opts();
10117
+ await mcpServeHandler({
10118
+ profile: globals.profile,
10119
+ ...globals.mcpUrl !== void 0 ? { mcpUrlFlag: globals.mcpUrl } : {}
10120
+ });
10121
+ });
9833
10122
  void program.parseAsync(process.argv);
9834
10123
  //# sourceMappingURL=cli.cjs.map