lee-spec-kit 0.4.12 → 0.4.14
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/README.en.md +54 -1
- package/README.md +58 -1
- package/dist/index.js +314 -124
- package/package.json +1 -1
- package/templates/en/common/agents/pr-template.md +21 -3
- package/templates/en/common/agents/skills/create-feature.md +2 -16
- package/templates/en/common/agents/skills/create-pr.md +24 -4
- package/templates/en/common/agents/skills/execute-task.md +5 -3
- package/templates/en/fullstack/README.md +5 -2
- package/templates/en/fullstack/agents/agents.md +2 -1
- package/templates/en/fullstack/features/feature-base/plan.md +1 -1
- package/templates/en/fullstack/features/feature-base/spec.md +1 -1
- package/templates/en/fullstack/features/feature-base/tasks.md +10 -1
- package/templates/en/single/README.md +5 -2
- package/templates/en/single/agents/agents.md +2 -1
- package/templates/en/single/features/feature-base/plan.md +1 -1
- package/templates/en/single/features/feature-base/spec.md +1 -1
- package/templates/en/single/features/feature-base/tasks.md +10 -1
- package/templates/ko/common/agents/pr-template.md +21 -3
- package/templates/ko/common/agents/skills/create-feature.md +2 -16
- package/templates/ko/common/agents/skills/create-pr.md +24 -4
- package/templates/ko/common/agents/skills/execute-task.md +7 -13
- package/templates/ko/fullstack/README.md +5 -2
- package/templates/ko/fullstack/agents/agents.md +2 -1
- package/templates/ko/fullstack/features/feature-base/plan.md +1 -1
- package/templates/ko/fullstack/features/feature-base/spec.md +1 -1
- package/templates/ko/fullstack/features/feature-base/tasks.md +11 -2
- package/templates/ko/single/README.md +5 -2
- package/templates/ko/single/agents/agents.md +2 -1
- package/templates/ko/single/features/feature-base/plan.md +1 -1
- package/templates/ko/single/features/feature-base/spec.md +1 -1
- package/templates/ko/single/features/feature-base/tasks.md +11 -2
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import
|
|
2
|
+
import path11 from 'path';
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
4
|
import { program } from 'commander';
|
|
5
5
|
import fs8 from 'fs-extra';
|
|
@@ -10,7 +10,7 @@ import { spawn, execSync, execFileSync } from 'child_process';
|
|
|
10
10
|
import os from 'os';
|
|
11
11
|
|
|
12
12
|
var getFilename = () => fileURLToPath(import.meta.url);
|
|
13
|
-
var getDirname = () =>
|
|
13
|
+
var getDirname = () => path11.dirname(getFilename());
|
|
14
14
|
var __dirname$1 = /* @__PURE__ */ getDirname();
|
|
15
15
|
async function copyTemplates(src, dest) {
|
|
16
16
|
await fs8.copy(src, dest, {
|
|
@@ -41,10 +41,10 @@ async function replaceInFiles(dir, replacements) {
|
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
var __filename2 = fileURLToPath(import.meta.url);
|
|
44
|
-
var __dirname2 =
|
|
44
|
+
var __dirname2 = path11.dirname(__filename2);
|
|
45
45
|
function getTemplatesDir() {
|
|
46
|
-
const rootDir =
|
|
47
|
-
return
|
|
46
|
+
const rootDir = path11.resolve(__dirname2, "..");
|
|
47
|
+
return path11.join(rootDir, "templates");
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
// src/utils/i18n.ts
|
|
@@ -113,9 +113,12 @@ var I18N = {
|
|
|
113
113
|
"doctor.issue.specStatusUnset": "spec.md\uC758 Status(\uC0C1\uD0DC)\uAC00 \uC124\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. (\uD15C\uD50C\uB9BF \uADF8\uB300\uB85C\uC77C \uC218 \uC788\uC74C)",
|
|
114
114
|
"doctor.issue.planStatusUnset": "plan.md\uC758 Status(\uC0C1\uD0DC)\uAC00 \uC124\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. (\uD15C\uD50C\uB9BF \uADF8\uB300\uB85C\uC77C \uC218 \uC788\uC74C)",
|
|
115
115
|
"doctor.issue.tasksEmpty": "tasks.md\uC5D0 \uD0DC\uC2A4\uD06C\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
116
|
+
"doctor.issue.tasksDocStatusUnset": "tasks.md\uC758 \uBB38\uC11C \uC0C1\uD0DC(Doc Status)\uAC00 \uC124\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. (Review/Approved \uC911 \uD558\uB098\uB85C \uC124\uC815\uD558\uC138\uC694.)",
|
|
117
|
+
"doctor.issue.tasksDocStatusMissing": "tasks.md\uC5D0 \uBB38\uC11C \uC0C1\uD0DC(Doc Status) \uD544\uB4DC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. `- **\uBB38\uC11C \uC0C1\uD0DC**: Review | Approved`\uB97C \uCD94\uAC00\uD558\uC138\uC694.",
|
|
116
118
|
"doctor.issue.duplicateFeatureId": "\uC911\uBCF5 Feature ID \uAC10\uC9C0: {id} ({count}\uAC1C)",
|
|
117
119
|
"doctor.issue.missingFeatureId": "Feature \uD3F4\uB354\uBA85\uC774 F001-... \uD615\uC2DD\uC774 \uC544\uB2D9\uB2C8\uB2E4. (ID\uB97C \uCD94\uCD9C\uD560 \uC218 \uC5C6\uC74C)",
|
|
118
120
|
"context.noActiveFeatures": "\u26A0\uFE0F \uC9C4\uD589 \uC911\uC778 Feature\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
121
|
+
"context.header": "\u{1F4CD} \uD604\uC7AC \uCEE8\uD14D\uC2A4\uD2B8 \uD655\uC778",
|
|
119
122
|
"context.envWarnings": "\u26A0\uFE0F \uD658\uACBD \uACBD\uACE0:",
|
|
120
123
|
"context.openFallbackSummary": "(\uBE0C\uB79C\uCE58\uB85C Feature\uB97C \uD2B9\uC815\uD558\uC9C0 \uBABB\uD574 \uBBF8\uC644\uB8CC Feature\uB9CC \uD45C\uC2DC\uD569\uB2C8\uB2E4. \uC9C4\uD589 \uC911: {inProgress}\uAC1C / \uC885\uB8CC \uB300\uAE30: {readyToClose}\uAC1C / \uC644\uB8CC: {done}\uAC1C)",
|
|
121
124
|
"context.sectionInProgress": "\uC9C4\uD589 \uC911",
|
|
@@ -123,7 +126,9 @@ var I18N = {
|
|
|
123
126
|
"context.tipDetails": "Tip: \uD2B9\uC815 Feature\uC758 \uC0C1\uC138 \uC815\uBCF4\uB97C \uBCF4\uB824\uBA74:",
|
|
124
127
|
"context.tipShowAll": "\uC804\uCCB4 \uBCF4\uAE30",
|
|
125
128
|
"context.tipShowDone": "\uC644\uB8CC\uB9CC \uBCF4\uAE30",
|
|
126
|
-
"context.
|
|
129
|
+
"context.checkRequired": "[\uD655\uC778 \uD544\uC694] ",
|
|
130
|
+
"context.checkPolicyHint": "\u2139\uFE0F \uC0AC\uC6A9\uC790 \uD655\uC778 \uADDC\uCE59: /docs/agents/agents.md \uCC38\uACE0 (git push/merge/merge commit \uD3EC\uD568) \u2014 [\uD655\uC778 \uD544\uC694]\uAC00 \uC788\uC73C\uBA74 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uC815\uD655\uD788 OK \uC751\uB2F5\uC744 \uBC1B\uC740 \uB4A4 \uC9C4\uD589 (config: approval\uB85C \uC870\uC815 \uAC00\uB2A5)",
|
|
131
|
+
"context.tipDocsCommitRules": "\uCEE4\uBC0B \uBA54\uC2DC\uC9C0 \uADDC\uCE59: /docs/agents/git-workflow.md \uCC38\uACE0",
|
|
127
132
|
"context.list.docsCommitNeeded": "\uBB38\uC11C \uCEE4\uBC0B \uD544\uC694",
|
|
128
133
|
"context.list.issueNumberNeeded": "\uC774\uC288 \uBC88\uD638 \uAE30\uB85D \uD544\uC694",
|
|
129
134
|
"context.list.addPrMetadata": "PR \uBA54\uD0C0\uB370\uC774\uD130(PR/PR \uC0C1\uD0DC) \uCD94\uAC00",
|
|
@@ -187,7 +192,7 @@ var I18N = {
|
|
|
187
192
|
specApprove: "spec.md \uC2B9\uC778",
|
|
188
193
|
planWrite: "plan.md \uC791\uC131",
|
|
189
194
|
planApprove: "plan.md \uC2B9\uC778",
|
|
190
|
-
tasksWrite: "tasks.md \uC791\uC131",
|
|
195
|
+
tasksWrite: "tasks.md \uC791\uC131/\uC2B9\uC778",
|
|
191
196
|
docsInitialCommit: "\uCD08\uAE30 \uBB38\uC11C \uCEE4\uBC0B",
|
|
192
197
|
docsCommitPlanning: "\uBB38\uC11C \uCEE4\uBC0B(\uB3D9\uAE30\uD654)",
|
|
193
198
|
issueCreate: "GitHub Issue \uC0DD\uC131",
|
|
@@ -207,6 +212,8 @@ var I18N = {
|
|
|
207
212
|
planApproval: "plan.md \uB0B4\uC6A9\uC744 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uACF5\uC720\uD558\uACE0 \uC2B9\uC778(OK)\uC744 \uBC1B\uC73C\uC138\uC694.",
|
|
208
213
|
tasksCreate: "tasks.md \uD15C\uD50C\uB9BF\uC744 \uBCF5\uC0AC\uD574 \uD0DC\uC2A4\uD06C\uB97C \uC791\uC131\uD558\uC138\uC694. (features/feature-base/tasks.md \uCC38\uACE0)",
|
|
209
214
|
tasksNeedAtLeastOne: "tasks.md\uC5D0 \uCD5C\uC18C 1\uAC1C \uC774\uC0C1\uC758 \uD0DC\uC2A4\uD06C\uB97C \uC791\uC131\uD558\uC138\uC694.",
|
|
215
|
+
tasksImprove: "tasks.md\uB97C \uBCF4\uC644\uD558\uACE0 \uBB38\uC11C \uC0C1\uD0DC\uB97C Review\uB85C \uBCC0\uACBD\uD558\uC138\uC694.",
|
|
216
|
+
tasksApproval: "tasks.md \uB0B4\uC6A9\uC744 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uACF5\uC720\uD558\uACE0 \uC9C4\uD589 \uC2B9\uC778(OK)\uC744 \uBC1B\uC73C\uC138\uC694. (\uC2B9\uC778 \uD6C4 \uBB38\uC11C \uC0C1\uD0DC\uB97C Approved\uB85C \uBCC0\uACBD)",
|
|
210
217
|
docsCommitPlanning: 'cd "{docsGitCwd}" && git add "{featurePath}" && git commit -m "docs(planning): {folderName} \uAE30\uD68D \uBB38\uC11C"',
|
|
211
218
|
issueCreateAndWrite: "GitHub Issue\uB97C \uC0DD\uC131\uD55C \uB4A4, spec.md/tasks.md\uC758 \uC774\uC288 \uBC88\uD638\uB97C \uCC44\uC6B0\uACE0 \uBB38\uC11C \uCEE4\uBC0B\uC744 \uC900\uBE44\uD558\uC138\uC694. (skills/create-issue.md \uCC38\uACE0)",
|
|
212
219
|
docsCommitIssueUpdate: 'cd "{docsGitCwd}" && git add "{featurePath}" && git commit -m "docs(#{issueNumber}): {folderName} \uBB38\uC11C \uC5C5\uB370\uC774\uD2B8"',
|
|
@@ -215,12 +222,12 @@ var I18N = {
|
|
|
215
222
|
createBranch: 'cd "{projectGitCwd}" && git checkout -b feat/{issueNumber}-{slug}',
|
|
216
223
|
tasksAllDoneButNoChecklist: '\uBAA8\uB4E0 \uD0DC\uC2A4\uD06C\uAC00 DONE\uC774\uC9C0\uB9CC \uC644\uB8CC \uC870\uAC74 \uCCB4\uD06C\uB9AC\uC2A4\uD2B8 \uC139\uC158\uC744 \uCC3E\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. tasks.md\uC758 "\uC644\uB8CC \uC870\uAC74" \uC139\uC158\uC744 \uCD94\uAC00/\uD655\uC778\uD558\uC138\uC694.',
|
|
217
224
|
tasksAllDoneButChecklist: "\uBAA8\uB4E0 \uD0DC\uC2A4\uD06C\uAC00 DONE\uC774\uC9C0\uB9CC \uC644\uB8CC \uC870\uAC74 \uCCB4\uD06C\uB9AC\uC2A4\uD2B8\uAC00 \uC644\uC804\uD788 \uCCB4\uD06C\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. ({checked}/{total})",
|
|
218
|
-
finishDoingTask: '\uD604\uC7AC DOING/REVIEW \uC911\uC778 \uD0DC\uC2A4\uD06C\uB97C \uC644\uB8CC\uD558\uC138\uC694: "{title}" ({done}/{total}) (skills/execute-task.md \uCC38\uACE0)',
|
|
219
|
-
startNextTodoTask: '\uB2E4\uC74C TODO \uD0DC\uC2A4\uD06C\uB97C \uC2DC\uC791\uD558\uC138\uC694: "{title}" ({done}/{total}) (skills/execute-task.md \uCC38\uACE0)',
|
|
225
|
+
finishDoingTask: '\uD604\uC7AC DOING/REVIEW \uC911\uC778 \uD0DC\uC2A4\uD06C\uB97C \uC644\uB8CC\uD558\uC138\uC694: "{title}" ({done}/{total}) (\uC644\uB8CC \uC804 \uACB0\uACFC/\uAC80\uC99D \uACF5\uC720 + \uC2B9\uC778(OK) \uD6C4 DONE \uCC98\uB9AC) (skills/execute-task.md \uCC38\uACE0)',
|
|
226
|
+
startNextTodoTask: '\uB2E4\uC74C TODO \uD0DC\uC2A4\uD06C\uB97C \uC2DC\uC791\uD558\uC138\uC694: "{title}" ({done}/{total}) (\uC2DC\uC791 \uC804 \uC81C\uBAA9 \uACF5\uC720 + \uC2B9\uC778(OK) \uD6C4 DOING \uCC98\uB9AC) (skills/execute-task.md \uCC38\uACE0)',
|
|
220
227
|
checkTaskStatuses: "\uD0DC\uC2A4\uD06C \uC0C1\uD0DC\uB97C \uD655\uC778\uD558\uC138\uC694. ({done}/{total}) (skills/execute-task.md \uCC38\uACE0)",
|
|
221
|
-
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? (
|
|
228
|
+
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)",
|
|
222
229
|
prCreate: "PR\uC744 \uC0DD\uC131\uD558\uACE0 tasks.md\uC5D0 PR \uB9C1\uD06C\uB97C \uAE30\uB85D\uD558\uC138\uC694. (skills/create-pr.md \uCC38\uACE0)",
|
|
223
|
-
prFillStatus: "tasks.md\uC758 PR \uC0C1\uD0DC\uB97C
|
|
230
|
+
prFillStatus: "tasks.md\uC758 PR \uC0C1\uD0DC\uB97C Review/Approved \uC911 \uD558\uB098\uB85C \uC124\uC815\uD558\uC138\uC694. (merge \uD6C4 Approved\uB85C \uC5C5\uB370\uC774\uD2B8)",
|
|
224
231
|
prResolveReview: "\uB9AC\uBDF0 \uCF54\uBA58\uD2B8\uB97C \uD574\uACB0\uD558\uACE0 PR \uC0C1\uD0DC\uB97C \uC5C5\uB370\uC774\uD2B8\uD558\uC138\uC694. (PR \uC0C1\uD0DC: Review \u2192 Approved)",
|
|
225
232
|
prRequestReview: "\uB9AC\uBDF0\uC5B4\uC5D0\uAC8C \uB9AC\uBDF0\uB97C \uC694\uCCAD\uD558\uACE0 PR \uC0C1\uD0DC\uB97C Review\uB85C \uC5C5\uB370\uC774\uD2B8\uD558\uC138\uC694.",
|
|
226
233
|
featureDone: "PR\uC774 Approved\uC774\uACE0 \uBAA8\uB4E0 \uD0DC\uC2A4\uD06C/\uC644\uB8CC \uC870\uAC74\uC774 \uCDA9\uC871\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uC774 Feature\uB294 \uC644\uB8CC \uC0C1\uD0DC\uC785\uB2C8\uB2E4.",
|
|
@@ -229,12 +236,13 @@ var I18N = {
|
|
|
229
236
|
warnings: {
|
|
230
237
|
projectBranchUnavailable: "\uD504\uB85C\uC81D\uD2B8 \uBE0C\uB79C\uCE58\uB97C \uD655\uC778\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. (standalone \uBAA8\uB4DC\uC5D0\uC11C\uB294 projectRoot\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.)",
|
|
231
238
|
docsGitUnavailable: "docs \uB808\uD3EC\uC758 git \uC0C1\uD0DC\uB97C \uD655\uC778\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. (\uB808\uD3EC \uC704\uCE58 / git init \uD655\uC778)",
|
|
232
|
-
docsUncommittedChanges: "\uBB38\uC11C \uBCC0\uACBD\uC0AC\uD56D\uC774 \uCEE4\uBC0B\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. (\uCD94\uAC00 \uBB38\uC11C \uCEE4\uBC0B \uD544\uC694)",
|
|
239
|
+
docsUncommittedChanges: "\uBB38\uC11C \uBCC0\uACBD\uC0AC\uD56D\uC774 \uCEE4\uBC0B\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. (\uCD94\uAC00 \uBB38\uC11C \uCEE4\uBC0B \uD544\uC694) \uCEE4\uBC0B \uBA54\uC2DC\uC9C0 \uADDC\uCE59: /docs/agents/git-workflow.md \uCC38\uACE0",
|
|
240
|
+
legacyTasksDocStatusField: "\uAD6C\uBC84\uC804 tasks.md \uD3EC\uB9F7\uC785\uB2C8\uB2E4. `\uBB38\uC11C \uC0C1\uD0DC` \uD544\uB4DC(Review/Approved)\uB97C \uCD94\uAC00\uD574 \uD0DC\uC2A4\uD06C \uC2B9\uC778 \uB2E8\uACC4\uB97C \uD65C\uC131\uD654\uD558\uC138\uC694.",
|
|
233
241
|
legacyTasksPrFields: "\uAD6C\uBC84\uC804 tasks.md \uD3EC\uB9F7\uC785\uB2C8\uB2E4. PR \uB2E8\uACC4 \uC804\uC5D0 `PR` \uBC0F `PR \uC0C1\uD0DC` \uD544\uB4DC\uB97C \uCD94\uAC00\uD558\uC138\uC694.",
|
|
234
242
|
workflowSpecNotApproved: "\uC644\uB8CC \uC0C1\uD0DC\uC774\uC9C0\uB9CC spec.md \uC0C1\uD0DC\uAC00 Approved\uAC00 \uC544\uB2D9\uB2C8\uB2E4. (spec.md\uC758 \uC0C1\uD0DC\uB97C Approved\uB85C \uC5C5\uB370\uC774\uD2B8\uD558\uC138\uC694.)",
|
|
235
243
|
workflowPlanNotApproved: "\uC644\uB8CC \uC0C1\uD0DC\uC774\uC9C0\uB9CC plan.md \uC0C1\uD0DC\uAC00 Approved\uAC00 \uC544\uB2D9\uB2C8\uB2E4. (plan.md\uC758 \uC0C1\uD0DC\uB97C Approved\uB85C \uC5C5\uB370\uC774\uD2B8\uD558\uC138\uC694.)",
|
|
236
244
|
workflowPrLinkMissing: "\uC644\uB8CC \uC0C1\uD0DC\uC774\uC9C0\uB9CC PR \uB9C1\uD06C\uAC00 \uBE44\uC5B4\uC788\uC2B5\uB2C8\uB2E4. (tasks.md\uC758 PR \uD544\uB4DC\uB97C \uCC44\uC6B0\uC138\uC694.)",
|
|
237
|
-
workflowPrStatusMissing: "\uC644\uB8CC \uC0C1\uD0DC\uC774\uC9C0\uB9CC PR \uC0C1\uD0DC\uAC00 \uBE44\uC5B4\uC788\uC2B5\uB2C8\uB2E4. (tasks.md\uC758 PR \uC0C1\uD0DC\uB97C
|
|
245
|
+
workflowPrStatusMissing: "\uC644\uB8CC \uC0C1\uD0DC\uC774\uC9C0\uB9CC PR \uC0C1\uD0DC\uAC00 \uBE44\uC5B4\uC788\uC2B5\uB2C8\uB2E4. (tasks.md\uC758 PR \uC0C1\uD0DC\uB97C Review/Approved \uC911 \uD558\uB098\uB85C \uC124\uC815\uD558\uC138\uC694.)",
|
|
238
246
|
workflowPrStatusNotApproved: "\uC644\uB8CC \uC0C1\uD0DC\uC774\uC9C0\uB9CC PR \uC0C1\uD0DC\uAC00 Approved\uAC00 \uC544\uB2D9\uB2C8\uB2E4. (merge \uD6C4 PR \uC0C1\uD0DC\uB97C Approved\uB85C \uC5C5\uB370\uC774\uD2B8\uD558\uC138\uC694.)"
|
|
239
247
|
}
|
|
240
248
|
},
|
|
@@ -291,9 +299,12 @@ var I18N = {
|
|
|
291
299
|
"doctor.issue.specStatusUnset": "spec.md Status is not set. (May still be a template)",
|
|
292
300
|
"doctor.issue.planStatusUnset": "plan.md Status is not set. (May still be a template)",
|
|
293
301
|
"doctor.issue.tasksEmpty": "tasks.md has no tasks.",
|
|
302
|
+
"doctor.issue.tasksDocStatusUnset": "tasks.md Doc Status is not set. (Set it to Review or Approved.)",
|
|
303
|
+
"doctor.issue.tasksDocStatusMissing": "tasks.md is missing the Doc Status field. Add `- **Doc Status**: Review | Approved`.",
|
|
294
304
|
"doctor.issue.duplicateFeatureId": "Duplicate Feature ID detected: {id} ({count})",
|
|
295
305
|
"doctor.issue.missingFeatureId": "Feature folder name is not in F001-... format. (Cannot extract ID)",
|
|
296
306
|
"context.noActiveFeatures": "\u26A0\uFE0F No active features found.",
|
|
307
|
+
"context.header": "\u{1F4CD} Current Context Check",
|
|
297
308
|
"context.envWarnings": "\u26A0\uFE0F Environment warnings:",
|
|
298
309
|
"context.openFallbackSummary": "(Could not detect a feature from the branch, so showing only open features. In Progress: {inProgress} / Ready To Close: {readyToClose} / Done: {done})",
|
|
299
310
|
"context.sectionInProgress": "In Progress",
|
|
@@ -301,7 +312,9 @@ var I18N = {
|
|
|
301
312
|
"context.tipDetails": "Tip: To view details for a feature:",
|
|
302
313
|
"context.tipShowAll": "Show all",
|
|
303
314
|
"context.tipShowDone": "Show done only",
|
|
304
|
-
"context.
|
|
315
|
+
"context.checkRequired": "[CHECK required] ",
|
|
316
|
+
"context.checkPolicyHint": "\u2139\uFE0F User check policy: see /docs/agents/agents.md (includes git push/merge and merge commits) \u2014 if you see [CHECK required], wait for explicit OK before proceeding (config: approval can override)",
|
|
317
|
+
"context.tipDocsCommitRules": "Commit message rules: /docs/agents/git-workflow.md",
|
|
305
318
|
"context.list.docsCommitNeeded": "Commit docs changes",
|
|
306
319
|
"context.list.issueNumberNeeded": "Fill issue number in docs",
|
|
307
320
|
"context.list.addPrMetadata": "Add PR metadata (PR/PR Status)",
|
|
@@ -365,7 +378,7 @@ var I18N = {
|
|
|
365
378
|
specApprove: "Approve spec.md",
|
|
366
379
|
planWrite: "Write plan.md",
|
|
367
380
|
planApprove: "Approve plan.md",
|
|
368
|
-
tasksWrite: "Write tasks.md",
|
|
381
|
+
tasksWrite: "Write/approve tasks.md",
|
|
369
382
|
docsInitialCommit: "Initial docs commit",
|
|
370
383
|
docsCommitPlanning: "Commit docs (sync)",
|
|
371
384
|
issueCreate: "Create GitHub Issue",
|
|
@@ -385,6 +398,8 @@ var I18N = {
|
|
|
385
398
|
planApproval: "Share plan.md with the user and get approval (OK).",
|
|
386
399
|
tasksCreate: "Create tasks.md by copying the template. (See features/feature-base/tasks.md)",
|
|
387
400
|
tasksNeedAtLeastOne: "Write at least 1 task in tasks.md.",
|
|
401
|
+
tasksImprove: "Improve tasks.md and change Doc Status to Review.",
|
|
402
|
+
tasksApproval: "Share tasks.md with the user and get progress approval (OK). (Then set Doc Status to Approved)",
|
|
388
403
|
docsCommitPlanning: 'cd "{docsGitCwd}" && git add "{featurePath}" && git commit -m "docs(planning): {folderName} planning docs"',
|
|
389
404
|
issueCreateAndWrite: "Create a GitHub Issue, fill the issue number in spec.md/tasks.md, then prepare a docs commit. (See skills/create-issue.md)",
|
|
390
405
|
docsCommitIssueUpdate: 'cd "{docsGitCwd}" && git add "{featurePath}" && git commit -m "docs(#{issueNumber}): {folderName} docs update"',
|
|
@@ -393,12 +408,12 @@ var I18N = {
|
|
|
393
408
|
createBranch: 'cd "{projectGitCwd}" && git checkout -b feat/{issueNumber}-{slug}',
|
|
394
409
|
tasksAllDoneButNoChecklist: 'All tasks are DONE, but no completion checklist section was found. Add/verify the "Completion Criteria" section in tasks.md.',
|
|
395
410
|
tasksAllDoneButChecklist: "All tasks are DONE, but the completion checklist is not fully checked. ({checked}/{total})",
|
|
396
|
-
finishDoingTask: 'Finish the current DOING/REVIEW task: "{title}" ({done}/{total}) (See skills/execute-task.md)',
|
|
397
|
-
startNextTodoTask: 'Start the next TODO task: "{title}" ({done}/{total}) (See skills/execute-task.md)',
|
|
411
|
+
finishDoingTask: 'Finish the current DOING/REVIEW task: "{title}" ({done}/{total}) (Share outcome/verification + get OK before marking DONE) (See skills/execute-task.md)',
|
|
412
|
+
startNextTodoTask: 'Start the next TODO task: "{title}" ({done}/{total}) (Share title + get OK before marking DOING) (See skills/execute-task.md)',
|
|
398
413
|
checkTaskStatuses: "Check task statuses. ({done}/{total}) (See skills/execute-task.md)",
|
|
399
|
-
prLegacyAsk: "tasks.md is missing PR/PR Status fields. Update to the latest template format? (
|
|
414
|
+
prLegacyAsk: "tasks.md is missing PR/PR Status fields. Update to the latest template format? (CHECK required)",
|
|
400
415
|
prCreate: "Create a PR and record the PR link in tasks.md. (See skills/create-pr.md)",
|
|
401
|
-
prFillStatus: "Set PR Status in tasks.md to
|
|
416
|
+
prFillStatus: "Set PR Status in tasks.md to Review/Approved. (After merge, update it to Approved.)",
|
|
402
417
|
prResolveReview: "Resolve review comments and update PR Status. (PR Status: Review \u2192 Approved)",
|
|
403
418
|
prRequestReview: "Request review and update PR Status to Review.",
|
|
404
419
|
featureDone: "PR is Approved and all tasks/completion criteria are satisfied. This feature is done.",
|
|
@@ -407,12 +422,13 @@ var I18N = {
|
|
|
407
422
|
warnings: {
|
|
408
423
|
projectBranchUnavailable: "Cannot determine project branch. (In standalone mode, projectRoot is required.)",
|
|
409
424
|
docsGitUnavailable: "Cannot read git status for the docs repo. (Check repo location / git init.)",
|
|
410
|
-
docsUncommittedChanges: "Docs changes are not committed. (Additional docs commit needed.)",
|
|
425
|
+
docsUncommittedChanges: "Docs changes are not committed. (Additional docs commit needed.) Commit message rules: /docs/agents/git-workflow.md",
|
|
426
|
+
legacyTasksDocStatusField: "Legacy tasks.md format detected. Add a `Doc Status` field (Review/Approved) to enable tasks approval.",
|
|
411
427
|
legacyTasksPrFields: "Legacy tasks.md format detected. Add `PR` and `PR Status` fields before PR steps.",
|
|
412
428
|
workflowSpecNotApproved: "Implementation is done but spec.md Status is not Approved. (Update spec.md Status to Approved.)",
|
|
413
429
|
workflowPlanNotApproved: "Implementation is done but plan.md Status is not Approved. (Update plan.md Status to Approved.)",
|
|
414
430
|
workflowPrLinkMissing: "Implementation is done but PR link is missing. (Fill the PR field in tasks.md.)",
|
|
415
|
-
workflowPrStatusMissing: "Implementation is done but PR Status is missing. (Set PR Status to
|
|
431
|
+
workflowPrStatusMissing: "Implementation is done but PR Status is missing. (Set PR Status to Review/Approved in tasks.md.)",
|
|
416
432
|
workflowPrStatusNotApproved: "Implementation is done but PR Status is not Approved. (After merge, update PR Status to Approved in tasks.md.)"
|
|
417
433
|
}
|
|
418
434
|
}
|
|
@@ -548,7 +564,7 @@ ${tr(lang, "cli", "common.canceled")}`)
|
|
|
548
564
|
}
|
|
549
565
|
async function runInit(options) {
|
|
550
566
|
const cwd = process.cwd();
|
|
551
|
-
const defaultName =
|
|
567
|
+
const defaultName = path11.basename(cwd);
|
|
552
568
|
let projectName = options.name || defaultName;
|
|
553
569
|
let projectType = options.type;
|
|
554
570
|
let lang = options.lang || "en";
|
|
@@ -556,7 +572,7 @@ async function runInit(options) {
|
|
|
556
572
|
let pushDocs;
|
|
557
573
|
let docsRemote;
|
|
558
574
|
let projectRoot;
|
|
559
|
-
const targetDir =
|
|
575
|
+
const targetDir = path11.resolve(cwd, options.dir || "./docs");
|
|
560
576
|
const isInsideGitRepo = checkGitRepo(cwd);
|
|
561
577
|
if (!options.yes) {
|
|
562
578
|
if (!options.lang) {
|
|
@@ -798,8 +814,8 @@ async function runInit(options) {
|
|
|
798
814
|
);
|
|
799
815
|
console.log();
|
|
800
816
|
const templatesDir = getTemplatesDir();
|
|
801
|
-
const commonPath =
|
|
802
|
-
const typePath =
|
|
817
|
+
const commonPath = path11.join(templatesDir, lang, "common");
|
|
818
|
+
const typePath = path11.join(templatesDir, lang, projectType);
|
|
803
819
|
if (await fs8.pathExists(commonPath)) {
|
|
804
820
|
await copyTemplates(commonPath, targetDir);
|
|
805
821
|
}
|
|
@@ -819,7 +835,15 @@ async function runInit(options) {
|
|
|
819
835
|
projectType,
|
|
820
836
|
lang,
|
|
821
837
|
createdAt: (/* @__PURE__ */ new Date()).toISOString().split("T")[0],
|
|
822
|
-
docsRepo
|
|
838
|
+
docsRepo,
|
|
839
|
+
pr: {
|
|
840
|
+
screenshots: { upload: false }
|
|
841
|
+
},
|
|
842
|
+
// Approval policy for "requiresUserCheck" actions shown by `context`.
|
|
843
|
+
// - builtin (default): Use requiresUserCheck embedded in steps/actions.
|
|
844
|
+
// - category: Override by action category (recommended for automation).
|
|
845
|
+
// - steps: Override by step number (fragile; not recommended).
|
|
846
|
+
approval: { mode: "builtin" }
|
|
823
847
|
};
|
|
824
848
|
if (docsRepo === "standalone") {
|
|
825
849
|
config.pushDocs = pushDocs;
|
|
@@ -830,7 +854,7 @@ async function runInit(options) {
|
|
|
830
854
|
config.projectRoot = projectRoot;
|
|
831
855
|
}
|
|
832
856
|
}
|
|
833
|
-
const configPath =
|
|
857
|
+
const configPath = path11.join(targetDir, ".lee-spec-kit.json");
|
|
834
858
|
await fs8.writeJson(configPath, config, { spaces: 2 });
|
|
835
859
|
console.log(chalk6.green(tr(lang, "cli", "init.log.docsCreated")));
|
|
836
860
|
console.log();
|
|
@@ -867,7 +891,7 @@ async function initGit(cwd, targetDir, docsRepo, lang, pushDocs, docsRemote) {
|
|
|
867
891
|
console.log(chalk6.blue(tr(lang, "cli", "init.log.gitInit")));
|
|
868
892
|
runGit(["init"], cwd);
|
|
869
893
|
}
|
|
870
|
-
const relativePath =
|
|
894
|
+
const relativePath = path11.relative(cwd, targetDir);
|
|
871
895
|
const stagedBeforeAdd = getCachedStagedFiles(cwd);
|
|
872
896
|
if (relativePath === "." && stagedBeforeAdd && stagedBeforeAdd.length > 0) {
|
|
873
897
|
console.log(
|
|
@@ -905,10 +929,10 @@ async function initGit(cwd, targetDir, docsRepo, lang, pushDocs, docsRemote) {
|
|
|
905
929
|
}
|
|
906
930
|
function getAncestorDirs(startDir) {
|
|
907
931
|
const dirs = [];
|
|
908
|
-
let current =
|
|
932
|
+
let current = path11.resolve(startDir);
|
|
909
933
|
while (true) {
|
|
910
934
|
dirs.push(current);
|
|
911
|
-
const parent =
|
|
935
|
+
const parent = path11.dirname(current);
|
|
912
936
|
if (parent === current) break;
|
|
913
937
|
current = parent;
|
|
914
938
|
}
|
|
@@ -917,21 +941,21 @@ function getAncestorDirs(startDir) {
|
|
|
917
941
|
async function getConfig(cwd) {
|
|
918
942
|
const explicitDocsDir = (process.env.LEE_SPEC_KIT_DOCS_DIR || "").trim();
|
|
919
943
|
const baseDirs = [
|
|
920
|
-
...explicitDocsDir ? [
|
|
944
|
+
...explicitDocsDir ? [path11.resolve(explicitDocsDir)] : [],
|
|
921
945
|
...getAncestorDirs(cwd)
|
|
922
946
|
];
|
|
923
947
|
const visitedBaseDirs = /* @__PURE__ */ new Set();
|
|
924
948
|
const visitedDocsDirs = /* @__PURE__ */ new Set();
|
|
925
949
|
for (const baseDir of baseDirs) {
|
|
926
|
-
const resolvedBaseDir =
|
|
950
|
+
const resolvedBaseDir = path11.resolve(baseDir);
|
|
927
951
|
if (visitedBaseDirs.has(resolvedBaseDir)) continue;
|
|
928
952
|
visitedBaseDirs.add(resolvedBaseDir);
|
|
929
|
-
const possibleDocsDirs = [
|
|
953
|
+
const possibleDocsDirs = [path11.join(resolvedBaseDir, "docs"), resolvedBaseDir];
|
|
930
954
|
for (const docsDir of possibleDocsDirs) {
|
|
931
|
-
const resolvedDocsDir =
|
|
955
|
+
const resolvedDocsDir = path11.resolve(docsDir);
|
|
932
956
|
if (visitedDocsDirs.has(resolvedDocsDir)) continue;
|
|
933
957
|
visitedDocsDirs.add(resolvedDocsDir);
|
|
934
|
-
const configPath =
|
|
958
|
+
const configPath = path11.join(resolvedDocsDir, ".lee-spec-kit.json");
|
|
935
959
|
if (await fs8.pathExists(configPath)) {
|
|
936
960
|
try {
|
|
937
961
|
const configFile = await fs8.readJson(configPath);
|
|
@@ -943,18 +967,20 @@ async function getConfig(cwd) {
|
|
|
943
967
|
docsRepo: configFile.docsRepo,
|
|
944
968
|
pushDocs: configFile.pushDocs,
|
|
945
969
|
docsRemote: configFile.docsRemote,
|
|
946
|
-
projectRoot: configFile.projectRoot
|
|
970
|
+
projectRoot: configFile.projectRoot,
|
|
971
|
+
pr: configFile.pr,
|
|
972
|
+
approval: configFile.approval
|
|
947
973
|
};
|
|
948
974
|
} catch {
|
|
949
975
|
}
|
|
950
976
|
}
|
|
951
|
-
const agentsPath =
|
|
952
|
-
const featuresPath =
|
|
977
|
+
const agentsPath = path11.join(resolvedDocsDir, "agents");
|
|
978
|
+
const featuresPath = path11.join(resolvedDocsDir, "features");
|
|
953
979
|
if (await fs8.pathExists(agentsPath) && await fs8.pathExists(featuresPath)) {
|
|
954
|
-
const bePath =
|
|
955
|
-
const fePath =
|
|
980
|
+
const bePath = path11.join(featuresPath, "be");
|
|
981
|
+
const fePath = path11.join(featuresPath, "fe");
|
|
956
982
|
const projectType = await fs8.pathExists(bePath) || await fs8.pathExists(fePath) ? "fullstack" : "single";
|
|
957
|
-
const agentsMdPath =
|
|
983
|
+
const agentsMdPath = path11.join(agentsPath, "agents.md");
|
|
958
984
|
let lang = "en";
|
|
959
985
|
if (await fs8.pathExists(agentsMdPath)) {
|
|
960
986
|
const content = await fs8.readFile(agentsMdPath, "utf-8");
|
|
@@ -1031,12 +1057,12 @@ async function runFeature(name, options) {
|
|
|
1031
1057
|
}
|
|
1032
1058
|
let featuresDir;
|
|
1033
1059
|
if (projectType === "fullstack" && repo) {
|
|
1034
|
-
featuresDir =
|
|
1060
|
+
featuresDir = path11.join(docsDir, "features", repo);
|
|
1035
1061
|
} else {
|
|
1036
|
-
featuresDir =
|
|
1062
|
+
featuresDir = path11.join(docsDir, "features");
|
|
1037
1063
|
}
|
|
1038
1064
|
const featureFolderName = `${featureId}-${name}`;
|
|
1039
|
-
const featureDir =
|
|
1065
|
+
const featureDir = path11.join(featuresDir, featureFolderName);
|
|
1040
1066
|
if (await fs8.pathExists(featureDir)) {
|
|
1041
1067
|
console.error(
|
|
1042
1068
|
chalk6.red(
|
|
@@ -1045,7 +1071,7 @@ async function runFeature(name, options) {
|
|
|
1045
1071
|
);
|
|
1046
1072
|
process.exit(1);
|
|
1047
1073
|
}
|
|
1048
|
-
const featureBasePath =
|
|
1074
|
+
const featureBasePath = path11.join(docsDir, "features", "feature-base");
|
|
1049
1075
|
if (!await fs8.pathExists(featureBasePath)) {
|
|
1050
1076
|
console.error(
|
|
1051
1077
|
chalk6.red(
|
|
@@ -1103,12 +1129,12 @@ async function runFeature(name, options) {
|
|
|
1103
1129
|
console.log();
|
|
1104
1130
|
}
|
|
1105
1131
|
async function getNextFeatureId(docsDir, projectType) {
|
|
1106
|
-
const featuresDir =
|
|
1132
|
+
const featuresDir = path11.join(docsDir, "features");
|
|
1107
1133
|
let max = 0;
|
|
1108
1134
|
const scanDirs = [];
|
|
1109
1135
|
if (projectType === "fullstack") {
|
|
1110
|
-
scanDirs.push(
|
|
1111
|
-
scanDirs.push(
|
|
1136
|
+
scanDirs.push(path11.join(featuresDir, "be"));
|
|
1137
|
+
scanDirs.push(path11.join(featuresDir, "fe"));
|
|
1112
1138
|
} else {
|
|
1113
1139
|
scanDirs.push(featuresDir);
|
|
1114
1140
|
}
|
|
@@ -1133,14 +1159,17 @@ async function getNextFeatureId(docsDir, projectType) {
|
|
|
1133
1159
|
function isCompletionChecklistDone(feature) {
|
|
1134
1160
|
return !!feature.completionChecklist && feature.completionChecklist.total > 0 && feature.completionChecklist.checked === feature.completionChecklist.total;
|
|
1135
1161
|
}
|
|
1162
|
+
function isTasksDocApproved(feature) {
|
|
1163
|
+
return !feature.docs.tasksDocStatusFieldExists || feature.tasksDocStatus === "Approved";
|
|
1164
|
+
}
|
|
1136
1165
|
function isImplementationDone(feature) {
|
|
1137
|
-
return feature.docs.tasksExists && feature.tasks.total > 0 && feature.tasks.total === feature.tasks.done && isCompletionChecklistDone(feature);
|
|
1166
|
+
return feature.docs.tasksExists && feature.tasks.total > 0 && feature.tasks.total === feature.tasks.done && isCompletionChecklistDone(feature) && isTasksDocApproved(feature);
|
|
1138
1167
|
}
|
|
1139
1168
|
function isPrMetadataConfigured(feature) {
|
|
1140
1169
|
return feature.docs.prFieldExists && feature.docs.prStatusFieldExists;
|
|
1141
1170
|
}
|
|
1142
1171
|
function isFeatureDone(feature) {
|
|
1143
|
-
return feature.specStatus === "Approved" && feature.planStatus === "Approved" && feature.docs.tasksExists && feature.tasks.total > 0 && feature.tasks.total === feature.tasks.done && isCompletionChecklistDone(feature) && isPrMetadataConfigured(feature) && !!feature.pr.link && feature.pr.status === "Approved";
|
|
1172
|
+
return feature.specStatus === "Approved" && feature.planStatus === "Approved" && feature.docs.tasksExists && feature.tasks.total > 0 && feature.tasks.total === feature.tasks.done && isCompletionChecklistDone(feature) && isTasksDocApproved(feature) && isPrMetadataConfigured(feature) && !!feature.pr.link && feature.pr.status === "Approved";
|
|
1144
1173
|
}
|
|
1145
1174
|
function getStepDefinitions(lang) {
|
|
1146
1175
|
return [
|
|
@@ -1160,6 +1189,7 @@ function getStepDefinitions(lang) {
|
|
|
1160
1189
|
actions: (f) => [
|
|
1161
1190
|
{
|
|
1162
1191
|
type: "instruction",
|
|
1192
|
+
category: "spec_write",
|
|
1163
1193
|
message: !f.docs.specExists ? tr(lang, "messages", "specCreate") : tr(lang, "messages", "specImprove")
|
|
1164
1194
|
}
|
|
1165
1195
|
]
|
|
@@ -1174,7 +1204,8 @@ function getStepDefinitions(lang) {
|
|
|
1174
1204
|
actions: () => [
|
|
1175
1205
|
{
|
|
1176
1206
|
type: "instruction",
|
|
1177
|
-
|
|
1207
|
+
category: "spec_approve",
|
|
1208
|
+
requiresUserCheck: true,
|
|
1178
1209
|
message: tr(lang, "messages", "specApproval")
|
|
1179
1210
|
}
|
|
1180
1211
|
]
|
|
@@ -1191,6 +1222,7 @@ function getStepDefinitions(lang) {
|
|
|
1191
1222
|
actions: (f) => [
|
|
1192
1223
|
{
|
|
1193
1224
|
type: "instruction",
|
|
1225
|
+
category: "plan_write",
|
|
1194
1226
|
message: !f.docs.planExists ? tr(lang, "messages", "planCreate") : tr(lang, "messages", "planImprove")
|
|
1195
1227
|
}
|
|
1196
1228
|
]
|
|
@@ -1205,7 +1237,8 @@ function getStepDefinitions(lang) {
|
|
|
1205
1237
|
actions: () => [
|
|
1206
1238
|
{
|
|
1207
1239
|
type: "instruction",
|
|
1208
|
-
|
|
1240
|
+
category: "plan_approve",
|
|
1241
|
+
requiresUserCheck: true,
|
|
1209
1242
|
message: tr(lang, "messages", "planApproval")
|
|
1210
1243
|
}
|
|
1211
1244
|
]
|
|
@@ -1215,24 +1248,54 @@ function getStepDefinitions(lang) {
|
|
|
1215
1248
|
step: 6,
|
|
1216
1249
|
name: tr(lang, "steps", "tasksWrite"),
|
|
1217
1250
|
checklist: {
|
|
1218
|
-
done: (f) => f.docs.tasksExists && f.tasks.total > 0,
|
|
1251
|
+
done: (f) => f.docs.tasksExists && f.tasks.total > 0 && isTasksDocApproved(f),
|
|
1219
1252
|
detail: (f) => f.tasks.total > 0 ? `(${f.tasks.total})` : ""
|
|
1220
1253
|
},
|
|
1221
1254
|
current: {
|
|
1222
|
-
when: (f) => f.planStatus === "Approved" && (!f.docs.tasksExists || f.tasks.total === 0),
|
|
1255
|
+
when: (f) => f.planStatus === "Approved" && (!f.docs.tasksExists || f.tasks.total === 0 || f.docs.tasksDocStatusFieldExists && (!f.tasksDocStatus || f.tasksDocStatus === "Draft" || f.tasksDocStatus === "Review")),
|
|
1223
1256
|
actions: (f) => {
|
|
1224
1257
|
if (!f.docs.tasksExists) {
|
|
1225
1258
|
return [
|
|
1226
1259
|
{
|
|
1227
1260
|
type: "instruction",
|
|
1261
|
+
category: "tasks_write",
|
|
1228
1262
|
message: tr(lang, "messages", "tasksCreate")
|
|
1229
1263
|
}
|
|
1230
1264
|
];
|
|
1231
1265
|
}
|
|
1266
|
+
if (f.tasks.total === 0) {
|
|
1267
|
+
return [
|
|
1268
|
+
{
|
|
1269
|
+
type: "instruction",
|
|
1270
|
+
category: "tasks_write",
|
|
1271
|
+
message: tr(lang, "messages", "tasksNeedAtLeastOne")
|
|
1272
|
+
}
|
|
1273
|
+
];
|
|
1274
|
+
}
|
|
1275
|
+
if (f.docs.tasksDocStatusFieldExists && (!f.tasksDocStatus || f.tasksDocStatus === "Draft")) {
|
|
1276
|
+
return [
|
|
1277
|
+
{
|
|
1278
|
+
type: "instruction",
|
|
1279
|
+
category: "tasks_write",
|
|
1280
|
+
message: tr(lang, "messages", "tasksImprove")
|
|
1281
|
+
}
|
|
1282
|
+
];
|
|
1283
|
+
}
|
|
1284
|
+
if (f.docs.tasksDocStatusFieldExists && f.tasksDocStatus === "Review") {
|
|
1285
|
+
return [
|
|
1286
|
+
{
|
|
1287
|
+
type: "instruction",
|
|
1288
|
+
category: "tasks_approve",
|
|
1289
|
+
requiresUserCheck: true,
|
|
1290
|
+
message: tr(lang, "messages", "tasksApproval")
|
|
1291
|
+
}
|
|
1292
|
+
];
|
|
1293
|
+
}
|
|
1232
1294
|
return [
|
|
1233
1295
|
{
|
|
1234
1296
|
type: "instruction",
|
|
1235
|
-
|
|
1297
|
+
category: "tasks_write",
|
|
1298
|
+
message: tr(lang, "messages", "tasksImprove")
|
|
1236
1299
|
}
|
|
1237
1300
|
];
|
|
1238
1301
|
}
|
|
@@ -1242,16 +1305,17 @@ function getStepDefinitions(lang) {
|
|
|
1242
1305
|
step: 7,
|
|
1243
1306
|
name: tr(lang, "steps", "docsInitialCommit"),
|
|
1244
1307
|
checklist: {
|
|
1245
|
-
done: (f) => f.docs.tasksExists && f.tasks.total > 0 && f.specStatus === "Approved" && f.planStatus === "Approved" && f.git.docsEverCommitted
|
|
1308
|
+
done: (f) => f.docs.tasksExists && f.tasks.total > 0 && f.specStatus === "Approved" && f.planStatus === "Approved" && isTasksDocApproved(f) && f.git.docsEverCommitted
|
|
1246
1309
|
},
|
|
1247
1310
|
current: {
|
|
1248
|
-
when: (f) => f.docs.tasksExists && f.tasks.total > 0 && f.specStatus === "Approved" && f.planStatus === "Approved" && !f.activeTask && !f.git.docsEverCommitted && f.git.docsHasUncommittedChanges,
|
|
1311
|
+
when: (f) => f.docs.tasksExists && f.tasks.total > 0 && f.specStatus === "Approved" && f.planStatus === "Approved" && isTasksDocApproved(f) && !f.activeTask && !f.git.docsEverCommitted && f.git.docsHasUncommittedChanges,
|
|
1249
1312
|
actions: (f) => {
|
|
1250
1313
|
if (f.issueNumber) {
|
|
1251
1314
|
return [
|
|
1252
1315
|
{
|
|
1253
1316
|
type: "command",
|
|
1254
|
-
|
|
1317
|
+
category: "docs_commit",
|
|
1318
|
+
requiresUserCheck: true,
|
|
1255
1319
|
scope: "docs",
|
|
1256
1320
|
cwd: f.git.docsGitCwd,
|
|
1257
1321
|
cmd: tr(lang, "messages", "docsCommitIssueUpdate", {
|
|
@@ -1266,7 +1330,8 @@ function getStepDefinitions(lang) {
|
|
|
1266
1330
|
return [
|
|
1267
1331
|
{
|
|
1268
1332
|
type: "command",
|
|
1269
|
-
|
|
1333
|
+
category: "docs_commit",
|
|
1334
|
+
requiresUserCheck: true,
|
|
1270
1335
|
scope: "docs",
|
|
1271
1336
|
cwd: f.git.docsGitCwd,
|
|
1272
1337
|
cmd: tr(lang, "messages", "docsCommitPlanning", {
|
|
@@ -1286,12 +1351,13 @@ function getStepDefinitions(lang) {
|
|
|
1286
1351
|
done: (f) => !!f.issueNumber
|
|
1287
1352
|
},
|
|
1288
1353
|
current: {
|
|
1289
|
-
when: (f) => f.docs.tasksExists && f.tasks.total > 0 && f.specStatus === "Approved" && f.planStatus === "Approved" && !f.issueNumber,
|
|
1354
|
+
when: (f) => f.docs.tasksExists && f.tasks.total > 0 && f.specStatus === "Approved" && f.planStatus === "Approved" && isTasksDocApproved(f) && !f.issueNumber,
|
|
1290
1355
|
actions: (f) => {
|
|
1291
1356
|
return [
|
|
1292
1357
|
{
|
|
1293
1358
|
type: "instruction",
|
|
1294
|
-
|
|
1359
|
+
category: "issue_create",
|
|
1360
|
+
requiresUserCheck: true,
|
|
1295
1361
|
message: tr(lang, "messages", "issueCreateAndWrite")
|
|
1296
1362
|
}
|
|
1297
1363
|
];
|
|
@@ -1309,6 +1375,7 @@ function getStepDefinitions(lang) {
|
|
|
1309
1375
|
return [
|
|
1310
1376
|
{
|
|
1311
1377
|
type: "instruction",
|
|
1378
|
+
category: "branch_create",
|
|
1312
1379
|
message: tr(lang, "messages", "standaloneNeedsProjectRoot")
|
|
1313
1380
|
}
|
|
1314
1381
|
];
|
|
@@ -1316,6 +1383,7 @@ function getStepDefinitions(lang) {
|
|
|
1316
1383
|
return [
|
|
1317
1384
|
{
|
|
1318
1385
|
type: "command",
|
|
1386
|
+
category: "branch_create",
|
|
1319
1387
|
scope: "project",
|
|
1320
1388
|
cwd: f.git.projectGitCwd,
|
|
1321
1389
|
cmd: tr(lang, "messages", "createBranch", {
|
|
@@ -1332,17 +1400,18 @@ function getStepDefinitions(lang) {
|
|
|
1332
1400
|
step: 10,
|
|
1333
1401
|
name: tr(lang, "steps", "tasksExecute"),
|
|
1334
1402
|
checklist: {
|
|
1335
|
-
done: (f) => f.docs.tasksExists && f.tasks.total > 0 && f.tasks.total === f.tasks.done && isCompletionChecklistDone(f),
|
|
1403
|
+
done: (f) => f.docs.tasksExists && f.tasks.total > 0 && f.tasks.total === f.tasks.done && isCompletionChecklistDone(f) && isTasksDocApproved(f),
|
|
1336
1404
|
detail: (f) => f.tasks.total > 0 ? `(${f.tasks.done}/${f.tasks.total})` : ""
|
|
1337
1405
|
},
|
|
1338
1406
|
current: {
|
|
1339
|
-
when: (f) => f.docs.tasksExists && f.tasks.total > 0 && (f.tasks.done < f.tasks.total || !isCompletionChecklistDone(f)) && (f.git.onExpectedBranch || f.tasks.done === f.tasks.total),
|
|
1407
|
+
when: (f) => f.docs.tasksExists && f.tasks.total > 0 && (f.tasks.done < f.tasks.total || !isCompletionChecklistDone(f)) && isTasksDocApproved(f) && (f.git.onExpectedBranch || f.tasks.done === f.tasks.total),
|
|
1340
1408
|
actions: (f) => {
|
|
1341
1409
|
if (f.tasks.total === f.tasks.done && !isCompletionChecklistDone(f)) {
|
|
1342
1410
|
const actions = [
|
|
1343
1411
|
{
|
|
1344
1412
|
type: "instruction",
|
|
1345
|
-
|
|
1413
|
+
category: "task_execute",
|
|
1414
|
+
requiresUserCheck: true,
|
|
1346
1415
|
message: !f.completionChecklist ? tr(lang, "messages", "tasksAllDoneButNoChecklist") : tr(lang, "messages", "tasksAllDoneButChecklist", {
|
|
1347
1416
|
checked: f.completionChecklist.checked,
|
|
1348
1417
|
total: f.completionChecklist.total
|
|
@@ -1352,7 +1421,8 @@ function getStepDefinitions(lang) {
|
|
|
1352
1421
|
if (!isPrMetadataConfigured(f)) {
|
|
1353
1422
|
actions.push({
|
|
1354
1423
|
type: "instruction",
|
|
1355
|
-
|
|
1424
|
+
category: "pr_metadata_migrate",
|
|
1425
|
+
requiresUserCheck: true,
|
|
1356
1426
|
message: tr(lang, "messages", "prLegacyAsk")
|
|
1357
1427
|
});
|
|
1358
1428
|
}
|
|
@@ -1362,7 +1432,8 @@ function getStepDefinitions(lang) {
|
|
|
1362
1432
|
return [
|
|
1363
1433
|
{
|
|
1364
1434
|
type: "instruction",
|
|
1365
|
-
|
|
1435
|
+
category: "task_execute",
|
|
1436
|
+
requiresUserCheck: true,
|
|
1366
1437
|
message: tr(lang, "messages", "finishDoingTask", {
|
|
1367
1438
|
title: f.activeTask.title,
|
|
1368
1439
|
done: f.tasks.done,
|
|
@@ -1376,7 +1447,8 @@ function getStepDefinitions(lang) {
|
|
|
1376
1447
|
return [
|
|
1377
1448
|
{
|
|
1378
1449
|
type: "command",
|
|
1379
|
-
|
|
1450
|
+
category: "docs_commit",
|
|
1451
|
+
requiresUserCheck: true,
|
|
1380
1452
|
scope: "docs",
|
|
1381
1453
|
cwd: f.git.docsGitCwd,
|
|
1382
1454
|
cmd: f.issueNumber ? tr(lang, "messages", "docsCommitIssueUpdate", {
|
|
@@ -1395,7 +1467,8 @@ function getStepDefinitions(lang) {
|
|
|
1395
1467
|
return [
|
|
1396
1468
|
{
|
|
1397
1469
|
type: "instruction",
|
|
1398
|
-
|
|
1470
|
+
category: "task_execute",
|
|
1471
|
+
requiresUserCheck: true,
|
|
1399
1472
|
message: tr(lang, "messages", "startNextTodoTask", {
|
|
1400
1473
|
title: f.nextTodoTask.title,
|
|
1401
1474
|
done: f.tasks.done,
|
|
@@ -1407,7 +1480,8 @@ function getStepDefinitions(lang) {
|
|
|
1407
1480
|
return [
|
|
1408
1481
|
{
|
|
1409
1482
|
type: "instruction",
|
|
1410
|
-
|
|
1483
|
+
category: "task_execute",
|
|
1484
|
+
requiresUserCheck: true,
|
|
1411
1485
|
message: tr(lang, "messages", "checkTaskStatuses", {
|
|
1412
1486
|
done: f.tasks.done,
|
|
1413
1487
|
total: f.tasks.total
|
|
@@ -1428,7 +1502,8 @@ function getStepDefinitions(lang) {
|
|
|
1428
1502
|
actions: (f) => [
|
|
1429
1503
|
{
|
|
1430
1504
|
type: "command",
|
|
1431
|
-
|
|
1505
|
+
category: "docs_commit",
|
|
1506
|
+
requiresUserCheck: true,
|
|
1432
1507
|
scope: "docs",
|
|
1433
1508
|
cwd: f.git.docsGitCwd,
|
|
1434
1509
|
cmd: f.issueNumber ? tr(lang, "messages", "docsCommitIssueUpdate", {
|
|
@@ -1456,7 +1531,8 @@ function getStepDefinitions(lang) {
|
|
|
1456
1531
|
return [
|
|
1457
1532
|
{
|
|
1458
1533
|
type: "instruction",
|
|
1459
|
-
|
|
1534
|
+
category: "pr_metadata_migrate",
|
|
1535
|
+
requiresUserCheck: true,
|
|
1460
1536
|
message: tr(lang, "messages", "prLegacyAsk")
|
|
1461
1537
|
}
|
|
1462
1538
|
];
|
|
@@ -1464,7 +1540,8 @@ function getStepDefinitions(lang) {
|
|
|
1464
1540
|
return [
|
|
1465
1541
|
{
|
|
1466
1542
|
type: "instruction",
|
|
1467
|
-
|
|
1543
|
+
category: "pr_create",
|
|
1544
|
+
requiresUserCheck: true,
|
|
1468
1545
|
message: tr(lang, "messages", "prCreate")
|
|
1469
1546
|
}
|
|
1470
1547
|
];
|
|
@@ -1484,7 +1561,8 @@ function getStepDefinitions(lang) {
|
|
|
1484
1561
|
return [
|
|
1485
1562
|
{
|
|
1486
1563
|
type: "instruction",
|
|
1487
|
-
|
|
1564
|
+
category: "pr_status_update",
|
|
1565
|
+
requiresUserCheck: true,
|
|
1488
1566
|
message: tr(lang, "messages", "prFillStatus")
|
|
1489
1567
|
}
|
|
1490
1568
|
];
|
|
@@ -1493,6 +1571,7 @@ function getStepDefinitions(lang) {
|
|
|
1493
1571
|
return [
|
|
1494
1572
|
{
|
|
1495
1573
|
type: "instruction",
|
|
1574
|
+
category: "code_review",
|
|
1496
1575
|
message: tr(lang, "messages", "prResolveReview")
|
|
1497
1576
|
}
|
|
1498
1577
|
];
|
|
@@ -1500,6 +1579,7 @@ function getStepDefinitions(lang) {
|
|
|
1500
1579
|
return [
|
|
1501
1580
|
{
|
|
1502
1581
|
type: "instruction",
|
|
1582
|
+
category: "code_review",
|
|
1503
1583
|
message: tr(lang, "messages", "prRequestReview")
|
|
1504
1584
|
}
|
|
1505
1585
|
];
|
|
@@ -1515,6 +1595,7 @@ function getStepDefinitions(lang) {
|
|
|
1515
1595
|
actions: () => [
|
|
1516
1596
|
{
|
|
1517
1597
|
type: "instruction",
|
|
1598
|
+
category: "feature_done",
|
|
1518
1599
|
message: tr(lang, "messages", "featureDone")
|
|
1519
1600
|
}
|
|
1520
1601
|
]
|
|
@@ -1529,12 +1610,53 @@ getStepDefinitions("ko");
|
|
|
1529
1610
|
getStepsMap("ko");
|
|
1530
1611
|
|
|
1531
1612
|
// src/utils/context/progress.ts
|
|
1532
|
-
function
|
|
1613
|
+
function normalizeApprovalToken(value) {
|
|
1614
|
+
return (value ?? "").trim().toLowerCase();
|
|
1615
|
+
}
|
|
1616
|
+
function applyApprovalPolicy(step, actions, approval) {
|
|
1617
|
+
if (!approval) return actions;
|
|
1618
|
+
const mode = approval.mode ?? "builtin";
|
|
1619
|
+
if (mode === "builtin") return actions;
|
|
1620
|
+
if (mode === "steps") {
|
|
1621
|
+
const required = new Set(
|
|
1622
|
+
(approval.requireCheckSteps ?? approval.requireOkSteps ?? []).map((n) => typeof n === "number" ? n : Number(n)).filter((n) => Number.isFinite(n))
|
|
1623
|
+
);
|
|
1624
|
+
const requiresUserCheck = required.has(step);
|
|
1625
|
+
return actions.map((a) => ({ ...a, requiresUserCheck }));
|
|
1626
|
+
}
|
|
1627
|
+
const requiredCategories = new Set(
|
|
1628
|
+
(approval.requireCheckCategories ?? approval.requireOkCategories ?? []).map((c) => normalizeApprovalToken(c)).filter(Boolean)
|
|
1629
|
+
);
|
|
1630
|
+
const skippedCategories = new Set(
|
|
1631
|
+
(approval.skipCheckCategories ?? approval.skipOkCategories ?? []).map((c) => normalizeApprovalToken(c)).filter(Boolean)
|
|
1632
|
+
);
|
|
1633
|
+
const defaultPolicy = approval.default ?? "keep";
|
|
1634
|
+
return actions.map((a) => {
|
|
1635
|
+
const builtin = Boolean(a.requiresUserCheck);
|
|
1636
|
+
const category = normalizeApprovalToken(a.category ?? "uncategorized");
|
|
1637
|
+
let requiresUserCheck = builtin;
|
|
1638
|
+
if (requiredCategories.has("*") || requiredCategories.has(category)) {
|
|
1639
|
+
requiresUserCheck = true;
|
|
1640
|
+
} else if (skippedCategories.has("*") || skippedCategories.has(category)) {
|
|
1641
|
+
requiresUserCheck = false;
|
|
1642
|
+
} else if (defaultPolicy === "require") {
|
|
1643
|
+
requiresUserCheck = true;
|
|
1644
|
+
} else if (defaultPolicy === "skip") {
|
|
1645
|
+
requiresUserCheck = false;
|
|
1646
|
+
}
|
|
1647
|
+
return { ...a, requiresUserCheck };
|
|
1648
|
+
});
|
|
1649
|
+
}
|
|
1650
|
+
function resolveFeatureProgress(feature, stepDefinitions, lang, approval) {
|
|
1533
1651
|
const ordered = [...stepDefinitions].sort((a, b) => a.step - b.step);
|
|
1534
1652
|
for (const definition of ordered) {
|
|
1535
1653
|
if (!definition.current) continue;
|
|
1536
1654
|
if (definition.current.when(feature)) {
|
|
1537
|
-
const actions =
|
|
1655
|
+
const actions = applyApprovalPolicy(
|
|
1656
|
+
definition.step,
|
|
1657
|
+
definition.current.actions(feature),
|
|
1658
|
+
approval
|
|
1659
|
+
);
|
|
1538
1660
|
return {
|
|
1539
1661
|
currentStep: definition.step,
|
|
1540
1662
|
actions,
|
|
@@ -1548,6 +1670,7 @@ function resolveFeatureProgress(feature, stepDefinitions, lang) {
|
|
|
1548
1670
|
actions: [
|
|
1549
1671
|
{
|
|
1550
1672
|
type: "instruction",
|
|
1673
|
+
category: "fallback",
|
|
1551
1674
|
message: tr(lang, "messages", "fallbackRerunContext")
|
|
1552
1675
|
}
|
|
1553
1676
|
],
|
|
@@ -1654,6 +1777,16 @@ function extractSpecValue(content, key) {
|
|
|
1654
1777
|
const match = content.match(regex);
|
|
1655
1778
|
return match ? match[1].trim() : void 0;
|
|
1656
1779
|
}
|
|
1780
|
+
function hasSpecKey(content, key) {
|
|
1781
|
+
const regex = new RegExp(
|
|
1782
|
+
`^\\s*-\\s*\\*\\*${escapeRegExp(key)}\\*\\*\\s*:`,
|
|
1783
|
+
"m"
|
|
1784
|
+
);
|
|
1785
|
+
return regex.test(content);
|
|
1786
|
+
}
|
|
1787
|
+
function hasAnySpecKey(content, keys) {
|
|
1788
|
+
return keys.some((key) => hasSpecKey(content, key));
|
|
1789
|
+
}
|
|
1657
1790
|
function extractFirstSpecValue(content, keys) {
|
|
1658
1791
|
for (const key of keys) {
|
|
1659
1792
|
const value = extractSpecValue(content, key);
|
|
@@ -1693,7 +1826,13 @@ function parseTasks(content) {
|
|
|
1693
1826
|
let activeTask;
|
|
1694
1827
|
let nextTodoTask;
|
|
1695
1828
|
const lines = content.split("\n");
|
|
1829
|
+
let inCodeBlock = false;
|
|
1696
1830
|
for (const line of lines) {
|
|
1831
|
+
if (/^\s*(```|~~~)/.test(line)) {
|
|
1832
|
+
inCodeBlock = !inCodeBlock;
|
|
1833
|
+
continue;
|
|
1834
|
+
}
|
|
1835
|
+
if (inCodeBlock) continue;
|
|
1697
1836
|
const match = line.match(/^\s*-\s*\[([A-Z]+)\]((?:\[[^\]]+\])*)\s*(.+?)\s*$/);
|
|
1698
1837
|
if (!match) continue;
|
|
1699
1838
|
const status = match[1].toUpperCase();
|
|
@@ -1737,13 +1876,13 @@ function isPrMetadataConfigured2(feature) {
|
|
|
1737
1876
|
}
|
|
1738
1877
|
async function parseFeature(featurePath, type, context, options) {
|
|
1739
1878
|
const lang = options.lang;
|
|
1740
|
-
const folderName =
|
|
1879
|
+
const folderName = path11.basename(featurePath);
|
|
1741
1880
|
const match = folderName.match(/^(F\d+)-(.+)$/);
|
|
1742
1881
|
const id = match?.[1];
|
|
1743
1882
|
const slug = match?.[2] || folderName;
|
|
1744
|
-
const specPath =
|
|
1745
|
-
const planPath =
|
|
1746
|
-
const tasksPath =
|
|
1883
|
+
const specPath = path11.join(featurePath, "spec.md");
|
|
1884
|
+
const planPath = path11.join(featurePath, "plan.md");
|
|
1885
|
+
const tasksPath = path11.join(featurePath, "tasks.md");
|
|
1747
1886
|
let specStatus;
|
|
1748
1887
|
let issueNumber;
|
|
1749
1888
|
const specExists = await fs8.pathExists(specPath);
|
|
@@ -1765,6 +1904,8 @@ async function parseFeature(featurePath, type, context, options) {
|
|
|
1765
1904
|
const tasksSummary = { total: 0, todo: 0, doing: 0, done: 0 };
|
|
1766
1905
|
let activeTask;
|
|
1767
1906
|
let nextTodoTask;
|
|
1907
|
+
let tasksDocStatus;
|
|
1908
|
+
let tasksDocStatusFieldExists = false;
|
|
1768
1909
|
let completionChecklist;
|
|
1769
1910
|
let prLink;
|
|
1770
1911
|
let prStatus;
|
|
@@ -1784,11 +1925,14 @@ async function parseFeature(featurePath, type, context, options) {
|
|
|
1784
1925
|
const issueValue = extractFirstSpecValue(content, ["\uC774\uC288 \uBC88\uD638", "Issue Number", "Issue"]);
|
|
1785
1926
|
issueNumber = parseIssueNumber(issueValue);
|
|
1786
1927
|
}
|
|
1928
|
+
const tasksDocStatusValue = extractFirstSpecValue(content, ["\uBB38\uC11C \uC0C1\uD0DC", "Doc Status"]);
|
|
1929
|
+
tasksDocStatusFieldExists = hasAnySpecKey(content, ["\uBB38\uC11C \uC0C1\uD0DC", "Doc Status"]);
|
|
1930
|
+
tasksDocStatus = parseDocStatus(tasksDocStatusValue);
|
|
1787
1931
|
const prValue = extractFirstSpecValue(content, ["PR", "Pull Request"]);
|
|
1788
|
-
prFieldExists =
|
|
1932
|
+
prFieldExists = hasAnySpecKey(content, ["PR", "Pull Request"]);
|
|
1789
1933
|
prLink = parsePrLink(prValue);
|
|
1790
1934
|
const prStatusValue = extractFirstSpecValue(content, ["PR \uC0C1\uD0DC", "PR Status"]);
|
|
1791
|
-
prStatusFieldExists =
|
|
1935
|
+
prStatusFieldExists = hasAnySpecKey(content, ["PR \uC0C1\uD0DC", "PR Status"]);
|
|
1792
1936
|
prStatus = parseDocStatus(prStatusValue);
|
|
1793
1937
|
}
|
|
1794
1938
|
const warnings = [];
|
|
@@ -1801,7 +1945,7 @@ async function parseFeature(featurePath, type, context, options) {
|
|
|
1801
1945
|
slug,
|
|
1802
1946
|
folderName
|
|
1803
1947
|
);
|
|
1804
|
-
const relativeFeaturePathFromDocs =
|
|
1948
|
+
const relativeFeaturePathFromDocs = path11.relative(context.docsDir, featurePath);
|
|
1805
1949
|
const docsStatus = getGitStatusPorcelain(context.docsGitCwd, [relativeFeaturePathFromDocs]);
|
|
1806
1950
|
const docsHasUncommittedChanges = docsStatus === void 0 ? true : docsStatus.trim().length > 0;
|
|
1807
1951
|
const docsLastCommit = getLastCommitForPath(
|
|
@@ -1815,10 +1959,14 @@ async function parseFeature(featurePath, type, context, options) {
|
|
|
1815
1959
|
if (tasksExists && (!prFieldExists || !prStatusFieldExists)) {
|
|
1816
1960
|
warnings.push(tr(lang, "warnings", "legacyTasksPrFields"));
|
|
1817
1961
|
}
|
|
1962
|
+
if (tasksExists && !tasksDocStatusFieldExists) {
|
|
1963
|
+
warnings.push(tr(lang, "warnings", "legacyTasksDocStatusField"));
|
|
1964
|
+
}
|
|
1818
1965
|
if (docsEverCommitted && docsHasUncommittedChanges) {
|
|
1819
1966
|
warnings.push(tr(lang, "warnings", "docsUncommittedChanges"));
|
|
1820
1967
|
}
|
|
1821
|
-
const
|
|
1968
|
+
const tasksDocApproved = !tasksDocStatusFieldExists || tasksDocStatus === "Approved";
|
|
1969
|
+
const implementationDone = tasksExists && tasksSummary.total > 0 && tasksSummary.total === tasksSummary.done && isCompletionChecklistDone2({ completionChecklist }) && tasksDocApproved;
|
|
1822
1970
|
const workflowDone = implementationDone && specStatus === "Approved" && planStatus === "Approved" && isPrMetadataConfigured2({ docs: { prFieldExists, prStatusFieldExists } }) && !!prLink && prStatus === "Approved";
|
|
1823
1971
|
if (implementationDone && !workflowDone) {
|
|
1824
1972
|
if (specStatus !== "Approved") {
|
|
@@ -1848,6 +1996,7 @@ async function parseFeature(featurePath, type, context, options) {
|
|
|
1848
1996
|
issueNumber,
|
|
1849
1997
|
specStatus,
|
|
1850
1998
|
planStatus,
|
|
1999
|
+
tasksDocStatus,
|
|
1851
2000
|
tasks: tasksSummary,
|
|
1852
2001
|
activeTask,
|
|
1853
2002
|
nextTodoTask,
|
|
@@ -1868,6 +2017,7 @@ async function parseFeature(featurePath, type, context, options) {
|
|
|
1868
2017
|
specExists,
|
|
1869
2018
|
planExists,
|
|
1870
2019
|
tasksExists,
|
|
2020
|
+
tasksDocStatusFieldExists,
|
|
1871
2021
|
prFieldExists,
|
|
1872
2022
|
prStatusFieldExists
|
|
1873
2023
|
}
|
|
@@ -1875,7 +2025,8 @@ async function parseFeature(featurePath, type, context, options) {
|
|
|
1875
2025
|
const { currentStep, actions, nextAction } = resolveFeatureProgress(
|
|
1876
2026
|
featureState,
|
|
1877
2027
|
options.stepDefinitions,
|
|
1878
|
-
lang
|
|
2028
|
+
lang,
|
|
2029
|
+
options.approval
|
|
1879
2030
|
);
|
|
1880
2031
|
return { ...featureState, currentStep, actions, nextAction, warnings };
|
|
1881
2032
|
}
|
|
@@ -1924,7 +2075,7 @@ async function scanFeatures(config) {
|
|
|
1924
2075
|
docsDir: config.docsDir,
|
|
1925
2076
|
projectBranchAvailable: Boolean(singleProject?.cwd)
|
|
1926
2077
|
},
|
|
1927
|
-
{ lang: config.lang, stepDefinitions }
|
|
2078
|
+
{ lang: config.lang, stepDefinitions, approval: config.approval }
|
|
1928
2079
|
)
|
|
1929
2080
|
);
|
|
1930
2081
|
}
|
|
@@ -1946,7 +2097,7 @@ async function scanFeatures(config) {
|
|
|
1946
2097
|
docsDir: config.docsDir,
|
|
1947
2098
|
projectBranchAvailable: Boolean(feProject?.cwd)
|
|
1948
2099
|
},
|
|
1949
|
-
{ lang: config.lang, stepDefinitions }
|
|
2100
|
+
{ lang: config.lang, stepDefinitions, approval: config.approval }
|
|
1950
2101
|
)
|
|
1951
2102
|
);
|
|
1952
2103
|
}
|
|
@@ -1965,7 +2116,7 @@ async function scanFeatures(config) {
|
|
|
1965
2116
|
docsDir: config.docsDir,
|
|
1966
2117
|
projectBranchAvailable: Boolean(beProject?.cwd)
|
|
1967
2118
|
},
|
|
1968
|
-
{ lang: config.lang, stepDefinitions }
|
|
2119
|
+
{ lang: config.lang, stepDefinitions, approval: config.approval }
|
|
1969
2120
|
)
|
|
1970
2121
|
);
|
|
1971
2122
|
}
|
|
@@ -2005,7 +2156,7 @@ async function runStatus(options) {
|
|
|
2005
2156
|
process.exit(1);
|
|
2006
2157
|
}
|
|
2007
2158
|
const { docsDir, projectType, projectName, lang } = config;
|
|
2008
|
-
const featuresDir =
|
|
2159
|
+
const featuresDir = path11.join(docsDir, "features");
|
|
2009
2160
|
const scan = await scanFeatures(config);
|
|
2010
2161
|
const features = [];
|
|
2011
2162
|
const idMap = /* @__PURE__ */ new Map();
|
|
@@ -2018,7 +2169,7 @@ async function runStatus(options) {
|
|
|
2018
2169
|
""
|
|
2019
2170
|
) : projectName ?? "{{projectName}}";
|
|
2020
2171
|
const issue = f.issueNumber ? `#${f.issueNumber}` : "-";
|
|
2021
|
-
const relPath =
|
|
2172
|
+
const relPath = path11.relative(docsDir, f.path);
|
|
2022
2173
|
if (!idMap.has(id)) idMap.set(id, []);
|
|
2023
2174
|
idMap.get(id).push(relPath);
|
|
2024
2175
|
const total = f.tasks.total;
|
|
@@ -2083,7 +2234,7 @@ async function runStatus(options) {
|
|
|
2083
2234
|
}
|
|
2084
2235
|
console.log();
|
|
2085
2236
|
if (options.write) {
|
|
2086
|
-
const outputPath =
|
|
2237
|
+
const outputPath = path11.join(featuresDir, "status.md");
|
|
2087
2238
|
const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
2088
2239
|
const content = [
|
|
2089
2240
|
"# Feature Status",
|
|
@@ -2111,7 +2262,7 @@ function escapeRegExp2(value) {
|
|
|
2111
2262
|
}
|
|
2112
2263
|
async function getFeatureNameFromSpec(featureDir, fallbackSlug, fallbackFolderName) {
|
|
2113
2264
|
try {
|
|
2114
|
-
const specPath =
|
|
2265
|
+
const specPath = path11.join(featureDir, "spec.md");
|
|
2115
2266
|
if (!await fs8.pathExists(specPath)) return fallbackSlug;
|
|
2116
2267
|
const content = await fs8.readFile(specPath, "utf-8");
|
|
2117
2268
|
const keys = ["\uAE30\uB2A5\uBA85", "Feature Name"];
|
|
@@ -2169,7 +2320,7 @@ async function runUpdate(options) {
|
|
|
2169
2320
|
}
|
|
2170
2321
|
const { docsDir, projectType, lang } = config;
|
|
2171
2322
|
const templatesDir = getTemplatesDir();
|
|
2172
|
-
const sourceDir =
|
|
2323
|
+
const sourceDir = path11.join(templatesDir, lang, projectType);
|
|
2173
2324
|
const forceOverwrite = !!options.force || await isDocsWorktreeCleanOrThrow(docsDir, lang);
|
|
2174
2325
|
const hasExplicitSelection = !!(options.agents || options.skills || options.templates);
|
|
2175
2326
|
const updateAgents = options.agents || options.skills || !hasExplicitSelection;
|
|
@@ -2188,12 +2339,12 @@ async function runUpdate(options) {
|
|
|
2188
2339
|
agentsMode === "skills" ? tr(lang, "cli", "update.updatingSkills") : tr(lang, "cli", "update.updatingAgents")
|
|
2189
2340
|
)
|
|
2190
2341
|
);
|
|
2191
|
-
const commonAgentsBase =
|
|
2192
|
-
const typeAgentsBase =
|
|
2193
|
-
const targetAgentsBase =
|
|
2194
|
-
const commonAgents = agentsMode === "skills" ?
|
|
2195
|
-
const typeAgents = agentsMode === "skills" ?
|
|
2196
|
-
const targetAgents = agentsMode === "skills" ?
|
|
2342
|
+
const commonAgentsBase = path11.join(templatesDir, lang, "common", "agents");
|
|
2343
|
+
const typeAgentsBase = path11.join(templatesDir, lang, projectType, "agents");
|
|
2344
|
+
const targetAgentsBase = path11.join(docsDir, "agents");
|
|
2345
|
+
const commonAgents = agentsMode === "skills" ? path11.join(commonAgentsBase, "skills") : commonAgentsBase;
|
|
2346
|
+
const typeAgents = agentsMode === "skills" ? path11.join(typeAgentsBase, "skills") : typeAgentsBase;
|
|
2347
|
+
const targetAgents = agentsMode === "skills" ? path11.join(targetAgentsBase, "skills") : targetAgentsBase;
|
|
2197
2348
|
const featurePath = projectType === "fullstack" ? "docs/features/{be|fe}" : "docs/features";
|
|
2198
2349
|
const projectName = config.projectName ?? "{{projectName}}";
|
|
2199
2350
|
const commonReplacements = {
|
|
@@ -2231,8 +2382,8 @@ async function runUpdate(options) {
|
|
|
2231
2382
|
}
|
|
2232
2383
|
if (updateTemplates) {
|
|
2233
2384
|
console.log(chalk6.blue(tr(lang, "cli", "update.updatingFeatureBase")));
|
|
2234
|
-
const sourceFeatureBase =
|
|
2235
|
-
const targetFeatureBase =
|
|
2385
|
+
const sourceFeatureBase = path11.join(sourceDir, "features", "feature-base");
|
|
2386
|
+
const targetFeatureBase = path11.join(docsDir, "features", "feature-base");
|
|
2236
2387
|
if (await fs8.pathExists(sourceFeatureBase)) {
|
|
2237
2388
|
const replacements = {
|
|
2238
2389
|
"{{projectName}}": config.projectName ?? "{{projectName}}"
|
|
@@ -2265,8 +2416,8 @@ async function updateFolder(sourceDir, targetDir, force, replacements, lang = DE
|
|
|
2265
2416
|
const files = await fs8.readdir(sourceDir);
|
|
2266
2417
|
let updatedCount = 0;
|
|
2267
2418
|
for (const file of files) {
|
|
2268
|
-
const sourcePath =
|
|
2269
|
-
const targetPath =
|
|
2419
|
+
const sourcePath = path11.join(sourceDir, file);
|
|
2420
|
+
const targetPath = path11.join(targetDir, file);
|
|
2270
2421
|
const stat = await fs8.stat(sourcePath);
|
|
2271
2422
|
if (stat.isFile()) {
|
|
2272
2423
|
if (protectedFiles.has(file)) {
|
|
@@ -2326,7 +2477,7 @@ function getGitTopLevel2(cwd) {
|
|
|
2326
2477
|
function getDocsPorcelainStatus(docsDir) {
|
|
2327
2478
|
const top = getGitTopLevel2(docsDir);
|
|
2328
2479
|
if (!top) return null;
|
|
2329
|
-
const rel =
|
|
2480
|
+
const rel = path11.relative(top, docsDir) || ".";
|
|
2330
2481
|
try {
|
|
2331
2482
|
return execFileSync("git", ["status", "--porcelain=v1", "--", rel], {
|
|
2332
2483
|
cwd: top,
|
|
@@ -2375,7 +2526,7 @@ async function runConfig(options) {
|
|
|
2375
2526
|
);
|
|
2376
2527
|
process.exit(1);
|
|
2377
2528
|
}
|
|
2378
|
-
const configPath =
|
|
2529
|
+
const configPath = path11.join(config.docsDir, ".lee-spec-kit.json");
|
|
2379
2530
|
if (!options.projectRoot) {
|
|
2380
2531
|
console.log();
|
|
2381
2532
|
console.log(chalk6.blue(tr(config.lang, "cli", "config.currentTitle")));
|
|
@@ -2608,6 +2759,17 @@ async function runContext(featureName, options) {
|
|
|
2608
2759
|
inProgressCandidates: selectionMode === "open" ? inProgressFeatures : [],
|
|
2609
2760
|
readyToCloseCandidates: selectionMode === "open" ? readyToCloseFeatures : [],
|
|
2610
2761
|
actions: targetFeatures.length === 1 ? targetFeatures[0].actions : [],
|
|
2762
|
+
checkPolicy: {
|
|
2763
|
+
docPath: "/docs/agents/agents.md",
|
|
2764
|
+
hint: tr(lang, "cli", "context.checkPolicyHint"),
|
|
2765
|
+
token: "OK",
|
|
2766
|
+
config: config.approval ?? { mode: "builtin" }
|
|
2767
|
+
},
|
|
2768
|
+
prPolicy: {
|
|
2769
|
+
screenshots: {
|
|
2770
|
+
upload: config.pr?.screenshots?.upload ?? false
|
|
2771
|
+
}
|
|
2772
|
+
},
|
|
2611
2773
|
recommendation: ""
|
|
2612
2774
|
};
|
|
2613
2775
|
if (result.status === "multiple_active") {
|
|
@@ -2623,7 +2785,7 @@ async function runContext(featureName, options) {
|
|
|
2623
2785
|
return;
|
|
2624
2786
|
}
|
|
2625
2787
|
console.log();
|
|
2626
|
-
console.log(chalk6.bold("
|
|
2788
|
+
console.log(chalk6.bold(tr(lang, "cli", "context.header")));
|
|
2627
2789
|
if (config.projectType === "single") {
|
|
2628
2790
|
if (branches.project.single) {
|
|
2629
2791
|
console.log(
|
|
@@ -2738,7 +2900,8 @@ async function runContext(featureName, options) {
|
|
|
2738
2900
|
}
|
|
2739
2901
|
const f = targetFeatures[0];
|
|
2740
2902
|
const stepName = stepsMap[f.currentStep] || "Unknown";
|
|
2741
|
-
const
|
|
2903
|
+
const checkTag = (requiresUserCheck) => requiresUserCheck ? chalk6.yellow(tr(lang, "cli", "context.checkRequired")) : "";
|
|
2904
|
+
const hasCheckAction = (f.actions || []).some((a) => !!a.requiresUserCheck);
|
|
2742
2905
|
console.log(
|
|
2743
2906
|
`\u{1F539} Feature: ${chalk6.bold(f.folderName)} ${config.projectType === "fullstack" ? chalk6.cyan(`(${f.type})`) : ""}`
|
|
2744
2907
|
);
|
|
@@ -2748,7 +2911,7 @@ async function runContext(featureName, options) {
|
|
|
2748
2911
|
if (f.issueNumber) {
|
|
2749
2912
|
console.log(` \u2022 Issue: #${f.issueNumber}`);
|
|
2750
2913
|
}
|
|
2751
|
-
console.log(` \u2022 Path: ${
|
|
2914
|
+
console.log(` \u2022 Path: ${path11.relative(cwd, f.path)}`);
|
|
2752
2915
|
if (f.git.projectBranch) {
|
|
2753
2916
|
console.log(` \u2022 Project Branch: ${f.git.projectBranch}`);
|
|
2754
2917
|
}
|
|
@@ -2773,6 +2936,9 @@ async function runContext(featureName, options) {
|
|
|
2773
2936
|
}
|
|
2774
2937
|
console.log();
|
|
2775
2938
|
console.log(chalk6.gray("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"));
|
|
2939
|
+
if (hasCheckAction) {
|
|
2940
|
+
console.log(chalk6.gray(tr(lang, "cli", "context.checkPolicyHint")));
|
|
2941
|
+
}
|
|
2776
2942
|
if (!f.actions || f.actions.length === 0) {
|
|
2777
2943
|
console.log(`\u{1F449} Next Action: ${chalk6.green(chalk6.bold(f.nextAction))}`);
|
|
2778
2944
|
console.log();
|
|
@@ -2782,24 +2948,32 @@ async function runContext(featureName, options) {
|
|
|
2782
2948
|
const action = f.actions[0];
|
|
2783
2949
|
if (action.type === "command") {
|
|
2784
2950
|
console.log(
|
|
2785
|
-
`\u{1F449} Next Action (${chalk6.cyan(action.scope)}): ${
|
|
2951
|
+
`\u{1F449} Next Action (${chalk6.cyan(action.scope)}): ${checkTag(action.requiresUserCheck)}${chalk6.green(chalk6.bold(action.cmd))}`
|
|
2786
2952
|
);
|
|
2953
|
+
if (action.scope === "docs") {
|
|
2954
|
+
console.log(chalk6.gray(` \u21B3 ${tr(lang, "cli", "context.tipDocsCommitRules")}`));
|
|
2955
|
+
}
|
|
2787
2956
|
} else {
|
|
2788
2957
|
console.log(
|
|
2789
|
-
`\u{1F449} Next Action: ${
|
|
2958
|
+
`\u{1F449} Next Action: ${checkTag(action.requiresUserCheck)}${chalk6.green(chalk6.bold(action.message))}`
|
|
2790
2959
|
);
|
|
2791
2960
|
}
|
|
2792
2961
|
console.log();
|
|
2793
2962
|
return;
|
|
2794
2963
|
}
|
|
2795
2964
|
console.log(chalk6.green(chalk6.bold("\u{1F449} Next Actions:")));
|
|
2965
|
+
let hasDocsCommand = false;
|
|
2796
2966
|
f.actions.forEach((action) => {
|
|
2797
2967
|
if (action.type === "command") {
|
|
2798
|
-
console.log(` \u2022 (${action.scope}) ${
|
|
2968
|
+
console.log(` \u2022 (${action.scope}) ${checkTag(action.requiresUserCheck)}${action.cmd}`);
|
|
2969
|
+
if (action.scope === "docs") hasDocsCommand = true;
|
|
2799
2970
|
} else {
|
|
2800
|
-
console.log(` \u2022 ${
|
|
2971
|
+
console.log(` \u2022 ${checkTag(action.requiresUserCheck)}${action.message}`);
|
|
2801
2972
|
}
|
|
2802
2973
|
});
|
|
2974
|
+
if (hasDocsCommand) {
|
|
2975
|
+
console.log(chalk6.gray(` \u21B3 ${tr(lang, "cli", "context.tipDocsCommitRules")}`));
|
|
2976
|
+
}
|
|
2803
2977
|
console.log();
|
|
2804
2978
|
}
|
|
2805
2979
|
function printChecklist(f, stepDefinitions) {
|
|
@@ -2814,7 +2988,7 @@ function printChecklist(f, stepDefinitions) {
|
|
|
2814
2988
|
}
|
|
2815
2989
|
function formatPath(cwd, p) {
|
|
2816
2990
|
if (!p) return "";
|
|
2817
|
-
return
|
|
2991
|
+
return path11.isAbsolute(p) ? path11.relative(cwd, p) : p;
|
|
2818
2992
|
}
|
|
2819
2993
|
function detectPlaceholders(content) {
|
|
2820
2994
|
const patterns = [
|
|
@@ -2841,7 +3015,7 @@ async function checkDocsStructure(config, cwd) {
|
|
|
2841
3015
|
const issues = [];
|
|
2842
3016
|
const requiredDirs = ["agents", "features", "prd", "designs", "ideas"];
|
|
2843
3017
|
for (const dir of requiredDirs) {
|
|
2844
|
-
const p =
|
|
3018
|
+
const p = path11.join(config.docsDir, dir);
|
|
2845
3019
|
if (!await fs8.pathExists(p)) {
|
|
2846
3020
|
issues.push({
|
|
2847
3021
|
level: "error",
|
|
@@ -2851,7 +3025,7 @@ async function checkDocsStructure(config, cwd) {
|
|
|
2851
3025
|
});
|
|
2852
3026
|
}
|
|
2853
3027
|
}
|
|
2854
|
-
const configPath =
|
|
3028
|
+
const configPath = path11.join(config.docsDir, ".lee-spec-kit.json");
|
|
2855
3029
|
if (!await fs8.pathExists(configPath)) {
|
|
2856
3030
|
issues.push({
|
|
2857
3031
|
level: "warn",
|
|
@@ -2874,13 +3048,13 @@ async function checkFeatures(config, cwd, features) {
|
|
|
2874
3048
|
}
|
|
2875
3049
|
const idMap = /* @__PURE__ */ new Map();
|
|
2876
3050
|
for (const f of features) {
|
|
2877
|
-
const rel = f.docs.featurePathFromDocs ||
|
|
3051
|
+
const rel = f.docs.featurePathFromDocs || path11.relative(config.docsDir, f.path);
|
|
2878
3052
|
const id = f.id || "UNKNOWN";
|
|
2879
3053
|
if (!idMap.has(id)) idMap.set(id, []);
|
|
2880
3054
|
idMap.get(id).push(rel);
|
|
2881
3055
|
const featureDocs = ["spec.md", "plan.md", "tasks.md", "decisions.md"];
|
|
2882
3056
|
for (const file of featureDocs) {
|
|
2883
|
-
const p =
|
|
3057
|
+
const p = path11.join(f.path, file);
|
|
2884
3058
|
if (!await fs8.pathExists(p)) continue;
|
|
2885
3059
|
const content = await fs8.readFile(p, "utf-8");
|
|
2886
3060
|
const placeholders = detectPlaceholders(content);
|
|
@@ -2906,7 +3080,7 @@ async function checkFeatures(config, cwd, features) {
|
|
|
2906
3080
|
level: "warn",
|
|
2907
3081
|
code: "spec_status_unset",
|
|
2908
3082
|
message: tr(config.lang, "cli", "doctor.issue.specStatusUnset"),
|
|
2909
|
-
path: formatPath(cwd,
|
|
3083
|
+
path: formatPath(cwd, path11.join(f.path, "spec.md"))
|
|
2910
3084
|
});
|
|
2911
3085
|
}
|
|
2912
3086
|
if (f.docs.planExists && !f.planStatus) {
|
|
@@ -2914,7 +3088,7 @@ async function checkFeatures(config, cwd, features) {
|
|
|
2914
3088
|
level: "warn",
|
|
2915
3089
|
code: "plan_status_unset",
|
|
2916
3090
|
message: tr(config.lang, "cli", "doctor.issue.planStatusUnset"),
|
|
2917
|
-
path: formatPath(cwd,
|
|
3091
|
+
path: formatPath(cwd, path11.join(f.path, "plan.md"))
|
|
2918
3092
|
});
|
|
2919
3093
|
}
|
|
2920
3094
|
if (f.docs.tasksExists && f.tasks.total === 0) {
|
|
@@ -2922,7 +3096,23 @@ async function checkFeatures(config, cwd, features) {
|
|
|
2922
3096
|
level: "warn",
|
|
2923
3097
|
code: "tasks_empty",
|
|
2924
3098
|
message: tr(config.lang, "cli", "doctor.issue.tasksEmpty"),
|
|
2925
|
-
path: formatPath(cwd,
|
|
3099
|
+
path: formatPath(cwd, path11.join(f.path, "tasks.md"))
|
|
3100
|
+
});
|
|
3101
|
+
}
|
|
3102
|
+
if (f.docs.tasksExists && !f.docs.tasksDocStatusFieldExists) {
|
|
3103
|
+
issues.push({
|
|
3104
|
+
level: "warn",
|
|
3105
|
+
code: "tasks_doc_status_missing",
|
|
3106
|
+
message: tr(config.lang, "cli", "doctor.issue.tasksDocStatusMissing"),
|
|
3107
|
+
path: formatPath(cwd, path11.join(f.path, "tasks.md"))
|
|
3108
|
+
});
|
|
3109
|
+
}
|
|
3110
|
+
if (f.docs.tasksExists && f.docs.tasksDocStatusFieldExists && !f.tasksDocStatus) {
|
|
3111
|
+
issues.push({
|
|
3112
|
+
level: "warn",
|
|
3113
|
+
code: "tasks_doc_status_unset",
|
|
3114
|
+
message: tr(config.lang, "cli", "doctor.issue.tasksDocStatusUnset"),
|
|
3115
|
+
path: formatPath(cwd, path11.join(f.path, "tasks.md"))
|
|
2926
3116
|
});
|
|
2927
3117
|
}
|
|
2928
3118
|
}
|
|
@@ -2946,7 +3136,7 @@ async function checkFeatures(config, cwd, features) {
|
|
|
2946
3136
|
level: "warn",
|
|
2947
3137
|
code: "missing_feature_id",
|
|
2948
3138
|
message: tr(config.lang, "cli", "doctor.issue.missingFeatureId"),
|
|
2949
|
-
path: formatPath(cwd,
|
|
3139
|
+
path: formatPath(cwd, path11.join(config.docsDir, p))
|
|
2950
3140
|
});
|
|
2951
3141
|
}
|
|
2952
3142
|
return issues;
|
|
@@ -2996,7 +3186,7 @@ function doctorCommand(program2) {
|
|
|
2996
3186
|
}
|
|
2997
3187
|
console.log();
|
|
2998
3188
|
console.log(chalk6.bold(tr(lang, "cli", "doctor.title")));
|
|
2999
|
-
console.log(chalk6.gray(`- Docs: ${
|
|
3189
|
+
console.log(chalk6.gray(`- Docs: ${path11.relative(cwd, docsDir)}`));
|
|
3000
3190
|
console.log(chalk6.gray(`- Type: ${projectType}`));
|
|
3001
3191
|
console.log(chalk6.gray(`- Lang: ${lang}`));
|
|
3002
3192
|
console.log();
|
|
@@ -3090,11 +3280,11 @@ ${version}
|
|
|
3090
3280
|
}
|
|
3091
3281
|
return `${ascii}${footer}`;
|
|
3092
3282
|
}
|
|
3093
|
-
var CACHE_FILE =
|
|
3283
|
+
var CACHE_FILE = path11.join(os.homedir(), ".lee-spec-kit-version-cache.json");
|
|
3094
3284
|
var CHECK_INTERVAL = 24 * 60 * 60 * 1e3;
|
|
3095
3285
|
function getCurrentVersion() {
|
|
3096
3286
|
try {
|
|
3097
|
-
const packageJsonPath =
|
|
3287
|
+
const packageJsonPath = path11.join(__dirname$1, "..", "package.json");
|
|
3098
3288
|
if (fs8.existsSync(packageJsonPath)) {
|
|
3099
3289
|
const pkg = fs8.readJsonSync(packageJsonPath);
|
|
3100
3290
|
return pkg.version;
|
|
@@ -3184,7 +3374,7 @@ function shouldCheckForUpdates() {
|
|
|
3184
3374
|
if (shouldCheckForUpdates()) checkForUpdates();
|
|
3185
3375
|
function getCliVersion() {
|
|
3186
3376
|
try {
|
|
3187
|
-
const packageJsonPath =
|
|
3377
|
+
const packageJsonPath = path11.join(__dirname$1, "..", "package.json");
|
|
3188
3378
|
if (fs8.existsSync(packageJsonPath)) {
|
|
3189
3379
|
const pkg = fs8.readJsonSync(packageJsonPath);
|
|
3190
3380
|
if (pkg?.version) return String(pkg.version);
|