lee-spec-kit 0.1.8 → 0.2.0

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.
Files changed (34) hide show
  1. package/dist/index.js +74 -48
  2. package/package.json +1 -1
  3. package/templates/en/{fullstack → common}/agents/git-workflow.md +26 -34
  4. package/templates/en/{single → common}/agents/issue-template.md +10 -5
  5. package/templates/en/{single → common}/agents/pr-template.md +9 -2
  6. package/templates/en/common/agents/skills/create-feature.md +53 -0
  7. package/templates/en/common/agents/skills/create-issue.md +52 -0
  8. package/templates/en/common/agents/skills/create-pr.md +97 -0
  9. package/templates/en/common/agents/skills/execute-task.md +86 -0
  10. package/templates/en/fullstack/agents/agents.md +11 -26
  11. package/templates/en/single/agents/agents.md +8 -21
  12. package/templates/ko/{fullstack → common}/agents/git-workflow.md +20 -73
  13. package/templates/ko/{fullstack → common}/agents/issue-template.md +10 -5
  14. package/templates/ko/{fullstack → common}/agents/pr-template.md +9 -2
  15. package/templates/ko/common/agents/skills/create-feature.md +53 -0
  16. package/templates/ko/common/agents/skills/create-issue.md +52 -0
  17. package/templates/ko/common/agents/skills/create-pr.md +97 -0
  18. package/templates/ko/common/agents/skills/execute-task.md +86 -0
  19. package/templates/ko/fullstack/agents/agents.md +11 -33
  20. package/templates/ko/single/agents/agents.md +13 -21
  21. package/templates/en/fullstack/agents/constitution.md +0 -80
  22. package/templates/en/fullstack/agents/issue-template.md +0 -110
  23. package/templates/en/fullstack/agents/pr-template.md +0 -96
  24. package/templates/en/single/agents/custom.md +0 -29
  25. package/templates/en/single/agents/git-workflow.md +0 -170
  26. package/templates/ko/single/agents/constitution.md +0 -80
  27. package/templates/ko/single/agents/custom.md +0 -29
  28. package/templates/ko/single/agents/git-workflow.md +0 -170
  29. package/templates/ko/single/agents/issue-template.md +0 -114
  30. package/templates/ko/single/agents/pr-template.md +0 -110
  31. /package/templates/en/{single → common}/agents/constitution.md +0 -0
  32. /package/templates/en/{fullstack → common}/agents/custom.md +0 -0
  33. /package/templates/ko/{fullstack → common}/agents/constitution.md +0 -0
  34. /package/templates/ko/{fullstack → common}/agents/custom.md +0 -0
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import { program } from 'commander';
3
3
  import prompts from 'prompts';
4
4
  import chalk from 'chalk';
5
- import path3 from 'path';
5
+ import path6 from 'path';
6
6
  import fs6 from 'fs-extra';
7
7
  import { glob } from 'glob';
8
8
  import { fileURLToPath } from 'url';
@@ -32,10 +32,10 @@ async function replaceInFiles(dir, replacements) {
32
32
  }
33
33
  }
34
34
  var __filename2 = fileURLToPath(import.meta.url);
35
- var __dirname2 = path3.dirname(__filename2);
35
+ var __dirname2 = path6.dirname(__filename2);
36
36
  function getTemplatesDir() {
37
- const rootDir = path3.resolve(__dirname2, "..");
38
- return path3.join(rootDir, "templates");
37
+ const rootDir = path6.resolve(__dirname2, "..");
38
+ return path6.join(rootDir, "templates");
39
39
  }
40
40
 
41
41
  // src/utils/validation.ts
@@ -150,11 +150,11 @@ function initCommand(program2) {
150
150
  }
151
151
  async function runInit(options) {
152
152
  const cwd = process.cwd();
153
- const defaultName = path3.basename(cwd);
153
+ const defaultName = path6.basename(cwd);
154
154
  let projectName = options.name || defaultName;
155
155
  let projectType = options.type;
156
156
  let lang = options.lang || "ko";
157
- const targetDir = path3.resolve(cwd, options.dir || "./docs");
157
+ const targetDir = path6.resolve(cwd, options.dir || "./docs");
158
158
  if (!options.yes) {
159
159
  const response = await prompts(
160
160
  [
@@ -232,14 +232,20 @@ async function runInit(options) {
232
232
  console.log(chalk.gray(` \uACBD\uB85C: ${targetDir}`));
233
233
  console.log();
234
234
  const templatesDir = getTemplatesDir();
235
- const templatePath = path3.join(templatesDir, lang, projectType);
236
- if (!await fs6.pathExists(templatePath)) {
237
- throw new Error(`\uD15C\uD50C\uB9BF\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${templatePath}`);
235
+ const commonPath = path6.join(templatesDir, lang, "common");
236
+ const typePath = path6.join(templatesDir, lang, projectType);
237
+ if (await fs6.pathExists(commonPath)) {
238
+ await copyTemplates(commonPath, targetDir);
238
239
  }
239
- await copyTemplates(templatePath, targetDir);
240
+ if (!await fs6.pathExists(typePath)) {
241
+ throw new Error(`\uD15C\uD50C\uB9BF\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${typePath}`);
242
+ }
243
+ await copyTemplates(typePath, targetDir);
244
+ const featurePath = projectType === "fullstack" ? "docs/features/{be|fe}" : "docs/features";
240
245
  const replacements = {
241
246
  "{{projectName}}": projectName,
242
- "{{date}}": (/* @__PURE__ */ new Date()).toISOString().split("T")[0]
247
+ "{{date}}": (/* @__PURE__ */ new Date()).toISOString().split("T")[0],
248
+ "{{featurePath}}": featurePath
243
249
  };
244
250
  await replaceInFiles(targetDir, replacements);
245
251
  const config = {
@@ -248,7 +254,7 @@ async function runInit(options) {
248
254
  lang,
249
255
  createdAt: (/* @__PURE__ */ new Date()).toISOString().split("T")[0]
250
256
  };
251
- const configPath = path3.join(targetDir, ".lee-spec-kit.json");
257
+ const configPath = path6.join(targetDir, ".lee-spec-kit.json");
252
258
  await fs6.writeJson(configPath, config, { spaces: 2 });
253
259
  console.log(chalk.green("\u2705 docs \uAD6C\uC870 \uC0DD\uC131 \uC644\uB8CC!"));
254
260
  console.log();
@@ -273,7 +279,7 @@ async function initGit(cwd, targetDir) {
273
279
  console.log(chalk.blue("\u{1F4E6} Git \uCD08\uAE30\uD654 \uC911..."));
274
280
  execSync("git init", { cwd, stdio: "ignore" });
275
281
  }
276
- const relativePath = path3.relative(cwd, targetDir);
282
+ const relativePath = path6.relative(cwd, targetDir);
277
283
  execSync(`git add "${relativePath}"`, { cwd, stdio: "ignore" });
278
284
  execSync('git commit -m "init: docs \uAD6C\uC870 \uCD08\uAE30\uD654 (lee-spec-kit)"', {
279
285
  cwd,
@@ -290,12 +296,12 @@ async function initGit(cwd, targetDir) {
290
296
  }
291
297
  async function getConfig(cwd) {
292
298
  const possibleDirs = [
293
- path3.join(cwd, "docs"),
299
+ path6.join(cwd, "docs"),
294
300
  cwd
295
301
  // 이미 docs 폴더 안에 있을 수 있음
296
302
  ];
297
303
  for (const docsDir of possibleDirs) {
298
- const configPath = path3.join(docsDir, ".lee-spec-kit.json");
304
+ const configPath = path6.join(docsDir, ".lee-spec-kit.json");
299
305
  if (await fs6.pathExists(configPath)) {
300
306
  try {
301
307
  const configFile = await fs6.readJson(configPath);
@@ -308,13 +314,13 @@ async function getConfig(cwd) {
308
314
  } catch {
309
315
  }
310
316
  }
311
- const agentsPath = path3.join(docsDir, "agents");
312
- const featuresPath = path3.join(docsDir, "features");
317
+ const agentsPath = path6.join(docsDir, "agents");
318
+ const featuresPath = path6.join(docsDir, "features");
313
319
  if (await fs6.pathExists(agentsPath) && await fs6.pathExists(featuresPath)) {
314
- const bePath = path3.join(featuresPath, "be");
315
- const fePath = path3.join(featuresPath, "fe");
320
+ const bePath = path6.join(featuresPath, "be");
321
+ const fePath = path6.join(featuresPath, "fe");
316
322
  const projectType = await fs6.pathExists(bePath) || await fs6.pathExists(fePath) ? "fullstack" : "single";
317
- const agentsMdPath = path3.join(agentsPath, "agents.md");
323
+ const agentsMdPath = path6.join(agentsPath, "agents.md");
318
324
  let lang = "ko";
319
325
  if (await fs6.pathExists(agentsMdPath)) {
320
326
  const content = await fs6.readFile(agentsMdPath, "utf-8");
@@ -386,17 +392,17 @@ async function runFeature(name, options) {
386
392
  }
387
393
  let featuresDir;
388
394
  if (projectType === "fullstack" && repo) {
389
- featuresDir = path3.join(docsDir, "features", repo);
395
+ featuresDir = path6.join(docsDir, "features", repo);
390
396
  } else {
391
- featuresDir = path3.join(docsDir, "features");
397
+ featuresDir = path6.join(docsDir, "features");
392
398
  }
393
399
  const featureFolderName = `${featureId}-${name}`;
394
- const featureDir = path3.join(featuresDir, featureFolderName);
400
+ const featureDir = path6.join(featuresDir, featureFolderName);
395
401
  if (await fs6.pathExists(featureDir)) {
396
402
  console.error(chalk.red(`\uC774\uBBF8 \uC874\uC7AC\uD558\uB294 \uD3F4\uB354\uC785\uB2C8\uB2E4: ${featureDir}`));
397
403
  process.exit(1);
398
404
  }
399
- const featureBasePath = path3.join(docsDir, "features", "feature-base");
405
+ const featureBasePath = path6.join(docsDir, "features", "feature-base");
400
406
  if (!await fs6.pathExists(featureBasePath)) {
401
407
  console.error(chalk.red("feature-base \uD15C\uD50C\uB9BF\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4."));
402
408
  process.exit(1);
@@ -432,12 +438,12 @@ async function runFeature(name, options) {
432
438
  console.log();
433
439
  }
434
440
  async function getNextFeatureId(docsDir, projectType) {
435
- const featuresDir = path3.join(docsDir, "features");
441
+ const featuresDir = path6.join(docsDir, "features");
436
442
  let max = 0;
437
443
  const scanDirs = [];
438
444
  if (projectType === "fullstack") {
439
- scanDirs.push(path3.join(featuresDir, "be"));
440
- scanDirs.push(path3.join(featuresDir, "fe"));
445
+ scanDirs.push(path6.join(featuresDir, "be"));
446
+ scanDirs.push(path6.join(featuresDir, "fe"));
441
447
  } else {
442
448
  scanDirs.push(featuresDir);
443
449
  }
@@ -477,20 +483,20 @@ async function runStatus(options) {
477
483
  process.exit(1);
478
484
  }
479
485
  const { docsDir, projectType } = config;
480
- const featuresDir = path3.join(docsDir, "features");
486
+ const featuresDir = path6.join(docsDir, "features");
481
487
  const features = [];
482
488
  const idMap = /* @__PURE__ */ new Map();
483
489
  const scopes = projectType === "fullstack" ? ["be", "fe"] : [""];
484
490
  for (const scope of scopes) {
485
- const scanDir = scope ? path3.join(featuresDir, scope) : featuresDir;
491
+ const scanDir = scope ? path6.join(featuresDir, scope) : featuresDir;
486
492
  if (!await fs6.pathExists(scanDir)) continue;
487
493
  const entries = await fs6.readdir(scanDir, { withFileTypes: true });
488
494
  for (const entry of entries) {
489
495
  if (!entry.isDirectory()) continue;
490
496
  if (entry.name === "feature-base") continue;
491
- const featureDir = path3.join(scanDir, entry.name);
492
- const specPath = path3.join(featureDir, "spec.md");
493
- const tasksPath = path3.join(featureDir, "tasks.md");
497
+ const featureDir = path6.join(scanDir, entry.name);
498
+ const specPath = path6.join(featureDir, "spec.md");
499
+ const tasksPath = path6.join(featureDir, "tasks.md");
494
500
  if (!await fs6.pathExists(specPath)) continue;
495
501
  if (!await fs6.pathExists(tasksPath)) continue;
496
502
  const specContent = await fs6.readFile(specPath, "utf-8");
@@ -499,7 +505,7 @@ async function runStatus(options) {
499
505
  const name = extractSpecValue(specContent, "\uAE30\uB2A5\uBA85") || extractSpecValue(specContent, "Feature Name") || entry.name;
500
506
  const repo = extractSpecValue(specContent, "\uB300\uC0C1 \uB808\uD3EC") || extractSpecValue(specContent, "Target Repo") || (scope ? `{{projectName}}-${scope}` : "{{projectName}}");
501
507
  const issue = extractSpecValue(specContent, "\uC774\uC288 \uBC88\uD638") || extractSpecValue(specContent, "Issue Number") || "-";
502
- const relPath = path3.relative(docsDir, featureDir);
508
+ const relPath = path6.relative(docsDir, featureDir);
503
509
  if (!idMap.has(id)) {
504
510
  idMap.set(id, []);
505
511
  }
@@ -569,7 +575,7 @@ async function runStatus(options) {
569
575
  }
570
576
  console.log();
571
577
  if (options.write) {
572
- const outputPath = path3.join(featuresDir, "status.md");
578
+ const outputPath = path6.join(featuresDir, "status.md");
573
579
  const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
574
580
  const content = [
575
581
  "# Feature Status",
@@ -636,7 +642,7 @@ async function runUpdate(options) {
636
642
  }
637
643
  const { docsDir, projectType, lang } = config;
638
644
  const templatesDir = getTemplatesDir();
639
- const sourceDir = path3.join(templatesDir, lang, projectType);
645
+ const sourceDir = path6.join(templatesDir, lang, projectType);
640
646
  const updateAgents = options.agents || !options.agents && !options.templates;
641
647
  const updateTemplates = options.templates || !options.agents && !options.templates;
642
648
  console.log(chalk.blue("\u{1F4E6} \uD15C\uD50C\uB9BF \uC5C5\uB370\uC774\uD2B8\uB97C \uC2DC\uC791\uD569\uB2C8\uB2E4..."));
@@ -646,22 +652,32 @@ async function runUpdate(options) {
646
652
  let updatedCount = 0;
647
653
  if (updateAgents) {
648
654
  console.log(chalk.blue("\u{1F4C1} agents/ \uD3F4\uB354 \uC5C5\uB370\uC774\uD2B8 \uC911..."));
649
- const sourceAgents = path3.join(sourceDir, "agents");
650
- const targetAgents = path3.join(docsDir, "agents");
651
- if (await fs6.pathExists(sourceAgents)) {
655
+ const commonAgents = path6.join(templatesDir, lang, "common", "agents");
656
+ const typeAgents = path6.join(templatesDir, lang, projectType, "agents");
657
+ const targetAgents = path6.join(docsDir, "agents");
658
+ const featurePath = projectType === "fullstack" ? "docs/features/{be|fe}" : "docs/features";
659
+ const replacements = {
660
+ "{{featurePath}}": featurePath
661
+ };
662
+ if (await fs6.pathExists(commonAgents)) {
652
663
  const count = await updateFolder(
653
- sourceAgents,
664
+ commonAgents,
654
665
  targetAgents,
655
- options.force
666
+ options.force,
667
+ replacements
656
668
  );
657
669
  updatedCount += count;
658
- console.log(chalk.green(` \u2705 ${count}\uAC1C \uD30C\uC77C \uC5C5\uB370\uC774\uD2B8 \uC644\uB8CC`));
659
670
  }
671
+ if (await fs6.pathExists(typeAgents)) {
672
+ const count = await updateFolder(typeAgents, targetAgents, options.force);
673
+ updatedCount += count;
674
+ }
675
+ console.log(chalk.green(` \u2705 agents/ \uC5C5\uB370\uC774\uD2B8 \uC644\uB8CC`));
660
676
  }
661
677
  if (updateTemplates) {
662
678
  console.log(chalk.blue("\u{1F4C1} features/feature-base/ \uD3F4\uB354 \uC5C5\uB370\uC774\uD2B8 \uC911..."));
663
- const sourceFeatureBase = path3.join(sourceDir, "features", "feature-base");
664
- const targetFeatureBase = path3.join(docsDir, "features", "feature-base");
679
+ const sourceFeatureBase = path6.join(sourceDir, "features", "feature-base");
680
+ const targetFeatureBase = path6.join(docsDir, "features", "feature-base");
665
681
  if (await fs6.pathExists(sourceFeatureBase)) {
666
682
  const count = await updateFolder(
667
683
  sourceFeatureBase,
@@ -675,19 +691,24 @@ async function runUpdate(options) {
675
691
  console.log();
676
692
  console.log(chalk.green(`\u2705 \uCD1D ${updatedCount}\uAC1C \uD30C\uC77C \uC5C5\uB370\uC774\uD2B8 \uC644\uB8CC!`));
677
693
  }
678
- async function updateFolder(sourceDir, targetDir, force) {
694
+ async function updateFolder(sourceDir, targetDir, force, replacements) {
679
695
  await fs6.ensureDir(targetDir);
680
696
  const files = await fs6.readdir(sourceDir);
681
697
  let updatedCount = 0;
682
698
  for (const file of files) {
683
- const sourcePath = path3.join(sourceDir, file);
684
- const targetPath = path3.join(targetDir, file);
699
+ const sourcePath = path6.join(sourceDir, file);
700
+ const targetPath = path6.join(targetDir, file);
685
701
  const stat = await fs6.stat(sourcePath);
686
702
  if (stat.isFile()) {
687
703
  if (file === "custom.md") {
688
704
  continue;
689
705
  }
690
- const sourceContent = await fs6.readFile(sourcePath, "utf-8");
706
+ let sourceContent = await fs6.readFile(sourcePath, "utf-8");
707
+ if (replacements) {
708
+ for (const [key, value] of Object.entries(replacements)) {
709
+ sourceContent = sourceContent.replaceAll(key, value);
710
+ }
711
+ }
691
712
  let shouldUpdate = true;
692
713
  if (await fs6.pathExists(targetPath)) {
693
714
  const targetContent = await fs6.readFile(targetPath, "utf-8");
@@ -707,7 +728,12 @@ async function updateFolder(sourceDir, targetDir, force) {
707
728
  updatedCount++;
708
729
  }
709
730
  } else if (stat.isDirectory()) {
710
- const subCount = await updateFolder(sourcePath, targetPath, force);
731
+ const subCount = await updateFolder(
732
+ sourcePath,
733
+ targetPath,
734
+ force,
735
+ replacements
736
+ );
711
737
  updatedCount += subCount;
712
738
  }
713
739
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lee-spec-kit",
3
- "version": "0.1.8",
3
+ "version": "0.2.0",
4
4
  "description": "Project documentation structure generator for AI-assisted development",
5
5
  "type": "module",
6
6
  "bin": {
@@ -37,6 +37,11 @@ main
37
37
  | `refactor` | Refactoring |
38
38
  | `docs` | Documentation |
39
39
 
40
+ **Examples:**
41
+
42
+ - `feat/123-user-auth`
43
+ - `fix/456-login-error`
44
+
40
45
  ---
41
46
 
42
47
  ## Commit Convention
@@ -65,49 +70,36 @@ main
65
70
 
66
71
  ## Automation Workflow
67
72
 
68
- ### 1. Feature Start
69
-
70
- ```bash
71
- # 1. Create GitHub Issue (Feature = Issue)
72
- # 2. Create branch
73
- git checkout -b feat/{issue-number}-{feature-name}
74
- ```
75
-
76
- ### 2. Document Commit (docs repo)
77
-
78
- > 📌 The docs folder is managed as a separate git, so a separate commit strategy is used.
73
+ > 📖 Refer to `skills/` folder for step-by-step guides.
79
74
 
80
- | # | Commit Timing | Included Documents | Commit Message Example |
81
- | --- | -------------------------------------------------------- | ------------------------------- | ------------------------------- |
82
- | 1 | **When planning is complete** (spec+plan+tasks approved) | spec.md, plan.md, tasks.md | `docs(#123): spec, plan, tasks` |
83
- | 2 | **When Feature is complete** (all tasks done) | tasks.md (status), decisions.md | `docs(#123): Feature complete` |
75
+ | Workflow | Guide |
76
+ | -------------- | -------------------------- |
77
+ | Feature Start | `skills/create-feature.md` |
78
+ | Issue Creation | `skills/create-issue.md` |
79
+ | Task Execution | `skills/execute-task.md` |
80
+ | PR Creation | `skills/create-pr.md` |
84
81
 
85
- > ⚠️ **Do not commit when creating Feature folder.**
86
-
87
- ### 3. Auto Commit on Task Completion
82
+ ### Branch Creation
88
83
 
89
84
  ```bash
90
- git add .
91
- git commit -m "{type}(#{issue}): {task-description}"
85
+ git checkout -b feat/{issue-number}-{feature-name}
92
86
  ```
93
87
 
94
- ### 4. Create PR on Feature Completion
88
+ ### Document Commit Timing (docs repo)
95
89
 
96
- ```bash
97
- git push origin feat/{issue-number}-{feature-name}
98
- gh pr create --title "feat(#{issue}): {feature-title}" \
99
- --body "Closes #{issue}" \
100
- --base main
101
- ```
90
+ | Commit Timing | Included Content | Commit Message Example |
91
+ | ------------------------------------------------- | ----------------------------------- | --------------------------------------------- |
92
+ | When planning complete (spec+plan+tasks approved) | `F{number}-{feature-name}/` folder | `docs(#{issue}): F{number} spec, plan, tasks` |
93
+ | When Feature complete (all tasks done) | `F{number}-{feature-name}/` changes | `docs(#{issue}): F{number} Feature complete` |
102
94
 
103
- ### 5. Merge
95
+ > ⚠️ Do not commit when creating Feature folder.
104
96
 
105
- ```bash
106
- git checkout main
107
- git pull
108
- gh pr merge --squash --delete-branch
109
- git pull
110
- ```
97
+ ### Merge Strategy
98
+
99
+ | Situation | Merge Method |
100
+ | -------------- | ---------------- |
101
+ | Normal Feature | Squash and Merge |
102
+ | Urgent Hotfix | Squash and Merge |
111
103
 
112
104
  ---
113
105
 
@@ -36,12 +36,17 @@ In GitHub Issues, use different link formats **based on file location**:
36
36
  [react-i18next](https://react.i18next.com/)
37
37
  ```
38
38
 
39
- 3. **External/local documents** (no URL available): Use **relative path as text only**
40
- ```text
41
- ../docs/features/F001-feature-name/spec.md
39
+ 3. **Local documents** (no URL available): **Path from project root**
40
+
41
+ > 📁 Local documents use paths **from project root**.
42
+ > Format: `- **{Label}**: \`{path}\``
43
+
44
+ ```markdown
45
+ - **Spec**: `{{featurePath}}/F001-feature-name/spec.md`
46
+ - **Tasks**: `{{featurePath}}/F001-feature-name/tasks.md`
42
47
  ```
43
48
 
44
- > ⚠️ Local documents are not clickable on GitHub, so provide path text only.
49
+ > ⚠️ Local documents are not clickable on GitHub, so use **bold label + code block path** format instead of markdown links.
45
50
 
46
51
  ---
47
52
 
@@ -64,7 +69,7 @@ In GitHub Issues, use different link formats **based on file location**:
64
69
 
65
70
  ## Related Documents
66
71
 
67
- - Spec: `docs/features/F{number}-{feature-name}/spec.md`
72
+ - **Spec**: `{{featurePath}}/F{number}-{feature-name}/spec.md`
68
73
 
69
74
  ## Labels
70
75
 
@@ -42,17 +42,24 @@ For file links within the repo in PR body, **always use current branch name**:
42
42
 
43
43
  ## Tests
44
44
 
45
+ > ⚠️ **Check only after running tests. Do NOT check items that were not executed.**
46
+
45
47
  - [ ] Unit tests passed
46
48
  - [ ] Integration tests completed
47
49
 
50
+ ### Execution Results
51
+
52
+ - Command: `{test command executed}`
53
+ - Result: `{PASS/FAIL summary}`
54
+
48
55
  ## Screenshots (for UI changes)
49
56
 
50
57
  {Attach if applicable}
51
58
 
52
59
  ## Related Documents
53
60
 
54
- - Spec: `docs/features/F{number}-{feature-name}/spec.md`
55
- - Tasks: `docs/features/F{number}-{feature-name}/tasks.md`
61
+ - **Spec**: `{{featurePath}}/F{number}-{feature-name}/spec.md`
62
+ - **Tasks**: `{{featurePath}}/F{number}-{feature-name}/tasks.md`
56
63
 
57
64
  Closes #{issue-number}
58
65
  ```
@@ -0,0 +1,53 @@
1
+ # New Feature Creation Process
2
+
3
+ Step-by-step guide for adding a new Feature.
4
+
5
+ ---
6
+
7
+ ## Steps
8
+
9
+ ### 1. Create Feature Folder
10
+
11
+ ```bash
12
+ npx lee-spec-kit feature <name> -d "<description>"
13
+ ```
14
+
15
+ - `<name>`: Feature name (lowercase, hyphens allowed)
16
+ - `-d`: Feature description (auto-filled in spec.md)
17
+
18
+ **Example:**
19
+
20
+ ```bash
21
+ npx lee-spec-kit feature user-auth -d "User authentication and session management"
22
+ ```
23
+
24
+ ### 2. Write spec.md
25
+
26
+ - **What**: Clearly describe what the feature does
27
+ - **Why**: Explain why this feature is needed
28
+ - ❌ Do NOT include tech stack (covered in plan.md)
29
+
30
+ ### 3. Request User Approval
31
+
32
+ > 🚨 **User Approval Required**
33
+
34
+ Share full spec.md content with user and wait for **explicit approval (OK)**
35
+
36
+ ### 4. Create GitHub Issue
37
+
38
+ → See `skills/create-issue.md`
39
+
40
+ ### 5. Pre-Commit Checklist
41
+
42
+ > ⚠️ **Before committing, verify:**
43
+
44
+ - [ ] Issue number in spec.md (`- **Issue Number**: #{issue}`)
45
+ - [ ] Issue number in tasks.md (`- **Issue**: #{issue}`)
46
+ - [ ] Branch name in tasks.md (`feat/{issue-number}-{feature-name}`)
47
+
48
+ ---
49
+
50
+ ## Reference Documents
51
+
52
+ - **Feature Template**: `features/feature-base/`
53
+ - **Issue Creation Guide**: `skills/create-issue.md`
@@ -0,0 +1,52 @@
1
+ # GitHub Issue Creation Process
2
+
3
+ Guide for creating GitHub Issues.
4
+
5
+ ---
6
+
7
+ ## Prerequisites
8
+
9
+ - [ ] `spec.md` completed
10
+ - [ ] User approval received
11
+
12
+ ---
13
+
14
+ ## Steps
15
+
16
+ ### 1. Prepare Issue Content
17
+
18
+ > 📖 **Always refer to `issue-template.md`**
19
+
20
+ | Item | Format |
21
+ | -------- | ------------------------------------------- |
22
+ | Title | `F{number}: {feature-name} ({description})` |
23
+ | Body | Overview, Goals, Criteria, Related docs |
24
+ | Labels | `enhancement`, `bug`, `documentation`, etc. |
25
+ | Assignee | `@me` (default) |
26
+
27
+ ### 2. Request User Approval
28
+
29
+ > 🚨 **User Approval Required**
30
+
31
+ Before creating issue, share and wait for approval:
32
+
33
+ - Title
34
+ - Body
35
+ - Labels
36
+
37
+ ### 3. Create Issue
38
+
39
+ ```bash
40
+ gh issue create \
41
+ --title "F{number}: {feature-name} ({description})" \
42
+ --body-file /tmp/issue-body.md \
43
+ --assignee @me \
44
+ --label enhancement
45
+ ```
46
+
47
+ ---
48
+
49
+ ## Reference Documents
50
+
51
+ - **Issue Template**: `issue-template.md`
52
+ - **Link Format Rules**: `issue-template.md` > "Link Format" section
@@ -0,0 +1,97 @@
1
+ # Pull Request Creation Process
2
+
3
+ Guide for creating Pull Requests.
4
+
5
+ ---
6
+
7
+ ## Prerequisites
8
+
9
+ - [ ] All tasks in `[DONE]` state
10
+ - [ ] Changes committed
11
+ - [ ] Branch pushed
12
+
13
+ ---
14
+
15
+ ## Steps
16
+
17
+ ### 1. Prepare PR Content
18
+
19
+ > 📖 **Always refer to `pr-template.md`**
20
+
21
+ | Item | Format |
22
+ | -------- | ---------------------------------- |
23
+ | Title | `feat(#{issue-number}): {feature}` |
24
+ | Body | Overview, Changes, Tests, Docs |
25
+ | Labels | Appropriate labels |
26
+ | Assignee | `@me` (default) |
27
+
28
+ ### 2. Test Verification
29
+
30
+ > 🚨 **Cannot create PR if tests fail**
31
+
32
+ 1. Run related test commands (e.g., `npm test`, `pnpm test`)
33
+ 2. Check results (PASS/FAIL)
34
+ 3. Record **execution results** in PR body "Tests" section
35
+ 4. Check boxes **only for items that actually passed**
36
+
37
+ ### 3. Request User Approval
38
+
39
+ > 🚨 **User Approval Required**
40
+
41
+ Before creating PR, share and wait for approval:
42
+
43
+ - Title
44
+ - Body (including test results)
45
+ - Labels
46
+
47
+ ### 4. Create PR
48
+
49
+ ```bash
50
+ gh pr create \
51
+ --title "feat(#{issue-number}): {feature}" \
52
+ --body-file /tmp/pr-body.md \
53
+ --assignee @me \
54
+ --base main
55
+ ```
56
+
57
+ ---
58
+
59
+ ## Important Notes
60
+
61
+ ### Link Format
62
+
63
+ Use **current branch name** for file links in PR body:
64
+
65
+ ```markdown
66
+ [filename](https://github.com/{owner}/{repo}/blob/{branch-name}/path/to/file)
67
+ ```
68
+
69
+ > ⚠️ `main` branch links will return 404 until merged!
70
+
71
+ ---
72
+
73
+ ## Code Review Modification Guidelines
74
+
75
+ > 📋 **Criteria for deciding whether to add a task when modifications are needed from review feedback**
76
+
77
+ ### No task needed (Minor changes)
78
+
79
+ - Typo/code style fixes
80
+ - Variable/function name changes
81
+ - Comment additions/modifications
82
+ - Lint error fixes
83
+
84
+ ### Task needed (Major changes)
85
+
86
+ - Logic/algorithm changes
87
+ - New file/function additions
88
+ - API signature changes
89
+ - Test case additions
90
+ - Requires changes to spec.md or plan.md
91
+
92
+ ---
93
+
94
+ ## Reference Documents
95
+
96
+ - **PR Template**: `pr-template.md`
97
+ - **Git Workflow**: `git-workflow.md`