lee-spec-kit 0.1.7 → 0.1.8

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
@@ -3,12 +3,12 @@ import { program } from 'commander';
3
3
  import prompts from 'prompts';
4
4
  import chalk from 'chalk';
5
5
  import path3 from 'path';
6
- import fs3 from 'fs-extra';
6
+ import fs6 from 'fs-extra';
7
7
  import { glob } from 'glob';
8
8
  import { fileURLToPath } from 'url';
9
9
 
10
10
  async function copyTemplates(src, dest) {
11
- await fs3.copy(src, dest, {
11
+ await fs6.copy(src, dest, {
12
12
  overwrite: true,
13
13
  errorOnExist: false
14
14
  });
@@ -16,19 +16,19 @@ async function copyTemplates(src, dest) {
16
16
  async function replaceInFiles(dir, replacements) {
17
17
  const files = await glob("**/*.md", { cwd: dir, absolute: true });
18
18
  for (const file of files) {
19
- let content = await fs3.readFile(file, "utf-8");
19
+ let content = await fs6.readFile(file, "utf-8");
20
20
  for (const [search, replace] of Object.entries(replacements)) {
21
21
  content = content.replaceAll(search, replace);
22
22
  }
23
- await fs3.writeFile(file, content, "utf-8");
23
+ await fs6.writeFile(file, content, "utf-8");
24
24
  }
25
25
  const shFiles = await glob("**/*.sh", { cwd: dir, absolute: true });
26
26
  for (const file of shFiles) {
27
- let content = await fs3.readFile(file, "utf-8");
27
+ let content = await fs6.readFile(file, "utf-8");
28
28
  for (const [search, replace] of Object.entries(replacements)) {
29
29
  content = content.replaceAll(search, replace);
30
30
  }
31
- await fs3.writeFile(file, content, "utf-8");
31
+ await fs6.writeFile(file, content, "utf-8");
32
32
  }
33
33
  }
34
34
  var __filename2 = fileURLToPath(import.meta.url);
@@ -209,8 +209,8 @@ async function runInit(options) {
209
209
  assertValid(validateSafeName(projectName), "\uD504\uB85C\uC81D\uD2B8 \uC774\uB984");
210
210
  assertValid(validateProjectType(projectType), "\uD504\uB85C\uC81D\uD2B8 \uD0C0\uC785");
211
211
  assertValid(validateLanguage(lang), "\uC5B8\uC5B4");
212
- if (await fs3.pathExists(targetDir)) {
213
- const files = await fs3.readdir(targetDir);
212
+ if (await fs6.pathExists(targetDir)) {
213
+ const files = await fs6.readdir(targetDir);
214
214
  if (files.length > 0) {
215
215
  const { overwrite } = await prompts({
216
216
  type: "confirm",
@@ -233,7 +233,7 @@ async function runInit(options) {
233
233
  console.log();
234
234
  const templatesDir = getTemplatesDir();
235
235
  const templatePath = path3.join(templatesDir, lang, projectType);
236
- if (!await fs3.pathExists(templatePath)) {
236
+ if (!await fs6.pathExists(templatePath)) {
237
237
  throw new Error(`\uD15C\uD50C\uB9BF\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${templatePath}`);
238
238
  }
239
239
  await copyTemplates(templatePath, targetDir);
@@ -249,7 +249,7 @@ async function runInit(options) {
249
249
  createdAt: (/* @__PURE__ */ new Date()).toISOString().split("T")[0]
250
250
  };
251
251
  const configPath = path3.join(targetDir, ".lee-spec-kit.json");
252
- await fs3.writeJson(configPath, config, { spaces: 2 });
252
+ await fs6.writeJson(configPath, config, { spaces: 2 });
253
253
  console.log(chalk.green("\u2705 docs \uAD6C\uC870 \uC0DD\uC131 \uC644\uB8CC!"));
254
254
  console.log();
255
255
  await initGit(cwd, targetDir);
@@ -296,9 +296,9 @@ async function getConfig(cwd) {
296
296
  ];
297
297
  for (const docsDir of possibleDirs) {
298
298
  const configPath = path3.join(docsDir, ".lee-spec-kit.json");
299
- if (await fs3.pathExists(configPath)) {
299
+ if (await fs6.pathExists(configPath)) {
300
300
  try {
301
- const configFile = await fs3.readJson(configPath);
301
+ const configFile = await fs6.readJson(configPath);
302
302
  return {
303
303
  docsDir,
304
304
  projectName: configFile.projectName,
@@ -310,14 +310,14 @@ async function getConfig(cwd) {
310
310
  }
311
311
  const agentsPath = path3.join(docsDir, "agents");
312
312
  const featuresPath = path3.join(docsDir, "features");
313
- if (await fs3.pathExists(agentsPath) && await fs3.pathExists(featuresPath)) {
313
+ if (await fs6.pathExists(agentsPath) && await fs6.pathExists(featuresPath)) {
314
314
  const bePath = path3.join(featuresPath, "be");
315
315
  const fePath = path3.join(featuresPath, "fe");
316
- const projectType = await fs3.pathExists(bePath) || await fs3.pathExists(fePath) ? "fullstack" : "single";
316
+ const projectType = await fs6.pathExists(bePath) || await fs6.pathExists(fePath) ? "fullstack" : "single";
317
317
  const agentsMdPath = path3.join(agentsPath, "agents.md");
318
318
  let lang = "ko";
319
- if (await fs3.pathExists(agentsMdPath)) {
320
- const content = await fs3.readFile(agentsMdPath, "utf-8");
319
+ if (await fs6.pathExists(agentsMdPath)) {
320
+ const content = await fs6.readFile(agentsMdPath, "utf-8");
321
321
  if (!/[가-힣]/.test(content)) {
322
322
  lang = "en";
323
323
  }
@@ -392,16 +392,16 @@ async function runFeature(name, options) {
392
392
  }
393
393
  const featureFolderName = `${featureId}-${name}`;
394
394
  const featureDir = path3.join(featuresDir, featureFolderName);
395
- if (await fs3.pathExists(featureDir)) {
395
+ if (await fs6.pathExists(featureDir)) {
396
396
  console.error(chalk.red(`\uC774\uBBF8 \uC874\uC7AC\uD558\uB294 \uD3F4\uB354\uC785\uB2C8\uB2E4: ${featureDir}`));
397
397
  process.exit(1);
398
398
  }
399
399
  const featureBasePath = path3.join(docsDir, "features", "feature-base");
400
- if (!await fs3.pathExists(featureBasePath)) {
400
+ if (!await fs6.pathExists(featureBasePath)) {
401
401
  console.error(chalk.red("feature-base \uD15C\uD50C\uB9BF\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4."));
402
402
  process.exit(1);
403
403
  }
404
- await fs3.copy(featureBasePath, featureDir);
404
+ await fs6.copy(featureBasePath, featureDir);
405
405
  const idNumber = featureId.replace("F", "");
406
406
  const repoName = projectType === "fullstack" && repo ? `{{projectName}}-${repo}` : "{{projectName}}";
407
407
  const replacements = {
@@ -442,8 +442,8 @@ async function getNextFeatureId(docsDir, projectType) {
442
442
  scanDirs.push(featuresDir);
443
443
  }
444
444
  for (const dir of scanDirs) {
445
- if (!await fs3.pathExists(dir)) continue;
446
- const entries = await fs3.readdir(dir, { withFileTypes: true });
445
+ if (!await fs6.pathExists(dir)) continue;
446
+ const entries = await fs6.readdir(dir, { withFileTypes: true });
447
447
  for (const entry of entries) {
448
448
  if (!entry.isDirectory()) continue;
449
449
  const match = entry.name.match(/^F(\d+)-/);
@@ -483,18 +483,18 @@ async function runStatus(options) {
483
483
  const scopes = projectType === "fullstack" ? ["be", "fe"] : [""];
484
484
  for (const scope of scopes) {
485
485
  const scanDir = scope ? path3.join(featuresDir, scope) : featuresDir;
486
- if (!await fs3.pathExists(scanDir)) continue;
487
- const entries = await fs3.readdir(scanDir, { withFileTypes: true });
486
+ if (!await fs6.pathExists(scanDir)) continue;
487
+ const entries = await fs6.readdir(scanDir, { withFileTypes: true });
488
488
  for (const entry of entries) {
489
489
  if (!entry.isDirectory()) continue;
490
490
  if (entry.name === "feature-base") continue;
491
491
  const featureDir = path3.join(scanDir, entry.name);
492
492
  const specPath = path3.join(featureDir, "spec.md");
493
493
  const tasksPath = path3.join(featureDir, "tasks.md");
494
- if (!await fs3.pathExists(specPath)) continue;
495
- if (!await fs3.pathExists(tasksPath)) continue;
496
- const specContent = await fs3.readFile(specPath, "utf-8");
497
- const tasksContent = await fs3.readFile(tasksPath, "utf-8");
494
+ if (!await fs6.pathExists(specPath)) continue;
495
+ if (!await fs6.pathExists(tasksPath)) continue;
496
+ const specContent = await fs6.readFile(specPath, "utf-8");
497
+ const tasksContent = await fs6.readFile(tasksPath, "utf-8");
498
498
  const id = extractSpecValue(specContent, "\uAE30\uB2A5 ID") || extractSpecValue(specContent, "Feature ID") || "UNKNOWN";
499
499
  const name = extractSpecValue(specContent, "\uAE30\uB2A5\uBA85") || extractSpecValue(specContent, "Feature Name") || entry.name;
500
500
  const repo = extractSpecValue(specContent, "\uB300\uC0C1 \uB808\uD3EC") || extractSpecValue(specContent, "Target Repo") || (scope ? `{{projectName}}-${scope}` : "{{projectName}}");
@@ -584,7 +584,7 @@ async function runStatus(options) {
584
584
  ),
585
585
  ""
586
586
  ].join("\n");
587
- await fs3.writeFile(outputPath, content, "utf-8");
587
+ await fs6.writeFile(outputPath, content, "utf-8");
588
588
  console.log(chalk.green(`\u2705 ${outputPath} \uC0DD\uC131 \uC644\uB8CC`));
589
589
  }
590
590
  }
@@ -611,6 +611,108 @@ function countTasks(content) {
611
611
  }
612
612
  return { total, done, doing, todo };
613
613
  }
614
+ function updateCommand(program2) {
615
+ 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) => {
616
+ try {
617
+ await runUpdate(options);
618
+ } catch (error) {
619
+ if (error instanceof Error && error.message === "canceled") {
620
+ console.log(chalk.yellow("\n\uC791\uC5C5\uC774 \uCDE8\uC18C\uB418\uC5C8\uC2B5\uB2C8\uB2E4."));
621
+ process.exit(0);
622
+ }
623
+ console.error(chalk.red("\uC624\uB958:"), error);
624
+ process.exit(1);
625
+ }
626
+ });
627
+ }
628
+ async function runUpdate(options) {
629
+ const cwd = process.cwd();
630
+ const config = await getConfig(cwd);
631
+ if (!config) {
632
+ console.error(
633
+ chalk.red("docs \uD3F4\uB354\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uBA3C\uC800 init\uC744 \uC2E4\uD589\uD558\uC138\uC694.")
634
+ );
635
+ process.exit(1);
636
+ }
637
+ const { docsDir, projectType, lang } = config;
638
+ const templatesDir = getTemplatesDir();
639
+ const sourceDir = path3.join(templatesDir, lang, projectType);
640
+ const updateAgents = options.agents || !options.agents && !options.templates;
641
+ const updateTemplates = options.templates || !options.agents && !options.templates;
642
+ console.log(chalk.blue("\u{1F4E6} \uD15C\uD50C\uB9BF \uC5C5\uB370\uC774\uD2B8\uB97C \uC2DC\uC791\uD569\uB2C8\uB2E4..."));
643
+ console.log(chalk.gray(` - \uC5B8\uC5B4: ${lang}`));
644
+ console.log(chalk.gray(` - \uD0C0\uC785: ${projectType}`));
645
+ console.log();
646
+ let updatedCount = 0;
647
+ if (updateAgents) {
648
+ 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)) {
652
+ const count = await updateFolder(
653
+ sourceAgents,
654
+ targetAgents,
655
+ options.force
656
+ );
657
+ updatedCount += count;
658
+ console.log(chalk.green(` \u2705 ${count}\uAC1C \uD30C\uC77C \uC5C5\uB370\uC774\uD2B8 \uC644\uB8CC`));
659
+ }
660
+ }
661
+ if (updateTemplates) {
662
+ 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");
665
+ if (await fs6.pathExists(sourceFeatureBase)) {
666
+ const count = await updateFolder(
667
+ sourceFeatureBase,
668
+ targetFeatureBase,
669
+ options.force
670
+ );
671
+ updatedCount += count;
672
+ console.log(chalk.green(` \u2705 ${count}\uAC1C \uD30C\uC77C \uC5C5\uB370\uC774\uD2B8 \uC644\uB8CC`));
673
+ }
674
+ }
675
+ console.log();
676
+ console.log(chalk.green(`\u2705 \uCD1D ${updatedCount}\uAC1C \uD30C\uC77C \uC5C5\uB370\uC774\uD2B8 \uC644\uB8CC!`));
677
+ }
678
+ async function updateFolder(sourceDir, targetDir, force) {
679
+ await fs6.ensureDir(targetDir);
680
+ const files = await fs6.readdir(sourceDir);
681
+ let updatedCount = 0;
682
+ for (const file of files) {
683
+ const sourcePath = path3.join(sourceDir, file);
684
+ const targetPath = path3.join(targetDir, file);
685
+ const stat = await fs6.stat(sourcePath);
686
+ if (stat.isFile()) {
687
+ if (file === "custom.md") {
688
+ continue;
689
+ }
690
+ const sourceContent = await fs6.readFile(sourcePath, "utf-8");
691
+ let shouldUpdate = true;
692
+ if (await fs6.pathExists(targetPath)) {
693
+ const targetContent = await fs6.readFile(targetPath, "utf-8");
694
+ if (sourceContent === targetContent) {
695
+ continue;
696
+ }
697
+ if (!force) {
698
+ console.log(
699
+ chalk.yellow(` \u26A0\uFE0F ${file} - \uBCC0\uACBD \uAC10\uC9C0 (--force\uB85C \uB36E\uC5B4\uC4F0\uAE30)`)
700
+ );
701
+ shouldUpdate = false;
702
+ }
703
+ }
704
+ if (shouldUpdate) {
705
+ await fs6.writeFile(targetPath, sourceContent);
706
+ console.log(chalk.gray(` \u{1F4C4} ${file} \uC5C5\uB370\uC774\uD2B8`));
707
+ updatedCount++;
708
+ }
709
+ } else if (stat.isDirectory()) {
710
+ const subCount = await updateFolder(sourcePath, targetPath, force);
711
+ updatedCount += subCount;
712
+ }
713
+ }
714
+ return updatedCount;
715
+ }
614
716
 
615
717
  // src/index.ts
616
718
  program.name("lee-spec-kit").description(
@@ -619,4 +721,5 @@ program.name("lee-spec-kit").description(
619
721
  initCommand(program);
620
722
  featureCommand(program);
621
723
  statusCommand(program);
724
+ updateCommand(program);
622
725
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lee-spec-kit",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "Project documentation structure generator for AI-assisted development",
5
5
  "type": "module",
6
6
  "bin": {
@@ -12,6 +12,13 @@
12
12
  "dist",
13
13
  "templates"
14
14
  ],
15
+ "scripts": {
16
+ "build": "tsup",
17
+ "dev": "tsup --watch",
18
+ "lint": "eslint src",
19
+ "format": "prettier --write .",
20
+ "prepublishOnly": "pnpm build"
21
+ },
15
22
  "keywords": [
16
23
  "docs",
17
24
  "template",
@@ -49,10 +56,5 @@
49
56
  "tsup": "^8.5.1",
50
57
  "typescript": "^5.9.3"
51
58
  },
52
- "scripts": {
53
- "build": "tsup",
54
- "dev": "tsup --watch",
55
- "lint": "eslint src",
56
- "format": "prettier --write ."
57
- }
58
- }
59
+ "packageManager": "pnpm@10.7.0"
60
+ }
@@ -4,10 +4,38 @@ Operating rules for AI code assistants to perform consistent code generation and
4
4
 
5
5
  ---
6
6
 
7
+ ## 🚨 User Approval Required (MUST)
8
+
9
+ > ⚠️ **The following actions require explicit user approval (OK) before proceeding.**
10
+ > **If approval is not given, stop immediately and request confirmation.**
11
+
12
+ | Action | When to Confirm | What to Share |
13
+ | --------------------- | ------------------------ | ------------------------- |
14
+ | Spec Writing | After writing `spec.md` | Full spec content |
15
+ | Task Execution | Before each task | Execution plan |
16
+ | Commit Creation | Before `git commit` | Commit message, file list |
17
+ | Issue Creation | Before `gh issue create` | Title, body, labels |
18
+ | PR Creation | Before `gh pr create` | Title, body, labels |
19
+ | Assignee Change | When assigning others | Target username |
20
+ | Remote Git Operations | Before `push`, `merge` | Branch, changes |
21
+
22
+ ### Approval Process
23
+
24
+ 1. **Share** action details with user first
25
+ 2. **Wait** for explicit user approval (OK)
26
+ 3. **Execute** only after approval
27
+
28
+ > 🚫 **Prohibited**: Proceeding without user response
29
+
30
+ ---
31
+
7
32
  ## Reference Documents
8
33
 
9
34
  ### Core Documents
10
35
 
36
+ > ⚠️ **Rules in `custom.md` take precedence over all other rules.**
37
+
38
+ - **🔴 Custom Rules (Highest Priority)**: `/docs/agents/custom.md`
11
39
  - **Project Principles**: `/docs/agents/constitution.md`
12
40
  - **Git Workflow**: `/docs/agents/git-workflow.md`
13
41
  - **Issue Template**: `/docs/agents/issue-template.md`
@@ -0,0 +1,29 @@
1
+ # Custom Rules
2
+
3
+ > ⚠️ This document contains **user-defined rules**.
4
+ > It is NOT affected by `npx lee-spec-kit update`.
5
+ > **Rules in this document take precedence over all other agent rules.**
6
+
7
+ ---
8
+
9
+ ## Project-Specific Rules
10
+
11
+ (Write your project-specific rules here)
12
+
13
+ ---
14
+
15
+ ## Additional Language/Code Rules
16
+
17
+ (Override default rules or add additional rules here)
18
+
19
+ ---
20
+
21
+ ## Custom Workflows
22
+
23
+ (Write project-specific workflows here)
24
+
25
+ ---
26
+
27
+ ## Other
28
+
29
+ (Write other rules here)
@@ -73,17 +73,16 @@ main
73
73
  git checkout -b feat/{issue-number}-{feature-name}
74
74
  ```
75
75
 
76
- ### 2. Document Writing and Commit
76
+ ### 2. Document Commit (docs repo)
77
77
 
78
- | Document | Commit Timing | Commit Message Example |
79
- | ------------ | ----------------------- | ------------------------------ |
80
- | spec.md | After user approval | `docs(#123): write spec` |
81
- | plan.md | After user approval | `docs(#123): write plan` |
82
- | tasks.md | After user approval | `docs(#123): break down tasks` |
83
- | decisions.md | Included in task commit | (no separate commit) |
78
+ > 📌 The docs folder is managed as a separate git, so a separate commit strategy is used.
84
79
 
85
- > 📌 **Do not commit when creating Feature folder.**
86
- > Commit each document individually **after user approval**.
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` |
84
+
85
+ > ⚠️ **Do not commit when creating Feature folder.**
87
86
 
88
87
  ### 3. Auto Commit on Task Completion
89
88
 
@@ -4,10 +4,38 @@ Operating rules for AI code assistants to perform consistent code generation and
4
4
 
5
5
  ---
6
6
 
7
+ ## 🚨 User Approval Required (MUST)
8
+
9
+ > ⚠️ **The following actions require explicit user approval (OK) before proceeding.**
10
+ > **If approval is not given, stop immediately and request confirmation.**
11
+
12
+ | Action | When to Confirm | What to Share |
13
+ | --------------------- | ------------------------ | ------------------------- |
14
+ | Spec Writing | After writing `spec.md` | Full spec content |
15
+ | Task Execution | Before each task | Execution plan |
16
+ | Commit Creation | Before `git commit` | Commit message, file list |
17
+ | Issue Creation | Before `gh issue create` | Title, body, labels |
18
+ | PR Creation | Before `gh pr create` | Title, body, labels |
19
+ | Assignee Change | When assigning others | Target username |
20
+ | Remote Git Operations | Before `push`, `merge` | Branch, changes |
21
+
22
+ ### Approval Process
23
+
24
+ 1. **Share** action details with user first
25
+ 2. **Wait** for explicit user approval (OK)
26
+ 3. **Execute** only after approval
27
+
28
+ > 🚫 **Prohibited**: Proceeding without user response
29
+
30
+ ---
31
+
7
32
  ## Reference Documents
8
33
 
9
34
  ### Core Documents
10
35
 
36
+ > ⚠️ **Rules in `custom.md` take precedence over all other rules.**
37
+
38
+ - **🔴 Custom Rules (Highest Priority)**: `/docs/agents/custom.md`
11
39
  - **Project Principles**: `/docs/agents/constitution.md`
12
40
  - **Git Workflow**: `/docs/agents/git-workflow.md`
13
41
  - **Issue Template**: `/docs/agents/issue-template.md`
@@ -0,0 +1,29 @@
1
+ # Custom Rules
2
+
3
+ > ⚠️ This document contains **user-defined rules**.
4
+ > It is NOT affected by `npx lee-spec-kit update`.
5
+ > **Rules in this document take precedence over all other agent rules.**
6
+
7
+ ---
8
+
9
+ ## Project-Specific Rules
10
+
11
+ (Write your project-specific rules here)
12
+
13
+ ---
14
+
15
+ ## Additional Language/Code Rules
16
+
17
+ (Override default rules or add additional rules here)
18
+
19
+ ---
20
+
21
+ ## Custom Workflows
22
+
23
+ (Write project-specific workflows here)
24
+
25
+ ---
26
+
27
+ ## Other
28
+
29
+ (Write other rules here)
@@ -80,17 +80,16 @@ git checkout -b feat/{issue-number}-{feature-name}
80
80
 
81
81
  > When creating/modifying issues/PRs with `gh`, share the title/body/labels first and **wait for user confirmation (OK)** before proceeding.
82
82
 
83
- ### 2. Document Writing and Commit
83
+ ### 2. Document Commit (docs repo)
84
84
 
85
- | Document | Commit Timing | Commit Message Example |
86
- | ------------ | ----------------------- | ------------------------------ |
87
- | spec.md | After user approval | `docs(#123): write spec` |
88
- | plan.md | After user approval | `docs(#123): write plan` |
89
- | tasks.md | After user approval | `docs(#123): break down tasks` |
90
- | decisions.md | Included in task commit | (no separate commit) |
85
+ > 📌 The docs folder is managed as a separate git, so a separate commit strategy is used.
91
86
 
92
- > 📌 **Do not commit when creating Feature folder.**
93
- > Commit each document individually **after user approval**.
87
+ | # | Commit Timing | Included Documents | Commit Message Example |
88
+ | --- | -------------------------------------------------------- | ------------------------------- | ------------------------------- |
89
+ | 1 | **When planning is complete** (spec+plan+tasks approved) | spec.md, plan.md, tasks.md | `docs(#123): spec, plan, tasks` |
90
+ | 2 | **When Feature is complete** (all tasks done) | tasks.md (status), decisions.md | `docs(#123): Feature complete` |
91
+
92
+ > ⚠️ **Do not commit when creating Feature folder.**
94
93
 
95
94
  ### 3. Auto Commit on Task Completion
96
95
 
@@ -4,10 +4,38 @@
4
4
 
5
5
  ---
6
6
 
7
+ ## 🚨 사용자 확인 필수 규칙 (MUST)
8
+
9
+ > ⚠️ **아래 작업은 반드시 사용자의 명시적 승인(OK)을 받은 후에만 진행합니다.**
10
+ > **확인 없이 진행 시 작업을 즉시 중단해야 합니다.**
11
+
12
+ | 작업 | 확인 시점 | 공유 내용 |
13
+ | ------------- | -------------------- | --------------------------- |
14
+ | 스펙 작성 | `spec.md` 작성 후 | 스펙 내용 전문 |
15
+ | 태스크 실행 | 각 태스크 시작 전 | 실행 계획 |
16
+ | 커밋 생성 | `git commit` 전 | 커밋 메시지, 포함 파일 목록 |
17
+ | 이슈 생성 | `gh issue create` 전 | 제목, 본문, 라벨 |
18
+ | PR 생성 | `gh pr create` 전 | 제목, 본문, 라벨 |
19
+ | Assignee 변경 | 본인 외 지정 시 | 대상 사용자명 |
20
+ | Git 원격 작업 | `push`, `merge` 전 | 브랜치, 변경 사항 |
21
+
22
+ ### 확인 프로세스
23
+
24
+ 1. 작업 내용을 사용자에게 **먼저 공유**
25
+ 2. 사용자의 **명시적 승인(OK)** 대기
26
+ 3. 승인 후에만 실행
27
+
28
+ > 🚫 **금지 사항**: 사용자 응답 없이 임의로 진행하는 것
29
+
30
+ ---
31
+
7
32
  ## 참조 문서
8
33
 
9
34
  ### 핵심 문서
10
35
 
36
+ > ⚠️ **`custom.md`의 규칙은 다른 모든 규칙보다 우선합니다.**
37
+
38
+ - **🔴 커스텀 규칙 (최우선)**: `/docs/agents/custom.md`
11
39
  - **프로젝트 원칙**: `/docs/agents/constitution.md`
12
40
  - **Git 워크플로우**: `/docs/agents/git-workflow.md`
13
41
  - **이슈 템플릿**: `/docs/agents/issue-template.md`
@@ -0,0 +1,29 @@
1
+ # Custom Rules
2
+
3
+ > ⚠️ 이 문서는 **사용자 정의 규칙**입니다.
4
+ > `npx lee-spec-kit update`의 영향을 받지 않습니다.
5
+ > **이 문서의 규칙은 다른 모든 agents 규칙보다 우선합니다.**
6
+
7
+ ---
8
+
9
+ ## 프로젝트 특화 규칙
10
+
11
+ (여기에 프로젝트만의 규칙을 작성하세요)
12
+
13
+ ---
14
+
15
+ ## 추가 언어/코드 규칙
16
+
17
+ (기본 규칙을 오버라이드하거나 추가 규칙을 작성하세요)
18
+
19
+ ---
20
+
21
+ ## 커스텀 워크플로우
22
+
23
+ (프로젝트만의 워크플로우가 있다면 작성하세요)
24
+
25
+ ---
26
+
27
+ ## 기타
28
+
29
+ (기타 규칙을 작성하세요)
@@ -80,17 +80,16 @@ git checkout -b feat/{issue-number}-{feature-name}
80
80
 
81
81
  > `gh`로 이슈/PR 생성·수정 시 작성할 제목/본문/라벨을 먼저 공유하고 **반드시** 사용자 확인(OK) 후 진행합니다.
82
82
 
83
- ### 2. 문서 작성 커밋
83
+ ### 2. 문서 커밋 (docs 레포)
84
84
 
85
- | 문서 | 커밋 시점 | 커밋 메시지 예시 |
86
- | ------------ | ------------------ | ------------------------ |
87
- | spec.md | 사용자 승인 후 | `docs(#123): spec 작성` |
88
- | plan.md | 사용자 승인 후 | `docs(#123): plan 작성` |
89
- | tasks.md | 사용자 승인 후 | `docs(#123): tasks 분해` |
90
- | decisions.md | 태스크 커밋에 포함 | (별도 커밋 없음) |
85
+ > 📌 docs 폴더는 별도 git으로 관리되므로 프로젝트와 분리된 커밋 전략을 사용합니다.
91
86
 
92
- > 📌 **Feature 폴더 생성 시점**에는 커밋하지 않습니다.
93
- > 문서가 **사용자 승인**을 받은 개별 커밋합니다.
87
+ | # | 커밋 시점 | 포함 문서 | 커밋 메시지 예시 |
88
+ | --- | ------------------------------------------ | ----------------------------- | ------------------------------------ |
89
+ | 1 | **계획 완료 시** (spec+plan+tasks 승인 후) | spec.md, plan.md, tasks.md | `docs(#123): spec, plan, tasks 작성` |
90
+ | 2 | **Feature 완료 시** (모든 태스크 완료 후) | tasks.md (상태), decisions.md | `docs(#123): Feature 완료` |
91
+
92
+ > ⚠️ **Feature 폴더 생성 시점**에는 커밋하지 않습니다.
94
93
 
95
94
  ### 3. 태스크 완료 시 자동 커밋
96
95
 
@@ -4,10 +4,38 @@
4
4
 
5
5
  ---
6
6
 
7
+ ## 🚨 사용자 확인 필수 규칙 (MUST)
8
+
9
+ > ⚠️ **아래 작업은 반드시 사용자의 명시적 승인(OK)을 받은 후에만 진행합니다.**
10
+ > **확인 없이 진행 시 작업을 즉시 중단해야 합니다.**
11
+
12
+ | 작업 | 확인 시점 | 공유 내용 |
13
+ | ------------- | -------------------- | --------------------------- |
14
+ | 스펙 작성 | `spec.md` 작성 후 | 스펙 내용 전문 |
15
+ | 태스크 실행 | 각 태스크 시작 전 | 실행 계획 |
16
+ | 커밋 생성 | `git commit` 전 | 커밋 메시지, 포함 파일 목록 |
17
+ | 이슈 생성 | `gh issue create` 전 | 제목, 본문, 라벨 |
18
+ | PR 생성 | `gh pr create` 전 | 제목, 본문, 라벨 |
19
+ | Assignee 변경 | 본인 외 지정 시 | 대상 사용자명 |
20
+ | Git 원격 작업 | `push`, `merge` 전 | 브랜치, 변경 사항 |
21
+
22
+ ### 확인 프로세스
23
+
24
+ 1. 작업 내용을 사용자에게 **먼저 공유**
25
+ 2. 사용자의 **명시적 승인(OK)** 대기
26
+ 3. 승인 후에만 실행
27
+
28
+ > 🚫 **금지 사항**: 사용자 응답 없이 임의로 진행하는 것
29
+
30
+ ---
31
+
7
32
  ## 참조 문서
8
33
 
9
34
  ### 핵심 문서
10
35
 
36
+ > ⚠️ **`custom.md`의 규칙은 다른 모든 규칙보다 우선합니다.**
37
+
38
+ - **🔴 커스텀 규칙 (최우선)**: `/docs/agents/custom.md`
11
39
  - **프로젝트 원칙**: `/docs/agents/constitution.md`
12
40
  - **Git 워크플로우**: `/docs/agents/git-workflow.md`
13
41
  - **이슈 템플릿**: `/docs/agents/issue-template.md`
@@ -0,0 +1,29 @@
1
+ # Custom Rules
2
+
3
+ > ⚠️ 이 문서는 **사용자 정의 규칙**입니다.
4
+ > `npx lee-spec-kit update`의 영향을 받지 않습니다.
5
+ > **이 문서의 규칙은 다른 모든 agents 규칙보다 우선합니다.**
6
+
7
+ ---
8
+
9
+ ## 프로젝트 특화 규칙
10
+
11
+ (여기에 프로젝트만의 규칙을 작성하세요)
12
+
13
+ ---
14
+
15
+ ## 추가 언어/코드 규칙
16
+
17
+ (기본 규칙을 오버라이드하거나 추가 규칙을 작성하세요)
18
+
19
+ ---
20
+
21
+ ## 커스텀 워크플로우
22
+
23
+ (프로젝트만의 워크플로우가 있다면 작성하세요)
24
+
25
+ ---
26
+
27
+ ## 기타
28
+
29
+ (기타 규칙을 작성하세요)
@@ -80,17 +80,16 @@ git checkout -b feat/{issue-number}-{feature-name}
80
80
 
81
81
  > `gh`로 이슈/PR 생성·수정 시 작성할 제목/본문/라벨을 먼저 공유하고 **반드시** 사용자 확인(OK) 후 진행합니다.
82
82
 
83
- ### 2. 문서 작성 커밋
83
+ ### 2. 문서 커밋 (docs 레포)
84
84
 
85
- | 문서 | 커밋 시점 | 커밋 메시지 예시 |
86
- | ------------ | ------------------ | ------------------------ |
87
- | spec.md | 사용자 승인 후 | `docs(#123): spec 작성` |
88
- | plan.md | 사용자 승인 후 | `docs(#123): plan 작성` |
89
- | tasks.md | 사용자 승인 후 | `docs(#123): tasks 분해` |
90
- | decisions.md | 태스크 커밋에 포함 | (별도 커밋 없음) |
85
+ > 📌 docs 폴더는 별도 git으로 관리되므로 프로젝트와 분리된 커밋 전략을 사용합니다.
91
86
 
92
- > 📌 **Feature 폴더 생성 시점**에는 커밋하지 않습니다.
93
- > 문서가 **사용자 승인**을 받은 개별 커밋합니다.
87
+ | # | 커밋 시점 | 포함 문서 | 커밋 메시지 예시 |
88
+ | --- | ------------------------------------------ | ----------------------------- | ------------------------------------ |
89
+ | 1 | **계획 완료 시** (spec+plan+tasks 승인 후) | spec.md, plan.md, tasks.md | `docs(#123): spec, plan, tasks 작성` |
90
+ | 2 | **Feature 완료 시** (모든 태스크 완료 후) | tasks.md (상태), decisions.md | `docs(#123): Feature 완료` |
91
+
92
+ > ⚠️ **Feature 폴더 생성 시점**에는 커밋하지 않습니다.
94
93
 
95
94
  ### 3. 태스크 완료 시 자동 커밋
96
95