lee-spec-kit 0.7.2 → 0.7.3

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 (27) hide show
  1. package/dist/index.js +450 -332
  2. package/dist/index.js.map +1 -1
  3. package/package.json +1 -1
  4. package/templates/en/common/README.md +7 -0
  5. package/templates/en/common/agents/agents.md +5 -3
  6. package/templates/en/common/agents/issue-template.md +1 -5
  7. package/templates/en/common/agents/pr-template.md +2 -11
  8. package/templates/en/common/agents/skills/create-feature.md +3 -0
  9. package/templates/en/common/agents/skills/create-issue.md +4 -7
  10. package/templates/en/common/agents/skills/create-pr.md +4 -8
  11. package/templates/en/common/agents/skills/execute-task.md +3 -0
  12. package/templates/en/common/features/README.md +19 -0
  13. package/templates/en/common/features/feature-base/decisions.md +1 -0
  14. package/templates/en/common/features/feature-base/plan.md +1 -0
  15. package/templates/en/common/features/feature-base/tasks.md +1 -0
  16. package/templates/ko/common/README.md +7 -0
  17. package/templates/ko/common/agents/agents.md +5 -3
  18. package/templates/ko/common/agents/issue-template.md +1 -5
  19. package/templates/ko/common/agents/pr-template.md +2 -11
  20. package/templates/ko/common/agents/skills/create-feature.md +3 -0
  21. package/templates/ko/common/agents/skills/create-issue.md +4 -7
  22. package/templates/ko/common/agents/skills/create-pr.md +4 -8
  23. package/templates/ko/common/agents/skills/execute-task.md +4 -0
  24. package/templates/ko/common/features/README.md +19 -0
  25. package/templates/ko/common/features/feature-base/decisions.md +1 -0
  26. package/templates/ko/common/features/feature-base/plan.md +1 -0
  27. package/templates/ko/common/features/feature-base/tasks.md +1 -0
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import path13 from 'path';
2
+ import path14 from 'path';
3
3
  import { fileURLToPath } from 'url';
4
4
  import { program } from 'commander';
5
5
  import fs from 'fs-extra';
@@ -8,11 +8,11 @@ import chalk9 from 'chalk';
8
8
  import { spawn, spawnSync, execFileSync, execSync } from 'child_process';
9
9
  import os from 'os';
10
10
  import { createHash, randomUUID } from 'crypto';
11
- import fs10 from 'fs';
11
+ import fs11 from 'fs';
12
12
  import { Buffer as Buffer$1 } from 'buffer';
13
13
 
14
14
  var getFilename = () => fileURLToPath(import.meta.url);
15
- var getDirname = () => path13.dirname(getFilename());
15
+ var getDirname = () => path14.dirname(getFilename());
16
16
  var __dirname$1 = /* @__PURE__ */ getDirname();
17
17
  async function walkFiles(fsAdapter, rootDir, options = {}) {
18
18
  const out = [];
@@ -25,7 +25,7 @@ async function walkFiles(fsAdapter, rootDir, options = {}) {
25
25
  async function visit(current) {
26
26
  const entries = await fsAdapter.readdir(current);
27
27
  for (const entryName of entries) {
28
- const absolute = path13.join(current, entryName);
28
+ const absolute = path14.join(current, entryName);
29
29
  const stat = await fsAdapter.stat(absolute);
30
30
  if (stat.isDirectory()) {
31
31
  if (ignored.has(entryName.trim().toLowerCase())) continue;
@@ -34,7 +34,7 @@ async function walkFiles(fsAdapter, rootDir, options = {}) {
34
34
  }
35
35
  if (!stat.isFile()) continue;
36
36
  if (normalizedExtensions.size > 0) {
37
- const ext = path13.extname(entryName).toLowerCase();
37
+ const ext = path14.extname(entryName).toLowerCase();
38
38
  if (!normalizedExtensions.has(ext)) continue;
39
39
  }
40
40
  out.push(absolute);
@@ -50,7 +50,7 @@ async function listSubdirectories(fsAdapter, rootDir) {
50
50
  const entries = await fsAdapter.readdir(rootDir);
51
51
  const dirs = [];
52
52
  for (const entryName of entries) {
53
- const absolute = path13.join(rootDir, entryName);
53
+ const absolute = path14.join(rootDir, entryName);
54
54
  const stat = await fsAdapter.stat(absolute);
55
55
  if (stat.isDirectory()) {
56
56
  dirs.push(absolute);
@@ -151,10 +151,10 @@ var DefaultFileSystemAdapter = class {
151
151
  }
152
152
  };
153
153
  var __filename2 = fileURLToPath(import.meta.url);
154
- var __dirname2 = path13.dirname(__filename2);
154
+ var __dirname2 = path14.dirname(__filename2);
155
155
  function getTemplatesDir() {
156
- const rootDir = path13.resolve(__dirname2, "..");
157
- return path13.join(rootDir, "templates");
156
+ const rootDir = path14.resolve(__dirname2, "..");
157
+ return path14.join(rootDir, "templates");
158
158
  }
159
159
 
160
160
  // src/utils/locales/ko/cli.ts
@@ -1741,10 +1741,10 @@ var DEFAULT_STALE_MS = 2 * 6e4;
1741
1741
  var RUNTIME_GIT_DIRNAME = "lee-spec-kit.runtime";
1742
1742
  var RUNTIME_TEMP_DIRNAME = "lee-spec-kit-runtime";
1743
1743
  function toScopeKey(value) {
1744
- return createHash("sha1").update(path13.resolve(value)).digest("hex").slice(0, 16);
1744
+ return createHash("sha1").update(path14.resolve(value)).digest("hex").slice(0, 16);
1745
1745
  }
1746
1746
  function getTempRuntimeDir(scopePath) {
1747
- return path13.join(os.tmpdir(), RUNTIME_TEMP_DIRNAME, toScopeKey(scopePath));
1747
+ return path14.join(os.tmpdir(), RUNTIME_TEMP_DIRNAME, toScopeKey(scopePath));
1748
1748
  }
1749
1749
  function resolveGitRuntimeDir(cwd) {
1750
1750
  try {
@@ -1758,38 +1758,38 @@ function resolveGitRuntimeDir(cwd) {
1758
1758
  }
1759
1759
  ).trim();
1760
1760
  if (!out) return null;
1761
- return path13.isAbsolute(out) ? out : path13.resolve(cwd, out);
1761
+ return path14.isAbsolute(out) ? out : path14.resolve(cwd, out);
1762
1762
  } catch {
1763
1763
  return null;
1764
1764
  }
1765
1765
  }
1766
1766
  function getRuntimeStateDir(cwd) {
1767
- const resolved = path13.resolve(cwd);
1767
+ const resolved = path14.resolve(cwd);
1768
1768
  return resolveGitRuntimeDir(resolved) ?? getTempRuntimeDir(resolved);
1769
1769
  }
1770
1770
  function getDocsLockPath(docsDir) {
1771
- return path13.join(
1771
+ return path14.join(
1772
1772
  getRuntimeStateDir(docsDir),
1773
1773
  "locks",
1774
1774
  `docs-${toScopeKey(docsDir)}.lock`
1775
1775
  );
1776
1776
  }
1777
1777
  function getInitLockPath(targetDir) {
1778
- return path13.join(
1779
- getRuntimeStateDir(path13.dirname(path13.resolve(targetDir))),
1778
+ return path14.join(
1779
+ getRuntimeStateDir(path14.dirname(path14.resolve(targetDir))),
1780
1780
  "locks",
1781
1781
  `init-${toScopeKey(targetDir)}.lock`
1782
1782
  );
1783
1783
  }
1784
1784
  function getApprovalTicketStorePath(docsDir) {
1785
- return path13.join(
1785
+ return path14.join(
1786
1786
  getRuntimeStateDir(docsDir),
1787
1787
  "tickets",
1788
1788
  `approval-${toScopeKey(docsDir)}.json`
1789
1789
  );
1790
1790
  }
1791
1791
  function getProjectExecutionLockPath(cwd) {
1792
- return path13.join(getRuntimeStateDir(cwd), "locks", "project.lock");
1792
+ return path14.join(getRuntimeStateDir(cwd), "locks", "project.lock");
1793
1793
  }
1794
1794
  async function isStaleLock(lockPath, staleMs) {
1795
1795
  try {
@@ -1830,7 +1830,7 @@ function isProcessAlive(pid) {
1830
1830
  }
1831
1831
  }
1832
1832
  async function tryAcquire(lockPath, owner) {
1833
- await fs.ensureDir(path13.dirname(lockPath));
1833
+ await fs.ensureDir(path14.dirname(lockPath));
1834
1834
  try {
1835
1835
  const fd = await fs.open(lockPath, "wx");
1836
1836
  const payload = JSON.stringify(
@@ -1907,30 +1907,30 @@ var ENGINE_MANAGED_AGENT_FILES = [
1907
1907
  "pr-template.md"
1908
1908
  ];
1909
1909
  var ENGINE_MANAGED_AGENT_DIRS = ["skills"];
1910
- var ENGINE_MANAGED_FEATURE_PATH = path13.join(
1910
+ var ENGINE_MANAGED_FEATURE_PATH = path14.join(
1911
1911
  "features",
1912
1912
  "feature-base"
1913
1913
  );
1914
1914
  async function pruneEngineManagedDocs(docsDir) {
1915
1915
  const removed = [];
1916
1916
  for (const file of ENGINE_MANAGED_AGENT_FILES) {
1917
- const target = path13.join(docsDir, "agents", file);
1917
+ const target = path14.join(docsDir, "agents", file);
1918
1918
  if (await fs.pathExists(target)) {
1919
1919
  await fs.remove(target);
1920
- removed.push(path13.relative(docsDir, target));
1920
+ removed.push(path14.relative(docsDir, target));
1921
1921
  }
1922
1922
  }
1923
1923
  for (const dir of ENGINE_MANAGED_AGENT_DIRS) {
1924
- const target = path13.join(docsDir, "agents", dir);
1924
+ const target = path14.join(docsDir, "agents", dir);
1925
1925
  if (await fs.pathExists(target)) {
1926
1926
  await fs.remove(target);
1927
- removed.push(path13.relative(docsDir, target));
1927
+ removed.push(path14.relative(docsDir, target));
1928
1928
  }
1929
1929
  }
1930
- const featureBasePath = path13.join(docsDir, ENGINE_MANAGED_FEATURE_PATH);
1930
+ const featureBasePath = path14.join(docsDir, ENGINE_MANAGED_FEATURE_PATH);
1931
1931
  if (await fs.pathExists(featureBasePath)) {
1932
1932
  await fs.remove(featureBasePath);
1933
- removed.push(path13.relative(docsDir, featureBasePath));
1933
+ removed.push(path14.relative(docsDir, featureBasePath));
1934
1934
  }
1935
1935
  return removed;
1936
1936
  }
@@ -2011,7 +2011,7 @@ Auto-run continuity (main/sub-agent orchestration):
2011
2011
  3. Else run \`npx lee-spec-kit context --json-compact\` (fallback: \`--json\`) and continue from current \`actionOptions\`/\`autoRun\`.
2012
2012
  - Pause and report to user only when:
2013
2013
  - \`approvalRequest.required === true\`, or
2014
- - \`autoRun.reasonCode\` is \`AUTO_GATE_REACHED\` or \`AUTO_MANUAL_REQUIRED\`, or
2014
+ - \`autoRun.reasonCode\` is \`AUTO_GATE_REACHED\`, \`AUTO_DELEGATED_HANDOFF\`, or \`AUTO_MANUAL_REQUIRED\`, or
2015
2015
  - command execution fails (non-zero/error), or
2016
2016
  - user explicitly asks to pause.
2017
2017
 
@@ -2229,7 +2229,7 @@ ${tr(lang2, "cli", "common.canceled")}`));
2229
2229
  }
2230
2230
  async function runInit(options) {
2231
2231
  const cwd = process.cwd();
2232
- const defaultName = path13.basename(cwd);
2232
+ const defaultName = path14.basename(cwd);
2233
2233
  let projectName = options.name || defaultName;
2234
2234
  let projectType = options.type;
2235
2235
  let components = parseComponentsOption(options.components);
@@ -2240,7 +2240,7 @@ async function runInit(options) {
2240
2240
  let docsRemote = options.docsRemote;
2241
2241
  let projectRoot;
2242
2242
  const componentProjectRoots = options.componentProjectRoots ? parseComponentProjectRootsOption(options.componentProjectRoots) : {};
2243
- const targetDir = path13.resolve(cwd, options.dir || "./docs");
2243
+ const targetDir = path14.resolve(cwd, options.dir || "./docs");
2244
2244
  const skipPrompts = !!options.yes || !!options.nonInteractive;
2245
2245
  if (options.docsRepo && !["embedded", "standalone"].includes(options.docsRepo)) {
2246
2246
  throw createCliError(
@@ -2637,7 +2637,7 @@ async function runInit(options) {
2637
2637
  );
2638
2638
  console.log();
2639
2639
  const templatesDir = getTemplatesDir();
2640
- const commonPath = path13.join(templatesDir, lang, "common");
2640
+ const commonPath = path14.join(templatesDir, lang, "common");
2641
2641
  if (!await fs.pathExists(commonPath)) {
2642
2642
  throw new Error(
2643
2643
  tr(lang, "cli", "init.error.templateNotFound", { path: commonPath })
@@ -2646,11 +2646,11 @@ async function runInit(options) {
2646
2646
  const fsAdapter = new DefaultFileSystemAdapter();
2647
2647
  await copyTemplates(fsAdapter, commonPath, targetDir);
2648
2648
  if (projectType === "multi") {
2649
- const featuresRoot = path13.join(targetDir, "features");
2649
+ const featuresRoot = path14.join(targetDir, "features");
2650
2650
  for (const component of components) {
2651
- const componentDir = path13.join(featuresRoot, component);
2651
+ const componentDir = path14.join(featuresRoot, component);
2652
2652
  await fs.ensureDir(componentDir);
2653
- const readmePath = path13.join(componentDir, "README.md");
2653
+ const readmePath = path14.join(componentDir, "README.md");
2654
2654
  if (!await fs.pathExists(readmePath)) {
2655
2655
  await fs.writeFile(
2656
2656
  readmePath,
@@ -2711,20 +2711,20 @@ async function runInit(options) {
2711
2711
  config.projectRoot = projectRoot;
2712
2712
  }
2713
2713
  }
2714
- const configPath = path13.join(targetDir, ".lee-spec-kit.json");
2714
+ const configPath = path14.join(targetDir, ".lee-spec-kit.json");
2715
2715
  await fs.writeJson(configPath, config, { spaces: 2 });
2716
2716
  const extraCommitPathsAbs = [];
2717
2717
  try {
2718
2718
  if (docsRepo === "embedded") {
2719
2719
  const repoRoot = getGitTopLevelOrNull(cwd) || cwd;
2720
- const agentsMdPath = path13.join(repoRoot, "AGENTS.md");
2720
+ const agentsMdPath = path14.join(repoRoot, "AGENTS.md");
2721
2721
  const result = await upsertLeeSpecKitAgentsMd(agentsMdPath, {
2722
2722
  lang,
2723
2723
  docsRepo
2724
2724
  });
2725
2725
  if (result.changed) extraCommitPathsAbs.push(agentsMdPath);
2726
2726
  } else {
2727
- await upsertLeeSpecKitAgentsMd(path13.join(targetDir, "AGENTS.md"), {
2727
+ await upsertLeeSpecKitAgentsMd(path14.join(targetDir, "AGENTS.md"), {
2728
2728
  lang,
2729
2729
  docsRepo
2730
2730
  });
@@ -2734,16 +2734,16 @@ async function runInit(options) {
2734
2734
  } else if (projectRoot && typeof projectRoot === "object") {
2735
2735
  roots.push(...Object.values(projectRoot));
2736
2736
  }
2737
- const resolvedCwd = path13.resolve(cwd);
2737
+ const resolvedCwd = path14.resolve(cwd);
2738
2738
  for (const raw of roots) {
2739
2739
  const value = String(raw || "").trim();
2740
2740
  if (!value) continue;
2741
- const abs = path13.resolve(cwd, value);
2742
- if (abs === resolvedCwd || abs.startsWith(`${resolvedCwd}${path13.sep}`)) {
2741
+ const abs = path14.resolve(cwd, value);
2742
+ if (abs === resolvedCwd || abs.startsWith(`${resolvedCwd}${path14.sep}`)) {
2743
2743
  if (await fs.pathExists(abs)) {
2744
2744
  const stat = await fs.stat(abs);
2745
2745
  if (stat.isDirectory()) {
2746
- await upsertLeeSpecKitAgentsMd(path13.join(abs, "AGENTS.md"), {
2746
+ await upsertLeeSpecKitAgentsMd(path14.join(abs, "AGENTS.md"), {
2747
2747
  lang,
2748
2748
  docsRepo
2749
2749
  });
@@ -2833,7 +2833,7 @@ async function initGit(cwd, targetDir, docsRepo, lang, pushDocs, docsRemote, ext
2833
2833
  console.log(chalk9.blue(tr(lang, "cli", "init.log.gitInit")));
2834
2834
  runGitOrThrow(["init"], gitWorkdir);
2835
2835
  }
2836
- const relativePath = docsRepo === "standalone" ? "." : path13.relative(gitWorkdir, targetDir);
2836
+ const relativePath = docsRepo === "standalone" ? "." : path14.relative(gitWorkdir, targetDir);
2837
2837
  const stagedBeforeAdd = getCachedStagedFiles(gitWorkdir);
2838
2838
  if (relativePath === "." && stagedBeforeAdd && stagedBeforeAdd.length > 0) {
2839
2839
  console.log(chalk9.yellow(tr(lang, "cli", "init.warn.stagedChangesSkip")));
@@ -2860,7 +2860,7 @@ async function initGit(cwd, targetDir, docsRepo, lang, pushDocs, docsRemote, ext
2860
2860
  console.log();
2861
2861
  return;
2862
2862
  }
2863
- const extraRelativePaths = extraCommitPathsAbs.map((absPath) => path13.relative(gitWorkdir, absPath)).map((p) => p.replace(/\\/g, "/").trim()).filter((p) => !!p && p !== "." && !p.startsWith("../"));
2863
+ const extraRelativePaths = extraCommitPathsAbs.map((absPath) => path14.relative(gitWorkdir, absPath)).map((p) => p.replace(/\\/g, "/").trim()).filter((p) => !!p && p !== "." && !p.startsWith("../"));
2864
2864
  const pathsToStage = [relativePath, ...extraRelativePaths];
2865
2865
  for (const p of pathsToStage) {
2866
2866
  runGitOrThrow(["add", p], gitWorkdir);
@@ -2896,17 +2896,17 @@ async function initGit(cwd, targetDir, docsRepo, lang, pushDocs, docsRemote, ext
2896
2896
  }
2897
2897
  function getAncestorDirs(startDir) {
2898
2898
  const dirs = [];
2899
- let current = path13.resolve(startDir);
2899
+ let current = path14.resolve(startDir);
2900
2900
  while (true) {
2901
2901
  dirs.push(current);
2902
- const parent = path13.dirname(current);
2902
+ const parent = path14.dirname(current);
2903
2903
  if (parent === current) break;
2904
2904
  current = parent;
2905
2905
  }
2906
2906
  return dirs;
2907
2907
  }
2908
2908
  function hasWorkspaceBoundary(dir) {
2909
- return fs.existsSync(path13.join(dir, "package.json")) || fs.existsSync(path13.join(dir, ".git"));
2909
+ return fs.existsSync(path14.join(dir, "package.json")) || fs.existsSync(path14.join(dir, ".git"));
2910
2910
  }
2911
2911
  function getSearchBaseDirs(cwd) {
2912
2912
  const ancestors = getAncestorDirs(cwd);
@@ -2922,7 +2922,7 @@ function normalizeComponentKeys(value) {
2922
2922
  return Object.keys(value).map((key) => key.trim().toLowerCase()).filter(Boolean);
2923
2923
  }
2924
2924
  async function inferComponentsFromFeaturesDir(docsDir) {
2925
- const featuresPath = path13.join(docsDir, "features");
2925
+ const featuresPath = path14.join(docsDir, "features");
2926
2926
  if (!await fs.pathExists(featuresPath)) return [];
2927
2927
  const entries = await fs.readdir(featuresPath, { withFileTypes: true });
2928
2928
  const inferred = entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name.trim().toLowerCase()).filter(
@@ -2933,21 +2933,21 @@ async function inferComponentsFromFeaturesDir(docsDir) {
2933
2933
  async function getConfig(cwd) {
2934
2934
  const explicitDocsDir = (process.env.LEE_SPEC_KIT_DOCS_DIR || "").trim();
2935
2935
  const baseDirs = [
2936
- ...explicitDocsDir ? [path13.resolve(explicitDocsDir)] : [],
2936
+ ...explicitDocsDir ? [path14.resolve(explicitDocsDir)] : [],
2937
2937
  ...getSearchBaseDirs(cwd)
2938
2938
  ];
2939
2939
  const visitedBaseDirs = /* @__PURE__ */ new Set();
2940
2940
  const visitedDocsDirs = /* @__PURE__ */ new Set();
2941
2941
  for (const baseDir of baseDirs) {
2942
- const resolvedBaseDir = path13.resolve(baseDir);
2942
+ const resolvedBaseDir = path14.resolve(baseDir);
2943
2943
  if (visitedBaseDirs.has(resolvedBaseDir)) continue;
2944
2944
  visitedBaseDirs.add(resolvedBaseDir);
2945
- const possibleDocsDirs = [path13.join(resolvedBaseDir, "docs"), resolvedBaseDir];
2945
+ const possibleDocsDirs = [path14.join(resolvedBaseDir, "docs"), resolvedBaseDir];
2946
2946
  for (const docsDir of possibleDocsDirs) {
2947
- const resolvedDocsDir = path13.resolve(docsDir);
2947
+ const resolvedDocsDir = path14.resolve(docsDir);
2948
2948
  if (visitedDocsDirs.has(resolvedDocsDir)) continue;
2949
2949
  visitedDocsDirs.add(resolvedDocsDir);
2950
- const configPath = path13.join(resolvedDocsDir, ".lee-spec-kit.json");
2950
+ const configPath = path14.join(resolvedDocsDir, ".lee-spec-kit.json");
2951
2951
  if (await fs.pathExists(configPath)) {
2952
2952
  try {
2953
2953
  const configFile = await fs.readJson(configPath);
@@ -2977,16 +2977,16 @@ async function getConfig(cwd) {
2977
2977
  } catch {
2978
2978
  }
2979
2979
  }
2980
- const agentsPath = path13.join(resolvedDocsDir, "agents");
2981
- const featuresPath = path13.join(resolvedDocsDir, "features");
2980
+ const agentsPath = path14.join(resolvedDocsDir, "agents");
2981
+ const featuresPath = path14.join(resolvedDocsDir, "features");
2982
2982
  if (await fs.pathExists(agentsPath) && await fs.pathExists(featuresPath)) {
2983
2983
  const inferredComponents = await inferComponentsFromFeaturesDir(resolvedDocsDir);
2984
2984
  const projectType = inferredComponents.length > 0 ? "multi" : "single";
2985
2985
  const components = projectType === "multi" ? resolveProjectComponents("multi", inferredComponents) : void 0;
2986
2986
  const langProbeCandidates = [
2987
- path13.join(agentsPath, "custom.md"),
2988
- path13.join(agentsPath, "constitution.md"),
2989
- path13.join(agentsPath, "agents.md")
2987
+ path14.join(agentsPath, "custom.md"),
2988
+ path14.join(agentsPath, "constitution.md"),
2989
+ path14.join(agentsPath, "agents.md")
2990
2990
  ];
2991
2991
  let lang = "en";
2992
2992
  for (const candidate of langProbeCandidates) {
@@ -3057,13 +3057,85 @@ async function patchMarkdownIfExists(filePath, transform) {
3057
3057
  await fs.writeFile(filePath, transform(content), "utf-8");
3058
3058
  }
3059
3059
  async function applyLocalWorkflowTemplateToFeatureDir(featureDir, lang) {
3060
- await patchMarkdownIfExists(path13.join(featureDir, "spec.md"), sanitizeSpecForLocal);
3060
+ await patchMarkdownIfExists(path14.join(featureDir, "spec.md"), sanitizeSpecForLocal);
3061
3061
  await patchMarkdownIfExists(
3062
- path13.join(featureDir, "tasks.md"),
3062
+ path14.join(featureDir, "tasks.md"),
3063
3063
  (content) => sanitizeTasksForLocal(content, lang)
3064
3064
  );
3065
- await fs.remove(path13.join(featureDir, "issue.md"));
3066
- await fs.remove(path13.join(featureDir, "pr.md"));
3065
+ await fs.remove(path14.join(featureDir, "issue.md"));
3066
+ await fs.remove(path14.join(featureDir, "pr.md"));
3067
+ }
3068
+ var IDEA_REF_PATTERN = /\b(I\d{3,}(?:-[A-Za-z0-9._-]+)?)\b/;
3069
+ var IDEA_PATH_PATTERN = /\b(?:\.\/)?docs\/ideas\/[^\s]+\.md\b/;
3070
+ function extractExplicitIdeaRef(requestText) {
3071
+ const pathMatch = requestText.match(IDEA_PATH_PATTERN);
3072
+ if (pathMatch) return pathMatch[0];
3073
+ const refMatch = requestText.match(IDEA_REF_PATTERN);
3074
+ if (refMatch) return refMatch[1];
3075
+ return null;
3076
+ }
3077
+ async function resolveIdeaReference(docsDir, ref, lang) {
3078
+ const ideasDir = path14.join(docsDir, "ideas");
3079
+ const trimmedRef = ref.trim();
3080
+ if (!trimmedRef) {
3081
+ throw createCliError(
3082
+ "INVALID_ARGUMENT",
3083
+ tr(lang, "cli", "feature.ideaNotFound", { ref })
3084
+ );
3085
+ }
3086
+ if (trimmedRef.includes("/") || trimmedRef.endsWith(".md")) {
3087
+ const candidate = path14.resolve(process.cwd(), trimmedRef);
3088
+ if (await fs.pathExists(candidate)) {
3089
+ return { path: candidate };
3090
+ }
3091
+ throw createCliError(
3092
+ "INVALID_ARGUMENT",
3093
+ tr(lang, "cli", "feature.ideaNotFound", { ref: trimmedRef })
3094
+ );
3095
+ }
3096
+ if (!await fs.pathExists(ideasDir)) {
3097
+ throw createCliError(
3098
+ "INVALID_ARGUMENT",
3099
+ tr(lang, "cli", "feature.ideaNotFound", { ref: trimmedRef })
3100
+ );
3101
+ }
3102
+ const entries = await fs.readdir(ideasDir, { withFileTypes: true });
3103
+ const files = entries.filter((entry) => entry.isFile() && entry.name.toLowerCase().endsWith(".md")).map((entry) => entry.name);
3104
+ const exactName = `${trimmedRef}.md`;
3105
+ if (files.includes(exactName)) {
3106
+ return { path: path14.join(ideasDir, exactName) };
3107
+ }
3108
+ const byId = /^I\d{3,}$/.test(trimmedRef) ? files.filter((name) => name.startsWith(`${trimmedRef}-`)) : [];
3109
+ if (byId.length === 1) {
3110
+ return { path: path14.join(ideasDir, byId[0]) };
3111
+ }
3112
+ if (byId.length > 1) {
3113
+ throw createCliError(
3114
+ "INVALID_ARGUMENT",
3115
+ tr(lang, "cli", "feature.ideaAmbiguous", { ref: trimmedRef })
3116
+ );
3117
+ }
3118
+ throw createCliError(
3119
+ "INVALID_ARGUMENT",
3120
+ tr(lang, "cli", "feature.ideaNotFound", { ref: trimmedRef })
3121
+ );
3122
+ }
3123
+ async function readIdeaMetadataValue(ideaPath, label) {
3124
+ const content = await fs.readFile(ideaPath, "utf-8");
3125
+ const pattern = new RegExp(`^- \\*\\*${escapeRegExp(label)}\\*\\*:\\s*(.+)$`, "m");
3126
+ const match = content.match(pattern);
3127
+ if (!match) return null;
3128
+ const value = match[1].trim();
3129
+ return value.length > 0 ? value : null;
3130
+ }
3131
+ async function deriveFeatureNameFromIdea(ideaPath) {
3132
+ const ideaName = await readIdeaMetadataValue(ideaPath, "Idea Name");
3133
+ if (ideaName && ideaName !== "-") return ideaName;
3134
+ const basename = path14.basename(ideaPath, ".md");
3135
+ return basename.replace(/^I\d{3,}-/, "");
3136
+ }
3137
+ function escapeRegExp(value) {
3138
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
3067
3139
  }
3068
3140
 
3069
3141
  // src/commands/feature.ts
@@ -3215,19 +3287,19 @@ async function runFeature(name, options) {
3215
3287
  }
3216
3288
  let featuresDir;
3217
3289
  if (projectType === "multi") {
3218
- featuresDir = path13.join(docsDir, "features", component);
3290
+ featuresDir = path14.join(docsDir, "features", component);
3219
3291
  } else {
3220
- featuresDir = path13.join(docsDir, "features");
3292
+ featuresDir = path14.join(docsDir, "features");
3221
3293
  }
3222
3294
  const featureFolderName = `${featureId}-${name}`;
3223
- const featureDir = path13.join(featuresDir, featureFolderName);
3295
+ const featureDir = path14.join(featuresDir, featureFolderName);
3224
3296
  if (await fs.pathExists(featureDir)) {
3225
3297
  throw createCliError(
3226
3298
  "INVALID_ARGUMENT",
3227
3299
  tr(lang, "cli", "feature.folderExists", { path: featureDir })
3228
3300
  );
3229
3301
  }
3230
- const featureBasePath = path13.join(
3302
+ const featureBasePath = path14.join(
3231
3303
  getTemplatesDir(),
3232
3304
  lang,
3233
3305
  "common",
@@ -3274,8 +3346,8 @@ async function runFeature(name, options) {
3274
3346
  await replaceInFiles(fsAdapter, featureDir, replacements);
3275
3347
  if (linkedIdea) {
3276
3348
  await stampIdeaReferenceInSpec(
3277
- path13.join(featureDir, "spec.md"),
3278
- path13.relative(featureDir, linkedIdea.path)
3349
+ path14.join(featureDir, "spec.md"),
3350
+ path14.relative(featureDir, linkedIdea.path)
3279
3351
  );
3280
3352
  await markIdeaAsFeatureized(linkedIdea.path, featureFolderName);
3281
3353
  }
@@ -3303,58 +3375,12 @@ async function runFeature(name, options) {
3303
3375
  featureName: name,
3304
3376
  component: projectType === "multi" ? component : void 0,
3305
3377
  featurePath: featureDir,
3306
- featurePathFromDocs: path13.relative(docsDir, featureDir)
3378
+ featurePathFromDocs: path14.relative(docsDir, featureDir)
3307
3379
  };
3308
3380
  },
3309
3381
  { owner: "feature" }
3310
3382
  );
3311
3383
  }
3312
- async function resolveIdeaReference(docsDir, ref, lang) {
3313
- const ideasDir = path13.join(docsDir, "ideas");
3314
- const trimmedRef = ref.trim();
3315
- if (!trimmedRef) {
3316
- throw createCliError(
3317
- "INVALID_ARGUMENT",
3318
- tr(lang, "cli", "feature.ideaNotFound", { ref })
3319
- );
3320
- }
3321
- if (trimmedRef.includes("/") || trimmedRef.endsWith(".md")) {
3322
- const candidate = path13.resolve(process.cwd(), trimmedRef);
3323
- if (await fs.pathExists(candidate)) {
3324
- return { path: candidate };
3325
- }
3326
- throw createCliError(
3327
- "INVALID_ARGUMENT",
3328
- tr(lang, "cli", "feature.ideaNotFound", { ref: trimmedRef })
3329
- );
3330
- }
3331
- if (!await fs.pathExists(ideasDir)) {
3332
- throw createCliError(
3333
- "INVALID_ARGUMENT",
3334
- tr(lang, "cli", "feature.ideaNotFound", { ref: trimmedRef })
3335
- );
3336
- }
3337
- const entries = await fs.readdir(ideasDir, { withFileTypes: true });
3338
- const files = entries.filter((entry) => entry.isFile() && entry.name.toLowerCase().endsWith(".md")).map((entry) => entry.name);
3339
- const exactName = `${trimmedRef}.md`;
3340
- if (files.includes(exactName)) {
3341
- return { path: path13.join(ideasDir, exactName) };
3342
- }
3343
- const byId = /^I\d{3,}$/.test(trimmedRef) ? files.filter((name) => name.startsWith(`${trimmedRef}-`)) : [];
3344
- if (byId.length === 1) {
3345
- return { path: path13.join(ideasDir, byId[0]) };
3346
- }
3347
- if (byId.length > 1) {
3348
- throw createCliError(
3349
- "INVALID_ARGUMENT",
3350
- tr(lang, "cli", "feature.ideaAmbiguous", { ref: trimmedRef })
3351
- );
3352
- }
3353
- throw createCliError(
3354
- "INVALID_ARGUMENT",
3355
- tr(lang, "cli", "feature.ideaNotFound", { ref: trimmedRef })
3356
- );
3357
- }
3358
3384
  async function stampIdeaReferenceInSpec(specPath, relativeIdeaPath) {
3359
3385
  const normalizedPath = relativeIdeaPath.replace(/\\/g, "/");
3360
3386
  const ideaLine = `- Idea: \`${normalizedPath}\``;
@@ -3385,7 +3411,7 @@ async function markIdeaAsFeatureized(ideaPath, featureFolderName) {
3385
3411
  await fs.writeFile(ideaPath, content, "utf-8");
3386
3412
  }
3387
3413
  function replaceOrAppendIdeaMetadata(content, label, value) {
3388
- const pattern = new RegExp(`^- \\*\\*${escapeRegExp(label)}\\*\\*:.*$`, "m");
3414
+ const pattern = new RegExp(`^- \\*\\*${escapeRegExp2(label)}\\*\\*:.*$`, "m");
3389
3415
  const line = `- **${label}**: ${value}`;
3390
3416
  if (pattern.test(content)) {
3391
3417
  return content.replace(pattern, line);
@@ -3403,15 +3429,15 @@ ${heading}
3403
3429
  ${line}
3404
3430
  `;
3405
3431
  }
3406
- function escapeRegExp(value) {
3432
+ function escapeRegExp2(value) {
3407
3433
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
3408
3434
  }
3409
3435
  async function waitForConfigAfterInit(cwd, timeoutMs = 8e3) {
3410
3436
  const explicitDocsDir = (process.env.LEE_SPEC_KIT_DOCS_DIR || "").trim();
3411
3437
  const candidates = [
3412
- ...explicitDocsDir ? [path13.resolve(explicitDocsDir)] : [],
3413
- path13.resolve(cwd, "docs"),
3414
- path13.resolve(cwd)
3438
+ ...explicitDocsDir ? [path14.resolve(explicitDocsDir)] : [],
3439
+ path14.resolve(cwd, "docs"),
3440
+ path14.resolve(cwd)
3415
3441
  ];
3416
3442
  const endAt = Date.now() + timeoutMs;
3417
3443
  while (Date.now() < endAt) {
@@ -3438,12 +3464,12 @@ async function waitForConfigAfterInit(cwd, timeoutMs = 8e3) {
3438
3464
  return getConfig(cwd);
3439
3465
  }
3440
3466
  async function getNextFeatureId(docsDir, projectType, components) {
3441
- const featuresDir = path13.join(docsDir, "features");
3467
+ const featuresDir = path14.join(docsDir, "features");
3442
3468
  let max = 0;
3443
3469
  const scanDirs = [];
3444
3470
  if (projectType === "multi") {
3445
3471
  scanDirs.push(
3446
- ...components.map((component) => path13.join(featuresDir, component))
3472
+ ...components.map((component) => path14.join(featuresDir, component))
3447
3473
  );
3448
3474
  } else {
3449
3475
  scanDirs.push(featuresDir);
@@ -3544,16 +3570,16 @@ async function runIdea(name, options) {
3544
3570
  getDocsLockPath(docsDir),
3545
3571
  async () => {
3546
3572
  const ideaId = options.id ? validateProvidedIdeaId(options.id, lang) : await getNextIdeaId(docsDir);
3547
- const ideasDir = path13.join(docsDir, "ideas");
3573
+ const ideasDir = path14.join(docsDir, "ideas");
3548
3574
  const ideaFileName = `${ideaId}-${name}.md`;
3549
- const ideaPath = path13.join(ideasDir, ideaFileName);
3575
+ const ideaPath = path14.join(ideasDir, ideaFileName);
3550
3576
  if (await fs.pathExists(ideaPath)) {
3551
3577
  throw createCliError(
3552
3578
  "INVALID_ARGUMENT",
3553
3579
  tr(lang, "cli", "idea.fileExists", { path: ideaPath })
3554
3580
  );
3555
3581
  }
3556
- const templatePath = path13.join(
3582
+ const templatePath = path14.join(
3557
3583
  getTemplatesDir(),
3558
3584
  lang,
3559
3585
  "common",
@@ -3591,7 +3617,7 @@ async function runIdea(name, options) {
3591
3617
  ideaName: name,
3592
3618
  component: component || void 0,
3593
3619
  ideaPath,
3594
- ideaPathFromDocs: path13.relative(docsDir, ideaPath)
3620
+ ideaPathFromDocs: path14.relative(docsDir, ideaPath)
3595
3621
  };
3596
3622
  },
3597
3623
  { owner: "idea" }
@@ -3609,7 +3635,7 @@ function applyIdeaTemplate(template, values) {
3609
3635
  return template.replaceAll("{idea-id}", values.ideaId).replaceAll("{idea-name}", values.name).replaceAll("{YYYY-MM-DD}", values.created).replaceAll("{{description}}", values.description).replaceAll("{component}", values.component);
3610
3636
  }
3611
3637
  async function getNextIdeaId(docsDir) {
3612
- const ideasDir = path13.join(docsDir, "ideas");
3638
+ const ideasDir = path14.join(docsDir, "ideas");
3613
3639
  let max = 0;
3614
3640
  if (await fs.pathExists(ideasDir)) {
3615
3641
  const entries = await fs.readdir(ideasDir, { withFileTypes: true });
@@ -4048,7 +4074,7 @@ function isNonNegativeIntegerValue(value) {
4048
4074
  }
4049
4075
  function isLikelyCurrentPrePrReviewEvidence(evidencePath, feature) {
4050
4076
  try {
4051
- const raw = fs10.readFileSync(evidencePath, "utf-8");
4077
+ const raw = fs11.readFileSync(evidencePath, "utf-8");
4052
4078
  const parsed = JSON.parse(raw);
4053
4079
  const evidenceFeature = (parsed.feature || "").toString().trim();
4054
4080
  if (evidenceFeature && evidenceFeature !== feature.folderName) {
@@ -4064,31 +4090,31 @@ function resolvePrePrReviewEvidencePath(feature) {
4064
4090
  const candidates = [];
4065
4091
  const explicit = (feature.prePrReview.evidence || "").trim();
4066
4092
  if (explicit && explicit !== "-") {
4067
- if (path13.isAbsolute(explicit)) {
4093
+ if (path14.isAbsolute(explicit)) {
4068
4094
  candidates.push(explicit);
4069
4095
  } else {
4070
- candidates.push(path13.resolve(feature.path, explicit));
4071
- candidates.push(path13.resolve(docsRoot, explicit));
4096
+ candidates.push(path14.resolve(feature.path, explicit));
4097
+ candidates.push(path14.resolve(docsRoot, explicit));
4072
4098
  const normalizedExplicit = explicit.replace(/\\/g, "/");
4073
4099
  if (normalizedExplicit.startsWith("docs/")) {
4074
4100
  const withoutDocsPrefix = normalizedExplicit.slice("docs/".length);
4075
4101
  if (withoutDocsPrefix) {
4076
- candidates.push(path13.resolve(docsRoot, withoutDocsPrefix));
4102
+ candidates.push(path14.resolve(docsRoot, withoutDocsPrefix));
4077
4103
  }
4078
4104
  }
4079
4105
  }
4080
4106
  }
4081
- candidates.push(path13.join(feature.path, "review-trace.json"));
4082
- candidates.push(path13.join(docsRoot, "review-trace.json"));
4107
+ candidates.push(path14.join(feature.path, "review-trace.json"));
4108
+ candidates.push(path14.join(docsRoot, "review-trace.json"));
4083
4109
  const seen = /* @__PURE__ */ new Set();
4084
4110
  for (const candidate of candidates) {
4085
- const abs = path13.resolve(candidate);
4111
+ const abs = path14.resolve(candidate);
4086
4112
  if (seen.has(abs)) continue;
4087
4113
  seen.add(abs);
4088
- if (!fs10.existsSync(abs)) continue;
4114
+ if (!fs11.existsSync(abs)) continue;
4089
4115
  if (!abs.toLowerCase().endsWith(".json")) continue;
4090
4116
  if (!isLikelyCurrentPrePrReviewEvidence(abs, feature)) continue;
4091
- const rel = path13.relative(docsRoot, abs).replace(/\\/g, "/");
4117
+ const rel = path14.relative(docsRoot, abs).replace(/\\/g, "/");
4092
4118
  if (rel && !rel.startsWith("../")) {
4093
4119
  return rel;
4094
4120
  }
@@ -4129,8 +4155,8 @@ function getReviewFixCommitGuidance(feature, lang, options) {
4129
4155
  }
4130
4156
  function resolveManagedWorktreeCleanupPaths(projectGitCwd) {
4131
4157
  if (!projectGitCwd) return null;
4132
- const normalized = path13.resolve(projectGitCwd);
4133
- const marker = `${path13.sep}.worktrees${path13.sep}`;
4158
+ const normalized = path14.resolve(projectGitCwd);
4159
+ const marker = `${path14.sep}.worktrees${path14.sep}`;
4134
4160
  const markerIndex = normalized.lastIndexOf(marker);
4135
4161
  if (markerIndex <= 0) return null;
4136
4162
  const projectRoot = normalized.slice(0, markerIndex);
@@ -4173,7 +4199,7 @@ function toTaskKey(rawTitle) {
4173
4199
  function countDoneTransitionsInLatestTasksCommit(ctx, feature) {
4174
4200
  const docsGitCwd = feature.git.docsGitCwd;
4175
4201
  const tasksRelativePath = normalizeGitRelativePath(
4176
- path13.join(feature.docs.featurePathFromDocs, "tasks.md")
4202
+ path14.join(feature.docs.featurePathFromDocs, "tasks.md")
4177
4203
  );
4178
4204
  const diff = readGitText(ctx, docsGitCwd, [
4179
4205
  "diff",
@@ -4248,7 +4274,7 @@ function checkTaskCommitGate(ctx, feature) {
4248
4274
  return { pass: true };
4249
4275
  }
4250
4276
  const args = ["log", "-n", "1", "--pretty=%s", "--", "."];
4251
- const relativeDocsDir = path13.relative(projectGitCwd, feature.git.docsGitCwd);
4277
+ const relativeDocsDir = path14.relative(projectGitCwd, feature.git.docsGitCwd);
4252
4278
  const normalizedDocsDir = normalizeGitRelativePath(relativeDocsDir);
4253
4279
  if (normalizedDocsDir && normalizedDocsDir !== "." && normalizedDocsDir !== ".." && !normalizedDocsDir.startsWith("../")) {
4254
4280
  args.push(`:(exclude)${normalizedDocsDir}/**`);
@@ -5864,17 +5890,17 @@ function isGitPathIgnored(ctx, cwd, relativePath) {
5864
5890
  }
5865
5891
  }
5866
5892
  var GIT_WORKTREE_CACHE = /* @__PURE__ */ new Map();
5867
- var WORKTREE_MARKER = `${path13.sep}.worktrees${path13.sep}`;
5893
+ var WORKTREE_MARKER = `${path14.sep}.worktrees${path14.sep}`;
5868
5894
  function resetContextGitCaches() {
5869
5895
  GIT_WORKTREE_CACHE.clear();
5870
5896
  }
5871
5897
  function isManagedWorktreePath(cwd) {
5872
5898
  if (!cwd) return false;
5873
- const normalized = path13.resolve(cwd);
5899
+ const normalized = path14.resolve(cwd);
5874
5900
  return normalized.includes(WORKTREE_MARKER);
5875
5901
  }
5876
5902
  function resolveProjectRootFromGitCwd(cwd) {
5877
- const normalized = path13.resolve(cwd);
5903
+ const normalized = path14.resolve(cwd);
5878
5904
  const markerIndex = normalized.lastIndexOf(WORKTREE_MARKER);
5879
5905
  if (markerIndex <= 0) return normalized;
5880
5906
  const projectRoot = normalized.slice(0, markerIndex);
@@ -5893,7 +5919,7 @@ function getGitTopLevel(ctx, cwd) {
5893
5919
  }
5894
5920
  function listGitWorktrees(ctx, cwd) {
5895
5921
  const topLevel = getGitTopLevel(ctx, cwd) || cwd;
5896
- const cacheKey = path13.resolve(topLevel);
5922
+ const cacheKey = path14.resolve(topLevel);
5897
5923
  const cached = GIT_WORKTREE_CACHE.get(cacheKey);
5898
5924
  if (cached) return cached;
5899
5925
  try {
@@ -5994,12 +6020,12 @@ function countDocumentLines(content) {
5994
6020
  if (lines[lines.length - 1] === "") return lines.length - 1;
5995
6021
  return lines.length;
5996
6022
  }
5997
- function escapeRegExp2(value) {
6023
+ function escapeRegExp3(value) {
5998
6024
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
5999
6025
  }
6000
6026
  function extractSpecValue(content, key) {
6001
6027
  const regex = new RegExp(
6002
- `^\\s*-\\s*\\*\\*${escapeRegExp2(key)}\\*\\*\\s*:\\s*(.*)$`,
6028
+ `^\\s*-\\s*\\*\\*${escapeRegExp3(key)}\\*\\*\\s*:\\s*(.*)$`,
6003
6029
  "m"
6004
6030
  );
6005
6031
  const match = content.match(regex);
@@ -6007,7 +6033,7 @@ function extractSpecValue(content, key) {
6007
6033
  }
6008
6034
  function hasSpecKey(content, key) {
6009
6035
  const regex = new RegExp(
6010
- `^\\s*-\\s*\\*\\*${escapeRegExp2(key)}\\*\\*\\s*:`,
6036
+ `^\\s*-\\s*\\*\\*${escapeRegExp3(key)}\\*\\*\\s*:`,
6011
6037
  "m"
6012
6038
  );
6013
6039
  return regex.test(content);
@@ -6199,7 +6225,7 @@ function splitReviewLogSections(content, headerRegex) {
6199
6225
  }
6200
6226
  function collectStructuredReviewEntries(section, keys) {
6201
6227
  const lines = section.split("\n");
6202
- const escaped = keys.map((key) => escapeRegExp2(key));
6228
+ const escaped = keys.map((key) => escapeRegExp3(key));
6203
6229
  const fieldRegex = new RegExp(
6204
6230
  `^\\s*-\\s*\\*\\*(?:${escaped.join("|")})\\*\\*\\s*:\\s*(.*)$`,
6205
6231
  "i"
@@ -6381,17 +6407,17 @@ function resolveLocalEvidencePathCandidates(rawValue, context) {
6381
6407
  if (!evidencePath) return [];
6382
6408
  if (/^https?:\/\//i.test(evidencePath)) return [];
6383
6409
  const candidates = /* @__PURE__ */ new Set();
6384
- if (path13.isAbsolute(evidencePath)) {
6385
- candidates.add(path13.resolve(evidencePath));
6410
+ if (path14.isAbsolute(evidencePath)) {
6411
+ candidates.add(path14.resolve(evidencePath));
6386
6412
  } else {
6387
- candidates.add(path13.resolve(context.featurePath, evidencePath));
6388
- candidates.add(path13.resolve(context.docsDir, evidencePath));
6389
- candidates.add(path13.resolve(path13.dirname(context.docsDir), evidencePath));
6413
+ candidates.add(path14.resolve(context.featurePath, evidencePath));
6414
+ candidates.add(path14.resolve(context.docsDir, evidencePath));
6415
+ candidates.add(path14.resolve(path14.dirname(context.docsDir), evidencePath));
6390
6416
  const normalizedEvidencePath = evidencePath.replace(/\\/g, "/");
6391
6417
  if (normalizedEvidencePath.startsWith("docs/")) {
6392
6418
  const withoutDocsPrefix = normalizedEvidencePath.slice("docs/".length);
6393
6419
  if (withoutDocsPrefix) {
6394
- candidates.add(path13.resolve(context.docsDir, withoutDocsPrefix));
6420
+ candidates.add(path14.resolve(context.docsDir, withoutDocsPrefix));
6395
6421
  }
6396
6422
  }
6397
6423
  }
@@ -6453,13 +6479,13 @@ function parsePrLink(value) {
6453
6479
  return trimmed;
6454
6480
  }
6455
6481
  function normalizeGitPath(value) {
6456
- return value.split(path13.sep).join("/");
6482
+ return value.split(path14.sep).join("/");
6457
6483
  }
6458
6484
  function resolveProjectStatusPaths(projectGitCwd, docsDir) {
6459
- const relativeDocsDir = path13.relative(projectGitCwd, docsDir);
6485
+ const relativeDocsDir = path14.relative(projectGitCwd, docsDir);
6460
6486
  if (!relativeDocsDir) return [];
6461
- if (path13.isAbsolute(relativeDocsDir)) return [];
6462
- if (relativeDocsDir === ".." || relativeDocsDir.startsWith(`..${path13.sep}`)) {
6487
+ if (path14.isAbsolute(relativeDocsDir)) return [];
6488
+ if (relativeDocsDir === ".." || relativeDocsDir.startsWith(`..${path14.sep}`)) {
6463
6489
  return [];
6464
6490
  }
6465
6491
  const normalizedDocsDir = normalizeGitPath(relativeDocsDir).replace(
@@ -6497,7 +6523,7 @@ function getExpectedWorktreeCandidates(projectGitCwd, issueNumber, slug, folderN
6497
6523
  const seen = /* @__PURE__ */ new Set();
6498
6524
  const out = [];
6499
6525
  for (const name of names) {
6500
- const candidate = path13.resolve(projectRoot, ".worktrees", name);
6526
+ const candidate = path14.resolve(projectRoot, ".worktrees", name);
6501
6527
  if (seen.has(candidate)) continue;
6502
6528
  seen.add(candidate);
6503
6529
  out.push(candidate);
@@ -6511,7 +6537,7 @@ function resolveExistingExpectedWorktreePath(projectGitCwd, issueNumber, slug, f
6511
6537
  slug,
6512
6538
  folderName
6513
6539
  )) {
6514
- if (!fs10.existsSync(candidate)) continue;
6540
+ if (!fs11.existsSync(candidate)) continue;
6515
6541
  return candidate;
6516
6542
  }
6517
6543
  return void 0;
@@ -6541,7 +6567,7 @@ function resolveFeatureWorktreePath(ctx, projectGitCwd, issueNumber, slug, folde
6541
6567
  slug,
6542
6568
  folderName
6543
6569
  )) {
6544
- if (!fs10.existsSync(candidate)) continue;
6570
+ if (!fs11.existsSync(candidate)) continue;
6545
6571
  const branchName = getCurrentBranch(ctx, candidate);
6546
6572
  if (!expectedBranchesSet.has(branchName)) continue;
6547
6573
  return {
@@ -6682,10 +6708,10 @@ async function resolveComponentStatusPaths(ctx, projectGitCwd, component, workfl
6682
6708
  const normalizedCandidates = uniqueNormalizedPaths(
6683
6709
  candidates.map((candidate) => {
6684
6710
  if (!candidate) return "";
6685
- if (!path13.isAbsolute(candidate)) return candidate;
6686
- const relative = path13.relative(projectGitCwd, candidate);
6711
+ if (!path14.isAbsolute(candidate)) return candidate;
6712
+ const relative = path14.relative(projectGitCwd, candidate);
6687
6713
  if (!relative) return "";
6688
- if (relative === ".." || relative.startsWith(`..${path13.sep}`))
6714
+ if (relative === ".." || relative.startsWith(`..${path14.sep}`))
6689
6715
  return "";
6690
6716
  return relative;
6691
6717
  }).filter(Boolean)
@@ -6699,7 +6725,7 @@ async function resolveComponentStatusPaths(ctx, projectGitCwd, component, workfl
6699
6725
  if (cached) return [...cached];
6700
6726
  const existing = [];
6701
6727
  for (const candidate of normalizedCandidates) {
6702
- if (await ctx.fs.pathExists(path13.join(projectGitCwd, candidate))) {
6728
+ if (await ctx.fs.pathExists(path14.join(projectGitCwd, candidate))) {
6703
6729
  existing.push(candidate);
6704
6730
  }
6705
6731
  }
@@ -6787,16 +6813,16 @@ async function parseFeature(ctx, featurePath, type, context, options) {
6787
6813
  const lang = options.lang;
6788
6814
  const workflowPolicy = resolveWorkflowPolicy(options.workflow);
6789
6815
  const prePrReviewPolicy = resolvePrePrReviewPolicy(options.workflow);
6790
- const folderName = path13.basename(featurePath);
6816
+ const folderName = path14.basename(featurePath);
6791
6817
  const match = folderName.match(/^(F\d+)-(.+)$/);
6792
6818
  const id = match?.[1];
6793
6819
  const slug = match?.[2] || folderName;
6794
- const specPath = path13.join(featurePath, "spec.md");
6795
- const planPath = path13.join(featurePath, "plan.md");
6796
- const tasksPath = path13.join(featurePath, "tasks.md");
6797
- const decisionsPath = path13.join(featurePath, "decisions.md");
6798
- const issueDocPath = path13.join(featurePath, "issue.md");
6799
- const prDocPath = path13.join(featurePath, "pr.md");
6820
+ const specPath = path14.join(featurePath, "spec.md");
6821
+ const planPath = path14.join(featurePath, "plan.md");
6822
+ const tasksPath = path14.join(featurePath, "tasks.md");
6823
+ const decisionsPath = path14.join(featurePath, "decisions.md");
6824
+ const issueDocPath = path14.join(featurePath, "issue.md");
6825
+ const prDocPath = path14.join(featurePath, "pr.md");
6800
6826
  let specStatus;
6801
6827
  let issueNumber;
6802
6828
  const specExists = await ctx.fs.pathExists(specPath);
@@ -7058,7 +7084,7 @@ async function parseFeature(ctx, featurePath, type, context, options) {
7058
7084
  } else if (workflowPolicy.requireWorktree && tasksSummary.total > tasksSummary.done && !projectInManagedWorktree) {
7059
7085
  warnings.push(tr(lang, "warnings", "workflowWorktreeRequired"));
7060
7086
  }
7061
- const relativeFeaturePathFromDocs = path13.relative(
7087
+ const relativeFeaturePathFromDocs = path14.relative(
7062
7088
  context.docsDir,
7063
7089
  featurePath
7064
7090
  );
@@ -7421,7 +7447,7 @@ async function parseFeature(ctx, featurePath, type, context, options) {
7421
7447
  async function listFeatureDirs(ctx, rootDir) {
7422
7448
  const dirs = await listSubdirectories(ctx.fs, rootDir);
7423
7449
  return dirs.filter(
7424
- (value) => path13.basename(value).trim().toLowerCase() !== "feature-base"
7450
+ (value) => path14.basename(value).trim().toLowerCase() !== "feature-base"
7425
7451
  );
7426
7452
  }
7427
7453
  function normalizeRelPath(value) {
@@ -7562,7 +7588,7 @@ async function scanFeatures(ctx) {
7562
7588
  if (config.projectType === "single") {
7563
7589
  const featureDirs = await listFeatureDirs(
7564
7590
  ctx,
7565
- path13.join(config.docsDir, "features")
7591
+ path14.join(config.docsDir, "features")
7566
7592
  );
7567
7593
  componentFeatureDirs.set("single", featureDirs);
7568
7594
  allFeatureDirs.push(...featureDirs);
@@ -7574,14 +7600,14 @@ async function scanFeatures(ctx) {
7574
7600
  for (const component of components) {
7575
7601
  const componentDirs = await listFeatureDirs(
7576
7602
  ctx,
7577
- path13.join(config.docsDir, "features", component)
7603
+ path14.join(config.docsDir, "features", component)
7578
7604
  );
7579
7605
  componentFeatureDirs.set(component, componentDirs);
7580
7606
  allFeatureDirs.push(...componentDirs);
7581
7607
  }
7582
7608
  }
7583
7609
  const relativeFeaturePaths = allFeatureDirs.map(
7584
- (dir) => normalizeRelPath(path13.relative(config.docsDir, dir))
7610
+ (dir) => normalizeRelPath(path14.relative(config.docsDir, dir))
7585
7611
  );
7586
7612
  const docsGitMeta = buildDocsFeatureGitMeta(
7587
7613
  ctx,
@@ -7598,7 +7624,7 @@ async function scanFeatures(ctx) {
7598
7624
  const parsed = await Promise.all(
7599
7625
  target.dirs.map(async (dir) => {
7600
7626
  const relativeFeaturePathFromDocs = normalizeRelPath(
7601
- path13.relative(config.docsDir, dir)
7627
+ path14.relative(config.docsDir, dir)
7602
7628
  );
7603
7629
  const docsMeta = docsGitMeta.get(relativeFeaturePathFromDocs);
7604
7630
  return parseFeature(
@@ -7668,13 +7694,13 @@ async function runStatus(options) {
7668
7694
  );
7669
7695
  }
7670
7696
  const { docsDir, projectType, projectName, lang } = ctx.config;
7671
- const featuresDir = path13.join(docsDir, "features");
7697
+ const featuresDir = path14.join(docsDir, "features");
7672
7698
  const scan = await scanFeatures(ctx);
7673
7699
  const features = [];
7674
7700
  const idMap = /* @__PURE__ */ new Map();
7675
7701
  for (const f of scan.features) {
7676
7702
  const id = f.id || "UNKNOWN";
7677
- const relPath = path13.relative(docsDir, f.path);
7703
+ const relPath = path14.relative(docsDir, f.path);
7678
7704
  if (!idMap.has(id)) idMap.set(id, []);
7679
7705
  idMap.get(id).push(relPath);
7680
7706
  if (!f.docs.specExists || !f.docs.tasksExists) continue;
@@ -7765,7 +7791,7 @@ async function runStatus(options) {
7765
7791
  }
7766
7792
  console.log();
7767
7793
  if (options.write) {
7768
- const outputPath = path13.join(featuresDir, "status.md");
7794
+ const outputPath = path14.join(featuresDir, "status.md");
7769
7795
  const date = getLocalDateString();
7770
7796
  const content = [
7771
7797
  "# Feature Status",
@@ -7786,18 +7812,18 @@ async function runStatus(options) {
7786
7812
  );
7787
7813
  }
7788
7814
  }
7789
- function escapeRegExp3(value) {
7815
+ function escapeRegExp4(value) {
7790
7816
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
7791
7817
  }
7792
7818
  async function getFeatureNameFromSpec(fsAdapter, featureDir, fallbackSlug, fallbackFolderName) {
7793
7819
  try {
7794
- const specPath = path13.join(featureDir, "spec.md");
7820
+ const specPath = path14.join(featureDir, "spec.md");
7795
7821
  if (!await fsAdapter.pathExists(specPath)) return fallbackSlug;
7796
7822
  const content = await fsAdapter.readFile(specPath, "utf-8");
7797
7823
  const keys = ["\uAE30\uB2A5\uBA85", "Feature Name"];
7798
7824
  for (const key of keys) {
7799
7825
  const regex = new RegExp(
7800
- `^\\s*-\\s*\\*\\*${escapeRegExp3(key)}\\*\\*\\s*:\\s*(.*)$`,
7826
+ `^\\s*-\\s*\\*\\*${escapeRegExp4(key)}\\*\\*\\s*:\\s*(.*)$`,
7801
7827
  "m"
7802
7828
  );
7803
7829
  const match = content.match(regex);
@@ -7875,8 +7901,8 @@ async function runUpdate(options) {
7875
7901
  console.log(chalk9.blue(tr(lang, "cli", "update.updatingAgents")));
7876
7902
  }
7877
7903
  if (agentsMode === "all") {
7878
- const commonAgentsBase = path13.join(templatesDir, lang, "common", "agents");
7879
- const targetAgentsBase = path13.join(docsDir, "agents");
7904
+ const commonAgentsBase = path14.join(templatesDir, lang, "common", "agents");
7905
+ const targetAgentsBase = path14.join(docsDir, "agents");
7880
7906
  const commonAgents = commonAgentsBase;
7881
7907
  const targetAgents = targetAgentsBase;
7882
7908
  const featurePath = projectType === "multi" ? "docs/features/{component}" : "docs/features";
@@ -7974,21 +8000,21 @@ async function collectAgentsMdTargets(cwd, config) {
7974
8000
  const targets = /* @__PURE__ */ new Set();
7975
8001
  const docsRepo = config.docsRepo ?? "embedded";
7976
8002
  if (docsRepo === "embedded") {
7977
- const repoRoot = getGitTopLevelOrNull2(cwd) || getGitTopLevelOrNull2(config.docsDir) || path13.resolve(config.docsDir, "..");
7978
- targets.add(path13.join(repoRoot, "AGENTS.md"));
8003
+ const repoRoot = getGitTopLevelOrNull2(cwd) || getGitTopLevelOrNull2(config.docsDir) || path14.resolve(config.docsDir, "..");
8004
+ targets.add(path14.join(repoRoot, "AGENTS.md"));
7979
8005
  return [...targets];
7980
8006
  }
7981
- targets.add(path13.join(config.docsDir, "AGENTS.md"));
8007
+ targets.add(path14.join(config.docsDir, "AGENTS.md"));
7982
8008
  const baseDir = getGitTopLevelOrNull2(cwd) || getGitTopLevelOrNull2(config.docsDir) || process.cwd();
7983
8009
  const rawRoots = typeof config.projectRoot === "string" ? [config.projectRoot] : config.projectRoot && typeof config.projectRoot === "object" ? Object.values(config.projectRoot) : [];
7984
8010
  for (const rawRoot of rawRoots) {
7985
8011
  const value = String(rawRoot || "").trim();
7986
8012
  if (!value) continue;
7987
- const resolved = path13.resolve(baseDir, value);
8013
+ const resolved = path14.resolve(baseDir, value);
7988
8014
  if (!await fs.pathExists(resolved)) continue;
7989
8015
  const stat = await fs.stat(resolved);
7990
8016
  if (!stat.isDirectory()) continue;
7991
- targets.add(path13.join(resolved, "AGENTS.md"));
8017
+ targets.add(path14.join(resolved, "AGENTS.md"));
7992
8018
  }
7993
8019
  return [...targets];
7994
8020
  }
@@ -8028,7 +8054,7 @@ function normalizeDecisionEnumList2(raw) {
8028
8054
  return [...deduped];
8029
8055
  }
8030
8056
  async function backfillMissingConfigDefaults(docsDir) {
8031
- const configPath = path13.join(docsDir, ".lee-spec-kit.json");
8057
+ const configPath = path14.join(docsDir, ".lee-spec-kit.json");
8032
8058
  if (!await fs.pathExists(configPath)) {
8033
8059
  return { changed: false, changedPaths: [] };
8034
8060
  }
@@ -8151,8 +8177,8 @@ async function updateFolder(sourceDir, targetDir, force, replacements, lang = DE
8151
8177
  const files = await fs.readdir(sourceDir);
8152
8178
  let updatedCount = 0;
8153
8179
  for (const file of files) {
8154
- const sourcePath = path13.join(sourceDir, file);
8155
- const targetPath = path13.join(targetDir, file);
8180
+ const sourcePath = path14.join(sourceDir, file);
8181
+ const targetPath = path14.join(targetDir, file);
8156
8182
  const stat = await fs.stat(sourcePath);
8157
8183
  if (stat.isFile()) {
8158
8184
  if (protectedFiles.has(file)) {
@@ -8235,7 +8261,7 @@ function extractPorcelainPaths(line) {
8235
8261
  function getDocsPorcelainStatus(docsDir, ignoredAbsPaths = []) {
8236
8262
  const top = getGitTopLevel2(docsDir);
8237
8263
  if (!top) return null;
8238
- const rel = path13.relative(top, docsDir) || ".";
8264
+ const rel = path14.relative(top, docsDir) || ".";
8239
8265
  try {
8240
8266
  const output = execFileSync("git", ["status", "--porcelain=v1", "--", rel], {
8241
8267
  cwd: top,
@@ -8247,7 +8273,7 @@ function getDocsPorcelainStatus(docsDir, ignoredAbsPaths = []) {
8247
8273
  }
8248
8274
  const ignoredRelPaths = new Set(
8249
8275
  ignoredAbsPaths.map(
8250
- (absPath) => normalizeGitPath2(path13.relative(top, absPath) || ".")
8276
+ (absPath) => normalizeGitPath2(path14.relative(top, absPath) || ".")
8251
8277
  )
8252
8278
  );
8253
8279
  const filtered = output.split("\n").filter((line) => {
@@ -8305,7 +8331,7 @@ ${tr(lang2, "cli", "common.canceled")}`));
8305
8331
  }
8306
8332
  async function runConfig(options) {
8307
8333
  const cwd = process.cwd();
8308
- const targetCwd = options.dir ? path13.resolve(cwd, options.dir) : cwd;
8334
+ const targetCwd = options.dir ? path14.resolve(cwd, options.dir) : cwd;
8309
8335
  const config = await getConfig(targetCwd);
8310
8336
  if (!config) {
8311
8337
  throw createCliError(
@@ -8313,7 +8339,7 @@ async function runConfig(options) {
8313
8339
  tr(DEFAULT_LANG, "cli", "common.configNotFound")
8314
8340
  );
8315
8341
  }
8316
- const configPath = path13.join(config.docsDir, ".lee-spec-kit.json");
8342
+ const configPath = path14.join(config.docsDir, ".lee-spec-kit.json");
8317
8343
  if (!options.projectRoot) {
8318
8344
  console.log();
8319
8345
  console.log(chalk9.blue(tr(config.lang, "cli", "config.currentTitle")));
@@ -8419,47 +8445,47 @@ var BUILTIN_DOC_DEFINITIONS = [
8419
8445
  {
8420
8446
  id: "agents",
8421
8447
  title: { ko: "\uC5D0\uC774\uC804\uD2B8 \uC6B4\uC601 \uADDC\uCE59", en: "Agent Operating Rules" },
8422
- relativePath: (_, lang) => path13.join(lang, "common", "agents", "agents.md")
8448
+ relativePath: (_, lang) => path14.join(lang, "common", "agents", "agents.md")
8423
8449
  },
8424
8450
  {
8425
8451
  id: "git-workflow",
8426
8452
  title: { ko: "Git \uC6CC\uD06C\uD50C\uB85C\uC6B0", en: "Git Workflow" },
8427
- relativePath: (_, lang) => path13.join(lang, "common", "agents", "git-workflow.md")
8453
+ relativePath: (_, lang) => path14.join(lang, "common", "agents", "git-workflow.md")
8428
8454
  },
8429
8455
  {
8430
8456
  id: "issue-doc",
8431
8457
  title: { ko: "Issue \uBB38\uC11C \uD15C\uD50C\uB9BF", en: "Issue Document Template" },
8432
- relativePath: (_, lang) => path13.join(lang, "common", "features", "feature-base", "issue.md")
8458
+ relativePath: (_, lang) => path14.join(lang, "common", "features", "feature-base", "issue.md")
8433
8459
  },
8434
8460
  {
8435
8461
  id: "pr-doc",
8436
8462
  title: { ko: "PR \uBB38\uC11C \uD15C\uD50C\uB9BF", en: "PR Document Template" },
8437
- relativePath: (_, lang) => path13.join(lang, "common", "features", "feature-base", "pr.md")
8463
+ relativePath: (_, lang) => path14.join(lang, "common", "features", "feature-base", "pr.md")
8438
8464
  },
8439
8465
  {
8440
8466
  id: "create-feature",
8441
8467
  title: { ko: "create-feature \uC2A4\uD0AC", en: "create-feature skill" },
8442
- relativePath: (_, lang) => path13.join(lang, "common", "agents", "skills", "create-feature.md")
8468
+ relativePath: (_, lang) => path14.join(lang, "common", "agents", "skills", "create-feature.md")
8443
8469
  },
8444
8470
  {
8445
8471
  id: "execute-task",
8446
8472
  title: { ko: "execute-task \uC2A4\uD0AC", en: "execute-task skill" },
8447
- relativePath: (_, lang) => path13.join(lang, "common", "agents", "skills", "execute-task.md")
8473
+ relativePath: (_, lang) => path14.join(lang, "common", "agents", "skills", "execute-task.md")
8448
8474
  },
8449
8475
  {
8450
8476
  id: "create-issue",
8451
8477
  title: { ko: "create-issue \uC2A4\uD0AC", en: "create-issue skill" },
8452
- relativePath: (_, lang) => path13.join(lang, "common", "agents", "skills", "create-issue.md")
8478
+ relativePath: (_, lang) => path14.join(lang, "common", "agents", "skills", "create-issue.md")
8453
8479
  },
8454
8480
  {
8455
8481
  id: "create-pr",
8456
8482
  title: { ko: "create-pr \uC2A4\uD0AC", en: "create-pr skill" },
8457
- relativePath: (_, lang) => path13.join(lang, "common", "agents", "skills", "create-pr.md")
8483
+ relativePath: (_, lang) => path14.join(lang, "common", "agents", "skills", "create-pr.md")
8458
8484
  },
8459
8485
  {
8460
8486
  id: "split-feature",
8461
8487
  title: { ko: "feature \uBD84\uD560 \uAC00\uC774\uB4DC", en: "feature split guide" },
8462
- relativePath: (_, lang) => path13.join(lang, "common", "agents", "skills", "split-feature.md")
8488
+ relativePath: (_, lang) => path14.join(lang, "common", "agents", "skills", "split-feature.md")
8463
8489
  }
8464
8490
  ];
8465
8491
  var DOC_FOLLOWUPS = {
@@ -8556,7 +8582,7 @@ function listBuiltinDocs(projectType, lang) {
8556
8582
  id: doc.id,
8557
8583
  title: doc.title[lang],
8558
8584
  relativePath,
8559
- absolutePath: path13.join(templatesDir, relativePath)
8585
+ absolutePath: path14.join(templatesDir, relativePath)
8560
8586
  };
8561
8587
  });
8562
8588
  }
@@ -8966,6 +8992,13 @@ async function resolveContextSelection(ctx, featureName, options) {
8966
8992
 
8967
8993
  // src/services/ContextPresenter.ts
8968
8994
  function getActionExecutionMetadata(action) {
8995
+ if (action.category === "task_execute" && action.taskExecutePhase === "start") {
8996
+ return {
8997
+ handoffOnly: true,
8998
+ advancesWorkflow: false,
8999
+ nextMainState: "task_complete"
9000
+ };
9001
+ }
8969
9002
  if (action.category === "code_review_run") {
8970
9003
  return {
8971
9004
  handoffOnly: true,
@@ -9050,6 +9083,7 @@ function buildAgentOrchestrationPolicy(actionOptions, autoRunAvailable, autoRunC
9050
9083
  pauseAndReportWhen: [
9051
9084
  "approvalRequest.required=true",
9052
9085
  "AUTO_GATE_REACHED",
9086
+ "AUTO_DELEGATED_HANDOFF",
9053
9087
  "AUTO_MANUAL_REQUIRED",
9054
9088
  "command execution error"
9055
9089
  ],
@@ -9593,7 +9627,7 @@ function getApprovalSessionId() {
9593
9627
  function getApprovalTicketPaths(config) {
9594
9628
  return {
9595
9629
  runtimePath: getApprovalTicketStorePath(config.docsDir),
9596
- legacyPath: path13.join(config.docsDir, LEGACY_APPROVAL_TICKET_FILENAME)
9630
+ legacyPath: path14.join(config.docsDir, LEGACY_APPROVAL_TICKET_FILENAME)
9597
9631
  };
9598
9632
  }
9599
9633
  async function loadApprovalTicketStore(storePath) {
@@ -9607,7 +9641,7 @@ async function loadApprovalTicketStore(storePath) {
9607
9641
  }
9608
9642
  }
9609
9643
  async function saveApprovalTicketStore(storePath, payload) {
9610
- await fs.ensureDir(path13.dirname(storePath));
9644
+ await fs.ensureDir(path14.dirname(storePath));
9611
9645
  await fs.writeJson(storePath, payload, { spaces: 2 });
9612
9646
  }
9613
9647
  function pruneApprovalTickets(tickets, nowMs) {
@@ -9793,6 +9827,14 @@ function getCommandExecutionLockPath(action, config) {
9793
9827
  return getProjectExecutionLockPath(action.cwd);
9794
9828
  }
9795
9829
  function buildApprovedHandoffMetadata(action, featureRef) {
9830
+ if (action.category === "task_execute" && action.taskExecutePhase === "start") {
9831
+ const taskId = action.cmd.match(/\b--task\s+([^\s]+)/)?.[1];
9832
+ return {
9833
+ delegatedWorkRequired: true,
9834
+ doNotReapproveSameLabel: true,
9835
+ reuseKey: taskId ? `task:${featureRef}:${taskId}` : `task:${featureRef}`
9836
+ };
9837
+ }
9796
9838
  if (action.category === "pre_pr_review_run") {
9797
9839
  return {
9798
9840
  delegatedWorkRequired: true,
@@ -10460,7 +10502,7 @@ async function runContext(featureName, options) {
10460
10502
  untilCategories: autoRunPlan.untilCategories,
10461
10503
  unknownCategories: autoRunPlan.unknownCategories,
10462
10504
  manualBoundary: autoRunPlan.manualBoundary,
10463
- guidance: 'Use auto-run only when `autoRun.available=true`. If `autoRun.policyEligible=true` but `autoRun.executableNow=false`, resolve `autoRun.manualBoundary` first. Do not treat `autoRun.available` alone as a delegation trigger; use `agentOrchestration.subAgentHandoff.required` + `mode="auto_run"` for actual delegation. Stop and request approval when `approvalRequest.required=true` or when auto mode reaches configured gate categories.'
10505
+ guidance: 'Use auto-run only when `autoRun.available=true`. If `autoRun.policyEligible=true` but `autoRun.executableNow=false`, resolve `autoRun.manualBoundary` first. Do not treat `autoRun.available` alone as a delegation trigger; use `agentOrchestration.subAgentHandoff.required` + `mode="auto_run"` for actual delegation. Stop and request approval when `approvalRequest.required=true`, when auto mode reaches configured gate categories, or when a delegated handoff pause must be resumed.'
10464
10506
  },
10465
10507
  approvalRequest: {
10466
10508
  guidance: approvalGuidance.replace(
@@ -10684,7 +10726,7 @@ async function runContext(featureName, options) {
10684
10726
  if (f.issueNumber) {
10685
10727
  console.log(` \u2022 Issue: #${f.issueNumber}`);
10686
10728
  }
10687
- console.log(` \u2022 Path: ${path13.relative(cwd, f.path)}`);
10729
+ console.log(` \u2022 Path: ${path14.relative(cwd, f.path)}`);
10688
10730
  if (f.git.projectBranch) {
10689
10731
  console.log(` \u2022 Project Branch: ${f.git.projectBranch}`);
10690
10732
  }
@@ -10836,7 +10878,7 @@ function extractTitleAfterId(line, id) {
10836
10878
  return cleaned ? cleaned : void 0;
10837
10879
  }
10838
10880
  async function scanPrdRequirements(fsAdapter, docsDir) {
10839
- const prdDir = path13.join(docsDir, "prd");
10881
+ const prdDir = path14.join(docsDir, "prd");
10840
10882
  const files = await walkFiles(fsAdapter, prdDir, {
10841
10883
  extensions: [".md"],
10842
10884
  ignoreDirs: [".git", "node_modules", "dist", "tmp"]
@@ -10844,7 +10886,7 @@ async function scanPrdRequirements(fsAdapter, docsDir) {
10844
10886
  const definitions = /* @__PURE__ */ new Map();
10845
10887
  const duplicates = [];
10846
10888
  for (const filePath of files) {
10847
- if (path13.basename(filePath).toLowerCase() === "readme.md") {
10889
+ if (path14.basename(filePath).toLowerCase() === "readme.md") {
10848
10890
  continue;
10849
10891
  }
10850
10892
  let content = "";
@@ -10853,7 +10895,7 @@ async function scanPrdRequirements(fsAdapter, docsDir) {
10853
10895
  } catch {
10854
10896
  continue;
10855
10897
  }
10856
- const relFile = normalizeRelPath2(path13.relative(docsDir, filePath));
10898
+ const relFile = normalizeRelPath2(path14.relative(docsDir, filePath));
10857
10899
  const lines = content.split(/\r?\n/);
10858
10900
  let inCodeBlock = false;
10859
10901
  for (let i = 0; i < lines.length; i += 1) {
@@ -10928,7 +10970,7 @@ var FIXABLE_ISSUE_CODES = /* @__PURE__ */ new Set([
10928
10970
  ]);
10929
10971
  function formatPath(cwd, p) {
10930
10972
  if (!p) return "";
10931
- return path13.isAbsolute(p) ? path13.relative(cwd, p) : p;
10973
+ return path14.isAbsolute(p) ? path14.relative(cwd, p) : p;
10932
10974
  }
10933
10975
  function detectPlaceholders(content) {
10934
10976
  const patterns = [
@@ -11087,7 +11129,7 @@ async function applyDoctorFixes(config, cwd, features, dryRun) {
11087
11129
  const placeholderContext = {
11088
11130
  projectName: config.projectName,
11089
11131
  featureName: f.slug,
11090
- featurePath: f.docs.featurePathFromDocs || path13.relative(config.docsDir, f.path),
11132
+ featurePath: f.docs.featurePathFromDocs || path14.relative(config.docsDir, f.path),
11091
11133
  repoType: f.type,
11092
11134
  featureNumber
11093
11135
  };
@@ -11097,7 +11139,7 @@ async function applyDoctorFixes(config, cwd, features, dryRun) {
11097
11139
  "tasks.md"
11098
11140
  ];
11099
11141
  for (const file of files) {
11100
- const fullPath = path13.join(f.path, file);
11142
+ const fullPath = path14.join(f.path, file);
11101
11143
  if (!await fs.pathExists(fullPath)) continue;
11102
11144
  const original = await fs.readFile(fullPath, "utf-8");
11103
11145
  let next = original;
@@ -11150,7 +11192,7 @@ async function checkDocsStructure(config, cwd) {
11150
11192
  const issues = [];
11151
11193
  const requiredDirs = ["agents", "features", "prd", "designs", "ideas"];
11152
11194
  for (const dir of requiredDirs) {
11153
- const p = path13.join(config.docsDir, dir);
11195
+ const p = path14.join(config.docsDir, dir);
11154
11196
  if (!await fs.pathExists(p)) {
11155
11197
  issues.push({
11156
11198
  level: "error",
@@ -11162,7 +11204,7 @@ async function checkDocsStructure(config, cwd) {
11162
11204
  });
11163
11205
  }
11164
11206
  }
11165
- const configPath = path13.join(config.docsDir, ".lee-spec-kit.json");
11207
+ const configPath = path14.join(config.docsDir, ".lee-spec-kit.json");
11166
11208
  if (!await fs.pathExists(configPath)) {
11167
11209
  issues.push({
11168
11210
  level: "warn",
@@ -11190,7 +11232,7 @@ async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
11190
11232
  }
11191
11233
  const idMap = /* @__PURE__ */ new Map();
11192
11234
  for (const f of features) {
11193
- const rel = f.docs.featurePathFromDocs || path13.relative(config.docsDir, f.path);
11235
+ const rel = f.docs.featurePathFromDocs || path14.relative(config.docsDir, f.path);
11194
11236
  const id = f.id || "UNKNOWN";
11195
11237
  if (!idMap.has(id)) idMap.set(id, []);
11196
11238
  idMap.get(id).push(rel);
@@ -11198,7 +11240,7 @@ async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
11198
11240
  if (!isInitialTemplateState) {
11199
11241
  const featureDocs = ["spec.md", "plan.md", "tasks.md"];
11200
11242
  for (const file of featureDocs) {
11201
- const p = path13.join(f.path, file);
11243
+ const p = path14.join(f.path, file);
11202
11244
  if (!await fs.pathExists(p)) continue;
11203
11245
  const content = await fs.readFile(p, "utf-8");
11204
11246
  const placeholders = detectPlaceholders(content);
@@ -11213,7 +11255,7 @@ async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
11213
11255
  });
11214
11256
  }
11215
11257
  if (decisionsPlaceholderMode !== "off") {
11216
- const decisionsPath = path13.join(f.path, "decisions.md");
11258
+ const decisionsPath = path14.join(f.path, "decisions.md");
11217
11259
  if (await fs.pathExists(decisionsPath)) {
11218
11260
  const content = await fs.readFile(decisionsPath, "utf-8");
11219
11261
  const placeholders = detectPlaceholders(content);
@@ -11242,7 +11284,7 @@ async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
11242
11284
  level: "warn",
11243
11285
  code: "spec_status_unset",
11244
11286
  message: tr(config.lang, "cli", "doctor.issue.specStatusUnset"),
11245
- path: formatPath(cwd, path13.join(f.path, "spec.md"))
11287
+ path: formatPath(cwd, path14.join(f.path, "spec.md"))
11246
11288
  });
11247
11289
  }
11248
11290
  if (f.docs.planExists && !f.planStatus && !isInitialTemplateState) {
@@ -11250,7 +11292,7 @@ async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
11250
11292
  level: "warn",
11251
11293
  code: "plan_status_unset",
11252
11294
  message: tr(config.lang, "cli", "doctor.issue.planStatusUnset"),
11253
- path: formatPath(cwd, path13.join(f.path, "plan.md"))
11295
+ path: formatPath(cwd, path14.join(f.path, "plan.md"))
11254
11296
  });
11255
11297
  }
11256
11298
  if (f.docs.tasksExists && f.tasks.total === 0 && !isInitialTemplateState) {
@@ -11258,11 +11300,11 @@ async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
11258
11300
  level: "warn",
11259
11301
  code: "tasks_empty",
11260
11302
  message: tr(config.lang, "cli", "doctor.issue.tasksEmpty"),
11261
- path: formatPath(cwd, path13.join(f.path, "tasks.md"))
11303
+ path: formatPath(cwd, path14.join(f.path, "tasks.md"))
11262
11304
  });
11263
11305
  }
11264
11306
  if (f.docs.tasksExists) {
11265
- const tasksPath = path13.join(f.path, "tasks.md");
11307
+ const tasksPath = path14.join(f.path, "tasks.md");
11266
11308
  const tasksContent = await fs.readFile(tasksPath, "utf-8");
11267
11309
  const unknownPrdTags = [...new Set(
11268
11310
  parseTaskLines(tasksContent).flatMap((task) => task.tags).filter((tag) => isPrdRequirementId(tag)).map((tag) => tag.trim().toUpperCase()).filter((tag) => !prdDefinitions.has(tag))
@@ -11284,7 +11326,7 @@ async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
11284
11326
  level: "warn",
11285
11327
  code: "tasks_doc_status_missing",
11286
11328
  message: tr(config.lang, "cli", "doctor.issue.tasksDocStatusMissing"),
11287
- path: formatPath(cwd, path13.join(f.path, "tasks.md"))
11329
+ path: formatPath(cwd, path14.join(f.path, "tasks.md"))
11288
11330
  });
11289
11331
  }
11290
11332
  if (f.docs.tasksExists && f.docs.tasksDocStatusFieldExists && !f.tasksDocStatus && !isInitialTemplateState) {
@@ -11292,7 +11334,7 @@ async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
11292
11334
  level: "warn",
11293
11335
  code: "tasks_doc_status_unset",
11294
11336
  message: tr(config.lang, "cli", "doctor.issue.tasksDocStatusUnset"),
11295
- path: formatPath(cwd, path13.join(f.path, "tasks.md"))
11337
+ path: formatPath(cwd, path14.join(f.path, "tasks.md"))
11296
11338
  });
11297
11339
  }
11298
11340
  }
@@ -11316,7 +11358,7 @@ async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
11316
11358
  level: "warn",
11317
11359
  code: "missing_feature_id",
11318
11360
  message: tr(config.lang, "cli", "doctor.issue.missingFeatureId"),
11319
- path: formatPath(cwd, path13.join(config.docsDir, p))
11361
+ path: formatPath(cwd, path14.join(config.docsDir, p))
11320
11362
  });
11321
11363
  }
11322
11364
  return issues;
@@ -11447,7 +11489,7 @@ function doctorCommand(program2) {
11447
11489
  }
11448
11490
  console.log();
11449
11491
  console.log(chalk9.bold(tr(lang, "cli", "doctor.title")));
11450
- console.log(chalk9.gray(`- Docs: ${path13.relative(cwd, docsDir)}`));
11492
+ console.log(chalk9.gray(`- Docs: ${path14.relative(cwd, docsDir)}`));
11451
11493
  console.log(chalk9.gray(`- Type: ${projectType}`));
11452
11494
  console.log(chalk9.gray(`- Lang: ${lang}`));
11453
11495
  console.log();
@@ -11628,7 +11670,7 @@ async function runView(featureName, options) {
11628
11670
  }
11629
11671
  console.log();
11630
11672
  console.log(chalk9.bold("\u{1F4CA} Workflow View"));
11631
- console.log(chalk9.gray(`- Docs: ${path13.relative(cwd, config.docsDir)}`));
11673
+ console.log(chalk9.gray(`- Docs: ${path14.relative(cwd, config.docsDir)}`));
11632
11674
  console.log(
11633
11675
  chalk9.gray(
11634
11676
  `- Features: ${state.features.length} (open ${state.openFeatures.length} / done ${state.doneFeatures.length})`
@@ -11713,13 +11755,13 @@ function normalizeRunId(raw) {
11713
11755
  return value;
11714
11756
  }
11715
11757
  function getFlowRunBaseDir(cwd) {
11716
- return path13.join(getRuntimeStateDir(cwd), "flow-runs");
11758
+ return path14.join(getRuntimeStateDir(cwd), "flow-runs");
11717
11759
  }
11718
11760
  function getFlowRunPath(cwd, runId) {
11719
- return path13.join(getFlowRunBaseDir(cwd), `${runId}.json`);
11761
+ return path14.join(getFlowRunBaseDir(cwd), `${runId}.json`);
11720
11762
  }
11721
11763
  function getFlowRunLockPath(cwd, runId) {
11722
- return path13.join(getRuntimeStateDir(cwd), "locks", `flow-run-${runId}.lock`);
11764
+ return path14.join(getRuntimeStateDir(cwd), "locks", `flow-run-${runId}.lock`);
11723
11765
  }
11724
11766
  async function readFlowRunRecordUnsafe(cwd, runId) {
11725
11767
  const normalized = normalizeRunId(runId);
@@ -11745,7 +11787,7 @@ async function readFlowRunRecordUnsafe(cwd, runId) {
11745
11787
  }
11746
11788
  async function writeFlowRunRecord(cwd, record) {
11747
11789
  const filePath = getFlowRunPath(cwd, record.runId);
11748
- await fs.ensureDir(path13.dirname(filePath));
11790
+ await fs.ensureDir(path14.dirname(filePath));
11749
11791
  await fs.writeJson(filePath, record, { spaces: 2 });
11750
11792
  }
11751
11793
  async function createFlowRunRecord(cwd, input) {
@@ -11895,6 +11937,7 @@ function toCompactAutoRun(autoRun) {
11895
11937
  iterations: autoRun.iterations,
11896
11938
  executionCount: autoRun.executions.length,
11897
11939
  lastExecution,
11940
+ delegated: autoRun.delegated ?? null,
11898
11941
  gate: autoRun.gate ?? null,
11899
11942
  manual: autoRun.manual ?? null,
11900
11943
  resume: autoRun.resume,
@@ -11939,6 +11982,7 @@ function buildAgentOrchestrationPolicy2(autoRun, featureRef) {
11939
11982
  pauseAndReportWhen: [
11940
11983
  "approvalRequest.required=true",
11941
11984
  "AUTO_GATE_REACHED",
11985
+ "AUTO_DELEGATED_HANDOFF",
11942
11986
  "AUTO_MANUAL_REQUIRED",
11943
11987
  "command execution error"
11944
11988
  ],
@@ -12164,6 +12208,7 @@ function resolveAutoMode(config, options, requestText) {
12164
12208
  }
12165
12209
  function toAutoReasonCode(status) {
12166
12210
  const map = {
12211
+ delegated_handoff: "AUTO_DELEGATED_HANDOFF",
12167
12212
  gate_reached: "AUTO_GATE_REACHED",
12168
12213
  manual_required: "AUTO_MANUAL_REQUIRED",
12169
12214
  no_action_options: "AUTO_NO_ACTION_OPTIONS",
@@ -12187,6 +12232,7 @@ function isAutoRunFailureStatus(status) {
12187
12232
  }
12188
12233
  function toFlowRunStatus(status) {
12189
12234
  switch (status) {
12235
+ case "delegated_handoff":
12190
12236
  case "gate_reached":
12191
12237
  case "manual_required":
12192
12238
  return "paused";
@@ -12201,6 +12247,17 @@ function toFlowRunStatus(status) {
12201
12247
  return "failed";
12202
12248
  }
12203
12249
  }
12250
+ function isTaskCommitCheckpointOption(option, state) {
12251
+ if (!option || state.status !== "single_matched" || !state.matchedFeature) {
12252
+ return false;
12253
+ }
12254
+ if (state.matchedFeature.currentSubstateId !== "task_commit_pending") {
12255
+ return false;
12256
+ }
12257
+ if (option.action.type !== "command") return false;
12258
+ if (option.action.category === "docs_commit") return true;
12259
+ return option.action.category === "task_execute" && option.action.scope === "project" && /\bgit\s+commit\b/i.test(option.action.cmd);
12260
+ }
12204
12261
  async function runAutoUntilCategory(config, featureName, selectionOptions, untilCategories, requestText, metadata) {
12205
12262
  const contextArgs = [
12206
12263
  "context",
@@ -12378,6 +12435,29 @@ async function runAutoUntilCategory(config, featureName, selectionOptions, until
12378
12435
  manual: null
12379
12436
  };
12380
12437
  }
12438
+ const taskCommitCheckpoint = actionOptions.find(
12439
+ (option) => isTaskCommitCheckpointOption(option, state)
12440
+ );
12441
+ if (taskCommitCheckpoint) {
12442
+ return {
12443
+ enabled: true,
12444
+ untilCategories,
12445
+ request: requestText,
12446
+ preset: metadata?.preset ?? null,
12447
+ source: metadata?.source ?? null,
12448
+ resume,
12449
+ status: "manual_required",
12450
+ reasonCode: toAutoReasonCode("manual_required"),
12451
+ iterations,
12452
+ executions,
12453
+ gate: null,
12454
+ manual: {
12455
+ label: taskCommitCheckpoint.label,
12456
+ category: taskCommitCheckpoint.action.category,
12457
+ detail: taskCommitCheckpoint.detail
12458
+ }
12459
+ };
12460
+ }
12381
12461
  const executable = actionOptions.find(
12382
12462
  (option) => option.action.type === "command"
12383
12463
  );
@@ -12463,16 +12543,18 @@ async function runAutoUntilCategory(config, featureName, selectionOptions, until
12463
12543
  preset: metadata?.preset ?? null,
12464
12544
  source: metadata?.source ?? null,
12465
12545
  resume,
12466
- status: "manual_required",
12467
- reasonCode: toAutoReasonCode("manual_required"),
12546
+ status: "delegated_handoff",
12547
+ reasonCode: toAutoReasonCode("delegated_handoff"),
12468
12548
  iterations,
12469
12549
  executions,
12470
- gate: null,
12471
- manual: {
12550
+ delegated: {
12472
12551
  label: executable.label,
12473
12552
  category: executable.action.category,
12474
- detail: typeof executeResult?.nextMainState === "string" ? `Complete the delegated handoff work, then continue from ${executeResult.nextMainState}.` : executable.detail
12475
- }
12553
+ detail: typeof executeResult?.nextMainState === "string" ? `Complete the delegated handoff work, then continue from ${executeResult.nextMainState}.` : executable.detail,
12554
+ nextMainState: executeResult?.nextMainState
12555
+ },
12556
+ gate: null,
12557
+ manual: null
12476
12558
  };
12477
12559
  }
12478
12560
  if (executeResult?.status !== "approved_executed") {
@@ -12663,6 +12745,20 @@ async function runFlow(featureName, options) {
12663
12745
  "`--request` requires auto mode. Use `--auto-until-category`, `--auto-preset`, or configure `workflow.auto.defaultPreset`."
12664
12746
  );
12665
12747
  }
12748
+ if (autoMode && !resolvedFeatureName && requestText) {
12749
+ const bootstrapped = await bootstrapFeatureFromIdeaRequest(
12750
+ config,
12751
+ requestText,
12752
+ selectedComponent
12753
+ );
12754
+ if (bootstrapped) {
12755
+ resolvedFeatureName = bootstrapped.featureRef;
12756
+ if (!selectedComponent && bootstrapped.component) {
12757
+ selectedComponent = bootstrapped.component;
12758
+ selectionOptions.component = bootstrapped.component;
12759
+ }
12760
+ }
12761
+ }
12666
12762
  if (autoMode && !featureName) {
12667
12763
  if (!resolvedFeatureName) {
12668
12764
  throw createCliError(
@@ -12757,7 +12853,8 @@ async function runFlow(featureName, options) {
12757
12853
  },
12758
12854
  lastAutoStatus: autoRun.status,
12759
12855
  lastReasonCode: autoRun.reasonCode,
12760
- lastError: autoRun.error
12856
+ lastError: autoRun.error,
12857
+ lastDelegatedHandoff: autoRun.delegated ?? null
12761
12858
  })
12762
12859
  );
12763
12860
  autoRun.run = {
@@ -12943,6 +13040,45 @@ async function runFlow(featureName, options) {
12943
13040
  );
12944
13041
  console.log();
12945
13042
  }
13043
+ async function bootstrapFeatureFromIdeaRequest(config, requestText, selectedComponent) {
13044
+ const ideaRef = extractExplicitIdeaRef(requestText);
13045
+ if (!ideaRef) return null;
13046
+ const resolvedIdea = await resolveIdeaReference(
13047
+ config.docsDir,
13048
+ ideaRef,
13049
+ config.lang
13050
+ );
13051
+ const existingFeatureRef = await readIdeaMetadataValue(
13052
+ resolvedIdea.path,
13053
+ "Feature"
13054
+ );
13055
+ if (existingFeatureRef && existingFeatureRef !== "-") {
13056
+ return { featureRef: existingFeatureRef, component: selectedComponent };
13057
+ }
13058
+ let component = selectedComponent;
13059
+ if (config.projectType === "multi" && !component) {
13060
+ const ideaComponent = await readIdeaMetadataValue(
13061
+ resolvedIdea.path,
13062
+ "Component"
13063
+ );
13064
+ if (ideaComponent && ideaComponent !== "-" && ideaComponent !== "all") {
13065
+ component = ideaComponent.toLowerCase();
13066
+ } else {
13067
+ return null;
13068
+ }
13069
+ }
13070
+ const featureName = await deriveFeatureNameFromIdea(resolvedIdea.path);
13071
+ const result = await runFeature(featureName, {
13072
+ component,
13073
+ idea: ideaRef,
13074
+ nonInteractive: true,
13075
+ json: true
13076
+ });
13077
+ return {
13078
+ featureRef: `${result.featureId}-${result.featureName}`,
13079
+ component
13080
+ };
13081
+ }
12946
13082
  function runProcess(bin, args, cwd) {
12947
13083
  const result = spawnSync(bin, args, {
12948
13084
  cwd,
@@ -13056,27 +13192,27 @@ function tg(lang, key, vars = {}) {
13056
13192
  function detectGithubCliLangSync(cwd) {
13057
13193
  const explicitDocsDir = (process.env.LEE_SPEC_KIT_DOCS_DIR || "").trim();
13058
13194
  const startDirs = [
13059
- explicitDocsDir ? path13.resolve(explicitDocsDir) : "",
13060
- path13.resolve(cwd)
13195
+ explicitDocsDir ? path14.resolve(explicitDocsDir) : "",
13196
+ path14.resolve(cwd)
13061
13197
  ].filter(Boolean);
13062
13198
  const scanOrder = [];
13063
13199
  const seen = /* @__PURE__ */ new Set();
13064
13200
  for (const start of startDirs) {
13065
13201
  let current = start;
13066
13202
  while (true) {
13067
- const abs = path13.resolve(current);
13203
+ const abs = path14.resolve(current);
13068
13204
  if (!seen.has(abs)) {
13069
13205
  scanOrder.push(abs);
13070
13206
  seen.add(abs);
13071
13207
  }
13072
- const parent = path13.dirname(abs);
13208
+ const parent = path14.dirname(abs);
13073
13209
  if (parent === abs) break;
13074
13210
  current = parent;
13075
13211
  }
13076
13212
  }
13077
13213
  for (const base of scanOrder) {
13078
- for (const docsDir of [path13.join(base, "docs"), base]) {
13079
- const configPath = path13.join(docsDir, ".lee-spec-kit.json");
13214
+ for (const docsDir of [path14.join(base, "docs"), base]) {
13215
+ const configPath = path14.join(docsDir, ".lee-spec-kit.json");
13080
13216
  if (fs.existsSync(configPath)) {
13081
13217
  try {
13082
13218
  const parsed = fs.readJsonSync(configPath);
@@ -13085,11 +13221,11 @@ function detectGithubCliLangSync(cwd) {
13085
13221
  } catch {
13086
13222
  }
13087
13223
  }
13088
- const agentsPath = path13.join(docsDir, "agents");
13089
- const featuresPath = path13.join(docsDir, "features");
13224
+ const agentsPath = path14.join(docsDir, "agents");
13225
+ const featuresPath = path14.join(docsDir, "features");
13090
13226
  if (!fs.existsSync(agentsPath) || !fs.existsSync(featuresPath)) continue;
13091
13227
  for (const probe of ["custom.md", "constitution.md", "agents.md"]) {
13092
- const file = path13.join(agentsPath, probe);
13228
+ const file = path14.join(agentsPath, probe);
13093
13229
  if (!fs.existsSync(file)) continue;
13094
13230
  try {
13095
13231
  const content = fs.readFileSync(file, "utf-8");
@@ -13109,13 +13245,13 @@ function parseLabels(raw, lang) {
13109
13245
  }
13110
13246
  return [...new Set(labels)];
13111
13247
  }
13112
- function escapeRegExp4(value) {
13248
+ function escapeRegExp5(value) {
13113
13249
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
13114
13250
  }
13115
13251
  function extractDraftMetadataValue(content, keys) {
13116
13252
  for (const key of keys) {
13117
13253
  const re = new RegExp(
13118
- `^\\s*-\\s*\\*\\*${escapeRegExp4(key)}\\*\\*\\s*:\\s*(.*?)\\s*$`,
13254
+ `^\\s*-\\s*\\*\\*${escapeRegExp5(key)}\\*\\*\\s*:\\s*(.*?)\\s*$`,
13119
13255
  "mi"
13120
13256
  );
13121
13257
  const match = content.match(re);
@@ -13194,7 +13330,7 @@ async function prepareGithubBody(params) {
13194
13330
  };
13195
13331
  }
13196
13332
  }
13197
- await fs.ensureDir(path13.dirname(defaultBodyFile));
13333
+ await fs.ensureDir(path14.dirname(defaultBodyFile));
13198
13334
  await fs.writeFile(defaultBodyFile, generatedBody, "utf-8");
13199
13335
  return {
13200
13336
  body: generatedBody,
@@ -13234,7 +13370,7 @@ function ensureSections(body, sections, kind, lang) {
13234
13370
  };
13235
13371
  const hasMetadataField = (field) => {
13236
13372
  const re = new RegExp(
13237
- `^\\s*-\\s*\\*\\*${escapeRegExp4(field)}\\*\\*\\s*:`,
13373
+ `^\\s*-\\s*\\*\\*${escapeRegExp5(field)}\\*\\*\\s*:`,
13238
13374
  "m"
13239
13375
  );
13240
13376
  return re.test(body);
@@ -13264,7 +13400,7 @@ function ensureSections(body, sections, kind, lang) {
13264
13400
  }
13265
13401
  function ensureDocsExist(docsDir, relativePaths, lang) {
13266
13402
  const missing = relativePaths.filter(
13267
- (relativePath) => !fs.existsSync(path13.join(docsDir, relativePath))
13403
+ (relativePath) => !fs.existsSync(path14.join(docsDir, relativePath))
13268
13404
  );
13269
13405
  if (missing.length > 0) {
13270
13406
  throw createCliError(
@@ -13274,18 +13410,18 @@ function ensureDocsExist(docsDir, relativePaths, lang) {
13274
13410
  }
13275
13411
  }
13276
13412
  function buildDefaultBodyFileName(kind, docsDir, component) {
13277
- const key = `${path13.resolve(docsDir)}::${component.trim().toLowerCase()}`;
13413
+ const key = `${path14.resolve(docsDir)}::${component.trim().toLowerCase()}`;
13278
13414
  const digest = createHash("sha1").update(key).digest("hex").slice(0, 12);
13279
13415
  return `lee-spec-kit.${digest}.${kind}.md`;
13280
13416
  }
13281
13417
  function toBodyFilePath(raw, kind, docsDir, component, lang) {
13282
- const selected = raw?.trim() || path13.join(os.tmpdir(), buildDefaultBodyFileName(kind, docsDir, component));
13418
+ const selected = raw?.trim() || path14.join(os.tmpdir(), buildDefaultBodyFileName(kind, docsDir, component));
13283
13419
  assertValid(
13284
13420
  validatePathWithLang(selected, lang),
13285
13421
  `github.${kind}.bodyFile`,
13286
13422
  lang
13287
13423
  );
13288
- return path13.resolve(selected);
13424
+ return path14.resolve(selected);
13289
13425
  }
13290
13426
  function toProjectRootDocsPath(relativePathFromDocs) {
13291
13427
  const normalized = relativePathFromDocs.replace(/\\/g, "/").replace(/^\.\//, "").replace(/^\/+/, "");
@@ -14122,7 +14258,7 @@ function stripMarkdownCodeContexts(body) {
14122
14258
  function hasIssueClosingKeyword(body, issueNumber) {
14123
14259
  if (!issueNumber) return false;
14124
14260
  const cleaned = stripMarkdownCodeContexts(body);
14125
- const issue = escapeRegExp4(issueNumber);
14261
+ const issue = escapeRegExp5(issueNumber);
14126
14262
  const closeKeywordRegex = new RegExp(
14127
14263
  `\\b(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?)\\b\\s*(?:[a-zA-Z0-9_.-]+\\/)?#\\s*${issue}\\b`,
14128
14264
  "i"
@@ -14340,7 +14476,7 @@ function ensureCleanWorktree(cwd, lang) {
14340
14476
  function commitAndPushPaths(cwd, absPaths, message, lang, options) {
14341
14477
  const uniqueRelativePaths = [
14342
14478
  ...new Set(
14343
- absPaths.filter((absPath) => !!absPath && fs.existsSync(absPath)).map((absPath) => path13.relative(cwd, absPath) || absPath)
14479
+ absPaths.filter((absPath) => !!absPath && fs.existsSync(absPath)).map((absPath) => path14.relative(cwd, absPath) || absPath)
14344
14480
  )
14345
14481
  ];
14346
14482
  if (uniqueRelativePaths.length === 0) return;
@@ -14536,15 +14672,15 @@ function githubCommand(program2) {
14536
14672
  config.lang
14537
14673
  );
14538
14674
  const specContent = await fs.readFile(
14539
- path13.join(config.docsDir, paths.specPath),
14675
+ path14.join(config.docsDir, paths.specPath),
14540
14676
  "utf-8"
14541
14677
  );
14542
14678
  const planContent = await fs.readFile(
14543
- path13.join(config.docsDir, paths.planPath),
14679
+ path14.join(config.docsDir, paths.planPath),
14544
14680
  "utf-8"
14545
14681
  );
14546
14682
  const tasksContent = await fs.readFile(
14547
- path13.join(config.docsDir, paths.tasksPath),
14683
+ path14.join(config.docsDir, paths.tasksPath),
14548
14684
  "utf-8"
14549
14685
  );
14550
14686
  const overview = resolveOverviewFromSpec(
@@ -14587,7 +14723,7 @@ function githubCommand(program2) {
14587
14723
  create: options.create,
14588
14724
  explicitBodyFile,
14589
14725
  defaultBodyFile,
14590
- workflowDraftPath: path13.join(config.docsDir, paths.issuePath),
14726
+ workflowDraftPath: path14.join(config.docsDir, paths.issuePath),
14591
14727
  generatedBody,
14592
14728
  requiredSections: getRequiredIssueSections(config.lang),
14593
14729
  kindLabel: tg(config.lang, "kindIssue"),
@@ -14603,7 +14739,7 @@ function githubCommand(program2) {
14603
14739
  `${feature.type}-issue-sanitized`,
14604
14740
  config.lang
14605
14741
  );
14606
- await fs.ensureDir(path13.dirname(sanitizedBodyFile));
14742
+ await fs.ensureDir(path14.dirname(sanitizedBodyFile));
14607
14743
  await fs.writeFile(sanitizedBodyFile, body, "utf-8");
14608
14744
  bodyFile = sanitizedBodyFile;
14609
14745
  }
@@ -14652,12 +14788,12 @@ function githubCommand(program2) {
14652
14788
  const syncedIssueNumber = extractIssueNumberFromUrl(issueUrl);
14653
14789
  if (syncedIssueNumber) {
14654
14790
  const synced = syncTasksIssueMetadata(
14655
- path13.join(config.docsDir, paths.tasksPath),
14791
+ path14.join(config.docsDir, paths.tasksPath),
14656
14792
  syncedIssueNumber,
14657
14793
  config.lang
14658
14794
  );
14659
14795
  const draftSynced = syncIssueDraftMetadata(
14660
- path13.join(config.docsDir, paths.issuePath),
14796
+ path14.join(config.docsDir, paths.issuePath),
14661
14797
  syncedIssueNumber
14662
14798
  );
14663
14799
  syncChanged = synced.changed || draftSynced.changed;
@@ -14768,13 +14904,13 @@ function githubCommand(program2) {
14768
14904
  config.lang
14769
14905
  );
14770
14906
  const specContent = await fs.readFile(
14771
- path13.join(config.docsDir, paths.specPath),
14907
+ path14.join(config.docsDir, paths.specPath),
14772
14908
  "utf-8"
14773
14909
  );
14774
- const planPath = path13.join(config.docsDir, paths.planPath);
14910
+ const planPath = path14.join(config.docsDir, paths.planPath);
14775
14911
  const planContent = await fs.pathExists(planPath) ? await fs.readFile(planPath, "utf-8") : "";
14776
14912
  const tasksContent = await fs.readFile(
14777
- path13.join(config.docsDir, paths.tasksPath),
14913
+ path14.join(config.docsDir, paths.tasksPath),
14778
14914
  "utf-8"
14779
14915
  );
14780
14916
  const overview = resolveOverviewFromSpec(
@@ -14822,7 +14958,7 @@ function githubCommand(program2) {
14822
14958
  create: options.create,
14823
14959
  explicitBodyFile,
14824
14960
  defaultBodyFile,
14825
- workflowDraftPath: path13.join(config.docsDir, paths.prPath),
14961
+ workflowDraftPath: path14.join(config.docsDir, paths.prPath),
14826
14962
  generatedBody,
14827
14963
  requiredSections: getRequiredPrSections(config.lang),
14828
14964
  kindLabel: tg(config.lang, "kindPr"),
@@ -14840,7 +14976,7 @@ function githubCommand(program2) {
14840
14976
  `${feature.type}-pr-sanitized`,
14841
14977
  config.lang
14842
14978
  );
14843
- await fs.ensureDir(path13.dirname(sanitizedBodyFile));
14979
+ await fs.ensureDir(path14.dirname(sanitizedBodyFile));
14844
14980
  await fs.writeFile(sanitizedBodyFile, body, "utf-8");
14845
14981
  bodyFile = sanitizedBodyFile;
14846
14982
  }
@@ -14868,7 +15004,7 @@ function githubCommand(program2) {
14868
15004
  if (preparedBody.source === "generated") {
14869
15005
  await fs.writeFile(bodyFile, body, "utf-8");
14870
15006
  } else {
14871
- await fs.ensureDir(path13.dirname(fallbackBodyFile));
15007
+ await fs.ensureDir(path14.dirname(fallbackBodyFile));
14872
15008
  await fs.writeFile(fallbackBodyFile, body, "utf-8");
14873
15009
  bodyFile = fallbackBodyFile;
14874
15010
  }
@@ -14929,13 +15065,13 @@ function githubCommand(program2) {
14929
15065
  }
14930
15066
  if (prUrl && options.syncTasks !== false) {
14931
15067
  const syncedTasks = syncTasksPrMetadata(
14932
- path13.join(config.docsDir, paths.tasksPath),
15068
+ path14.join(config.docsDir, paths.tasksPath),
14933
15069
  prUrl,
14934
15070
  "Review",
14935
15071
  config.lang
14936
15072
  );
14937
15073
  const syncedDraft = syncPrDraftMetadata(
14938
- path13.join(config.docsDir, paths.prPath),
15074
+ path14.join(config.docsDir, paths.prPath),
14939
15075
  prUrl,
14940
15076
  "Review"
14941
15077
  );
@@ -14976,13 +15112,13 @@ function githubCommand(program2) {
14976
15112
  mergeAlreadyMerged = merged.alreadyMerged;
14977
15113
  if (prUrl && options.syncTasks !== false) {
14978
15114
  const mergedTasksSync = syncTasksPrMetadata(
14979
- path13.join(config.docsDir, paths.tasksPath),
15115
+ path14.join(config.docsDir, paths.tasksPath),
14980
15116
  prUrl,
14981
15117
  "Approved",
14982
15118
  config.lang
14983
15119
  );
14984
15120
  const mergedDraftSync = syncPrDraftMetadata(
14985
- path13.join(config.docsDir, paths.prPath),
15121
+ path14.join(config.docsDir, paths.prPath),
14986
15122
  prUrl,
14987
15123
  "Approved"
14988
15124
  );
@@ -15253,7 +15389,7 @@ function docsCommand(program2) {
15253
15389
  );
15254
15390
  return;
15255
15391
  }
15256
- const relativeFromCwd = path13.relative(process.cwd(), loaded.entry.absolutePath);
15392
+ const relativeFromCwd = path14.relative(process.cwd(), loaded.entry.absolutePath);
15257
15393
  console.log();
15258
15394
  console.log(chalk9.bold(`\u{1F4C4} ${loaded.entry.id}: ${loaded.entry.title}`));
15259
15395
  console.log(
@@ -15333,7 +15469,7 @@ function detectCommand(program2) {
15333
15469
  }
15334
15470
  async function runDetect(options) {
15335
15471
  const cwd = process.cwd();
15336
- const targetCwd = options.dir ? path13.resolve(cwd, options.dir) : cwd;
15472
+ const targetCwd = options.dir ? path14.resolve(cwd, options.dir) : cwd;
15337
15473
  const config = await getConfig(targetCwd);
15338
15474
  const detected = !!config;
15339
15475
  const reasonCode = detected ? "PROJECT_DETECTED" : "PROJECT_NOT_DETECTED";
@@ -15360,7 +15496,7 @@ async function runDetect(options) {
15360
15496
  );
15361
15497
  return;
15362
15498
  }
15363
- const configPath2 = path13.join(config.docsDir, ".lee-spec-kit.json");
15499
+ const configPath2 = path14.join(config.docsDir, ".lee-spec-kit.json");
15364
15500
  const configFilePresent2 = await fs.pathExists(configPath2);
15365
15501
  const detectionSource2 = configFilePresent2 ? "config" : "heuristic";
15366
15502
  console.log(
@@ -15394,7 +15530,7 @@ async function runDetect(options) {
15394
15530
  console.log();
15395
15531
  return;
15396
15532
  }
15397
- const configPath = path13.join(config.docsDir, ".lee-spec-kit.json");
15533
+ const configPath = path14.join(config.docsDir, ".lee-spec-kit.json");
15398
15534
  const configFilePresent = await fs.pathExists(configPath);
15399
15535
  const detectionSource = configFilePresent ? "config" : "heuristic";
15400
15536
  console.log(chalk9.green(`- ${tr(lang, "cli", "detect.resultDetected")}`));
@@ -15471,19 +15607,19 @@ function hasTemplateMarkers(content) {
15471
15607
  return patterns.some((pattern) => pattern.test(content));
15472
15608
  }
15473
15609
  async function countFeatureDirs(ctx, docsDir, projectType) {
15474
- const featuresRoot = path13.join(docsDir, "features");
15610
+ const featuresRoot = path14.join(docsDir, "features");
15475
15611
  if (projectType === "single") {
15476
15612
  const dirs = await listSubdirectories(ctx.fs, featuresRoot);
15477
- return dirs.filter((value) => path13.basename(value) !== "feature-base").length;
15613
+ return dirs.filter((value) => path14.basename(value) !== "feature-base").length;
15478
15614
  }
15479
15615
  const components = await listSubdirectories(ctx.fs, featuresRoot);
15480
15616
  let total = 0;
15481
15617
  for (const componentDir of components) {
15482
- const componentName = path13.basename(componentDir).trim().toLowerCase();
15618
+ const componentName = path14.basename(componentDir).trim().toLowerCase();
15483
15619
  if (!componentName || componentName === "feature-base") continue;
15484
15620
  const dirs = await listSubdirectories(ctx.fs, componentDir);
15485
15621
  total += dirs.filter(
15486
- (value) => path13.basename(value) !== "feature-base"
15622
+ (value) => path14.basename(value) !== "feature-base"
15487
15623
  ).length;
15488
15624
  }
15489
15625
  return total;
@@ -15495,7 +15631,7 @@ async function hasUserPrdFile(ctx, prdDir) {
15495
15631
  ignoreDirs: ["node_modules"]
15496
15632
  });
15497
15633
  return files.some(
15498
- (absolutePath) => path13.basename(absolutePath).toLowerCase() !== "readme.md"
15634
+ (absolutePath) => path14.basename(absolutePath).toLowerCase() !== "readme.md"
15499
15635
  );
15500
15636
  }
15501
15637
  function finalizeChecks(checks) {
@@ -15664,7 +15800,7 @@ async function runOnboardChecks(ctx) {
15664
15800
  });
15665
15801
  }
15666
15802
  }
15667
- const constitutionPath = path13.join(docsDir, "agents", "constitution.md");
15803
+ const constitutionPath = path14.join(docsDir, "agents", "constitution.md");
15668
15804
  if (!await fs.pathExists(constitutionPath)) {
15669
15805
  checks.push({
15670
15806
  id: "constitution_exists",
@@ -15706,7 +15842,7 @@ async function runOnboardChecks(ctx) {
15706
15842
  });
15707
15843
  }
15708
15844
  }
15709
- const customPath = path13.join(docsDir, "agents", "custom.md");
15845
+ const customPath = path14.join(docsDir, "agents", "custom.md");
15710
15846
  if (await fs.pathExists(customPath)) {
15711
15847
  const content = await fs.readFile(customPath, "utf-8");
15712
15848
  if (hasTemplateMarkers(content)) {
@@ -15735,7 +15871,7 @@ async function runOnboardChecks(ctx) {
15735
15871
  });
15736
15872
  }
15737
15873
  }
15738
- const prdDir = path13.join(docsDir, "prd");
15874
+ const prdDir = path14.join(docsDir, "prd");
15739
15875
  const featureCount = await countFeatureDirs(ctx, docsDir, config.projectType);
15740
15876
  const prdReady = await hasUserPrdFile(ctx, prdDir);
15741
15877
  if (!prdReady) {
@@ -15753,7 +15889,7 @@ async function runOnboardChecks(ctx) {
15753
15889
  "PRD is empty. If features already exist, fill PRD as soon as possible."
15754
15890
  ),
15755
15891
  path: prdDir,
15756
- suggestedCommand: `touch ${quotePath(path13.join(prdDir, `${toSlug(config.projectName || "project")}-prd.md`))}`
15892
+ suggestedCommand: `touch ${quotePath(path14.join(prdDir, `${toSlug(config.projectName || "project")}-prd.md`))}`
15757
15893
  });
15758
15894
  } else {
15759
15895
  checks.push({
@@ -16191,7 +16327,7 @@ var PrePrReviewValidator = class {
16191
16327
  return result.evidence;
16192
16328
  }
16193
16329
  async validateEvidenceWithScope(evidencePath, projectRoot) {
16194
- const fullPath = path13.resolve(evidencePath);
16330
+ const fullPath = path14.resolve(evidencePath);
16195
16331
  if (!await fs.pathExists(fullPath)) {
16196
16332
  throw createCliError(
16197
16333
  "INVALID_ARGUMENT",
@@ -16289,9 +16425,9 @@ var PrePrReviewValidator = class {
16289
16425
  ]);
16290
16426
  const reviewedFiles = new Set(
16291
16427
  normalizedEvidence.files.map(
16292
- (f) => path13.relative(
16428
+ (f) => path14.relative(
16293
16429
  projectRoot,
16294
- path13.resolve(projectRoot, f.path)
16430
+ path14.resolve(projectRoot, f.path)
16295
16431
  )
16296
16432
  ).map((entry) => normalizeGitPath3(entry)).filter(Boolean)
16297
16433
  );
@@ -16487,7 +16623,7 @@ var DEFAULT_EVIDENCE_FOR_ANY_MODE = {
16487
16623
  residualRisks: ["none"],
16488
16624
  commandsExecuted: []
16489
16625
  };
16490
- function escapeRegExp5(value) {
16626
+ function escapeRegExp6(value) {
16491
16627
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
16492
16628
  }
16493
16629
  function normalizeDecision(raw) {
@@ -16501,14 +16637,14 @@ function normalizeDecision(raw) {
16501
16637
  return null;
16502
16638
  }
16503
16639
  function findSpecLineIndex(lines, keys) {
16504
- const escaped = keys.map((key) => escapeRegExp5(key));
16640
+ const escaped = keys.map((key) => escapeRegExp6(key));
16505
16641
  const re = new RegExp(
16506
16642
  `^\\s*-\\s*\\*\\*(?:${escaped.join("|")})\\*\\*\\s*:\\s*`
16507
16643
  );
16508
16644
  return lines.findIndex((line) => re.test(line));
16509
16645
  }
16510
16646
  function replaceSpecLine(line, keys, preferredKey, value) {
16511
- const escaped = keys.map((key) => escapeRegExp5(key));
16647
+ const escaped = keys.map((key) => escapeRegExp6(key));
16512
16648
  const re = new RegExp(
16513
16649
  `^(\\s*-\\s*\\*\\*)(?:${escaped.join("|")})(\\*\\*\\s*:\\s*)(.*)$`
16514
16650
  );
@@ -16752,7 +16888,7 @@ async function runPrePrReviewRun(featureName, options) {
16752
16888
  );
16753
16889
  const policy = resolvePrePrReviewPolicy(config.workflow);
16754
16890
  const preferred = getPreferredKeys(config.lang);
16755
- const tasksPath = path13.join(feature.path, "tasks.md");
16891
+ const tasksPath = path14.join(feature.path, "tasks.md");
16756
16892
  let tasksUpdated = false;
16757
16893
  if (await fs.pathExists(tasksPath)) {
16758
16894
  const tasksContent = await fs.readFile(tasksPath, "utf-8");
@@ -16799,8 +16935,6 @@ async function runPrePrReviewRun(featureName, options) {
16799
16935
  handoffOnly: true,
16800
16936
  advancesWorkflow: false,
16801
16937
  reuseKey: `pre-pr:${featureRef}`,
16802
- suggestedParallelism: 1,
16803
- fallbackToMainAgentWhenQuotaExceeded: true,
16804
16938
  nextStepRequirement: "generate_review_trace_then_record",
16805
16939
  delegatedWorkRequired: true,
16806
16940
  nextMainState: "pre_pr_review_in_progress",
@@ -16863,7 +16997,7 @@ async function runPrePrReview(featureName, options) {
16863
16997
  `tasks.md not found for feature: ${feature.folderName}`
16864
16998
  );
16865
16999
  }
16866
- const tasksPath = path13.join(feature.path, "tasks.md");
17000
+ const tasksPath = path14.join(feature.path, "tasks.md");
16867
17001
  const tasksContent = await fs.readFile(tasksPath, "utf-8");
16868
17002
  const policy = resolvePrePrReviewPolicy(config.workflow);
16869
17003
  const preferred = getPreferredKeys(config.lang);
@@ -16961,7 +17095,7 @@ async function runPrePrReview(featureName, options) {
16961
17095
  }
16962
17096
  }
16963
17097
  }
16964
- const decisionsPath = path13.join(feature.path, "decisions.md");
17098
+ const decisionsPath = path14.join(feature.path, "decisions.md");
16965
17099
  const decisionLogEntry = buildReportContent({
16966
17100
  folderName: feature.folderName,
16967
17101
  date,
@@ -16977,9 +17111,9 @@ async function runPrePrReview(featureName, options) {
16977
17111
  await fs.writeFile(decisionsPath, nextDecisions, "utf-8");
16978
17112
  }
16979
17113
  const decisionsPathFromDocs = normalizePathForDoc(
16980
- path13.join(feature.docs.featurePathFromDocs, "decisions.md")
17114
+ path14.join(feature.docs.featurePathFromDocs, "decisions.md")
16981
17115
  );
16982
- const evidencePath = path13.basename(config.docsDir) === "docs" ? normalizePathForDoc(path13.join("docs", decisionsPathFromDocs)) : decisionsPathFromDocs;
17116
+ const evidencePath = path14.basename(config.docsDir) === "docs" ? normalizePathForDoc(path14.join("docs", decisionsPathFromDocs)) : decisionsPathFromDocs;
16983
17117
  let nextTasks = tasksContent;
16984
17118
  nextTasks = upsertSpecLine(
16985
17119
  nextTasks,
@@ -17034,18 +17168,18 @@ async function runPrePrReview(featureName, options) {
17034
17168
  }
17035
17169
  console.log();
17036
17170
  }
17037
- function escapeRegExp6(value) {
17171
+ function escapeRegExp7(value) {
17038
17172
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
17039
17173
  }
17040
17174
  function findSpecLineIndex2(lines, keys) {
17041
- const escaped = keys.map((key) => escapeRegExp6(key));
17175
+ const escaped = keys.map((key) => escapeRegExp7(key));
17042
17176
  const re = new RegExp(
17043
17177
  `^\\s*-\\s*\\*\\*(?:${escaped.join("|")})\\*\\*\\s*:\\s*`
17044
17178
  );
17045
17179
  return lines.findIndex((line) => re.test(line));
17046
17180
  }
17047
17181
  function replaceSpecLine2(line, keys, preferredKey, value) {
17048
- const escaped = keys.map((key) => escapeRegExp6(key));
17182
+ const escaped = keys.map((key) => escapeRegExp7(key));
17049
17183
  const re = new RegExp(
17050
17184
  `^(\\s*-\\s*\\*\\*)(?:${escaped.join("|")})(\\*\\*\\s*:\\s*)(.*)$`
17051
17185
  );
@@ -17120,7 +17254,7 @@ async function runCodeReviewRun(featureName, options) {
17120
17254
  );
17121
17255
  }
17122
17256
  const feature = state.matchedFeature;
17123
- const tasksPath = path13.join(feature.path, "tasks.md");
17257
+ const tasksPath = path14.join(feature.path, "tasks.md");
17124
17258
  let tasksUpdated = false;
17125
17259
  if (await fs.pathExists(tasksPath)) {
17126
17260
  const tasksContent = await fs.readFile(tasksPath, "utf-8");
@@ -17150,12 +17284,10 @@ async function runCodeReviewRun(featureName, options) {
17150
17284
  handoffOnly: true,
17151
17285
  advancesWorkflow: false,
17152
17286
  reuseKey: `code-review:${feature.folderName}`,
17153
- suggestedParallelism: 1,
17154
- fallbackToMainAgentWhenQuotaExceeded: true,
17155
17287
  nextMainState: "code_review_running",
17156
17288
  tasksUpdated,
17157
17289
  tasksPath,
17158
- decisionsPath: path13.join(feature.path, "decisions.md"),
17290
+ decisionsPath: path14.join(feature.path, "decisions.md"),
17159
17291
  prompt,
17160
17292
  recordedAt: getLocalDateString()
17161
17293
  };
@@ -17173,12 +17305,6 @@ async function runCodeReviewRun(featureName, options) {
17173
17305
  console.log(chalk9.gray(`- substate: ${payload.substateId}`));
17174
17306
  console.log(chalk9.gray(`- owner: ${payload.owner}`));
17175
17307
  console.log(chalk9.gray(`- reuse key: ${payload.reuseKey}`));
17176
- console.log(chalk9.gray(`- suggested parallelism: ${payload.suggestedParallelism}`));
17177
- console.log(
17178
- chalk9.gray(
17179
- `- quota fallback: ${payload.fallbackToMainAgentWhenQuotaExceeded ? "continue in main agent" : "none"}`
17180
- )
17181
- );
17182
17308
  console.log(chalk9.gray(`- next main state: ${payload.nextMainState}`));
17183
17309
  if (tasksUpdated) {
17184
17310
  console.log(chalk9.gray(`- tasks.md updated: ${payload.tasksPath}`));
@@ -17280,7 +17406,7 @@ async function runRequirements(options) {
17280
17406
  }
17281
17407
  for (const feature of scan.features) {
17282
17408
  if (!feature.docs.tasksExists) continue;
17283
- const tasksPath = path13.join(feature.path, "tasks.md");
17409
+ const tasksPath = path14.join(feature.path, "tasks.md");
17284
17410
  let tasksContent = "";
17285
17411
  try {
17286
17412
  tasksContent = await ctx.fs.readFile(tasksPath, "utf-8");
@@ -17414,7 +17540,7 @@ async function runRequirements(options) {
17414
17540
  process.stdout.write(`${lines.join("\n")}
17415
17541
  `);
17416
17542
  if (options.write) {
17417
- const outputPath = path13.join(docsDir, "prd", "status.md");
17543
+ const outputPath = path14.join(docsDir, "prd", "status.md");
17418
17544
  await ctx.fs.writeFile(outputPath, `${lines.join("\n")}
17419
17545
  `, "utf-8");
17420
17546
  console.log(chalk9.green(`\u2705 wrote: ${outputPath}`));
@@ -17499,7 +17625,7 @@ async function resolveTaskRunContext(featureName, options) {
17499
17625
  }
17500
17626
  async function runTaskRun(featureName, options) {
17501
17627
  const { config, feature } = await resolveTaskRunContext(featureName, options);
17502
- const tasksPath = path13.join(feature.path, "tasks.md");
17628
+ const tasksPath = path14.join(feature.path, "tasks.md");
17503
17629
  if (!await fs.pathExists(tasksPath)) {
17504
17630
  throw createCliError(
17505
17631
  "PRECONDITION_FAILED",
@@ -17556,8 +17682,6 @@ async function runTaskRun(featureName, options) {
17556
17682
  owner: "subagent",
17557
17683
  handoffOnly: true,
17558
17684
  reuseKey: `task:${feature.folderName}:${resolvedTask.taskId}`,
17559
- suggestedParallelism: 1,
17560
- fallbackToMainAgentWhenQuotaExceeded: true,
17561
17685
  nextMainState: "task_complete",
17562
17686
  tasksUpdated,
17563
17687
  tasksPath,
@@ -17573,12 +17697,6 @@ async function runTaskRun(featureName, options) {
17573
17697
  console.log(chalk9.gray(`- substate: ${payload.substateId}`));
17574
17698
  console.log(chalk9.gray(`- owner: ${payload.owner}`));
17575
17699
  console.log(chalk9.gray(`- reuse key: ${payload.reuseKey}`));
17576
- console.log(chalk9.gray(`- suggested parallelism: ${payload.suggestedParallelism}`));
17577
- console.log(
17578
- chalk9.gray(
17579
- `- quota fallback: ${payload.fallbackToMainAgentWhenQuotaExceeded ? "continue in main agent" : "none"}`
17580
- )
17581
- );
17582
17700
  console.log(chalk9.gray(`- next main state: ${payload.nextMainState}`));
17583
17701
  if (tasksUpdated) {
17584
17702
  console.log();
@@ -17658,7 +17776,7 @@ async function resolveTaskCompleteContext(featureName, options) {
17658
17776
  }
17659
17777
  async function runTaskComplete(featureName, options) {
17660
17778
  const { feature } = await resolveTaskCompleteContext(featureName, options);
17661
- const tasksPath = path13.join(feature.path, "tasks.md");
17779
+ const tasksPath = path14.join(feature.path, "tasks.md");
17662
17780
  if (!await fs.pathExists(tasksPath)) {
17663
17781
  throw createCliError(
17664
17782
  "PRECONDITION_FAILED",
@@ -17797,11 +17915,11 @@ ${version}
17797
17915
  }
17798
17916
  return `${ascii}${footer}`;
17799
17917
  }
17800
- var CACHE_FILE = path13.join(os.homedir(), ".lee-spec-kit-version-cache.json");
17918
+ var CACHE_FILE = path14.join(os.homedir(), ".lee-spec-kit-version-cache.json");
17801
17919
  var CHECK_INTERVAL = 24 * 60 * 60 * 1e3;
17802
17920
  function getCurrentVersion() {
17803
17921
  try {
17804
- const packageJsonPath = path13.join(__dirname$1, "..", "package.json");
17922
+ const packageJsonPath = path14.join(__dirname$1, "..", "package.json");
17805
17923
  if (fs.existsSync(packageJsonPath)) {
17806
17924
  const pkg = fs.readJsonSync(packageJsonPath);
17807
17925
  return pkg.version;
@@ -17905,7 +18023,7 @@ function shouldCheckForUpdates() {
17905
18023
  if (shouldCheckForUpdates()) checkForUpdates();
17906
18024
  function getCliVersion() {
17907
18025
  try {
17908
- const packageJsonPath = path13.join(__dirname$1, "..", "package.json");
18026
+ const packageJsonPath = path14.join(__dirname$1, "..", "package.json");
17909
18027
  if (fs.existsSync(packageJsonPath)) {
17910
18028
  const pkg = fs.readJsonSync(packageJsonPath);
17911
18029
  if (pkg?.version) return String(pkg.version);