lee-spec-kit 0.6.38 → 0.6.40
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 +191 -129
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/en/common/README.md +2 -0
- package/templates/en/common/features/README.md +1 -0
- package/templates/en/common/features/feature-base/spec.md +2 -0
- package/templates/en/common/features/feature-base/tasks.md +4 -0
- package/templates/en/common/ideas/README.md +1 -0
- package/templates/en/common/prd/README.md +2 -0
- package/templates/ko/common/README.md +2 -0
- package/templates/ko/common/features/README.md +1 -0
- package/templates/ko/common/features/feature-base/spec.md +2 -0
- package/templates/ko/common/features/feature-base/tasks.md +4 -0
- package/templates/ko/common/ideas/README.md +1 -0
- package/templates/ko/common/prd/README.md +2 -0
package/dist/index.js
CHANGED
|
@@ -8,7 +8,7 @@ import chalk8 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
|
|
11
|
+
import fs9 from 'fs';
|
|
12
12
|
import { Buffer as Buffer$1 } from 'buffer';
|
|
13
13
|
|
|
14
14
|
var getFilename = () => fileURLToPath(import.meta.url);
|
|
@@ -215,6 +215,7 @@ var koCli = {
|
|
|
215
215
|
"doctor.issue.tasksEmpty": "tasks.md\uC5D0 \uD0DC\uC2A4\uD06C\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
216
216
|
"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.)",
|
|
217
217
|
"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.",
|
|
218
|
+
"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.",
|
|
218
219
|
"doctor.issue.duplicateFeatureId": "\uC911\uBCF5 Feature ID \uAC10\uC9C0: {id} ({count}\uAC1C)",
|
|
219
220
|
"doctor.issue.missingFeatureId": "Feature \uD3F4\uB354\uBA85\uC774 F001-... \uD615\uC2DD\uC774 \uC544\uB2D9\uB2C8\uB2E4. (ID\uB97C \uCD94\uCD9C\uD560 \uC218 \uC5C6\uC74C)",
|
|
220
221
|
"init.selectLangPrompt": "\uBB38\uC11C \uC5B8\uC5B4\uB97C \uC120\uD0DD\uD558\uC138\uC694:",
|
|
@@ -469,15 +470,15 @@ var koContext = {
|
|
|
469
470
|
"context.autoRunUnavailable": "\uD604\uC7AC \uCEE8\uD14D\uC2A4\uD2B8\uC5D0\uC11C\uB294 \uC790\uB3D9 \uC2E4\uD589\uC744 \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
470
471
|
"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}",
|
|
471
472
|
"context.autoRunCommandHint": "\uC790\uB3D9 \uC2E4\uD589 \uBA85\uB839(config \uAC8C\uC774\uD2B8): {command}",
|
|
472
|
-
"context.subAgentOrchestrationHint": "\uBA54\uC778 \uC5D0\uC774\uC804\uD2B8 \
|
|
473
|
+
"context.subAgentOrchestrationHint": "\uBA54\uC778 \uC5D0\uC774\uC804\uD2B8\uAC00 \uC804\uCCB4 \uD750\uB984\uACFC \uC2B9\uC778\uC744 \uAD00\uB9AC\uD569\uB2C8\uB2E4. \uD604\uC7AC \uB2E8\uACC4\uC758 owner\uAC00 `subagent`\uBA74 \uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8\uC5D0 \uB9E1\uAE30\uACE0, `main`\uC774\uBA74 \uBA54\uC778\uC5D0\uC11C \uC9C4\uD589\uD558\uC138\uC694.",
|
|
473
474
|
"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",
|
|
474
475
|
"context.commandDetail.branchCreateWithBranch": "({scope}) \uBE0C\uB79C\uCE58 {branch}\uC6A9 worktree\uB97C \uC0DD\uC131\uD558\uAC70\uB098 \uC7AC\uC0AC\uC6A9\uD558\uC138\uC694",
|
|
475
476
|
"context.commandDetail.branchCreateGeneric": "({scope}) feature \uBE0C\uB79C\uCE58\uC6A9 worktree\uB97C \uC0DD\uC131\uD558\uAC70\uB098 \uC7AC\uC0AC\uC6A9\uD558\uC138\uC694",
|
|
476
477
|
"context.commandDetail.codeReviewMergeAfterOk": "({scope}) \uBA85\uC2DC\uC801 \uC2B9\uC778 \uD6C4 PR\uC744 \uBA38\uC9C0\uD558\uC138\uC694",
|
|
477
478
|
"context.commandDetail.codeReviewPushFix": "({scope}) \uB9AC\uBDF0 \uC218\uC815 \uCEE4\uBC0B\uC744 push\uD558\uC138\uC694",
|
|
478
|
-
"context.commandDetail.prePrReviewRun": "({scope}) \
|
|
479
|
+
"context.commandDetail.prePrReviewRun": "({scope}) \uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8(sub-agent)\uB85C PR \uC804 \uB9AC\uBDF0\uB97C \uC2E4\uD589\uD574 `review-trace.json`\uC744 \uC900\uBE44\uD558\uC138\uC694",
|
|
479
480
|
"context.commandDetail.prePrReviewRecord": "({scope}) Pre-PR \uB9AC\uBDF0 evidence\uB97C decisions.md\uC640 tasks.md\uC5D0 \uAE30\uB85D\uD558\uC138\uC694",
|
|
480
|
-
"context.commandDetail.codeReviewRun": "({scope}) \
|
|
481
|
+
"context.commandDetail.codeReviewRun": "({scope}) \uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8(sub-agent)\uB85C PR \uB9AC\uBDF0\uB97C \uC2E4\uD589\uD574 evidence/\uC218\uC815 \uC694\uC57D\uC744 \uC900\uBE44\uD558\uC138\uC694",
|
|
481
482
|
"context.actionSummary.runDocsCommand": "\uBB38\uC11C \uC791\uC5C5 \uBA85\uB839\uC744 \uC2E4\uD589\uD558\uC138\uC694",
|
|
482
483
|
"context.actionSummary.runProjectCommand": "\uD504\uB85C\uC81D\uD2B8 \uC791\uC5C5 \uBA85\uB839\uC744 \uC2E4\uD589\uD558\uC138\uC694",
|
|
483
484
|
"context.actionDetail.featureFolder": "Feature \uD3F4\uB354\uC640 \uAE30\uBCF8 \uBB38\uC11C \uACE8\uACA9\uC744 \uC900\uBE44\uD558\uC138\uC694",
|
|
@@ -495,12 +496,12 @@ var koContext = {
|
|
|
495
496
|
"context.actionDetail.issueCreatePrepareFromDoc": "issue.md \uCD08\uC548\uC744 \uBCF4\uC644\uD558\uACE0 \uC0C1\uD0DC\uB97C Ready\uB85C \uC124\uC815\uD558\uC138\uC694",
|
|
496
497
|
"context.actionDetail.issueCreateFromDoc": "Ready \uC0C1\uD0DC issue.md\uB85C \uC774\uC288\uB97C \uC0DD\uC131\uD558\uACE0 \uBC88\uD638\uB97C \uB3D9\uAE30\uD654\uD558\uC138\uC694",
|
|
497
498
|
"context.actionDetail.taskExecute": "\uD604\uC7AC \uD0DC\uC2A4\uD06C\uB97C \uC9C4\uD589\uD558\uC138\uC694",
|
|
498
|
-
"context.actionDetail.taskExecuteRun": "\
|
|
499
|
-
"context.actionDetail.taskExecuteContinue": "\
|
|
499
|
+
"context.actionDetail.taskExecuteRun": "\uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8(sub-agent) \uC791\uC5C5 handoff\uB97C \uC900\uBE44\uD558\uACE0 \uD0DC\uC2A4\uD06C\uB97C \uC2DC\uC791\uD558\uC138\uC694. (TODO\uBA74 DOING\uC73C\uB85C \uBCC0\uACBD)",
|
|
500
|
+
"context.actionDetail.taskExecuteContinue": "\uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8(sub-agent) \uC791\uC5C5 handoff\uB97C \uC900\uBE44\uD574 \uC9C4\uD589 \uC911\uC778 \uD0DC\uC2A4\uD06C\uB97C \uC774\uC5B4\uAC00\uC138\uC694",
|
|
500
501
|
"context.actionDetail.reviewFixCommit": "\uD574\uACB0\uD55C \uB9AC\uBDF0 \uD56D\uBAA9 \uC694\uC57D\uC73C\uB85C \uB9AC\uBDF0 \uC218\uC815 \uCEE4\uBC0B\uC744 \uB9CC\uB4DC\uC138\uC694",
|
|
501
|
-
"context.actionDetail.prePrReviewRun": "PR \uC804 \uB9AC\uBDF0\uB97C \
|
|
502
|
+
"context.actionDetail.prePrReviewRun": "\uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8(sub-agent)\uB85C PR \uC804 \uB9AC\uBDF0\uB97C \uC2E4\uD589\uD574 `review-trace.json`\uC744 \uC900\uBE44\uD558\uC138\uC694",
|
|
502
503
|
"context.actionDetail.prePrReviewRecord": "PR \uC804 \uB9AC\uBDF0 evidence\uB97C decisions.md\uC640 tasks.md\uC5D0 \uAE30\uB85D\uD558\uC138\uC694",
|
|
503
|
-
"context.actionDetail.codeReviewRun": "PR \uB9AC\uBDF0\uB97C \
|
|
504
|
+
"context.actionDetail.codeReviewRun": "\uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8(sub-agent)\uB85C PR \uB9AC\uBDF0\uB97C \uC2E4\uD589\uD574 evidence/\uC218\uC815 \uC694\uC57D\uC744 \uC900\uBE44\uD558\uC138\uC694",
|
|
504
505
|
"context.actionDetail.prCreate": "PR\uC744 \uC0DD\uC131\uD558\uACE0 tasks \uAE30.md\uC758 PR \uC815\uBCF4\uB97C \uB9DE\uCD94\uC138\uC694",
|
|
505
506
|
"context.actionDetail.prCreateRequiredSequence": "PR 2\uB2E8\uACC4(\uCD08\uC548/\uC2B9\uC778 \uD6C4 \uC0DD\uC131/\uB3D9\uAE30\uD654)\uB97C \uC21C\uC11C\uB300\uB85C \uC644\uB8CC\uD558\uC138\uC694",
|
|
506
507
|
"context.actionDetail.prCreatePrepareFromDoc": "pr.md \uCD08\uC548\uC744 \uBCF4\uC644\uD558\uACE0 \uC0C1\uD0DC\uB97C Ready\uB85C \uC124\uC815\uD558\uC138\uC694",
|
|
@@ -623,7 +624,7 @@ var koMessages = {
|
|
|
623
624
|
taskCommitGateReasonMismatchLastDone: "\uCD5C\uADFC \uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uCEE4\uBC0B\uC774 \uC9C1\uC804 \uC644\uB8CC \uD0DC\uC2A4\uD06C\uC640 \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4",
|
|
624
625
|
prLegacyAsk: "tasks.md\uC5D0 PR/PR \uC0C1\uD0DC \uD544\uB4DC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. \uD15C\uD50C\uB9BF\uC744 \uCD5C\uC2E0 \uD3EC\uB9F7\uC73C\uB85C \uC5C5\uB370\uC774\uD2B8\uD560\uAE4C\uC694? (\uD655\uC778 \uD544\uC694)",
|
|
625
626
|
prePrReviewFieldMissing: "tasks.md\uC5D0 `PR \uC804 \uB9AC\uBDF0` \uD544\uB4DC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. `- **PR \uC804 \uB9AC\uBDF0**: Pending | Done` \uD56D\uBAA9\uC744 \uCD94\uAC00\uD558\uACE0 \uB2E4\uC2DC context\uB97C \uC2E4\uD589\uD558\uC138\uC694. (\uD655\uC778 \uD544\uC694)",
|
|
626
|
-
prePrReviewRun: "\uCF54\uB4DC \uB9AC\uBDF0 \uC5D0\uC774\uC804\uD2B8\uB97C \uC2E4\uD589\uD574 `spec.md`/`plan.md`/`tasks.md` \uB300\uBE44 \uAD6C\uD604 \uC801\uD569\uC131\uC744 \uAC80\uD1A0\uD558\uACE0, `Summary`/`Feature Intent Summary`/`Implementation Fit`/`Missing Cases`/`Spec Alignment Checked`/`Finding Count`/`Blocking Findings`/`Findings`/`Residual Risks`\uAC00 \uD3EC\uD568\uB41C `review-trace.json`\uC744 \uC0DD\uC131\uD55C \uB4A4 `pre-pr-review`\uB85C \uB9AC\uBDF0 \uACB0\uACFC\uB97C \uAE30\uB85D\uD558\uC138\uC694. \uD604\uC7AC evidence \uC815\uCC45\uC774 \uACBD\uB85C\uB97C \uC694\uAD6C\uD560 \uB54C\uB9CC `--evidence review-trace.json`\uC744 \uD568\uAED8 \uC0AC\uC6A9\uD558\uC138\uC694. (\uD655\uC778 \uD544\uC694)",
|
|
627
|
+
prePrReviewRun: "\uCF54\uB4DC \uB9AC\uBDF0 \uC5D0\uC774\uC804\uD2B8\uB97C \uC2E4\uD589\uD574 `spec.md`/`plan.md`/`tasks.md` \uB300\uBE44 \uAD6C\uD604 \uC801\uD569\uC131\uC744 \uAC80\uD1A0\uD558\uACE0, `Summary`/`Feature Intent Summary`/`Implementation Fit`/`Missing Cases`/`Spec Alignment Checked`/`Finding Count`/`Blocking Findings`/`Findings`/`Residual Risks`\uAC00 \uD3EC\uD568\uB41C `review-trace.json`\uC744 \uC0DD\uC131\uD55C \uB4A4 `pre-pr-review`\uB85C \uB9AC\uBDF0 \uACB0\uACFC\uB97C \uAE30\uB85D\uD558\uC138\uC694. `pre-pr-review-run` \uC790\uCCB4\uB294 evidence\uB97C \uC0DD\uC131\uD558\uAC70\uB098 \uC0C1\uD0DC\uB97C \uBC14\uB85C \uB118\uAE30\uC9C0 \uC54A\uC73C\uBA70, \uD604\uC7AC evidence \uC815\uCC45\uC774 \uACBD\uB85C\uB97C \uC694\uAD6C\uD560 \uB54C\uB9CC `--evidence review-trace.json`\uC744 \uD568\uAED8 \uC0AC\uC6A9\uD558\uC138\uC694. (\uD655\uC778 \uD544\uC694)",
|
|
627
628
|
prePrReviewEvidenceMissing: "tasks.md\uC758 `PR \uC804 \uB9AC\uBDF0 Evidence`\uAC00 \uBE44\uC5B4\uC788\uAC70\uB098 \uC720\uD6A8\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC2E4\uC81C \uD30C\uC77C \uACBD\uB85C\uC640 `Pre-PR Review Log`(\uB610\uB294 `PR \uC804 \uB9AC\uBDF0 \uB85C\uADF8`)\uC5D0 placeholder\uAC00 \uC544\uB2CC `Summary`/`Feature Intent Summary`/`Implementation Fit`/`Missing Cases`/`Spec Alignment Checked`/`Finding Count`/`Blocking Findings`/`Decision`/`Findings`(\uB610\uB294 \uBA85\uC2DC\uC801 `0 findings`)/`Residual Risks`\uB97C \uAE30\uB85D\uD558\uC138\uC694. (\uD655\uC778 \uD544\uC694)",
|
|
628
629
|
prePrReviewDecisionMissing: "tasks.md\uC758 `PR \uC804 \uB9AC\uBDF0 Decision`\uC774 \uBE44\uC5B4\uC788\uAC70\uB098 \uACB0\uC815 \uD615\uC2DD\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. `\uACB0\uC815: ...`(\uB610\uB294 `decision: ...`) \uD615\uC2DD\uC73C\uB85C \uAE30\uB85D\uD558\uC138\uC694. (\uD655\uC778 \uD544\uC694)",
|
|
629
630
|
prePrReviewFixRequired: "\uD604\uC7AC `PR \uC804 \uB9AC\uBDF0 Decision`\uC774 `{decision}`\uC785\uB2C8\uB2E4. PR \uC0DD\uC131 \uB2E8\uACC4\uB85C \uC774\uB3D9\uD558\uAE30 \uC804\uC5D0 pre-PR \uC9C0\uC801\uC0AC\uD56D\uC744 \uCF54\uB4DC\uC5D0 \uBC18\uC601\uD558\uC138\uC694. (\uD655\uC778 \uD544\uC694)",
|
|
@@ -766,6 +767,7 @@ var enCli = {
|
|
|
766
767
|
"doctor.issue.tasksEmpty": "tasks.md has no tasks.",
|
|
767
768
|
"doctor.issue.tasksDocStatusUnset": "tasks.md Doc Status is not set. (Set it to Draft, Review, or Approved.)",
|
|
768
769
|
"doctor.issue.tasksDocStatusMissing": "tasks.md is missing the Doc Status field. Add `- **Doc Status**: -` and `Values: Draft | Review | Approved`.",
|
|
770
|
+
"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.",
|
|
769
771
|
"doctor.issue.duplicateFeatureId": "Duplicate Feature ID detected: {id} ({count})",
|
|
770
772
|
"doctor.issue.missingFeatureId": "Feature folder name is not in F001-... format. (Cannot extract ID)",
|
|
771
773
|
"init.selectLangPrompt": "Select docs language:",
|
|
@@ -1020,15 +1022,15 @@ var enContext = {
|
|
|
1020
1022
|
"context.autoRunUnavailable": "Auto-run is not available in the current context.",
|
|
1021
1023
|
"context.autoRunSummary": "Run continuously by config until approval-required categories appear: {categories}",
|
|
1022
1024
|
"context.autoRunCommandHint": "Auto-run command (config-based gate): {command}",
|
|
1023
|
-
"context.subAgentOrchestrationHint": "
|
|
1025
|
+
"context.subAgentOrchestrationHint": "The main agent manages overall flow and approvals. If the current state owner is `subagent`, hand execution to a helper agent; if it is `main`, keep it in the main agent.",
|
|
1024
1026
|
"context.commandDetail.branchCreateWithWorktree": "({scope}) create or reuse worktree {worktree} for branch {branch}",
|
|
1025
1027
|
"context.commandDetail.branchCreateWithBranch": "({scope}) create or reuse worktree for branch {branch}",
|
|
1026
1028
|
"context.commandDetail.branchCreateGeneric": "({scope}) create or reuse feature branch worktree",
|
|
1027
1029
|
"context.commandDetail.codeReviewMergeAfterOk": "({scope}) merge PR after explicit OK",
|
|
1028
1030
|
"context.commandDetail.codeReviewPushFix": "({scope}) push review-fix commits",
|
|
1029
|
-
"context.commandDetail.prePrReviewRun": "({scope})
|
|
1031
|
+
"context.commandDetail.prePrReviewRun": "({scope}) run the pre-PR review via a helper agent/sub-agent and prepare `review-trace.json`",
|
|
1030
1032
|
"context.commandDetail.prePrReviewRecord": "({scope}) record pre-PR review evidence into decisions.md + tasks.md",
|
|
1031
|
-
"context.commandDetail.codeReviewRun": "({scope})
|
|
1033
|
+
"context.commandDetail.codeReviewRun": "({scope}) run the PR review via a helper agent/sub-agent and prepare evidence/fix summary",
|
|
1032
1034
|
"context.actionSummary.runDocsCommand": "Run docs command",
|
|
1033
1035
|
"context.actionSummary.runProjectCommand": "Run project command",
|
|
1034
1036
|
"context.actionDetail.featureFolder": "Prepare feature folder and baseline docs",
|
|
@@ -1046,12 +1048,12 @@ var enContext = {
|
|
|
1046
1048
|
"context.actionDetail.issueCreatePrepareFromDoc": "Refine issue.md draft and set Status to Ready",
|
|
1047
1049
|
"context.actionDetail.issueCreateFromDoc": "Create GitHub Issue from ready issue.md and sync Issue",
|
|
1048
1050
|
"context.actionDetail.taskExecute": "Proceed with the current task",
|
|
1049
|
-
"context.actionDetail.taskExecuteRun": "
|
|
1050
|
-
"context.actionDetail.taskExecuteContinue": "
|
|
1051
|
+
"context.actionDetail.taskExecuteRun": "Prepare helper agent/sub-agent task handoff and start the task. (TODO becomes DOING)",
|
|
1052
|
+
"context.actionDetail.taskExecuteContinue": "Prepare helper agent/sub-agent handoff and continue the in-progress task",
|
|
1051
1053
|
"context.actionDetail.reviewFixCommit": "Create a review-fix commit with resolved feedback summary",
|
|
1052
|
-
"context.actionDetail.prePrReviewRun": "Run pre-PR review and
|
|
1054
|
+
"context.actionDetail.prePrReviewRun": "Run the pre-PR review via a helper agent/sub-agent and prepare `review-trace.json`",
|
|
1053
1055
|
"context.actionDetail.prePrReviewRecord": "Record pre-PR review evidence into decisions.md and tasks.md",
|
|
1054
|
-
"context.actionDetail.codeReviewRun": "Run PR review and prepare
|
|
1056
|
+
"context.actionDetail.codeReviewRun": "Run the PR review via a helper agent/sub-agent and prepare evidence/fix summary",
|
|
1055
1057
|
"context.actionDetail.prCreate": "Create PR and sync PR fields in tasks.md",
|
|
1056
1058
|
"context.actionDetail.prCreateRequiredSequence": "Complete PR 2-step flow: prepare draft + OK, then create and sync",
|
|
1057
1059
|
"context.actionDetail.prCreatePrepareFromDoc": "Refine pr.md draft and set Status to Ready",
|
|
@@ -1174,7 +1176,7 @@ var enMessages = {
|
|
|
1174
1176
|
taskCommitGateReasonMismatchLastDone: "The latest project code commit does not match the last completed task",
|
|
1175
1177
|
prLegacyAsk: "tasks.md is missing PR/PR Status fields. Update to the latest template format? (CHECK required)",
|
|
1176
1178
|
prePrReviewFieldMissing: "tasks.md is missing the `Pre-PR Review` field. Add `- **Pre-PR Review**: Pending | Done` and run context again. (CHECK required)",
|
|
1177
|
-
prePrReviewRun: "Run the code review agent, compare the implementation against `spec.md`/`plan.md`/`tasks.md`, and generate `review-trace.json` with `Summary`, `Feature Intent Summary`, `Implementation Fit`, `Missing Cases`, `Spec Alignment Checked`, `Finding Count`, `Blocking Findings`, `Findings`, and `Residual Risks`. Then record findings with `pre-pr-review`; use `--evidence review-trace.json` when the active evidence policy requires a path. (CHECK required)",
|
|
1179
|
+
prePrReviewRun: "Run the code review agent, compare the implementation against `spec.md`/`plan.md`/`tasks.md`, and generate `review-trace.json` with `Summary`, `Feature Intent Summary`, `Implementation Fit`, `Missing Cases`, `Spec Alignment Checked`, `Finding Count`, `Blocking Findings`, `Findings`, and `Residual Risks`. Then record findings with `pre-pr-review`; `pre-pr-review-run` itself does not generate evidence or advance state, and you should use `--evidence review-trace.json` only when the active evidence policy requires a path. (CHECK required)",
|
|
1178
1180
|
prePrReviewEvidenceMissing: "tasks.md `Pre-PR Evidence` is empty/invalid. Point to a real file and include a `Pre-PR Review Log` section with non-placeholder `Summary`, `Feature Intent Summary`, `Implementation Fit`, `Missing Cases`, `Spec Alignment Checked`, `Finding Count`, `Blocking Findings`, `Decision`, `Findings` (or explicit `0 findings`), and `Residual Risks`. (CHECK required)",
|
|
1179
1181
|
prePrReviewDecisionMissing: "tasks.md `Pre-PR Decision` is empty/placeholder or missing decision format. Record it as `decision: ...` (or `\uACB0\uC815: ...`). (CHECK required)",
|
|
1180
1182
|
prePrReviewFixRequired: "Current `Pre-PR Decision` is `{decision}`. Apply the requested fixes from pre-PR findings before moving to PR creation. (CHECK required)",
|
|
@@ -3699,19 +3701,35 @@ function buildCodeReviewRunCommandArgs(feature) {
|
|
|
3699
3701
|
}
|
|
3700
3702
|
return commandArgs;
|
|
3701
3703
|
}
|
|
3704
|
+
function isNonEmptyStringValue(value) {
|
|
3705
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
3706
|
+
}
|
|
3707
|
+
function isNonNegativeIntegerValue(value) {
|
|
3708
|
+
return Number.isInteger(value) && Number(value) >= 0;
|
|
3709
|
+
}
|
|
3710
|
+
function isLikelyCurrentPrePrReviewEvidence(evidencePath, feature) {
|
|
3711
|
+
try {
|
|
3712
|
+
const raw = fs9.readFileSync(evidencePath, "utf-8");
|
|
3713
|
+
const parsed = JSON.parse(raw);
|
|
3714
|
+
const evidenceFeature = (parsed.feature || "").toString().trim();
|
|
3715
|
+
if (evidenceFeature && evidenceFeature !== feature.folderName) {
|
|
3716
|
+
return false;
|
|
3717
|
+
}
|
|
3718
|
+
return isNonEmptyStringValue(parsed.summary) && isNonEmptyStringValue(parsed.featureIntentSummary) && isNonEmptyStringValue(parsed.implementationFit) && isNonEmptyStringValue(parsed.missingCases) && typeof parsed.specAlignmentChecked === "boolean" && isNonNegativeIntegerValue(parsed.findingCount) && isNonNegativeIntegerValue(parsed.blockingFindings) && Array.isArray(parsed.files);
|
|
3719
|
+
} catch {
|
|
3720
|
+
return false;
|
|
3721
|
+
}
|
|
3722
|
+
}
|
|
3702
3723
|
function resolvePrePrReviewEvidencePath(feature) {
|
|
3703
3724
|
const docsRoot = feature.git.docsGitCwd;
|
|
3704
|
-
const docsParent = path12.dirname(docsRoot);
|
|
3705
3725
|
const candidates = [];
|
|
3706
3726
|
const explicit = (feature.prePrReview.evidence || "").trim();
|
|
3707
3727
|
if (explicit && explicit !== "-") {
|
|
3708
3728
|
if (path12.isAbsolute(explicit)) {
|
|
3709
3729
|
candidates.push(explicit);
|
|
3710
3730
|
} else {
|
|
3711
|
-
candidates.push(path12.resolve(docsRoot, explicit));
|
|
3712
|
-
candidates.push(path12.resolve(docsParent, explicit));
|
|
3713
|
-
candidates.push(path12.resolve(process.cwd(), explicit));
|
|
3714
3731
|
candidates.push(path12.resolve(feature.path, explicit));
|
|
3732
|
+
candidates.push(path12.resolve(docsRoot, explicit));
|
|
3715
3733
|
const normalizedExplicit = explicit.replace(/\\/g, "/");
|
|
3716
3734
|
if (normalizedExplicit.startsWith("docs/")) {
|
|
3717
3735
|
const withoutDocsPrefix = normalizedExplicit.slice("docs/".length);
|
|
@@ -3721,16 +3739,16 @@ function resolvePrePrReviewEvidencePath(feature) {
|
|
|
3721
3739
|
}
|
|
3722
3740
|
}
|
|
3723
3741
|
}
|
|
3724
|
-
candidates.push(path12.resolve(process.cwd(), "review-trace.json"));
|
|
3725
|
-
candidates.push(path12.join(docsRoot, "review-trace.json"));
|
|
3726
3742
|
candidates.push(path12.join(feature.path, "review-trace.json"));
|
|
3743
|
+
candidates.push(path12.join(docsRoot, "review-trace.json"));
|
|
3727
3744
|
const seen = /* @__PURE__ */ new Set();
|
|
3728
3745
|
for (const candidate of candidates) {
|
|
3729
3746
|
const abs = path12.resolve(candidate);
|
|
3730
3747
|
if (seen.has(abs)) continue;
|
|
3731
3748
|
seen.add(abs);
|
|
3732
|
-
if (!
|
|
3749
|
+
if (!fs9.existsSync(abs)) continue;
|
|
3733
3750
|
if (!abs.toLowerCase().endsWith(".json")) continue;
|
|
3751
|
+
if (!isLikelyCurrentPrePrReviewEvidence(abs, feature)) continue;
|
|
3734
3752
|
const rel = path12.relative(docsRoot, abs).replace(/\\/g, "/");
|
|
3735
3753
|
if (rel && !rel.startsWith("../")) {
|
|
3736
3754
|
return rel;
|
|
@@ -6032,7 +6050,7 @@ function resolveExistingExpectedWorktreePath(projectGitCwd, issueNumber, slug, f
|
|
|
6032
6050
|
slug,
|
|
6033
6051
|
folderName
|
|
6034
6052
|
)) {
|
|
6035
|
-
if (!
|
|
6053
|
+
if (!fs9.existsSync(candidate)) continue;
|
|
6036
6054
|
return candidate;
|
|
6037
6055
|
}
|
|
6038
6056
|
return void 0;
|
|
@@ -6062,7 +6080,7 @@ function resolveFeatureWorktreePath(ctx, projectGitCwd, issueNumber, slug, folde
|
|
|
6062
6080
|
slug,
|
|
6063
6081
|
folderName
|
|
6064
6082
|
)) {
|
|
6065
|
-
if (!
|
|
6083
|
+
if (!fs9.existsSync(candidate)) continue;
|
|
6066
6084
|
const branchName = getCurrentBranch(ctx, candidate);
|
|
6067
6085
|
if (!expectedBranchesSet.has(branchName)) continue;
|
|
6068
6086
|
return {
|
|
@@ -10090,6 +10108,108 @@ function printChecklist(f, stepDefinitions) {
|
|
|
10090
10108
|
console.log(` ${mark} ${definition.step}. ${label} ${detail}`);
|
|
10091
10109
|
});
|
|
10092
10110
|
}
|
|
10111
|
+
var PRD_REQUIREMENT_ID_RE = /\bPRD-(?:FR|US|NFR)-\d+\b/gi;
|
|
10112
|
+
function isPrdRequirementId(value) {
|
|
10113
|
+
return /^PRD-(?:FR|US|NFR)-\d+$/i.test(value.trim());
|
|
10114
|
+
}
|
|
10115
|
+
function isNonPrdTag(value) {
|
|
10116
|
+
const trimmed = value.trim();
|
|
10117
|
+
return /^NON[-_ ]?PRD$/i.test(trimmed);
|
|
10118
|
+
}
|
|
10119
|
+
function normalizeRelPath2(value) {
|
|
10120
|
+
return value.replace(/\\/g, "/").replace(/^\.\/+/, "");
|
|
10121
|
+
}
|
|
10122
|
+
function extractTitleAfterId(line, id) {
|
|
10123
|
+
const idx = line.indexOf(id);
|
|
10124
|
+
if (idx < 0) return void 0;
|
|
10125
|
+
const after = line.slice(idx + id.length);
|
|
10126
|
+
const cleaned = after.replace(/^[\s::\-–—)\]]+/, "").trim();
|
|
10127
|
+
return cleaned ? cleaned : void 0;
|
|
10128
|
+
}
|
|
10129
|
+
async function scanPrdRequirements(fsAdapter, docsDir) {
|
|
10130
|
+
const prdDir = path12.join(docsDir, "prd");
|
|
10131
|
+
const files = await walkFiles(fsAdapter, prdDir, {
|
|
10132
|
+
extensions: [".md"],
|
|
10133
|
+
ignoreDirs: [".git", "node_modules", "dist", "tmp"]
|
|
10134
|
+
});
|
|
10135
|
+
const definitions = /* @__PURE__ */ new Map();
|
|
10136
|
+
const duplicates = [];
|
|
10137
|
+
for (const filePath of files) {
|
|
10138
|
+
if (path12.basename(filePath).toLowerCase() === "readme.md") {
|
|
10139
|
+
continue;
|
|
10140
|
+
}
|
|
10141
|
+
let content = "";
|
|
10142
|
+
try {
|
|
10143
|
+
content = await fsAdapter.readFile(filePath, "utf-8");
|
|
10144
|
+
} catch {
|
|
10145
|
+
continue;
|
|
10146
|
+
}
|
|
10147
|
+
const relFile = normalizeRelPath2(path12.relative(docsDir, filePath));
|
|
10148
|
+
const lines = content.split(/\r?\n/);
|
|
10149
|
+
let inCodeBlock = false;
|
|
10150
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
10151
|
+
const line = lines[i] || "";
|
|
10152
|
+
if (/^\s*(```|~~~)/.test(line)) {
|
|
10153
|
+
inCodeBlock = !inCodeBlock;
|
|
10154
|
+
continue;
|
|
10155
|
+
}
|
|
10156
|
+
if (inCodeBlock) continue;
|
|
10157
|
+
const ids = [...line.matchAll(PRD_REQUIREMENT_ID_RE)].map(
|
|
10158
|
+
(match) => (match[0] || "").toUpperCase()
|
|
10159
|
+
);
|
|
10160
|
+
if (ids.length === 0) continue;
|
|
10161
|
+
for (const id of ids) {
|
|
10162
|
+
const def = {
|
|
10163
|
+
id,
|
|
10164
|
+
title: extractTitleAfterId(line, id),
|
|
10165
|
+
file: relFile,
|
|
10166
|
+
line: i + 1
|
|
10167
|
+
};
|
|
10168
|
+
const existing = definitions.get(id);
|
|
10169
|
+
if (existing) {
|
|
10170
|
+
duplicates.push(def);
|
|
10171
|
+
continue;
|
|
10172
|
+
}
|
|
10173
|
+
definitions.set(id, def);
|
|
10174
|
+
}
|
|
10175
|
+
}
|
|
10176
|
+
}
|
|
10177
|
+
return { definitions, duplicates, filesScanned: files.length };
|
|
10178
|
+
}
|
|
10179
|
+
function parseTaskLines(content) {
|
|
10180
|
+
const out = [];
|
|
10181
|
+
const lines = content.split(/\r?\n/);
|
|
10182
|
+
let inCodeBlock = false;
|
|
10183
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
10184
|
+
const line = lines[i] || "";
|
|
10185
|
+
if (/^\s*(```|~~~)/.test(line)) {
|
|
10186
|
+
inCodeBlock = !inCodeBlock;
|
|
10187
|
+
continue;
|
|
10188
|
+
}
|
|
10189
|
+
if (inCodeBlock) continue;
|
|
10190
|
+
const match = line.match(
|
|
10191
|
+
/^\s*-\s*\[([A-Z]+)\]((?:\[[^\]]+\])*)\s*(.+?)\s*$/
|
|
10192
|
+
);
|
|
10193
|
+
if (!match) continue;
|
|
10194
|
+
const status = (match[1] || "").trim().toUpperCase();
|
|
10195
|
+
const tagsPart = match[2] || "";
|
|
10196
|
+
const title = (match[3] || "").trim();
|
|
10197
|
+
if (!title) continue;
|
|
10198
|
+
if (status !== "TODO" && status !== "DOING" && status !== "DONE" && status !== "REVIEW") {
|
|
10199
|
+
continue;
|
|
10200
|
+
}
|
|
10201
|
+
const tags = [...tagsPart.matchAll(/\[([^\]]+)\]/g)].map((m) => (m[1] || "").trim()).filter(Boolean);
|
|
10202
|
+
out.push({
|
|
10203
|
+
status,
|
|
10204
|
+
tags,
|
|
10205
|
+
title,
|
|
10206
|
+
line: i + 1
|
|
10207
|
+
});
|
|
10208
|
+
}
|
|
10209
|
+
return out;
|
|
10210
|
+
}
|
|
10211
|
+
|
|
10212
|
+
// src/commands/doctor.ts
|
|
10093
10213
|
var FIXABLE_ISSUE_CODES = /* @__PURE__ */ new Set([
|
|
10094
10214
|
"placeholder_left",
|
|
10095
10215
|
"spec_status_unset",
|
|
@@ -10346,6 +10466,10 @@ async function checkDocsStructure(config, cwd) {
|
|
|
10346
10466
|
}
|
|
10347
10467
|
async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
|
|
10348
10468
|
const issues = [];
|
|
10469
|
+
const { definitions: prdDefinitions } = await scanPrdRequirements(
|
|
10470
|
+
fs,
|
|
10471
|
+
config.docsDir
|
|
10472
|
+
);
|
|
10349
10473
|
if (features.length === 0) {
|
|
10350
10474
|
issues.push({
|
|
10351
10475
|
level: "warn",
|
|
@@ -10427,6 +10551,24 @@ async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
|
|
|
10427
10551
|
path: formatPath(cwd, path12.join(f.path, "tasks.md"))
|
|
10428
10552
|
});
|
|
10429
10553
|
}
|
|
10554
|
+
if (f.docs.tasksExists) {
|
|
10555
|
+
const tasksPath = path12.join(f.path, "tasks.md");
|
|
10556
|
+
const tasksContent = await fs.readFile(tasksPath, "utf-8");
|
|
10557
|
+
const unknownPrdTags = [...new Set(
|
|
10558
|
+
parseTaskLines(tasksContent).flatMap((task) => task.tags).filter((tag) => isPrdRequirementId(tag)).map((tag) => tag.trim().toUpperCase()).filter((tag) => !prdDefinitions.has(tag))
|
|
10559
|
+
)].sort();
|
|
10560
|
+
if (unknownPrdTags.length > 0) {
|
|
10561
|
+
issues.push({
|
|
10562
|
+
level: "warn",
|
|
10563
|
+
code: "tasks_prd_tag_unknown",
|
|
10564
|
+
message: tr(config.lang, "cli", "doctor.issue.tasksPrdTagUnknown", {
|
|
10565
|
+
ids: unknownPrdTags.slice(0, 5).join(", "),
|
|
10566
|
+
extra: unknownPrdTags.length > 5 ? ` (+${unknownPrdTags.length - 5} more)` : ""
|
|
10567
|
+
}),
|
|
10568
|
+
path: formatPath(cwd, tasksPath)
|
|
10569
|
+
});
|
|
10570
|
+
}
|
|
10571
|
+
}
|
|
10430
10572
|
if (f.docs.tasksExists && !f.docs.tasksDocStatusFieldExists && !isInitialTemplateState) {
|
|
10431
10573
|
issues.push({
|
|
10432
10574
|
level: "warn",
|
|
@@ -15644,6 +15786,9 @@ async function runPrePrReviewRun(featureName, options) {
|
|
|
15644
15786
|
feature: featureRef,
|
|
15645
15787
|
skills: policy.skills,
|
|
15646
15788
|
fallback: policy.fallback,
|
|
15789
|
+
handoffOnly: true,
|
|
15790
|
+
advancesWorkflow: false,
|
|
15791
|
+
nextStepRequirement: "generate_review_trace_then_record",
|
|
15647
15792
|
evidenceFile: "review-trace.json",
|
|
15648
15793
|
prompt,
|
|
15649
15794
|
recordCommands: {
|
|
@@ -15659,6 +15804,11 @@ async function runPrePrReviewRun(featureName, options) {
|
|
|
15659
15804
|
}
|
|
15660
15805
|
console.log(prompt);
|
|
15661
15806
|
console.log();
|
|
15807
|
+
console.log(
|
|
15808
|
+
chalk8.yellow(
|
|
15809
|
+
config.lang === "ko" ? "\uC774 \uBA85\uB839\uC740 \uB9AC\uBDF0 handoff\uB9CC \uC900\uBE44\uD569\uB2C8\uB2E4. review-trace.json\uC744 \uC9C1\uC811 \uC0DD\uC131\uD558\uAC70\uB098 \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC0C1\uD0DC\uB97C \uBC14\uB85C \uB118\uAE30\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4." : "This command only prepares the review handoff. It does not generate review-trace.json or advance workflow state by itself."
|
|
15810
|
+
)
|
|
15811
|
+
);
|
|
15662
15812
|
console.log(`Evidence file: review-trace.json`);
|
|
15663
15813
|
console.log(`Record changes requested: ${changesRequestedCommand}`);
|
|
15664
15814
|
console.log(`Record approval: ${approveCommand}`);
|
|
@@ -15887,6 +16037,8 @@ async function runCodeReviewRun(featureName, options) {
|
|
|
15887
16037
|
feature: feature.folderName,
|
|
15888
16038
|
substateId: "code_review_run",
|
|
15889
16039
|
owner: "subagent",
|
|
16040
|
+
handoffOnly: true,
|
|
16041
|
+
advancesWorkflow: false,
|
|
15890
16042
|
nextMainState: "code_review_finalize",
|
|
15891
16043
|
tasksPath: path12.join(feature.path, "tasks.md"),
|
|
15892
16044
|
decisionsPath: path12.join(feature.path, "decisions.md"),
|
|
@@ -15899,6 +16051,11 @@ async function runCodeReviewRun(featureName, options) {
|
|
|
15899
16051
|
}
|
|
15900
16052
|
console.log(prompt);
|
|
15901
16053
|
console.log();
|
|
16054
|
+
console.log(
|
|
16055
|
+
chalk8.yellow(
|
|
16056
|
+
config.lang === "ko" ? "\uC774 \uBA85\uB839\uC740 PR \uB9AC\uBDF0 handoff\uB9CC \uC900\uBE44\uD569\uB2C8\uB2E4. \uB9AC\uBDF0 evidence/decision\uC744 \uC9C1\uC811 \uAE30\uB85D\uD558\uAC70\uB098 \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC0C1\uD0DC\uB97C \uBC14\uB85C \uB118\uAE30\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4." : "This command only prepares the PR review handoff. It does not record review evidence/decision or advance workflow state by itself."
|
|
16057
|
+
)
|
|
16058
|
+
);
|
|
15902
16059
|
console.log(chalk8.gray(`- substate: ${payload.substateId}`));
|
|
15903
16060
|
console.log(chalk8.gray(`- owner: ${payload.owner}`));
|
|
15904
16061
|
console.log(chalk8.gray(`- next main state: ${payload.nextMainState}`));
|
|
@@ -15933,105 +16090,6 @@ function codeReviewRunCommand(program2) {
|
|
|
15933
16090
|
}
|
|
15934
16091
|
);
|
|
15935
16092
|
}
|
|
15936
|
-
var PRD_REQUIREMENT_ID_RE = /\bPRD-(?:FR|US|NFR)-\d+\b/gi;
|
|
15937
|
-
function isPrdRequirementId(value) {
|
|
15938
|
-
return /^PRD-(?:FR|US|NFR)-\d+$/i.test(value.trim());
|
|
15939
|
-
}
|
|
15940
|
-
function isNonPrdTag(value) {
|
|
15941
|
-
const trimmed = value.trim();
|
|
15942
|
-
return /^NON[-_ ]?PRD$/i.test(trimmed);
|
|
15943
|
-
}
|
|
15944
|
-
function normalizeRelPath2(value) {
|
|
15945
|
-
return value.replace(/\\/g, "/").replace(/^\.\/+/, "");
|
|
15946
|
-
}
|
|
15947
|
-
function extractTitleAfterId(line, id) {
|
|
15948
|
-
const idx = line.indexOf(id);
|
|
15949
|
-
if (idx < 0) return void 0;
|
|
15950
|
-
const after = line.slice(idx + id.length);
|
|
15951
|
-
const cleaned = after.replace(/^[\s::\-–—)\]]+/, "").trim();
|
|
15952
|
-
return cleaned ? cleaned : void 0;
|
|
15953
|
-
}
|
|
15954
|
-
async function scanPrdRequirements(fsAdapter, docsDir) {
|
|
15955
|
-
const prdDir = path12.join(docsDir, "prd");
|
|
15956
|
-
const files = await walkFiles(fsAdapter, prdDir, {
|
|
15957
|
-
extensions: [".md"],
|
|
15958
|
-
ignoreDirs: [".git", "node_modules", "dist", "tmp"]
|
|
15959
|
-
});
|
|
15960
|
-
const definitions = /* @__PURE__ */ new Map();
|
|
15961
|
-
const duplicates = [];
|
|
15962
|
-
for (const filePath of files) {
|
|
15963
|
-
let content = "";
|
|
15964
|
-
try {
|
|
15965
|
-
content = await fsAdapter.readFile(filePath, "utf-8");
|
|
15966
|
-
} catch {
|
|
15967
|
-
continue;
|
|
15968
|
-
}
|
|
15969
|
-
const relFile = normalizeRelPath2(path12.relative(docsDir, filePath));
|
|
15970
|
-
const lines = content.split(/\r?\n/);
|
|
15971
|
-
let inCodeBlock = false;
|
|
15972
|
-
for (let i = 0; i < lines.length; i += 1) {
|
|
15973
|
-
const line = lines[i] || "";
|
|
15974
|
-
if (/^\s*(```|~~~)/.test(line)) {
|
|
15975
|
-
inCodeBlock = !inCodeBlock;
|
|
15976
|
-
continue;
|
|
15977
|
-
}
|
|
15978
|
-
if (inCodeBlock) continue;
|
|
15979
|
-
const ids = [...line.matchAll(PRD_REQUIREMENT_ID_RE)].map(
|
|
15980
|
-
(match) => (match[0] || "").toUpperCase()
|
|
15981
|
-
);
|
|
15982
|
-
if (ids.length === 0) continue;
|
|
15983
|
-
for (const id of ids) {
|
|
15984
|
-
const def = {
|
|
15985
|
-
id,
|
|
15986
|
-
title: extractTitleAfterId(line, id),
|
|
15987
|
-
file: relFile,
|
|
15988
|
-
line: i + 1
|
|
15989
|
-
};
|
|
15990
|
-
const existing = definitions.get(id);
|
|
15991
|
-
if (existing) {
|
|
15992
|
-
duplicates.push(def);
|
|
15993
|
-
continue;
|
|
15994
|
-
}
|
|
15995
|
-
definitions.set(id, def);
|
|
15996
|
-
}
|
|
15997
|
-
}
|
|
15998
|
-
}
|
|
15999
|
-
return { definitions, duplicates, filesScanned: files.length };
|
|
16000
|
-
}
|
|
16001
|
-
function parseTaskLines(content) {
|
|
16002
|
-
const out = [];
|
|
16003
|
-
const lines = content.split(/\r?\n/);
|
|
16004
|
-
let inCodeBlock = false;
|
|
16005
|
-
for (let i = 0; i < lines.length; i += 1) {
|
|
16006
|
-
const line = lines[i] || "";
|
|
16007
|
-
if (/^\s*(```|~~~)/.test(line)) {
|
|
16008
|
-
inCodeBlock = !inCodeBlock;
|
|
16009
|
-
continue;
|
|
16010
|
-
}
|
|
16011
|
-
if (inCodeBlock) continue;
|
|
16012
|
-
const match = line.match(
|
|
16013
|
-
/^\s*-\s*\[([A-Z]+)\]((?:\[[^\]]+\])*)\s*(.+?)\s*$/
|
|
16014
|
-
);
|
|
16015
|
-
if (!match) continue;
|
|
16016
|
-
const status = (match[1] || "").trim().toUpperCase();
|
|
16017
|
-
const tagsPart = match[2] || "";
|
|
16018
|
-
const title = (match[3] || "").trim();
|
|
16019
|
-
if (!title) continue;
|
|
16020
|
-
if (status !== "TODO" && status !== "DOING" && status !== "DONE" && status !== "REVIEW") {
|
|
16021
|
-
continue;
|
|
16022
|
-
}
|
|
16023
|
-
const tags = [...tagsPart.matchAll(/\[([^\]]+)\]/g)].map((m) => (m[1] || "").trim()).filter(Boolean);
|
|
16024
|
-
out.push({
|
|
16025
|
-
status,
|
|
16026
|
-
tags,
|
|
16027
|
-
title,
|
|
16028
|
-
line: i + 1
|
|
16029
|
-
});
|
|
16030
|
-
}
|
|
16031
|
-
return out;
|
|
16032
|
-
}
|
|
16033
|
-
|
|
16034
|
-
// src/commands/requirements.ts
|
|
16035
16093
|
function getRequirementState(tasks) {
|
|
16036
16094
|
if (tasks.total === 0) return "UNTRACKED";
|
|
16037
16095
|
if (tasks.done === tasks.total) return "DONE";
|
|
@@ -16236,7 +16294,7 @@ async function runRequirements(options) {
|
|
|
16236
16294
|
}
|
|
16237
16295
|
function parseTaskLine(line) {
|
|
16238
16296
|
const match = line.match(
|
|
16239
|
-
/^\s*-\s*\[(TODO|DOING|DONE|REVIEW)\]\[([^\]]+)\]
|
|
16297
|
+
/^\s*-\s*\[(TODO|DOING|DONE|REVIEW)\]\[([^\]]+)\](?:\[[^\]]+\])*\s+(T-[A-Za-z0-9-]+)\s+(.+?)\s*$/
|
|
16240
16298
|
);
|
|
16241
16299
|
if (!match) return null;
|
|
16242
16300
|
return {
|
|
@@ -16259,9 +16317,10 @@ function buildTaskRunPrompt(input) {
|
|
|
16259
16317
|
];
|
|
16260
16318
|
if (input.lang === "ko") {
|
|
16261
16319
|
return [
|
|
16262
|
-
`${input.mode === "start" ? "\uC0C8 task \uC2E4\uD589\
|
|
16320
|
+
`${input.mode === "start" ? "\uC0C8 task \uC2E4\uD589\uC6A9 handoff\uB97C \uC900\uBE44\uD558\uC138\uC694." : "\uC9C4\uD589 \uC911\uC778 task handoff\uB97C \uC774\uC5B4\uAC00\uC138\uC694."}`,
|
|
16263
16321
|
`- Feature: ${input.featureRef}`,
|
|
16264
16322
|
`- Task: ${input.taskId} ${input.title}`,
|
|
16323
|
+
input.mode === "start" ? "- \uC774 \uBA85\uB839\uC740 `tasks.md`\uC758 \uD604\uC7AC task\uB97C `DOING`\uC73C\uB85C \uBC14\uAFB8\uACE0, \uC774\uD6C4 \uAD6C\uD604 handoff prompt\uB97C \uC900\uBE44\uD569\uB2C8\uB2E4." : "- \uC774 \uBA85\uB839\uC740 \uC9C4\uD589 \uC911 task\uC758 \uAD6C\uD604 handoff prompt\uB97C \uB2E4\uC2DC \uC900\uBE44\uD569\uB2C8\uB2E4.",
|
|
16265
16324
|
"- \uBA3C\uC800 `spec.md`, `plan.md`, `tasks.md`\uB97C \uC77D\uACE0 \uBC94\uC704\uC640 \uC644\uB8CC \uAE30\uC900\uC744 \uC815\uB9AC\uD558\uC138\uC694.",
|
|
16266
16325
|
"- \uCF54\uB4DC \uBD84\uC11D\uACFC \uD0D0\uC0C9 \uC791\uC5C5\uC740 \uAE30\uBCF8\uC801\uC73C\uB85C \uC11C\uBE0C\uC5D0\uC774\uC804\uD2B8\uB97C \uC0AC\uC6A9\uD558\uC138\uC694.",
|
|
16267
16326
|
"- \uC601\uD5A5 \uBC94\uC704 \uBD84\uC11D, \uD14C\uC2A4\uD2B8 \uC704\uCE58 \uD0D0\uC0C9, \uAE30\uC874 \uD328\uD134 \uC870\uC0AC\uCC98\uB7FC \uB3C5\uB9BD\uC801\uC778 \uBD84\uC11D\uC740 \uBCD1\uB82C\uB85C \uC218\uD589\uD558\uC138\uC694.",
|
|
@@ -16271,9 +16330,10 @@ function buildTaskRunPrompt(input) {
|
|
|
16271
16330
|
].join("\n");
|
|
16272
16331
|
}
|
|
16273
16332
|
return [
|
|
16274
|
-
input.mode === "start" ? "
|
|
16333
|
+
input.mode === "start" ? "Prepare the handoff for this task execution." : "Prepare the handoff for this in-progress task.",
|
|
16275
16334
|
`- Feature: ${input.featureRef}`,
|
|
16276
16335
|
`- Task: ${input.taskId} ${input.title}`,
|
|
16336
|
+
`- ${input.mode === "start" ? "This command marks the current task as DOING in tasks.md, then prepares the implementation handoff prompt." : "This command prepares the implementation handoff prompt again for the in-progress task."}`,
|
|
16277
16337
|
...shared.map((line) => `- ${line}`)
|
|
16278
16338
|
].join("\n");
|
|
16279
16339
|
}
|
|
@@ -16385,7 +16445,9 @@ async function runTaskRun(featureName, options) {
|
|
|
16385
16445
|
}
|
|
16386
16446
|
}
|
|
16387
16447
|
function taskRunCommand(program2) {
|
|
16388
|
-
program2.command("task-run [feature-name]").description(
|
|
16448
|
+
program2.command("task-run [feature-name]").description(
|
|
16449
|
+
"Prepare task execution handoff for sub-agent work (marks TODO tasks as DOING)"
|
|
16450
|
+
).option("--component <component>", "Component name for multi projects").option("--task <task-id>", "Explicit task id to execute").option("--json", "Output JSON").action(async (featureName, options) => {
|
|
16389
16451
|
try {
|
|
16390
16452
|
await runTaskRun(featureName, options);
|
|
16391
16453
|
} catch (error) {
|