lee-spec-kit 0.6.24 → 0.6.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -163,6 +163,9 @@ var ko = {
163
163
  "context.suggestionHeader": "\uCD94\uCC9C \uB2E4\uC74C \uC120\uD0DD\uC9C0",
164
164
  "context.suggestionCommandHint": "\uB77C\uBCA8 \uCC38\uACE0 \uBA85\uB839: {command}",
165
165
  "context.suggestionFinalPrompt": "\uD604\uC7AC \uCD94\uCC9C \uB77C\uBCA8: {labels}. \uC751\uB2F5\uC740 \uB77C\uBCA8 \uD1A0\uD070 \uD3EC\uD568 \uD615\uC2DD\uC73C\uB85C \uD574\uC8FC\uC138\uC694. (\uC608: {example}, `A \uC9C4\uD589\uD574`)",
166
+ "context.autoRunUnavailable": "\uD604\uC7AC \uCEE8\uD14D\uC2A4\uD2B8\uC5D0\uC11C\uB294 \uC790\uB3D9 \uC2E4\uD589\uC744 \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
167
+ "context.autoRunSummary": "config \uAE30\uC900\uC73C\uB85C \uC2B9\uC778 \uD544\uC694 \uCE74\uD14C\uACE0\uB9AC \uC804\uAE4C\uC9C0 \uC5F0\uC18D \uC2E4\uD589\uD558\uC138\uC694: {categories}",
168
+ "context.autoRunCommandHint": "\uC790\uB3D9 \uC2E4\uD589 \uBA85\uB839(config \uAC8C\uC774\uD2B8): {command}",
166
169
  "context.commandDetail.branchCreateWithWorktree": "({scope}) worktree {worktree}\uB97C \uC0AC\uC6A9\uD574 \uBE0C\uB79C\uCE58 {branch}\uB97C \uC0DD\uC131\uD558\uAC70\uB098 \uC7AC\uC0AC\uC6A9\uD558\uC138\uC694",
167
170
  "context.commandDetail.branchCreateWithBranch": "({scope}) \uBE0C\uB79C\uCE58 {branch}\uC6A9 worktree\uB97C \uC0DD\uC131\uD558\uAC70\uB098 \uC7AC\uC0AC\uC6A9\uD558\uC138\uC694",
168
171
  "context.commandDetail.branchCreateGeneric": "({scope}) feature \uBE0C\uB79C\uCE58\uC6A9 worktree\uB97C \uC0DD\uC131\uD558\uAC70\uB098 \uC7AC\uC0AC\uC6A9\uD558\uC138\uC694",
@@ -492,8 +495,8 @@ var ko = {
492
495
  worktreeCleanupCommand: 'cd "{projectGitCwd}" && git worktree remove "{worktreePath}" && git worktree prune && CURRENT_BRANCH=$(git branch --show-current) && DEFAULT_BRANCH=$(git symbolic-ref --quiet --short refs/remotes/origin/HEAD 2>/dev/null | cut -d/ -f2-) && TARGET_BRANCH="${DEFAULT_BRANCH:-$CURRENT_BRANCH}" && if [ -n "$TARGET_BRANCH" ]; then git checkout "$TARGET_BRANCH" >/dev/null 2>&1 || true; fi && if git rev-parse --abbrev-ref --symbolic-full-name "@{u}" >/dev/null 2>&1 && [ -z "$(git status --porcelain)" ]; then git pull --ff-only || true; fi',
493
496
  tasksAllDoneButNoChecklist: '\uC644\uB8CC \uC870\uAC74 \uCCB4\uD06C\uB9AC\uC2A4\uD2B8\uB97C \uC791\uC131\uD558\uC138\uC694. tasks.md\uC758 "\uC644\uB8CC \uC870\uAC74" \uC139\uC158\uC5D0 \uAC80\uC99D \uD56D\uBAA9\uC744 \uCD94\uAC00\uD558\uACE0, \uC0AC\uC6A9\uC790\uC640 \uD655\uC778 \uD6C4 \uCDA9\uC871 \uD56D\uBAA9\uC744 [x]\uB85C \uCCB4\uD06C\uD558\uC138\uC694. \uCD5C\uC885 \uC2B9\uC778(OK)\uB3C4 \uBC18\uC601\uD558\uC138\uC694.',
494
497
  tasksAllDoneButChecklist: "\uC644\uB8CC \uC870\uAC74 \uCCB4\uD06C\uB9AC\uC2A4\uD2B8\uC758 \uB0A8\uC740 \uD56D\uBAA9\uC744 \uC9C4\uD589\uD558\uC138\uC694. \uD604\uC7AC \uC9C4\uD589: ({checked}/{total}) \uC0AC\uC6A9\uC790\uC640 \uD655\uC778 \uD6C4 \uCDA9\uC871 \uD56D\uBAA9\uC744 [x]\uB85C \uCCB4\uD06C\uD558\uACE0 \uCD5C\uC885 \uC2B9\uC778(OK)\uC744 \uBC18\uC601\uD558\uC138\uC694.",
495
- finishDoingTask: '\uD604\uC7AC DOING/REVIEW \uD0DC\uC2A4\uD06C\uB97C \uC218\uD589\uD558\uC138\uC694: "{title}" ({done}/{total}) \uC644\uB8CC \uC2DC \uACB0\uACFC/\uAC80\uC99D\uC744 \uACF5\uC720\uD558\uACE0 \uC2B9\uC778(`A` \uB610\uB294 `A OK` \uD615\uC2DD)\uC744 \uBC1B\uC740 \uB4A4 DONE \uCC98\uB9AC',
496
- startNextTodoTask: '\uB2E4\uC74C TODO \uD0DC\uC2A4\uD06C\uB97C \uC2DC\uC791\uD569\uB2C8\uB2E4: "{title}" ({done}/{total}) \uC2B9\uC778(`A` \uB610\uB294 `A OK` \uD615\uC2DD) \uD6C4 DOING \uCC98\uB9AC',
498
+ finishDoingTask: '\uD604\uC7AC DOING/REVIEW \uD0DC\uC2A4\uD06C\uB97C \uC218\uD589\uD558\uC138\uC694: "{title}" ({done}/{total}) \uC644\uB8CC \uC2DC \uACB0\uACFC/\uAC80\uC99D\uC744 \uACF5\uC720\uD558\uACE0 DONE \uCC98\uB9AC',
499
+ startNextTodoTask: '\uB2E4\uC74C TODO \uD0DC\uC2A4\uD06C\uB97C \uC2DC\uC791\uD569\uB2C8\uB2E4: "{title}" ({done}/{total}) \uC791\uC5C5\uC744 \uC2DC\uC791\uD558\uBA74 DOING \uCC98\uB9AC',
497
500
  checkTaskStatuses: "\uD0DC\uC2A4\uD06C \uC0C1\uD0DC\uB97C \uD655\uC778\uD558\uC138\uC694. ({done}/{total})",
498
501
  taskCommitGateStrictBlock: "\uB2E4\uC74C TODO \uD0DC\uC2A4\uD06C\uB85C \uB118\uC5B4\uAC00\uAE30 \uC804\uC5D0 `1 \uD0DC\uC2A4\uD06C = 1 \uCEE4\uBC0B` \uADDC\uCE59\uC744 \uCDA9\uC871\uD574\uC57C \uD569\uB2C8\uB2E4. \uC810\uAC80 \uACB0\uACFC: {reason}. \uD0DC\uC2A4\uD06C \uCEE4\uBC0B \uB2E8\uC704\uB97C \uC815\uB9AC\uD55C \uB4A4 \uB2E4\uC2DC \uC9C4\uD589\uD558\uC138\uC694.",
499
502
  taskCommitGateWarnProceed: "\u26A0\uFE0F \uD0DC\uC2A4\uD06C \uCEE4\uBC0B \uB2E8\uC704 \uC810\uAC80 \uACBD\uACE0: {reason}. \uD604\uC7AC\uB294 \uC9C4\uD589 \uAC00\uB2A5\uD558\uC9C0\uB9CC `1 \uD0DC\uC2A4\uD06C = 1 \uCEE4\uBC0B`\uC744 \uAD8C\uC7A5\uD569\uB2C8\uB2E4.",
@@ -650,6 +653,9 @@ var en = {
650
653
  "context.suggestionHeader": "Suggested Next Options",
651
654
  "context.suggestionCommandHint": "Reference command: {command}",
652
655
  "context.suggestionFinalPrompt": "Recommended labels now: {labels}. Please reply with a format that includes a label token. (e.g. {example}, `A proceed`)",
656
+ "context.autoRunUnavailable": "Auto-run is not available in the current context.",
657
+ "context.autoRunSummary": "Run continuously by config until approval-required categories appear: {categories}",
658
+ "context.autoRunCommandHint": "Auto-run command (config-based gate): {command}",
653
659
  "context.commandDetail.branchCreateWithWorktree": "({scope}) create or reuse worktree {worktree} for branch {branch}",
654
660
  "context.commandDetail.branchCreateWithBranch": "({scope}) create or reuse worktree for branch {branch}",
655
661
  "context.commandDetail.branchCreateGeneric": "({scope}) create or reuse feature branch worktree",
@@ -979,8 +985,8 @@ var en = {
979
985
  worktreeCleanupCommand: 'cd "{projectGitCwd}" && git worktree remove "{worktreePath}" && git worktree prune && CURRENT_BRANCH=$(git branch --show-current) && DEFAULT_BRANCH=$(git symbolic-ref --quiet --short refs/remotes/origin/HEAD 2>/dev/null | cut -d/ -f2-) && TARGET_BRANCH="${DEFAULT_BRANCH:-$CURRENT_BRANCH}" && if [ -n "$TARGET_BRANCH" ]; then git checkout "$TARGET_BRANCH" >/dev/null 2>&1 || true; fi && if git rev-parse --abbrev-ref --symbolic-full-name "@{u}" >/dev/null 2>&1 && [ -z "$(git status --porcelain)" ]; then git pull --ff-only || true; fi',
980
986
  tasksAllDoneButNoChecklist: 'Create the completion checklist. Add verification items to the tasks.md "Completion Criteria" section, then mark satisfied items as [x] after user confirmation. Record final approval (OK) as well.',
981
987
  tasksAllDoneButChecklist: "Proceed with remaining completion checklist items. Current progress: ({checked}/{total}) Mark items as [x] only after user confirmation and real verification. Record final approval (OK) as well.",
982
- finishDoingTask: 'Continue working on the current DOING/REVIEW task: "{title}" ({done}/{total}) After it is complete, share outcome/verification and get approval before marking DONE',
983
- startNextTodoTask: 'Start the next TODO task: "{title}" ({done}/{total}) Get approval (`A` or `A OK`) before marking DOING',
988
+ finishDoingTask: 'Continue working on the current DOING/REVIEW task: "{title}" ({done}/{total}) After it is complete, share outcome/verification and mark it DONE',
989
+ startNextTodoTask: 'Start the next TODO task: "{title}" ({done}/{total}) Mark it DOING when you begin work',
984
990
  checkTaskStatuses: "Check task statuses. ({done}/{total})",
985
991
  taskCommitGateStrictBlock: "Before moving to the next TODO task, you must satisfy the `1 task = 1 commit` rule. Check result: {reason}. Re-align task commit boundaries, then continue.",
986
992
  taskCommitGateWarnProceed: "\u26A0\uFE0F Task commit boundary warning: {reason}. You may continue, but `1 task = 1 commit` is recommended.",
@@ -7116,6 +7122,72 @@ function buildSuggestionFinalPrompt(lang, suggestionOptions) {
7116
7122
  example
7117
7123
  });
7118
7124
  }
7125
+ function normalizeCategoryToken(value) {
7126
+ if (typeof value !== "string") return null;
7127
+ const normalized = value.trim().toLowerCase();
7128
+ if (!normalized) return null;
7129
+ return normalized;
7130
+ }
7131
+ function resolveAutoRunCategories(approval) {
7132
+ const known = new Set(ACTION_CATEGORIES);
7133
+ const unique2 = /* @__PURE__ */ new Set();
7134
+ const unknown = /* @__PURE__ */ new Set();
7135
+ for (const raw of approval?.requireCheckCategories ?? approval?.requireOkCategories ?? []) {
7136
+ const normalized = normalizeCategoryToken(raw);
7137
+ if (!normalized) continue;
7138
+ if (known.has(normalized)) {
7139
+ unique2.add(normalized);
7140
+ } else {
7141
+ unknown.add(normalized);
7142
+ }
7143
+ }
7144
+ return {
7145
+ untilCategories: Array.from(unique2),
7146
+ unknownCategories: Array.from(unknown)
7147
+ };
7148
+ }
7149
+ function buildAutoRunCommand(state, featureName, selectedComponent, untilCategories) {
7150
+ if (untilCategories.length === 0) return "";
7151
+ const featureRef = resolveFeatureRefForApproval(state, featureName);
7152
+ const componentArg = selectedComponent ? ` --component ${selectedComponent}` : "";
7153
+ return `npx lee-spec-kit flow ${featureRef}${componentArg} --auto-until-category ${untilCategories.join(",")}`;
7154
+ }
7155
+ function resolveAutoRunPlan(lang, state, featureName, selectedComponent, approval, approvalRequired) {
7156
+ const base = (reasonCode, untilCategories2 = [], unknownCategories2 = []) => ({
7157
+ available: false,
7158
+ reasonCode,
7159
+ summary: tr(lang, "cli", "context.autoRunUnavailable"),
7160
+ command: "",
7161
+ untilCategories: untilCategories2,
7162
+ unknownCategories: unknownCategories2
7163
+ });
7164
+ if (state.status !== "single_matched") return base("NOT_SINGLE_MATCHED");
7165
+ if (state.actionOptions.length === 0) return base("NO_ACTION_OPTIONS");
7166
+ if (approvalRequired) return base("APPROVAL_REQUIRED");
7167
+ const mode = approval?.mode ?? "builtin";
7168
+ if (mode !== "category") return base("APPROVAL_MODE_NOT_CATEGORY");
7169
+ const defaultPolicy = approval?.default ?? "keep";
7170
+ if (defaultPolicy !== "skip") return base("DEFAULT_NOT_SKIP");
7171
+ const { untilCategories, unknownCategories } = resolveAutoRunCategories(approval);
7172
+ if (untilCategories.length === 0) {
7173
+ return base("NO_REQUIRE_CHECK_CATEGORIES", [], unknownCategories);
7174
+ }
7175
+ return {
7176
+ available: true,
7177
+ reasonCode: "AVAILABLE",
7178
+ summary: tr(lang, "cli", "context.autoRunSummary", {
7179
+ categories: untilCategories.join(", ")
7180
+ }),
7181
+ command: buildAutoRunCommand(
7182
+ state,
7183
+ featureName,
7184
+ selectedComponent,
7185
+ untilCategories
7186
+ ),
7187
+ untilCategories,
7188
+ unknownCategories
7189
+ };
7190
+ }
7119
7191
  function toSuggestionLabel(index) {
7120
7192
  let n = index + 1;
7121
7193
  let label = "";
@@ -7520,6 +7592,26 @@ async function runContext(featureName, options) {
7520
7592
  selectedComponent
7521
7593
  );
7522
7594
  const suggestionFinalPrompt = buildSuggestionFinalPrompt(lang, suggestionOptions);
7595
+ const checkRequiredLabels = state.actionOptions.filter((option) => !!option.action.requiresUserCheck).map((option) => option.label);
7596
+ const checkRequiredCategories = [
7597
+ ...new Set(
7598
+ state.actionOptions.filter((option) => !!option.action.requiresUserCheck).map((option) => option.action.category || "uncategorized")
7599
+ )
7600
+ ];
7601
+ const approvalRequired = checkRequiredLabels.length > 0;
7602
+ const finalApprovalPrompt = approvalRequired ? buildFinalApprovalPrompt(lang, state.actionOptions) : "";
7603
+ const approvalUserFacingLines = approvalRequired ? [
7604
+ ...state.actionOptions.map((o) => o.approvalPrompt),
7605
+ finalApprovalPrompt
7606
+ ].filter((line) => line.length > 0) : [];
7607
+ const autoRunPlan = resolveAutoRunPlan(
7608
+ lang,
7609
+ state,
7610
+ featureName,
7611
+ selectedComponent,
7612
+ config.approval,
7613
+ approvalRequired
7614
+ );
7523
7615
  if (options.approve || options.execute) {
7524
7616
  await runApprovedOption(
7525
7617
  state,
@@ -7534,18 +7626,6 @@ async function runContext(featureName, options) {
7534
7626
  const jsonMode = !!options.json || !!options.jsonCompact;
7535
7627
  if (jsonMode) {
7536
7628
  const primaryAction = state.actionOptions[0] ?? null;
7537
- const checkRequiredLabels = state.actionOptions.filter((option) => !!option.action.requiresUserCheck).map((option) => option.label);
7538
- const checkRequiredCategories = [
7539
- ...new Set(
7540
- state.actionOptions.filter((option) => !!option.action.requiresUserCheck).map((option) => option.action.category || "uncategorized")
7541
- )
7542
- ];
7543
- const approvalRequired = checkRequiredLabels.length > 0;
7544
- const finalApprovalPrompt = approvalRequired ? buildFinalApprovalPrompt(lang, state.actionOptions) : "";
7545
- const approvalUserFacingLines = approvalRequired ? [
7546
- ...state.actionOptions.map((o) => o.approvalPrompt),
7547
- finalApprovalPrompt
7548
- ].filter((line) => line.length > 0) : [];
7549
7629
  const approveCommand = buildApprovalCommand(
7550
7630
  state,
7551
7631
  featureName,
@@ -7607,6 +7687,14 @@ async function runContext(featureName, options) {
7607
7687
  contextVersion: state.contextVersion,
7608
7688
  config: config.approval ?? { mode: "builtin" }
7609
7689
  },
7690
+ autoRun: {
7691
+ available: autoRunPlan.available,
7692
+ reasonCode: autoRunPlan.reasonCode,
7693
+ summary: autoRunPlan.summary,
7694
+ command: autoRunPlan.command,
7695
+ untilCategories: autoRunPlan.untilCategories,
7696
+ unknownCategories: autoRunPlan.unknownCategories
7697
+ },
7610
7698
  approvalRequest: {
7611
7699
  required: approvalRequired,
7612
7700
  finalPrompt: finalApprovalPrompt,
@@ -7686,6 +7774,15 @@ async function runContext(featureName, options) {
7686
7774
  contextVersion: state.contextVersion,
7687
7775
  config: config.approval ?? { mode: "builtin" }
7688
7776
  },
7777
+ autoRun: {
7778
+ available: autoRunPlan.available,
7779
+ reasonCode: autoRunPlan.reasonCode,
7780
+ summary: autoRunPlan.summary,
7781
+ command: autoRunPlan.command,
7782
+ untilCategories: autoRunPlan.untilCategories,
7783
+ unknownCategories: autoRunPlan.unknownCategories,
7784
+ guidance: "Use auto-run only when `autoRun.available=true`. Stop and request approval when `approvalRequest.required=true` or when auto mode reaches configured gate categories."
7785
+ },
7689
7786
  approvalRequest: {
7690
7787
  guidance: "User-facing output must include only approval prompts (`A: ...`) and `finalPrompt`. Do not expose `requiredDocs`, `checkPolicy`, or raw `cmd` unless explicitly requested. For approved command actions, prefer one-shot `flow --approve <LABEL> --execute`.",
7691
7788
  required: approvalRequired,
@@ -7899,7 +7996,7 @@ async function runContext(featureName, options) {
7899
7996
  const f = state.targetFeatures[0];
7900
7997
  const stepName = stepsMap[f.currentStep] || "Unknown";
7901
7998
  const checkTag = (requiresUserCheck) => requiresUserCheck ? chalk6.yellow(tr(lang, "cli", "context.checkRequired")) : "";
7902
- const hasCheckAction = (f.actions || []).some((a) => !!a.requiresUserCheck);
7999
+ const hasCheckAction = approvalRequired;
7903
8000
  console.log(
7904
8001
  `\u{1F539} Feature: ${chalk6.bold(f.folderName)} ${config.projectType === "multi" ? chalk6.cyan(`(${f.type})`) : ""}`
7905
8002
  );
@@ -7971,8 +8068,17 @@ async function runContext(featureName, options) {
7971
8068
  );
7972
8069
  }
7973
8070
  }
8071
+ if (autoRunPlan.available) {
8072
+ console.log(chalk6.gray(` \u21B3 ${autoRunPlan.summary}`));
8073
+ console.log(
8074
+ chalk6.gray(
8075
+ ` \u21B3 ${tr(lang, "cli", "context.autoRunCommandHint", {
8076
+ command: autoRunPlan.command
8077
+ })}`
8078
+ )
8079
+ );
8080
+ }
7974
8081
  if (actionOptions.length > 0 && hasCheckAction) {
7975
- const finalApprovalPrompt = buildFinalApprovalPrompt(lang, actionOptions);
7976
8082
  const approveCommand = buildApprovalCommand(
7977
8083
  state,
7978
8084
  featureName,