lee-spec-kit 0.4.12 → 0.4.13
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 +48 -1
- package/README.md +52 -1
- package/dist/index.js +305 -124
- package/package.json +1 -1
- package/templates/en/common/agents/pr-template.md +7 -1
- package/templates/en/common/agents/skills/create-feature.md +1 -1
- package/templates/en/common/agents/skills/create-pr.md +18 -1
- package/templates/en/common/agents/skills/execute-task.md +5 -2
- 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 +7 -1
- package/templates/ko/common/agents/skills/create-feature.md +3 -3
- package/templates/ko/common/agents/skills/create-pr.md +18 -1
- package/templates/ko/common/agents/skills/execute-task.md +7 -5
- 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,12 @@ 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
|
+
// Approval policy for "requiresUserCheck" actions shown by `context`.
|
|
840
|
+
// - builtin (default): Use requiresUserCheck embedded in steps/actions.
|
|
841
|
+
// - category: Override by action category (recommended for automation).
|
|
842
|
+
// - steps: Override by step number (fragile; not recommended).
|
|
843
|
+
approval: { mode: "builtin" }
|
|
823
844
|
};
|
|
824
845
|
if (docsRepo === "standalone") {
|
|
825
846
|
config.pushDocs = pushDocs;
|
|
@@ -830,7 +851,7 @@ async function runInit(options) {
|
|
|
830
851
|
config.projectRoot = projectRoot;
|
|
831
852
|
}
|
|
832
853
|
}
|
|
833
|
-
const configPath =
|
|
854
|
+
const configPath = path11.join(targetDir, ".lee-spec-kit.json");
|
|
834
855
|
await fs8.writeJson(configPath, config, { spaces: 2 });
|
|
835
856
|
console.log(chalk6.green(tr(lang, "cli", "init.log.docsCreated")));
|
|
836
857
|
console.log();
|
|
@@ -867,7 +888,7 @@ async function initGit(cwd, targetDir, docsRepo, lang, pushDocs, docsRemote) {
|
|
|
867
888
|
console.log(chalk6.blue(tr(lang, "cli", "init.log.gitInit")));
|
|
868
889
|
runGit(["init"], cwd);
|
|
869
890
|
}
|
|
870
|
-
const relativePath =
|
|
891
|
+
const relativePath = path11.relative(cwd, targetDir);
|
|
871
892
|
const stagedBeforeAdd = getCachedStagedFiles(cwd);
|
|
872
893
|
if (relativePath === "." && stagedBeforeAdd && stagedBeforeAdd.length > 0) {
|
|
873
894
|
console.log(
|
|
@@ -905,10 +926,10 @@ async function initGit(cwd, targetDir, docsRepo, lang, pushDocs, docsRemote) {
|
|
|
905
926
|
}
|
|
906
927
|
function getAncestorDirs(startDir) {
|
|
907
928
|
const dirs = [];
|
|
908
|
-
let current =
|
|
929
|
+
let current = path11.resolve(startDir);
|
|
909
930
|
while (true) {
|
|
910
931
|
dirs.push(current);
|
|
911
|
-
const parent =
|
|
932
|
+
const parent = path11.dirname(current);
|
|
912
933
|
if (parent === current) break;
|
|
913
934
|
current = parent;
|
|
914
935
|
}
|
|
@@ -917,21 +938,21 @@ function getAncestorDirs(startDir) {
|
|
|
917
938
|
async function getConfig(cwd) {
|
|
918
939
|
const explicitDocsDir = (process.env.LEE_SPEC_KIT_DOCS_DIR || "").trim();
|
|
919
940
|
const baseDirs = [
|
|
920
|
-
...explicitDocsDir ? [
|
|
941
|
+
...explicitDocsDir ? [path11.resolve(explicitDocsDir)] : [],
|
|
921
942
|
...getAncestorDirs(cwd)
|
|
922
943
|
];
|
|
923
944
|
const visitedBaseDirs = /* @__PURE__ */ new Set();
|
|
924
945
|
const visitedDocsDirs = /* @__PURE__ */ new Set();
|
|
925
946
|
for (const baseDir of baseDirs) {
|
|
926
|
-
const resolvedBaseDir =
|
|
947
|
+
const resolvedBaseDir = path11.resolve(baseDir);
|
|
927
948
|
if (visitedBaseDirs.has(resolvedBaseDir)) continue;
|
|
928
949
|
visitedBaseDirs.add(resolvedBaseDir);
|
|
929
|
-
const possibleDocsDirs = [
|
|
950
|
+
const possibleDocsDirs = [path11.join(resolvedBaseDir, "docs"), resolvedBaseDir];
|
|
930
951
|
for (const docsDir of possibleDocsDirs) {
|
|
931
|
-
const resolvedDocsDir =
|
|
952
|
+
const resolvedDocsDir = path11.resolve(docsDir);
|
|
932
953
|
if (visitedDocsDirs.has(resolvedDocsDir)) continue;
|
|
933
954
|
visitedDocsDirs.add(resolvedDocsDir);
|
|
934
|
-
const configPath =
|
|
955
|
+
const configPath = path11.join(resolvedDocsDir, ".lee-spec-kit.json");
|
|
935
956
|
if (await fs8.pathExists(configPath)) {
|
|
936
957
|
try {
|
|
937
958
|
const configFile = await fs8.readJson(configPath);
|
|
@@ -943,18 +964,19 @@ async function getConfig(cwd) {
|
|
|
943
964
|
docsRepo: configFile.docsRepo,
|
|
944
965
|
pushDocs: configFile.pushDocs,
|
|
945
966
|
docsRemote: configFile.docsRemote,
|
|
946
|
-
projectRoot: configFile.projectRoot
|
|
967
|
+
projectRoot: configFile.projectRoot,
|
|
968
|
+
approval: configFile.approval
|
|
947
969
|
};
|
|
948
970
|
} catch {
|
|
949
971
|
}
|
|
950
972
|
}
|
|
951
|
-
const agentsPath =
|
|
952
|
-
const featuresPath =
|
|
973
|
+
const agentsPath = path11.join(resolvedDocsDir, "agents");
|
|
974
|
+
const featuresPath = path11.join(resolvedDocsDir, "features");
|
|
953
975
|
if (await fs8.pathExists(agentsPath) && await fs8.pathExists(featuresPath)) {
|
|
954
|
-
const bePath =
|
|
955
|
-
const fePath =
|
|
976
|
+
const bePath = path11.join(featuresPath, "be");
|
|
977
|
+
const fePath = path11.join(featuresPath, "fe");
|
|
956
978
|
const projectType = await fs8.pathExists(bePath) || await fs8.pathExists(fePath) ? "fullstack" : "single";
|
|
957
|
-
const agentsMdPath =
|
|
979
|
+
const agentsMdPath = path11.join(agentsPath, "agents.md");
|
|
958
980
|
let lang = "en";
|
|
959
981
|
if (await fs8.pathExists(agentsMdPath)) {
|
|
960
982
|
const content = await fs8.readFile(agentsMdPath, "utf-8");
|
|
@@ -1031,12 +1053,12 @@ async function runFeature(name, options) {
|
|
|
1031
1053
|
}
|
|
1032
1054
|
let featuresDir;
|
|
1033
1055
|
if (projectType === "fullstack" && repo) {
|
|
1034
|
-
featuresDir =
|
|
1056
|
+
featuresDir = path11.join(docsDir, "features", repo);
|
|
1035
1057
|
} else {
|
|
1036
|
-
featuresDir =
|
|
1058
|
+
featuresDir = path11.join(docsDir, "features");
|
|
1037
1059
|
}
|
|
1038
1060
|
const featureFolderName = `${featureId}-${name}`;
|
|
1039
|
-
const featureDir =
|
|
1061
|
+
const featureDir = path11.join(featuresDir, featureFolderName);
|
|
1040
1062
|
if (await fs8.pathExists(featureDir)) {
|
|
1041
1063
|
console.error(
|
|
1042
1064
|
chalk6.red(
|
|
@@ -1045,7 +1067,7 @@ async function runFeature(name, options) {
|
|
|
1045
1067
|
);
|
|
1046
1068
|
process.exit(1);
|
|
1047
1069
|
}
|
|
1048
|
-
const featureBasePath =
|
|
1070
|
+
const featureBasePath = path11.join(docsDir, "features", "feature-base");
|
|
1049
1071
|
if (!await fs8.pathExists(featureBasePath)) {
|
|
1050
1072
|
console.error(
|
|
1051
1073
|
chalk6.red(
|
|
@@ -1103,12 +1125,12 @@ async function runFeature(name, options) {
|
|
|
1103
1125
|
console.log();
|
|
1104
1126
|
}
|
|
1105
1127
|
async function getNextFeatureId(docsDir, projectType) {
|
|
1106
|
-
const featuresDir =
|
|
1128
|
+
const featuresDir = path11.join(docsDir, "features");
|
|
1107
1129
|
let max = 0;
|
|
1108
1130
|
const scanDirs = [];
|
|
1109
1131
|
if (projectType === "fullstack") {
|
|
1110
|
-
scanDirs.push(
|
|
1111
|
-
scanDirs.push(
|
|
1132
|
+
scanDirs.push(path11.join(featuresDir, "be"));
|
|
1133
|
+
scanDirs.push(path11.join(featuresDir, "fe"));
|
|
1112
1134
|
} else {
|
|
1113
1135
|
scanDirs.push(featuresDir);
|
|
1114
1136
|
}
|
|
@@ -1133,14 +1155,17 @@ async function getNextFeatureId(docsDir, projectType) {
|
|
|
1133
1155
|
function isCompletionChecklistDone(feature) {
|
|
1134
1156
|
return !!feature.completionChecklist && feature.completionChecklist.total > 0 && feature.completionChecklist.checked === feature.completionChecklist.total;
|
|
1135
1157
|
}
|
|
1158
|
+
function isTasksDocApproved(feature) {
|
|
1159
|
+
return !feature.docs.tasksDocStatusFieldExists || feature.tasksDocStatus === "Approved";
|
|
1160
|
+
}
|
|
1136
1161
|
function isImplementationDone(feature) {
|
|
1137
|
-
return feature.docs.tasksExists && feature.tasks.total > 0 && feature.tasks.total === feature.tasks.done && isCompletionChecklistDone(feature);
|
|
1162
|
+
return feature.docs.tasksExists && feature.tasks.total > 0 && feature.tasks.total === feature.tasks.done && isCompletionChecklistDone(feature) && isTasksDocApproved(feature);
|
|
1138
1163
|
}
|
|
1139
1164
|
function isPrMetadataConfigured(feature) {
|
|
1140
1165
|
return feature.docs.prFieldExists && feature.docs.prStatusFieldExists;
|
|
1141
1166
|
}
|
|
1142
1167
|
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";
|
|
1168
|
+
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
1169
|
}
|
|
1145
1170
|
function getStepDefinitions(lang) {
|
|
1146
1171
|
return [
|
|
@@ -1160,6 +1185,7 @@ function getStepDefinitions(lang) {
|
|
|
1160
1185
|
actions: (f) => [
|
|
1161
1186
|
{
|
|
1162
1187
|
type: "instruction",
|
|
1188
|
+
category: "spec_write",
|
|
1163
1189
|
message: !f.docs.specExists ? tr(lang, "messages", "specCreate") : tr(lang, "messages", "specImprove")
|
|
1164
1190
|
}
|
|
1165
1191
|
]
|
|
@@ -1174,7 +1200,8 @@ function getStepDefinitions(lang) {
|
|
|
1174
1200
|
actions: () => [
|
|
1175
1201
|
{
|
|
1176
1202
|
type: "instruction",
|
|
1177
|
-
|
|
1203
|
+
category: "spec_approve",
|
|
1204
|
+
requiresUserCheck: true,
|
|
1178
1205
|
message: tr(lang, "messages", "specApproval")
|
|
1179
1206
|
}
|
|
1180
1207
|
]
|
|
@@ -1191,6 +1218,7 @@ function getStepDefinitions(lang) {
|
|
|
1191
1218
|
actions: (f) => [
|
|
1192
1219
|
{
|
|
1193
1220
|
type: "instruction",
|
|
1221
|
+
category: "plan_write",
|
|
1194
1222
|
message: !f.docs.planExists ? tr(lang, "messages", "planCreate") : tr(lang, "messages", "planImprove")
|
|
1195
1223
|
}
|
|
1196
1224
|
]
|
|
@@ -1205,7 +1233,8 @@ function getStepDefinitions(lang) {
|
|
|
1205
1233
|
actions: () => [
|
|
1206
1234
|
{
|
|
1207
1235
|
type: "instruction",
|
|
1208
|
-
|
|
1236
|
+
category: "plan_approve",
|
|
1237
|
+
requiresUserCheck: true,
|
|
1209
1238
|
message: tr(lang, "messages", "planApproval")
|
|
1210
1239
|
}
|
|
1211
1240
|
]
|
|
@@ -1215,24 +1244,54 @@ function getStepDefinitions(lang) {
|
|
|
1215
1244
|
step: 6,
|
|
1216
1245
|
name: tr(lang, "steps", "tasksWrite"),
|
|
1217
1246
|
checklist: {
|
|
1218
|
-
done: (f) => f.docs.tasksExists && f.tasks.total > 0,
|
|
1247
|
+
done: (f) => f.docs.tasksExists && f.tasks.total > 0 && isTasksDocApproved(f),
|
|
1219
1248
|
detail: (f) => f.tasks.total > 0 ? `(${f.tasks.total})` : ""
|
|
1220
1249
|
},
|
|
1221
1250
|
current: {
|
|
1222
|
-
when: (f) => f.planStatus === "Approved" && (!f.docs.tasksExists || f.tasks.total === 0),
|
|
1251
|
+
when: (f) => f.planStatus === "Approved" && (!f.docs.tasksExists || f.tasks.total === 0 || f.docs.tasksDocStatusFieldExists && (!f.tasksDocStatus || f.tasksDocStatus === "Draft" || f.tasksDocStatus === "Review")),
|
|
1223
1252
|
actions: (f) => {
|
|
1224
1253
|
if (!f.docs.tasksExists) {
|
|
1225
1254
|
return [
|
|
1226
1255
|
{
|
|
1227
1256
|
type: "instruction",
|
|
1257
|
+
category: "tasks_write",
|
|
1228
1258
|
message: tr(lang, "messages", "tasksCreate")
|
|
1229
1259
|
}
|
|
1230
1260
|
];
|
|
1231
1261
|
}
|
|
1262
|
+
if (f.tasks.total === 0) {
|
|
1263
|
+
return [
|
|
1264
|
+
{
|
|
1265
|
+
type: "instruction",
|
|
1266
|
+
category: "tasks_write",
|
|
1267
|
+
message: tr(lang, "messages", "tasksNeedAtLeastOne")
|
|
1268
|
+
}
|
|
1269
|
+
];
|
|
1270
|
+
}
|
|
1271
|
+
if (f.docs.tasksDocStatusFieldExists && (!f.tasksDocStatus || f.tasksDocStatus === "Draft")) {
|
|
1272
|
+
return [
|
|
1273
|
+
{
|
|
1274
|
+
type: "instruction",
|
|
1275
|
+
category: "tasks_write",
|
|
1276
|
+
message: tr(lang, "messages", "tasksImprove")
|
|
1277
|
+
}
|
|
1278
|
+
];
|
|
1279
|
+
}
|
|
1280
|
+
if (f.docs.tasksDocStatusFieldExists && f.tasksDocStatus === "Review") {
|
|
1281
|
+
return [
|
|
1282
|
+
{
|
|
1283
|
+
type: "instruction",
|
|
1284
|
+
category: "tasks_approve",
|
|
1285
|
+
requiresUserCheck: true,
|
|
1286
|
+
message: tr(lang, "messages", "tasksApproval")
|
|
1287
|
+
}
|
|
1288
|
+
];
|
|
1289
|
+
}
|
|
1232
1290
|
return [
|
|
1233
1291
|
{
|
|
1234
1292
|
type: "instruction",
|
|
1235
|
-
|
|
1293
|
+
category: "tasks_write",
|
|
1294
|
+
message: tr(lang, "messages", "tasksImprove")
|
|
1236
1295
|
}
|
|
1237
1296
|
];
|
|
1238
1297
|
}
|
|
@@ -1242,16 +1301,17 @@ function getStepDefinitions(lang) {
|
|
|
1242
1301
|
step: 7,
|
|
1243
1302
|
name: tr(lang, "steps", "docsInitialCommit"),
|
|
1244
1303
|
checklist: {
|
|
1245
|
-
done: (f) => f.docs.tasksExists && f.tasks.total > 0 && f.specStatus === "Approved" && f.planStatus === "Approved" && f.git.docsEverCommitted
|
|
1304
|
+
done: (f) => f.docs.tasksExists && f.tasks.total > 0 && f.specStatus === "Approved" && f.planStatus === "Approved" && isTasksDocApproved(f) && f.git.docsEverCommitted
|
|
1246
1305
|
},
|
|
1247
1306
|
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,
|
|
1307
|
+
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
1308
|
actions: (f) => {
|
|
1250
1309
|
if (f.issueNumber) {
|
|
1251
1310
|
return [
|
|
1252
1311
|
{
|
|
1253
1312
|
type: "command",
|
|
1254
|
-
|
|
1313
|
+
category: "docs_commit",
|
|
1314
|
+
requiresUserCheck: true,
|
|
1255
1315
|
scope: "docs",
|
|
1256
1316
|
cwd: f.git.docsGitCwd,
|
|
1257
1317
|
cmd: tr(lang, "messages", "docsCommitIssueUpdate", {
|
|
@@ -1266,7 +1326,8 @@ function getStepDefinitions(lang) {
|
|
|
1266
1326
|
return [
|
|
1267
1327
|
{
|
|
1268
1328
|
type: "command",
|
|
1269
|
-
|
|
1329
|
+
category: "docs_commit",
|
|
1330
|
+
requiresUserCheck: true,
|
|
1270
1331
|
scope: "docs",
|
|
1271
1332
|
cwd: f.git.docsGitCwd,
|
|
1272
1333
|
cmd: tr(lang, "messages", "docsCommitPlanning", {
|
|
@@ -1286,12 +1347,13 @@ function getStepDefinitions(lang) {
|
|
|
1286
1347
|
done: (f) => !!f.issueNumber
|
|
1287
1348
|
},
|
|
1288
1349
|
current: {
|
|
1289
|
-
when: (f) => f.docs.tasksExists && f.tasks.total > 0 && f.specStatus === "Approved" && f.planStatus === "Approved" && !f.issueNumber,
|
|
1350
|
+
when: (f) => f.docs.tasksExists && f.tasks.total > 0 && f.specStatus === "Approved" && f.planStatus === "Approved" && isTasksDocApproved(f) && !f.issueNumber,
|
|
1290
1351
|
actions: (f) => {
|
|
1291
1352
|
return [
|
|
1292
1353
|
{
|
|
1293
1354
|
type: "instruction",
|
|
1294
|
-
|
|
1355
|
+
category: "issue_create",
|
|
1356
|
+
requiresUserCheck: true,
|
|
1295
1357
|
message: tr(lang, "messages", "issueCreateAndWrite")
|
|
1296
1358
|
}
|
|
1297
1359
|
];
|
|
@@ -1309,6 +1371,7 @@ function getStepDefinitions(lang) {
|
|
|
1309
1371
|
return [
|
|
1310
1372
|
{
|
|
1311
1373
|
type: "instruction",
|
|
1374
|
+
category: "branch_create",
|
|
1312
1375
|
message: tr(lang, "messages", "standaloneNeedsProjectRoot")
|
|
1313
1376
|
}
|
|
1314
1377
|
];
|
|
@@ -1316,6 +1379,7 @@ function getStepDefinitions(lang) {
|
|
|
1316
1379
|
return [
|
|
1317
1380
|
{
|
|
1318
1381
|
type: "command",
|
|
1382
|
+
category: "branch_create",
|
|
1319
1383
|
scope: "project",
|
|
1320
1384
|
cwd: f.git.projectGitCwd,
|
|
1321
1385
|
cmd: tr(lang, "messages", "createBranch", {
|
|
@@ -1332,17 +1396,18 @@ function getStepDefinitions(lang) {
|
|
|
1332
1396
|
step: 10,
|
|
1333
1397
|
name: tr(lang, "steps", "tasksExecute"),
|
|
1334
1398
|
checklist: {
|
|
1335
|
-
done: (f) => f.docs.tasksExists && f.tasks.total > 0 && f.tasks.total === f.tasks.done && isCompletionChecklistDone(f),
|
|
1399
|
+
done: (f) => f.docs.tasksExists && f.tasks.total > 0 && f.tasks.total === f.tasks.done && isCompletionChecklistDone(f) && isTasksDocApproved(f),
|
|
1336
1400
|
detail: (f) => f.tasks.total > 0 ? `(${f.tasks.done}/${f.tasks.total})` : ""
|
|
1337
1401
|
},
|
|
1338
1402
|
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),
|
|
1403
|
+
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
1404
|
actions: (f) => {
|
|
1341
1405
|
if (f.tasks.total === f.tasks.done && !isCompletionChecklistDone(f)) {
|
|
1342
1406
|
const actions = [
|
|
1343
1407
|
{
|
|
1344
1408
|
type: "instruction",
|
|
1345
|
-
|
|
1409
|
+
category: "task_execute",
|
|
1410
|
+
requiresUserCheck: true,
|
|
1346
1411
|
message: !f.completionChecklist ? tr(lang, "messages", "tasksAllDoneButNoChecklist") : tr(lang, "messages", "tasksAllDoneButChecklist", {
|
|
1347
1412
|
checked: f.completionChecklist.checked,
|
|
1348
1413
|
total: f.completionChecklist.total
|
|
@@ -1352,7 +1417,8 @@ function getStepDefinitions(lang) {
|
|
|
1352
1417
|
if (!isPrMetadataConfigured(f)) {
|
|
1353
1418
|
actions.push({
|
|
1354
1419
|
type: "instruction",
|
|
1355
|
-
|
|
1420
|
+
category: "pr_metadata_migrate",
|
|
1421
|
+
requiresUserCheck: true,
|
|
1356
1422
|
message: tr(lang, "messages", "prLegacyAsk")
|
|
1357
1423
|
});
|
|
1358
1424
|
}
|
|
@@ -1362,7 +1428,8 @@ function getStepDefinitions(lang) {
|
|
|
1362
1428
|
return [
|
|
1363
1429
|
{
|
|
1364
1430
|
type: "instruction",
|
|
1365
|
-
|
|
1431
|
+
category: "task_execute",
|
|
1432
|
+
requiresUserCheck: true,
|
|
1366
1433
|
message: tr(lang, "messages", "finishDoingTask", {
|
|
1367
1434
|
title: f.activeTask.title,
|
|
1368
1435
|
done: f.tasks.done,
|
|
@@ -1376,7 +1443,8 @@ function getStepDefinitions(lang) {
|
|
|
1376
1443
|
return [
|
|
1377
1444
|
{
|
|
1378
1445
|
type: "command",
|
|
1379
|
-
|
|
1446
|
+
category: "docs_commit",
|
|
1447
|
+
requiresUserCheck: true,
|
|
1380
1448
|
scope: "docs",
|
|
1381
1449
|
cwd: f.git.docsGitCwd,
|
|
1382
1450
|
cmd: f.issueNumber ? tr(lang, "messages", "docsCommitIssueUpdate", {
|
|
@@ -1395,7 +1463,8 @@ function getStepDefinitions(lang) {
|
|
|
1395
1463
|
return [
|
|
1396
1464
|
{
|
|
1397
1465
|
type: "instruction",
|
|
1398
|
-
|
|
1466
|
+
category: "task_execute",
|
|
1467
|
+
requiresUserCheck: true,
|
|
1399
1468
|
message: tr(lang, "messages", "startNextTodoTask", {
|
|
1400
1469
|
title: f.nextTodoTask.title,
|
|
1401
1470
|
done: f.tasks.done,
|
|
@@ -1407,7 +1476,8 @@ function getStepDefinitions(lang) {
|
|
|
1407
1476
|
return [
|
|
1408
1477
|
{
|
|
1409
1478
|
type: "instruction",
|
|
1410
|
-
|
|
1479
|
+
category: "task_execute",
|
|
1480
|
+
requiresUserCheck: true,
|
|
1411
1481
|
message: tr(lang, "messages", "checkTaskStatuses", {
|
|
1412
1482
|
done: f.tasks.done,
|
|
1413
1483
|
total: f.tasks.total
|
|
@@ -1428,7 +1498,8 @@ function getStepDefinitions(lang) {
|
|
|
1428
1498
|
actions: (f) => [
|
|
1429
1499
|
{
|
|
1430
1500
|
type: "command",
|
|
1431
|
-
|
|
1501
|
+
category: "docs_commit",
|
|
1502
|
+
requiresUserCheck: true,
|
|
1432
1503
|
scope: "docs",
|
|
1433
1504
|
cwd: f.git.docsGitCwd,
|
|
1434
1505
|
cmd: f.issueNumber ? tr(lang, "messages", "docsCommitIssueUpdate", {
|
|
@@ -1456,7 +1527,8 @@ function getStepDefinitions(lang) {
|
|
|
1456
1527
|
return [
|
|
1457
1528
|
{
|
|
1458
1529
|
type: "instruction",
|
|
1459
|
-
|
|
1530
|
+
category: "pr_metadata_migrate",
|
|
1531
|
+
requiresUserCheck: true,
|
|
1460
1532
|
message: tr(lang, "messages", "prLegacyAsk")
|
|
1461
1533
|
}
|
|
1462
1534
|
];
|
|
@@ -1464,7 +1536,8 @@ function getStepDefinitions(lang) {
|
|
|
1464
1536
|
return [
|
|
1465
1537
|
{
|
|
1466
1538
|
type: "instruction",
|
|
1467
|
-
|
|
1539
|
+
category: "pr_create",
|
|
1540
|
+
requiresUserCheck: true,
|
|
1468
1541
|
message: tr(lang, "messages", "prCreate")
|
|
1469
1542
|
}
|
|
1470
1543
|
];
|
|
@@ -1484,7 +1557,8 @@ function getStepDefinitions(lang) {
|
|
|
1484
1557
|
return [
|
|
1485
1558
|
{
|
|
1486
1559
|
type: "instruction",
|
|
1487
|
-
|
|
1560
|
+
category: "pr_status_update",
|
|
1561
|
+
requiresUserCheck: true,
|
|
1488
1562
|
message: tr(lang, "messages", "prFillStatus")
|
|
1489
1563
|
}
|
|
1490
1564
|
];
|
|
@@ -1493,6 +1567,7 @@ function getStepDefinitions(lang) {
|
|
|
1493
1567
|
return [
|
|
1494
1568
|
{
|
|
1495
1569
|
type: "instruction",
|
|
1570
|
+
category: "code_review",
|
|
1496
1571
|
message: tr(lang, "messages", "prResolveReview")
|
|
1497
1572
|
}
|
|
1498
1573
|
];
|
|
@@ -1500,6 +1575,7 @@ function getStepDefinitions(lang) {
|
|
|
1500
1575
|
return [
|
|
1501
1576
|
{
|
|
1502
1577
|
type: "instruction",
|
|
1578
|
+
category: "code_review",
|
|
1503
1579
|
message: tr(lang, "messages", "prRequestReview")
|
|
1504
1580
|
}
|
|
1505
1581
|
];
|
|
@@ -1515,6 +1591,7 @@ function getStepDefinitions(lang) {
|
|
|
1515
1591
|
actions: () => [
|
|
1516
1592
|
{
|
|
1517
1593
|
type: "instruction",
|
|
1594
|
+
category: "feature_done",
|
|
1518
1595
|
message: tr(lang, "messages", "featureDone")
|
|
1519
1596
|
}
|
|
1520
1597
|
]
|
|
@@ -1529,12 +1606,53 @@ getStepDefinitions("ko");
|
|
|
1529
1606
|
getStepsMap("ko");
|
|
1530
1607
|
|
|
1531
1608
|
// src/utils/context/progress.ts
|
|
1532
|
-
function
|
|
1609
|
+
function normalizeApprovalToken(value) {
|
|
1610
|
+
return (value ?? "").trim().toLowerCase();
|
|
1611
|
+
}
|
|
1612
|
+
function applyApprovalPolicy(step, actions, approval) {
|
|
1613
|
+
if (!approval) return actions;
|
|
1614
|
+
const mode = approval.mode ?? "builtin";
|
|
1615
|
+
if (mode === "builtin") return actions;
|
|
1616
|
+
if (mode === "steps") {
|
|
1617
|
+
const required = new Set(
|
|
1618
|
+
(approval.requireCheckSteps ?? approval.requireOkSteps ?? []).map((n) => typeof n === "number" ? n : Number(n)).filter((n) => Number.isFinite(n))
|
|
1619
|
+
);
|
|
1620
|
+
const requiresUserCheck = required.has(step);
|
|
1621
|
+
return actions.map((a) => ({ ...a, requiresUserCheck }));
|
|
1622
|
+
}
|
|
1623
|
+
const requiredCategories = new Set(
|
|
1624
|
+
(approval.requireCheckCategories ?? approval.requireOkCategories ?? []).map((c) => normalizeApprovalToken(c)).filter(Boolean)
|
|
1625
|
+
);
|
|
1626
|
+
const skippedCategories = new Set(
|
|
1627
|
+
(approval.skipCheckCategories ?? approval.skipOkCategories ?? []).map((c) => normalizeApprovalToken(c)).filter(Boolean)
|
|
1628
|
+
);
|
|
1629
|
+
const defaultPolicy = approval.default ?? "keep";
|
|
1630
|
+
return actions.map((a) => {
|
|
1631
|
+
const builtin = Boolean(a.requiresUserCheck);
|
|
1632
|
+
const category = normalizeApprovalToken(a.category ?? "uncategorized");
|
|
1633
|
+
let requiresUserCheck = builtin;
|
|
1634
|
+
if (requiredCategories.has("*") || requiredCategories.has(category)) {
|
|
1635
|
+
requiresUserCheck = true;
|
|
1636
|
+
} else if (skippedCategories.has("*") || skippedCategories.has(category)) {
|
|
1637
|
+
requiresUserCheck = false;
|
|
1638
|
+
} else if (defaultPolicy === "require") {
|
|
1639
|
+
requiresUserCheck = true;
|
|
1640
|
+
} else if (defaultPolicy === "skip") {
|
|
1641
|
+
requiresUserCheck = false;
|
|
1642
|
+
}
|
|
1643
|
+
return { ...a, requiresUserCheck };
|
|
1644
|
+
});
|
|
1645
|
+
}
|
|
1646
|
+
function resolveFeatureProgress(feature, stepDefinitions, lang, approval) {
|
|
1533
1647
|
const ordered = [...stepDefinitions].sort((a, b) => a.step - b.step);
|
|
1534
1648
|
for (const definition of ordered) {
|
|
1535
1649
|
if (!definition.current) continue;
|
|
1536
1650
|
if (definition.current.when(feature)) {
|
|
1537
|
-
const actions =
|
|
1651
|
+
const actions = applyApprovalPolicy(
|
|
1652
|
+
definition.step,
|
|
1653
|
+
definition.current.actions(feature),
|
|
1654
|
+
approval
|
|
1655
|
+
);
|
|
1538
1656
|
return {
|
|
1539
1657
|
currentStep: definition.step,
|
|
1540
1658
|
actions,
|
|
@@ -1548,6 +1666,7 @@ function resolveFeatureProgress(feature, stepDefinitions, lang) {
|
|
|
1548
1666
|
actions: [
|
|
1549
1667
|
{
|
|
1550
1668
|
type: "instruction",
|
|
1669
|
+
category: "fallback",
|
|
1551
1670
|
message: tr(lang, "messages", "fallbackRerunContext")
|
|
1552
1671
|
}
|
|
1553
1672
|
],
|
|
@@ -1654,6 +1773,16 @@ function extractSpecValue(content, key) {
|
|
|
1654
1773
|
const match = content.match(regex);
|
|
1655
1774
|
return match ? match[1].trim() : void 0;
|
|
1656
1775
|
}
|
|
1776
|
+
function hasSpecKey(content, key) {
|
|
1777
|
+
const regex = new RegExp(
|
|
1778
|
+
`^\\s*-\\s*\\*\\*${escapeRegExp(key)}\\*\\*\\s*:`,
|
|
1779
|
+
"m"
|
|
1780
|
+
);
|
|
1781
|
+
return regex.test(content);
|
|
1782
|
+
}
|
|
1783
|
+
function hasAnySpecKey(content, keys) {
|
|
1784
|
+
return keys.some((key) => hasSpecKey(content, key));
|
|
1785
|
+
}
|
|
1657
1786
|
function extractFirstSpecValue(content, keys) {
|
|
1658
1787
|
for (const key of keys) {
|
|
1659
1788
|
const value = extractSpecValue(content, key);
|
|
@@ -1693,7 +1822,13 @@ function parseTasks(content) {
|
|
|
1693
1822
|
let activeTask;
|
|
1694
1823
|
let nextTodoTask;
|
|
1695
1824
|
const lines = content.split("\n");
|
|
1825
|
+
let inCodeBlock = false;
|
|
1696
1826
|
for (const line of lines) {
|
|
1827
|
+
if (/^\s*(```|~~~)/.test(line)) {
|
|
1828
|
+
inCodeBlock = !inCodeBlock;
|
|
1829
|
+
continue;
|
|
1830
|
+
}
|
|
1831
|
+
if (inCodeBlock) continue;
|
|
1697
1832
|
const match = line.match(/^\s*-\s*\[([A-Z]+)\]((?:\[[^\]]+\])*)\s*(.+?)\s*$/);
|
|
1698
1833
|
if (!match) continue;
|
|
1699
1834
|
const status = match[1].toUpperCase();
|
|
@@ -1737,13 +1872,13 @@ function isPrMetadataConfigured2(feature) {
|
|
|
1737
1872
|
}
|
|
1738
1873
|
async function parseFeature(featurePath, type, context, options) {
|
|
1739
1874
|
const lang = options.lang;
|
|
1740
|
-
const folderName =
|
|
1875
|
+
const folderName = path11.basename(featurePath);
|
|
1741
1876
|
const match = folderName.match(/^(F\d+)-(.+)$/);
|
|
1742
1877
|
const id = match?.[1];
|
|
1743
1878
|
const slug = match?.[2] || folderName;
|
|
1744
|
-
const specPath =
|
|
1745
|
-
const planPath =
|
|
1746
|
-
const tasksPath =
|
|
1879
|
+
const specPath = path11.join(featurePath, "spec.md");
|
|
1880
|
+
const planPath = path11.join(featurePath, "plan.md");
|
|
1881
|
+
const tasksPath = path11.join(featurePath, "tasks.md");
|
|
1747
1882
|
let specStatus;
|
|
1748
1883
|
let issueNumber;
|
|
1749
1884
|
const specExists = await fs8.pathExists(specPath);
|
|
@@ -1765,6 +1900,8 @@ async function parseFeature(featurePath, type, context, options) {
|
|
|
1765
1900
|
const tasksSummary = { total: 0, todo: 0, doing: 0, done: 0 };
|
|
1766
1901
|
let activeTask;
|
|
1767
1902
|
let nextTodoTask;
|
|
1903
|
+
let tasksDocStatus;
|
|
1904
|
+
let tasksDocStatusFieldExists = false;
|
|
1768
1905
|
let completionChecklist;
|
|
1769
1906
|
let prLink;
|
|
1770
1907
|
let prStatus;
|
|
@@ -1784,11 +1921,14 @@ async function parseFeature(featurePath, type, context, options) {
|
|
|
1784
1921
|
const issueValue = extractFirstSpecValue(content, ["\uC774\uC288 \uBC88\uD638", "Issue Number", "Issue"]);
|
|
1785
1922
|
issueNumber = parseIssueNumber(issueValue);
|
|
1786
1923
|
}
|
|
1924
|
+
const tasksDocStatusValue = extractFirstSpecValue(content, ["\uBB38\uC11C \uC0C1\uD0DC", "Doc Status"]);
|
|
1925
|
+
tasksDocStatusFieldExists = hasAnySpecKey(content, ["\uBB38\uC11C \uC0C1\uD0DC", "Doc Status"]);
|
|
1926
|
+
tasksDocStatus = parseDocStatus(tasksDocStatusValue);
|
|
1787
1927
|
const prValue = extractFirstSpecValue(content, ["PR", "Pull Request"]);
|
|
1788
|
-
prFieldExists =
|
|
1928
|
+
prFieldExists = hasAnySpecKey(content, ["PR", "Pull Request"]);
|
|
1789
1929
|
prLink = parsePrLink(prValue);
|
|
1790
1930
|
const prStatusValue = extractFirstSpecValue(content, ["PR \uC0C1\uD0DC", "PR Status"]);
|
|
1791
|
-
prStatusFieldExists =
|
|
1931
|
+
prStatusFieldExists = hasAnySpecKey(content, ["PR \uC0C1\uD0DC", "PR Status"]);
|
|
1792
1932
|
prStatus = parseDocStatus(prStatusValue);
|
|
1793
1933
|
}
|
|
1794
1934
|
const warnings = [];
|
|
@@ -1801,7 +1941,7 @@ async function parseFeature(featurePath, type, context, options) {
|
|
|
1801
1941
|
slug,
|
|
1802
1942
|
folderName
|
|
1803
1943
|
);
|
|
1804
|
-
const relativeFeaturePathFromDocs =
|
|
1944
|
+
const relativeFeaturePathFromDocs = path11.relative(context.docsDir, featurePath);
|
|
1805
1945
|
const docsStatus = getGitStatusPorcelain(context.docsGitCwd, [relativeFeaturePathFromDocs]);
|
|
1806
1946
|
const docsHasUncommittedChanges = docsStatus === void 0 ? true : docsStatus.trim().length > 0;
|
|
1807
1947
|
const docsLastCommit = getLastCommitForPath(
|
|
@@ -1815,10 +1955,14 @@ async function parseFeature(featurePath, type, context, options) {
|
|
|
1815
1955
|
if (tasksExists && (!prFieldExists || !prStatusFieldExists)) {
|
|
1816
1956
|
warnings.push(tr(lang, "warnings", "legacyTasksPrFields"));
|
|
1817
1957
|
}
|
|
1958
|
+
if (tasksExists && !tasksDocStatusFieldExists) {
|
|
1959
|
+
warnings.push(tr(lang, "warnings", "legacyTasksDocStatusField"));
|
|
1960
|
+
}
|
|
1818
1961
|
if (docsEverCommitted && docsHasUncommittedChanges) {
|
|
1819
1962
|
warnings.push(tr(lang, "warnings", "docsUncommittedChanges"));
|
|
1820
1963
|
}
|
|
1821
|
-
const
|
|
1964
|
+
const tasksDocApproved = !tasksDocStatusFieldExists || tasksDocStatus === "Approved";
|
|
1965
|
+
const implementationDone = tasksExists && tasksSummary.total > 0 && tasksSummary.total === tasksSummary.done && isCompletionChecklistDone2({ completionChecklist }) && tasksDocApproved;
|
|
1822
1966
|
const workflowDone = implementationDone && specStatus === "Approved" && planStatus === "Approved" && isPrMetadataConfigured2({ docs: { prFieldExists, prStatusFieldExists } }) && !!prLink && prStatus === "Approved";
|
|
1823
1967
|
if (implementationDone && !workflowDone) {
|
|
1824
1968
|
if (specStatus !== "Approved") {
|
|
@@ -1848,6 +1992,7 @@ async function parseFeature(featurePath, type, context, options) {
|
|
|
1848
1992
|
issueNumber,
|
|
1849
1993
|
specStatus,
|
|
1850
1994
|
planStatus,
|
|
1995
|
+
tasksDocStatus,
|
|
1851
1996
|
tasks: tasksSummary,
|
|
1852
1997
|
activeTask,
|
|
1853
1998
|
nextTodoTask,
|
|
@@ -1868,6 +2013,7 @@ async function parseFeature(featurePath, type, context, options) {
|
|
|
1868
2013
|
specExists,
|
|
1869
2014
|
planExists,
|
|
1870
2015
|
tasksExists,
|
|
2016
|
+
tasksDocStatusFieldExists,
|
|
1871
2017
|
prFieldExists,
|
|
1872
2018
|
prStatusFieldExists
|
|
1873
2019
|
}
|
|
@@ -1875,7 +2021,8 @@ async function parseFeature(featurePath, type, context, options) {
|
|
|
1875
2021
|
const { currentStep, actions, nextAction } = resolveFeatureProgress(
|
|
1876
2022
|
featureState,
|
|
1877
2023
|
options.stepDefinitions,
|
|
1878
|
-
lang
|
|
2024
|
+
lang,
|
|
2025
|
+
options.approval
|
|
1879
2026
|
);
|
|
1880
2027
|
return { ...featureState, currentStep, actions, nextAction, warnings };
|
|
1881
2028
|
}
|
|
@@ -1924,7 +2071,7 @@ async function scanFeatures(config) {
|
|
|
1924
2071
|
docsDir: config.docsDir,
|
|
1925
2072
|
projectBranchAvailable: Boolean(singleProject?.cwd)
|
|
1926
2073
|
},
|
|
1927
|
-
{ lang: config.lang, stepDefinitions }
|
|
2074
|
+
{ lang: config.lang, stepDefinitions, approval: config.approval }
|
|
1928
2075
|
)
|
|
1929
2076
|
);
|
|
1930
2077
|
}
|
|
@@ -1946,7 +2093,7 @@ async function scanFeatures(config) {
|
|
|
1946
2093
|
docsDir: config.docsDir,
|
|
1947
2094
|
projectBranchAvailable: Boolean(feProject?.cwd)
|
|
1948
2095
|
},
|
|
1949
|
-
{ lang: config.lang, stepDefinitions }
|
|
2096
|
+
{ lang: config.lang, stepDefinitions, approval: config.approval }
|
|
1950
2097
|
)
|
|
1951
2098
|
);
|
|
1952
2099
|
}
|
|
@@ -1965,7 +2112,7 @@ async function scanFeatures(config) {
|
|
|
1965
2112
|
docsDir: config.docsDir,
|
|
1966
2113
|
projectBranchAvailable: Boolean(beProject?.cwd)
|
|
1967
2114
|
},
|
|
1968
|
-
{ lang: config.lang, stepDefinitions }
|
|
2115
|
+
{ lang: config.lang, stepDefinitions, approval: config.approval }
|
|
1969
2116
|
)
|
|
1970
2117
|
);
|
|
1971
2118
|
}
|
|
@@ -2005,7 +2152,7 @@ async function runStatus(options) {
|
|
|
2005
2152
|
process.exit(1);
|
|
2006
2153
|
}
|
|
2007
2154
|
const { docsDir, projectType, projectName, lang } = config;
|
|
2008
|
-
const featuresDir =
|
|
2155
|
+
const featuresDir = path11.join(docsDir, "features");
|
|
2009
2156
|
const scan = await scanFeatures(config);
|
|
2010
2157
|
const features = [];
|
|
2011
2158
|
const idMap = /* @__PURE__ */ new Map();
|
|
@@ -2018,7 +2165,7 @@ async function runStatus(options) {
|
|
|
2018
2165
|
""
|
|
2019
2166
|
) : projectName ?? "{{projectName}}";
|
|
2020
2167
|
const issue = f.issueNumber ? `#${f.issueNumber}` : "-";
|
|
2021
|
-
const relPath =
|
|
2168
|
+
const relPath = path11.relative(docsDir, f.path);
|
|
2022
2169
|
if (!idMap.has(id)) idMap.set(id, []);
|
|
2023
2170
|
idMap.get(id).push(relPath);
|
|
2024
2171
|
const total = f.tasks.total;
|
|
@@ -2083,7 +2230,7 @@ async function runStatus(options) {
|
|
|
2083
2230
|
}
|
|
2084
2231
|
console.log();
|
|
2085
2232
|
if (options.write) {
|
|
2086
|
-
const outputPath =
|
|
2233
|
+
const outputPath = path11.join(featuresDir, "status.md");
|
|
2087
2234
|
const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
2088
2235
|
const content = [
|
|
2089
2236
|
"# Feature Status",
|
|
@@ -2111,7 +2258,7 @@ function escapeRegExp2(value) {
|
|
|
2111
2258
|
}
|
|
2112
2259
|
async function getFeatureNameFromSpec(featureDir, fallbackSlug, fallbackFolderName) {
|
|
2113
2260
|
try {
|
|
2114
|
-
const specPath =
|
|
2261
|
+
const specPath = path11.join(featureDir, "spec.md");
|
|
2115
2262
|
if (!await fs8.pathExists(specPath)) return fallbackSlug;
|
|
2116
2263
|
const content = await fs8.readFile(specPath, "utf-8");
|
|
2117
2264
|
const keys = ["\uAE30\uB2A5\uBA85", "Feature Name"];
|
|
@@ -2169,7 +2316,7 @@ async function runUpdate(options) {
|
|
|
2169
2316
|
}
|
|
2170
2317
|
const { docsDir, projectType, lang } = config;
|
|
2171
2318
|
const templatesDir = getTemplatesDir();
|
|
2172
|
-
const sourceDir =
|
|
2319
|
+
const sourceDir = path11.join(templatesDir, lang, projectType);
|
|
2173
2320
|
const forceOverwrite = !!options.force || await isDocsWorktreeCleanOrThrow(docsDir, lang);
|
|
2174
2321
|
const hasExplicitSelection = !!(options.agents || options.skills || options.templates);
|
|
2175
2322
|
const updateAgents = options.agents || options.skills || !hasExplicitSelection;
|
|
@@ -2188,12 +2335,12 @@ async function runUpdate(options) {
|
|
|
2188
2335
|
agentsMode === "skills" ? tr(lang, "cli", "update.updatingSkills") : tr(lang, "cli", "update.updatingAgents")
|
|
2189
2336
|
)
|
|
2190
2337
|
);
|
|
2191
|
-
const commonAgentsBase =
|
|
2192
|
-
const typeAgentsBase =
|
|
2193
|
-
const targetAgentsBase =
|
|
2194
|
-
const commonAgents = agentsMode === "skills" ?
|
|
2195
|
-
const typeAgents = agentsMode === "skills" ?
|
|
2196
|
-
const targetAgents = agentsMode === "skills" ?
|
|
2338
|
+
const commonAgentsBase = path11.join(templatesDir, lang, "common", "agents");
|
|
2339
|
+
const typeAgentsBase = path11.join(templatesDir, lang, projectType, "agents");
|
|
2340
|
+
const targetAgentsBase = path11.join(docsDir, "agents");
|
|
2341
|
+
const commonAgents = agentsMode === "skills" ? path11.join(commonAgentsBase, "skills") : commonAgentsBase;
|
|
2342
|
+
const typeAgents = agentsMode === "skills" ? path11.join(typeAgentsBase, "skills") : typeAgentsBase;
|
|
2343
|
+
const targetAgents = agentsMode === "skills" ? path11.join(targetAgentsBase, "skills") : targetAgentsBase;
|
|
2197
2344
|
const featurePath = projectType === "fullstack" ? "docs/features/{be|fe}" : "docs/features";
|
|
2198
2345
|
const projectName = config.projectName ?? "{{projectName}}";
|
|
2199
2346
|
const commonReplacements = {
|
|
@@ -2231,8 +2378,8 @@ async function runUpdate(options) {
|
|
|
2231
2378
|
}
|
|
2232
2379
|
if (updateTemplates) {
|
|
2233
2380
|
console.log(chalk6.blue(tr(lang, "cli", "update.updatingFeatureBase")));
|
|
2234
|
-
const sourceFeatureBase =
|
|
2235
|
-
const targetFeatureBase =
|
|
2381
|
+
const sourceFeatureBase = path11.join(sourceDir, "features", "feature-base");
|
|
2382
|
+
const targetFeatureBase = path11.join(docsDir, "features", "feature-base");
|
|
2236
2383
|
if (await fs8.pathExists(sourceFeatureBase)) {
|
|
2237
2384
|
const replacements = {
|
|
2238
2385
|
"{{projectName}}": config.projectName ?? "{{projectName}}"
|
|
@@ -2265,8 +2412,8 @@ async function updateFolder(sourceDir, targetDir, force, replacements, lang = DE
|
|
|
2265
2412
|
const files = await fs8.readdir(sourceDir);
|
|
2266
2413
|
let updatedCount = 0;
|
|
2267
2414
|
for (const file of files) {
|
|
2268
|
-
const sourcePath =
|
|
2269
|
-
const targetPath =
|
|
2415
|
+
const sourcePath = path11.join(sourceDir, file);
|
|
2416
|
+
const targetPath = path11.join(targetDir, file);
|
|
2270
2417
|
const stat = await fs8.stat(sourcePath);
|
|
2271
2418
|
if (stat.isFile()) {
|
|
2272
2419
|
if (protectedFiles.has(file)) {
|
|
@@ -2326,7 +2473,7 @@ function getGitTopLevel2(cwd) {
|
|
|
2326
2473
|
function getDocsPorcelainStatus(docsDir) {
|
|
2327
2474
|
const top = getGitTopLevel2(docsDir);
|
|
2328
2475
|
if (!top) return null;
|
|
2329
|
-
const rel =
|
|
2476
|
+
const rel = path11.relative(top, docsDir) || ".";
|
|
2330
2477
|
try {
|
|
2331
2478
|
return execFileSync("git", ["status", "--porcelain=v1", "--", rel], {
|
|
2332
2479
|
cwd: top,
|
|
@@ -2375,7 +2522,7 @@ async function runConfig(options) {
|
|
|
2375
2522
|
);
|
|
2376
2523
|
process.exit(1);
|
|
2377
2524
|
}
|
|
2378
|
-
const configPath =
|
|
2525
|
+
const configPath = path11.join(config.docsDir, ".lee-spec-kit.json");
|
|
2379
2526
|
if (!options.projectRoot) {
|
|
2380
2527
|
console.log();
|
|
2381
2528
|
console.log(chalk6.blue(tr(config.lang, "cli", "config.currentTitle")));
|
|
@@ -2608,6 +2755,12 @@ async function runContext(featureName, options) {
|
|
|
2608
2755
|
inProgressCandidates: selectionMode === "open" ? inProgressFeatures : [],
|
|
2609
2756
|
readyToCloseCandidates: selectionMode === "open" ? readyToCloseFeatures : [],
|
|
2610
2757
|
actions: targetFeatures.length === 1 ? targetFeatures[0].actions : [],
|
|
2758
|
+
checkPolicy: {
|
|
2759
|
+
docPath: "/docs/agents/agents.md",
|
|
2760
|
+
hint: tr(lang, "cli", "context.checkPolicyHint"),
|
|
2761
|
+
token: "OK",
|
|
2762
|
+
config: config.approval ?? { mode: "builtin" }
|
|
2763
|
+
},
|
|
2611
2764
|
recommendation: ""
|
|
2612
2765
|
};
|
|
2613
2766
|
if (result.status === "multiple_active") {
|
|
@@ -2623,7 +2776,7 @@ async function runContext(featureName, options) {
|
|
|
2623
2776
|
return;
|
|
2624
2777
|
}
|
|
2625
2778
|
console.log();
|
|
2626
|
-
console.log(chalk6.bold("
|
|
2779
|
+
console.log(chalk6.bold(tr(lang, "cli", "context.header")));
|
|
2627
2780
|
if (config.projectType === "single") {
|
|
2628
2781
|
if (branches.project.single) {
|
|
2629
2782
|
console.log(
|
|
@@ -2738,7 +2891,8 @@ async function runContext(featureName, options) {
|
|
|
2738
2891
|
}
|
|
2739
2892
|
const f = targetFeatures[0];
|
|
2740
2893
|
const stepName = stepsMap[f.currentStep] || "Unknown";
|
|
2741
|
-
const
|
|
2894
|
+
const checkTag = (requiresUserCheck) => requiresUserCheck ? chalk6.yellow(tr(lang, "cli", "context.checkRequired")) : "";
|
|
2895
|
+
const hasCheckAction = (f.actions || []).some((a) => !!a.requiresUserCheck);
|
|
2742
2896
|
console.log(
|
|
2743
2897
|
`\u{1F539} Feature: ${chalk6.bold(f.folderName)} ${config.projectType === "fullstack" ? chalk6.cyan(`(${f.type})`) : ""}`
|
|
2744
2898
|
);
|
|
@@ -2748,7 +2902,7 @@ async function runContext(featureName, options) {
|
|
|
2748
2902
|
if (f.issueNumber) {
|
|
2749
2903
|
console.log(` \u2022 Issue: #${f.issueNumber}`);
|
|
2750
2904
|
}
|
|
2751
|
-
console.log(` \u2022 Path: ${
|
|
2905
|
+
console.log(` \u2022 Path: ${path11.relative(cwd, f.path)}`);
|
|
2752
2906
|
if (f.git.projectBranch) {
|
|
2753
2907
|
console.log(` \u2022 Project Branch: ${f.git.projectBranch}`);
|
|
2754
2908
|
}
|
|
@@ -2773,6 +2927,9 @@ async function runContext(featureName, options) {
|
|
|
2773
2927
|
}
|
|
2774
2928
|
console.log();
|
|
2775
2929
|
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"));
|
|
2930
|
+
if (hasCheckAction) {
|
|
2931
|
+
console.log(chalk6.gray(tr(lang, "cli", "context.checkPolicyHint")));
|
|
2932
|
+
}
|
|
2776
2933
|
if (!f.actions || f.actions.length === 0) {
|
|
2777
2934
|
console.log(`\u{1F449} Next Action: ${chalk6.green(chalk6.bold(f.nextAction))}`);
|
|
2778
2935
|
console.log();
|
|
@@ -2782,24 +2939,32 @@ async function runContext(featureName, options) {
|
|
|
2782
2939
|
const action = f.actions[0];
|
|
2783
2940
|
if (action.type === "command") {
|
|
2784
2941
|
console.log(
|
|
2785
|
-
`\u{1F449} Next Action (${chalk6.cyan(action.scope)}): ${
|
|
2942
|
+
`\u{1F449} Next Action (${chalk6.cyan(action.scope)}): ${checkTag(action.requiresUserCheck)}${chalk6.green(chalk6.bold(action.cmd))}`
|
|
2786
2943
|
);
|
|
2944
|
+
if (action.scope === "docs") {
|
|
2945
|
+
console.log(chalk6.gray(` \u21B3 ${tr(lang, "cli", "context.tipDocsCommitRules")}`));
|
|
2946
|
+
}
|
|
2787
2947
|
} else {
|
|
2788
2948
|
console.log(
|
|
2789
|
-
`\u{1F449} Next Action: ${
|
|
2949
|
+
`\u{1F449} Next Action: ${checkTag(action.requiresUserCheck)}${chalk6.green(chalk6.bold(action.message))}`
|
|
2790
2950
|
);
|
|
2791
2951
|
}
|
|
2792
2952
|
console.log();
|
|
2793
2953
|
return;
|
|
2794
2954
|
}
|
|
2795
2955
|
console.log(chalk6.green(chalk6.bold("\u{1F449} Next Actions:")));
|
|
2956
|
+
let hasDocsCommand = false;
|
|
2796
2957
|
f.actions.forEach((action) => {
|
|
2797
2958
|
if (action.type === "command") {
|
|
2798
|
-
console.log(` \u2022 (${action.scope}) ${
|
|
2959
|
+
console.log(` \u2022 (${action.scope}) ${checkTag(action.requiresUserCheck)}${action.cmd}`);
|
|
2960
|
+
if (action.scope === "docs") hasDocsCommand = true;
|
|
2799
2961
|
} else {
|
|
2800
|
-
console.log(` \u2022 ${
|
|
2962
|
+
console.log(` \u2022 ${checkTag(action.requiresUserCheck)}${action.message}`);
|
|
2801
2963
|
}
|
|
2802
2964
|
});
|
|
2965
|
+
if (hasDocsCommand) {
|
|
2966
|
+
console.log(chalk6.gray(` \u21B3 ${tr(lang, "cli", "context.tipDocsCommitRules")}`));
|
|
2967
|
+
}
|
|
2803
2968
|
console.log();
|
|
2804
2969
|
}
|
|
2805
2970
|
function printChecklist(f, stepDefinitions) {
|
|
@@ -2814,7 +2979,7 @@ function printChecklist(f, stepDefinitions) {
|
|
|
2814
2979
|
}
|
|
2815
2980
|
function formatPath(cwd, p) {
|
|
2816
2981
|
if (!p) return "";
|
|
2817
|
-
return
|
|
2982
|
+
return path11.isAbsolute(p) ? path11.relative(cwd, p) : p;
|
|
2818
2983
|
}
|
|
2819
2984
|
function detectPlaceholders(content) {
|
|
2820
2985
|
const patterns = [
|
|
@@ -2841,7 +3006,7 @@ async function checkDocsStructure(config, cwd) {
|
|
|
2841
3006
|
const issues = [];
|
|
2842
3007
|
const requiredDirs = ["agents", "features", "prd", "designs", "ideas"];
|
|
2843
3008
|
for (const dir of requiredDirs) {
|
|
2844
|
-
const p =
|
|
3009
|
+
const p = path11.join(config.docsDir, dir);
|
|
2845
3010
|
if (!await fs8.pathExists(p)) {
|
|
2846
3011
|
issues.push({
|
|
2847
3012
|
level: "error",
|
|
@@ -2851,7 +3016,7 @@ async function checkDocsStructure(config, cwd) {
|
|
|
2851
3016
|
});
|
|
2852
3017
|
}
|
|
2853
3018
|
}
|
|
2854
|
-
const configPath =
|
|
3019
|
+
const configPath = path11.join(config.docsDir, ".lee-spec-kit.json");
|
|
2855
3020
|
if (!await fs8.pathExists(configPath)) {
|
|
2856
3021
|
issues.push({
|
|
2857
3022
|
level: "warn",
|
|
@@ -2874,13 +3039,13 @@ async function checkFeatures(config, cwd, features) {
|
|
|
2874
3039
|
}
|
|
2875
3040
|
const idMap = /* @__PURE__ */ new Map();
|
|
2876
3041
|
for (const f of features) {
|
|
2877
|
-
const rel = f.docs.featurePathFromDocs ||
|
|
3042
|
+
const rel = f.docs.featurePathFromDocs || path11.relative(config.docsDir, f.path);
|
|
2878
3043
|
const id = f.id || "UNKNOWN";
|
|
2879
3044
|
if (!idMap.has(id)) idMap.set(id, []);
|
|
2880
3045
|
idMap.get(id).push(rel);
|
|
2881
3046
|
const featureDocs = ["spec.md", "plan.md", "tasks.md", "decisions.md"];
|
|
2882
3047
|
for (const file of featureDocs) {
|
|
2883
|
-
const p =
|
|
3048
|
+
const p = path11.join(f.path, file);
|
|
2884
3049
|
if (!await fs8.pathExists(p)) continue;
|
|
2885
3050
|
const content = await fs8.readFile(p, "utf-8");
|
|
2886
3051
|
const placeholders = detectPlaceholders(content);
|
|
@@ -2906,7 +3071,7 @@ async function checkFeatures(config, cwd, features) {
|
|
|
2906
3071
|
level: "warn",
|
|
2907
3072
|
code: "spec_status_unset",
|
|
2908
3073
|
message: tr(config.lang, "cli", "doctor.issue.specStatusUnset"),
|
|
2909
|
-
path: formatPath(cwd,
|
|
3074
|
+
path: formatPath(cwd, path11.join(f.path, "spec.md"))
|
|
2910
3075
|
});
|
|
2911
3076
|
}
|
|
2912
3077
|
if (f.docs.planExists && !f.planStatus) {
|
|
@@ -2914,7 +3079,7 @@ async function checkFeatures(config, cwd, features) {
|
|
|
2914
3079
|
level: "warn",
|
|
2915
3080
|
code: "plan_status_unset",
|
|
2916
3081
|
message: tr(config.lang, "cli", "doctor.issue.planStatusUnset"),
|
|
2917
|
-
path: formatPath(cwd,
|
|
3082
|
+
path: formatPath(cwd, path11.join(f.path, "plan.md"))
|
|
2918
3083
|
});
|
|
2919
3084
|
}
|
|
2920
3085
|
if (f.docs.tasksExists && f.tasks.total === 0) {
|
|
@@ -2922,7 +3087,23 @@ async function checkFeatures(config, cwd, features) {
|
|
|
2922
3087
|
level: "warn",
|
|
2923
3088
|
code: "tasks_empty",
|
|
2924
3089
|
message: tr(config.lang, "cli", "doctor.issue.tasksEmpty"),
|
|
2925
|
-
path: formatPath(cwd,
|
|
3090
|
+
path: formatPath(cwd, path11.join(f.path, "tasks.md"))
|
|
3091
|
+
});
|
|
3092
|
+
}
|
|
3093
|
+
if (f.docs.tasksExists && !f.docs.tasksDocStatusFieldExists) {
|
|
3094
|
+
issues.push({
|
|
3095
|
+
level: "warn",
|
|
3096
|
+
code: "tasks_doc_status_missing",
|
|
3097
|
+
message: tr(config.lang, "cli", "doctor.issue.tasksDocStatusMissing"),
|
|
3098
|
+
path: formatPath(cwd, path11.join(f.path, "tasks.md"))
|
|
3099
|
+
});
|
|
3100
|
+
}
|
|
3101
|
+
if (f.docs.tasksExists && f.docs.tasksDocStatusFieldExists && !f.tasksDocStatus) {
|
|
3102
|
+
issues.push({
|
|
3103
|
+
level: "warn",
|
|
3104
|
+
code: "tasks_doc_status_unset",
|
|
3105
|
+
message: tr(config.lang, "cli", "doctor.issue.tasksDocStatusUnset"),
|
|
3106
|
+
path: formatPath(cwd, path11.join(f.path, "tasks.md"))
|
|
2926
3107
|
});
|
|
2927
3108
|
}
|
|
2928
3109
|
}
|
|
@@ -2946,7 +3127,7 @@ async function checkFeatures(config, cwd, features) {
|
|
|
2946
3127
|
level: "warn",
|
|
2947
3128
|
code: "missing_feature_id",
|
|
2948
3129
|
message: tr(config.lang, "cli", "doctor.issue.missingFeatureId"),
|
|
2949
|
-
path: formatPath(cwd,
|
|
3130
|
+
path: formatPath(cwd, path11.join(config.docsDir, p))
|
|
2950
3131
|
});
|
|
2951
3132
|
}
|
|
2952
3133
|
return issues;
|
|
@@ -2996,7 +3177,7 @@ function doctorCommand(program2) {
|
|
|
2996
3177
|
}
|
|
2997
3178
|
console.log();
|
|
2998
3179
|
console.log(chalk6.bold(tr(lang, "cli", "doctor.title")));
|
|
2999
|
-
console.log(chalk6.gray(`- Docs: ${
|
|
3180
|
+
console.log(chalk6.gray(`- Docs: ${path11.relative(cwd, docsDir)}`));
|
|
3000
3181
|
console.log(chalk6.gray(`- Type: ${projectType}`));
|
|
3001
3182
|
console.log(chalk6.gray(`- Lang: ${lang}`));
|
|
3002
3183
|
console.log();
|
|
@@ -3090,11 +3271,11 @@ ${version}
|
|
|
3090
3271
|
}
|
|
3091
3272
|
return `${ascii}${footer}`;
|
|
3092
3273
|
}
|
|
3093
|
-
var CACHE_FILE =
|
|
3274
|
+
var CACHE_FILE = path11.join(os.homedir(), ".lee-spec-kit-version-cache.json");
|
|
3094
3275
|
var CHECK_INTERVAL = 24 * 60 * 60 * 1e3;
|
|
3095
3276
|
function getCurrentVersion() {
|
|
3096
3277
|
try {
|
|
3097
|
-
const packageJsonPath =
|
|
3278
|
+
const packageJsonPath = path11.join(__dirname$1, "..", "package.json");
|
|
3098
3279
|
if (fs8.existsSync(packageJsonPath)) {
|
|
3099
3280
|
const pkg = fs8.readJsonSync(packageJsonPath);
|
|
3100
3281
|
return pkg.version;
|
|
@@ -3184,7 +3365,7 @@ function shouldCheckForUpdates() {
|
|
|
3184
3365
|
if (shouldCheckForUpdates()) checkForUpdates();
|
|
3185
3366
|
function getCliVersion() {
|
|
3186
3367
|
try {
|
|
3187
|
-
const packageJsonPath =
|
|
3368
|
+
const packageJsonPath = path11.join(__dirname$1, "..", "package.json");
|
|
3188
3369
|
if (fs8.existsSync(packageJsonPath)) {
|
|
3189
3370
|
const pkg = fs8.readJsonSync(packageJsonPath);
|
|
3190
3371
|
if (pkg?.version) return String(pkg.version);
|