lee-spec-kit 0.4.3 → 0.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js
CHANGED
|
@@ -43,6 +43,372 @@ function getTemplatesDir() {
|
|
|
43
43
|
return path4.join(rootDir, "templates");
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
// src/utils/i18n.ts
|
|
47
|
+
var DEFAULT_LANG = "en";
|
|
48
|
+
function normalizeLang(lang) {
|
|
49
|
+
if (lang === "ko" || lang === "en") return lang;
|
|
50
|
+
return DEFAULT_LANG;
|
|
51
|
+
}
|
|
52
|
+
function formatTemplate(template, vars) {
|
|
53
|
+
return template.replace(/\{(\w+)\}/g, (_, key) => {
|
|
54
|
+
const value = vars[key];
|
|
55
|
+
return value === void 0 ? `{${key}}` : String(value);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
var I18N = {
|
|
59
|
+
ko: {
|
|
60
|
+
cli: {
|
|
61
|
+
"common.errorLabel": "\uC624\uB958:",
|
|
62
|
+
"common.canceled": "\uC791\uC5C5\uC774 \uCDE8\uC18C\uB418\uC5C8\uC2B5\uB2C8\uB2E4.",
|
|
63
|
+
"common.configNotFound": "\uC124\uC815 \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uBA3C\uC800 init\uC744 \uC2E4\uD589\uD574\uC8FC\uC138\uC694.",
|
|
64
|
+
"common.docsNotFound": "docs \uD3F4\uB354\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uBA3C\uC800 init\uC744 \uC2E4\uD589\uD558\uC138\uC694.",
|
|
65
|
+
"status.noFeatures": "Feature\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
66
|
+
"status.duplicateIds": "\uC911\uBCF5 Feature ID \uBC1C\uACAC:",
|
|
67
|
+
"status.missingIds": "Feature ID\uAC00 \uC5C6\uB294 \uD56D\uBAA9:",
|
|
68
|
+
"status.wrote": "\u2705 {path} \uC0DD\uC131 \uC644\uB8CC",
|
|
69
|
+
"feature.selectRepo": "\uB808\uD3EC\uC9C0\uD1A0\uB9AC\uB97C \uC120\uD0DD\uD558\uC138\uC694:",
|
|
70
|
+
"feature.folderExists": "\uC774\uBBF8 \uC874\uC7AC\uD558\uB294 \uD3F4\uB354\uC785\uB2C8\uB2E4: {path}",
|
|
71
|
+
"feature.baseNotFound": "feature-base \uD15C\uD50C\uB9BF\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
72
|
+
"feature.created": "\u2705 Feature \uD3F4\uB354 \uC0DD\uC131 \uC644\uB8CC: {path}",
|
|
73
|
+
"feature.nextStepsTitle": "\uB2E4\uC74C \uB2E8\uACC4:",
|
|
74
|
+
"feature.nextSteps1": " 1. {path}/spec.md \uC791\uC131",
|
|
75
|
+
"feature.nextSteps2": " 2. \uC0AC\uC6A9\uC790 \uB9AC\uBDF0 \uC694\uCCAD",
|
|
76
|
+
"feature.nextSteps3": " 3. \uC2B9\uC778 \uD6C4 plan.md \uC791\uC131",
|
|
77
|
+
"config.currentTitle": "\u{1F4CB} \uD604\uC7AC \uC124\uC815:",
|
|
78
|
+
"config.pathLabel": "\uACBD\uB85C",
|
|
79
|
+
"config.projectRootStandaloneOnly": "\u26A0\uFE0F projectRoot\uB294 standalone \uBAA8\uB4DC\uC5D0\uC11C\uB9CC \uC124\uC815 \uAC00\uB2A5\uD569\uB2C8\uB2E4.",
|
|
80
|
+
"config.selectRepoToUpdate": "\uC218\uC815\uD560 \uB808\uD3EC\uC9C0\uD1A0\uB9AC\uB97C \uC120\uD0DD\uD558\uC138\uC694:",
|
|
81
|
+
"config.fullstackRepoRequired": "Fullstack \uD504\uB85C\uC81D\uD2B8\uB294 --repo fe \uB610\uB294 --repo be\uB97C \uC9C0\uC815\uD574\uC57C \uD569\uB2C8\uB2E4.",
|
|
82
|
+
"config.projectRootSet": "\u2705 {repo} projectRoot \uC124\uC815 \uC644\uB8CC: {path}",
|
|
83
|
+
"config.projectRootSetSingle": "\u2705 projectRoot \uC124\uC815 \uC644\uB8CC: {path}",
|
|
84
|
+
"update.start": "\u{1F4E6} \uD15C\uD50C\uB9BF \uC5C5\uB370\uC774\uD2B8\uB97C \uC2DC\uC791\uD569\uB2C8\uB2E4...",
|
|
85
|
+
"update.langLabel": "\uC5B8\uC5B4",
|
|
86
|
+
"update.typeLabel": "\uD0C0\uC785",
|
|
87
|
+
"update.updatingAgents": "\u{1F4C1} agents/ \uD3F4\uB354 \uC5C5\uB370\uC774\uD2B8 \uC911...",
|
|
88
|
+
"update.updatingSkills": "\u{1F4C1} agents/skills \uD3F4\uB354 \uC5C5\uB370\uC774\uD2B8 \uC911...",
|
|
89
|
+
"update.agentsUpdated": "agents/ \uC5C5\uB370\uC774\uD2B8 \uC644\uB8CC",
|
|
90
|
+
"update.skillsUpdated": "agents/skills \uC5C5\uB370\uC774\uD2B8 \uC644\uB8CC",
|
|
91
|
+
"update.updatingFeatureBase": "\u{1F4C1} features/feature-base/ \uD3F4\uB354 \uC5C5\uB370\uC774\uD2B8 \uC911...",
|
|
92
|
+
"update.filesUpdated": "{count}\uAC1C \uD30C\uC77C \uC5C5\uB370\uC774\uD2B8 \uC644\uB8CC",
|
|
93
|
+
"update.updatedTotal": "\uCD1D {count}\uAC1C \uD30C\uC77C \uC5C5\uB370\uC774\uD2B8 \uC644\uB8CC!",
|
|
94
|
+
"update.changeDetected": "\uBCC0\uACBD \uAC10\uC9C0 (--force\uB85C \uB36E\uC5B4\uC4F0\uAE30)",
|
|
95
|
+
"update.fileUpdated": "{file} \uC5C5\uB370\uC774\uD2B8",
|
|
96
|
+
"doctor.title": "\u{1F50E} \uBB38\uC11C \uC9C4\uB2E8",
|
|
97
|
+
"doctor.envWarnings": "\u26A0\uFE0F \uD658\uACBD \uACBD\uACE0:",
|
|
98
|
+
"doctor.noIssues": "\u2705 \uBB38\uC81C\uB97C \uCC3E\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.",
|
|
99
|
+
"doctor.errorsTitle": "\uC624\uB958",
|
|
100
|
+
"doctor.warningsTitle": "\uACBD\uACE0",
|
|
101
|
+
"doctor.tipJson": "Tip: \uC5D0\uC774\uC804\uD2B8\uC6A9 JSON \uCD9C\uB825: npx lee-spec-kit doctor --json{strictFlag}",
|
|
102
|
+
"doctor.issue.missingRequiredDir": "\uD544\uC218 \uD3F4\uB354\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4: {dir}",
|
|
103
|
+
"doctor.issue.missingConfig": "\uC124\uC815 \uD30C\uC77C(.lee-spec-kit.json)\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. \uC77C\uBD80 \uAE30\uB2A5\uC774 \uD3F4\uB354 \uAD6C\uC870 \uCD94\uC815\uC73C\uB85C \uB3D9\uC791\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.",
|
|
104
|
+
"doctor.issue.noFeatures": "Feature \uD3F4\uB354\uB97C \uCC3E\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. (feature-base\uB9CC \uC874\uC7AC\uD558\uAC70\uB098 \uC544\uC9C1 feature\uB97C \uB9CC\uB4E4\uC9C0 \uC54A\uC558\uC744 \uC218 \uC788\uC2B5\uB2C8\uB2E4.)",
|
|
105
|
+
"doctor.issue.placeholdersLeft": "\uD50C\uB808\uC774\uC2A4\uD640\uB354\uAC00 \uB0A8\uC544\uC788\uC2B5\uB2C8\uB2E4: {placeholders}",
|
|
106
|
+
"doctor.issue.missingSpec": "spec.md\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
107
|
+
"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)",
|
|
108
|
+
"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)",
|
|
109
|
+
"doctor.issue.tasksEmpty": "tasks.md\uC5D0 \uD0DC\uC2A4\uD06C\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
110
|
+
"doctor.issue.duplicateFeatureId": "\uC911\uBCF5 Feature ID \uAC10\uC9C0: {id} ({count}\uAC1C)",
|
|
111
|
+
"doctor.issue.missingFeatureId": "Feature \uD3F4\uB354\uBA85\uC774 F001-... \uD615\uC2DD\uC774 \uC544\uB2D9\uB2C8\uB2E4. (ID\uB97C \uCD94\uCD9C\uD560 \uC218 \uC5C6\uC74C)",
|
|
112
|
+
"context.noActiveFeatures": "\u26A0\uFE0F \uC9C4\uD589 \uC911\uC778 Feature\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
113
|
+
"context.envWarnings": "\u26A0\uFE0F \uD658\uACBD \uACBD\uACE0:",
|
|
114
|
+
"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)",
|
|
115
|
+
"context.sectionInProgress": "\uC9C4\uD589 \uC911",
|
|
116
|
+
"context.sectionReadyToClose": "\uC885\uB8CC \uC900\uBE44",
|
|
117
|
+
"context.tipDetails": "Tip: \uD2B9\uC815 Feature\uC758 \uC0C1\uC138 \uC815\uBCF4\uB97C \uBCF4\uB824\uBA74:",
|
|
118
|
+
"context.tipShowAll": "\uC804\uCCB4 \uBCF4\uAE30",
|
|
119
|
+
"context.tipShowDone": "\uC644\uB8CC\uB9CC \uBCF4\uAE30",
|
|
120
|
+
"context.okRequired": "[OK \uD544\uC694] ",
|
|
121
|
+
"context.list.docsCommitNeeded": "\uBB38\uC11C \uCEE4\uBC0B \uD544\uC694",
|
|
122
|
+
"context.list.issueNumberNeeded": "\uC774\uC288 \uBC88\uD638 \uAE30\uB85D \uD544\uC694",
|
|
123
|
+
"context.list.addPrMetadata": "PR \uBA54\uD0C0\uB370\uC774\uD130(PR/PR \uC0C1\uD0DC) \uCD94\uAC00",
|
|
124
|
+
"context.list.recordPrLink": "PR \uB9C1\uD06C \uAE30\uB85D",
|
|
125
|
+
"context.list.setPrStatus": "PR \uC0C1\uD0DC \uC124\uC815",
|
|
126
|
+
"context.list.prStatusToApproved": "PR \uC0C1\uD0DC {status} \u2192 Approved",
|
|
127
|
+
"context.list.approveSpec": "spec \uC2B9\uC778 \uD544\uC694",
|
|
128
|
+
"context.list.approvePlan": "plan \uC2B9\uC778 \uD544\uC694",
|
|
129
|
+
"init.selectLangPrompt": "\uBB38\uC11C \uC5B8\uC5B4\uB97C \uC120\uD0DD\uD558\uC138\uC694:",
|
|
130
|
+
"init.currentDirectoryLabel": "\u{1F4CD} \uD604\uC7AC \uC704\uCE58",
|
|
131
|
+
"init.gitDetected": "\u2705 Git \uB808\uD3EC\uC9C0\uD1A0\uB9AC \uAC10\uC9C0\uB428",
|
|
132
|
+
"init.insideProjectRoot": "\uD604\uC7AC \uD504\uB85C\uC81D\uD2B8 \uB8E8\uD2B8 \uB0B4\uC5D0\uC11C \uC2E4\uD589\uD558\uACE0 \uACC4\uC2ED\uB2C8\uB2E4.",
|
|
133
|
+
"init.modeEmbeddedDesc": "\u2022 embedded: \uC5EC\uAE30\uC5D0 ./docs \uD3F4\uB354\uB97C \uC0DD\uC131\uD569\uB2C8\uB2E4. \uD504\uB85C\uC81D\uD2B8\uC640 \uD568\uAED8 \uAD00\uB9AC\uB429\uB2C8\uB2E4.",
|
|
134
|
+
"init.modeStandaloneDesc": "\u2022 standalone: \uBCC4\uB3C4 \uD3F4\uB354\uC5D0\uC11C \uB3C5\uB9BD docs \uB808\uD3EC\uB85C \uAD00\uB9AC\uD558\uB824\uBA74,",
|
|
135
|
+
"init.modeStandaloneMove": " \uD574\uB2F9 \uD3F4\uB354\uB85C \uC774\uB3D9 \uD6C4 \uB2E4\uC2DC \uC2E4\uD589\uD574\uC8FC\uC138\uC694.",
|
|
136
|
+
"init.gitNotDetected": "\u26A0\uFE0F Git \uB808\uD3EC\uC9C0\uD1A0\uB9AC\uAC00 \uAC10\uC9C0\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.",
|
|
137
|
+
"init.gitNotDetectedDetail": "\uC0C8\uB85C\uC6B4 Git \uB808\uD3EC\uC9C0\uD1A0\uB9AC\uAC00 \uC0DD\uC131\uB429\uB2C8\uB2E4.",
|
|
138
|
+
"init.prompt.projectName": "\uD504\uB85C\uC81D\uD2B8 \uC774\uB984\uC744 \uC785\uB825\uD558\uC138\uC694:",
|
|
139
|
+
"init.prompt.projectType": "\uD504\uB85C\uC81D\uD2B8 \uD0C0\uC785\uC744 \uC120\uD0DD\uD558\uC138\uC694:",
|
|
140
|
+
"init.choice.projectType.single.title": "Single - \uB2E8\uC77C \uB808\uD3EC \uD504\uB85C\uC81D\uD2B8",
|
|
141
|
+
"init.choice.projectType.single.desc": "features/ \uD3F4\uB354 \uD558\uB098\uB85C \uAD00\uB9AC",
|
|
142
|
+
"init.choice.projectType.fullstack.title": "Fullstack - FE/BE \uBD84\uB9AC \uD504\uB85C\uC81D\uD2B8",
|
|
143
|
+
"init.choice.projectType.fullstack.desc": "features/be/, features/fe/ \uBD84\uB9AC \uAD00\uB9AC",
|
|
144
|
+
"init.prompt.docsMode": "Docs \uAD00\uB9AC \uBC29\uC2DD\uC744 \uC120\uD0DD\uD558\uC138\uC694:",
|
|
145
|
+
"init.choice.docsRepo.embedded.title": "embedded - \uD504\uB85C\uC81D\uD2B8 \uB0B4 \uD3EC\uD568 (./docs)",
|
|
146
|
+
"init.choice.docsRepo.embedded.desc": "\uD504\uB85C\uC81D\uD2B8\uC640 \uD568\uAED8 push\uB429\uB2C8\uB2E4",
|
|
147
|
+
"init.choice.docsRepo.standalone.title": "standalone - \uBCC4\uB3C4 \uB3C5\uB9BD \uB808\uD3EC",
|
|
148
|
+
"init.choice.docsRepo.standalone.desc": "push \uC5EC\uBD80\uB97C \uBCC4\uB3C4\uB85C \uC124\uC815\uD569\uB2C8\uB2E4",
|
|
149
|
+
"init.prompt.feRepoPath": "Frontend \uB808\uD3EC\uC9C0\uD1A0\uB9AC \uACBD\uB85C\uB97C \uC785\uB825\uD558\uC138\uC694:",
|
|
150
|
+
"init.prompt.beRepoPath": "Backend \uB808\uD3EC\uC9C0\uD1A0\uB9AC \uACBD\uB85C\uB97C \uC785\uB825\uD558\uC138\uC694:",
|
|
151
|
+
"init.prompt.projectRepoPath": "\uD504\uB85C\uC81D\uD2B8 \uB808\uD3EC\uC9C0\uD1A0\uB9AC \uACBD\uB85C\uB97C \uC785\uB825\uD558\uC138\uC694:",
|
|
152
|
+
"init.validation.enterPath": "\uACBD\uB85C\uB97C \uC785\uB825\uD574\uC8FC\uC138\uC694",
|
|
153
|
+
"init.prompt.pushMode": "Docs push \uBC29\uC2DD\uC744 \uC120\uD0DD\uD558\uC138\uC694:",
|
|
154
|
+
"init.choice.push.local": "local - \uB85C\uCEEC\uC5D0\uC11C\uB9CC \uAD00\uB9AC (push \uC548 \uD568)",
|
|
155
|
+
"init.choice.push.remote": "remote - \uC6D0\uACA9\uC5D0\uB3C4 push",
|
|
156
|
+
"init.prompt.remoteUrl": "\uC6D0\uACA9 \uB808\uD3EC URL\uC744 \uC785\uB825\uD558\uC138\uC694:",
|
|
157
|
+
"init.validation.enterUrl": "URL\uC744 \uC785\uB825\uD574\uC8FC\uC138\uC694",
|
|
158
|
+
"init.prompt.overwrite": "{dir} \uD3F4\uB354\uAC00 \uC774\uBBF8 \uC874\uC7AC\uD569\uB2C8\uB2E4. \uB36E\uC5B4\uC4F0\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?",
|
|
159
|
+
"init.log.creatingDocs": "\u{1F4C1} docs \uAD6C\uC870 \uC0DD\uC131 \uC911...",
|
|
160
|
+
"init.log.projectLabel": "\uD504\uB85C\uC81D\uD2B8",
|
|
161
|
+
"init.log.typeLabel": "\uD0C0\uC785",
|
|
162
|
+
"init.log.langLabel": "\uC5B8\uC5B4",
|
|
163
|
+
"init.log.pathLabel": "\uACBD\uB85C",
|
|
164
|
+
"init.log.docsCreated": "\u2705 docs \uAD6C\uC870 \uC0DD\uC131 \uC644\uB8CC!",
|
|
165
|
+
"init.log.nextStepsTitle": "\uB2E4\uC74C \uB2E8\uACC4:",
|
|
166
|
+
"init.log.nextSteps1": " 1. {docsDir}/prd/README.md \uC791\uC131",
|
|
167
|
+
"init.log.nextSteps2": " 2. npx lee-spec-kit feature <name> \uC73C\uB85C \uAE30\uB2A5 \uCD94\uAC00",
|
|
168
|
+
"init.log.gitRepoDetectedCommit": "\u{1F4E6} Git \uB808\uD3EC\uC9C0\uD1A0\uB9AC \uAC10\uC9C0, docs \uCEE4\uBC0B \uC911...",
|
|
169
|
+
"init.log.gitInit": "\u{1F4E6} Git \uCD08\uAE30\uD654 \uC911...",
|
|
170
|
+
"init.warn.stagedChangesSkip": '\u26A0\uFE0F \uD604\uC7AC Git index\uC5D0 \uC774\uBBF8 stage\uB41C \uBCC0\uACBD\uC774 \uC788\uC2B5\uB2C8\uB2E4. (--dir "." \uC778 \uACBD\uC6B0 \uCEE4\uBC0B \uBC94\uC704\uB97C \uC548\uC804\uD558\uAC8C \uC81C\uD55C\uD560 \uC218 \uC5C6\uC5B4 \uC790\uB3D9 \uCEE4\uBC0B\uC744 \uAC74\uB108\uB701\uB2C8\uB2E4)',
|
|
171
|
+
"init.warn.commitManually": " \uC218\uB3D9\uC73C\uB85C \uBCC0\uACBD \uB0B4\uC6A9\uC744 \uD655\uC778\uD55C \uB4A4 \uCEE4\uBC0B\uD574\uC8FC\uC138\uC694.",
|
|
172
|
+
"init.log.gitRemoteSet": "\u2705 Git remote \uC124\uC815 \uC644\uB8CC: {remote}",
|
|
173
|
+
"init.warn.gitRemoteExists": "\u26A0\uFE0F Git remote\uAC00 \uC774\uBBF8 \uC874\uC7AC\uD569\uB2C8\uB2E4.",
|
|
174
|
+
"init.log.gitInitialCommitDone": "\u2705 Git \uCD08\uAE30 \uCEE4\uBC0B \uC644\uB8CC!",
|
|
175
|
+
"init.warn.skipGitInit": "\u26A0\uFE0F Git \uCD08\uAE30\uD654\uB97C \uAC74\uB108\uB701\uB2C8\uB2E4 (\uC218\uB3D9\uC73C\uB85C \uCEE4\uBC0B\uD574\uC8FC\uC138\uC694)",
|
|
176
|
+
"init.error.templateNotFound": "\uD15C\uD50C\uB9BF\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: {path}"
|
|
177
|
+
},
|
|
178
|
+
steps: {
|
|
179
|
+
featureFolder: "Feature \uD3F4\uB354 \uC0DD\uC131",
|
|
180
|
+
specWrite: "spec.md \uC791\uC131",
|
|
181
|
+
specApprove: "spec.md \uC2B9\uC778",
|
|
182
|
+
planWrite: "plan.md \uC791\uC131",
|
|
183
|
+
planApprove: "plan.md \uC2B9\uC778",
|
|
184
|
+
tasksWrite: "tasks.md \uC791\uC131",
|
|
185
|
+
docsCommitPlanning: "\uBB38\uC11C \uCEE4\uBC0B(\uB3D9\uAE30\uD654)",
|
|
186
|
+
issueCreate: "GitHub Issue \uC0DD\uC131",
|
|
187
|
+
branchCreate: "\uBE0C\uB79C\uCE58 \uC0DD\uC131",
|
|
188
|
+
tasksExecute: "\uD0DC\uC2A4\uD06C \uC2E4\uD589",
|
|
189
|
+
prCreate: "PR \uC0DD\uC131",
|
|
190
|
+
codeReview: "\uCF54\uB4DC \uB9AC\uBDF0",
|
|
191
|
+
featureDone: "Feature \uC644\uB8CC"
|
|
192
|
+
},
|
|
193
|
+
messages: {
|
|
194
|
+
specCreate: "spec.md \uD15C\uD50C\uB9BF\uC744 \uBCF5\uC0AC\uD574 \uC791\uC131\uD558\uC138\uC694. (features/feature-base/spec.md \uCC38\uACE0)",
|
|
195
|
+
specImprove: "spec.md\uB97C \uBCF4\uC644\uD558\uACE0 \uC0C1\uD0DC\uB97C Review\uB85C \uBCC0\uACBD\uD558\uC138\uC694.",
|
|
196
|
+
specApproval: "spec.md \uB0B4\uC6A9\uC744 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uACF5\uC720\uD558\uACE0 \uC2B9\uC778(OK)\uC744 \uBC1B\uC73C\uC138\uC694.",
|
|
197
|
+
planCreate: "plan.md \uD15C\uD50C\uB9BF\uC744 \uBCF5\uC0AC\uD574 \uC791\uC131\uD558\uC138\uC694. (features/feature-base/plan.md \uCC38\uACE0)",
|
|
198
|
+
planImprove: "plan.md\uB97C \uBCF4\uC644\uD558\uACE0 \uC0C1\uD0DC\uB97C Review\uB85C \uBCC0\uACBD\uD558\uC138\uC694.",
|
|
199
|
+
planApproval: "plan.md \uB0B4\uC6A9\uC744 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uACF5\uC720\uD558\uACE0 \uC2B9\uC778(OK)\uC744 \uBC1B\uC73C\uC138\uC694.",
|
|
200
|
+
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)",
|
|
201
|
+
tasksNeedAtLeastOne: "tasks.md\uC5D0 \uCD5C\uC18C 1\uAC1C \uC774\uC0C1\uC758 \uD0DC\uC2A4\uD06C\uB97C \uC791\uC131\uD558\uC138\uC694.",
|
|
202
|
+
docsCommitPlanning: 'cd "{docsGitCwd}" && git add "{featurePath}" && git commit -m "docs(planning): {folderName} \uAE30\uD68D \uBB38\uC11C"',
|
|
203
|
+
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)",
|
|
204
|
+
docsCommitIssueUpdate: 'cd "{docsGitCwd}" && git add "{featurePath}" && git commit -m "docs(#{issueNumber}): {folderName} \uBB38\uC11C \uC5C5\uB370\uC774\uD2B8"',
|
|
205
|
+
standaloneNeedsProjectRoot: "standalone \uBAA8\uB4DC\uC5D0\uC11C\uB294 projectRoot \uC124\uC815\uC774 \uD544\uC694\uD569\uB2C8\uB2E4. (npx lee-spec-kit config --project-root ...)",
|
|
206
|
+
createBranch: 'cd "{projectGitCwd}" && git checkout -b feat/{issueNumber}-{slug}',
|
|
207
|
+
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.',
|
|
208
|
+
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})",
|
|
209
|
+
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)',
|
|
210
|
+
startNextTodoTask: '\uB2E4\uC74C TODO \uD0DC\uC2A4\uD06C\uB97C \uC2DC\uC791\uD558\uC138\uC694: "{title}" ({done}/{total}) (skills/execute-task.md \uCC38\uACE0)',
|
|
211
|
+
checkTaskStatuses: "\uD0DC\uC2A4\uD06C \uC0C1\uD0DC\uB97C \uD655\uC778\uD558\uC138\uC694. ({done}/{total}) (skills/execute-task.md \uCC38\uACE0)",
|
|
212
|
+
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? (OK \uD544\uC694)",
|
|
213
|
+
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)",
|
|
214
|
+
prFillStatus: "tasks.md\uC758 PR \uC0C1\uD0DC\uB97C Draft/Review/Approved \uC911 \uD558\uB098\uB85C \uC124\uC815\uD558\uC138\uC694. (merge \uD6C4 Approved\uB85C \uC5C5\uB370\uC774\uD2B8)",
|
|
215
|
+
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)",
|
|
216
|
+
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.",
|
|
217
|
+
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.",
|
|
218
|
+
fallbackRerunContext: "\uC0C1\uD0DC\uB97C \uD310\uBCC4\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uBB38\uC11C\uB97C \uD655\uC778\uD55C \uB4A4 \uB2E4\uC2DC context\uB97C \uC2E4\uD589\uD558\uC138\uC694."
|
|
219
|
+
},
|
|
220
|
+
warnings: {
|
|
221
|
+
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.)",
|
|
222
|
+
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)",
|
|
223
|
+
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)",
|
|
224
|
+
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.",
|
|
225
|
+
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.)",
|
|
226
|
+
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.)",
|
|
227
|
+
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.)",
|
|
228
|
+
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 Draft/Review/Approved \uC911 \uD558\uB098\uB85C \uC124\uC815\uD558\uC138\uC694.)",
|
|
229
|
+
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.)"
|
|
230
|
+
}
|
|
231
|
+
},
|
|
232
|
+
en: {
|
|
233
|
+
cli: {
|
|
234
|
+
"common.errorLabel": "Error:",
|
|
235
|
+
"common.canceled": "Operation canceled.",
|
|
236
|
+
"common.configNotFound": "Config file not found. Run `init` first.",
|
|
237
|
+
"common.docsNotFound": "docs folder not found. Run `init` first.",
|
|
238
|
+
"status.noFeatures": "No features found.",
|
|
239
|
+
"status.duplicateIds": "Duplicate Feature IDs found:",
|
|
240
|
+
"status.missingIds": "Entries missing Feature ID:",
|
|
241
|
+
"status.wrote": "\u2705 Wrote {path}",
|
|
242
|
+
"feature.selectRepo": "Select a repository:",
|
|
243
|
+
"feature.folderExists": "Folder already exists: {path}",
|
|
244
|
+
"feature.baseNotFound": "feature-base template not found.",
|
|
245
|
+
"feature.created": "\u2705 Feature folder created: {path}",
|
|
246
|
+
"feature.nextStepsTitle": "Next steps:",
|
|
247
|
+
"feature.nextSteps1": " 1. Write {path}/spec.md",
|
|
248
|
+
"feature.nextSteps2": " 2. Ask for review",
|
|
249
|
+
"feature.nextSteps3": " 3. After approval, write plan.md",
|
|
250
|
+
"config.currentTitle": "\u{1F4CB} Current config:",
|
|
251
|
+
"config.pathLabel": "Path",
|
|
252
|
+
"config.projectRootStandaloneOnly": "\u26A0\uFE0F projectRoot can only be set in standalone mode.",
|
|
253
|
+
"config.selectRepoToUpdate": "Select a repository to update:",
|
|
254
|
+
"config.fullstackRepoRequired": "For fullstack projects, you must specify `--repo fe` or `--repo be`.",
|
|
255
|
+
"config.projectRootSet": "\u2705 {repo} projectRoot set: {path}",
|
|
256
|
+
"config.projectRootSetSingle": "\u2705 projectRoot set: {path}",
|
|
257
|
+
"update.start": "\u{1F4E6} Starting template update...",
|
|
258
|
+
"update.langLabel": "Lang",
|
|
259
|
+
"update.typeLabel": "Type",
|
|
260
|
+
"update.updatingAgents": "\u{1F4C1} Updating agents/ folder...",
|
|
261
|
+
"update.updatingSkills": "\u{1F4C1} Updating agents/skills folder...",
|
|
262
|
+
"update.agentsUpdated": "agents/ updated",
|
|
263
|
+
"update.skillsUpdated": "agents/skills updated",
|
|
264
|
+
"update.updatingFeatureBase": "\u{1F4C1} Updating features/feature-base/ folder...",
|
|
265
|
+
"update.filesUpdated": "{count} files updated",
|
|
266
|
+
"update.updatedTotal": "Updated {count} files!",
|
|
267
|
+
"update.changeDetected": "changes detected (use --force to overwrite)",
|
|
268
|
+
"update.fileUpdated": "{file} updated",
|
|
269
|
+
"doctor.title": "\u{1F50E} Docs Doctor",
|
|
270
|
+
"doctor.envWarnings": "\u26A0\uFE0F Environment warnings:",
|
|
271
|
+
"doctor.noIssues": "\u2705 No issues found.",
|
|
272
|
+
"doctor.errorsTitle": "Errors",
|
|
273
|
+
"doctor.warningsTitle": "Warnings",
|
|
274
|
+
"doctor.tipJson": "Tip: Agent JSON output: npx lee-spec-kit doctor --json{strictFlag}",
|
|
275
|
+
"doctor.issue.missingRequiredDir": "Missing required directory: {dir}",
|
|
276
|
+
"doctor.issue.missingConfig": "Missing .lee-spec-kit.json. Some commands may rely on folder-structure heuristics.",
|
|
277
|
+
"doctor.issue.noFeatures": "No feature folders found. (Only feature-base exists, or no features created yet.)",
|
|
278
|
+
"doctor.issue.placeholdersLeft": "Leftover placeholders detected: {placeholders}",
|
|
279
|
+
"doctor.issue.missingSpec": "Missing spec.md.",
|
|
280
|
+
"doctor.issue.specStatusUnset": "spec.md Status is not set. (May still be a template)",
|
|
281
|
+
"doctor.issue.planStatusUnset": "plan.md Status is not set. (May still be a template)",
|
|
282
|
+
"doctor.issue.tasksEmpty": "tasks.md has no tasks.",
|
|
283
|
+
"doctor.issue.duplicateFeatureId": "Duplicate Feature ID detected: {id} ({count})",
|
|
284
|
+
"doctor.issue.missingFeatureId": "Feature folder name is not in F001-... format. (Cannot extract ID)",
|
|
285
|
+
"context.noActiveFeatures": "\u26A0\uFE0F No active features found.",
|
|
286
|
+
"context.envWarnings": "\u26A0\uFE0F Environment warnings:",
|
|
287
|
+
"context.openFallbackSummary": "(Could not detect a feature from the branch, so showing only open features. In Progress: {inProgress} / Ready To Close: {readyToClose} / Done: {done})",
|
|
288
|
+
"context.sectionInProgress": "In Progress",
|
|
289
|
+
"context.sectionReadyToClose": "Ready To Close",
|
|
290
|
+
"context.tipDetails": "Tip: To view details for a feature:",
|
|
291
|
+
"context.tipShowAll": "Show all",
|
|
292
|
+
"context.tipShowDone": "Show done only",
|
|
293
|
+
"context.okRequired": "[OK required] ",
|
|
294
|
+
"context.list.docsCommitNeeded": "Commit docs changes",
|
|
295
|
+
"context.list.issueNumberNeeded": "Fill issue number in docs",
|
|
296
|
+
"context.list.addPrMetadata": "Add PR metadata (PR/PR Status)",
|
|
297
|
+
"context.list.recordPrLink": "Record PR link",
|
|
298
|
+
"context.list.setPrStatus": "Set PR Status",
|
|
299
|
+
"context.list.prStatusToApproved": "PR Status {status} \u2192 Approved",
|
|
300
|
+
"context.list.approveSpec": "Approve spec",
|
|
301
|
+
"context.list.approvePlan": "Approve plan",
|
|
302
|
+
"init.selectLangPrompt": "Select docs language:",
|
|
303
|
+
"init.currentDirectoryLabel": "\u{1F4CD} Current directory",
|
|
304
|
+
"init.gitDetected": "\u2705 Git repository detected",
|
|
305
|
+
"init.insideProjectRoot": "You are running inside your project root.",
|
|
306
|
+
"init.modeEmbeddedDesc": "\u2022 embedded: creates ./docs here and manages it with the project.",
|
|
307
|
+
"init.modeStandaloneDesc": "\u2022 standalone: to manage docs as a separate repo,",
|
|
308
|
+
"init.modeStandaloneMove": " move to that folder and run again.",
|
|
309
|
+
"init.gitNotDetected": "\u26A0\uFE0F Git repository not detected.",
|
|
310
|
+
"init.gitNotDetectedDetail": "A new Git repo will be initialized.",
|
|
311
|
+
"init.prompt.projectName": "Enter project name:",
|
|
312
|
+
"init.prompt.projectType": "Select project type:",
|
|
313
|
+
"init.choice.projectType.single.title": "Single - single repo project",
|
|
314
|
+
"init.choice.projectType.single.desc": "Manage with a single features/ folder",
|
|
315
|
+
"init.choice.projectType.fullstack.title": "Fullstack - split FE/BE repos",
|
|
316
|
+
"init.choice.projectType.fullstack.desc": "Manage with features/be/ and features/fe/",
|
|
317
|
+
"init.prompt.docsMode": "Select docs mode:",
|
|
318
|
+
"init.choice.docsRepo.embedded.title": "embedded - inside the project (./docs)",
|
|
319
|
+
"init.choice.docsRepo.embedded.desc": "Pushed together with the project",
|
|
320
|
+
"init.choice.docsRepo.standalone.title": "standalone - separate docs repo",
|
|
321
|
+
"init.choice.docsRepo.standalone.desc": "Configure push settings separately",
|
|
322
|
+
"init.prompt.feRepoPath": "Enter frontend repository path:",
|
|
323
|
+
"init.prompt.beRepoPath": "Enter backend repository path:",
|
|
324
|
+
"init.prompt.projectRepoPath": "Enter project repository path:",
|
|
325
|
+
"init.validation.enterPath": "Please enter a path",
|
|
326
|
+
"init.prompt.pushMode": "Select docs push mode:",
|
|
327
|
+
"init.choice.push.local": "local - manage locally (no push)",
|
|
328
|
+
"init.choice.push.remote": "remote - push to remote",
|
|
329
|
+
"init.prompt.remoteUrl": "Enter remote repository URL:",
|
|
330
|
+
"init.validation.enterUrl": "Please enter a URL",
|
|
331
|
+
"init.prompt.overwrite": "{dir} already exists. Overwrite?",
|
|
332
|
+
"init.log.creatingDocs": "\u{1F4C1} Creating docs structure...",
|
|
333
|
+
"init.log.projectLabel": "Project",
|
|
334
|
+
"init.log.typeLabel": "Type",
|
|
335
|
+
"init.log.langLabel": "Lang",
|
|
336
|
+
"init.log.pathLabel": "Path",
|
|
337
|
+
"init.log.docsCreated": "\u2705 Docs structure created!",
|
|
338
|
+
"init.log.nextStepsTitle": "Next steps:",
|
|
339
|
+
"init.log.nextSteps1": " 1. Write {docsDir}/prd/README.md",
|
|
340
|
+
"init.log.nextSteps2": " 2. Add a feature with: npx lee-spec-kit feature <name>",
|
|
341
|
+
"init.log.gitRepoDetectedCommit": "\u{1F4E6} Git repo detected, committing docs...",
|
|
342
|
+
"init.log.gitInit": "\u{1F4E6} Initializing Git...",
|
|
343
|
+
"init.warn.stagedChangesSkip": '\u26A0\uFE0F There are already staged changes in the Git index. (With --dir ".", commit scope cannot be safely restricted, so auto-commit is skipped.)',
|
|
344
|
+
"init.warn.commitManually": " Review the changes and commit manually.",
|
|
345
|
+
"init.log.gitRemoteSet": "\u2705 Git remote set: {remote}",
|
|
346
|
+
"init.warn.gitRemoteExists": "\u26A0\uFE0F Git remote already exists.",
|
|
347
|
+
"init.log.gitInitialCommitDone": "\u2705 Initial Git commit created!",
|
|
348
|
+
"init.warn.skipGitInit": "\u26A0\uFE0F Skipping Git initialization (please commit manually)",
|
|
349
|
+
"init.error.templateNotFound": "Template not found: {path}"
|
|
350
|
+
},
|
|
351
|
+
steps: {
|
|
352
|
+
featureFolder: "Create feature folder",
|
|
353
|
+
specWrite: "Write spec.md",
|
|
354
|
+
specApprove: "Approve spec.md",
|
|
355
|
+
planWrite: "Write plan.md",
|
|
356
|
+
planApprove: "Approve plan.md",
|
|
357
|
+
tasksWrite: "Write tasks.md",
|
|
358
|
+
docsCommitPlanning: "Commit docs (sync)",
|
|
359
|
+
issueCreate: "Create GitHub Issue",
|
|
360
|
+
branchCreate: "Create branch",
|
|
361
|
+
tasksExecute: "Execute tasks",
|
|
362
|
+
prCreate: "Create PR",
|
|
363
|
+
codeReview: "Code review",
|
|
364
|
+
featureDone: "Feature done"
|
|
365
|
+
},
|
|
366
|
+
messages: {
|
|
367
|
+
specCreate: "Create spec.md by copying the template. (See features/feature-base/spec.md)",
|
|
368
|
+
specImprove: "Improve spec.md and change Status to Review.",
|
|
369
|
+
specApproval: "Share spec.md with the user and get approval (OK).",
|
|
370
|
+
planCreate: "Create plan.md by copying the template. (See features/feature-base/plan.md)",
|
|
371
|
+
planImprove: "Improve plan.md and change Status to Review.",
|
|
372
|
+
planApproval: "Share plan.md with the user and get approval (OK).",
|
|
373
|
+
tasksCreate: "Create tasks.md by copying the template. (See features/feature-base/tasks.md)",
|
|
374
|
+
tasksNeedAtLeastOne: "Write at least 1 task in tasks.md.",
|
|
375
|
+
docsCommitPlanning: 'cd "{docsGitCwd}" && git add "{featurePath}" && git commit -m "docs(planning): {folderName} planning docs"',
|
|
376
|
+
issueCreateAndWrite: "Create a GitHub Issue, fill the issue number in spec.md/tasks.md, then prepare a docs commit. (See skills/create-issue.md)",
|
|
377
|
+
docsCommitIssueUpdate: 'cd "{docsGitCwd}" && git add "{featurePath}" && git commit -m "docs(#{issueNumber}): {folderName} docs update"',
|
|
378
|
+
standaloneNeedsProjectRoot: "Standalone mode requires projectRoot. (npx lee-spec-kit config --project-root ...)",
|
|
379
|
+
createBranch: 'cd "{projectGitCwd}" && git checkout -b feat/{issueNumber}-{slug}',
|
|
380
|
+
tasksAllDoneButNoChecklist: 'All tasks are DONE, but no completion checklist section was found. Add/verify the "Completion Criteria" section in tasks.md.',
|
|
381
|
+
tasksAllDoneButChecklist: "All tasks are DONE, but the completion checklist is not fully checked. ({checked}/{total})",
|
|
382
|
+
finishDoingTask: 'Finish the current DOING/REVIEW task: "{title}" ({done}/{total}) (See skills/execute-task.md)',
|
|
383
|
+
startNextTodoTask: 'Start the next TODO task: "{title}" ({done}/{total}) (See skills/execute-task.md)',
|
|
384
|
+
checkTaskStatuses: "Check task statuses. ({done}/{total}) (See skills/execute-task.md)",
|
|
385
|
+
prLegacyAsk: "tasks.md is missing PR/PR Status fields. Update to the latest template format? (OK required)",
|
|
386
|
+
prCreate: "Create a PR and record the PR link in tasks.md. (See skills/create-pr.md)",
|
|
387
|
+
prFillStatus: "Set PR Status in tasks.md to Draft/Review/Approved. (After merge, update it to Approved.)",
|
|
388
|
+
prResolveReview: "Resolve review comments and update PR Status. (PR Status: Review \u2192 Approved)",
|
|
389
|
+
prRequestReview: "Request review and update PR Status to Review.",
|
|
390
|
+
featureDone: "PR is Approved and all tasks/completion criteria are satisfied. This feature is done.",
|
|
391
|
+
fallbackRerunContext: "Cannot determine status. Check the docs and run context again."
|
|
392
|
+
},
|
|
393
|
+
warnings: {
|
|
394
|
+
projectBranchUnavailable: "Cannot determine project branch. (In standalone mode, projectRoot is required.)",
|
|
395
|
+
docsGitUnavailable: "Cannot read git status for the docs repo. (Check repo location / git init.)",
|
|
396
|
+
docsUncommittedChanges: "Docs changes are not committed. (Additional docs commit needed.)",
|
|
397
|
+
legacyTasksPrFields: "Legacy tasks.md format detected. Add `PR` and `PR Status` fields before PR steps.",
|
|
398
|
+
workflowSpecNotApproved: "Implementation is done but spec.md Status is not Approved. (Update spec.md Status to Approved.)",
|
|
399
|
+
workflowPlanNotApproved: "Implementation is done but plan.md Status is not Approved. (Update plan.md Status to Approved.)",
|
|
400
|
+
workflowPrLinkMissing: "Implementation is done but PR link is missing. (Fill the PR field in tasks.md.)",
|
|
401
|
+
workflowPrStatusMissing: "Implementation is done but PR Status is missing. (Set PR Status to Draft/Review/Approved in tasks.md.)",
|
|
402
|
+
workflowPrStatusNotApproved: "Implementation is done but PR Status is not Approved. (After merge, update PR Status to Approved in tasks.md.)"
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
};
|
|
406
|
+
function tr(lang, category, key, vars = {}) {
|
|
407
|
+
const safeLang = normalizeLang(lang);
|
|
408
|
+
const template = I18N[safeLang]?.[category]?.[key] ?? I18N[DEFAULT_LANG]?.[category]?.[key] ?? I18N.ko?.[category]?.[key] ?? `${category}.${key}`;
|
|
409
|
+
return formatTemplate(template, vars);
|
|
410
|
+
}
|
|
411
|
+
|
|
46
412
|
// src/utils/validation.ts
|
|
47
413
|
var VALID_PROJECT_TYPES = ["single", "fullstack"];
|
|
48
414
|
var VALID_LANGUAGES = ["ko", "en"];
|
|
@@ -149,15 +515,19 @@ function checkGitRepo(cwd) {
|
|
|
149
515
|
}
|
|
150
516
|
}
|
|
151
517
|
function initCommand(program2) {
|
|
152
|
-
program2.command("init").description("Initialize project documentation structure").option("-n, --name <name>", "Project name (default: current folder name)").option("-t, --type <type>", "Project type: single | fullstack").option("-l, --lang <lang>", "Language: ko | en (default:
|
|
518
|
+
program2.command("init").description("Initialize project documentation structure").option("-n, --name <name>", "Project name (default: current folder name)").option("-t, --type <type>", "Project type: single | fullstack").option("-l, --lang <lang>", "Language: ko | en (default: en)").option("-d, --dir <dir>", "Target directory (default: ./docs)", "./docs").option("-y, --yes", "Skip prompts and use defaults").action(async (options) => {
|
|
153
519
|
try {
|
|
154
520
|
await runInit(options);
|
|
155
521
|
} catch (error) {
|
|
156
522
|
if (error instanceof Error && error.message === "canceled") {
|
|
157
|
-
|
|
523
|
+
const lang = options.lang ?? DEFAULT_LANG;
|
|
524
|
+
console.log(
|
|
525
|
+
chalk6.yellow(`
|
|
526
|
+
${tr(lang, "cli", "common.canceled")}`)
|
|
527
|
+
);
|
|
158
528
|
process.exit(0);
|
|
159
529
|
}
|
|
160
|
-
console.error(chalk6.red("
|
|
530
|
+
console.error(chalk6.red(tr(DEFAULT_LANG, "cli", "common.errorLabel")), error);
|
|
161
531
|
process.exit(1);
|
|
162
532
|
}
|
|
163
533
|
});
|
|
@@ -167,7 +537,7 @@ async function runInit(options) {
|
|
|
167
537
|
const defaultName = path4.basename(cwd);
|
|
168
538
|
let projectName = options.name || defaultName;
|
|
169
539
|
let projectType = options.type;
|
|
170
|
-
let lang = options.lang || "
|
|
540
|
+
let lang = options.lang || "en";
|
|
171
541
|
let docsRepo = "embedded";
|
|
172
542
|
let pushDocs;
|
|
173
543
|
let docsRemote;
|
|
@@ -175,24 +545,62 @@ async function runInit(options) {
|
|
|
175
545
|
const targetDir = path4.resolve(cwd, options.dir || "./docs");
|
|
176
546
|
const isInsideGitRepo = checkGitRepo(cwd);
|
|
177
547
|
if (!options.yes) {
|
|
548
|
+
if (!options.lang) {
|
|
549
|
+
const langResponse = await prompts(
|
|
550
|
+
[
|
|
551
|
+
{
|
|
552
|
+
type: "select",
|
|
553
|
+
name: "lang",
|
|
554
|
+
message: tr(DEFAULT_LANG, "cli", "init.selectLangPrompt"),
|
|
555
|
+
choices: [
|
|
556
|
+
{ title: "English (en)", value: "en" },
|
|
557
|
+
{ title: "\uD55C\uAD6D\uC5B4 (ko)", value: "ko" }
|
|
558
|
+
],
|
|
559
|
+
initial: 0
|
|
560
|
+
}
|
|
561
|
+
],
|
|
562
|
+
{
|
|
563
|
+
onCancel: () => {
|
|
564
|
+
throw new Error("canceled");
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
);
|
|
568
|
+
lang = langResponse.lang || lang;
|
|
569
|
+
}
|
|
178
570
|
console.log();
|
|
179
|
-
console.log(
|
|
571
|
+
console.log(
|
|
572
|
+
chalk6.blue(`${tr(lang, "cli", "init.currentDirectoryLabel")}: ${cwd}`)
|
|
573
|
+
);
|
|
180
574
|
if (isInsideGitRepo) {
|
|
181
|
-
console.log(chalk6.green("
|
|
575
|
+
console.log(chalk6.green(tr(lang, "cli", "init.gitDetected")));
|
|
182
576
|
console.log();
|
|
183
|
-
console.log(chalk6.gray("\uD604\uC7AC \uD504\uB85C\uC81D\uD2B8 \uB8E8\uD2B8 \uB0B4\uC5D0\uC11C \uC2E4\uD589\uD558\uACE0 \uACC4\uC2ED\uB2C8\uB2E4."));
|
|
184
577
|
console.log(
|
|
185
578
|
chalk6.gray(
|
|
186
|
-
"
|
|
579
|
+
tr(lang, "cli", "init.insideProjectRoot")
|
|
187
580
|
)
|
|
188
581
|
);
|
|
189
582
|
console.log(
|
|
190
|
-
chalk6.gray(
|
|
583
|
+
chalk6.gray(
|
|
584
|
+
tr(lang, "cli", "init.modeEmbeddedDesc")
|
|
585
|
+
)
|
|
586
|
+
);
|
|
587
|
+
console.log(
|
|
588
|
+
chalk6.gray(
|
|
589
|
+
tr(lang, "cli", "init.modeStandaloneDesc")
|
|
590
|
+
)
|
|
591
|
+
);
|
|
592
|
+
console.log(
|
|
593
|
+
chalk6.gray(
|
|
594
|
+
tr(lang, "cli", "init.modeStandaloneMove")
|
|
595
|
+
)
|
|
191
596
|
);
|
|
192
|
-
console.log(chalk6.gray(" \uD574\uB2F9 \uD3F4\uB354\uB85C \uC774\uB3D9 \uD6C4 \uB2E4\uC2DC \uC2E4\uD589\uD574\uC8FC\uC138\uC694."));
|
|
193
597
|
} else {
|
|
194
|
-
console.log(
|
|
195
|
-
|
|
598
|
+
console.log(
|
|
599
|
+
chalk6.yellow(
|
|
600
|
+
tr(lang, "cli", "init.gitNotDetected")
|
|
601
|
+
)
|
|
602
|
+
);
|
|
603
|
+
console.log(chalk6.gray(tr(lang, "cli", "init.gitNotDetectedDetail")));
|
|
196
604
|
}
|
|
197
605
|
console.log();
|
|
198
606
|
const response = await prompts(
|
|
@@ -200,51 +608,41 @@ async function runInit(options) {
|
|
|
200
608
|
{
|
|
201
609
|
type: options.name ? null : "text",
|
|
202
610
|
name: "projectName",
|
|
203
|
-
message: "
|
|
611
|
+
message: tr(lang, "cli", "init.prompt.projectName"),
|
|
204
612
|
initial: defaultName
|
|
205
613
|
},
|
|
206
614
|
{
|
|
207
615
|
type: options.type ? null : "select",
|
|
208
616
|
name: "projectType",
|
|
209
|
-
message: "
|
|
617
|
+
message: tr(lang, "cli", "init.prompt.projectType"),
|
|
210
618
|
choices: [
|
|
211
619
|
{
|
|
212
|
-
title: "
|
|
620
|
+
title: tr(lang, "cli", "init.choice.projectType.single.title"),
|
|
213
621
|
value: "single",
|
|
214
|
-
description: "
|
|
622
|
+
description: tr(lang, "cli", "init.choice.projectType.single.desc")
|
|
215
623
|
},
|
|
216
624
|
{
|
|
217
|
-
title: "
|
|
625
|
+
title: tr(lang, "cli", "init.choice.projectType.fullstack.title"),
|
|
218
626
|
value: "fullstack",
|
|
219
|
-
description: "
|
|
627
|
+
description: tr(lang, "cli", "init.choice.projectType.fullstack.desc")
|
|
220
628
|
}
|
|
221
629
|
],
|
|
222
630
|
initial: 0
|
|
223
631
|
},
|
|
224
|
-
{
|
|
225
|
-
type: options.lang ? null : "select",
|
|
226
|
-
name: "lang",
|
|
227
|
-
message: "\uBB38\uC11C \uC5B8\uC5B4\uB97C \uC120\uD0DD\uD558\uC138\uC694:",
|
|
228
|
-
choices: [
|
|
229
|
-
{ title: "\uD55C\uAD6D\uC5B4 (ko)", value: "ko" },
|
|
230
|
-
{ title: "English (en)", value: "en" }
|
|
231
|
-
],
|
|
232
|
-
initial: 0
|
|
233
|
-
},
|
|
234
632
|
{
|
|
235
633
|
type: "select",
|
|
236
634
|
name: "docsRepo",
|
|
237
|
-
message: "
|
|
635
|
+
message: tr(lang, "cli", "init.prompt.docsMode"),
|
|
238
636
|
choices: [
|
|
239
637
|
{
|
|
240
|
-
title: "embedded
|
|
638
|
+
title: tr(lang, "cli", "init.choice.docsRepo.embedded.title"),
|
|
241
639
|
value: "embedded",
|
|
242
|
-
description: "
|
|
640
|
+
description: tr(lang, "cli", "init.choice.docsRepo.embedded.desc")
|
|
243
641
|
},
|
|
244
642
|
{
|
|
245
|
-
title: "
|
|
643
|
+
title: tr(lang, "cli", "init.choice.docsRepo.standalone.title"),
|
|
246
644
|
value: "standalone",
|
|
247
|
-
description: "
|
|
645
|
+
description: tr(lang, "cli", "init.choice.docsRepo.standalone.desc")
|
|
248
646
|
}
|
|
249
647
|
],
|
|
250
648
|
initial: 0
|
|
@@ -258,7 +656,6 @@ async function runInit(options) {
|
|
|
258
656
|
);
|
|
259
657
|
projectName = response.projectName || projectName;
|
|
260
658
|
projectType = response.projectType || projectType;
|
|
261
|
-
lang = response.lang || lang;
|
|
262
659
|
docsRepo = response.docsRepo || "embedded";
|
|
263
660
|
if (docsRepo === "standalone") {
|
|
264
661
|
const resolvedType = projectType || response.projectType || "single";
|
|
@@ -268,14 +665,14 @@ async function runInit(options) {
|
|
|
268
665
|
{
|
|
269
666
|
type: "text",
|
|
270
667
|
name: "feRoot",
|
|
271
|
-
message: "
|
|
272
|
-
validate: (value) => value.trim() ? true : "
|
|
668
|
+
message: tr(lang, "cli", "init.prompt.feRepoPath"),
|
|
669
|
+
validate: (value) => value.trim() ? true : tr(lang, "cli", "init.validation.enterPath")
|
|
273
670
|
},
|
|
274
671
|
{
|
|
275
672
|
type: "text",
|
|
276
673
|
name: "beRoot",
|
|
277
|
-
message: "
|
|
278
|
-
validate: (value) => value.trim() ? true : "
|
|
674
|
+
message: tr(lang, "cli", "init.prompt.beRepoPath"),
|
|
675
|
+
validate: (value) => value.trim() ? true : tr(lang, "cli", "init.validation.enterPath")
|
|
279
676
|
}
|
|
280
677
|
],
|
|
281
678
|
{
|
|
@@ -294,8 +691,8 @@ async function runInit(options) {
|
|
|
294
691
|
{
|
|
295
692
|
type: "text",
|
|
296
693
|
name: "projectRoot",
|
|
297
|
-
message: "
|
|
298
|
-
validate: (value) => value.trim() ? true : "
|
|
694
|
+
message: tr(lang, "cli", "init.prompt.projectRepoPath"),
|
|
695
|
+
validate: (value) => value.trim() ? true : tr(lang, "cli", "init.validation.enterPath")
|
|
299
696
|
}
|
|
300
697
|
],
|
|
301
698
|
{
|
|
@@ -311,14 +708,14 @@ async function runInit(options) {
|
|
|
311
708
|
{
|
|
312
709
|
type: "select",
|
|
313
710
|
name: "pushDocs",
|
|
314
|
-
message: "
|
|
711
|
+
message: tr(lang, "cli", "init.prompt.pushMode"),
|
|
315
712
|
choices: [
|
|
316
713
|
{
|
|
317
|
-
title: "
|
|
714
|
+
title: tr(lang, "cli", "init.choice.push.local"),
|
|
318
715
|
value: false
|
|
319
716
|
},
|
|
320
717
|
{
|
|
321
|
-
title: "
|
|
718
|
+
title: tr(lang, "cli", "init.choice.push.remote"),
|
|
322
719
|
value: true
|
|
323
720
|
}
|
|
324
721
|
],
|
|
@@ -338,8 +735,8 @@ async function runInit(options) {
|
|
|
338
735
|
{
|
|
339
736
|
type: "text",
|
|
340
737
|
name: "docsRemote",
|
|
341
|
-
message: "
|
|
342
|
-
validate: (value) => value.trim() ? true : "
|
|
738
|
+
message: tr(lang, "cli", "init.prompt.remoteUrl"),
|
|
739
|
+
validate: (value) => value.trim() ? true : tr(lang, "cli", "init.validation.enterUrl")
|
|
343
740
|
}
|
|
344
741
|
],
|
|
345
742
|
{
|
|
@@ -364,21 +761,27 @@ async function runInit(options) {
|
|
|
364
761
|
const { overwrite } = await prompts({
|
|
365
762
|
type: "confirm",
|
|
366
763
|
name: "overwrite",
|
|
367
|
-
message:
|
|
764
|
+
message: tr(lang, "cli", "init.prompt.overwrite", { dir: targetDir }),
|
|
368
765
|
initial: false
|
|
369
766
|
});
|
|
370
767
|
if (!overwrite) {
|
|
371
|
-
console.log(chalk6.yellow("
|
|
768
|
+
console.log(chalk6.yellow(tr(lang, "cli", "common.canceled")));
|
|
372
769
|
return;
|
|
373
770
|
}
|
|
374
771
|
}
|
|
375
772
|
}
|
|
376
773
|
console.log();
|
|
377
|
-
console.log(chalk6.blue("
|
|
378
|
-
console.log(
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
console.log(
|
|
774
|
+
console.log(chalk6.blue(tr(lang, "cli", "init.log.creatingDocs")));
|
|
775
|
+
console.log(
|
|
776
|
+
chalk6.gray(` ${tr(lang, "cli", "init.log.projectLabel")}: ${projectName}`)
|
|
777
|
+
);
|
|
778
|
+
console.log(
|
|
779
|
+
chalk6.gray(` ${tr(lang, "cli", "init.log.typeLabel")}: ${projectType}`)
|
|
780
|
+
);
|
|
781
|
+
console.log(chalk6.gray(` ${tr(lang, "cli", "init.log.langLabel")}: ${lang}`));
|
|
782
|
+
console.log(
|
|
783
|
+
chalk6.gray(` ${tr(lang, "cli", "init.log.pathLabel")}: ${targetDir}`)
|
|
784
|
+
);
|
|
382
785
|
console.log();
|
|
383
786
|
const templatesDir = getTemplatesDir();
|
|
384
787
|
const commonPath = path4.join(templatesDir, lang, "common");
|
|
@@ -387,7 +790,7 @@ async function runInit(options) {
|
|
|
387
790
|
await copyTemplates(commonPath, targetDir);
|
|
388
791
|
}
|
|
389
792
|
if (!await fs8.pathExists(typePath)) {
|
|
390
|
-
throw new Error(
|
|
793
|
+
throw new Error(tr(lang, "cli", "init.error.templateNotFound", { path: typePath }));
|
|
391
794
|
}
|
|
392
795
|
await copyTemplates(typePath, targetDir);
|
|
393
796
|
const featurePath = projectType === "fullstack" ? "docs/features/{be|fe}" : "docs/features";
|
|
@@ -415,17 +818,17 @@ async function runInit(options) {
|
|
|
415
818
|
}
|
|
416
819
|
const configPath = path4.join(targetDir, ".lee-spec-kit.json");
|
|
417
820
|
await fs8.writeJson(configPath, config, { spaces: 2 });
|
|
418
|
-
console.log(chalk6.green("
|
|
821
|
+
console.log(chalk6.green(tr(lang, "cli", "init.log.docsCreated")));
|
|
419
822
|
console.log();
|
|
420
|
-
await initGit(cwd, targetDir, docsRepo, pushDocs, docsRemote);
|
|
421
|
-
console.log(chalk6.blue("
|
|
422
|
-
console.log(chalk6.gray(` 1. ${targetDir}/prd/README.md \uC791\uC131`));
|
|
823
|
+
await initGit(cwd, targetDir, docsRepo, lang, pushDocs, docsRemote);
|
|
824
|
+
console.log(chalk6.blue(tr(lang, "cli", "init.log.nextStepsTitle")));
|
|
423
825
|
console.log(
|
|
424
|
-
chalk6.gray("
|
|
826
|
+
chalk6.gray(tr(lang, "cli", "init.log.nextSteps1", { docsDir: targetDir }))
|
|
425
827
|
);
|
|
828
|
+
console.log(chalk6.gray(tr(lang, "cli", "init.log.nextSteps2")));
|
|
426
829
|
console.log();
|
|
427
830
|
}
|
|
428
|
-
async function initGit(cwd, targetDir, docsRepo, pushDocs, docsRemote) {
|
|
831
|
+
async function initGit(cwd, targetDir, docsRepo, lang, pushDocs, docsRemote) {
|
|
429
832
|
try {
|
|
430
833
|
const runGit = (args, workdir) => {
|
|
431
834
|
execFileSync("git", args, { cwd: workdir, stdio: "ignore" });
|
|
@@ -445,9 +848,9 @@ async function initGit(cwd, targetDir, docsRepo, pushDocs, docsRemote) {
|
|
|
445
848
|
};
|
|
446
849
|
try {
|
|
447
850
|
runGit(["rev-parse", "--is-inside-work-tree"], cwd);
|
|
448
|
-
console.log(chalk6.blue("
|
|
851
|
+
console.log(chalk6.blue(tr(lang, "cli", "init.log.gitRepoDetectedCommit")));
|
|
449
852
|
} catch {
|
|
450
|
-
console.log(chalk6.blue("
|
|
853
|
+
console.log(chalk6.blue(tr(lang, "cli", "init.log.gitInit")));
|
|
451
854
|
runGit(["init"], cwd);
|
|
452
855
|
}
|
|
453
856
|
const relativePath = path4.relative(cwd, targetDir);
|
|
@@ -455,10 +858,10 @@ async function initGit(cwd, targetDir, docsRepo, pushDocs, docsRemote) {
|
|
|
455
858
|
if (relativePath === "." && stagedBeforeAdd && stagedBeforeAdd.length > 0) {
|
|
456
859
|
console.log(
|
|
457
860
|
chalk6.yellow(
|
|
458
|
-
|
|
861
|
+
tr(lang, "cli", "init.warn.stagedChangesSkip")
|
|
459
862
|
)
|
|
460
863
|
);
|
|
461
|
-
console.log(chalk6.gray("
|
|
864
|
+
console.log(chalk6.gray(tr(lang, "cli", "init.warn.commitManually")));
|
|
462
865
|
console.log();
|
|
463
866
|
return;
|
|
464
867
|
}
|
|
@@ -470,16 +873,18 @@ async function initGit(cwd, targetDir, docsRepo, pushDocs, docsRemote) {
|
|
|
470
873
|
if (docsRepo === "standalone" && pushDocs && docsRemote) {
|
|
471
874
|
try {
|
|
472
875
|
runGit(["remote", "add", "origin", docsRemote], cwd);
|
|
473
|
-
console.log(
|
|
876
|
+
console.log(
|
|
877
|
+
chalk6.green(tr(lang, "cli", "init.log.gitRemoteSet", { remote: docsRemote }))
|
|
878
|
+
);
|
|
474
879
|
} catch {
|
|
475
|
-
console.log(chalk6.yellow("
|
|
880
|
+
console.log(chalk6.yellow(tr(lang, "cli", "init.warn.gitRemoteExists")));
|
|
476
881
|
}
|
|
477
882
|
}
|
|
478
|
-
console.log(chalk6.green("
|
|
883
|
+
console.log(chalk6.green(tr(lang, "cli", "init.log.gitInitialCommitDone")));
|
|
479
884
|
console.log();
|
|
480
885
|
} catch {
|
|
481
886
|
console.log(
|
|
482
|
-
chalk6.yellow(
|
|
887
|
+
chalk6.yellow(tr(lang, "cli", "init.warn.skipGitInit"))
|
|
483
888
|
);
|
|
484
889
|
console.log();
|
|
485
890
|
}
|
|
@@ -536,12 +941,10 @@ async function getConfig(cwd) {
|
|
|
536
941
|
const fePath = path4.join(featuresPath, "fe");
|
|
537
942
|
const projectType = await fs8.pathExists(bePath) || await fs8.pathExists(fePath) ? "fullstack" : "single";
|
|
538
943
|
const agentsMdPath = path4.join(agentsPath, "agents.md");
|
|
539
|
-
let lang = "
|
|
944
|
+
let lang = "en";
|
|
540
945
|
if (await fs8.pathExists(agentsMdPath)) {
|
|
541
946
|
const content = await fs8.readFile(agentsMdPath, "utf-8");
|
|
542
|
-
if (
|
|
543
|
-
lang = "en";
|
|
544
|
-
}
|
|
947
|
+
if (/[가-힣]/.test(content)) lang = "ko";
|
|
545
948
|
}
|
|
546
949
|
return { docsDir: resolvedDocsDir, projectType, lang };
|
|
547
950
|
}
|
|
@@ -557,10 +960,13 @@ function featureCommand(program2) {
|
|
|
557
960
|
await runFeature(name, options);
|
|
558
961
|
} catch (error) {
|
|
559
962
|
if (error instanceof Error && error.message === "canceled") {
|
|
560
|
-
|
|
963
|
+
const config = await getConfig(process.cwd());
|
|
964
|
+
const lang = config?.lang ?? DEFAULT_LANG;
|
|
965
|
+
console.log(chalk6.yellow(`
|
|
966
|
+
${tr(lang, "cli", "common.canceled")}`));
|
|
561
967
|
process.exit(0);
|
|
562
968
|
}
|
|
563
|
-
console.error(chalk6.red("
|
|
969
|
+
console.error(chalk6.red(tr(DEFAULT_LANG, "cli", "common.errorLabel")), error);
|
|
564
970
|
process.exit(1);
|
|
565
971
|
}
|
|
566
972
|
});
|
|
@@ -570,7 +976,9 @@ async function runFeature(name, options) {
|
|
|
570
976
|
const config = await getConfig(cwd);
|
|
571
977
|
if (!config) {
|
|
572
978
|
console.error(
|
|
573
|
-
chalk6.red(
|
|
979
|
+
chalk6.red(
|
|
980
|
+
tr(DEFAULT_LANG, "cli", "common.docsNotFound")
|
|
981
|
+
)
|
|
574
982
|
);
|
|
575
983
|
process.exit(1);
|
|
576
984
|
}
|
|
@@ -582,7 +990,7 @@ async function runFeature(name, options) {
|
|
|
582
990
|
{
|
|
583
991
|
type: "select",
|
|
584
992
|
name: "repo",
|
|
585
|
-
message: "
|
|
993
|
+
message: tr(lang, "cli", "feature.selectRepo"),
|
|
586
994
|
choices: [
|
|
587
995
|
{ title: "Backend (be)", value: "be" },
|
|
588
996
|
{ title: "Frontend (fe)", value: "fe" }
|
|
@@ -615,12 +1023,20 @@ async function runFeature(name, options) {
|
|
|
615
1023
|
const featureFolderName = `${featureId}-${name}`;
|
|
616
1024
|
const featureDir = path4.join(featuresDir, featureFolderName);
|
|
617
1025
|
if (await fs8.pathExists(featureDir)) {
|
|
618
|
-
console.error(
|
|
1026
|
+
console.error(
|
|
1027
|
+
chalk6.red(
|
|
1028
|
+
tr(lang, "cli", "feature.folderExists", { path: featureDir })
|
|
1029
|
+
)
|
|
1030
|
+
);
|
|
619
1031
|
process.exit(1);
|
|
620
1032
|
}
|
|
621
1033
|
const featureBasePath = path4.join(docsDir, "features", "feature-base");
|
|
622
1034
|
if (!await fs8.pathExists(featureBasePath)) {
|
|
623
|
-
console.error(
|
|
1035
|
+
console.error(
|
|
1036
|
+
chalk6.red(
|
|
1037
|
+
tr(lang, "cli", "feature.baseNotFound")
|
|
1038
|
+
)
|
|
1039
|
+
);
|
|
624
1040
|
process.exit(1);
|
|
625
1041
|
}
|
|
626
1042
|
await fs8.copy(featureBasePath, featureDir);
|
|
@@ -650,12 +1066,24 @@ async function runFeature(name, options) {
|
|
|
650
1066
|
}
|
|
651
1067
|
await replaceInFiles(featureDir, replacements);
|
|
652
1068
|
console.log();
|
|
653
|
-
console.log(
|
|
1069
|
+
console.log(
|
|
1070
|
+
chalk6.green(
|
|
1071
|
+
tr(lang, "cli", "feature.created", { path: featureDir })
|
|
1072
|
+
)
|
|
1073
|
+
);
|
|
654
1074
|
console.log();
|
|
655
|
-
console.log(chalk6.blue("
|
|
656
|
-
console.log(
|
|
657
|
-
|
|
658
|
-
|
|
1075
|
+
console.log(chalk6.blue(tr(lang, "cli", "feature.nextStepsTitle")));
|
|
1076
|
+
console.log(
|
|
1077
|
+
chalk6.gray(
|
|
1078
|
+
tr(lang, "cli", "feature.nextSteps1", { path: featureDir })
|
|
1079
|
+
)
|
|
1080
|
+
);
|
|
1081
|
+
console.log(chalk6.gray(tr(lang, "cli", "feature.nextSteps2")));
|
|
1082
|
+
console.log(
|
|
1083
|
+
chalk6.gray(
|
|
1084
|
+
tr(lang, "cli", "feature.nextSteps3")
|
|
1085
|
+
)
|
|
1086
|
+
);
|
|
659
1087
|
console.log();
|
|
660
1088
|
}
|
|
661
1089
|
async function getNextFeatureId(docsDir, projectType) {
|
|
@@ -685,128 +1113,6 @@ async function getNextFeatureId(docsDir, projectType) {
|
|
|
685
1113
|
return `F${String(next).padStart(width, "0")}`;
|
|
686
1114
|
}
|
|
687
1115
|
|
|
688
|
-
// src/utils/context/i18n.ts
|
|
689
|
-
function formatTemplate(template, vars) {
|
|
690
|
-
return template.replace(/\{(\w+)\}/g, (_, key) => {
|
|
691
|
-
const value = vars[key];
|
|
692
|
-
return value === void 0 ? `{${key}}` : String(value);
|
|
693
|
-
});
|
|
694
|
-
}
|
|
695
|
-
var I18N = {
|
|
696
|
-
ko: {
|
|
697
|
-
steps: {
|
|
698
|
-
featureFolder: "Feature \uD3F4\uB354 \uC0DD\uC131",
|
|
699
|
-
specWrite: "spec.md \uC791\uC131",
|
|
700
|
-
specApprove: "spec.md \uC2B9\uC778",
|
|
701
|
-
planWrite: "plan.md \uC791\uC131",
|
|
702
|
-
planApprove: "plan.md \uC2B9\uC778",
|
|
703
|
-
tasksWrite: "tasks.md \uC791\uC131",
|
|
704
|
-
docsCommitPlanning: "\uBB38\uC11C \uCEE4\uBC0B(\uB3D9\uAE30\uD654)",
|
|
705
|
-
issueCreate: "GitHub Issue \uC0DD\uC131",
|
|
706
|
-
branchCreate: "\uBE0C\uB79C\uCE58 \uC0DD\uC131",
|
|
707
|
-
tasksExecute: "\uD0DC\uC2A4\uD06C \uC2E4\uD589",
|
|
708
|
-
prCreate: "PR \uC0DD\uC131",
|
|
709
|
-
codeReview: "\uCF54\uB4DC \uB9AC\uBDF0",
|
|
710
|
-
featureDone: "Feature \uC644\uB8CC"
|
|
711
|
-
},
|
|
712
|
-
messages: {
|
|
713
|
-
specCreate: "spec.md \uD15C\uD50C\uB9BF\uC744 \uBCF5\uC0AC\uD574 \uC791\uC131\uD558\uC138\uC694. (features/feature-base/spec.md \uCC38\uACE0)",
|
|
714
|
-
specImprove: "spec.md\uB97C \uBCF4\uC644\uD558\uACE0 \uC0C1\uD0DC\uB97C Review\uB85C \uBCC0\uACBD\uD558\uC138\uC694.",
|
|
715
|
-
specApproval: "spec.md \uB0B4\uC6A9\uC744 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uACF5\uC720\uD558\uACE0 \uC2B9\uC778(OK)\uC744 \uBC1B\uC73C\uC138\uC694.",
|
|
716
|
-
planCreate: "plan.md \uD15C\uD50C\uB9BF\uC744 \uBCF5\uC0AC\uD574 \uC791\uC131\uD558\uC138\uC694. (features/feature-base/plan.md \uCC38\uACE0)",
|
|
717
|
-
planImprove: "plan.md\uB97C \uBCF4\uC644\uD558\uACE0 \uC0C1\uD0DC\uB97C Review\uB85C \uBCC0\uACBD\uD558\uC138\uC694.",
|
|
718
|
-
planApproval: "plan.md \uB0B4\uC6A9\uC744 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uACF5\uC720\uD558\uACE0 \uC2B9\uC778(OK)\uC744 \uBC1B\uC73C\uC138\uC694.",
|
|
719
|
-
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)",
|
|
720
|
-
tasksNeedAtLeastOne: "tasks.md\uC5D0 \uCD5C\uC18C 1\uAC1C \uC774\uC0C1\uC758 \uD0DC\uC2A4\uD06C\uB97C \uC791\uC131\uD558\uC138\uC694.",
|
|
721
|
-
docsCommitPlanning: 'cd "{docsGitCwd}" && git add "{featurePath}" && git commit -m "docs(planning): {folderName} \uAE30\uD68D \uBB38\uC11C"',
|
|
722
|
-
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)",
|
|
723
|
-
docsCommitIssueUpdate: 'cd "{docsGitCwd}" && git add "{featurePath}" && git commit -m "docs(#{issueNumber}): {folderName} \uBB38\uC11C \uC5C5\uB370\uC774\uD2B8"',
|
|
724
|
-
standaloneNeedsProjectRoot: "standalone \uBAA8\uB4DC\uC5D0\uC11C\uB294 projectRoot \uC124\uC815\uC774 \uD544\uC694\uD569\uB2C8\uB2E4. (npx lee-spec-kit config --project-root ...)",
|
|
725
|
-
createBranch: 'cd "{projectGitCwd}" && git checkout -b feat/{issueNumber}-{slug}',
|
|
726
|
-
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.',
|
|
727
|
-
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})",
|
|
728
|
-
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)',
|
|
729
|
-
startNextTodoTask: '\uB2E4\uC74C TODO \uD0DC\uC2A4\uD06C\uB97C \uC2DC\uC791\uD558\uC138\uC694: "{title}" ({done}/{total}) (skills/execute-task.md \uCC38\uACE0)',
|
|
730
|
-
checkTaskStatuses: "\uD0DC\uC2A4\uD06C \uC0C1\uD0DC\uB97C \uD655\uC778\uD558\uC138\uC694. ({done}/{total}) (skills/execute-task.md \uCC38\uACE0)",
|
|
731
|
-
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? (OK \uD544\uC694)",
|
|
732
|
-
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)",
|
|
733
|
-
prFillStatus: "tasks.md\uC758 PR \uC0C1\uD0DC\uB97C Draft/Review/Approved \uC911 \uD558\uB098\uB85C \uC124\uC815\uD558\uC138\uC694. (merge \uD6C4 Approved\uB85C \uC5C5\uB370\uC774\uD2B8)",
|
|
734
|
-
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)",
|
|
735
|
-
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.",
|
|
736
|
-
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.",
|
|
737
|
-
fallbackRerunContext: "\uC0C1\uD0DC\uB97C \uD310\uBCC4\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uBB38\uC11C\uB97C \uD655\uC778\uD55C \uB4A4 \uB2E4\uC2DC context\uB97C \uC2E4\uD589\uD558\uC138\uC694."
|
|
738
|
-
},
|
|
739
|
-
warnings: {
|
|
740
|
-
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.)",
|
|
741
|
-
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)",
|
|
742
|
-
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.",
|
|
743
|
-
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.)",
|
|
744
|
-
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.)",
|
|
745
|
-
workflowPrLinkMissing: "\uC644\uB8CC \uC0C1\uD0DC\uC774\uC9C0\uB9CC PR \uB9C1\uD06C\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. (tasks.md\uC758 PR \uD544\uB4DC\uB97C \uCC44\uC6B0\uC138\uC694.)",
|
|
746
|
-
workflowPrStatusMissing: "\uC644\uB8CC \uC0C1\uD0DC\uC774\uC9C0\uB9CC PR \uC0C1\uD0DC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. (tasks.md\uC758 PR \uC0C1\uD0DC\uB97C Draft/Review/Approved \uC911 \uD558\uB098\uB85C \uC124\uC815\uD558\uC138\uC694.)",
|
|
747
|
-
workflowPrStatusNotApproved: "\uC644\uB8CC \uC0C1\uD0DC\uC774\uC9C0\uB9CC PR \uC0C1\uD0DC\uAC00 Approved\uAC00 \uC544\uB2D9\uB2C8\uB2E4. (merge \uD6C4 tasks.md\uC758 PR \uC0C1\uD0DC\uB97C Approved\uB85C \uC5C5\uB370\uC774\uD2B8\uD558\uC138\uC694.)"
|
|
748
|
-
}
|
|
749
|
-
},
|
|
750
|
-
en: {
|
|
751
|
-
steps: {
|
|
752
|
-
featureFolder: "Create feature folder",
|
|
753
|
-
specWrite: "Write spec.md",
|
|
754
|
-
specApprove: "Approve spec.md",
|
|
755
|
-
planWrite: "Write plan.md",
|
|
756
|
-
planApprove: "Approve plan.md",
|
|
757
|
-
tasksWrite: "Write tasks.md",
|
|
758
|
-
docsCommitPlanning: "Commit docs (sync)",
|
|
759
|
-
issueCreate: "Create GitHub Issue",
|
|
760
|
-
branchCreate: "Create branch",
|
|
761
|
-
tasksExecute: "Execute tasks",
|
|
762
|
-
prCreate: "Create PR",
|
|
763
|
-
codeReview: "Code review",
|
|
764
|
-
featureDone: "Feature done"
|
|
765
|
-
},
|
|
766
|
-
messages: {
|
|
767
|
-
specCreate: "Copy the spec.md template and write it. (See features/feature-base/spec.md)",
|
|
768
|
-
specImprove: "Improve spec.md and set Status to Review.",
|
|
769
|
-
specApproval: "Share spec.md with the user and get approval (OK).",
|
|
770
|
-
planCreate: "Copy the plan.md template and write it. (See features/feature-base/plan.md)",
|
|
771
|
-
planImprove: "Improve plan.md and set Status to Review.",
|
|
772
|
-
planApproval: "Share plan.md with the user and get approval (OK).",
|
|
773
|
-
tasksCreate: "Copy the tasks.md template and write tasks. (See features/feature-base/tasks.md)",
|
|
774
|
-
tasksNeedAtLeastOne: "Add at least one task to tasks.md.",
|
|
775
|
-
docsCommitPlanning: 'cd "{docsGitCwd}" && git add "{featurePath}" && git commit -m "docs(planning): {folderName} planning docs"',
|
|
776
|
-
issueCreateAndWrite: "Create a GitHub Issue, then fill in the issue number in spec.md/tasks.md and prepare to commit docs. (See skills/create-issue.md)",
|
|
777
|
-
docsCommitIssueUpdate: 'cd "{docsGitCwd}" && git add "{featurePath}" && git commit -m "docs(#{issueNumber}): {folderName} docs update"',
|
|
778
|
-
standaloneNeedsProjectRoot: "In standalone mode, projectRoot is required. (npx lee-spec-kit config --project-root ...)",
|
|
779
|
-
createBranch: 'cd "{projectGitCwd}" && git checkout -b feat/{issueNumber}-{slug}',
|
|
780
|
-
tasksAllDoneButNoChecklist: 'All tasks are DONE but no completion checklist section was found. Add/verify the "Completion Criteria" section in tasks.md.',
|
|
781
|
-
tasksAllDoneButChecklist: "All tasks are DONE but the completion checklist is not fully checked. ({checked}/{total})",
|
|
782
|
-
finishDoingTask: 'Finish the active DOING/REVIEW task: "{title}" ({done}/{total}) (See skills/execute-task.md)',
|
|
783
|
-
startNextTodoTask: 'Start the next TODO task: "{title}" ({done}/{total}) (See skills/execute-task.md)',
|
|
784
|
-
checkTaskStatuses: "Check task statuses. ({done}/{total}) (See skills/execute-task.md)",
|
|
785
|
-
prLegacyAsk: "Legacy tasks.md format detected (missing PR/PR Status fields). Update to the latest format? (OK required)",
|
|
786
|
-
prCreate: "Create a PR and record the PR link in tasks.md. (See skills/create-pr.md)",
|
|
787
|
-
prFillStatus: "Set PR Status in tasks.md to Draft/Review/Approved. (After merge, update to Approved)",
|
|
788
|
-
prResolveReview: "Resolve review comments and update PR status. (PR Status: Review \u2192 Approved)",
|
|
789
|
-
prRequestReview: "Request reviews and update PR status to Review.",
|
|
790
|
-
featureDone: "PR is Approved and all tasks/completion criteria are satisfied. This feature is done.",
|
|
791
|
-
fallbackRerunContext: "Unable to determine current state. Verify docs and run context again."
|
|
792
|
-
},
|
|
793
|
-
warnings: {
|
|
794
|
-
projectBranchUnavailable: "Cannot determine project branch. (In standalone mode, projectRoot is required.)",
|
|
795
|
-
docsGitUnavailable: "Cannot read git status for the docs repo. (Check repo location / git init.)",
|
|
796
|
-
legacyTasksPrFields: "Legacy tasks.md format detected. Add `PR` and `PR Status` fields before PR steps.",
|
|
797
|
-
workflowSpecNotApproved: "Implementation is done but spec.md Status is not Approved. (Update spec.md Status to Approved.)",
|
|
798
|
-
workflowPlanNotApproved: "Implementation is done but plan.md Status is not Approved. (Update plan.md Status to Approved.)",
|
|
799
|
-
workflowPrLinkMissing: "Implementation is done but PR link is missing. (Fill the PR field in tasks.md.)",
|
|
800
|
-
workflowPrStatusMissing: "Implementation is done but PR Status is missing. (Set PR Status to Draft/Review/Approved in tasks.md.)",
|
|
801
|
-
workflowPrStatusNotApproved: "Implementation is done but PR Status is not Approved. (After merge, update PR Status to Approved in tasks.md.)"
|
|
802
|
-
}
|
|
803
|
-
}
|
|
804
|
-
};
|
|
805
|
-
function tr(lang, category, key, vars = {}) {
|
|
806
|
-
const template = I18N[lang][category][key] ?? I18N.ko[category][key] ?? `${category}.${key}`;
|
|
807
|
-
return formatTemplate(template, vars);
|
|
808
|
-
}
|
|
809
|
-
|
|
810
1116
|
// src/utils/context/steps.ts
|
|
811
1117
|
function isCompletionChecklistDone(feature) {
|
|
812
1118
|
return !!feature.completionChecklist && feature.completionChecklist.total > 0 && feature.completionChecklist.checked === feature.completionChecklist.total;
|
|
@@ -893,21 +1199,12 @@ function getStepDefinitions(lang) {
|
|
|
893
1199
|
step: 6,
|
|
894
1200
|
name: tr(lang, "steps", "tasksWrite"),
|
|
895
1201
|
checklist: {
|
|
896
|
-
done: (f) => f.docs.tasksExists && f.tasks.total > 0
|
|
1202
|
+
done: (f) => f.docs.tasksExists && f.tasks.total > 0,
|
|
897
1203
|
detail: (f) => f.tasks.total > 0 ? `(${f.tasks.total})` : ""
|
|
898
1204
|
},
|
|
899
1205
|
current: {
|
|
900
|
-
when: (f) => f.planStatus === "Approved" && (!f.docs.tasksExists || f.tasks.total === 0
|
|
1206
|
+
when: (f) => f.planStatus === "Approved" && (!f.docs.tasksExists || f.tasks.total === 0),
|
|
901
1207
|
actions: (f) => {
|
|
902
|
-
if (f.docs.tasksExists && f.tasks.total > 0 && (!f.docs.prFieldExists || !f.docs.prStatusFieldExists)) {
|
|
903
|
-
return [
|
|
904
|
-
{
|
|
905
|
-
type: "instruction",
|
|
906
|
-
requiresUserOk: true,
|
|
907
|
-
message: tr(lang, "messages", "prLegacyAsk")
|
|
908
|
-
}
|
|
909
|
-
];
|
|
910
|
-
}
|
|
911
1208
|
if (!f.docs.tasksExists) {
|
|
912
1209
|
return [
|
|
913
1210
|
{
|
|
@@ -929,10 +1226,10 @@ function getStepDefinitions(lang) {
|
|
|
929
1226
|
step: 7,
|
|
930
1227
|
name: tr(lang, "steps", "docsCommitPlanning"),
|
|
931
1228
|
checklist: {
|
|
932
|
-
done: (f) => f.docs.tasksExists && f.tasks.total > 0 && f.specStatus === "Approved" && f.planStatus === "Approved" &&
|
|
1229
|
+
done: (f) => f.docs.tasksExists && f.tasks.total > 0 && f.specStatus === "Approved" && f.planStatus === "Approved" && f.git.docsEverCommitted
|
|
933
1230
|
},
|
|
934
1231
|
current: {
|
|
935
|
-
when: (f) => f.docs.tasksExists && f.tasks.total > 0 && f.specStatus === "Approved" && f.planStatus === "Approved" && !f.activeTask && f.git.docsHasUncommittedChanges,
|
|
1232
|
+
when: (f) => f.docs.tasksExists && f.tasks.total > 0 && f.specStatus === "Approved" && f.planStatus === "Approved" && !f.activeTask && !f.git.docsEverCommitted && f.git.docsHasUncommittedChanges,
|
|
936
1233
|
actions: (f) => {
|
|
937
1234
|
if (f.issueNumber) {
|
|
938
1235
|
return [
|
|
@@ -988,9 +1285,9 @@ function getStepDefinitions(lang) {
|
|
|
988
1285
|
{
|
|
989
1286
|
step: 9,
|
|
990
1287
|
name: tr(lang, "steps", "branchCreate"),
|
|
991
|
-
checklist: { done: (f) => f.git.onExpectedBranch },
|
|
1288
|
+
checklist: { done: (f) => f.git.onExpectedBranch || isImplementationDone(f) || isFeatureDone(f) },
|
|
992
1289
|
current: {
|
|
993
|
-
when: (f) => !!f.issueNumber &&
|
|
1290
|
+
when: (f) => !!f.issueNumber && f.tasks.total > 0 && f.tasks.done < f.tasks.total && !isFeatureDone(f) && (!f.git.projectBranchAvailable || !f.git.onExpectedBranch),
|
|
994
1291
|
actions: (f) => {
|
|
995
1292
|
if (!f.git.projectBranchAvailable || !f.git.projectGitCwd) {
|
|
996
1293
|
return [
|
|
@@ -1023,10 +1320,10 @@ function getStepDefinitions(lang) {
|
|
|
1023
1320
|
detail: (f) => f.tasks.total > 0 ? `(${f.tasks.done}/${f.tasks.total})` : ""
|
|
1024
1321
|
},
|
|
1025
1322
|
current: {
|
|
1026
|
-
when: (f) => f.
|
|
1323
|
+
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),
|
|
1027
1324
|
actions: (f) => {
|
|
1028
1325
|
if (f.tasks.total === f.tasks.done && !isCompletionChecklistDone(f)) {
|
|
1029
|
-
|
|
1326
|
+
const actions = [
|
|
1030
1327
|
{
|
|
1031
1328
|
type: "instruction",
|
|
1032
1329
|
requiresUserOk: true,
|
|
@@ -1036,6 +1333,14 @@ function getStepDefinitions(lang) {
|
|
|
1036
1333
|
})
|
|
1037
1334
|
}
|
|
1038
1335
|
];
|
|
1336
|
+
if (!isPrMetadataConfigured(f)) {
|
|
1337
|
+
actions.push({
|
|
1338
|
+
type: "instruction",
|
|
1339
|
+
requiresUserOk: true,
|
|
1340
|
+
message: tr(lang, "messages", "prLegacyAsk")
|
|
1341
|
+
});
|
|
1342
|
+
}
|
|
1343
|
+
return actions;
|
|
1039
1344
|
}
|
|
1040
1345
|
if (f.activeTask) {
|
|
1041
1346
|
return [
|
|
@@ -1208,6 +1513,18 @@ function getGitStatusPorcelain(cwd, relativePaths) {
|
|
|
1208
1513
|
return void 0;
|
|
1209
1514
|
}
|
|
1210
1515
|
}
|
|
1516
|
+
function getLastCommitForPath(cwd, relativePath) {
|
|
1517
|
+
try {
|
|
1518
|
+
const out = execSync(`git rev-list -n 1 HEAD -- "${relativePath}"`, {
|
|
1519
|
+
cwd,
|
|
1520
|
+
encoding: "utf-8",
|
|
1521
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
1522
|
+
}).trim();
|
|
1523
|
+
return out || void 0;
|
|
1524
|
+
} catch {
|
|
1525
|
+
return void 0;
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1211
1528
|
function getGitTopLevel(cwd) {
|
|
1212
1529
|
try {
|
|
1213
1530
|
return execSync("git rev-parse --show-toplevel", {
|
|
@@ -1420,12 +1737,20 @@ async function parseFeature(featurePath, type, context, options) {
|
|
|
1420
1737
|
const relativeFeaturePathFromDocs = path4.relative(context.docsDir, featurePath);
|
|
1421
1738
|
const docsStatus = getGitStatusPorcelain(context.docsGitCwd, [relativeFeaturePathFromDocs]);
|
|
1422
1739
|
const docsHasUncommittedChanges = docsStatus === void 0 ? true : docsStatus.trim().length > 0;
|
|
1740
|
+
const docsLastCommit = getLastCommitForPath(
|
|
1741
|
+
context.docsGitCwd,
|
|
1742
|
+
relativeFeaturePathFromDocs
|
|
1743
|
+
);
|
|
1744
|
+
const docsEverCommitted = !!docsLastCommit;
|
|
1423
1745
|
if (docsStatus === void 0) {
|
|
1424
1746
|
warnings.push(tr(lang, "warnings", "docsGitUnavailable"));
|
|
1425
1747
|
}
|
|
1426
1748
|
if (tasksExists && (!prFieldExists || !prStatusFieldExists)) {
|
|
1427
1749
|
warnings.push(tr(lang, "warnings", "legacyTasksPrFields"));
|
|
1428
1750
|
}
|
|
1751
|
+
if (docsEverCommitted && docsHasUncommittedChanges) {
|
|
1752
|
+
warnings.push(tr(lang, "warnings", "docsUncommittedChanges"));
|
|
1753
|
+
}
|
|
1429
1754
|
const implementationDone = tasksExists && tasksSummary.total > 0 && tasksSummary.total === tasksSummary.done && isCompletionChecklistDone2({ completionChecklist });
|
|
1430
1755
|
const workflowDone = implementationDone && specStatus === "Approved" && planStatus === "Approved" && isPrMetadataConfigured2({ docs: { prFieldExists, prStatusFieldExists } }) && !!prLink && prStatus === "Approved";
|
|
1431
1756
|
if (implementationDone && !workflowDone) {
|
|
@@ -1468,6 +1793,7 @@ async function parseFeature(featurePath, type, context, options) {
|
|
|
1468
1793
|
docsGitCwd: context.docsGitCwd,
|
|
1469
1794
|
projectGitCwd: context.projectGitCwd,
|
|
1470
1795
|
onExpectedBranch,
|
|
1796
|
+
docsEverCommitted,
|
|
1471
1797
|
docsHasUncommittedChanges
|
|
1472
1798
|
},
|
|
1473
1799
|
docs: {
|
|
@@ -1594,7 +1920,7 @@ function statusCommand(program2) {
|
|
|
1594
1920
|
try {
|
|
1595
1921
|
await runStatus(options);
|
|
1596
1922
|
} catch (error) {
|
|
1597
|
-
console.error(chalk6.red("
|
|
1923
|
+
console.error(chalk6.red(tr(DEFAULT_LANG, "cli", "common.errorLabel")), error);
|
|
1598
1924
|
process.exit(1);
|
|
1599
1925
|
}
|
|
1600
1926
|
});
|
|
@@ -1603,12 +1929,15 @@ async function runStatus(options) {
|
|
|
1603
1929
|
const cwd = process.cwd();
|
|
1604
1930
|
const config = await getConfig(cwd);
|
|
1605
1931
|
if (!config) {
|
|
1932
|
+
console.error(chalk6.red(tr(DEFAULT_LANG, "cli", "common.errorLabel")));
|
|
1606
1933
|
console.error(
|
|
1607
|
-
chalk6.red(
|
|
1934
|
+
chalk6.red(
|
|
1935
|
+
tr(DEFAULT_LANG, "cli", "common.docsNotFound")
|
|
1936
|
+
)
|
|
1608
1937
|
);
|
|
1609
1938
|
process.exit(1);
|
|
1610
1939
|
}
|
|
1611
|
-
const { docsDir, projectType, projectName } = config;
|
|
1940
|
+
const { docsDir, projectType, projectName, lang } = config;
|
|
1612
1941
|
const featuresDir = path4.join(docsDir, "features");
|
|
1613
1942
|
const scan = await scanFeatures(config);
|
|
1614
1943
|
const features = [];
|
|
@@ -1645,7 +1974,7 @@ async function runStatus(options) {
|
|
|
1645
1974
|
});
|
|
1646
1975
|
}
|
|
1647
1976
|
if (features.length === 0) {
|
|
1648
|
-
console.log(chalk6.yellow("
|
|
1977
|
+
console.log(chalk6.yellow(tr(lang, "cli", "status.noFeatures")));
|
|
1649
1978
|
return;
|
|
1650
1979
|
}
|
|
1651
1980
|
if (options.strict) {
|
|
@@ -1653,7 +1982,7 @@ async function runStatus(options) {
|
|
|
1653
1982
|
([, paths]) => paths.length > 1
|
|
1654
1983
|
);
|
|
1655
1984
|
if (duplicates.length > 0) {
|
|
1656
|
-
console.error(chalk6.red("
|
|
1985
|
+
console.error(chalk6.red(tr(lang, "cli", "status.duplicateIds")));
|
|
1657
1986
|
for (const [id, paths] of duplicates) {
|
|
1658
1987
|
console.error(chalk6.red(` ${id}:`));
|
|
1659
1988
|
for (const p of paths) {
|
|
@@ -1664,7 +1993,7 @@ async function runStatus(options) {
|
|
|
1664
1993
|
}
|
|
1665
1994
|
const unknowns = [...idMap.entries()].filter(([id]) => id === "UNKNOWN");
|
|
1666
1995
|
if (unknowns.length > 0) {
|
|
1667
|
-
console.error(chalk6.red("
|
|
1996
|
+
console.error(chalk6.red(tr(lang, "cli", "status.missingIds")));
|
|
1668
1997
|
for (const [, paths] of unknowns) {
|
|
1669
1998
|
for (const p of paths) {
|
|
1670
1999
|
console.error(chalk6.red(` - ${p}`));
|
|
@@ -1703,7 +2032,11 @@ async function runStatus(options) {
|
|
|
1703
2032
|
""
|
|
1704
2033
|
].join("\n");
|
|
1705
2034
|
await fs8.writeFile(outputPath, content, "utf-8");
|
|
1706
|
-
console.log(
|
|
2035
|
+
console.log(
|
|
2036
|
+
chalk6.green(
|
|
2037
|
+
tr(lang, "cli", "status.wrote", { path: outputPath })
|
|
2038
|
+
)
|
|
2039
|
+
);
|
|
1707
2040
|
}
|
|
1708
2041
|
}
|
|
1709
2042
|
function escapeRegExp2(value) {
|
|
@@ -1729,15 +2062,18 @@ async function getFeatureNameFromSpec(featureDir, fallbackSlug, fallbackFolderNa
|
|
|
1729
2062
|
return fallbackSlug || fallbackFolderName;
|
|
1730
2063
|
}
|
|
1731
2064
|
function updateCommand(program2) {
|
|
1732
|
-
program2.command("update").description("Update docs templates to the latest version").option("--agents", "Update agents/ folder only").option("--templates", "Update feature-base/ folder only").option("-f, --force", "Force overwrite without confirmation").action(async (options) => {
|
|
2065
|
+
program2.command("update").description("Update docs templates to the latest version").option("--agents", "Update agents/ folder only").option("--skills", "Update agents/skills folder only").option("--templates", "Update feature-base/ folder only").option("-f, --force", "Force overwrite without confirmation").action(async (options) => {
|
|
1733
2066
|
try {
|
|
1734
2067
|
await runUpdate(options);
|
|
1735
2068
|
} catch (error) {
|
|
1736
2069
|
if (error instanceof Error && error.message === "canceled") {
|
|
1737
|
-
|
|
2070
|
+
const config = await getConfig(process.cwd());
|
|
2071
|
+
const lang = config?.lang ?? DEFAULT_LANG;
|
|
2072
|
+
console.log(chalk6.yellow(`
|
|
2073
|
+
${tr(lang, "cli", "common.canceled")}`));
|
|
1738
2074
|
process.exit(0);
|
|
1739
2075
|
}
|
|
1740
|
-
console.error(chalk6.red("
|
|
2076
|
+
console.error(chalk6.red(tr(DEFAULT_LANG, "cli", "common.errorLabel")), error);
|
|
1741
2077
|
process.exit(1);
|
|
1742
2078
|
}
|
|
1743
2079
|
});
|
|
@@ -1746,26 +2082,40 @@ async function runUpdate(options) {
|
|
|
1746
2082
|
const cwd = process.cwd();
|
|
1747
2083
|
const config = await getConfig(cwd);
|
|
1748
2084
|
if (!config) {
|
|
2085
|
+
console.error(chalk6.red(tr(DEFAULT_LANG, "cli", "common.errorLabel")));
|
|
1749
2086
|
console.error(
|
|
1750
|
-
chalk6.red(
|
|
2087
|
+
chalk6.red(
|
|
2088
|
+
tr(DEFAULT_LANG, "cli", "common.docsNotFound")
|
|
2089
|
+
)
|
|
1751
2090
|
);
|
|
1752
2091
|
process.exit(1);
|
|
1753
2092
|
}
|
|
1754
2093
|
const { docsDir, projectType, lang } = config;
|
|
1755
2094
|
const templatesDir = getTemplatesDir();
|
|
1756
2095
|
const sourceDir = path4.join(templatesDir, lang, projectType);
|
|
1757
|
-
const
|
|
1758
|
-
const
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
console.log(chalk6.
|
|
2096
|
+
const hasExplicitSelection = !!(options.agents || options.skills || options.templates);
|
|
2097
|
+
const updateAgents = options.agents || options.skills || !hasExplicitSelection;
|
|
2098
|
+
const updateTemplates = options.templates || !hasExplicitSelection;
|
|
2099
|
+
const agentsMode = options.skills && !options.agents ? "skills" : "all";
|
|
2100
|
+
console.log(chalk6.blue(tr(lang, "cli", "update.start")));
|
|
2101
|
+
console.log(chalk6.gray(` - ${tr(lang, "cli", "update.langLabel")}: ${lang}`));
|
|
2102
|
+
console.log(
|
|
2103
|
+
chalk6.gray(` - ${tr(lang, "cli", "update.typeLabel")}: ${projectType}`)
|
|
2104
|
+
);
|
|
1762
2105
|
console.log();
|
|
1763
2106
|
let updatedCount = 0;
|
|
1764
2107
|
if (updateAgents) {
|
|
1765
|
-
console.log(
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
2108
|
+
console.log(
|
|
2109
|
+
chalk6.blue(
|
|
2110
|
+
agentsMode === "skills" ? tr(lang, "cli", "update.updatingSkills") : tr(lang, "cli", "update.updatingAgents")
|
|
2111
|
+
)
|
|
2112
|
+
);
|
|
2113
|
+
const commonAgentsBase = path4.join(templatesDir, lang, "common", "agents");
|
|
2114
|
+
const typeAgentsBase = path4.join(templatesDir, lang, projectType, "agents");
|
|
2115
|
+
const targetAgentsBase = path4.join(docsDir, "agents");
|
|
2116
|
+
const commonAgents = agentsMode === "skills" ? path4.join(commonAgentsBase, "skills") : commonAgentsBase;
|
|
2117
|
+
const typeAgents = agentsMode === "skills" ? path4.join(typeAgentsBase, "skills") : typeAgentsBase;
|
|
2118
|
+
const targetAgents = agentsMode === "skills" ? path4.join(targetAgentsBase, "skills") : targetAgentsBase;
|
|
1769
2119
|
const featurePath = projectType === "fullstack" ? "docs/features/{be|fe}" : "docs/features";
|
|
1770
2120
|
const replacements = {
|
|
1771
2121
|
"{{featurePath}}": featurePath
|
|
@@ -1775,34 +2125,55 @@ async function runUpdate(options) {
|
|
|
1775
2125
|
commonAgents,
|
|
1776
2126
|
targetAgents,
|
|
1777
2127
|
options.force,
|
|
1778
|
-
replacements
|
|
2128
|
+
replacements,
|
|
2129
|
+
lang
|
|
1779
2130
|
);
|
|
1780
2131
|
updatedCount += count;
|
|
1781
2132
|
}
|
|
1782
2133
|
if (await fs8.pathExists(typeAgents)) {
|
|
1783
|
-
const count = await updateFolder(
|
|
2134
|
+
const count = await updateFolder(
|
|
2135
|
+
typeAgents,
|
|
2136
|
+
targetAgents,
|
|
2137
|
+
options.force,
|
|
2138
|
+
void 0,
|
|
2139
|
+
lang
|
|
2140
|
+
);
|
|
1784
2141
|
updatedCount += count;
|
|
1785
2142
|
}
|
|
1786
|
-
console.log(
|
|
2143
|
+
console.log(
|
|
2144
|
+
chalk6.green(
|
|
2145
|
+
` \u2705 ${agentsMode === "skills" ? tr(lang, "cli", "update.skillsUpdated") : tr(lang, "cli", "update.agentsUpdated")}`
|
|
2146
|
+
)
|
|
2147
|
+
);
|
|
1787
2148
|
}
|
|
1788
2149
|
if (updateTemplates) {
|
|
1789
|
-
console.log(chalk6.blue("
|
|
2150
|
+
console.log(chalk6.blue(tr(lang, "cli", "update.updatingFeatureBase")));
|
|
1790
2151
|
const sourceFeatureBase = path4.join(sourceDir, "features", "feature-base");
|
|
1791
2152
|
const targetFeatureBase = path4.join(docsDir, "features", "feature-base");
|
|
1792
2153
|
if (await fs8.pathExists(sourceFeatureBase)) {
|
|
1793
2154
|
const count = await updateFolder(
|
|
1794
2155
|
sourceFeatureBase,
|
|
1795
2156
|
targetFeatureBase,
|
|
1796
|
-
options.force
|
|
2157
|
+
options.force,
|
|
2158
|
+
void 0,
|
|
2159
|
+
lang
|
|
1797
2160
|
);
|
|
1798
2161
|
updatedCount += count;
|
|
1799
|
-
console.log(
|
|
2162
|
+
console.log(
|
|
2163
|
+
chalk6.green(
|
|
2164
|
+
` \u2705 ${tr(lang, "cli", "update.filesUpdated", { count })}`
|
|
2165
|
+
)
|
|
2166
|
+
);
|
|
1800
2167
|
}
|
|
1801
2168
|
}
|
|
1802
2169
|
console.log();
|
|
1803
|
-
console.log(
|
|
2170
|
+
console.log(
|
|
2171
|
+
chalk6.green(
|
|
2172
|
+
`\u2705 ${tr(lang, "cli", "update.updatedTotal", { count: updatedCount })}`
|
|
2173
|
+
)
|
|
2174
|
+
);
|
|
1804
2175
|
}
|
|
1805
|
-
async function updateFolder(sourceDir, targetDir, force, replacements) {
|
|
2176
|
+
async function updateFolder(sourceDir, targetDir, force, replacements, lang = DEFAULT_LANG) {
|
|
1806
2177
|
const protectedFiles = /* @__PURE__ */ new Set(["custom.md", "constitution.md"]);
|
|
1807
2178
|
await fs8.ensureDir(targetDir);
|
|
1808
2179
|
const files = await fs8.readdir(sourceDir);
|
|
@@ -1829,14 +2200,18 @@ async function updateFolder(sourceDir, targetDir, force, replacements) {
|
|
|
1829
2200
|
}
|
|
1830
2201
|
if (!force) {
|
|
1831
2202
|
console.log(
|
|
1832
|
-
chalk6.yellow(
|
|
2203
|
+
chalk6.yellow(
|
|
2204
|
+
` \u26A0\uFE0F ${file} - ${tr(lang, "cli", "update.changeDetected")}`
|
|
2205
|
+
)
|
|
1833
2206
|
);
|
|
1834
2207
|
shouldUpdate = false;
|
|
1835
2208
|
}
|
|
1836
2209
|
}
|
|
1837
2210
|
if (shouldUpdate) {
|
|
1838
2211
|
await fs8.writeFile(targetPath, sourceContent);
|
|
1839
|
-
console.log(
|
|
2212
|
+
console.log(
|
|
2213
|
+
chalk6.gray(` \u{1F4C4} ${tr(lang, "cli", "update.fileUpdated", { file })}`)
|
|
2214
|
+
);
|
|
1840
2215
|
updatedCount++;
|
|
1841
2216
|
}
|
|
1842
2217
|
} else if (stat.isDirectory()) {
|
|
@@ -1844,7 +2219,8 @@ async function updateFolder(sourceDir, targetDir, force, replacements) {
|
|
|
1844
2219
|
sourcePath,
|
|
1845
2220
|
targetPath,
|
|
1846
2221
|
force,
|
|
1847
|
-
replacements
|
|
2222
|
+
replacements,
|
|
2223
|
+
lang
|
|
1848
2224
|
);
|
|
1849
2225
|
updatedCount += subCount;
|
|
1850
2226
|
}
|
|
@@ -1857,10 +2233,13 @@ function configCommand(program2) {
|
|
|
1857
2233
|
await runConfig(options);
|
|
1858
2234
|
} catch (error) {
|
|
1859
2235
|
if (error instanceof Error && error.message === "canceled") {
|
|
1860
|
-
|
|
2236
|
+
const config = await getConfig(process.cwd());
|
|
2237
|
+
const lang = config?.lang ?? DEFAULT_LANG;
|
|
2238
|
+
console.log(chalk6.yellow(`
|
|
2239
|
+
${tr(lang, "cli", "common.canceled")}`));
|
|
1861
2240
|
process.exit(0);
|
|
1862
2241
|
}
|
|
1863
|
-
console.error(chalk6.red("
|
|
2242
|
+
console.error(chalk6.red(tr(DEFAULT_LANG, "cli", "common.errorLabel")), error);
|
|
1864
2243
|
process.exit(1);
|
|
1865
2244
|
}
|
|
1866
2245
|
});
|
|
@@ -1870,16 +2249,22 @@ async function runConfig(options) {
|
|
|
1870
2249
|
const config = await getConfig(cwd);
|
|
1871
2250
|
if (!config) {
|
|
1872
2251
|
console.log(
|
|
1873
|
-
chalk6.red(
|
|
2252
|
+
chalk6.red(
|
|
2253
|
+
tr(DEFAULT_LANG, "cli", "common.configNotFound")
|
|
2254
|
+
)
|
|
1874
2255
|
);
|
|
1875
2256
|
process.exit(1);
|
|
1876
2257
|
}
|
|
1877
2258
|
const configPath = path4.join(config.docsDir, ".lee-spec-kit.json");
|
|
1878
2259
|
if (!options.projectRoot) {
|
|
1879
2260
|
console.log();
|
|
1880
|
-
console.log(chalk6.blue("
|
|
2261
|
+
console.log(chalk6.blue(tr(config.lang, "cli", "config.currentTitle")));
|
|
1881
2262
|
console.log();
|
|
1882
|
-
console.log(
|
|
2263
|
+
console.log(
|
|
2264
|
+
chalk6.gray(
|
|
2265
|
+
` ${tr(config.lang, "cli", "config.pathLabel")}: ${configPath}`
|
|
2266
|
+
)
|
|
2267
|
+
);
|
|
1883
2268
|
console.log();
|
|
1884
2269
|
const configFile2 = await fs8.readJson(configPath);
|
|
1885
2270
|
console.log(JSON.stringify(configFile2, null, 2));
|
|
@@ -1889,7 +2274,9 @@ async function runConfig(options) {
|
|
|
1889
2274
|
const configFile = await fs8.readJson(configPath);
|
|
1890
2275
|
if (configFile.docsRepo !== "standalone") {
|
|
1891
2276
|
console.log(
|
|
1892
|
-
chalk6.yellow(
|
|
2277
|
+
chalk6.yellow(
|
|
2278
|
+
tr(config.lang, "cli", "config.projectRootStandaloneOnly")
|
|
2279
|
+
)
|
|
1893
2280
|
);
|
|
1894
2281
|
return;
|
|
1895
2282
|
}
|
|
@@ -1901,7 +2288,7 @@ async function runConfig(options) {
|
|
|
1901
2288
|
{
|
|
1902
2289
|
type: "select",
|
|
1903
2290
|
name: "repo",
|
|
1904
|
-
message: "
|
|
2291
|
+
message: tr(config.lang, "cli", "config.selectRepoToUpdate"),
|
|
1905
2292
|
choices: [
|
|
1906
2293
|
{ title: "Frontend (fe)", value: "fe" },
|
|
1907
2294
|
{ title: "Backend (be)", value: "be" }
|
|
@@ -1919,7 +2306,7 @@ async function runConfig(options) {
|
|
|
1919
2306
|
if (!options.repo || !["fe", "be"].includes(options.repo)) {
|
|
1920
2307
|
console.log(
|
|
1921
2308
|
chalk6.red(
|
|
1922
|
-
"
|
|
2309
|
+
tr(config.lang, "cli", "config.fullstackRepoRequired")
|
|
1923
2310
|
)
|
|
1924
2311
|
);
|
|
1925
2312
|
return;
|
|
@@ -1936,13 +2323,20 @@ async function runConfig(options) {
|
|
|
1936
2323
|
}
|
|
1937
2324
|
console.log(
|
|
1938
2325
|
chalk6.green(
|
|
1939
|
-
|
|
2326
|
+
tr(config.lang, "cli", "config.projectRootSet", {
|
|
2327
|
+
repo: options.repo.toUpperCase(),
|
|
2328
|
+
path: options.projectRoot
|
|
2329
|
+
})
|
|
1940
2330
|
)
|
|
1941
2331
|
);
|
|
1942
2332
|
} else {
|
|
1943
2333
|
configFile.projectRoot = options.projectRoot;
|
|
1944
2334
|
console.log(
|
|
1945
|
-
chalk6.green(
|
|
2335
|
+
chalk6.green(
|
|
2336
|
+
tr(config.lang, "cli", "config.projectRootSetSingle", {
|
|
2337
|
+
path: options.projectRoot
|
|
2338
|
+
})
|
|
2339
|
+
)
|
|
1946
2340
|
);
|
|
1947
2341
|
}
|
|
1948
2342
|
await fs8.writeJson(configPath, configFile, { spaces: 2 });
|
|
@@ -1962,7 +2356,10 @@ function contextCommand(program2) {
|
|
|
1962
2356
|
})
|
|
1963
2357
|
);
|
|
1964
2358
|
} else {
|
|
1965
|
-
console.error(
|
|
2359
|
+
console.error(
|
|
2360
|
+
chalk6.red(tr(DEFAULT_LANG, "cli", "common.errorLabel")),
|
|
2361
|
+
error
|
|
2362
|
+
);
|
|
1966
2363
|
}
|
|
1967
2364
|
process.exit(1);
|
|
1968
2365
|
}
|
|
@@ -1985,12 +2382,43 @@ function detectFromBranch(branchName, features) {
|
|
|
1985
2382
|
(f) => f.slug.toLowerCase() === detected.toLowerCase() || f.folderName.toLowerCase() === detected.toLowerCase()
|
|
1986
2383
|
);
|
|
1987
2384
|
}
|
|
2385
|
+
function getListLabel(f, stepsMap, lang) {
|
|
2386
|
+
if (f.completion.implementationDone && !f.completion.workflowDone) {
|
|
2387
|
+
if (f.git.docsHasUncommittedChanges) {
|
|
2388
|
+
return tr(lang, "cli", "context.list.docsCommitNeeded");
|
|
2389
|
+
}
|
|
2390
|
+
if (!f.issueNumber) {
|
|
2391
|
+
return tr(lang, "cli", "context.list.issueNumberNeeded");
|
|
2392
|
+
}
|
|
2393
|
+
if (!f.docs.prFieldExists || !f.docs.prStatusFieldExists) {
|
|
2394
|
+
return tr(lang, "cli", "context.list.addPrMetadata");
|
|
2395
|
+
}
|
|
2396
|
+
if (!f.pr.link) {
|
|
2397
|
+
return tr(lang, "cli", "context.list.recordPrLink");
|
|
2398
|
+
}
|
|
2399
|
+
if (!f.pr.status) {
|
|
2400
|
+
return tr(lang, "cli", "context.list.setPrStatus");
|
|
2401
|
+
}
|
|
2402
|
+
if (f.pr.status !== "Approved") {
|
|
2403
|
+
return tr(lang, "cli", "context.list.prStatusToApproved", {
|
|
2404
|
+
status: f.pr.status
|
|
2405
|
+
});
|
|
2406
|
+
}
|
|
2407
|
+
if (f.specStatus !== "Approved") {
|
|
2408
|
+
return tr(lang, "cli", "context.list.approveSpec");
|
|
2409
|
+
}
|
|
2410
|
+
if (f.planStatus !== "Approved") {
|
|
2411
|
+
return tr(lang, "cli", "context.list.approvePlan");
|
|
2412
|
+
}
|
|
2413
|
+
}
|
|
2414
|
+
return stepsMap[f.currentStep] || "Unknown";
|
|
2415
|
+
}
|
|
1988
2416
|
async function runContext(featureName, options) {
|
|
1989
2417
|
const cwd = process.cwd();
|
|
1990
2418
|
const config = await getConfig(cwd);
|
|
1991
|
-
const lang = config?.lang ?? "
|
|
2419
|
+
const lang = config?.lang ?? "en";
|
|
1992
2420
|
if (!config) {
|
|
1993
|
-
throw new Error("
|
|
2421
|
+
throw new Error(tr(DEFAULT_LANG, "cli", "common.configNotFound"));
|
|
1994
2422
|
}
|
|
1995
2423
|
const stepDefinitions = getStepDefinitions(lang);
|
|
1996
2424
|
const stepsMap = getStepsMap(lang);
|
|
@@ -2104,12 +2532,16 @@ async function runContext(featureName, options) {
|
|
|
2104
2532
|
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"));
|
|
2105
2533
|
console.log();
|
|
2106
2534
|
if (features.length === 0) {
|
|
2107
|
-
console.log(
|
|
2535
|
+
console.log(
|
|
2536
|
+
chalk6.yellow(
|
|
2537
|
+
tr(lang, "cli", "context.noActiveFeatures")
|
|
2538
|
+
)
|
|
2539
|
+
);
|
|
2108
2540
|
console.log();
|
|
2109
2541
|
return;
|
|
2110
2542
|
}
|
|
2111
2543
|
if (warnings.length > 0) {
|
|
2112
|
-
console.log(chalk6.yellow("
|
|
2544
|
+
console.log(chalk6.yellow(tr(lang, "cli", "context.envWarnings")));
|
|
2113
2545
|
warnings.forEach((w) => console.log(chalk6.yellow(` - ${w}`)));
|
|
2114
2546
|
console.log();
|
|
2115
2547
|
}
|
|
@@ -2117,24 +2549,36 @@ async function runContext(featureName, options) {
|
|
|
2117
2549
|
if (selectionMode === "open") {
|
|
2118
2550
|
console.log(
|
|
2119
2551
|
chalk6.gray(
|
|
2120
|
-
`
|
|
2552
|
+
` ${tr(lang, "cli", "context.openFallbackSummary", {
|
|
2553
|
+
inProgress: inProgressFeatures.length,
|
|
2554
|
+
readyToClose: readyToCloseFeatures.length,
|
|
2555
|
+
done: doneFeatures.length
|
|
2556
|
+
})}`
|
|
2121
2557
|
)
|
|
2122
2558
|
);
|
|
2123
2559
|
console.log();
|
|
2124
2560
|
}
|
|
2125
2561
|
if (selectionMode === "open") {
|
|
2126
|
-
console.log(
|
|
2562
|
+
console.log(
|
|
2563
|
+
chalk6.blue(
|
|
2564
|
+
`\u{1F539} ${tr(lang, "cli", "context.sectionInProgress")} (${inProgressFeatures.length})`
|
|
2565
|
+
)
|
|
2566
|
+
);
|
|
2127
2567
|
inProgressFeatures.forEach((f2) => {
|
|
2128
|
-
const stepName2 =
|
|
2568
|
+
const stepName2 = getListLabel(f2, stepsMap, lang);
|
|
2129
2569
|
const typeStr = config.projectType === "fullstack" ? chalk6.cyan(`(${f2.type})`) : "";
|
|
2130
2570
|
console.log(
|
|
2131
2571
|
` \u2022 ${chalk6.bold(f2.folderName)} ${typeStr} - ${chalk6.yellow(stepName2)}`
|
|
2132
2572
|
);
|
|
2133
2573
|
});
|
|
2134
2574
|
console.log();
|
|
2135
|
-
console.log(
|
|
2575
|
+
console.log(
|
|
2576
|
+
chalk6.blue(
|
|
2577
|
+
`\u{1F538} ${tr(lang, "cli", "context.sectionReadyToClose")} (${readyToCloseFeatures.length})`
|
|
2578
|
+
)
|
|
2579
|
+
);
|
|
2136
2580
|
readyToCloseFeatures.forEach((f2) => {
|
|
2137
|
-
const stepName2 =
|
|
2581
|
+
const stepName2 = getListLabel(f2, stepsMap, lang);
|
|
2138
2582
|
const typeStr = config.projectType === "fullstack" ? chalk6.cyan(`(${f2.type})`) : "";
|
|
2139
2583
|
console.log(
|
|
2140
2584
|
` \u2022 ${chalk6.bold(f2.folderName)} ${typeStr} - ${chalk6.yellow(stepName2)}`
|
|
@@ -2145,7 +2589,7 @@ async function runContext(featureName, options) {
|
|
|
2145
2589
|
console.log(chalk6.blue(title));
|
|
2146
2590
|
console.log();
|
|
2147
2591
|
targetFeatures.forEach((f2) => {
|
|
2148
|
-
const stepName2 =
|
|
2592
|
+
const stepName2 = getListLabel(f2, stepsMap, lang);
|
|
2149
2593
|
const typeStr = config.projectType === "fullstack" ? chalk6.cyan(`(${f2.type})`) : "";
|
|
2150
2594
|
console.log(
|
|
2151
2595
|
` \u2022 ${chalk6.bold(f2.folderName)} ${typeStr} - ${chalk6.yellow(stepName2)}`
|
|
@@ -2153,20 +2597,28 @@ async function runContext(featureName, options) {
|
|
|
2153
2597
|
});
|
|
2154
2598
|
}
|
|
2155
2599
|
console.log();
|
|
2156
|
-
console.log(chalk6.gray("
|
|
2600
|
+
console.log(chalk6.gray(tr(lang, "cli", "context.tipDetails")));
|
|
2157
2601
|
console.log(
|
|
2158
2602
|
chalk6.gray(" $ npx lee-spec-kit context <slug|F001|F001-slug> [--repo fe|be]")
|
|
2159
2603
|
);
|
|
2160
2604
|
if (selectionMode === "open") {
|
|
2161
|
-
console.log(
|
|
2162
|
-
|
|
2605
|
+
console.log(
|
|
2606
|
+
chalk6.gray(
|
|
2607
|
+
` $ npx lee-spec-kit context --all # ${tr(lang, "cli", "context.tipShowAll")}`
|
|
2608
|
+
)
|
|
2609
|
+
);
|
|
2610
|
+
console.log(
|
|
2611
|
+
chalk6.gray(
|
|
2612
|
+
` $ npx lee-spec-kit context --done # ${tr(lang, "cli", "context.tipShowDone")}`
|
|
2613
|
+
)
|
|
2614
|
+
);
|
|
2163
2615
|
}
|
|
2164
2616
|
console.log();
|
|
2165
2617
|
return;
|
|
2166
2618
|
}
|
|
2167
2619
|
const f = targetFeatures[0];
|
|
2168
2620
|
const stepName = stepsMap[f.currentStep] || "Unknown";
|
|
2169
|
-
const okTag = (requiresUserOk) => requiresUserOk ? chalk6.yellow(lang
|
|
2621
|
+
const okTag = (requiresUserOk) => requiresUserOk ? chalk6.yellow(tr(lang, "cli", "context.okRequired")) : "";
|
|
2170
2622
|
console.log(
|
|
2171
2623
|
`\u{1F539} Feature: ${chalk6.bold(f.folderName)} ${config.projectType === "fullstack" ? chalk6.cyan(`(${f.type})`) : ""}`
|
|
2172
2624
|
);
|
|
@@ -2240,9 +2692,6 @@ function printChecklist(f, stepDefinitions) {
|
|
|
2240
2692
|
console.log(` ${mark} ${definition.step}. ${label} ${detail}`);
|
|
2241
2693
|
});
|
|
2242
2694
|
}
|
|
2243
|
-
function msg(lang, ko, en) {
|
|
2244
|
-
return lang === "en" ? en : ko;
|
|
2245
|
-
}
|
|
2246
2695
|
function formatPath(cwd, p) {
|
|
2247
2696
|
if (!p) return "";
|
|
2248
2697
|
return path4.isAbsolute(p) ? path4.relative(cwd, p) : p;
|
|
@@ -2277,11 +2726,7 @@ async function checkDocsStructure(config, cwd) {
|
|
|
2277
2726
|
issues.push({
|
|
2278
2727
|
level: "error",
|
|
2279
2728
|
code: "missing_dir",
|
|
2280
|
-
message:
|
|
2281
|
-
config.lang,
|
|
2282
|
-
`\uD544\uC218 \uD3F4\uB354\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4: ${dir}`,
|
|
2283
|
-
`Missing required directory: ${dir}`
|
|
2284
|
-
),
|
|
2729
|
+
message: tr(config.lang, "cli", "doctor.issue.missingRequiredDir", { dir }),
|
|
2285
2730
|
path: formatPath(cwd, p)
|
|
2286
2731
|
});
|
|
2287
2732
|
}
|
|
@@ -2291,11 +2736,7 @@ async function checkDocsStructure(config, cwd) {
|
|
|
2291
2736
|
issues.push({
|
|
2292
2737
|
level: "warn",
|
|
2293
2738
|
code: "missing_config",
|
|
2294
|
-
message:
|
|
2295
|
-
config.lang,
|
|
2296
|
-
"\uC124\uC815 \uD30C\uC77C(.lee-spec-kit.json)\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. \uC77C\uBD80 \uAE30\uB2A5\uC774 \uD3F4\uB354 \uAD6C\uC870 \uCD94\uC815\uC73C\uB85C \uB3D9\uC791\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.",
|
|
2297
|
-
"Missing .lee-spec-kit.json. Some commands may rely on folder-structure heuristics."
|
|
2298
|
-
),
|
|
2739
|
+
message: tr(config.lang, "cli", "doctor.issue.missingConfig"),
|
|
2299
2740
|
path: formatPath(cwd, configPath)
|
|
2300
2741
|
});
|
|
2301
2742
|
}
|
|
@@ -2307,11 +2748,7 @@ async function checkFeatures(config, cwd, features) {
|
|
|
2307
2748
|
issues.push({
|
|
2308
2749
|
level: "warn",
|
|
2309
2750
|
code: "no_features",
|
|
2310
|
-
message:
|
|
2311
|
-
config.lang,
|
|
2312
|
-
"Feature \uD3F4\uB354\uB97C \uCC3E\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. (feature-base\uB9CC \uC874\uC7AC\uD558\uAC70\uB098 \uC544\uC9C1 feature\uB97C \uB9CC\uB4E4\uC9C0 \uC54A\uC558\uC744 \uC218 \uC788\uC2B5\uB2C8\uB2E4.)",
|
|
2313
|
-
"No feature folders found. (Only feature-base exists, or no features created yet.)"
|
|
2314
|
-
)
|
|
2751
|
+
message: tr(config.lang, "cli", "doctor.issue.noFeatures")
|
|
2315
2752
|
});
|
|
2316
2753
|
return issues;
|
|
2317
2754
|
}
|
|
@@ -2331,11 +2768,9 @@ async function checkFeatures(config, cwd, features) {
|
|
|
2331
2768
|
issues.push({
|
|
2332
2769
|
level: "warn",
|
|
2333
2770
|
code: "placeholder_left",
|
|
2334
|
-
message:
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
`Leftover placeholders detected: ${placeholders.join(", ")}`
|
|
2338
|
-
),
|
|
2771
|
+
message: tr(config.lang, "cli", "doctor.issue.placeholdersLeft", {
|
|
2772
|
+
placeholders: placeholders.join(", ")
|
|
2773
|
+
}),
|
|
2339
2774
|
path: formatPath(cwd, p)
|
|
2340
2775
|
});
|
|
2341
2776
|
}
|
|
@@ -2343,22 +2778,14 @@ async function checkFeatures(config, cwd, features) {
|
|
|
2343
2778
|
issues.push({
|
|
2344
2779
|
level: "warn",
|
|
2345
2780
|
code: "missing_spec",
|
|
2346
|
-
message:
|
|
2347
|
-
config.lang,
|
|
2348
|
-
"spec.md\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
2349
|
-
"Missing spec.md."
|
|
2350
|
-
),
|
|
2781
|
+
message: tr(config.lang, "cli", "doctor.issue.missingSpec"),
|
|
2351
2782
|
path: formatPath(cwd, f.path)
|
|
2352
2783
|
});
|
|
2353
2784
|
} else if (!f.specStatus) {
|
|
2354
2785
|
issues.push({
|
|
2355
2786
|
level: "warn",
|
|
2356
2787
|
code: "spec_status_unset",
|
|
2357
|
-
message:
|
|
2358
|
-
config.lang,
|
|
2359
|
-
"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)",
|
|
2360
|
-
"spec.md Status is not set. (May still be a template)"
|
|
2361
|
-
),
|
|
2788
|
+
message: tr(config.lang, "cli", "doctor.issue.specStatusUnset"),
|
|
2362
2789
|
path: formatPath(cwd, path4.join(f.path, "spec.md"))
|
|
2363
2790
|
});
|
|
2364
2791
|
}
|
|
@@ -2366,11 +2793,7 @@ async function checkFeatures(config, cwd, features) {
|
|
|
2366
2793
|
issues.push({
|
|
2367
2794
|
level: "warn",
|
|
2368
2795
|
code: "plan_status_unset",
|
|
2369
|
-
message:
|
|
2370
|
-
config.lang,
|
|
2371
|
-
"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)",
|
|
2372
|
-
"plan.md Status is not set. (May still be a template)"
|
|
2373
|
-
),
|
|
2796
|
+
message: tr(config.lang, "cli", "doctor.issue.planStatusUnset"),
|
|
2374
2797
|
path: formatPath(cwd, path4.join(f.path, "plan.md"))
|
|
2375
2798
|
});
|
|
2376
2799
|
}
|
|
@@ -2378,11 +2801,7 @@ async function checkFeatures(config, cwd, features) {
|
|
|
2378
2801
|
issues.push({
|
|
2379
2802
|
level: "warn",
|
|
2380
2803
|
code: "tasks_empty",
|
|
2381
|
-
message:
|
|
2382
|
-
config.lang,
|
|
2383
|
-
"tasks.md\uC5D0 \uD0DC\uC2A4\uD06C\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
2384
|
-
"tasks.md has no tasks."
|
|
2385
|
-
),
|
|
2804
|
+
message: tr(config.lang, "cli", "doctor.issue.tasksEmpty"),
|
|
2386
2805
|
path: formatPath(cwd, path4.join(f.path, "tasks.md"))
|
|
2387
2806
|
});
|
|
2388
2807
|
}
|
|
@@ -2394,11 +2813,10 @@ async function checkFeatures(config, cwd, features) {
|
|
|
2394
2813
|
issues.push({
|
|
2395
2814
|
level: "warn",
|
|
2396
2815
|
code: "duplicate_feature_id",
|
|
2397
|
-
message:
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
),
|
|
2816
|
+
message: tr(config.lang, "cli", "doctor.issue.duplicateFeatureId", {
|
|
2817
|
+
id,
|
|
2818
|
+
count: String(paths.length)
|
|
2819
|
+
}),
|
|
2402
2820
|
path: formatPath(cwd, paths[0])
|
|
2403
2821
|
});
|
|
2404
2822
|
}
|
|
@@ -2407,11 +2825,7 @@ async function checkFeatures(config, cwd, features) {
|
|
|
2407
2825
|
issues.push({
|
|
2408
2826
|
level: "warn",
|
|
2409
2827
|
code: "missing_feature_id",
|
|
2410
|
-
message:
|
|
2411
|
-
config.lang,
|
|
2412
|
-
"Feature \uD3F4\uB354\uBA85\uC774 F001-... \uD615\uC2DD\uC774 \uC544\uB2D9\uB2C8\uB2E4. (ID\uB97C \uCD94\uCD9C\uD560 \uC218 \uC5C6\uC74C)",
|
|
2413
|
-
"Feature folder name is not in F001-... format. (Cannot extract ID)"
|
|
2414
|
-
),
|
|
2828
|
+
message: tr(config.lang, "cli", "doctor.issue.missingFeatureId"),
|
|
2415
2829
|
path: formatPath(cwd, path4.join(config.docsDir, p))
|
|
2416
2830
|
});
|
|
2417
2831
|
}
|
|
@@ -2422,11 +2836,11 @@ function doctorCommand(program2) {
|
|
|
2422
2836
|
const cwd = process.cwd();
|
|
2423
2837
|
const config = await getConfig(cwd);
|
|
2424
2838
|
if (!config) {
|
|
2425
|
-
const message = "
|
|
2839
|
+
const message = tr(DEFAULT_LANG, "cli", "common.configNotFound");
|
|
2426
2840
|
if (options.json) {
|
|
2427
2841
|
console.log(JSON.stringify({ status: "error", error: message }, null, 2));
|
|
2428
2842
|
} else {
|
|
2429
|
-
console.error(chalk6.red("
|
|
2843
|
+
console.error(chalk6.red(tr(DEFAULT_LANG, "cli", "common.errorLabel")), message);
|
|
2430
2844
|
}
|
|
2431
2845
|
process.exit(1);
|
|
2432
2846
|
}
|
|
@@ -2461,32 +2875,40 @@ function doctorCommand(program2) {
|
|
|
2461
2875
|
process.exit(exitCode);
|
|
2462
2876
|
}
|
|
2463
2877
|
console.log();
|
|
2464
|
-
console.log(chalk6.bold("
|
|
2878
|
+
console.log(chalk6.bold(tr(lang, "cli", "doctor.title")));
|
|
2465
2879
|
console.log(chalk6.gray(`- Docs: ${path4.relative(cwd, docsDir)}`));
|
|
2466
2880
|
console.log(chalk6.gray(`- Type: ${projectType}`));
|
|
2467
2881
|
console.log(chalk6.gray(`- Lang: ${lang}`));
|
|
2468
2882
|
console.log();
|
|
2469
2883
|
if (warnings.length > 0) {
|
|
2470
|
-
console.log(
|
|
2884
|
+
console.log(
|
|
2885
|
+
chalk6.yellow(tr(lang, "cli", "doctor.envWarnings"))
|
|
2886
|
+
);
|
|
2471
2887
|
warnings.forEach((w) => console.log(chalk6.yellow(` - ${w}`)));
|
|
2472
2888
|
console.log();
|
|
2473
2889
|
}
|
|
2474
2890
|
if (!hasIssues) {
|
|
2475
|
-
console.log(chalk6.green("
|
|
2891
|
+
console.log(chalk6.green(tr(lang, "cli", "doctor.noIssues")));
|
|
2476
2892
|
console.log();
|
|
2477
2893
|
process.exit(0);
|
|
2478
2894
|
}
|
|
2479
2895
|
const errors = issues.filter((i) => i.level === "error");
|
|
2480
2896
|
const warns = issues.filter((i) => i.level === "warn");
|
|
2481
2897
|
if (errors.length > 0) {
|
|
2482
|
-
console.log(
|
|
2898
|
+
console.log(
|
|
2899
|
+
chalk6.red(`\u274C ${tr(lang, "cli", "doctor.errorsTitle")} (${errors.length})`)
|
|
2900
|
+
);
|
|
2483
2901
|
errors.forEach(
|
|
2484
2902
|
(i) => console.log(chalk6.red(` - ${i.message}${i.path ? ` (${i.path})` : ""}`))
|
|
2485
2903
|
);
|
|
2486
2904
|
console.log();
|
|
2487
2905
|
}
|
|
2488
2906
|
if (warns.length > 0) {
|
|
2489
|
-
console.log(
|
|
2907
|
+
console.log(
|
|
2908
|
+
chalk6.yellow(
|
|
2909
|
+
`\u26A0\uFE0F ${tr(lang, "cli", "doctor.warningsTitle")} (${warns.length})`
|
|
2910
|
+
)
|
|
2911
|
+
);
|
|
2490
2912
|
warns.forEach(
|
|
2491
2913
|
(i) => console.log(
|
|
2492
2914
|
chalk6.yellow(` - ${i.message}${i.path ? ` (${i.path})` : ""}`)
|
|
@@ -2496,7 +2918,9 @@ function doctorCommand(program2) {
|
|
|
2496
2918
|
}
|
|
2497
2919
|
console.log(
|
|
2498
2920
|
chalk6.gray(
|
|
2499
|
-
|
|
2921
|
+
tr(lang, "cli", "doctor.tipJson", {
|
|
2922
|
+
strictFlag: options.strict ? " --strict" : ""
|
|
2923
|
+
})
|
|
2500
2924
|
)
|
|
2501
2925
|
);
|
|
2502
2926
|
console.log();
|