cleargate 0.10.0 → 0.11.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.
Files changed (72) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +11 -1
  3. package/dist/MANIFEST.json +40 -26
  4. package/dist/chunk-HZPJ5QX4.js +459 -0
  5. package/dist/chunk-HZPJ5QX4.js.map +1 -0
  6. package/dist/cli.cjs +419 -202
  7. package/dist/cli.cjs.map +1 -1
  8. package/dist/cli.js +387 -513
  9. package/dist/cli.js.map +1 -1
  10. package/dist/lib/lifecycle-reconcile.cjs +497 -0
  11. package/dist/lib/lifecycle-reconcile.cjs.map +1 -0
  12. package/dist/lib/lifecycle-reconcile.d.cts +136 -0
  13. package/dist/lib/lifecycle-reconcile.d.ts +136 -0
  14. package/dist/lib/lifecycle-reconcile.js +20 -0
  15. package/dist/lib/lifecycle-reconcile.js.map +1 -0
  16. package/dist/templates/cleargate-planning/.claude/agents/architect.md +55 -2
  17. package/dist/templates/cleargate-planning/.claude/agents/developer.md +22 -0
  18. package/dist/templates/cleargate-planning/.claude/agents/devops.md +249 -0
  19. package/dist/templates/cleargate-planning/.claude/agents/qa.md +41 -0
  20. package/dist/templates/cleargate-planning/.claude/agents/reporter.md +44 -8
  21. package/dist/templates/cleargate-planning/.claude/hooks/pre-commit-surface-gate.sh +21 -0
  22. package/dist/templates/cleargate-planning/.claude/hooks/stamp-and-gate.sh +12 -1
  23. package/dist/templates/cleargate-planning/.claude/hooks/token-ledger.sh +21 -1
  24. package/dist/templates/cleargate-planning/.claude/skills/sprint-execution/SKILL.md +200 -29
  25. package/dist/templates/cleargate-planning/.cleargate/knowledge/mid-sprint-triage-rubric.md +160 -0
  26. package/dist/templates/cleargate-planning/.cleargate/knowledge/readiness-gates.md +41 -9
  27. package/dist/templates/cleargate-planning/.cleargate/scripts/close_sprint.mjs +98 -16
  28. package/dist/templates/cleargate-planning/.cleargate/scripts/gate-checks.json +3 -3
  29. package/dist/templates/cleargate-planning/.cleargate/scripts/init_sprint.mjs +86 -10
  30. package/dist/templates/cleargate-planning/.cleargate/scripts/run_script.sh +173 -87
  31. package/dist/templates/cleargate-planning/.cleargate/scripts/suggest_improvements.mjs +150 -22
  32. package/dist/templates/cleargate-planning/.cleargate/scripts/test/test_flashcard_gate.sh +20 -20
  33. package/dist/templates/cleargate-planning/.cleargate/scripts/validate_state.mjs +32 -8
  34. package/dist/templates/cleargate-planning/.cleargate/scripts/write_dispatch.sh +12 -1
  35. package/dist/templates/cleargate-planning/.cleargate/templates/Bug.md +3 -0
  36. package/dist/templates/cleargate-planning/.cleargate/templates/CR.md +3 -0
  37. package/dist/templates/cleargate-planning/.cleargate/templates/epic.md +3 -0
  38. package/dist/templates/cleargate-planning/.cleargate/templates/hotfix.md +3 -0
  39. package/dist/templates/cleargate-planning/.cleargate/templates/initiative.md +1 -1
  40. package/dist/templates/cleargate-planning/.cleargate/templates/sprint_context.md +8 -0
  41. package/dist/templates/cleargate-planning/.cleargate/templates/story.md +3 -0
  42. package/dist/templates/cleargate-planning/CLAUDE.md +3 -1
  43. package/dist/templates/cleargate-planning/MANIFEST.json +40 -26
  44. package/package.json +8 -5
  45. package/templates/cleargate-planning/.claude/agents/architect.md +55 -2
  46. package/templates/cleargate-planning/.claude/agents/developer.md +22 -0
  47. package/templates/cleargate-planning/.claude/agents/devops.md +249 -0
  48. package/templates/cleargate-planning/.claude/agents/qa.md +41 -0
  49. package/templates/cleargate-planning/.claude/agents/reporter.md +44 -8
  50. package/templates/cleargate-planning/.claude/hooks/pre-commit-surface-gate.sh +21 -0
  51. package/templates/cleargate-planning/.claude/hooks/stamp-and-gate.sh +12 -1
  52. package/templates/cleargate-planning/.claude/hooks/token-ledger.sh +21 -1
  53. package/templates/cleargate-planning/.claude/skills/sprint-execution/SKILL.md +200 -29
  54. package/templates/cleargate-planning/.cleargate/knowledge/mid-sprint-triage-rubric.md +160 -0
  55. package/templates/cleargate-planning/.cleargate/knowledge/readiness-gates.md +41 -9
  56. package/templates/cleargate-planning/.cleargate/scripts/close_sprint.mjs +98 -16
  57. package/templates/cleargate-planning/.cleargate/scripts/gate-checks.json +3 -3
  58. package/templates/cleargate-planning/.cleargate/scripts/init_sprint.mjs +86 -10
  59. package/templates/cleargate-planning/.cleargate/scripts/run_script.sh +173 -87
  60. package/templates/cleargate-planning/.cleargate/scripts/suggest_improvements.mjs +150 -22
  61. package/templates/cleargate-planning/.cleargate/scripts/test/test_flashcard_gate.sh +20 -20
  62. package/templates/cleargate-planning/.cleargate/scripts/validate_state.mjs +32 -8
  63. package/templates/cleargate-planning/.cleargate/scripts/write_dispatch.sh +12 -1
  64. package/templates/cleargate-planning/.cleargate/templates/Bug.md +3 -0
  65. package/templates/cleargate-planning/.cleargate/templates/CR.md +3 -0
  66. package/templates/cleargate-planning/.cleargate/templates/epic.md +3 -0
  67. package/templates/cleargate-planning/.cleargate/templates/hotfix.md +3 -0
  68. package/templates/cleargate-planning/.cleargate/templates/initiative.md +1 -1
  69. package/templates/cleargate-planning/.cleargate/templates/sprint_context.md +8 -0
  70. package/templates/cleargate-planning/.cleargate/templates/story.md +3 -0
  71. package/templates/cleargate-planning/CLAUDE.md +3 -1
  72. package/templates/cleargate-planning/MANIFEST.json +40 -26
package/dist/cli.cjs CHANGED
@@ -696,10 +696,10 @@ var import_commander = require("commander");
696
696
  // package.json
697
697
  var package_default = {
698
698
  name: "cleargate",
699
- version: "0.10.0",
699
+ version: "0.11.0",
700
700
  private: false,
701
701
  type: "module",
702
- description: "Planning framework for Claude Code agents \u2014 sprint/epic/story protocol, four-agent loop (architect/developer/qa/reporter), Karpathy-style awareness wiki.",
702
+ description: "Planning framework for Claude Code agents \u2014 sprint/epic/story protocol, five-role agent team (architect/developer/qa/devops/reporter), Karpathy-style awareness wiki.",
703
703
  license: "MIT",
704
704
  bin: {
705
705
  cleargate: "dist/cli.js"
@@ -743,9 +743,12 @@ var package_default = {
743
743
  build: "tsup",
744
744
  dev: "tsup --watch",
745
745
  typecheck: "tsc --noEmit",
746
- pretest: "npm run build",
747
- test: "vitest run",
748
- "test:watch": "vitest"
746
+ test: "tsx --test --test-reporter=spec 'test/**/*.node.test.ts'",
747
+ "test:file": "tsx --test --test-reporter=spec",
748
+ "test:vitest": "npm run build && vitest run",
749
+ "test:vitest:watch": "vitest",
750
+ "test:node": "tsx --test --test-reporter=spec 'test/**/*.node.test.ts'",
751
+ "test:node:file": "tsx --test --test-reporter=spec"
749
752
  },
750
753
  dependencies: {
751
754
  "@napi-rs/keyring": "^1.2.0",
@@ -1991,7 +1994,20 @@ var HOOK_FILES_WITH_PIN = /* @__PURE__ */ new Set([
1991
1994
  ".claude/hooks/stamp-and-gate.sh",
1992
1995
  ".claude/hooks/session-start.sh"
1993
1996
  ]);
1994
- var SKIP_FILES = /* @__PURE__ */ new Set(["CLAUDE.md"]);
1997
+ var SKIP_FILES = /* @__PURE__ */ new Set(["CLAUDE.md", "MANIFEST.json"]);
1998
+ var FIRST_INSTALL_ONLY = [
1999
+ ".gitignore",
2000
+ ".cleargate/FLASHCARD.md",
2001
+ /^\.cleargate\/scripts\//
2002
+ ];
2003
+ function isFirstInstallOnly(relPath) {
2004
+ for (const pattern of FIRST_INSTALL_ONLY) {
2005
+ if (typeof pattern === "string" ? pattern === relPath : pattern.test(relPath)) {
2006
+ return true;
2007
+ }
2008
+ }
2009
+ return false;
2010
+ }
1995
2011
  function listFilesRecursive(dir) {
1996
2012
  const results = [];
1997
2013
  function walk(current, rel) {
@@ -2045,6 +2061,14 @@ function copyPayload(payloadDir, targetCwd, opts) {
2045
2061
  report.actions.push({ action: "skipped", relPath });
2046
2062
  continue;
2047
2063
  }
2064
+ if (isFirstInstallOnly(relPath)) {
2065
+ if (needsExec && process.platform !== "win32") {
2066
+ fs7.chmodSync(dstPath, 493);
2067
+ }
2068
+ report.skipped++;
2069
+ report.actions.push({ action: "skipped", relPath });
2070
+ continue;
2071
+ }
2048
2072
  fs7.writeFileSync(dstPath, srcBuffer);
2049
2073
  if (needsExec && process.platform !== "win32") {
2050
2074
  fs7.chmodSync(dstPath, 493);
@@ -2183,7 +2207,8 @@ var PREFIX_MAP = [
2183
2207
  { prefix: "SPRINT-", type: "sprint", bucket: "sprints" },
2184
2208
  { prefix: "PROPOSAL-", type: "proposal", bucket: "proposals" },
2185
2209
  { prefix: "CR-", type: "cr", bucket: "crs" },
2186
- { prefix: "BUG-", type: "bug", bucket: "bugs" }
2210
+ { prefix: "BUG-", type: "bug", bucket: "bugs" },
2211
+ { prefix: "INITIATIVE-", type: "initiative", bucket: "initiatives" }
2187
2212
  ];
2188
2213
  function deriveBucket(filename) {
2189
2214
  const base = filename.includes("/") ? filename.split("/").pop() : filename;
@@ -4223,14 +4248,18 @@ var FM_KEY_MAP = [
4223
4248
  { key: "epic_id", type: "epic" },
4224
4249
  { key: "proposal_id", type: "proposal" },
4225
4250
  { key: "cr_id", type: "cr" },
4226
- { key: "bug_id", type: "bug" }
4251
+ { key: "bug_id", type: "bug" },
4252
+ { key: "initiative_id", type: "initiative" },
4253
+ { key: "sprint_id", type: "sprint" }
4227
4254
  ];
4228
4255
  var PREFIX_MAP2 = [
4229
4256
  { prefix: "STORY-", type: "story" },
4230
4257
  { prefix: "EPIC-", type: "epic" },
4231
4258
  { prefix: "PROPOSAL-", type: "proposal" },
4232
4259
  { prefix: "CR-", type: "cr" },
4233
- { prefix: "BUG-", type: "bug" }
4260
+ { prefix: "BUG-", type: "bug" },
4261
+ { prefix: "INITIATIVE-", type: "initiative" },
4262
+ { prefix: "SPRINT-", type: "sprint" }
4234
4263
  ];
4235
4264
  function detectWorkItemTypeFromFm(fm) {
4236
4265
  for (const { key, type } of FM_KEY_MAP) {
@@ -4255,7 +4284,9 @@ var WORK_ITEM_TRANSITIONS = {
4255
4284
  epic: ["ready-for-decomposition", "ready-for-coding"],
4256
4285
  story: ["ready-for-execution"],
4257
4286
  cr: ["ready-to-apply"],
4258
- bug: ["ready-for-fix"]
4287
+ bug: ["ready-for-fix"],
4288
+ initiative: ["ready-for-decomposition"],
4289
+ sprint: ["ready-for-execution"]
4259
4290
  };
4260
4291
 
4261
4292
  // src/wiki/lint-checks.ts
@@ -5868,7 +5899,7 @@ async function doctorHandler(flags, cli) {
5868
5899
  // src/commands/gate.ts
5869
5900
  init_cjs_shims();
5870
5901
  var fs32 = __toESM(require("fs"), 1);
5871
- var path33 = __toESM(require("path"), 1);
5902
+ var path34 = __toESM(require("path"), 1);
5872
5903
  var import_node_child_process8 = require("child_process");
5873
5904
 
5874
5905
  // src/commands/execution-mode.ts
@@ -5957,13 +5988,21 @@ function printInertAndExit(stdoutFn, exitFn) {
5957
5988
  return exitFn(0);
5958
5989
  }
5959
5990
 
5991
+ // src/lib/script-paths.ts
5992
+ init_cjs_shims();
5993
+ var path32 = __toESM(require("path"), 1);
5994
+ function resolveCleargateScript(opts, scriptName) {
5995
+ const cwd = opts.cwd ?? process.cwd();
5996
+ return path32.join(cwd, ".cleargate", "scripts", scriptName);
5997
+ }
5998
+
5960
5999
  // src/commands/gate.ts
5961
6000
  var import_js_yaml6 = __toESM(require("js-yaml"), 1);
5962
6001
 
5963
6002
  // src/lib/readiness-predicates.ts
5964
6003
  init_cjs_shims();
5965
6004
  var fs30 = __toESM(require("fs"), 1);
5966
- var path32 = __toESM(require("path"), 1);
6005
+ var path33 = __toESM(require("path"), 1);
5967
6006
  function parsePredicate(src) {
5968
6007
  const s = src.trim();
5969
6008
  const fmMatch = s.match(
@@ -5995,7 +6034,7 @@ function parsePredicate(src) {
5995
6034
  return { kind: "body-contains", needle: bodyMatch[1], negated: false };
5996
6035
  }
5997
6036
  const sectionMatch = s.match(
5998
- /^section\((\d+)\) has (≥|>=|==|>)(\d+) (checked-checkbox|unchecked-checkbox|listed-item)$/
6037
+ /^section\((\d+)\) has (≥|>=|==|>)(\d+) (checked-checkbox|unchecked-checkbox|listed-item|declared-item)$/
5999
6038
  );
6000
6039
  if (sectionMatch) {
6001
6040
  const index = parseInt(sectionMatch[1], 10);
@@ -6023,6 +6062,9 @@ function parsePredicate(src) {
6023
6062
  const value = statusMatch[2].trim().replace(/^['"]|['"]$/g, "");
6024
6063
  return { kind: "status-of", id, value };
6025
6064
  }
6065
+ if (s === "existing-surfaces-verified") {
6066
+ return { kind: "existing-surfaces-verified" };
6067
+ }
6026
6068
  throw new Error(`unsupported predicate shape: ${src}`);
6027
6069
  }
6028
6070
  function parseValue(raw) {
@@ -6051,6 +6093,8 @@ function evaluate(predicate, doc, opts) {
6051
6093
  return evalLinkTargetExists(parsed, opts);
6052
6094
  case "status-of":
6053
6095
  return evalStatusOf(parsed, opts, projectRoot);
6096
+ case "existing-surfaces-verified":
6097
+ return evalExistingSurfacesVerified(doc, projectRoot);
6054
6098
  }
6055
6099
  }
6056
6100
  function evalFrontmatter(parsed, doc, projectRoot) {
@@ -6127,8 +6171,14 @@ function compareValues(actual, op, expected) {
6127
6171
  }
6128
6172
  function resolveLinkedPath(ref, docAbsPath, projectRoot) {
6129
6173
  const candidates = [
6130
- path32.resolve(path32.dirname(docAbsPath), ref),
6131
- path32.resolve(projectRoot, ref)
6174
+ path33.resolve(path33.dirname(docAbsPath), ref),
6175
+ // 1. relative to citer
6176
+ path33.resolve(projectRoot, ref),
6177
+ // 2. project root
6178
+ path33.resolve(projectRoot, ".cleargate", "delivery", "pending-sync", ref),
6179
+ // 3. live
6180
+ path33.resolve(projectRoot, ".cleargate", "delivery", "archive", ref)
6181
+ // 4. archived
6132
6182
  ];
6133
6183
  for (const candidate of candidates) {
6134
6184
  if (!candidate.startsWith(projectRoot)) continue;
@@ -6265,6 +6315,9 @@ function evalSection(parsed, doc) {
6265
6315
  case "listed-item":
6266
6316
  actualCount = (sectionContent.match(/^\s*- /gm) || []).length;
6267
6317
  break;
6318
+ case "declared-item":
6319
+ actualCount = countDeclaredItems(sectionContent);
6320
+ break;
6268
6321
  }
6269
6322
  const pass = applyCountOp(actualCount, parsed.count.op, parsed.count.n);
6270
6323
  const opStr = parsed.count.op === ">=" ? "\u2265" : parsed.count.op;
@@ -6281,9 +6334,39 @@ function applyCountOp(actual, op, n) {
6281
6334
  return actual > n;
6282
6335
  }
6283
6336
  }
6337
+ function countDeclaredItems(sectionContent) {
6338
+ const lines = sectionContent.split("\n");
6339
+ let count = 0;
6340
+ let inTable = false;
6341
+ for (const line of lines) {
6342
+ if (/^\s*- /.test(line)) {
6343
+ count++;
6344
+ inTable = false;
6345
+ continue;
6346
+ }
6347
+ if (/^\|.+\|/.test(line)) {
6348
+ if (/^\|[\s\-:]+\|[\s\-:|]*$/.test(line.replace(/\s/g, ""))) {
6349
+ inTable = true;
6350
+ continue;
6351
+ }
6352
+ if (inTable) {
6353
+ count++;
6354
+ }
6355
+ continue;
6356
+ }
6357
+ if (inTable && !/^\|/.test(line)) {
6358
+ inTable = false;
6359
+ }
6360
+ if (/^(\*{1,2}|_{1,2})?[A-Z][^|*\n]*(\*{1,2}|_{1,2})?:/.test(line.trim())) {
6361
+ count++;
6362
+ continue;
6363
+ }
6364
+ }
6365
+ return count;
6366
+ }
6284
6367
  function evalFileExists(parsed, projectRoot) {
6285
- const resolved = path32.resolve(projectRoot, parsed.path);
6286
- if (!resolved.startsWith(projectRoot + path32.sep) && resolved !== projectRoot) {
6368
+ const resolved = path33.resolve(projectRoot, parsed.path);
6369
+ if (!resolved.startsWith(projectRoot + path33.sep) && resolved !== projectRoot) {
6287
6370
  return {
6288
6371
  pass: false,
6289
6372
  detail: `path '${parsed.path}' resolves outside project root (sandbox violation)`
@@ -6297,7 +6380,7 @@ function evalFileExists(parsed, projectRoot) {
6297
6380
  }
6298
6381
  function evalLinkTargetExists(parsed, opts) {
6299
6382
  const projectRoot = opts?.projectRoot ?? process.cwd();
6300
- const wikiIndexPath = opts?.wikiIndexPath ?? path32.join(projectRoot, ".cleargate", "wiki", "index.md");
6383
+ const wikiIndexPath = opts?.wikiIndexPath ?? path33.join(projectRoot, ".cleargate", "wiki", "index.md");
6301
6384
  if (!wikiIndexPath.startsWith(projectRoot)) {
6302
6385
  return { pass: false, detail: "wikiIndexPath resolves outside project root" };
6303
6386
  }
@@ -6314,7 +6397,7 @@ function evalLinkTargetExists(parsed, opts) {
6314
6397
  };
6315
6398
  }
6316
6399
  function evalStatusOf(parsed, opts, projectRoot) {
6317
- const wikiIndexPath = opts?.wikiIndexPath ?? path32.join(projectRoot, ".cleargate", "wiki", "index.md");
6400
+ const wikiIndexPath = opts?.wikiIndexPath ?? path33.join(projectRoot, ".cleargate", "wiki", "index.md");
6318
6401
  if (!wikiIndexPath.startsWith(projectRoot)) {
6319
6402
  return { pass: false, detail: "wikiIndexPath resolves outside project root" };
6320
6403
  }
@@ -6331,7 +6414,7 @@ function evalStatusOf(parsed, opts, projectRoot) {
6331
6414
  return { pass: false, detail: `[[${parsed.id}]] not found in wiki index` };
6332
6415
  }
6333
6416
  const rawPath = rowMatch[1].trim();
6334
- const fullPath = path32.resolve(projectRoot, rawPath);
6417
+ const fullPath = path33.resolve(projectRoot, rawPath);
6335
6418
  if (!fullPath.startsWith(projectRoot)) {
6336
6419
  return { pass: false, detail: `wiki path for ${parsed.id} resolves outside project root` };
6337
6420
  }
@@ -6346,6 +6429,60 @@ function evalStatusOf(parsed, opts, projectRoot) {
6346
6429
  detail: pass ? `status-of([[${parsed.id}]]) == ${parsed.value}` : `status-of([[${parsed.id}]]) is '${status}', expected '${parsed.value}'`
6347
6430
  };
6348
6431
  }
6432
+ function evalExistingSurfacesVerified(doc, projectRoot) {
6433
+ const body = doc.body;
6434
+ const rawParts = body.split(/^(?=## )/m);
6435
+ let sectionContent;
6436
+ for (const part of rawParts) {
6437
+ if (part.startsWith("## Existing Surfaces")) {
6438
+ sectionContent = part;
6439
+ break;
6440
+ }
6441
+ }
6442
+ if (!sectionContent) {
6443
+ return {
6444
+ pass: true,
6445
+ detail: `not-applicable: ## Existing Surfaces section absent \u2014 reuse-audit-recorded already failing`
6446
+ };
6447
+ }
6448
+ const PATH_RE = /[a-zA-Z0-9_./-]+\.[a-zA-Z]{1,5}(?::[a-zA-Z_][a-zA-Z0-9_]*)?/g;
6449
+ const rawMatches = sectionContent.match(PATH_RE) ?? [];
6450
+ const paths = [...new Set(rawMatches.map((m) => m.replace(/:([a-zA-Z_][a-zA-Z0-9_]*)$/, "")))];
6451
+ if (paths.length === 0) {
6452
+ const SENTINEL_RE = /no overlap found|no existing surface|no prior implementation|audit returned empty/i;
6453
+ if (SENTINEL_RE.test(sectionContent)) {
6454
+ return {
6455
+ pass: true,
6456
+ detail: `## Existing Surfaces contains no path citations; sentinel phrase present \u2014 audit explicitly empty`
6457
+ };
6458
+ }
6459
+ return {
6460
+ pass: false,
6461
+ detail: `'## Existing Surfaces' has no path citations and no "no overlap found" sentinel`
6462
+ };
6463
+ }
6464
+ const missing = [];
6465
+ for (const p of paths) {
6466
+ const resolved = path33.resolve(projectRoot, p);
6467
+ if (!resolved.startsWith(projectRoot + path33.sep) && resolved !== projectRoot) {
6468
+ missing.push(p);
6469
+ continue;
6470
+ }
6471
+ if (!fs30.existsSync(resolved)) {
6472
+ missing.push(p);
6473
+ }
6474
+ }
6475
+ if (missing.length > 0) {
6476
+ return {
6477
+ pass: false,
6478
+ detail: `cited paths do not exist on disk: ${missing.join(", ")}`
6479
+ };
6480
+ }
6481
+ return {
6482
+ pass: true,
6483
+ detail: `all ${paths.length} cited path${paths.length === 1 ? "" : "s"} exist on disk`
6484
+ };
6485
+ }
6349
6486
 
6350
6487
  // src/lib/frontmatter-cache.ts
6351
6488
  init_cjs_shims();
@@ -6470,7 +6607,7 @@ async function gateCheckHandler(file, opts, cli) {
6470
6607
  const exitFn = cli?.exit ?? ((code) => process.exit(code));
6471
6608
  const cwd = cli?.cwd ?? process.cwd();
6472
6609
  const nowFn = cli?.now ?? (() => /* @__PURE__ */ new Date());
6473
- const absPath = path33.isAbsolute(file) ? file : path33.resolve(cwd, file);
6610
+ const absPath = path34.isAbsolute(file) ? file : path34.resolve(cwd, file);
6474
6611
  if (!fs32.existsSync(absPath)) {
6475
6612
  stderrFn(`[cleargate gate] error: file not found: ${absPath}`);
6476
6613
  return exitFn(1);
@@ -6496,7 +6633,7 @@ async function gateCheckHandler(file, opts, cli) {
6496
6633
  return exitFn(1);
6497
6634
  }
6498
6635
  const projectRoot = cwd;
6499
- const gatesDocPath = cli?.gatesDocPath ?? path33.join(projectRoot, ".cleargate", "knowledge", "readiness-gates.md");
6636
+ const gatesDocPath = cli?.gatesDocPath ?? path34.join(projectRoot, ".cleargate", "knowledge", "readiness-gates.md");
6500
6637
  if (!fs32.existsSync(gatesDocPath)) {
6501
6638
  stderrFn(`[cleargate gate] error: readiness-gates.md not found at: ${gatesDocPath}`);
6502
6639
  return exitFn(1);
@@ -6520,7 +6657,6 @@ async function gateCheckHandler(file, opts, cli) {
6520
6657
  const wikiIndexPath = cli?.wikiIndexPath;
6521
6658
  const parsedDoc = { fm, body, absPath };
6522
6659
  const evalOpts = { projectRoot, ...wikiIndexPath ? { wikiIndexPath } : {} };
6523
- const failingCriteria = [];
6524
6660
  const allResults = [];
6525
6661
  for (const criterion of gate2.criteria) {
6526
6662
  let result;
@@ -6529,9 +6665,32 @@ async function gateCheckHandler(file, opts, cli) {
6529
6665
  } catch (err) {
6530
6666
  result = { pass: false, detail: `predicate error: ${String(err)}` };
6531
6667
  }
6532
- allResults.push({ id: criterion.id, ...result });
6533
- if (!result.pass) {
6534
- failingCriteria.push({ id: criterion.id, detail: result.detail });
6668
+ allResults.push({ id: criterion.id, ...result, or_group: criterion.or_group });
6669
+ }
6670
+ const failingCriteria = [];
6671
+ const orGroups = /* @__PURE__ */ new Map();
6672
+ for (const r of allResults) {
6673
+ if (r.or_group) {
6674
+ const existing = orGroups.get(r.or_group) ?? [];
6675
+ existing.push(r);
6676
+ orGroups.set(r.or_group, existing);
6677
+ }
6678
+ }
6679
+ for (const r of allResults) {
6680
+ if (r.or_group) {
6681
+ const groupMembers = orGroups.get(r.or_group);
6682
+ const isFirstMember = groupMembers[0].id === r.id;
6683
+ if (isFirstMember) {
6684
+ const anyPasses = groupMembers.some((m) => m.pass);
6685
+ if (!anyPasses) {
6686
+ const details = groupMembers.map((m) => `${m.id}: ${m.detail}`).join("; ");
6687
+ failingCriteria.push({ id: r.or_group, detail: `OR-group failed \u2014 all alternatives failed: ${details}` });
6688
+ }
6689
+ }
6690
+ } else {
6691
+ if (!r.pass) {
6692
+ failingCriteria.push({ id: r.id, detail: r.detail });
6693
+ }
6535
6694
  }
6536
6695
  }
6537
6696
  const overallPass = failingCriteria.length === 0;
@@ -6548,15 +6707,15 @@ async function gateCheckHandler(file, opts, cli) {
6548
6707
  if (overallPass) {
6549
6708
  stdoutFn(`\u2705 ${detectedType}.${transition} passed (${gate2.criteria.length} criteria)`);
6550
6709
  } else {
6551
- for (const r of allResults) {
6552
- if (!r.pass) {
6553
- if (isAdvisory) {
6554
- stdoutFn(`\u26A0 ${r.id}: ${r.detail} (advisory)`);
6555
- } else {
6556
- stdoutFn(`\u274C ${r.id}: ${r.detail}`);
6557
- }
6710
+ for (const fc of failingCriteria) {
6711
+ if (isAdvisory) {
6712
+ stdoutFn(`\u26A0 ${fc.id}: ${fc.detail} (advisory)`);
6713
+ } else {
6714
+ stdoutFn(`\u274C ${fc.id}: ${fc.detail}`);
6558
6715
  }
6559
- if (opts.verbose) {
6716
+ }
6717
+ if (opts.verbose) {
6718
+ for (const r of allResults) {
6560
6719
  stdoutFn(` [${r.pass ? "pass" : "fail"}] ${r.id}: ${r.detail}`);
6561
6720
  }
6562
6721
  }
@@ -6570,7 +6729,7 @@ async function gateExplainHandler(file, cli) {
6570
6729
  const stderrFn = cli?.stderr ?? ((s) => process.stderr.write(s + "\n"));
6571
6730
  const exitFn = cli?.exit ?? ((code) => process.exit(code));
6572
6731
  const cwd = cli?.cwd ?? process.cwd();
6573
- const absPath = path33.isAbsolute(file) ? file : path33.resolve(cwd, file);
6732
+ const absPath = path34.isAbsolute(file) ? file : path34.resolve(cwd, file);
6574
6733
  if (!fs32.existsSync(absPath)) {
6575
6734
  stderrFn(`[cleargate gate] error: file not found: ${absPath}`);
6576
6735
  return exitFn(1);
@@ -6603,7 +6762,7 @@ async function gateExplainHandler(file, cli) {
6603
6762
  function resolveRunScriptForGate(opts) {
6604
6763
  if (opts.runScriptPath) return opts.runScriptPath;
6605
6764
  const cwd = opts.cwd ?? process.cwd();
6606
- return path33.join(cwd, ".cleargate", "scripts", "run_script.sh");
6765
+ return path34.join(cwd, ".cleargate", "scripts", "run_script.sh");
6607
6766
  }
6608
6767
  function gateQaHandler(opts, cli) {
6609
6768
  const stdoutFn = cli?.stdout ?? ((s) => process.stdout.write(s + "\n"));
@@ -6619,9 +6778,11 @@ function gateQaHandler(opts, cli) {
6619
6778
  return printInertAndExit(stdoutFn, exitFn);
6620
6779
  }
6621
6780
  const runScript = resolveRunScriptForGate(cli ?? {});
6781
+ const qaCwd = cli?.cwd ?? process.cwd();
6782
+ const gateRunnerPath = resolveCleargateScript({ cwd: qaCwd }, "pre_gate_runner.sh");
6622
6783
  const result = spawnFn(
6623
6784
  "bash",
6624
- [runScript, "pre_gate_runner.sh", "qa", opts.worktree, opts.branch],
6785
+ [runScript, "bash", gateRunnerPath, "qa", opts.worktree, opts.branch],
6625
6786
  { stdio: "inherit" }
6626
6787
  );
6627
6788
  if (result.error) {
@@ -6645,9 +6806,11 @@ function gateArchHandler(opts, cli) {
6645
6806
  return printInertAndExit(stdoutFn, exitFn);
6646
6807
  }
6647
6808
  const runScript = resolveRunScriptForGate(cli ?? {});
6809
+ const archCwd = cli?.cwd ?? process.cwd();
6810
+ const archGateRunnerPath = resolveCleargateScript({ cwd: archCwd }, "pre_gate_runner.sh");
6648
6811
  const result = spawnFn(
6649
6812
  "bash",
6650
- [runScript, "pre_gate_runner.sh", "arch", opts.worktree, opts.branch],
6813
+ [runScript, "bash", archGateRunnerPath, "arch", opts.worktree, opts.branch],
6651
6814
  { stdio: "inherit" }
6652
6815
  );
6653
6816
  if (result.error) {
@@ -6698,14 +6861,14 @@ function gateRunHandler(name, opts, cli) {
6698
6861
  // src/commands/sprint.ts
6699
6862
  init_cjs_shims();
6700
6863
  var fs34 = __toESM(require("fs"), 1);
6701
- var path35 = __toESM(require("path"), 1);
6864
+ var path36 = __toESM(require("path"), 1);
6702
6865
  var import_node_child_process11 = require("child_process");
6703
6866
  var import_js_yaml7 = __toESM(require("js-yaml"), 1);
6704
6867
 
6705
6868
  // src/lib/lifecycle-reconcile.ts
6706
6869
  init_cjs_shims();
6707
6870
  var fs33 = __toESM(require("fs"), 1);
6708
- var path34 = __toESM(require("path"), 1);
6871
+ var path35 = __toESM(require("path"), 1);
6709
6872
  var import_node_child_process10 = require("child_process");
6710
6873
  var VERB_STATUS_MAP = {
6711
6874
  feat: {
@@ -6765,7 +6928,7 @@ function findArtifactFile(deliveryRoot, id) {
6765
6928
  { rel: "archive", inArchive: true }
6766
6929
  ];
6767
6930
  for (const { rel, inArchive } of dirs) {
6768
- const dir = path34.join(deliveryRoot, rel);
6931
+ const dir = path35.join(deliveryRoot, rel);
6769
6932
  let entries;
6770
6933
  try {
6771
6934
  entries = fs33.readdirSync(dir);
@@ -6776,7 +6939,7 @@ function findArtifactFile(deliveryRoot, id) {
6776
6939
  (e) => (e.startsWith(prefix) || e === `${id}.md`) && e.endsWith(".md")
6777
6940
  );
6778
6941
  if (match) {
6779
- const absPath = path34.join(dir, match);
6942
+ const absPath = path35.join(dir, match);
6780
6943
  return { absPath, inArchive, relPath: `${rel}/${match}` };
6781
6944
  }
6782
6945
  }
@@ -6894,8 +7057,8 @@ function reconcileDecomposition(opts) {
6894
7057
  }
6895
7058
  const epics = Array.isArray(fm["epics"]) ? fm["epics"].map(String) : [];
6896
7059
  const proposals = Array.isArray(fm["proposals"]) ? fm["proposals"].map(String) : [];
6897
- const pendingDir = path34.join(deliveryRoot, "pending-sync");
6898
- const archiveDir = path34.join(deliveryRoot, "archive");
7060
+ const pendingDir = path35.join(deliveryRoot, "pending-sync");
7061
+ const archiveDir = path35.join(deliveryRoot, "archive");
6899
7062
  function listMdFiles(dir) {
6900
7063
  try {
6901
7064
  return fs33.readdirSync(dir).filter((f) => f.endsWith(".md"));
@@ -6970,7 +7133,7 @@ function findChildStories(epicId, pendingDir, pendingFiles, archiveDir, archiveF
6970
7133
  for (const f of files) {
6971
7134
  if (!f.startsWith(storyPrefix) && !f.startsWith("STORY-")) continue;
6972
7135
  if (!f.includes(storyPrefix)) continue;
6973
- const absPath = path34.join(dir, f);
7136
+ const absPath = path35.join(dir, f);
6974
7137
  try {
6975
7138
  const raw = fs33.readFileSync(absPath, "utf8");
6976
7139
  const { fm } = parseFrontmatter(raw);
@@ -6987,7 +7150,7 @@ function findChildStories(epicId, pendingDir, pendingFiles, archiveDir, archiveF
6987
7150
  function findDecomposedEpic(proposalId, pendingDir, pendingFiles) {
6988
7151
  for (const f of pendingFiles) {
6989
7152
  if (!f.startsWith("EPIC-")) continue;
6990
- const absPath = path34.join(pendingDir, f);
7153
+ const absPath = path35.join(pendingDir, f);
6991
7154
  try {
6992
7155
  const raw = fs33.readFileSync(absPath, "utf8");
6993
7156
  const { fm } = parseFrontmatter(raw);
@@ -7015,7 +7178,7 @@ var TERMINAL_STATUSES2 = /* @__PURE__ */ new Set(["Completed", "Done", "Abandone
7015
7178
  function resolveRunScript(opts) {
7016
7179
  if (opts.runScriptPath) return opts.runScriptPath;
7017
7180
  const cwd = opts.cwd ?? process.cwd();
7018
- return path35.join(cwd, ".cleargate", "scripts", "run_script.sh");
7181
+ return path36.join(cwd, ".cleargate", "scripts", "run_script.sh");
7019
7182
  }
7020
7183
  function defaultExit(code) {
7021
7184
  return process.exit(code);
@@ -7034,17 +7197,17 @@ function sprintInitHandler(opts, cli) {
7034
7197
  if (mode === "v1") {
7035
7198
  return printInertAndExit(stdoutFn, exitFn);
7036
7199
  }
7037
- const deliveryRoot = path35.join(cwd, ".cleargate", "delivery");
7200
+ const deliveryRoot = path36.join(cwd, ".cleargate", "delivery");
7038
7201
  let lifecycleInitMode = "warn";
7039
7202
  let sprintPlanPath = null;
7040
- const pendingDir = path35.join(deliveryRoot, "pending-sync");
7203
+ const pendingDir = path36.join(deliveryRoot, "pending-sync");
7041
7204
  try {
7042
7205
  const entries = fs34.readdirSync(pendingDir);
7043
7206
  const sprintFile = entries.find(
7044
7207
  (e) => (e.startsWith(`${opts.sprintId}_`) || e === `${opts.sprintId}.md`) && e.endsWith(".md")
7045
7208
  );
7046
7209
  if (sprintFile) {
7047
- sprintPlanPath = path35.join(pendingDir, sprintFile);
7210
+ sprintPlanPath = path36.join(pendingDir, sprintFile);
7048
7211
  const raw = fs34.readFileSync(sprintPlanPath, "utf8");
7049
7212
  const { fm } = parseFileFrontmatter(raw);
7050
7213
  if (fm["lifecycle_init_mode"] === "block") {
@@ -7128,8 +7291,12 @@ ${waiverLine}` : waiverLine;
7128
7291
  }
7129
7292
  }
7130
7293
  const runScript = resolveRunScript(cli ?? {});
7131
- const args = ["init_sprint.mjs", opts.sprintId, "--stories", opts.stories];
7132
- const result = spawnFn("bash", [runScript, ...args], { stdio: "inherit" });
7294
+ const scriptPath = resolveCleargateScript({ cwd }, "init_sprint.mjs");
7295
+ const result = spawnFn(
7296
+ "bash",
7297
+ [runScript, "node", scriptPath, opts.sprintId, "--stories", opts.stories],
7298
+ { stdio: "inherit" }
7299
+ );
7133
7300
  if (result.error) {
7134
7301
  stderrFn(`[cleargate sprint init] error: ${result.error.message}`);
7135
7302
  return exitFn(1);
@@ -7153,11 +7320,13 @@ function sprintCloseHandler(opts, cli) {
7153
7320
  return printInertAndExit(stdoutFn, exitFn);
7154
7321
  }
7155
7322
  const runScript = resolveRunScript(cli ?? {});
7156
- const args = ["close_sprint.mjs", opts.sprintId];
7323
+ const closeCwd = cli?.cwd ?? process.cwd();
7324
+ const closeScriptPath = resolveCleargateScript({ cwd: closeCwd }, "close_sprint.mjs");
7325
+ const closeArgs = [runScript, "node", closeScriptPath, opts.sprintId];
7157
7326
  if (opts.assumeAck === true) {
7158
- args.push("--assume-ack");
7327
+ closeArgs.push("--assume-ack");
7159
7328
  }
7160
- const result = spawnFn("bash", [runScript, ...args], { stdio: "inherit" });
7329
+ const result = spawnFn("bash", closeArgs, { stdio: "inherit" });
7161
7330
  if (result.error) {
7162
7331
  stderrFn(`[cleargate sprint close] error: ${result.error.message}`);
7163
7332
  return exitFn(1);
@@ -7170,20 +7339,20 @@ function reconcileLifecycleCliHandler(opts, cli) {
7170
7339
  const stderrFn = cli?.stderr ?? ((s) => process.stderr.write(s + "\n"));
7171
7340
  const exitFn = cli?.exit ?? defaultExit;
7172
7341
  const cwd = cli?.cwd ?? process.cwd();
7173
- const deliveryRoot = path35.join(cwd, ".cleargate", "delivery");
7342
+ const deliveryRoot = path36.join(cwd, ".cleargate", "delivery");
7174
7343
  let since;
7175
7344
  let until;
7176
7345
  if (opts.since) {
7177
7346
  since = new Date(opts.since);
7178
7347
  } else {
7179
7348
  try {
7180
- const pendingDir = path35.join(deliveryRoot, "pending-sync");
7349
+ const pendingDir = path36.join(deliveryRoot, "pending-sync");
7181
7350
  const entries = fs34.readdirSync(pendingDir);
7182
7351
  const sprintFile = entries.find(
7183
7352
  (e) => (e.startsWith(`${opts.sprintId}_`) || e === `${opts.sprintId}.md`) && e.endsWith(".md")
7184
7353
  );
7185
7354
  if (sprintFile) {
7186
- const raw = fs34.readFileSync(path35.join(pendingDir, sprintFile), "utf8");
7355
+ const raw = fs34.readFileSync(path36.join(pendingDir, sprintFile), "utf8");
7187
7356
  const { fm } = parseFileFrontmatter(raw);
7188
7357
  const startDate = fm["start_date"];
7189
7358
  since = typeof startDate === "string" ? new Date(startDate) : new Date(Date.now() - 90 * 24 * 60 * 60 * 1e3);
@@ -7339,7 +7508,7 @@ async function sprintArchiveHandler(opts, cli) {
7339
7508
  if (mode === "v1") {
7340
7509
  return printInertAndExit(stdoutFn, exitFn);
7341
7510
  }
7342
- const stateFile = path35.join(cwd, ".cleargate", "sprint-runs", opts.sprintId, "state.json");
7511
+ const stateFile = path36.join(cwd, ".cleargate", "sprint-runs", opts.sprintId, "state.json");
7343
7512
  if (!fs34.existsSync(stateFile)) {
7344
7513
  stderrFn(`[cleargate sprint archive] state.json not found at ${stateFile}`);
7345
7514
  return exitFn(1);
@@ -7358,12 +7527,12 @@ async function sprintArchiveHandler(opts, cli) {
7358
7527
  return exitFn(1);
7359
7528
  }
7360
7529
  const stateStories = state2.stories ?? {};
7361
- const pendingDir = path35.join(cwd, ".cleargate", "delivery", "pending-sync");
7362
- const archiveDir = path35.join(cwd, ".cleargate", "delivery", "archive");
7530
+ const pendingDir = path36.join(cwd, ".cleargate", "delivery", "pending-sync");
7531
+ const archiveDir = path36.join(cwd, ".cleargate", "delivery", "archive");
7363
7532
  let sprintFile = null;
7364
7533
  for (const entry of fs34.readdirSync(pendingDir)) {
7365
7534
  if ((entry.startsWith(`${opts.sprintId}_`) || entry === `${opts.sprintId}.md`) && entry.endsWith(".md")) {
7366
- sprintFile = path35.join(pendingDir, entry);
7535
+ sprintFile = path36.join(pendingDir, entry);
7367
7536
  break;
7368
7537
  }
7369
7538
  }
@@ -7379,7 +7548,7 @@ async function sprintArchiveHandler(opts, cli) {
7379
7548
  if (sprintFile) {
7380
7549
  plan.push({
7381
7550
  src: sprintFile,
7382
- destName: path35.basename(sprintFile),
7551
+ destName: path36.basename(sprintFile),
7383
7552
  status: "Completed"
7384
7553
  });
7385
7554
  }
@@ -7387,7 +7556,7 @@ async function sprintArchiveHandler(opts, cli) {
7387
7556
  for (const entry of fs34.readdirSync(pendingDir)) {
7388
7557
  if ((entry.startsWith(`${epicId}_`) || entry === `${epicId}.md`) && entry.endsWith(".md")) {
7389
7558
  plan.push({
7390
- src: path35.join(pendingDir, entry),
7559
+ src: path36.join(pendingDir, entry),
7391
7560
  destName: entry,
7392
7561
  status: "Approved"
7393
7562
  });
@@ -7399,7 +7568,7 @@ async function sprintArchiveHandler(opts, cli) {
7399
7568
  for (const entry of fs34.readdirSync(pendingDir)) {
7400
7569
  if ((entry.startsWith(`${storyId}_`) || entry === `${storyId}.md`) && entry.endsWith(".md")) {
7401
7570
  plan.push({
7402
- src: path35.join(pendingDir, entry),
7571
+ src: path36.join(pendingDir, entry),
7403
7572
  destName: entry,
7404
7573
  status: "Done"
7405
7574
  });
@@ -7413,7 +7582,7 @@ async function sprintArchiveHandler(opts, cli) {
7413
7582
  const orphans = [];
7414
7583
  for (const entry of fs34.readdirSync(pendingDir)) {
7415
7584
  if (!entry.startsWith("STORY-") || !entry.endsWith(".md")) continue;
7416
- const candidate = path35.join(pendingDir, entry);
7585
+ const candidate = path36.join(pendingDir, entry);
7417
7586
  if (planSrcs.has(candidate)) continue;
7418
7587
  let raw;
7419
7588
  try {
@@ -7434,18 +7603,18 @@ async function sprintArchiveHandler(opts, cli) {
7434
7603
  }
7435
7604
  const completedAt = (/* @__PURE__ */ new Date()).toISOString();
7436
7605
  const sprintBranch = deriveSprintBranchForArchive(opts.sprintId);
7437
- const activePath = path35.join(cwd, ".cleargate", "sprint-runs", ".active");
7606
+ const activePath = path36.join(cwd, ".cleargate", "sprint-runs", ".active");
7438
7607
  if (opts.dryRun) {
7439
7608
  stdoutFn(`[dry-run] Sprint archive plan for ${opts.sprintId}:`);
7440
7609
  stdoutFn(` Sprint branch: ${sprintBranch}`);
7441
7610
  stdoutFn(` Files to archive (${plan.length}):`);
7442
7611
  for (const entry of plan) {
7443
7612
  stdoutFn(
7444
- ` ${path35.basename(entry.src)} \u2192 archive/${entry.destName} [stamp: status=${entry.status}, completed_at=<now>]`
7613
+ ` ${path36.basename(entry.src)} \u2192 archive/${entry.destName} [stamp: status=${entry.status}, completed_at=<now>]`
7445
7614
  );
7446
7615
  }
7447
7616
  if (orphans.length > 0) {
7448
- stdoutFn(` Orphan files (${orphans.length}): ${orphans.map((o) => path35.basename(o)).join(", ")}`);
7617
+ stdoutFn(` Orphan files (${orphans.length}): ${orphans.map((o) => path36.basename(o)).join(", ")}`);
7449
7618
  }
7450
7619
  stdoutFn(` .active \u2192 "" (truncate)`);
7451
7620
  stdoutFn(` git checkout main`);
@@ -7454,7 +7623,7 @@ async function sprintArchiveHandler(opts, cli) {
7454
7623
  return exitFn(0);
7455
7624
  }
7456
7625
  let sprintFileSnapshot = null;
7457
- const wikiRoot = path35.join(cwd, ".cleargate", "wiki");
7626
+ const wikiRoot = path36.join(cwd, ".cleargate", "wiki");
7458
7627
  const wikiInitialised = fs34.existsSync(wikiRoot);
7459
7628
  if (sprintFile && fs34.existsSync(sprintFile)) {
7460
7629
  const { previousContent } = stampSprintClose(sprintFile, () => completedAt);
@@ -7489,7 +7658,7 @@ async function sprintArchiveHandler(opts, cli) {
7489
7658
  }
7490
7659
  const raw = fs34.readFileSync(entry.src, "utf8");
7491
7660
  const stamped = stampFile(raw, entry.status, completedAt);
7492
- const dest = path35.join(archiveDir, entry.destName);
7661
+ const dest = path36.join(archiveDir, entry.destName);
7493
7662
  atomicWriteStr(entry.src, stamped);
7494
7663
  fs34.renameSync(entry.src, dest);
7495
7664
  stdoutFn(`archived: ${entry.destName}`);
@@ -7550,11 +7719,11 @@ function checkPrevSprintCompleted(sprintId, cwd) {
7550
7719
  const prevNum = sprintNum - 1;
7551
7720
  const prevId = `SPRINT-${String(prevNum).padStart(2, "0")}`;
7552
7721
  const prevIdAlt = `SPRINT-${prevNum}`;
7553
- const sprintRunsBase = path35.join(cwd, ".cleargate", "sprint-runs");
7722
+ const sprintRunsBase = path36.join(cwd, ".cleargate", "sprint-runs");
7554
7723
  let stateJson = null;
7555
7724
  let resolvedPrevId = prevId;
7556
7725
  for (const pid of [prevId, prevIdAlt]) {
7557
- const stateFile = path35.join(sprintRunsBase, pid, "state.json");
7726
+ const stateFile = path36.join(sprintRunsBase, pid, "state.json");
7558
7727
  if (fs34.existsSync(stateFile)) {
7559
7728
  try {
7560
7729
  const raw = fs34.readFileSync(stateFile, "utf8");
@@ -7660,8 +7829,8 @@ function checkMainClean(cwd, execFn) {
7660
7829
  }
7661
7830
  function findSprintFile(sprintId, cwd) {
7662
7831
  const searchDirs = [
7663
- path35.join(cwd, ".cleargate", "delivery", "pending-sync"),
7664
- path35.join(cwd, ".cleargate", "delivery", "archive")
7832
+ path36.join(cwd, ".cleargate", "delivery", "pending-sync"),
7833
+ path36.join(cwd, ".cleargate", "delivery", "archive")
7665
7834
  ];
7666
7835
  for (const dir of searchDirs) {
7667
7836
  if (!fs34.existsSync(dir)) continue;
@@ -7674,7 +7843,7 @@ function findSprintFile(sprintId, cwd) {
7674
7843
  const prefix = `${sprintId}_`;
7675
7844
  for (const entry of entries) {
7676
7845
  if ((entry.startsWith(prefix) || entry === `${sprintId}.md`) && entry.endsWith(".md")) {
7677
- return path35.join(dir, entry);
7846
+ return path36.join(dir, entry);
7678
7847
  }
7679
7848
  }
7680
7849
  }
@@ -7682,8 +7851,8 @@ function findSprintFile(sprintId, cwd) {
7682
7851
  }
7683
7852
  function findWorkItemFileLocal(cwd, workItemId) {
7684
7853
  const searchDirs = [
7685
- path35.join(cwd, ".cleargate", "delivery", "pending-sync"),
7686
- path35.join(cwd, ".cleargate", "delivery", "archive")
7854
+ path36.join(cwd, ".cleargate", "delivery", "pending-sync"),
7855
+ path36.join(cwd, ".cleargate", "delivery", "archive")
7687
7856
  ];
7688
7857
  const prefix = `${workItemId}_`;
7689
7858
  for (const dir of searchDirs) {
@@ -7694,7 +7863,7 @@ function findWorkItemFileLocal(cwd, workItemId) {
7694
7863
  continue;
7695
7864
  }
7696
7865
  const match = entries.find((e) => (e.startsWith(prefix) || e === `${workItemId}.md`) && e.endsWith(".md"));
7697
- if (match) return path35.join(dir, match);
7866
+ if (match) return path36.join(dir, match);
7698
7867
  }
7699
7868
  return null;
7700
7869
  }
@@ -7725,7 +7894,7 @@ function readCachedGateSync(absPath) {
7725
7894
  return null;
7726
7895
  }
7727
7896
  function extractInScopeWorkItemIds(sprintFilePath, cwd, execFn) {
7728
- const scriptPath = path35.join(cwd, ".cleargate", "scripts", "assert_story_files.mjs");
7897
+ const scriptPath = path36.join(cwd, ".cleargate", "scripts", "assert_story_files.mjs");
7729
7898
  const cmd = `node "${scriptPath}" "${sprintFilePath}" --emit-json`;
7730
7899
  let stdout;
7731
7900
  try {
@@ -7862,6 +8031,41 @@ function checkPerItemReadinessGates(sprintId, cwd, execFn, mode) {
7862
8031
  Run: cleargate gate check <file> -v for each`
7863
8032
  };
7864
8033
  }
8034
+ function refreshScopedGateCaches(sprintId, cwd, execFn) {
8035
+ const result = { refreshed: [], skipped: [], errors: [] };
8036
+ const sprintFilePath = findSprintFile(sprintId, cwd);
8037
+ if (!sprintFilePath) {
8038
+ return result;
8039
+ }
8040
+ const childIds = extractInScopeWorkItemIds(sprintFilePath, cwd, execFn);
8041
+ if (!childIds || childIds.length === 0) {
8042
+ return result;
8043
+ }
8044
+ for (const id of childIds) {
8045
+ const absPath = findWorkItemFileLocal(cwd, id);
8046
+ if (!absPath) {
8047
+ continue;
8048
+ }
8049
+ let status = "";
8050
+ try {
8051
+ const raw = fs34.readFileSync(absPath, "utf8");
8052
+ const { fm } = parseFrontmatter(raw);
8053
+ status = String(fm["status"] ?? "");
8054
+ } catch {
8055
+ }
8056
+ if (TERMINAL_STATUSES2.has(status)) {
8057
+ result.skipped.push(id);
8058
+ continue;
8059
+ }
8060
+ try {
8061
+ execFn(`cleargate gate check "${absPath}"`, { cwd, encoding: "utf8" });
8062
+ result.refreshed.push(id);
8063
+ } catch (err) {
8064
+ result.errors.push({ id, message: String(err) });
8065
+ }
8066
+ }
8067
+ return result;
8068
+ }
7865
8069
  function emitPunchList(sprintId, results, stdoutFn, stderrFn) {
7866
8070
  const failures = results.filter((r) => !r.pass && !r.skipped);
7867
8071
  if (failures.length === 0) {
@@ -7893,6 +8097,13 @@ function sprintPreflightHandler(opts, cli) {
7893
8097
  }
7894
8098
  const execFn = cli?.execFn ?? ((cmd, execOpts) => (0, import_node_child_process11.execSync)(cmd, { ...execOpts, stdio: "pipe" }));
7895
8099
  const mode = readSprintExecutionMode(opts.sprintId, { cwd });
8100
+ const refresh = refreshScopedGateCaches(opts.sprintId, cwd, execFn);
8101
+ stdoutFn(`Step 0: refreshed ${refresh.refreshed.length} items, ${refresh.errors.length} errors.
8102
+ `);
8103
+ for (const e of refresh.errors) {
8104
+ stdoutFn(` - ${e.id}: ${e.message}
8105
+ `);
8106
+ }
7896
8107
  const results = [
7897
8108
  checkPrevSprintCompleted(opts.sprintId, cwd),
7898
8109
  checkNoLeftoverWorktrees(cwd, execFn),
@@ -7911,7 +8122,7 @@ function sprintPreflightHandler(opts, cli) {
7911
8122
  // src/commands/story.ts
7912
8123
  init_cjs_shims();
7913
8124
  var fs35 = __toESM(require("fs"), 1);
7914
- var path36 = __toESM(require("path"), 1);
8125
+ var path37 = __toESM(require("path"), 1);
7915
8126
  var import_node_child_process12 = require("child_process");
7916
8127
  function defaultExit2(code) {
7917
8128
  return process.exit(code);
@@ -7919,7 +8130,7 @@ function defaultExit2(code) {
7919
8130
  function resolveRunScript2(opts) {
7920
8131
  if (opts.runScriptPath) return opts.runScriptPath;
7921
8132
  const cwd = opts.cwd ?? process.cwd();
7922
- return path36.join(cwd, ".cleargate", "scripts", "run_script.sh");
8133
+ return path37.join(cwd, ".cleargate", "scripts", "run_script.sh");
7923
8134
  }
7924
8135
  function deriveSprintBranch(sprintId) {
7925
8136
  const match = /^SPRINT-(\d+)/.exec(sprintId);
@@ -7932,7 +8143,7 @@ function atomicWriteString(filePath, text) {
7932
8143
  fs35.renameSync(tmpFile, filePath);
7933
8144
  }
7934
8145
  function stateJsonPath(cwd, sprintId) {
7935
- return path36.join(cwd, ".cleargate", "sprint-runs", sprintId, "state.json");
8146
+ return path37.join(cwd, ".cleargate", "sprint-runs", sprintId, "state.json");
7936
8147
  }
7937
8148
  function storyStartHandler(opts, cli) {
7938
8149
  const stdoutFn = cli?.stdout ?? ((s) => process.stdout.write(s + "\n"));
@@ -7949,7 +8160,7 @@ function storyStartHandler(opts, cli) {
7949
8160
  return printInertAndExit(stdoutFn, exitFn);
7950
8161
  }
7951
8162
  const sprintBranch = deriveSprintBranch(sprintId);
7952
- const worktreePath = path36.join(cwd, ".worktrees", opts.storyId);
8163
+ const worktreePath = path37.join(cwd, ".worktrees", opts.storyId);
7953
8164
  const storyBranch = `story/${opts.storyId}`;
7954
8165
  const step1 = spawnFn(
7955
8166
  "git",
@@ -7966,9 +8177,10 @@ function storyStartHandler(opts, cli) {
7966
8177
  return exitFn(step1.status ?? 1);
7967
8178
  }
7968
8179
  const runScript = resolveRunScript2(cli ?? { cwd });
8180
+ const updateStateScript = resolveCleargateScript({ cwd }, "update_state.mjs");
7969
8181
  const step2 = spawnFn(
7970
8182
  "bash",
7971
- [runScript, "update_state.mjs", opts.storyId, "Bouncing"],
8183
+ [runScript, "node", updateStateScript, opts.storyId, "Bouncing"],
7972
8184
  { stdio: "pipe", cwd, encoding: "utf8" }
7973
8185
  );
7974
8186
  if (step2.error) {
@@ -8028,7 +8240,7 @@ function storyCompleteHandler(opts, cli) {
8028
8240
  }
8029
8241
  const sprintBranch = deriveSprintBranch(sprintId);
8030
8242
  const storyBranch = `story/${opts.storyId}`;
8031
- const worktreeRel = path36.join(".worktrees", opts.storyId);
8243
+ const worktreeRel = path37.join(".worktrees", opts.storyId);
8032
8244
  const step1 = spawnFn(
8033
8245
  "git",
8034
8246
  ["rev-list", "--count", `${sprintBranch}..${storyBranch}`],
@@ -8106,9 +8318,10 @@ function storyCompleteHandler(opts, cli) {
8106
8318
  return exitFn(step5.status ?? 1);
8107
8319
  }
8108
8320
  const runScript = resolveRunScript2(cli ?? { cwd });
8321
+ const updateStateDoneScript = resolveCleargateScript({ cwd }, "update_state.mjs");
8109
8322
  const step6 = spawnFn(
8110
8323
  "bash",
8111
- [runScript, "update_state.mjs", opts.storyId, "Done"],
8324
+ [runScript, "node", updateStateDoneScript, opts.storyId, "Done"],
8112
8325
  { stdio: "pipe", cwd, encoding: "utf8" }
8113
8326
  );
8114
8327
  if (step6.error) {
@@ -8126,7 +8339,7 @@ function storyCompleteHandler(opts, cli) {
8126
8339
 
8127
8340
  // src/commands/state.ts
8128
8341
  init_cjs_shims();
8129
- var path37 = __toESM(require("path"), 1);
8342
+ var path38 = __toESM(require("path"), 1);
8130
8343
  var import_node_child_process13 = require("child_process");
8131
8344
  function defaultExit3(code) {
8132
8345
  return process.exit(code);
@@ -8134,7 +8347,7 @@ function defaultExit3(code) {
8134
8347
  function resolveRunScript3(opts) {
8135
8348
  if (opts.runScriptPath) return opts.runScriptPath;
8136
8349
  const cwd = opts.cwd ?? process.cwd();
8137
- return path37.join(cwd, ".cleargate", "scripts", "run_script.sh");
8350
+ return path38.join(cwd, ".cleargate", "scripts", "run_script.sh");
8138
8351
  }
8139
8352
  function stateUpdateHandler(opts, cli) {
8140
8353
  const stdoutFn = cli?.stdout ?? ((s) => process.stdout.write(s + "\n"));
@@ -8151,9 +8364,11 @@ function stateUpdateHandler(opts, cli) {
8151
8364
  return printInertAndExit(stdoutFn, exitFn);
8152
8365
  }
8153
8366
  const runScript = resolveRunScript3(cli ?? {});
8367
+ const updateCwd = cli?.cwd ?? process.cwd();
8368
+ const updateScriptPath = resolveCleargateScript({ cwd: updateCwd }, "update_state.mjs");
8154
8369
  const result = spawnFn(
8155
8370
  "bash",
8156
- [runScript, "update_state.mjs", opts.storyId, opts.newState],
8371
+ [runScript, "node", updateScriptPath, opts.storyId, opts.newState],
8157
8372
  { stdio: "inherit" }
8158
8373
  );
8159
8374
  if (result.error) {
@@ -8176,9 +8391,11 @@ function stateValidateHandler(opts, cli) {
8176
8391
  return printInertAndExit(stdoutFn, exitFn);
8177
8392
  }
8178
8393
  const runScript = resolveRunScript3(cli ?? {});
8394
+ const validateCwd = cli?.cwd ?? process.cwd();
8395
+ const validateScriptPath = resolveCleargateScript({ cwd: validateCwd }, "validate_state.mjs");
8179
8396
  const result = spawnFn(
8180
8397
  "bash",
8181
- [runScript, "validate_state.mjs", opts.sprintId],
8398
+ [runScript, "node", validateScriptPath, opts.sprintId],
8182
8399
  { stdio: "inherit" }
8183
8400
  );
8184
8401
  if (result.error) {
@@ -8192,20 +8409,20 @@ function stateValidateHandler(opts, cli) {
8192
8409
  // src/commands/stamp-tokens.ts
8193
8410
  init_cjs_shims();
8194
8411
  var fs37 = __toESM(require("fs"), 1);
8195
- var path39 = __toESM(require("path"), 1);
8412
+ var path40 = __toESM(require("path"), 1);
8196
8413
 
8197
8414
  // src/lib/ledger-reader.ts
8198
8415
  init_cjs_shims();
8199
8416
  var fs36 = __toESM(require("fs"), 1);
8200
- var path38 = __toESM(require("path"), 1);
8417
+ var path39 = __toESM(require("path"), 1);
8201
8418
  function findSprintRunsRoot(startDir) {
8202
8419
  let dir = startDir;
8203
8420
  while (true) {
8204
- const candidate = path38.join(dir, ".cleargate", "sprint-runs");
8421
+ const candidate = path39.join(dir, ".cleargate", "sprint-runs");
8205
8422
  if (fs36.existsSync(candidate)) {
8206
8423
  return candidate;
8207
8424
  }
8208
- const parent = path38.dirname(dir);
8425
+ const parent = path39.dirname(dir);
8209
8426
  if (parent === dir) {
8210
8427
  return null;
8211
8428
  }
@@ -8264,7 +8481,7 @@ function readLedgerForWorkItem(workItemId, opts = {}) {
8264
8481
  let ledgerFiles;
8265
8482
  try {
8266
8483
  const entries = fs36.readdirSync(sprintRunsRoot, { withFileTypes: true });
8267
- ledgerFiles = entries.filter((e) => e.isDirectory()).map((e) => path38.join(sprintRunsRoot, e.name, "token-ledger.jsonl")).filter((f) => fs36.existsSync(f));
8484
+ ledgerFiles = entries.filter((e) => e.isDirectory()).map((e) => path39.join(sprintRunsRoot, e.name, "token-ledger.jsonl")).filter((f) => fs36.existsSync(f));
8268
8485
  } catch {
8269
8486
  return [];
8270
8487
  }
@@ -8323,7 +8540,7 @@ async function stampTokensHandler(file, opts, cli) {
8323
8540
  });
8324
8541
  const nowFn = cli?.now ?? (() => /* @__PURE__ */ new Date());
8325
8542
  const cwd = cli?.cwd ?? process.cwd();
8326
- const absPath = path39.isAbsolute(file) ? file : path39.resolve(cwd, file);
8543
+ const absPath = path40.isAbsolute(file) ? file : path40.resolve(cwd, file);
8327
8544
  if (/\/\.cleargate\/delivery\/archive\//.test(absPath)) {
8328
8545
  stdoutFn(`[frozen] ${absPath}`);
8329
8546
  exitFn(0);
@@ -8413,21 +8630,21 @@ async function stampTokensHandler(file, opts, cli) {
8413
8630
  exitFn(0);
8414
8631
  }
8415
8632
  function extractWorkItemId(fm, absPath) {
8416
- const idKeys = ["story_id", "epic_id", "proposal_id", "cr_id", "bug_id"];
8633
+ const idKeys = ["story_id", "epic_id", "proposal_id", "cr_id", "bug_id", "initiative_id", "sprint_id"];
8417
8634
  for (const key of idKeys) {
8418
8635
  const val = fm[key];
8419
8636
  if (typeof val === "string" && val.trim() !== "") {
8420
8637
  return val.trim();
8421
8638
  }
8422
8639
  }
8423
- const basename13 = path39.basename(absPath);
8424
- const match = basename13.match(/^(STORY|EPIC|PROPOSAL|CR|BUG)-\d+(-\d+)?/i);
8640
+ const basename13 = path40.basename(absPath);
8641
+ const match = basename13.match(/^(STORY|EPIC|PROPOSAL|CR|BUG|INITIATIVE|SPRINT)-\d+(-\d+)?/i);
8425
8642
  if (match) {
8426
8643
  return match[0].toUpperCase();
8427
8644
  }
8428
8645
  const typeFromPath = detectWorkItemType(absPath);
8429
8646
  if (typeFromPath) {
8430
- const idMatch = basename13.match(/((?:STORY|EPIC|PROPOSAL|CR|BUG)-\d+(?:-\d+)?)/i);
8647
+ const idMatch = basename13.match(/((?:STORY|EPIC|PROPOSAL|CR|BUG|INITIATIVE|SPRINT)-\d+(?:-\d+)?)/i);
8431
8648
  if (idMatch) {
8432
8649
  return idMatch[1].toUpperCase();
8433
8650
  }
@@ -8527,7 +8744,7 @@ ${body}`;
8527
8744
  init_cjs_shims();
8528
8745
  var fs38 = __toESM(require("fs"), 1);
8529
8746
  var fsp = __toESM(require("fs/promises"), 1);
8530
- var path40 = __toESM(require("path"), 1);
8747
+ var path41 = __toESM(require("path"), 1);
8531
8748
 
8532
8749
  // src/lib/changelog.ts
8533
8750
  init_cjs_shims();
@@ -8719,7 +8936,7 @@ async function writeAtomic2(filePath, content) {
8719
8936
  await fsp.rename(tmpPath, filePath);
8720
8937
  }
8721
8938
  async function updateSnapshotEntry(projectRoot, filePath, newSha) {
8722
- const snapshotPath = path40.join(projectRoot, ".cleargate", ".install-manifest.json");
8939
+ const snapshotPath = path41.join(projectRoot, ".cleargate", ".install-manifest.json");
8723
8940
  let snapshot;
8724
8941
  try {
8725
8942
  const raw = await fsp.readFile(snapshotPath, "utf-8");
@@ -8736,17 +8953,17 @@ async function updateSnapshotEntry(projectRoot, filePath, newSha) {
8736
8953
  await writeAtomic2(snapshotPath, JSON.stringify(updated, null, 2) + "\n");
8737
8954
  }
8738
8955
  function isClaudeMd(filePath) {
8739
- return path40.basename(filePath) === "CLAUDE.md";
8956
+ return path41.basename(filePath) === "CLAUDE.md";
8740
8957
  }
8741
8958
  function isSettingsJson(filePath) {
8742
- return path40.basename(filePath) === "settings.json" && filePath.includes(".claude");
8959
+ return path41.basename(filePath) === "settings.json" && filePath.includes(".claude");
8743
8960
  }
8744
8961
  async function applyAlwaysOverwrite(entry, projectRoot, packageRoot, stdout) {
8745
- const targetPath = path40.join(projectRoot, entry.path);
8746
- const sourcePath = path40.join(packageRoot, entry.path);
8962
+ const targetPath = path41.join(projectRoot, entry.path);
8963
+ const sourcePath = path41.join(packageRoot, entry.path);
8747
8964
  try {
8748
8965
  const pkgContent = await fsp.readFile(sourcePath, "utf-8");
8749
- await fsp.mkdir(path40.dirname(targetPath), { recursive: true });
8966
+ await fsp.mkdir(path41.dirname(targetPath), { recursive: true });
8750
8967
  await writeAtomic2(targetPath, pkgContent);
8751
8968
  await updateSnapshotEntry(projectRoot, entry.path, entry.sha256);
8752
8969
  stdout(`[always] overwritten: ${entry.path}`);
@@ -8756,8 +8973,8 @@ async function applyAlwaysOverwrite(entry, projectRoot, packageRoot, stdout) {
8756
8973
  }
8757
8974
  async function applyMerge3Way(entry, projectRoot, packageRoot, installSha, currentSha, flags, opts) {
8758
8975
  const { stdout, stderr, promptMergeChoiceFn, openInEditorFn, stdin } = opts;
8759
- const targetPath = path40.join(projectRoot, entry.path);
8760
- const sourcePath = path40.join(packageRoot, entry.path);
8976
+ const targetPath = path41.join(projectRoot, entry.path);
8977
+ const sourcePath = path41.join(packageRoot, entry.path);
8761
8978
  let ours = "";
8762
8979
  let theirs = "";
8763
8980
  try {
@@ -8820,7 +9037,7 @@ async function applyMerge3Way(entry, projectRoot, packageRoot, installSha, curre
8820
9037
  mergedContent = theirs;
8821
9038
  }
8822
9039
  }
8823
- await fsp.mkdir(path40.dirname(targetPath), { recursive: true });
9040
+ await fsp.mkdir(path41.dirname(targetPath), { recursive: true });
8824
9041
  await writeAtomic2(targetPath, mergedContent);
8825
9042
  const newSha2 = hashNormalized(mergedContent);
8826
9043
  await updateSnapshotEntry(projectRoot, entry.path, newSha2);
@@ -8832,7 +9049,7 @@ async function applyMerge3Way(entry, projectRoot, packageRoot, installSha, curre
8832
9049
  ${ours}=======
8833
9050
  ${theirs}>>>>>>> theirs (upstream)
8834
9051
  `;
8835
- await fsp.mkdir(path40.dirname(mergeFilePath), { recursive: true });
9052
+ await fsp.mkdir(path41.dirname(mergeFilePath), { recursive: true });
8836
9053
  await writeAtomic2(mergeFilePath, conflictContent);
8837
9054
  try {
8838
9055
  const result = await openInEditorFn(mergeFilePath);
@@ -8892,8 +9109,8 @@ async function upgradeHandler(flags, cli) {
8892
9109
  const installedVersion = installSnapshot?.cleargate_version ?? pkgManifest.cleargate_version;
8893
9110
  const targetVersion = pkgManifest.cleargate_version;
8894
9111
  if (installedVersion !== targetVersion) {
8895
- const pkgRoot = cli?.packageRoot ?? path40.join(path40.dirname(new URL(importMetaUrl).pathname), "..", "..");
8896
- const changelogPath = path40.join(pkgRoot, "CHANGELOG.md");
9112
+ const pkgRoot = cli?.packageRoot ?? path41.join(path41.dirname(new URL(importMetaUrl).pathname), "..", "..");
9113
+ const changelogPath = path41.join(pkgRoot, "CHANGELOG.md");
8897
9114
  try {
8898
9115
  const changelogContent = fs38.readFileSync(changelogPath, "utf-8");
8899
9116
  const sections = sliceChangelog(changelogContent, installedVersion, targetVersion);
@@ -8988,7 +9205,7 @@ async function upgradeHandler(flags, cli) {
8988
9205
  init_cjs_shims();
8989
9206
  var fs39 = __toESM(require("fs"), 1);
8990
9207
  var fsp2 = __toESM(require("fs/promises"), 1);
8991
- var path41 = __toESM(require("path"), 1);
9208
+ var path42 = __toESM(require("path"), 1);
8992
9209
  var import_node_child_process15 = require("child_process");
8993
9210
  var USER_ARTIFACT_TIERS = ["user-artifact"];
8994
9211
  var FRAMEWORK_TIERS = ["protocol", "template", "agent", "hook", "skill", "cli-config", "derived"];
@@ -9014,7 +9231,7 @@ function shouldPreserve(entry, preserveSet, removeSet) {
9014
9231
  return false;
9015
9232
  }
9016
9233
  function resolveProjectName(target) {
9017
- const pkgPath = path41.join(target, "package.json");
9234
+ const pkgPath = path42.join(target, "package.json");
9018
9235
  if (fs39.existsSync(pkgPath)) {
9019
9236
  try {
9020
9237
  const raw = fs39.readFileSync(pkgPath, "utf-8");
@@ -9025,7 +9242,7 @@ function resolveProjectName(target) {
9025
9242
  } catch {
9026
9243
  }
9027
9244
  }
9028
- return path41.basename(target);
9245
+ return path42.basename(target);
9029
9246
  }
9030
9247
  function detectUncommittedChanges(target, manifestPaths, gitRunner) {
9031
9248
  const run = gitRunner ?? ((args) => {
@@ -9054,7 +9271,7 @@ function detectUncommittedChanges(target, manifestPaths, gitRunner) {
9054
9271
  return changedFiles.filter((f) => manifestSet.has(f));
9055
9272
  }
9056
9273
  async function removeFromPackageJson(target, dryRun) {
9057
- const pkgPath = path41.join(target, "package.json");
9274
+ const pkgPath = path42.join(target, "package.json");
9058
9275
  if (!fs39.existsSync(pkgPath)) return false;
9059
9276
  let raw;
9060
9277
  try {
@@ -9116,10 +9333,10 @@ async function uninstallHandler(opts) {
9116
9333
  for (const t of FRAMEWORK_TIERS) removeSet.add(t);
9117
9334
  for (const u of USER_ARTIFACT_TIERS) removeSet.add(u);
9118
9335
  }
9119
- const target = opts.path ? path41.resolve(opts.path) : cwd;
9120
- const cleargateDir = path41.join(target, ".cleargate");
9121
- const manifestPath = path41.join(cleargateDir, ".install-manifest.json");
9122
- const uninstalledPath = path41.join(cleargateDir, ".uninstalled");
9336
+ const target = opts.path ? path42.resolve(opts.path) : cwd;
9337
+ const cleargateDir = path42.join(target, ".cleargate");
9338
+ const manifestPath = path42.join(cleargateDir, ".install-manifest.json");
9339
+ const uninstalledPath = path42.join(cleargateDir, ".uninstalled");
9123
9340
  if (!fs39.existsSync(manifestPath)) {
9124
9341
  if (fs39.existsSync(uninstalledPath)) {
9125
9342
  stdout("already uninstalled");
@@ -9152,7 +9369,7 @@ async function uninstallHandler(opts) {
9152
9369
  return;
9153
9370
  }
9154
9371
  }
9155
- const claudeMdPath = path41.join(target, "CLAUDE.md");
9372
+ const claudeMdPath = path42.join(target, "CLAUDE.md");
9156
9373
  let claudeMdContent = null;
9157
9374
  if (fs39.existsSync(claudeMdPath)) {
9158
9375
  claudeMdContent = fs39.readFileSync(claudeMdPath, "utf-8");
@@ -9171,7 +9388,7 @@ async function uninstallHandler(opts) {
9171
9388
  const toPreserve = [];
9172
9389
  const toSkip = [];
9173
9390
  for (const entry of snapshot.files) {
9174
- const filePath = path41.join(target, entry.path);
9391
+ const filePath = path42.join(target, entry.path);
9175
9392
  if (!fs39.existsSync(filePath)) {
9176
9393
  toSkip.push(entry);
9177
9394
  continue;
@@ -9229,7 +9446,7 @@ async function uninstallHandler(opts) {
9229
9446
  const removedPaths = [];
9230
9447
  const preservedPaths = [];
9231
9448
  for (const entry of toRemove) {
9232
- const filePath = path41.join(target, entry.path);
9449
+ const filePath = path42.join(target, entry.path);
9233
9450
  await removeFile(filePath);
9234
9451
  removedPaths.push(entry.path);
9235
9452
  }
@@ -9245,7 +9462,7 @@ async function uninstallHandler(opts) {
9245
9462
  stderr(`Warning: could not strip CLAUDE.md block: ${err.message}`);
9246
9463
  }
9247
9464
  }
9248
- const settingsPath = path41.join(target, ".claude", "settings.json");
9465
+ const settingsPath = path42.join(target, ".claude", "settings.json");
9249
9466
  if (fs39.existsSync(settingsPath)) {
9250
9467
  try {
9251
9468
  const raw = fs39.readFileSync(settingsPath, "utf-8");
@@ -9263,7 +9480,7 @@ async function uninstallHandler(opts) {
9263
9480
  stdout("Removed @cleargate/cli from package.json. Run `npm install` to update package-lock.json.");
9264
9481
  }
9265
9482
  await removeFile(manifestPath);
9266
- await removeFile(path41.join(cleargateDir, ".drift-state.json"));
9483
+ await removeFile(path42.join(cleargateDir, ".drift-state.json"));
9267
9484
  const marker = {
9268
9485
  uninstalled_at: now().toISOString(),
9269
9486
  prior_version: snapshot.cleargate_version,
@@ -9288,16 +9505,16 @@ async function uninstallHandler(opts) {
9288
9505
  // src/commands/sync.ts
9289
9506
  init_cjs_shims();
9290
9507
  var fsPromises8 = __toESM(require("fs/promises"), 1);
9291
- var path49 = __toESM(require("path"), 1);
9508
+ var path50 = __toESM(require("path"), 1);
9292
9509
 
9293
9510
  // src/lib/sync-log.ts
9294
9511
  init_cjs_shims();
9295
9512
  var fs40 = __toESM(require("fs"), 1);
9296
9513
  var fsPromises2 = __toESM(require("fs/promises"), 1);
9297
- var path42 = __toESM(require("path"), 1);
9514
+ var path43 = __toESM(require("path"), 1);
9298
9515
  function resolveActiveSprintDir(projectRoot, _opts) {
9299
- const sprintRunsRoot = path42.join(projectRoot, ".cleargate", "sprint-runs");
9300
- const offSprint = path42.join(sprintRunsRoot, "_off-sprint");
9516
+ const sprintRunsRoot = path43.join(projectRoot, ".cleargate", "sprint-runs");
9517
+ const offSprint = path43.join(sprintRunsRoot, "_off-sprint");
9301
9518
  if (!fs40.existsSync(sprintRunsRoot)) {
9302
9519
  fs40.mkdirSync(sprintRunsRoot, { recursive: true });
9303
9520
  fs40.mkdirSync(offSprint, { recursive: true });
@@ -9305,7 +9522,7 @@ function resolveActiveSprintDir(projectRoot, _opts) {
9305
9522
  }
9306
9523
  const entries = fs40.readdirSync(sprintRunsRoot, { withFileTypes: true });
9307
9524
  const sprintDirs = entries.filter((e) => e.isDirectory() && e.name !== "_off-sprint").map((e) => {
9308
- const fullPath = path42.join(sprintRunsRoot, e.name);
9525
+ const fullPath = path43.join(sprintRunsRoot, e.name);
9309
9526
  const stat = fs40.statSync(fullPath);
9310
9527
  return { name: e.name, fullPath, mtimeMs: stat.mtimeMs };
9311
9528
  }).sort((a, b) => b.mtimeMs - a.mtimeMs);
@@ -9322,7 +9539,7 @@ function redactDetail(detail) {
9322
9539
  return detail.replace(/eyJ[A-Za-z0-9._-]+/g, "[REDACTED]");
9323
9540
  }
9324
9541
  async function appendSyncLog(sprintRoot, entry) {
9325
- const logPath = path42.join(sprintRoot, "sync-log.jsonl");
9542
+ const logPath = path43.join(sprintRoot, "sync-log.jsonl");
9326
9543
  await fsPromises2.mkdir(sprintRoot, { recursive: true });
9327
9544
  const safeEntry = {
9328
9545
  ...entry,
@@ -9332,7 +9549,7 @@ async function appendSyncLog(sprintRoot, entry) {
9332
9549
  await fsPromises2.appendFile(logPath, line, { encoding: "utf8" });
9333
9550
  }
9334
9551
  async function readSyncLog(sprintRoot, filters) {
9335
- const logPath = path42.join(sprintRoot, "sync-log.jsonl");
9552
+ const logPath = path43.join(sprintRoot, "sync-log.jsonl");
9336
9553
  let raw;
9337
9554
  try {
9338
9555
  raw = await fsPromises2.readFile(logPath, "utf8");
@@ -9438,7 +9655,7 @@ function classify2(local, remote, since) {
9438
9655
  init_cjs_shims();
9439
9656
  var import_node_fs2 = require("fs");
9440
9657
  var os8 = __toESM(require("os"), 1);
9441
- var path43 = __toESM(require("path"), 1);
9658
+ var path44 = __toESM(require("path"), 1);
9442
9659
  function promptFourChoice(opts) {
9443
9660
  const { stdin, stdout } = opts;
9444
9661
  stdout("[k]eep mine / [t]ake theirs / [e]dit in $EDITOR / [a]bort: ");
@@ -9508,7 +9725,7 @@ async function promptThreeWayMerge(opts) {
9508
9725
  case "a":
9509
9726
  return { resolution: "aborted", body: local };
9510
9727
  case "e": {
9511
- const tmpFile = path43.join(os8.tmpdir(), `cleargate-merge-${itemId}-${now()}.md`);
9728
+ const tmpFile = path44.join(os8.tmpdir(), `cleargate-merge-${itemId}-${now()}.md`);
9512
9729
  const markerContent = `<<<<<<< local
9513
9730
  ${local}
9514
9731
  =======
@@ -9608,12 +9825,12 @@ init_config();
9608
9825
  // src/lib/intake.ts
9609
9826
  init_cjs_shims();
9610
9827
  var fsPromises4 = __toESM(require("fs/promises"), 1);
9611
- var path45 = __toESM(require("path"), 1);
9828
+ var path46 = __toESM(require("path"), 1);
9612
9829
 
9613
9830
  // src/lib/slug.ts
9614
9831
  init_cjs_shims();
9615
9832
  var fsPromises3 = __toESM(require("fs/promises"), 1);
9616
- var path44 = __toESM(require("path"), 1);
9833
+ var path45 = __toESM(require("path"), 1);
9617
9834
  function slugify(title, max = 40) {
9618
9835
  const normalized = title.normalize("NFKD").replace(new RegExp("\\p{M}", "gu"), "");
9619
9836
  const lowered = normalized.toLowerCase();
@@ -9628,8 +9845,8 @@ function slugify(title, max = 40) {
9628
9845
  var PROPOSAL_ID_RE = /^proposal_id:\s*"?PROP-(\d+)"?/m;
9629
9846
  async function nextProposalId(projectRoot) {
9630
9847
  const dirs = [
9631
- path44.join(projectRoot, ".cleargate", "delivery", "pending-sync"),
9632
- path44.join(projectRoot, ".cleargate", "delivery", "archive")
9848
+ path45.join(projectRoot, ".cleargate", "delivery", "pending-sync"),
9849
+ path45.join(projectRoot, ".cleargate", "delivery", "archive")
9633
9850
  ];
9634
9851
  let maxN = 0;
9635
9852
  for (const dir of dirs) {
@@ -9641,7 +9858,7 @@ async function nextProposalId(projectRoot) {
9641
9858
  }
9642
9859
  for (const entry of entries) {
9643
9860
  if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
9644
- const fullPath = path44.join(dir, entry.name);
9861
+ const fullPath = path45.join(dir, entry.name);
9645
9862
  try {
9646
9863
  const raw = await fsPromises3.readFile(fullPath, "utf8");
9647
9864
  const fmEnd = extractFrontmatterBlock(raw);
@@ -9659,8 +9876,8 @@ async function nextProposalId(projectRoot) {
9659
9876
  }
9660
9877
  async function findByRemoteId(projectRoot, remoteId) {
9661
9878
  const dirs = [
9662
- path44.join(projectRoot, ".cleargate", "delivery", "pending-sync"),
9663
- path44.join(projectRoot, ".cleargate", "delivery", "archive")
9879
+ path45.join(projectRoot, ".cleargate", "delivery", "pending-sync"),
9880
+ path45.join(projectRoot, ".cleargate", "delivery", "archive")
9664
9881
  ];
9665
9882
  const escaped = remoteId.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
9666
9883
  const re = new RegExp(`^remote_id:\\s*"?${escaped}"?\\s*$`, "m");
@@ -9673,7 +9890,7 @@ async function findByRemoteId(projectRoot, remoteId) {
9673
9890
  }
9674
9891
  for (const entry of entries) {
9675
9892
  if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
9676
- const fullPath = path44.join(dir, entry.name);
9893
+ const fullPath = path45.join(dir, entry.name);
9677
9894
  try {
9678
9895
  const raw = await fsPromises3.readFile(fullPath, "utf8");
9679
9896
  const fm = extractFrontmatterBlock(raw);
@@ -9710,7 +9927,7 @@ async function runIntakeBranch(opts) {
9710
9927
  labelFilter = "cleargate:proposal",
9711
9928
  now = () => (/* @__PURE__ */ new Date()).toISOString()
9712
9929
  } = opts;
9713
- const pendingSyncDir = path45.join(projectRoot, ".cleargate", "delivery", "pending-sync");
9930
+ const pendingSyncDir = path46.join(projectRoot, ".cleargate", "delivery", "pending-sync");
9714
9931
  let remoteItems = [];
9715
9932
  try {
9716
9933
  remoteItems = await mcp2.call(
@@ -9741,7 +9958,7 @@ async function runIntakeBranch(opts) {
9741
9958
  const slug2 = slugify(item.title ?? "untitled");
9742
9959
  const num2 = proposalId2.replace("PROP-", "");
9743
9960
  const filename2 = `PROPOSAL-${num2}-remote-${slug2}.md`;
9744
- const targetPath2 = path45.join(pendingSyncDir, filename2);
9961
+ const targetPath2 = path46.join(pendingSyncDir, filename2);
9745
9962
  createdItems.push({
9746
9963
  proposalId: proposalId2,
9747
9964
  remoteId: item.remote_id,
@@ -9754,7 +9971,7 @@ async function runIntakeBranch(opts) {
9754
9971
  const num = proposalId.replace("PROP-", "");
9755
9972
  const slug = slugify(item.title ?? "untitled");
9756
9973
  const filename = `PROPOSAL-${num}-remote-${slug}.md`;
9757
- const targetPath = path45.join(pendingSyncDir, filename);
9974
+ const targetPath = path46.join(pendingSyncDir, filename);
9758
9975
  const nowTs = now();
9759
9976
  const fm = {
9760
9977
  proposal_id: proposalId,
@@ -9846,8 +10063,8 @@ path/to/new/file.ext - {Explanation of purpose}
9846
10063
  }
9847
10064
  async function hasAnyRemoteAuthored(projectRoot) {
9848
10065
  const dirs = [
9849
- path45.join(projectRoot, ".cleargate", "delivery", "pending-sync"),
9850
- path45.join(projectRoot, ".cleargate", "delivery", "archive")
10066
+ path46.join(projectRoot, ".cleargate", "delivery", "pending-sync"),
10067
+ path46.join(projectRoot, ".cleargate", "delivery", "archive")
9851
10068
  ];
9852
10069
  for (const dir of dirs) {
9853
10070
  let entries;
@@ -9858,7 +10075,7 @@ async function hasAnyRemoteAuthored(projectRoot) {
9858
10075
  }
9859
10076
  for (const entry of entries) {
9860
10077
  if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
9861
- const fullPath = path45.join(dir, entry.name);
10078
+ const fullPath = path46.join(dir, entry.name);
9862
10079
  try {
9863
10080
  const raw = await fsPromises4.readFile(fullPath, "utf8");
9864
10081
  const fmEnd = raw.indexOf("\n---", 4);
@@ -9878,7 +10095,7 @@ async function hasAnyRemoteAuthored(projectRoot) {
9878
10095
  init_cjs_shims();
9879
10096
  var fs42 = __toESM(require("fs"), 1);
9880
10097
  var fsPromises5 = __toESM(require("fs/promises"), 1);
9881
- var path46 = __toESM(require("path"), 1);
10098
+ var path47 = __toESM(require("path"), 1);
9882
10099
  async function resolveActiveItems(projectRoot, localItems, nowFn = () => (/* @__PURE__ */ new Date()).toISOString()) {
9883
10100
  const active = /* @__PURE__ */ new Set();
9884
10101
  const now = Date.parse(nowFn());
@@ -9903,7 +10120,7 @@ async function resolveInSprintIds(projectRoot) {
9903
10120
  const ids = /* @__PURE__ */ new Set();
9904
10121
  try {
9905
10122
  const sprintDir = resolveActiveSprintDir(projectRoot);
9906
- const sprintId = path46.basename(sprintDir);
10123
+ const sprintId = path47.basename(sprintDir);
9907
10124
  if (sprintId === "_off-sprint") return ids;
9908
10125
  const sprintFile = await findSprintFile2(projectRoot, sprintId);
9909
10126
  if (!sprintFile) return ids;
@@ -9918,14 +10135,14 @@ async function resolveInSprintIds(projectRoot) {
9918
10135
  return ids;
9919
10136
  }
9920
10137
  async function findSprintFile2(projectRoot, sprintId) {
9921
- const pendingSync = path46.join(projectRoot, ".cleargate", "delivery", "pending-sync");
9922
- const archive = path46.join(projectRoot, ".cleargate", "delivery", "archive");
10138
+ const pendingSync = path47.join(projectRoot, ".cleargate", "delivery", "pending-sync");
10139
+ const archive = path47.join(projectRoot, ".cleargate", "delivery", "archive");
9923
10140
  for (const dir of [pendingSync, archive]) {
9924
10141
  try {
9925
10142
  const entries = fs42.readdirSync(dir, { withFileTypes: true });
9926
10143
  for (const entry of entries) {
9927
10144
  if (entry.isFile() && entry.name.startsWith(sprintId) && entry.name.endsWith(".md")) {
9928
- return path46.join(dir, entry.name);
10145
+ return path47.join(dir, entry.name);
9929
10146
  }
9930
10147
  }
9931
10148
  } catch {
@@ -9937,12 +10154,12 @@ async function findSprintFile2(projectRoot, sprintId) {
9937
10154
  // src/lib/comments-cache.ts
9938
10155
  init_cjs_shims();
9939
10156
  var fsPromises6 = __toESM(require("fs/promises"), 1);
9940
- var path47 = __toESM(require("path"), 1);
10157
+ var path48 = __toESM(require("path"), 1);
9941
10158
  function cacheDir(projectRoot) {
9942
- return path47.join(projectRoot, ".cleargate", ".comments-cache");
10159
+ return path48.join(projectRoot, ".cleargate", ".comments-cache");
9943
10160
  }
9944
10161
  function cachePath(projectRoot, remoteId) {
9945
- return path47.join(cacheDir(projectRoot), `${remoteId}.json`);
10162
+ return path48.join(cacheDir(projectRoot), `${remoteId}.json`);
9946
10163
  }
9947
10164
  async function writeCommentCache(projectRoot, remoteId, comments) {
9948
10165
  const dir = cacheDir(projectRoot);
@@ -9957,7 +10174,7 @@ async function writeCommentCache(projectRoot, remoteId, comments) {
9957
10174
  // src/lib/wiki-comments-render.ts
9958
10175
  init_cjs_shims();
9959
10176
  var fsPromises7 = __toESM(require("fs/promises"), 1);
9960
- var path48 = __toESM(require("path"), 1);
10177
+ var path49 = __toESM(require("path"), 1);
9961
10178
  var START = "<!-- cleargate:comments:start -->";
9962
10179
  var END = "<!-- cleargate:comments:end -->";
9963
10180
  function resolveBucket(fm) {
@@ -10002,7 +10219,7 @@ async function renderCommentsSection(opts) {
10002
10219
  const bucket = resolveBucket(localItem.fm);
10003
10220
  const primaryId = getPrimaryId(localItem.fm);
10004
10221
  if (!bucket || !primaryId) return;
10005
- const wikiPath = path48.join(
10222
+ const wikiPath = path49.join(
10006
10223
  projectRoot,
10007
10224
  ".cleargate",
10008
10225
  "wiki",
@@ -10038,7 +10255,7 @@ async function renderCommentsSection(opts) {
10038
10255
  await writeAtomic4(wikiPath, updated);
10039
10256
  }
10040
10257
  async function writeAtomic4(filePath, content) {
10041
- await fsPromises7.mkdir(path48.dirname(filePath), { recursive: true });
10258
+ await fsPromises7.mkdir(path49.dirname(filePath), { recursive: true });
10042
10259
  const tmpPath = `${filePath}.tmp.${Date.now()}`;
10043
10260
  await fsPromises7.writeFile(tmpPath, content, "utf8");
10044
10261
  await fsPromises7.rename(tmpPath, filePath);
@@ -10050,11 +10267,11 @@ async function syncCheckHandler(opts = {}) {
10050
10267
  const env = opts.env ?? process.env;
10051
10268
  const stdout = opts.stdout ?? ((s) => process.stdout.write(s));
10052
10269
  const nowFn = opts.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
10053
- const markerPath = path49.join(projectRoot, ".cleargate", ".sync-marker.json");
10270
+ const markerPath = path50.join(projectRoot, ".cleargate", ".sync-marker.json");
10054
10271
  const updateMarker = async (nowIso2) => {
10055
10272
  try {
10056
10273
  const content = JSON.stringify({ last_check: nowIso2 });
10057
- await fsPromises8.mkdir(path49.dirname(markerPath), { recursive: true });
10274
+ await fsPromises8.mkdir(path50.dirname(markerPath), { recursive: true });
10058
10275
  const tmpPath = `${markerPath}.tmp.${Date.now()}`;
10059
10276
  await fsPromises8.writeFile(tmpPath, content, "utf8");
10060
10277
  await fsPromises8.rename(tmpPath, markerPath);
@@ -10137,7 +10354,7 @@ async function syncHandler(opts = {}) {
10137
10354
  const nowFn = opts.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
10138
10355
  const identity = resolveIdentity(projectRoot);
10139
10356
  const sprintRoot = resolveActiveSprintDir(projectRoot);
10140
- const sprintId = path49.basename(sprintRoot);
10357
+ const sprintId = path50.basename(sprintRoot);
10141
10358
  let mcp2;
10142
10359
  if (opts.mcp) {
10143
10360
  mcp2 = opts.mcp;
@@ -10198,7 +10415,7 @@ async function syncHandler(opts = {}) {
10198
10415
  exit(2);
10199
10416
  return;
10200
10417
  }
10201
- const wikiMetaPath = path49.join(projectRoot, ".cleargate", "wiki", "meta.json");
10418
+ const wikiMetaPath = path50.join(projectRoot, ".cleargate", "wiki", "meta.json");
10202
10419
  let lastRemoteSync = "1970-01-01T00:00:00.000Z";
10203
10420
  try {
10204
10421
  const metaRaw = await fsPromises8.readFile(wikiMetaPath, "utf8");
@@ -10439,7 +10656,7 @@ async function syncHandler(opts = {}) {
10439
10656
  };
10440
10657
  await appendSyncLog(sprintRoot, entry);
10441
10658
  }
10442
- const conflictsFile = path49.join(projectRoot, ".cleargate", ".conflicts.json");
10659
+ const conflictsFile = path50.join(projectRoot, ".cleargate", ".conflicts.json");
10443
10660
  const conflictsContent = {
10444
10661
  generated_at: nowFn(),
10445
10662
  sprint_id: sprintId,
@@ -10447,7 +10664,7 @@ async function syncHandler(opts = {}) {
10447
10664
  };
10448
10665
  await writeAtomic5(conflictsFile, JSON.stringify(conflictsContent, null, 2) + "\n");
10449
10666
  try {
10450
- await fsPromises8.mkdir(path49.dirname(wikiMetaPath), { recursive: true });
10667
+ await fsPromises8.mkdir(path50.dirname(wikiMetaPath), { recursive: true });
10451
10668
  let meta = {};
10452
10669
  try {
10453
10670
  const raw = await fsPromises8.readFile(wikiMetaPath, "utf8");
@@ -10488,13 +10705,13 @@ async function applyPull(item, localPath, fm, actorEmail, nowFn) {
10488
10705
  await writeAtomic5(localPath, newContent);
10489
10706
  }
10490
10707
  async function writeAtomic5(filePath, content) {
10491
- await fsPromises8.mkdir(path49.dirname(filePath), { recursive: true });
10708
+ await fsPromises8.mkdir(path50.dirname(filePath), { recursive: true });
10492
10709
  const tmpPath = `${filePath}.tmp.${Date.now()}`;
10493
10710
  await fsPromises8.writeFile(tmpPath, content, "utf8");
10494
10711
  await fsPromises8.rename(tmpPath, filePath);
10495
10712
  }
10496
10713
  async function scanLocalItems(projectRoot) {
10497
- const pendingSync = path49.join(projectRoot, ".cleargate", "delivery", "pending-sync");
10714
+ const pendingSync = path50.join(projectRoot, ".cleargate", "delivery", "pending-sync");
10498
10715
  const results = [];
10499
10716
  let entries;
10500
10717
  try {
@@ -10504,7 +10721,7 @@ async function scanLocalItems(projectRoot) {
10504
10721
  }
10505
10722
  for (const entry of entries) {
10506
10723
  if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
10507
- const fullPath = path49.join(pendingSync, entry.name);
10724
+ const fullPath = path50.join(pendingSync, entry.name);
10508
10725
  try {
10509
10726
  const raw = await fsPromises8.readFile(fullPath, "utf8");
10510
10727
  const { fm, body } = parseFrontmatter(raw);
@@ -10532,7 +10749,7 @@ init_config();
10532
10749
  // src/lib/sync/work-items.ts
10533
10750
  init_cjs_shims();
10534
10751
  var fsPromises9 = __toESM(require("fs/promises"), 1);
10535
- var path50 = __toESM(require("path"), 1);
10752
+ var path51 = __toESM(require("path"), 1);
10536
10753
  var import_node_crypto2 = require("crypto");
10537
10754
  var BATCH_SIZE = 100;
10538
10755
  var ATTRIBUTION_FIELDS = /* @__PURE__ */ new Set([
@@ -10580,8 +10797,8 @@ function getItemId2(fm) {
10580
10797
  }
10581
10798
  async function walkDeliveryDirs(projectRoot) {
10582
10799
  const dirs = [
10583
- path50.join(projectRoot, ".cleargate", "delivery", "pending-sync"),
10584
- path50.join(projectRoot, ".cleargate", "delivery", "archive")
10800
+ path51.join(projectRoot, ".cleargate", "delivery", "pending-sync"),
10801
+ path51.join(projectRoot, ".cleargate", "delivery", "archive")
10585
10802
  ];
10586
10803
  const results = [];
10587
10804
  for (const dir of dirs) {
@@ -10593,7 +10810,7 @@ async function walkDeliveryDirs(projectRoot) {
10593
10810
  }
10594
10811
  for (const entry of entries) {
10595
10812
  if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
10596
- const fullPath = path50.join(dir, entry.name);
10813
+ const fullPath = path51.join(dir, entry.name);
10597
10814
  try {
10598
10815
  const raw = await fsPromises9.readFile(fullPath, "utf8");
10599
10816
  const { fm, body } = parseFrontmatter(raw);
@@ -10618,7 +10835,7 @@ async function walkDeliveryDirs(projectRoot) {
10618
10835
  return results;
10619
10836
  }
10620
10837
  async function writeAtomic6(filePath, content) {
10621
- await fsPromises9.mkdir(path50.dirname(filePath), { recursive: true });
10838
+ await fsPromises9.mkdir(path51.dirname(filePath), { recursive: true });
10622
10839
  const tmpPath = `${filePath}.tmp.${Date.now()}`;
10623
10840
  await fsPromises9.writeFile(tmpPath, content, "utf8");
10624
10841
  await fsPromises9.rename(tmpPath, filePath);
@@ -10687,7 +10904,7 @@ async function syncWorkItems(opts) {
10687
10904
  init_cjs_shims();
10688
10905
  var fs43 = __toESM(require("fs"), 1);
10689
10906
  var os9 = __toESM(require("os"), 1);
10690
- var path51 = __toESM(require("path"), 1);
10907
+ var path52 = __toESM(require("path"), 1);
10691
10908
  var DEFAULT_BASE = "https://admin.cleargate.soula.ge/";
10692
10909
  function adminUrl(urlPath, opts) {
10693
10910
  const env = opts?.env ?? process.env;
@@ -10710,7 +10927,7 @@ function adminUrl(urlPath, opts) {
10710
10927
  function readLocalConfig() {
10711
10928
  const home = os9.homedir();
10712
10929
  if (!home) return null;
10713
- const configPath = path51.join(home, ".cleargate", "config.json");
10930
+ const configPath = path52.join(home, ".cleargate", "config.json");
10714
10931
  const raw = fs43.readFileSync(configPath, "utf8");
10715
10932
  return JSON.parse(raw);
10716
10933
  }
@@ -10826,7 +11043,7 @@ async function syncWorkItemsHandler(opts = {}) {
10826
11043
  // src/commands/pull.ts
10827
11044
  init_cjs_shims();
10828
11045
  var fsPromises10 = __toESM(require("fs/promises"), 1);
10829
- var path52 = __toESM(require("path"), 1);
11046
+ var path53 = __toESM(require("path"), 1);
10830
11047
  init_acquire();
10831
11048
  init_config();
10832
11049
  async function pullHandler(idOrRemoteId, opts = {}) {
@@ -10941,7 +11158,7 @@ async function pullHandler(idOrRemoteId, opts = {}) {
10941
11158
  result: "ok"
10942
11159
  };
10943
11160
  await appendSyncLog(sprintRoot, entry);
10944
- stdout(`pull: ${remoteId} applied to ${path52.relative(projectRoot, localPath)}
11161
+ stdout(`pull: ${remoteId} applied to ${path53.relative(projectRoot, localPath)}
10945
11162
  `);
10946
11163
  if (opts.comments) {
10947
11164
  const comments = await mcp2.call(
@@ -10964,7 +11181,7 @@ async function resolveRemoteId(idOrRemoteId, projectRoot) {
10964
11181
  if (/^[A-Z]+-\d+/.test(idOrRemoteId)) {
10965
11182
  return idOrRemoteId;
10966
11183
  }
10967
- const pendingSync = path52.join(projectRoot, ".cleargate", "delivery", "pending-sync");
11184
+ const pendingSync = path53.join(projectRoot, ".cleargate", "delivery", "pending-sync");
10968
11185
  let entries;
10969
11186
  try {
10970
11187
  entries = await fsPromises10.readdir(pendingSync, { withFileTypes: true });
@@ -10974,7 +11191,7 @@ async function resolveRemoteId(idOrRemoteId, projectRoot) {
10974
11191
  for (const entry of entries) {
10975
11192
  if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
10976
11193
  try {
10977
- const raw = await fsPromises10.readFile(path52.join(pendingSync, entry.name), "utf8");
11194
+ const raw = await fsPromises10.readFile(path53.join(pendingSync, entry.name), "utf8");
10978
11195
  const { fm } = parseFrontmatter(raw);
10979
11196
  for (const key of ["story_id", "epic_id", "proposal_id", "cr_id", "bug_id"]) {
10980
11197
  if (fm[key] === idOrRemoteId && typeof fm["remote_id"] === "string") {
@@ -10987,7 +11204,7 @@ async function resolveRemoteId(idOrRemoteId, projectRoot) {
10987
11204
  return null;
10988
11205
  }
10989
11206
  async function findLocalFile(remoteId, projectRoot) {
10990
- const pendingSync = path52.join(projectRoot, ".cleargate", "delivery", "pending-sync");
11207
+ const pendingSync = path53.join(projectRoot, ".cleargate", "delivery", "pending-sync");
10991
11208
  let entries;
10992
11209
  try {
10993
11210
  entries = await fsPromises10.readdir(pendingSync, { withFileTypes: true });
@@ -10996,7 +11213,7 @@ async function findLocalFile(remoteId, projectRoot) {
10996
11213
  }
10997
11214
  for (const entry of entries) {
10998
11215
  if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
10999
- const fullPath = path52.join(pendingSync, entry.name);
11216
+ const fullPath = path53.join(pendingSync, entry.name);
11000
11217
  try {
11001
11218
  const raw = await fsPromises10.readFile(fullPath, "utf8");
11002
11219
  const { fm } = parseFrontmatter(raw);
@@ -11007,7 +11224,7 @@ async function findLocalFile(remoteId, projectRoot) {
11007
11224
  return null;
11008
11225
  }
11009
11226
  async function writeAtomic7(filePath, content) {
11010
- await fsPromises10.mkdir(path52.dirname(filePath), { recursive: true });
11227
+ await fsPromises10.mkdir(path53.dirname(filePath), { recursive: true });
11011
11228
  const tmpPath = `${filePath}.tmp.${Date.now()}`;
11012
11229
  await fsPromises10.writeFile(tmpPath, content, "utf8");
11013
11230
  await fsPromises10.rename(tmpPath, filePath);
@@ -11023,7 +11240,7 @@ function getItemId3(fm) {
11023
11240
  // src/commands/push.ts
11024
11241
  init_cjs_shims();
11025
11242
  var fsPromises11 = __toESM(require("fs/promises"), 1);
11026
- var path53 = __toESM(require("path"), 1);
11243
+ var path54 = __toESM(require("path"), 1);
11027
11244
  init_acquire();
11028
11245
  init_config();
11029
11246
  async function pushHandler(fileOrId, opts = {}) {
@@ -11099,7 +11316,7 @@ async function pushHandler(fileOrId, opts = {}) {
11099
11316
  }
11100
11317
  async function handlePush(filePath, ctx) {
11101
11318
  const { projectRoot, identity, sprintRoot, nowFn, resolveMcp, stdout, stderr, exit } = ctx;
11102
- const resolvedPath = path53.isAbsolute(filePath) ? filePath : path53.resolve(projectRoot, filePath);
11319
+ const resolvedPath = path54.isAbsolute(filePath) ? filePath : path54.resolve(projectRoot, filePath);
11103
11320
  let rawContent;
11104
11321
  try {
11105
11322
  rawContent = await fsPromises11.readFile(resolvedPath, "utf8");
@@ -11225,8 +11442,8 @@ async function handleRevert(idOrRemoteId, ctx) {
11225
11442
  void localPath;
11226
11443
  }
11227
11444
  async function resolveLocalItem(idOrRemoteId, projectRoot) {
11228
- const pendingSync = path53.join(projectRoot, ".cleargate", "delivery", "pending-sync");
11229
- const archive = path53.join(projectRoot, ".cleargate", "delivery", "archive");
11445
+ const pendingSync = path54.join(projectRoot, ".cleargate", "delivery", "pending-sync");
11446
+ const archive = path54.join(projectRoot, ".cleargate", "delivery", "archive");
11230
11447
  for (const dir of [pendingSync, archive]) {
11231
11448
  let entries;
11232
11449
  try {
@@ -11236,7 +11453,7 @@ async function resolveLocalItem(idOrRemoteId, projectRoot) {
11236
11453
  }
11237
11454
  for (const entry of entries) {
11238
11455
  if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
11239
- const fullPath = path53.join(dir, entry.name);
11456
+ const fullPath = path54.join(dir, entry.name);
11240
11457
  try {
11241
11458
  const raw = await fsPromises11.readFile(fullPath, "utf8");
11242
11459
  const { fm } = parseFrontmatter(raw);
@@ -11255,7 +11472,7 @@ async function resolveLocalItem(idOrRemoteId, projectRoot) {
11255
11472
  return null;
11256
11473
  }
11257
11474
  async function writeAtomic8(filePath, content) {
11258
- await fsPromises11.mkdir(path53.dirname(filePath), { recursive: true });
11475
+ await fsPromises11.mkdir(path54.dirname(filePath), { recursive: true });
11259
11476
  const tmpPath = `${filePath}.tmp.${Date.now()}`;
11260
11477
  await fsPromises11.writeFile(tmpPath, content, "utf8");
11261
11478
  await fsPromises11.rename(tmpPath, filePath);
@@ -11284,7 +11501,7 @@ function getItemType2(fm) {
11284
11501
  // src/commands/conflicts.ts
11285
11502
  init_cjs_shims();
11286
11503
  var fsPromises12 = __toESM(require("fs/promises"), 1);
11287
- var path54 = __toESM(require("path"), 1);
11504
+ var path55 = __toESM(require("path"), 1);
11288
11505
  init_acquire();
11289
11506
  init_config();
11290
11507
  var RESOLUTION_HINTS = {
@@ -11322,7 +11539,7 @@ async function conflictsHandler(opts = {}) {
11322
11539
  }
11323
11540
  }
11324
11541
  }
11325
- const conflictsFile = path54.join(projectRoot, ".cleargate", ".conflicts.json");
11542
+ const conflictsFile = path55.join(projectRoot, ".cleargate", ".conflicts.json");
11326
11543
  let data;
11327
11544
  try {
11328
11545
  const raw = await fsPromises12.readFile(conflictsFile, "utf8");
@@ -11411,7 +11628,7 @@ function formatEntry(entry) {
11411
11628
  // src/commands/admin-login.ts
11412
11629
  init_cjs_shims();
11413
11630
  var fs44 = __toESM(require("fs"), 1);
11414
- var path55 = __toESM(require("path"), 1);
11631
+ var path56 = __toESM(require("path"), 1);
11415
11632
  var os10 = __toESM(require("os"), 1);
11416
11633
  var DEFAULT_MCP_URL = "http://localhost:3000";
11417
11634
  function resolveMcpUrl(mcpUrlFlag, env) {
@@ -11420,10 +11637,10 @@ function resolveMcpUrl(mcpUrlFlag, env) {
11420
11637
  function resolveAuthFilePath(opts) {
11421
11638
  if (opts.authFilePath) return opts.authFilePath;
11422
11639
  const homedirFn = opts.homedir ?? os10.homedir;
11423
- return path55.join(homedirFn(), ".cleargate", "admin-auth.json");
11640
+ return path56.join(homedirFn(), ".cleargate", "admin-auth.json");
11424
11641
  }
11425
11642
  function writeAdminAuth(filePath, token) {
11426
- const dir = path55.dirname(filePath);
11643
+ const dir = path56.dirname(filePath);
11427
11644
  fs44.mkdirSync(dir, { recursive: true });
11428
11645
  const payload = JSON.stringify({ version: 1, token }, null, 2);
11429
11646
  fs44.writeFileSync(filePath, payload, { encoding: "utf8", mode: 384 });
@@ -11538,7 +11755,7 @@ async function adminLoginHandler(opts = {}) {
11538
11755
  // src/commands/hotfix.ts
11539
11756
  init_cjs_shims();
11540
11757
  var fs45 = __toESM(require("fs"), 1);
11541
- var path56 = __toESM(require("path"), 1);
11758
+ var path57 = __toESM(require("path"), 1);
11542
11759
  function defaultExit4(code) {
11543
11760
  return process.exit(code);
11544
11761
  }
@@ -11562,8 +11779,8 @@ function maxHotfixId(pendingDir) {
11562
11779
  return max;
11563
11780
  }
11564
11781
  function countActiveHotfixes(repoRoot) {
11565
- const pendingDir = path56.join(repoRoot, ".cleargate", "delivery", "pending-sync");
11566
- const archiveDir = path56.join(repoRoot, ".cleargate", "delivery", "archive");
11782
+ const pendingDir = path57.join(repoRoot, ".cleargate", "delivery", "pending-sync");
11783
+ const archiveDir = path57.join(repoRoot, ".cleargate", "delivery", "archive");
11567
11784
  const sevenDaysAgo = Date.now() - 7 * 24 * 60 * 60 * 1e3;
11568
11785
  let count = 0;
11569
11786
  let pendingEntries = [];
@@ -11582,7 +11799,7 @@ function countActiveHotfixes(repoRoot) {
11582
11799
  for (const entry of archiveEntries) {
11583
11800
  if (entry.startsWith("HOTFIX-") && entry.endsWith(".md")) {
11584
11801
  try {
11585
- const stat = fs45.statSync(path56.join(archiveDir, entry));
11802
+ const stat = fs45.statSync(path57.join(archiveDir, entry));
11586
11803
  if (stat.mtimeMs >= sevenDaysAgo) count++;
11587
11804
  } catch {
11588
11805
  }
@@ -11591,7 +11808,7 @@ function countActiveHotfixes(repoRoot) {
11591
11808
  return count;
11592
11809
  }
11593
11810
  function resolveTemplatePath(repoRoot) {
11594
- return path56.join(repoRoot, ".cleargate", "templates", "hotfix.md");
11811
+ return path57.join(repoRoot, ".cleargate", "templates", "hotfix.md");
11595
11812
  }
11596
11813
  function hotfixNewHandler(opts, cli) {
11597
11814
  const stdoutFn = cli?.stdout ?? ((s) => process.stdout.write(s + "\n"));
@@ -11610,7 +11827,7 @@ function hotfixNewHandler(opts, cli) {
11610
11827
  );
11611
11828
  return exitFn(1);
11612
11829
  }
11613
- const pendingDir = path56.join(repoRoot, ".cleargate", "delivery", "pending-sync");
11830
+ const pendingDir = path57.join(repoRoot, ".cleargate", "delivery", "pending-sync");
11614
11831
  const maxId = maxHotfixId(pendingDir);
11615
11832
  const nextId = maxId + 1;
11616
11833
  const idStr = `HOTFIX-${String(nextId).padStart(3, "0")}`;
@@ -11625,7 +11842,7 @@ function hotfixNewHandler(opts, cli) {
11625
11842
  const content = templateContent.replace(/\{ID\}/g, idStr).replace(/\{SLUG\}/g, opts.slug).replace(/\{ISO\}/g, now);
11626
11843
  const fileSlug = opts.slug.replace(/-/g, "_");
11627
11844
  const fileName = `${idStr}_${fileSlug}.md`;
11628
- const outPath = path56.join(pendingDir, fileName);
11845
+ const outPath = path57.join(pendingDir, fileName);
11629
11846
  try {
11630
11847
  fs45.mkdirSync(pendingDir, { recursive: true });
11631
11848
  fs45.writeFileSync(outPath, content, "utf8");