lee-spec-kit 0.7.10 → 0.7.11

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
@@ -9,6 +9,7 @@ import { spawn, spawnSync, execFileSync, execSync } from 'child_process';
9
9
  import os from 'os';
10
10
  import { createHash, randomUUID } from 'crypto';
11
11
  import fs13 from 'fs';
12
+ import fs20 from 'fs/promises';
12
13
  import { Buffer as Buffer$1 } from 'buffer';
13
14
 
14
15
  var getFilename = () => fileURLToPath(import.meta.url);
@@ -212,7 +213,7 @@ var koCli = {
212
213
  "doctor.issue.tasksEmpty": "tasks.md\uC5D0 \uD0DC\uC2A4\uD06C\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.",
213
214
  "doctor.issue.tasksDocStatusUnset": "tasks.md\uC758 \uBB38\uC11C \uC0C1\uD0DC(Doc Status)\uAC00 \uC124\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. (Draft/Review/Approved \uC911 \uD558\uB098\uB85C \uC124\uC815\uD558\uC138\uC694.)",
214
215
  "doctor.issue.tasksDocStatusMissing": "tasks.md\uC5D0 \uBB38\uC11C \uC0C1\uD0DC(Doc Status) \uD544\uB4DC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. `- **\uBB38\uC11C \uC0C1\uD0DC**: -`\uC640 `\uAC12: Draft | Review | Approved`\uB97C \uCD94\uAC00\uD558\uC138\uC694.",
215
- "doctor.issue.tasksPrdTagUnknown": "tasks.md\uC5D0 \uC815\uC758\uB418\uC9C0 \uC54A\uC740 PRD \uD0DC\uADF8\uAC00 \uC788\uC2B5\uB2C8\uB2E4: {ids}{extra}. tasks.md\uC5D0\uC11C PRD-FR-001 \uAC19\uC740 ID\uB97C \uC784\uC758\uB85C \uB9CC\uB4E4\uC9C0 \uB9D0\uACE0, \uBA3C\uC800 docs/prd \uB610\uB294 \uC0C1\uC704 \uC694\uAD6C\uC0AC\uD56D \uBB38\uC11C\uC5D0 ID\uB97C backfill\uD55C \uB4A4 spec.md `PRD Refs`\uC640 tasks \uD0DC\uADF8\uB97C \uD568\uAED8 \uB9DE\uCD94\uC138\uC694.",
216
+ "doctor.issue.tasksPrdTagUnknown": "tasks.md\uC5D0 \uC815\uC758\uB418\uC9C0 \uC54A\uC740 PRD \uD0DC\uADF8\uAC00 \uC788\uC2B5\uB2C8\uB2E4: {ids}{extra}. tasks.md\uC5D0\uC11C `PRD-*` ID\uB97C \uC784\uC758\uB85C \uB9CC\uB4E4\uC9C0 \uB9D0\uACE0, \uBA3C\uC800 docs/prd \uB610\uB294 \uC0C1\uC704 \uC694\uAD6C\uC0AC\uD56D \uBB38\uC11C\uC5D0 ID\uB97C backfill\uD55C \uB4A4 spec.md `PRD Refs`\uC640 tasks \uD0DC\uADF8\uB97C \uD568\uAED8 \uB9DE\uCD94\uC138\uC694.",
216
217
  "doctor.issue.unmanagedDocsEntry": "lee-spec-kit \uBB38\uC11C \uD45C\uBA74 \uBC16\uC758 \uBB38\uC11C \uC5D4\uD2B8\uB9AC\uAC00 \uAC10\uC9C0\uB418\uC5C8\uC2B5\uB2C8\uB2E4: {path}. \uCD5C\uC885 SSOT\uB85C \uC4F0\uC9C0 \uB9D0\uACE0 feature-local docs\uB85C \uC815\uADDC\uD654\uD558\uAC70\uB098, \uC758\uB3C4\uB41C \uACBD\uB85C\uB77C\uBA74 `.lee-spec-kit.json`\uC758 `allowedDocsEntries`\uC5D0 \uCD94\uAC00\uD558\uC138\uC694.",
217
218
  "doctor.issue.duplicateFeatureId": "\uC911\uBCF5 Feature ID \uAC10\uC9C0: {id} ({count}\uAC1C)",
218
219
  "doctor.issue.missingFeatureId": "Feature \uD3F4\uB354\uBA85\uC774 F001-... \uD615\uC2DD\uC774 \uC544\uB2D9\uB2C8\uB2E4. (ID\uB97C \uCD94\uCD9C\uD560 \uC218 \uC5C6\uC74C)",
@@ -478,7 +479,7 @@ var koContext = {
478
479
  "context.checkRequired": "[\uD655\uC778 \uD544\uC694] ",
479
480
  "context.checkPolicyHint": "\u2139\uFE0F \uC0AC\uC6A9\uC790 \uD655\uC778 \uC815\uCC45\uC740 \uC138\uC158 \uC2DC\uC791(\uB610\uB294 context \uC555\uCD95/\uB9AC\uC14B \uC9C1\uD6C4)\uC5D0 1\uD68C \uD655\uC778\uD558\uACE0, \uC774\uD6C4\uC5D0\uB294 \uC815\uCC45/\uC124\uC815 \uBCC0\uACBD \uB610\uB294 \uC0AC\uC6A9\uC790 \uC0C8\uB85C\uACE0\uCE68 \uC694\uCCAD \uC2DC\uC5D0\uB9CC \uC7AC\uD655\uC778\uD558\uC138\uC694. (git push/merge/merge commit \uD3EC\uD568) [\uD655\uC778 \uD544\uC694]\uAC00 \uC788\uC73C\uBA74 \uB77C\uBCA8 \uD1A0\uD070 \uADDC\uCE59(`A`, `A OK`, `A \uC9C4\uD589\uD574`)\uC5D0 \uB9DE\uB294 \uC751\uB2F5\uC744 \uBC1B\uC740 \uB4A4 \uC9C4\uD589\uD558\uC138\uC694. (config: approval\uB85C \uC870\uC815 \uAC00\uB2A5)",
480
481
  "context.actionOptionHint": "\uB77C\uBCA8 \uC751\uB2F5 \uADDC\uCE59: `A`, `A OK`, `A \uC9C4\uD589\uD574` \uC911 \uD558\uB098\uC758 \uD615\uC2DD\uC73C\uB85C \uC751\uB2F5",
481
- "context.actionExplainHint": "CLI\uAC00 \uC900 \uC2B9\uC778 \uBB38\uAD6C\uB97C \uBA3C\uC800 \uADF8\uB300\uB85C \uBCF4\uC5EC\uC8FC\uC138\uC694. \uCD94\uAC00 \uC124\uBA85\uC740 \uC0AC\uC6A9\uC790\uAC00 \uBB3C\uC744 \uB54C\uB9CC \uB367\uBD99\uC774\uACE0, \uC2B9\uC778 \uBB38\uAD6C \uC790\uCCB4\uB294 \uBC14\uAFB8\uC9C0 \uB9C8\uC138\uC694.",
482
+ "context.actionExplainHint": "\uC2B9\uC778 \uB300\uAE30 \uC0C1\uD0DC\uB77C\uBA74 `matchedFeature.currentSubstate*` \uAE30\uBC18 \uD604\uC7AC \uB2E8\uACC4 \uD55C \uC904 \uC694\uC57D\uC744 \uBA3C\uC800 \uBD99\uC77C \uC218 \uC788\uACE0, \uADF8 \uB2E4\uC74C CLI\uAC00 \uC900 \uC2B9\uC778 \uBB38\uAD6C\uB97C \uADF8\uB300\uB85C \uBCF4\uC5EC\uC8FC\uC138\uC694. \uCD94\uAC00 \uC124\uBA85\uC740 \uC0AC\uC6A9\uC790\uAC00 \uBB3C\uC744 \uB54C\uB9CC \uB367\uBD99\uC774\uACE0, \uC2B9\uC778 \uBB38\uAD6C \uC790\uCCB4\uB294 \uBC14\uAFB8\uC9C0 \uB9C8\uC138\uC694.",
482
483
  "context.finalLabelPrompt": "\uD604\uC7AC \uC120\uD0DD \uAC00\uB2A5\uD55C \uB77C\uBCA8: {labels}. \uB77C\uBCA8 \uC751\uB2F5 \uADDC\uCE59(`A`, `A OK`, `A \uC9C4\uD589\uD574`)\uC73C\uB85C \uC751\uB2F5\uD558\uC138\uC694. (\uC608: `{example}`)",
483
484
  "context.finalLabelPromptWithRequest": "\uD604\uC7AC \uC120\uD0DD \uAC00\uB2A5\uD55C \uB77C\uBCA8: {labels}. \uB77C\uBCA8 \uC751\uB2F5 \uADDC\uCE59(`A`, `A OK`, `A \uC9C4\uD589\uD574`)\uC73C\uB85C \uC751\uB2F5\uD558\uC138\uC694. (\uC608: `{example}`) \uC694\uCCAD \uD14D\uC2A4\uD2B8\uAC00 \uD544\uC694\uD55C \uB77C\uBCA8\uC740 \uB2E4\uC74C \uD615\uC2DD\uC73C\uB85C \uC785\uB825\uD558\uC138\uC694: {requestExamples}",
484
485
  "context.suggestionHeader": "\uCD94\uCC9C \uB2E4\uC74C \uC120\uD0DD\uC9C0",
@@ -508,6 +509,7 @@ var koContext = {
508
509
  "context.actionDetail.tasksWriteCreate": "tasks.md\uB97C \uC0DD\uC131\uD558\uACE0 \uBB38\uC11C \uC0C1\uD0DC\uB97C Review\uB85C \uC124\uC815\uD558\uC138\uC694",
509
510
  "context.actionDetail.tasksWriteNeedAtLeastOne": "tasks.md\uC5D0 \uCD5C\uC18C 1\uAC1C \uC774\uC0C1\uC758 \uD0DC\uC2A4\uD06C\uB97C \uCD94\uAC00\uD558\uC138\uC694",
510
511
  "context.actionDetail.tasksWriteImprove": "tasks.md\uB97C \uBCF4\uC644\uD558\uACE0 \uBB38\uC11C \uC0C1\uD0DC\uB97C \uC815\uB82C\uD558\uC138\uC694",
512
+ "context.actionDetail.tasksWriteChangeSync": "\uCD94\uAC00 \uAD6C\uD604 \uC804\uC5D0 \uC0C8 \uC0AC\uC6A9\uC790 \uC694\uCCAD\uC744 tasks.md\uC5D0 \uBA3C\uC800 \uBC18\uC601\uD558\uC138\uC694",
511
513
  "context.actionDetail.tasksApprove": "tasks.md\uB97C \uC2B9\uC778\uD569\uB2C8\uB2E4",
512
514
  "context.actionDetail.issueCreate": "\uC774\uC288\uB97C \uC0DD\uC131\uD558\uACE0 tasks.md\uC758 \uC774\uC288 \uC815\uBCF4\uB97C \uB9DE\uCD94\uC138\uC694",
513
515
  "context.actionDetail.issueCreateAndWrite": "\uC774\uC288 \uCD08\uC548\uC744 \uBCF4\uC644\uD558\uACE0 \uB77C\uBCA8 \uC2B9\uC778(`A` \uB610\uB294 `A OK`) \uD6C4 \uC774\uC288\uB97C \uC0DD\uC131\uD574 \uBC88\uD638\uB97C \uB3D9\uAE30\uD654\uD558\uC138\uC694",
@@ -680,6 +682,7 @@ var koMessages = {
680
682
  featureScopeSplitTwo: "Feature \uBC94\uC704\uAC00 \uD07D\uB2C8\uB2E4. (tasks: {taskCount}, decisions \uC904\uC218: {decisionsLineCount}) \uAD8C\uC7A5 \uADDC\uCE59\uC0C1 40~79 \uD0DC\uC2A4\uD06C\uC774\uBA74\uC11C \uD558\uB4DC \uAE30\uC900 \uBBF8\uB9CC\uC774\uBA74 2\uAC1C \uC774\uC288 \uBD84\uD560\uC774 \uAE30\uBCF8\uC785\uB2C8\uB2E4. `{guideCommand}`\uB97C \uB530\uB77C \uACB0\uD569\uB3C4/\uD30C\uC77C\uACB9\uCE68/\uD14C\uC2A4\uD2B8/\uBC30\uD3EC \uAE30\uC900\uC73C\uB85C \uBD84\uD560\uD558\uC138\uC694. \uAC01 \uC774\uC288\uC5D0\uB294 \uB2E4\uC74C \uD15C\uD50C\uB9BF\uC744 \uAE30\uB85D\uD558\uC138\uC694: \uBAA9\uD45C, \uD3EC\uD568 \uBC94\uC704, \uC81C\uC678 \uBC94\uC704, \uC120\uD589 \uC758\uC874\uC131, PR \uC644\uB8CC \uAE30\uC900.",
681
683
  featureScopeSplitFour: "Feature \uBC94\uC704\uAC00 \uD07D\uB2C8\uB2E4. (tasks: {taskCount}, decisions \uC904\uC218: {decisionsLineCount}) tasks >= {recommendFourTaskThreshold} \uB610\uB294 decisions \uC904\uC218 >= {recommendFourDecisionsThreshold}\uC774\uBA74 4\uAC1C \uC774\uC288 \uBD84\uD560\uC744 \uAC15\uD558\uAC8C \uAD8C\uC7A5\uD569\uB2C8\uB2E4. `{guideCommand}`\uB97C \uB530\uB77C 4\uAC1C\uC758 \uC5F0\uAD00 \uC774\uC288\uB85C \uBD84\uB9AC\uD558\uACE0 \uC758\uC874 \uC21C\uC11C\uB97C \uBA85\uC2DC\uD55C \uB4A4 PR\uC744 \uC21C\uCC28 \uBA38\uC9C0\uD558\uC138\uC694. \uAC01 \uC774\uC288 \uD15C\uD50C\uB9BF: \uBAA9\uD45C, \uD3EC\uD568 \uBC94\uC704, \uC81C\uC678 \uBC94\uC704, \uC120\uD589 \uC758\uC874\uC131, PR \uC644\uB8CC \uAE30\uC900.",
682
684
  userRequestReplan: "\uD604\uC7AC \uB2E8\uACC4\uC640 \uBCC4\uAC1C\uB85C \uC0AC\uC6A9\uC790\uAC00 \uC81C\uC548\uD55C \uC0C8 \uC694\uAD6C\uB97C \uBA3C\uC800 \uBC18\uC601\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4. \uC694\uAD6C\uC0AC\uD56D\uC744 \uC694\uC57D\uD574 tasks.md\uC5D0 \uCD94\uAC00\uD558\uAC70\uB098 \uBCC4\uB3C4 Feature\uB85C \uBD84\uB9AC\uD55C \uB4A4, \uBB38\uC11C \uC0C1\uD0DC\uB97C \uB9DE\uCD94\uACE0 context\uB97C \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694.",
685
+ changeRequestSync: 'tasks.md\uC5D0 \uC0C8 \uC0AC\uC6A9\uC790 \uC694\uCCAD\uC774 \uAE30\uB85D\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4: "{request}". \uCD94\uAC00 \uAD6C\uD604 \uC804\uC5D0 \uBA3C\uC800 tasks.md\uB97C \uAC31\uC2E0\uD558\uC138\uC694. \uC601\uD5A5\uBC1B\uB294 \uD0DC\uC2A4\uD06C\uB97C \uCD94\uAC00\uD558\uAC70\uB098 \uC7AC\uD0DC\uAE45\uD558\uACE0, \uC774 \uC694\uCCAD\uC774 \uC2E4\uC81C \uC0AC\uC6A9\uC790 \uB3D9\uC791\uC774\uB098 \uBC94\uC704\uB97C \uBC14\uAFB8\uBA74 decisions.md\uC640 spec/PRD \uCC38\uC870\uB3C4 \uD568\uAED8 \uB9DE\uCD94\uC138\uC694. \uB3D9\uAE30\uD654\uAC00 \uB05D\uB098\uBA74 `\uB300\uAE30 \uC911 \uBCC0\uACBD \uC694\uCCAD` \uAC12\uC744 \uBE44\uC6B0\uACE0 context/flow\uB97C \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694.',
683
686
  docsUnmanagedNormalize: "lee-spec-kit \uBB38\uC11C \uD45C\uBA74 \uBC16\uC758 \uBB38\uC11C \uC5D4\uD2B8\uB9AC\uAC00 \uAC10\uC9C0\uB418\uC5C8\uC2B5\uB2C8\uB2E4: {paths}. Feature `{featureRef}`\uB97C \uACC4\uC18D \uC9C4\uD589\uD558\uAE30 \uC804\uC5D0 \uC774 \uBB38\uC11C\uB4E4\uC740 reference \uC785\uB825\uC73C\uB85C\uB9CC \uCDE8\uAE09\uD558\uC138\uC694. \uC0AC\uC6A9\uC790 \uBC94\uC704/acceptance\uB294 `spec.md`, \uC544\uD0A4\uD14D\uCC98/\uD30C\uC77C/\uD14C\uC2A4\uD2B8 \uB0B4\uC6A9\uC740 `plan.md`, \uC2E4\uD589 \uC791\uC5C5\uC740 `tasks.md`, \uADFC\uAC70/\uD2B8\uB808\uC774\uB4DC\uC624\uD504\uB294 `decisions.md`\uB85C \uC815\uADDC\uD654\uD55C \uB4A4 `npx lee-spec-kit context {featureRef}`\uB97C \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694.",
684
687
  featureDone: "\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC694\uAD6C\uC0AC\uD56D\uACFC \uB85C\uCEEC \uC815\uB9AC\uAE4C\uC9C0 \uBAA8\uB450 \uB05D\uB0AC\uC2B5\uB2C8\uB2E4. \uC774 Feature\uB294 \uC644\uC804\uD788 \uC885\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.",
685
688
  fallbackRerunContext: "\uC0C1\uD0DC\uB97C \uD310\uBCC4\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uBB38\uC11C\uB97C \uD655\uC778\uD55C \uB4A4 \uB2E4\uC2DC context\uB97C \uC2E4\uD589\uD558\uC138\uC694."
@@ -789,7 +792,7 @@ var enCli = {
789
792
  "doctor.issue.tasksEmpty": "tasks.md has no tasks.",
790
793
  "doctor.issue.tasksDocStatusUnset": "tasks.md Doc Status is not set. (Set it to Draft, Review, or Approved.)",
791
794
  "doctor.issue.tasksDocStatusMissing": "tasks.md is missing the Doc Status field. Add `- **Doc Status**: -` and `Values: Draft | Review | Approved`.",
792
- "doctor.issue.tasksPrdTagUnknown": "tasks.md uses PRD tags with no matching source definition: {ids}{extra}. Do not invent IDs like PRD-FR-001 in tasks.md. Backfill IDs in docs/prd or the upstream requirements doc first, then align spec.md `PRD Refs` and task tags.",
795
+ "doctor.issue.tasksPrdTagUnknown": "tasks.md uses PRD tags with no matching source definition: {ids}{extra}. Do not invent `PRD-*` IDs in tasks.md. Backfill IDs in docs/prd or the upstream requirements doc first, then align spec.md `PRD Refs` and task tags.",
793
796
  "doctor.issue.unmanagedDocsEntry": "Unmanaged docs entry detected outside the lee-spec-kit docs surface: {path}. Treat it as reference input only, normalize it into feature-local docs, or allowlist it in `.lee-spec-kit.json` `allowedDocsEntries`.",
794
797
  "doctor.issue.duplicateFeatureId": "Duplicate Feature ID detected: {id} ({count})",
795
798
  "doctor.issue.missingFeatureId": "Feature folder name is not in F001-... format. (Cannot extract ID)",
@@ -1055,7 +1058,7 @@ var enContext = {
1055
1058
  "context.checkRequired": "[CHECK required] ",
1056
1059
  "context.checkPolicyHint": "\u2139\uFE0F Check user-approval policy once at session start (or right after context compression/reset); re-check only when policy/config changes or the user explicitly requests refresh. (includes git push/merge and merge commits). If you see [CHECK required], wait for a reply that follows label-token rules (`A`, `A OK`, `A proceed`) before proceeding (config: approval can override)",
1057
1060
  "context.actionOptionHint": "Label reply rules: answer as `A`, `A OK`, or `A proceed`",
1058
- "context.actionExplainHint": "Use the exact approval lines from the CLI first. Add extra explanation only if the user asks, and do not paraphrase the approval prompts.",
1061
+ "context.actionExplainHint": "If approval is pending, you may add one brief current-stage recap from `matchedFeature.currentSubstate*`, then use the exact approval lines from the CLI. Add further explanation only if the user asks, and do not paraphrase the approval prompts.",
1059
1062
  "context.finalLabelPrompt": "Available labels now: {labels}. Reply using label-token rules (`A`, `A OK`, `A proceed`). (e.g. `{example}`)",
1060
1063
  "context.finalLabelPromptWithRequest": "Available labels now: {labels}. Reply using label-token rules (`A`, `A OK`, `A proceed`). (e.g. `{example}`) Labels that require a request must be replied as: {requestExamples}",
1061
1064
  "context.suggestionHeader": "Suggested Next Options",
@@ -1085,6 +1088,7 @@ var enContext = {
1085
1088
  "context.actionDetail.tasksWriteCreate": "Create tasks.md and set Doc Status to Review",
1086
1089
  "context.actionDetail.tasksWriteNeedAtLeastOne": "Add at least one task to tasks.md",
1087
1090
  "context.actionDetail.tasksWriteImprove": "Refine tasks.md and align Doc Status",
1091
+ "context.actionDetail.tasksWriteChangeSync": "Sync the new user request into tasks.md before more implementation",
1088
1092
  "context.actionDetail.tasksApprove": "Approve tasks.md",
1089
1093
  "context.actionDetail.issueCreate": "Create the issue and sync issue fields in tasks.md",
1090
1094
  "context.actionDetail.issueCreateAndWrite": "Draft issue content, get explicit OK, then create and sync Issue",
@@ -1257,6 +1261,7 @@ var enMessages = {
1257
1261
  featureScopeSplitTwo: "Feature scope is large (tasks: {taskCount}, decisions lines: {decisionsLineCount}). Recommendation rule: 40~79 tasks and below the hard threshold usually maps to 2 issues. Follow `{guideCommand}` and split by coupling/file-overlap/test/deploy criteria. For each new issue, document this template: Goal, Included Scope, Excluded Scope, Depends On, PR Done Criteria.",
1258
1262
  featureScopeSplitFour: "Feature scope is large (tasks: {taskCount}, decisions lines: {decisionsLineCount}). Hard recommendation is 4 issues when tasks >= {recommendFourTaskThreshold} or decisions lines >= {recommendFourDecisionsThreshold}. Follow `{guideCommand}` and split into 4 linked issues with explicit dependency order and sequential PR merges. Use the per-issue template: Goal, Included Scope, Excluded Scope, Depends On, PR Done Criteria.",
1259
1263
  userRequestReplan: "You can pause this step and handle a newly requested user requirement first. Summarize it, add it to tasks.md or split it into a separate Feature, then align document statuses and rerun context.",
1264
+ changeRequestSync: 'A pending user request is recorded in tasks.md: "{request}". Before more implementation, update tasks.md first. Add or retag the affected task, and if this changes shipped behavior or scope, sync decisions.md plus spec/PRD references as needed. Clear `Pending Change Request` after syncing, then rerun context/flow.',
1260
1265
  docsUnmanagedNormalize: "Unmanaged docs entries were found outside the lee-spec-kit docs surface: {paths}. Before continuing feature `{featureRef}`, treat them as reference inputs only. Normalize user-facing scope and acceptance into `spec.md`, architecture/file/test details into `plan.md`, executable work into `tasks.md`, and rationale/trade-offs into `decisions.md`, then rerun `npx lee-spec-kit context {featureRef}`.",
1261
1266
  featureDone: "All workflow requirements and local cleanup are complete. This feature is fully finished.",
1262
1267
  fallbackRerunContext: "Cannot determine status. Check the docs and run context again."
@@ -2027,25 +2032,24 @@ Auto-run continuity (main/sub-agent orchestration):
2027
2032
  3. Else run \`npx lee-spec-kit context --json-compact\` (fallback: \`--json\`) and continue from current \`actionOptions\`/\`autoRun\`.
2028
2033
  - Pause and report to user only when:
2029
2034
  - \`approvalRequest.required === true\`, or
2030
- - \`autoRun.reasonCode\` is \`AUTO_GATE_REACHED\`, \`AUTO_DELEGATED_HANDOFF\`, or \`AUTO_MANUAL_REQUIRED\`, or
2035
+ - \`autoRun.reasonCode\` is \`AUTO_GATE_REACHED\`, \`AUTO_DELEGATED_HANDOFF\`, \`AUTO_MANUAL_REQUIRED\`, or \`AUTO_SELECTION_REQUIRED\`, or
2031
2036
  - command execution fails (non-zero/error), or
2032
2037
  - user explicitly asks to pause.
2038
+ - Special case: if \`matchedFeature.currentSubstateId === "change_request_sync"\` or \`matchedFeature.pendingChangeRequest\` is present, treat that \`AUTO_MANUAL_REQUIRED\` state as an internal docs-sync step first, not an immediate user-facing stop. Update \`tasks.md\` first, and if shipped behavior or scope changed, sync \`decisions.md\` plus \`spec.md\` / PRD refs as needed. Clear the pending change field after syncing, then continue with fresh \`context\`/\`flow\`. Only pause/report there if approval becomes required, execution fails, or the user explicitly asked to pause.
2033
2039
 
2034
2040
  User-facing output rule (state-aware):
2035
2041
 
2036
2042
  - Treat approval as a separate state.
2037
- - Approval-waiting state means:
2038
- - \`context --json-compact\` (or \`context --json\`) includes one or more \`actionOptions\`, and
2039
- - you are explicitly waiting for user approval before execution.
2043
+ - Approval-waiting state means the latest \`context --json-compact\` / \`flow --json-compact\` (fallback: \`context --json\` / \`flow --json\`) shows \`approvalRequest.required === true\`.
2044
+ - Do not infer approval-waiting from conversation tone, action type, or whether \`actionOptions[]\` merely exist.
2040
2045
 
2041
2046
  In approval-waiting state:
2042
2047
 
2043
- 1. Show \`actionOptions[*].approvalPrompt\` lines (at minimum, the primary label line like \`A: ...\`) exactly as provided.
2044
- 2. End with \`approvalRequest.finalPrompt\` exactly as provided.
2045
- 3. Do not paraphrase or omit these lines.
2046
- 4. Prefer \`approvalRequest.userFacingLines\` as the source for user-facing approval text.
2047
- 5. Prefer \`matchedFeature.currentSubstateOwner\` plus \`agentOrchestration.subAgentHandoff\` as the delegation SSOT.
2048
- 6. When \`matchedFeature.currentSubstateOwner="subagent"\` and \`agentOrchestration.subAgentHandoff.required=true\` with \`mode="command"\`, call \`spawn_agent\` first and do not execute the delegated command directly from the main agent. If the delegated command is handoff-only, continue the delegated work immediately and do not re-open the same approval label.
2048
+ 1. If \`matchedFeature.currentSubstateId\` is present, prepend one brief current-stage recap derived from \`matchedFeature.currentSubstateId/currentSubstateOwner/currentSubstatePhase\`.
2049
+ 2. Then show \`approvalRequest.userFacingLines\` exactly as provided. If those lines are unavailable, fall back to \`actionOptions[*].approvalPrompt\` plus \`approvalRequest.finalPrompt\`.
2050
+ 3. Do not paraphrase, reorder, or omit the CLI-provided approval lines.
2051
+ 4. Prefer \`matchedFeature.currentSubstateOwner\` plus \`agentOrchestration.subAgentHandoff\` as the delegation SSOT.
2052
+ 5. When \`matchedFeature.currentSubstateOwner="subagent"\` and \`agentOrchestration.subAgentHandoff.required=true\` with \`mode="command"\`, call \`spawn_agent\` first and do not execute the delegated command directly from the main agent. If the delegated command is handoff-only, continue the delegated work immediately and do not re-open the same approval label.
2049
2053
 
2050
2054
  In non-approval state (progress updates, analysis, tool execution logs, unrelated Q&A):
2051
2055
 
@@ -2056,10 +2060,11 @@ In non-approval state (progress updates, analysis, tool execution logs, unrelate
2056
2060
  If approval is still pending after answering an unrelated question:
2057
2061
 
2058
2062
  - First answer the question.
2059
- - Then re-open approval using both:
2060
- - \`actionOptions[*].approvalPrompt\` (label meaning included), and
2061
- - \`approvalRequest.finalPrompt\` (format line).
2062
- - Never output \`finalPrompt\` alone without the matching \`A: ...\` prompt.`;
2063
+ - Re-check the latest \`approvalRequest.required\`.
2064
+ - If it is still \`true\`, re-open approval with:
2065
+ - one brief current-stage recap from \`matchedFeature.currentSubstateId/currentSubstateOwner/currentSubstatePhase\` when available, then
2066
+ - the exact CLI-provided approval lines from \`approvalRequest.userFacingLines\` (fallback: \`actionOptions[*].approvalPrompt\` + \`approvalRequest.finalPrompt\`).
2067
+ - Never output \`finalPrompt\` alone without the matching \`A: ...\` prompt, and do not add custom label-summary wrappers such as \`Available labels:\`.`;
2063
2068
  function renderManagedSegment(lang, docsRepo) {
2064
2069
  return `${LEE_SPEC_KIT_AGENTS_BEGIN}
2065
2070
  ${CANONICAL_LEE_SPEC_KIT_AGENTS_TEXT}
@@ -4282,6 +4287,9 @@ function isCompletionChecklistDone(feature) {
4282
4287
  function isTasksDocApproved(feature) {
4283
4288
  return !feature.docs.tasksDocStatusFieldExists || feature.tasksDocStatus === "Approved";
4284
4289
  }
4290
+ function hasPendingChangeRequest(feature) {
4291
+ return typeof feature.pendingChangeRequest === "string" && feature.pendingChangeRequest.trim().length > 0;
4292
+ }
4285
4293
  function isImplementationDone(feature) {
4286
4294
  return feature.docs.tasksExists && feature.tasks.total > 0 && feature.tasks.total === feature.tasks.done && isCompletionChecklistDone(feature) && isTasksDocApproved(feature);
4287
4295
  }
@@ -4652,7 +4660,18 @@ function getStepDefinitions(ctx) {
4652
4660
  prePrReviewPolicy,
4653
4661
  taskCommitGatePolicy
4654
4662
  } = resolveWorkflowRuntime(ctx.config.workflow);
4655
- const isTaskExecuteCurrent = (f) => f.docs.tasksExists && f.tasks.total > 0 && (f.tasks.done < f.tasks.total || !isCompletionChecklistDone(f)) && isTasksDocApproved(f) && (!workflowPolicy.requireBranch || f.git.onExpectedBranch || f.tasks.done === f.tasks.total);
4663
+ const isTaskExecuteCurrent = (f) => f.docs.tasksExists && f.tasks.total > 0 && (hasPendingChangeRequest(f) || f.tasks.done < f.tasks.total || !isCompletionChecklistDone(f)) && isTasksDocApproved(f) && (!workflowPolicy.requireBranch || f.git.onExpectedBranch || f.tasks.done === f.tasks.total);
4664
+ const getChangeRequestSyncActions = (f) => [
4665
+ {
4666
+ type: "instruction",
4667
+ category: "tasks_write",
4668
+ requiresUserCheck: false,
4669
+ uiDetailKey: "context.actionDetail.tasksWriteChangeSync",
4670
+ message: tr(lang, "messages", "changeRequestSync", {
4671
+ request: f.pendingChangeRequest || "-"
4672
+ })
4673
+ }
4674
+ ];
4656
4675
  const isTaskExecuteWorktreeBlocked = (f) => isTaskExecuteCurrent(f) && workflowPolicy.requireWorktree && f.tasks.done < f.tasks.total && !!f.issueNumber && !f.git.projectInManagedWorktree;
4657
4676
  const isTaskExecuteFinalize = (f) => isTaskExecuteCurrent(f) && f.tasks.total === f.tasks.done && !isCompletionChecklistDone(f);
4658
4677
  const isTaskExecuteCommitPending = (f) => isTaskExecuteCurrent(f) && (isTaskExecuteFinalize(f) && (f.git.docsHasCommitRequiredChanges || f.git.projectHasUncommittedChanges) || !!f.nextTodoTask && (f.git.docsHasCommitRequiredChanges || f.git.projectHasUncommittedChanges));
@@ -5453,6 +5472,14 @@ ${tr(lang, "messages", "prePrReviewDecisionReconfirm", {
5453
5472
  detail: (f) => f.tasks.total > 0 ? `(${f.tasks.done}/${f.tasks.total})` : ""
5454
5473
  },
5455
5474
  substates: [
5475
+ {
5476
+ id: "change_request_sync",
5477
+ phase: "ready",
5478
+ owner: "main",
5479
+ category: "tasks_write",
5480
+ when: (f) => isTaskExecuteCurrent(f) && hasPendingChangeRequest(f),
5481
+ actions: (f) => getChangeRequestSyncActions(f)
5482
+ },
5456
5483
  {
5457
5484
  id: "task_blocked",
5458
5485
  phase: "blocked",
@@ -6364,6 +6391,15 @@ function extractFirstSpecValue(content, keys) {
6364
6391
  }
6365
6392
  return void 0;
6366
6393
  }
6394
+ function parsePendingChangeRequest(value) {
6395
+ if (!value) return void 0;
6396
+ const normalized = value.trim().replace(/\s+/g, " ");
6397
+ if (!normalized) return void 0;
6398
+ if (/^(?:-|#|none|n\/a|na|없음|미정)$/i.test(normalized)) {
6399
+ return void 0;
6400
+ }
6401
+ return normalized;
6402
+ }
6367
6403
  function parseDocStatus(value) {
6368
6404
  if (!value) return void 0;
6369
6405
  const trimmed = value.trim();
@@ -7190,6 +7226,7 @@ async function parseFeature(ctx, featurePath, type, context, options) {
7190
7226
  let lastDoneTask;
7191
7227
  let nextTodoTask;
7192
7228
  let tasksDocStatus;
7229
+ let pendingChangeRequest;
7193
7230
  let tasksDocStatusFieldExists = false;
7194
7231
  let completionChecklist;
7195
7232
  let prePrReviewStatus;
@@ -7251,6 +7288,11 @@ async function parseFeature(ctx, featurePath, type, context, options) {
7251
7288
  "Doc Status"
7252
7289
  ]);
7253
7290
  tasksDocStatus = parseDocStatus(tasksDocStatusValue);
7291
+ const pendingChangeRequestValue = extractFirstSpecValue(content, [
7292
+ "Pending Change Request",
7293
+ "\uB300\uAE30 \uC911 \uBCC0\uACBD \uC694\uCCAD"
7294
+ ]);
7295
+ pendingChangeRequest = parsePendingChangeRequest(pendingChangeRequestValue);
7254
7296
  const prValue = extractFirstSpecValue(content, ["PR", "Pull Request"]);
7255
7297
  prFieldExists = hasAnySpecKey(content, ["PR", "Pull Request"]);
7256
7298
  prLink = parsePrLink(prValue);
@@ -7657,6 +7699,7 @@ async function parseFeature(ctx, featurePath, type, context, options) {
7657
7699
  folderName,
7658
7700
  type,
7659
7701
  path: featurePath,
7702
+ pendingChangeRequest,
7660
7703
  completion: {
7661
7704
  implementationDone,
7662
7705
  workflowDone,
@@ -10186,6 +10229,81 @@ async function consumeApprovalTicket(config, token, expected) {
10186
10229
  }
10187
10230
 
10188
10231
  // src/services/ActionExecutor.ts
10232
+ var PENDING_CHANGE_REQUEST_KEYS = [
10233
+ "Pending Change Request",
10234
+ "\uB300\uAE30 \uC911 \uBCC0\uACBD \uC694\uCCAD"
10235
+ ];
10236
+ function escapeRegExp5(value) {
10237
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
10238
+ }
10239
+ function findSpecLineIndex(lines, keys) {
10240
+ const escaped = keys.map((key) => escapeRegExp5(key));
10241
+ const re = new RegExp(
10242
+ `^\\s*-\\s*\\*\\*(?:${escaped.join("|")})\\*\\*\\s*:`,
10243
+ "i"
10244
+ );
10245
+ return lines.findIndex((line) => re.test(line));
10246
+ }
10247
+ function replaceSpecLine(line, keys, preferredKey, value) {
10248
+ const escaped = keys.map((key) => escapeRegExp5(key));
10249
+ const re = new RegExp(
10250
+ `^(\\s*-\\s*\\*\\*)(?:${escaped.join("|")})(\\*\\*\\s*:\\s*)(.*)$`,
10251
+ "i"
10252
+ );
10253
+ if (!re.test(line)) return line;
10254
+ return line.replace(re, `$1${preferredKey}$2${value}`);
10255
+ }
10256
+ function computeSpecInsertIndex(lines, anchorKeys) {
10257
+ const anchorIndex = findSpecLineIndex(lines, anchorKeys);
10258
+ if (anchorIndex !== -1) {
10259
+ let cursor = anchorIndex + 1;
10260
+ while (cursor < lines.length && /^\s{2,}-\s+/.test(lines[cursor])) {
10261
+ cursor += 1;
10262
+ }
10263
+ return cursor;
10264
+ }
10265
+ const sectionIndex = lines.findIndex(
10266
+ (line) => /^\s*##\s+(Task List|태스크 목록)\s*$/.test(line)
10267
+ );
10268
+ if (sectionIndex !== -1) return sectionIndex;
10269
+ return lines.length;
10270
+ }
10271
+ function upsertPendingChangeRequestLine(content, requestText, lang) {
10272
+ const normalizedRequest = requestText.trim().replace(/\s+/g, " ");
10273
+ const preferredKey = lang === "ko" ? "\uB300\uAE30 \uC911 \uBCC0\uACBD \uC694\uCCAD" : "Pending Change Request";
10274
+ const lines = content.split("\n");
10275
+ const index = findSpecLineIndex(lines, PENDING_CHANGE_REQUEST_KEYS);
10276
+ if (index !== -1) {
10277
+ lines[index] = replaceSpecLine(
10278
+ lines[index],
10279
+ PENDING_CHANGE_REQUEST_KEYS,
10280
+ preferredKey,
10281
+ normalizedRequest
10282
+ );
10283
+ return lines.join("\n");
10284
+ }
10285
+ const insertAt = computeSpecInsertIndex(lines, [
10286
+ "Branch",
10287
+ "\uBE0C\uB79C\uCE58",
10288
+ "Issue",
10289
+ "Issue Number",
10290
+ "\uC774\uC288 \uBC88\uD638"
10291
+ ]);
10292
+ lines.splice(insertAt, 0, `- **${preferredKey}**: ${normalizedRequest}`);
10293
+ return lines.join("\n");
10294
+ }
10295
+ async function persistPendingChangeRequest(featurePath, requestText, lang) {
10296
+ const tasksPath = path16.join(featurePath, "tasks.md");
10297
+ let content;
10298
+ try {
10299
+ content = await fs20.readFile(tasksPath, "utf-8");
10300
+ } catch {
10301
+ return;
10302
+ }
10303
+ const nextContent = upsertPendingChangeRequestLine(content, requestText, lang);
10304
+ if (nextContent === content) return;
10305
+ await fs20.writeFile(tasksPath, nextContent, "utf-8");
10306
+ }
10189
10307
  function executeCommandAction(cmd, jsonMode, cwd) {
10190
10308
  const shellPath = process.env.SHELL || (process.platform === "win32" ? process.env.ComSpec || "cmd.exe" : "/bin/sh");
10191
10309
  if (jsonMode) {
@@ -10326,6 +10444,17 @@ async function runApprovedOption(state, config, lang, featureName, selectionOpti
10326
10444
  action: freshSelected.action
10327
10445
  });
10328
10446
  const featureRef = freshState.matchedFeature.folderName;
10447
+ if (selectedAction.category === "user_request_replan" && userRequest && freshState.matchedFeature.docs.tasksExists) {
10448
+ await withFileLock(
10449
+ getDocsLockPath(config.docsDir),
10450
+ async () => persistPendingChangeRequest(
10451
+ freshState.matchedFeature.path,
10452
+ userRequest,
10453
+ lang
10454
+ ),
10455
+ { owner: "context-approve:pending-change-request" }
10456
+ );
10457
+ }
10329
10458
  if (!options.execute) {
10330
10459
  const ticket = executeRequiresTicket ? await issueApprovalTicket(config, {
10331
10460
  contextVersion: freshState.contextVersion,
@@ -10893,7 +11022,7 @@ async function runContext(featureName, options) {
10893
11022
  approvalRequest: {
10894
11023
  guidance: approvalGuidance.replace(
10895
11024
  "Before asking for approval, show only `actionOptions[].approvalPrompt` lines and `approvalRequest.finalPrompt` to the user.",
10896
- "User-facing output must include only approval prompts (`A: ...`) and `finalPrompt`."
11025
+ "If approval is pending, you may prepend one brief current-stage recap derived from `matchedFeature.currentSubstate*`, then user-facing output must reuse the exact approval prompts (`A: ...`) and `finalPrompt`."
10897
11026
  ),
10898
11027
  required: approvalRequired,
10899
11028
  finalPrompt: finalApprovalPrompt,
@@ -11245,9 +11374,10 @@ function printChecklist(f, stepDefinitions) {
11245
11374
  console.log(` ${mark} ${definition.step}. ${label} ${detail}`);
11246
11375
  });
11247
11376
  }
11248
- var PRD_REQUIREMENT_ID_RE = /\bPRD-(?:FR|US|NFR)-\d+\b/gi;
11377
+ var PRD_REQUIREMENT_ID_EXACT_RE = /^PRD-[A-Z0-9]+(?:-[A-Z0-9]+)*$/i;
11378
+ var PRD_REQUIREMENT_ID_RE = /\bPRD-[A-Z0-9]+(?:-[A-Z0-9]+)*\b/gi;
11249
11379
  function isPrdRequirementId(value) {
11250
- return /^PRD-(?:FR|US|NFR)-\d+$/i.test(value.trim());
11380
+ return PRD_REQUIREMENT_ID_EXACT_RE.test(value.trim());
11251
11381
  }
11252
11382
  function isNonPrdTag(value) {
11253
11383
  const trimmed = value.trim();
@@ -12372,8 +12502,13 @@ function toCompactStatusReport(report) {
12372
12502
  };
12373
12503
  }
12374
12504
  function buildAgentOrchestrationPolicy2(autoRun, featureRef) {
12505
+ const resumableStatuses = /* @__PURE__ */ new Set([
12506
+ "delegated_handoff",
12507
+ "gate_reached",
12508
+ "manual_required"
12509
+ ]);
12375
12510
  const resumeCommand = autoRun?.run?.resumeCommand || autoRun?.resume?.flowCommand || null;
12376
- const handoffRequired = !!autoRun && !!resumeCommand;
12511
+ const handoffRequired = !!autoRun && !!resumeCommand && resumableStatuses.has(autoRun.status);
12377
12512
  const verifyCacheKey = handoffRequired ? `${(featureRef || "unknown").toLowerCase()}|${Buffer$1.from(
12378
12513
  resumeCommand
12379
12514
  ).toString("base64").slice(0, 12)}` : "";
@@ -12629,7 +12764,10 @@ function resolveAutoMode(config, options, requestText) {
12629
12764
  if (requestText) {
12630
12765
  return resolveConfigDefaultAutoMode(config);
12631
12766
  }
12632
- return null;
12767
+ if (options.approve || options.execute || options.resume) {
12768
+ return null;
12769
+ }
12770
+ return resolveConfigDefaultAutoMode(config);
12633
12771
  }
12634
12772
  function toAutoReasonCode(status) {
12635
12773
  const map = {
@@ -12647,8 +12785,6 @@ function toAutoReasonCode(status) {
12647
12785
  }
12648
12786
  function isAutoRunFailureStatus(status) {
12649
12787
  return [
12650
- "manual_required",
12651
- "selection_required",
12652
12788
  "no_progress",
12653
12789
  "request_label_missing",
12654
12790
  "request_failed",
@@ -12660,10 +12796,10 @@ function toFlowRunStatus(status) {
12660
12796
  case "delegated_handoff":
12661
12797
  case "gate_reached":
12662
12798
  case "manual_required":
12799
+ case "selection_required":
12663
12800
  return "paused";
12664
12801
  case "no_action_options":
12665
12802
  return "completed";
12666
- case "selection_required":
12667
12803
  case "no_progress":
12668
12804
  case "request_label_missing":
12669
12805
  case "request_failed":
@@ -12757,7 +12893,7 @@ async function runAutoUntilCategory(config, featureName, selectionOptions, until
12757
12893
  executions,
12758
12894
  gate: null,
12759
12895
  manual: null,
12760
- error: "Auto-run requires a single matched feature. Specify the feature explicitly."
12896
+ error: "Auto-run paused because a single matched feature is required before execution can continue."
12761
12897
  };
12762
12898
  }
12763
12899
  if (actionOptions.length === 0) {
@@ -13004,7 +13140,9 @@ async function runAutoUntilCategory(config, featureName, selectionOptions, until
13004
13140
 
13005
13141
  // src/commands/flow.ts
13006
13142
  function flowCommand(program2) {
13007
- program2.command("flow [feature-name]").description("Run combined workflow checks (context + status + doctor)").option("--json", "Output in JSON format for agents").option(
13143
+ program2.command("flow [feature-name]").description(
13144
+ "Run the default workflow auto-loop and pause at selection/approval/manual/resume boundaries"
13145
+ ).option("--json", "Output in JSON format for agents").option(
13008
13146
  "--json-compact",
13009
13147
  "Output compact JSON for agents (implies --json, reduced duplication)"
13010
13148
  ).option("--component <component>", "Component name for multi projects").option("--all", "Include completed features when auto-detecting").option("--done", "Show completed (workflow-done) features only").option(
@@ -13184,14 +13322,6 @@ async function runFlow(featureName, options) {
13184
13322
  }
13185
13323
  }
13186
13324
  }
13187
- if (autoMode && !featureName) {
13188
- if (!resolvedFeatureName) {
13189
- throw createCliError(
13190
- "CONTEXT_SELECTION_REQUIRED",
13191
- "Auto mode requires explicit <feature-name> (e.g. F004)."
13192
- );
13193
- }
13194
- }
13195
13325
  if (options.startAuto && !autoMode) {
13196
13326
  throw createCliError(
13197
13327
  "INVALID_ARGUMENT",
@@ -13672,13 +13802,13 @@ function parseLabels(raw, lang) {
13672
13802
  }
13673
13803
  return [...new Set(labels)];
13674
13804
  }
13675
- function escapeRegExp5(value) {
13805
+ function escapeRegExp6(value) {
13676
13806
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
13677
13807
  }
13678
13808
  function extractDraftMetadataValue(content, keys) {
13679
13809
  for (const key of keys) {
13680
13810
  const re = new RegExp(
13681
- `^\\s*-\\s*\\*\\*${escapeRegExp5(key)}\\*\\*\\s*:\\s*(.*?)\\s*$`,
13811
+ `^\\s*-\\s*\\*\\*${escapeRegExp6(key)}\\*\\*\\s*:\\s*(.*?)\\s*$`,
13682
13812
  "mi"
13683
13813
  );
13684
13814
  const match = content.match(re);
@@ -13797,7 +13927,7 @@ function ensureSections(body, sections, kind, lang) {
13797
13927
  };
13798
13928
  const hasMetadataField = (field) => {
13799
13929
  const re = new RegExp(
13800
- `^\\s*-\\s*\\*\\*${escapeRegExp5(field)}\\*\\*\\s*:`,
13930
+ `^\\s*-\\s*\\*\\*${escapeRegExp6(field)}\\*\\*\\s*:`,
13801
13931
  "m"
13802
13932
  );
13803
13933
  return re.test(body);
@@ -14685,7 +14815,7 @@ function stripMarkdownCodeContexts(body) {
14685
14815
  function hasIssueClosingKeyword(body, issueNumber) {
14686
14816
  if (!issueNumber) return false;
14687
14817
  const cleaned = stripMarkdownCodeContexts(body);
14688
- const issue = escapeRegExp5(issueNumber);
14818
+ const issue = escapeRegExp6(issueNumber);
14689
14819
  const closeKeywordRegex = new RegExp(
14690
14820
  `\\b(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?)\\b\\s*(?:[a-zA-Z0-9_.-]+\\/)?#\\s*${issue}\\b`,
14691
14821
  "i"
@@ -17134,7 +17264,7 @@ var DEFAULT_EVIDENCE_FOR_ANY_MODE = {
17134
17264
  residualRisks: ["none"],
17135
17265
  commandsExecuted: []
17136
17266
  };
17137
- function escapeRegExp6(value) {
17267
+ function escapeRegExp7(value) {
17138
17268
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
17139
17269
  }
17140
17270
  function normalizeDecision(raw) {
@@ -17147,15 +17277,15 @@ function normalizeDecision(raw) {
17147
17277
  if (value === "blocked" || value === "block") return "blocked";
17148
17278
  return null;
17149
17279
  }
17150
- function findSpecLineIndex(lines, keys) {
17151
- const escaped = keys.map((key) => escapeRegExp6(key));
17280
+ function findSpecLineIndex2(lines, keys) {
17281
+ const escaped = keys.map((key) => escapeRegExp7(key));
17152
17282
  const re = new RegExp(
17153
17283
  `^\\s*-\\s*\\*\\*(?:${escaped.join("|")})\\*\\*\\s*:\\s*`
17154
17284
  );
17155
17285
  return lines.findIndex((line) => re.test(line));
17156
17286
  }
17157
- function replaceSpecLine(line, keys, preferredKey, value) {
17158
- const escaped = keys.map((key) => escapeRegExp6(key));
17287
+ function replaceSpecLine2(line, keys, preferredKey, value) {
17288
+ const escaped = keys.map((key) => escapeRegExp7(key));
17159
17289
  const re = new RegExp(
17160
17290
  `^(\\s*-\\s*\\*\\*)(?:${escaped.join("|")})(\\*\\*\\s*:\\s*)(.*)$`
17161
17291
  );
@@ -17163,7 +17293,7 @@ function replaceSpecLine(line, keys, preferredKey, value) {
17163
17293
  return line.replace(re, `$1${preferredKey}$2${value}`);
17164
17294
  }
17165
17295
  function computeInsertIndex(lines, anchorKeys) {
17166
- const anchorIndex = findSpecLineIndex(lines, anchorKeys);
17296
+ const anchorIndex = findSpecLineIndex2(lines, anchorKeys);
17167
17297
  if (anchorIndex !== -1) {
17168
17298
  let cursor = anchorIndex + 1;
17169
17299
  while (cursor < lines.length && /^\s{2,}-\s+/.test(lines[cursor])) {
@@ -17179,9 +17309,9 @@ function computeInsertIndex(lines, anchorKeys) {
17179
17309
  }
17180
17310
  function upsertSpecLine(content, keys, preferredKey, value, anchorKeys) {
17181
17311
  const lines = content.split("\n");
17182
- const index = findSpecLineIndex(lines, keys);
17312
+ const index = findSpecLineIndex2(lines, keys);
17183
17313
  if (index !== -1) {
17184
- lines[index] = replaceSpecLine(lines[index], keys, preferredKey, value);
17314
+ lines[index] = replaceSpecLine2(lines[index], keys, preferredKey, value);
17185
17315
  return lines.join("\n");
17186
17316
  }
17187
17317
  const insertAt = computeInsertIndex(lines, anchorKeys);
@@ -17679,18 +17809,18 @@ async function runPrePrReview(featureName, options) {
17679
17809
  }
17680
17810
  console.log();
17681
17811
  }
17682
- function escapeRegExp7(value) {
17812
+ function escapeRegExp8(value) {
17683
17813
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
17684
17814
  }
17685
- function findSpecLineIndex2(lines, keys) {
17686
- const escaped = keys.map((key) => escapeRegExp7(key));
17815
+ function findSpecLineIndex3(lines, keys) {
17816
+ const escaped = keys.map((key) => escapeRegExp8(key));
17687
17817
  const re = new RegExp(
17688
17818
  `^\\s*-\\s*\\*\\*(?:${escaped.join("|")})\\*\\*\\s*:\\s*`
17689
17819
  );
17690
17820
  return lines.findIndex((line) => re.test(line));
17691
17821
  }
17692
- function replaceSpecLine2(line, keys, preferredKey, value) {
17693
- const escaped = keys.map((key) => escapeRegExp7(key));
17822
+ function replaceSpecLine3(line, keys, preferredKey, value) {
17823
+ const escaped = keys.map((key) => escapeRegExp8(key));
17694
17824
  const re = new RegExp(
17695
17825
  `^(\\s*-\\s*\\*\\*)(?:${escaped.join("|")})(\\*\\*\\s*:\\s*)(.*)$`
17696
17826
  );
@@ -17698,7 +17828,7 @@ function replaceSpecLine2(line, keys, preferredKey, value) {
17698
17828
  return line.replace(re, `$1${preferredKey}$2${value}`);
17699
17829
  }
17700
17830
  function computeInsertIndex2(lines, anchorKeys) {
17701
- const anchorIndex = findSpecLineIndex2(lines, anchorKeys);
17831
+ const anchorIndex = findSpecLineIndex3(lines, anchorKeys);
17702
17832
  if (anchorIndex !== -1) {
17703
17833
  let cursor = anchorIndex + 1;
17704
17834
  while (cursor < lines.length && /^\s{2,}-\s+/.test(lines[cursor])) {
@@ -17714,9 +17844,9 @@ function computeInsertIndex2(lines, anchorKeys) {
17714
17844
  }
17715
17845
  function upsertSpecLine2(content, keys, preferredKey, value, anchorKeys) {
17716
17846
  const lines = content.split("\n");
17717
- const index = findSpecLineIndex2(lines, keys);
17847
+ const index = findSpecLineIndex3(lines, keys);
17718
17848
  if (index !== -1) {
17719
- lines[index] = replaceSpecLine2(lines[index], keys, preferredKey, value);
17849
+ lines[index] = replaceSpecLine3(lines[index], keys, preferredKey, value);
17720
17850
  return lines.join("\n");
17721
17851
  }
17722
17852
  const insertAt = computeInsertIndex2(lines, anchorKeys);
@@ -18495,7 +18625,7 @@ function normalizeTaskDetailItems(values, flagName) {
18495
18625
  }
18496
18626
  return normalized;
18497
18627
  }
18498
- function escapeRegExp8(value) {
18628
+ function escapeRegExp9(value) {
18499
18629
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
18500
18630
  }
18501
18631
  function findTaskListHeadingIndex(lines) {
@@ -18530,7 +18660,7 @@ function normalizeTaskRef(value) {
18530
18660
  if (!trimmed) {
18531
18661
  throw createCliError(
18532
18662
  "INVALID_ARGUMENT",
18533
- "`--ref` is required. Use `NON-PRD` or an existing `PRD-...` requirement ID."
18663
+ "`--ref` is required. Use `NON-PRD` or an existing `PRD-*` requirement ID."
18534
18664
  );
18535
18665
  }
18536
18666
  if (isNonPrdTag(trimmed)) return "NON-PRD";
@@ -18538,14 +18668,14 @@ function normalizeTaskRef(value) {
18538
18668
  if (!isPrdRequirementId(normalized)) {
18539
18669
  throw createCliError(
18540
18670
  "INVALID_ARGUMENT",
18541
- "`--ref` must be `NON-PRD` or an existing `PRD-FR-001`-style requirement ID."
18671
+ "`--ref` must be `NON-PRD` or an existing `PRD-*` requirement ID (for example `PRD-FR-001` or `PRD-SCOPE-V1-DESKTOP-EDITOR`)."
18542
18672
  );
18543
18673
  }
18544
18674
  return normalized;
18545
18675
  }
18546
18676
  function getNextTaskSequence(content, featureFolderName) {
18547
18677
  const taskIdPattern = new RegExp(
18548
- `\\bT-${escapeRegExp8(featureFolderName)}-(\\d+)\\b`,
18678
+ `\\bT-${escapeRegExp9(featureFolderName)}-(\\d+)\\b`,
18549
18679
  "g"
18550
18680
  );
18551
18681
  let max = 0;
@@ -18675,7 +18805,7 @@ async function runTaskAdd(featureName, options) {
18675
18805
  }
18676
18806
  function taskCommand(program2) {
18677
18807
  const task = program2.command("task").description("Manage tasks");
18678
- task.command("add [feature-name]").description("Append a new task to the end of Task List").requiredOption("--title <title>", "Task title").requiredOption("--ref <ref>", "Requirement ref: NON-PRD or PRD-FR-001").option(
18808
+ task.command("add [feature-name]").description("Append a new task to the end of Task List").requiredOption("--title <title>", "Task title").requiredOption("--ref <ref>", "Requirement ref: NON-PRD or existing PRD-* key").option(
18679
18809
  "--acceptance <text>",
18680
18810
  "Acceptance item. Repeat to add more than one.",
18681
18811
  collectRepeatableOption,