lee-spec-kit 0.6.18 → 0.6.20
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 +62 -23
- package/package.json +1 -1
- package/templates/en/common/features/feature-base/issue.md +2 -1
- package/templates/en/common/features/feature-base/plan.md +2 -1
- package/templates/en/common/features/feature-base/pr.md +2 -1
- package/templates/en/common/features/feature-base/spec.md +2 -1
- package/templates/en/common/features/feature-base/tasks.md +4 -2
- package/templates/ko/common/features/feature-base/issue.md +2 -1
- package/templates/ko/common/features/feature-base/plan.md +2 -1
- package/templates/ko/common/features/feature-base/pr.md +2 -1
- package/templates/ko/common/features/feature-base/spec.md +2 -1
- package/templates/ko/common/features/feature-base/tasks.md +4 -2
package/dist/index.js
CHANGED
|
@@ -118,7 +118,7 @@ var I18N = {
|
|
|
118
118
|
"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)",
|
|
119
119
|
"doctor.issue.tasksEmpty": "tasks.md\uC5D0 \uD0DC\uC2A4\uD06C\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
120
120
|
"doctor.issue.tasksDocStatusUnset": "tasks.md\uC758 \uBB38\uC11C \uC0C1\uD0DC(Doc Status)\uAC00 \uC124\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. (Draft/Review/Approved \uC911 \uD558\uB098\uB85C \uC124\uC815\uD558\uC138\uC694.)",
|
|
121
|
-
"doctor.issue.tasksDocStatusMissing": "tasks.md\uC5D0 \uBB38\uC11C \uC0C1\uD0DC(Doc Status) \uD544\uB4DC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. `- **\uBB38\uC11C \uC0C1\uD0DC**: Draft | Review | Approved`\uB97C \uCD94\uAC00\uD558\uC138\uC694.",
|
|
121
|
+
"doctor.issue.tasksDocStatusMissing": "tasks.md\uC5D0 \uBB38\uC11C \uC0C1\uD0DC(Doc Status) \uD544\uB4DC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. `- **\uBB38\uC11C \uC0C1\uD0DC**: -`\uC640 `\uAC12: Draft | Review | Approved`\uB97C \uCD94\uAC00\uD558\uC138\uC694.",
|
|
122
122
|
"doctor.issue.duplicateFeatureId": "\uC911\uBCF5 Feature ID \uAC10\uC9C0: {id} ({count}\uAC1C)",
|
|
123
123
|
"doctor.issue.missingFeatureId": "Feature \uD3F4\uB354\uBA85\uC774 F001-... \uD615\uC2DD\uC774 \uC544\uB2D9\uB2C8\uB2E4. (ID\uB97C \uCD94\uCD9C\uD560 \uC218 \uC5C6\uC74C)",
|
|
124
124
|
"context.noActiveFeatures": "\u26A0\uFE0F \uC9C4\uD589 \uC911\uC778 Feature\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
@@ -575,7 +575,7 @@ var I18N = {
|
|
|
575
575
|
"doctor.issue.planStatusUnset": "plan.md Status is not set. (May still be a template)",
|
|
576
576
|
"doctor.issue.tasksEmpty": "tasks.md has no tasks.",
|
|
577
577
|
"doctor.issue.tasksDocStatusUnset": "tasks.md Doc Status is not set. (Set it to Draft, Review, or Approved.)",
|
|
578
|
-
"doctor.issue.tasksDocStatusMissing": "tasks.md is missing the Doc Status field. Add `- **Doc Status**: Draft | Review | Approved`.",
|
|
578
|
+
"doctor.issue.tasksDocStatusMissing": "tasks.md is missing the Doc Status field. Add `- **Doc Status**: -` and `Values: Draft | Review | Approved`.",
|
|
579
579
|
"doctor.issue.duplicateFeatureId": "Duplicate Feature ID detected: {id} ({count})",
|
|
580
580
|
"doctor.issue.missingFeatureId": "Feature folder name is not in F001-... format. (Cannot extract ID)",
|
|
581
581
|
"context.noActiveFeatures": "\u26A0\uFE0F No active features found.",
|
|
@@ -4188,6 +4188,9 @@ function isGitPathIgnored(cwd, relativePath) {
|
|
|
4188
4188
|
}
|
|
4189
4189
|
}
|
|
4190
4190
|
var GIT_WORKTREE_CACHE = /* @__PURE__ */ new Map();
|
|
4191
|
+
function resetContextGitCaches() {
|
|
4192
|
+
GIT_WORKTREE_CACHE.clear();
|
|
4193
|
+
}
|
|
4191
4194
|
function getGitTopLevel(cwd) {
|
|
4192
4195
|
try {
|
|
4193
4196
|
return execSync("git rev-parse --show-toplevel", {
|
|
@@ -4427,6 +4430,12 @@ var PROJECT_DIRTY_STATUS_CACHE = /* @__PURE__ */ new Map();
|
|
|
4427
4430
|
var COMPONENT_STATUS_PATH_CACHE = /* @__PURE__ */ new Map();
|
|
4428
4431
|
var PR_REMOTE_STATUS_CACHE = /* @__PURE__ */ new Map();
|
|
4429
4432
|
var FEATURE_WORKTREE_CACHE = /* @__PURE__ */ new Map();
|
|
4433
|
+
function resetContextParseCaches() {
|
|
4434
|
+
PROJECT_DIRTY_STATUS_CACHE.clear();
|
|
4435
|
+
COMPONENT_STATUS_PATH_CACHE.clear();
|
|
4436
|
+
PR_REMOTE_STATUS_CACHE.clear();
|
|
4437
|
+
FEATURE_WORKTREE_CACHE.clear();
|
|
4438
|
+
}
|
|
4430
4439
|
function resolveFeatureWorktreePath(projectGitCwd, issueNumber, slug, folderName) {
|
|
4431
4440
|
const expectedBranches = [
|
|
4432
4441
|
`feat/${issueNumber}-${slug}`,
|
|
@@ -4818,6 +4827,27 @@ async function parseFeature(featurePath, type, context, options) {
|
|
|
4818
4827
|
prReviewEvidence = prReviewEvidenceValue?.trim();
|
|
4819
4828
|
prReviewEvidenceProvided = !isPlaceholderReviewEvidence(prReviewEvidenceValue);
|
|
4820
4829
|
}
|
|
4830
|
+
if (effectiveProjectGitCwd && issueNumber) {
|
|
4831
|
+
const alreadyExpected = isExpectedFeatureBranch(
|
|
4832
|
+
effectiveProjectBranch,
|
|
4833
|
+
issueNumber,
|
|
4834
|
+
slug,
|
|
4835
|
+
folderName
|
|
4836
|
+
);
|
|
4837
|
+
if (!alreadyExpected) {
|
|
4838
|
+
const worktree = resolveFeatureWorktreePath(
|
|
4839
|
+
effectiveProjectGitCwd,
|
|
4840
|
+
issueNumber,
|
|
4841
|
+
slug,
|
|
4842
|
+
folderName
|
|
4843
|
+
);
|
|
4844
|
+
if (worktree) {
|
|
4845
|
+
effectiveProjectGitCwd = worktree.cwd;
|
|
4846
|
+
effectiveProjectBranch = worktree.branch;
|
|
4847
|
+
effectiveProjectBranchAvailable = true;
|
|
4848
|
+
}
|
|
4849
|
+
}
|
|
4850
|
+
}
|
|
4821
4851
|
const issueDocExists = await fs15.pathExists(issueDocPath);
|
|
4822
4852
|
if (issueDocExists) {
|
|
4823
4853
|
const content = await fs15.readFile(issueDocPath, "utf-8");
|
|
@@ -5207,6 +5237,8 @@ function buildDocsFeatureGitMeta(docsGitCwd, relativeFeaturePaths) {
|
|
|
5207
5237
|
return map;
|
|
5208
5238
|
}
|
|
5209
5239
|
async function scanFeatures(config) {
|
|
5240
|
+
resetContextGitCaches();
|
|
5241
|
+
resetContextParseCaches();
|
|
5210
5242
|
const features = [];
|
|
5211
5243
|
const warnings = [];
|
|
5212
5244
|
const stepDefinitions = getStepDefinitions(config.lang, config.workflow);
|
|
@@ -6019,6 +6051,19 @@ function getActionSummary(action) {
|
|
|
6019
6051
|
return action.message;
|
|
6020
6052
|
}
|
|
6021
6053
|
function formatActionSummary(action) {
|
|
6054
|
+
const formatBranchCreateDetail = (command) => {
|
|
6055
|
+
const worktreeMatch = command.match(/\.worktrees\/([A-Za-z0-9._-]+)/);
|
|
6056
|
+
const branchMatch = command.match(/\bfeat\/([A-Za-z0-9._-]+)/);
|
|
6057
|
+
const worktree = worktreeMatch ? `.worktrees/${worktreeMatch[1]}` : null;
|
|
6058
|
+
const branch = branchMatch ? `feat/${branchMatch[1]}` : null;
|
|
6059
|
+
if (worktree && branch) {
|
|
6060
|
+
return `(${action.scope}) create or reuse worktree ${worktree} for branch ${branch}`;
|
|
6061
|
+
}
|
|
6062
|
+
if (branch) {
|
|
6063
|
+
return `(${action.scope}) create or reuse worktree for branch ${branch}`;
|
|
6064
|
+
}
|
|
6065
|
+
return `(${action.scope}) create or reuse feature branch worktree`;
|
|
6066
|
+
};
|
|
6022
6067
|
const extractCommitMessage = (command) => {
|
|
6023
6068
|
const doubleQuoted = command.match(/git\s+commit\s+-m\s+"((?:\\"|[^"])*)"/);
|
|
6024
6069
|
if (doubleQuoted) {
|
|
@@ -6031,6 +6076,9 @@ function formatActionSummary(action) {
|
|
|
6031
6076
|
return null;
|
|
6032
6077
|
};
|
|
6033
6078
|
if (action.type === "command") {
|
|
6079
|
+
if (action.category === "branch_create") {
|
|
6080
|
+
return formatBranchCreateDetail(action.cmd);
|
|
6081
|
+
}
|
|
6034
6082
|
const commitMessage = extractCommitMessage(action.cmd);
|
|
6035
6083
|
if (commitMessage) {
|
|
6036
6084
|
return `(${action.scope}) commit: ${commitMessage}`;
|
|
@@ -6706,12 +6754,6 @@ function printSuggestionOptions(lang, suggestionOptions) {
|
|
|
6706
6754
|
console.log(chalk6.cyan(` \u21B3 ${finalPrompt}`));
|
|
6707
6755
|
}
|
|
6708
6756
|
}
|
|
6709
|
-
function formatActionSummary2(action) {
|
|
6710
|
-
if (action.type === "command") {
|
|
6711
|
-
return `(${action.scope}) ${action.cmd}`;
|
|
6712
|
-
}
|
|
6713
|
-
return action.message;
|
|
6714
|
-
}
|
|
6715
6757
|
function buildRequiredDocHints(actionOptions) {
|
|
6716
6758
|
const ids = getRecommendedDocIdsForCategories(
|
|
6717
6759
|
actionOptions.map((option) => option.action.category)
|
|
@@ -7414,14 +7456,12 @@ async function runContext(featureName, options) {
|
|
|
7414
7456
|
const actionOptions = state.actionOptions;
|
|
7415
7457
|
console.log(chalk6.green(chalk6.bold("\u{1F449} Next Options (Atomic):")));
|
|
7416
7458
|
let hasDocsCommand = false;
|
|
7417
|
-
actionOptions.forEach((
|
|
7418
|
-
|
|
7419
|
-
|
|
7420
|
-
|
|
7421
|
-
|
|
7422
|
-
|
|
7423
|
-
} else {
|
|
7424
|
-
console.log(` ${label}. ${checkTag(action.requiresUserCheck)}${action.message}`);
|
|
7459
|
+
actionOptions.forEach((option) => {
|
|
7460
|
+
const requiresCheck = option.action.requiresUserCheck;
|
|
7461
|
+
const detail = option.detail;
|
|
7462
|
+
console.log(` ${option.label}. ${checkTag(requiresCheck)}${detail}`);
|
|
7463
|
+
if (option.action.type === "command" && option.action.scope === "docs") {
|
|
7464
|
+
hasDocsCommand = true;
|
|
7425
7465
|
}
|
|
7426
7466
|
});
|
|
7427
7467
|
if (hasDocsCommand) {
|
|
@@ -7569,7 +7609,7 @@ async function runApprovedOption(state, config, lang, featureName, selectionOpti
|
|
|
7569
7609
|
}
|
|
7570
7610
|
console.log();
|
|
7571
7611
|
console.log(chalk6.green(`\u2705 Approved option: ${parsedLabel}`));
|
|
7572
|
-
console.log(chalk6.gray(` - Action: ${
|
|
7612
|
+
console.log(chalk6.gray(` - Action: ${freshSelected.detail}`));
|
|
7573
7613
|
if (selectedAction.type === "command") {
|
|
7574
7614
|
const selectedComponent = selectionOptions.component || "";
|
|
7575
7615
|
let executeCommand = buildApprovalCommand(
|
|
@@ -8400,16 +8440,15 @@ async function runView(featureName, options) {
|
|
|
8400
8440
|
console.log(`- State: ${stateLabel}`);
|
|
8401
8441
|
console.log(`- Progress: ${completion}`);
|
|
8402
8442
|
console.log(`- Step: ${f.currentStep}`);
|
|
8403
|
-
|
|
8443
|
+
const nextSummary = state.actionOptions.length > 0 ? state.actionOptions[0].detail : f.nextAction;
|
|
8444
|
+
console.log(`- Next: ${nextSummary}`);
|
|
8404
8445
|
if (state.actionOptions.length > 0) {
|
|
8405
8446
|
console.log();
|
|
8406
8447
|
console.log(chalk6.green("Atomic options:"));
|
|
8407
8448
|
for (const option of state.actionOptions) {
|
|
8408
|
-
|
|
8409
|
-
|
|
8410
|
-
}
|
|
8411
|
-
console.log(` ${option.label}. ${option.action.message}`);
|
|
8412
|
-
}
|
|
8449
|
+
const lang = config.lang ?? DEFAULT_LANG;
|
|
8450
|
+
const requiresCheck = option.action.requiresUserCheck ? tr(lang, "cli", "context.checkRequired") : "";
|
|
8451
|
+
console.log(` ${option.label}. ${requiresCheck}${option.detail}`);
|
|
8413
8452
|
}
|
|
8414
8453
|
console.log(
|
|
8415
8454
|
chalk6.gray(
|
package/package.json
CHANGED
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
|
|
13
13
|
## GitHub Issue
|
|
14
14
|
|
|
15
|
-
- **Doc Status**:
|
|
15
|
+
- **Doc Status**: -
|
|
16
|
+
- Values: Draft | Review | Approved
|
|
16
17
|
- **Repo**: {{projectName}}-{component}
|
|
17
18
|
- **Issue**: #{issue-number}
|
|
18
19
|
- **Branch**: `feat/{issue-number}-{feature-name}`
|
|
@@ -20,7 +21,8 @@
|
|
|
20
21
|
- Example: `#123` or PR URL
|
|
21
22
|
- **PR Status**: -
|
|
22
23
|
- Values: Review | Approved
|
|
23
|
-
- **Pre-PR Review**:
|
|
24
|
+
- **Pre-PR Review**: -
|
|
25
|
+
- Values: Pending | Done
|
|
24
26
|
- Mark `Done` after pre-PR review is completed
|
|
25
27
|
- **Pre-PR Findings**: major=0, minor=0
|
|
26
28
|
- Update with final findings counts from pre-PR review
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
|
|
13
13
|
## GitHub Issue
|
|
14
14
|
|
|
15
|
-
- **문서 상태**:
|
|
15
|
+
- **문서 상태**: -
|
|
16
|
+
- 값: Draft | Review | Approved
|
|
16
17
|
- **레포**: {{projectName}}-{component}
|
|
17
18
|
- **Issue**: #{이슈번호}
|
|
18
19
|
- **브랜치**: `feat/{이슈번호}-{기능명}`
|
|
@@ -20,7 +21,8 @@
|
|
|
20
21
|
- 예: `#123` 또는 PR URL
|
|
21
22
|
- **PR 상태**: -
|
|
22
23
|
- 값: Review | Approved
|
|
23
|
-
- **PR 전 리뷰**:
|
|
24
|
+
- **PR 전 리뷰**: -
|
|
25
|
+
- 값: Pending | Done
|
|
24
26
|
- 사전 코드리뷰 완료 후 `Done`으로 변경
|
|
25
27
|
- **PR 전 리뷰 Findings**: major=0, minor=0
|
|
26
28
|
- 사전 리뷰 최종 결과에 맞게 major/minor 건수를 갱신
|