sdd-tool 1.3.0 → 1.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -10
- package/dist/cli/index.js +138 -82
- package/dist/cli/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -345,11 +345,17 @@ sdd list # 목록 조회
|
|
|
345
345
|
### 기능 개발
|
|
346
346
|
|
|
347
347
|
```bash
|
|
348
|
-
sdd new <name> # 새 기능 생성
|
|
348
|
+
sdd new <name> # 새 기능 생성 (common 도메인)
|
|
349
|
+
sdd new <name> -d <domain> # 도메인 지정 생성 (v1.3.0)
|
|
349
350
|
sdd new <name> --all # spec + plan + tasks 모두 생성
|
|
350
351
|
sdd prepare <name> # 서브에이전트/스킬 점검
|
|
351
352
|
```
|
|
352
353
|
|
|
354
|
+
**v1.3.0 도메인 기반 구조:**
|
|
355
|
+
- 도메인 미지정 시 `common` 폴더에 생성
|
|
356
|
+
- 경로: `.sdd/specs/<domain>/<feature>/spec.md`
|
|
357
|
+
- 예: `sdd new login -d auth` → `.sdd/specs/auth/login/spec.md`
|
|
358
|
+
|
|
353
359
|
### 변경 관리
|
|
354
360
|
|
|
355
361
|
```bash
|
|
@@ -458,17 +464,20 @@ your-project/
|
|
|
458
464
|
│ ├── AGENTS.md # AI 워크플로우 가이드
|
|
459
465
|
│ ├── domains.yml # 도메인 정의 (v1.2.0)
|
|
460
466
|
│ ├── .context.json # 현재 컨텍스트 (v1.2.0)
|
|
461
|
-
│ ├── specs/ # 기능 명세
|
|
462
|
-
│ │ ├──
|
|
463
|
-
│ │ │
|
|
464
|
-
│ │ │
|
|
465
|
-
│ │ │
|
|
466
|
-
│ │ └──
|
|
467
|
-
│ │
|
|
468
|
-
│ │
|
|
467
|
+
│ ├── specs/ # 기능 명세 (v1.3.0: 도메인 기반 구조)
|
|
468
|
+
│ │ ├── common/ # 기본 도메인 (도메인 미지정 시)
|
|
469
|
+
│ │ │ └── feature-name/
|
|
470
|
+
│ │ │ ├── spec.md
|
|
471
|
+
│ │ │ ├── plan.md
|
|
472
|
+
│ │ │ └── tasks.md
|
|
473
|
+
│ │ └── auth/ # 도메인별 그룹
|
|
474
|
+
│ │ └── login/
|
|
475
|
+
│ │ ├── spec.md
|
|
476
|
+
│ │ ├── plan.md
|
|
477
|
+
│ │ └── tasks.md
|
|
469
478
|
│ ├── changes/ # 변경 제안
|
|
470
479
|
│ ├── archive/ # 완료된 변경
|
|
471
|
-
│ └── drafts/
|
|
480
|
+
│ └── .reverse-drafts/ # 역추출 임시 스펙 (v1.2.0)
|
|
472
481
|
│
|
|
473
482
|
└── .claude/
|
|
474
483
|
├── commands/ # 슬래시 커맨드 (29개)
|
package/dist/cli/index.js
CHANGED
|
@@ -1954,8 +1954,8 @@ var validateCommand = {
|
|
|
1954
1954
|
# \uC804\uCCB4 \uC2A4\uD399 \uAC80\uC99D
|
|
1955
1955
|
sdd validate
|
|
1956
1956
|
|
|
1957
|
-
# \uD2B9\uC815 \uD30C\uC77C \uAC80\uC99D
|
|
1958
|
-
sdd validate .sdd/specs/user-auth/spec.md
|
|
1957
|
+
# \uD2B9\uC815 \uD30C\uC77C \uAC80\uC99D (\uB3C4\uBA54\uC778 \uAE30\uBC18 \uACBD\uB85C)
|
|
1958
|
+
sdd validate .sdd/specs/auth/user-auth/spec.md
|
|
1959
1959
|
|
|
1960
1960
|
# \uC5C4\uACA9 \uBAA8\uB4DC (\uACBD\uACE0\uB3C4 \uC5D0\uB7EC\uB85C \uCC98\uB9AC)
|
|
1961
1961
|
sdd validate --strict
|
|
@@ -2080,7 +2080,7 @@ created: YYYY-MM-DD
|
|
|
2080
2080
|
|
|
2081
2081
|
## \uC601\uD5A5 \uBC94\uC704
|
|
2082
2082
|
### \uC601\uD5A5\uBC1B\uB294 \uC2A4\uD399
|
|
2083
|
-
-
|
|
2083
|
+
- \`.sdd/specs/auth/user-auth/spec.md\`
|
|
2084
2084
|
|
|
2085
2085
|
### \uBCC0\uACBD \uC720\uD615
|
|
2086
2086
|
- [x] \uC218\uC815 (MODIFIED)
|
|
@@ -2705,9 +2705,23 @@ sdd reverse finalize -d auth # \uD2B9\uC815 \uB3C4\uBA54\uC778 \uD655\uC815
|
|
|
2705
2705
|
|
|
2706
2706
|
**\uC218\uD589 \uC791\uC5C5:**
|
|
2707
2707
|
- \`.sdd/.reverse-drafts/\`\uC5D0\uC11C \uC2B9\uC778\uB41C \uC2A4\uD399 \uC77D\uAE30
|
|
2708
|
-
- \`.sdd/specs/<feature-id>/spec.md\` \uC0DD\uC131
|
|
2708
|
+
- \`.sdd/specs/<domain>/<feature-id>/spec.md\` \uC0DD\uC131 (\`/sdd.new\`\uC640 \uB3D9\uC77C\uD55C \uD615\uC2DD)
|
|
2709
2709
|
- \uCD08\uC548 \uD30C\uC77C \uC0AD\uC81C
|
|
2710
2710
|
|
|
2711
|
+
**\uC0DD\uC131\uB418\uB294 \uC2A4\uD399 \uD615\uC2DD:**
|
|
2712
|
+
|
|
2713
|
+
finalize\uB85C \uC0DD\uC131\uB418\uB294 \uC2A4\uD399\uC740 \`/sdd.new\`\uC640 **\uB3D9\uC77C\uD55C \uD615\uC2DD**\uC785\uB2C8\uB2E4:
|
|
2714
|
+
|
|
2715
|
+
- YAML frontmatter (id, title, status, domain, depends, ...)
|
|
2716
|
+
- \`## \uC694\uAD6C\uC0AC\uD56D\` + REQ-ID + RFC 2119 \uD0A4\uC6CC\uB4DC (SHALL)
|
|
2717
|
+
- \`## \uC2DC\uB098\uB9AC\uC624\` + \`- **GIVEN/WHEN/THEN**\` \uD615\uC2DD
|
|
2718
|
+
- \`## \uBE44\uAE30\uB2A5 \uC694\uAD6C\uC0AC\uD56D\`, \`## \uC81C\uC57D\uC0AC\uD56D\`, \`## \uC6A9\uC5B4 \uC815\uC758\`
|
|
2719
|
+
|
|
2720
|
+
\uCD94\uAC00 \uBA54\uD0C0\uB370\uC774\uD130 (\uC5ED\uCD94\uCD9C \uC804\uC6A9):
|
|
2721
|
+
- \`extracted_from: reverse-extraction\`
|
|
2722
|
+
- \`confidence: <\uC2E0\uB8B0\uB3C4 \uC810\uC218>\`
|
|
2723
|
+
- \`source_files: [\uC6D0\uBCF8 \uD30C\uC77C \uBAA9\uB85D]\`
|
|
2724
|
+
|
|
2711
2725
|
**\uC644\uB8CC \uD6C4 \uC548\uB0B4:** "\uC2A4\uD399 \uD655\uC815\uC774 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \`/sdd.validate\`\uB85C \uC2A4\uD399\uC744 \uAC80\uC99D\uD558\uAC70\uB098 \`/sdd.new\`\uB85C \uC0C8 \uAE30\uB2A5\uC744 \uCD94\uAC00\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4."
|
|
2712
2726
|
|
|
2713
2727
|
## \uCD9C\uB825 \uD30C\uC77C
|
|
@@ -21302,12 +21316,14 @@ function formatSpecAsMarkdown(spec) {
|
|
|
21302
21316
|
if (spec.scenarios.length > 0) {
|
|
21303
21317
|
lines.push("## \uC2DC\uB098\uB9AC\uC624");
|
|
21304
21318
|
lines.push("");
|
|
21305
|
-
for (
|
|
21306
|
-
|
|
21319
|
+
for (let i = 0; i < spec.scenarios.length; i++) {
|
|
21320
|
+
const scenario = spec.scenarios[i];
|
|
21321
|
+
const inferredTag = scenario.inferred ? " *(\uCD94\uB860\uB428)*" : "";
|
|
21322
|
+
lines.push(`### Scenario ${i + 1}: ${scenario.name}${inferredTag}`);
|
|
21307
21323
|
lines.push("");
|
|
21308
|
-
lines.push(
|
|
21309
|
-
lines.push(
|
|
21310
|
-
lines.push(
|
|
21324
|
+
lines.push(`- **GIVEN** ${scenario.given}`);
|
|
21325
|
+
lines.push(`- **WHEN** ${scenario.when}`);
|
|
21326
|
+
lines.push(`- **THEN** ${scenario.then}`);
|
|
21311
21327
|
lines.push("");
|
|
21312
21328
|
}
|
|
21313
21329
|
}
|
|
@@ -21759,88 +21775,128 @@ import path52 from "path";
|
|
|
21759
21775
|
import { promises as fs34 } from "fs";
|
|
21760
21776
|
import chalk7 from "chalk";
|
|
21761
21777
|
function convertToSddSpec(spec) {
|
|
21762
|
-
const
|
|
21763
|
-
|
|
21764
|
-
|
|
21765
|
-
|
|
21766
|
-
|
|
21767
|
-
|
|
21768
|
-
|
|
21769
|
-
|
|
21770
|
-
|
|
21771
|
-
|
|
21772
|
-
|
|
21773
|
-
|
|
21774
|
-
|
|
21775
|
-
|
|
21776
|
-
|
|
21777
|
-
|
|
21778
|
-
|
|
21779
|
-
|
|
21780
|
-
|
|
21781
|
-
|
|
21782
|
-
|
|
21783
|
-
|
|
21784
|
-
|
|
21778
|
+
const extractedAt = spec.metadata.extractedAt instanceof Date ? spec.metadata.extractedAt.toISOString().split("T")[0] : String(spec.metadata.extractedAt).split("T")[0];
|
|
21779
|
+
const featureId = spec.id.includes("/") ? spec.id.split("/").pop() : spec.id;
|
|
21780
|
+
const sourceFilesYaml = spec.metadata.sourceFiles.length > 0 ? spec.metadata.sourceFiles.map((f) => ` - ${f}`).join("\n") : " - (none)";
|
|
21781
|
+
let content = `---
|
|
21782
|
+
id: ${featureId}
|
|
21783
|
+
title: "${spec.name}"
|
|
21784
|
+
status: draft
|
|
21785
|
+
created: ${extractedAt}
|
|
21786
|
+
domain: ${spec.domain}
|
|
21787
|
+
depends: null
|
|
21788
|
+
extracted_from: reverse-extraction
|
|
21789
|
+
confidence: ${spec.confidence.score}
|
|
21790
|
+
source_files:
|
|
21791
|
+
${sourceFilesYaml}
|
|
21792
|
+
---
|
|
21793
|
+
|
|
21794
|
+
# ${spec.name}
|
|
21795
|
+
|
|
21796
|
+
> ${spec.description}
|
|
21797
|
+
|
|
21798
|
+
---
|
|
21799
|
+
|
|
21800
|
+
## \uAC1C\uC694
|
|
21801
|
+
|
|
21802
|
+
${spec.description}
|
|
21803
|
+
|
|
21804
|
+
---
|
|
21805
|
+
|
|
21806
|
+
## \uC694\uAD6C\uC0AC\uD56D
|
|
21807
|
+
|
|
21808
|
+
`;
|
|
21785
21809
|
if (spec.contracts.length > 0) {
|
|
21786
|
-
|
|
21787
|
-
|
|
21788
|
-
|
|
21789
|
-
|
|
21790
|
-
|
|
21791
|
-
|
|
21792
|
-
|
|
21793
|
-
|
|
21794
|
-
|
|
21795
|
-
|
|
21796
|
-
|
|
21797
|
-
|
|
21798
|
-
|
|
21799
|
-
|
|
21810
|
+
let reqIndex = 1;
|
|
21811
|
+
for (const contract of spec.contracts) {
|
|
21812
|
+
const reqId = `REQ-${String(reqIndex++).padStart(2, "0")}`;
|
|
21813
|
+
const reqTitle = contract.description.split("\uC758")[0] || contract.description;
|
|
21814
|
+
content += `### ${reqId}: ${reqTitle}
|
|
21815
|
+
|
|
21816
|
+
\uC2DC\uC2A4\uD15C\uC740 ${contract.description.toLowerCase()}\uC744(\uB97C) \uC81C\uACF5\uD574\uC57C \uD55C\uB2E4(SHALL).
|
|
21817
|
+
|
|
21818
|
+
`;
|
|
21819
|
+
if (contract.signature) {
|
|
21820
|
+
content += `\`\`\`typescript
|
|
21821
|
+
${contract.signature}
|
|
21822
|
+
\`\`\`
|
|
21823
|
+
|
|
21824
|
+
`;
|
|
21800
21825
|
}
|
|
21801
|
-
lines.push("");
|
|
21802
21826
|
}
|
|
21803
|
-
|
|
21804
|
-
|
|
21805
|
-
|
|
21806
|
-
|
|
21807
|
-
|
|
21808
|
-
|
|
21809
|
-
|
|
21810
|
-
|
|
21811
|
-
|
|
21812
|
-
|
|
21813
|
-
|
|
21814
|
-
|
|
21827
|
+
} else {
|
|
21828
|
+
content += `### REQ-01: [\uC694\uAD6C\uC0AC\uD56D \uC81C\uBAA9]
|
|
21829
|
+
|
|
21830
|
+
[\uC694\uAD6C\uC0AC\uD56D \uC0C1\uC138 \uC124\uBA85]
|
|
21831
|
+
- \uC2DC\uC2A4\uD15C\uC740 [\uAE30\uB2A5]\uC744 \uC9C0\uC6D0\uD574\uC57C \uD55C\uB2E4(SHALL)
|
|
21832
|
+
|
|
21833
|
+
`;
|
|
21834
|
+
}
|
|
21835
|
+
content += `---
|
|
21836
|
+
|
|
21837
|
+
## \uC2DC\uB098\uB9AC\uC624
|
|
21838
|
+
|
|
21839
|
+
`;
|
|
21840
|
+
if (spec.scenarios.length > 0) {
|
|
21841
|
+
for (let i = 0; i < spec.scenarios.length; i++) {
|
|
21842
|
+
const scenario = spec.scenarios[i];
|
|
21843
|
+
content += `### Scenario ${i + 1}: ${scenario.name}
|
|
21844
|
+
|
|
21845
|
+
- **GIVEN** ${scenario.given}
|
|
21846
|
+
- **WHEN** ${scenario.when}
|
|
21847
|
+
- **THEN** ${scenario.then}
|
|
21848
|
+
|
|
21849
|
+
`;
|
|
21815
21850
|
}
|
|
21851
|
+
} else {
|
|
21852
|
+
content += `### Scenario 1: [\uC2DC\uB098\uB9AC\uC624\uBA85]
|
|
21853
|
+
|
|
21854
|
+
- **GIVEN** [\uC804\uC81C \uC870\uAC74]
|
|
21855
|
+
- **WHEN** [\uD589\uB3D9/\uD2B8\uB9AC\uAC70]
|
|
21856
|
+
- **THEN** [\uC608\uC0C1 \uACB0\uACFC]
|
|
21857
|
+
|
|
21858
|
+
`;
|
|
21816
21859
|
}
|
|
21860
|
+
content += `---
|
|
21861
|
+
|
|
21862
|
+
## \uBE44\uAE30\uB2A5 \uC694\uAD6C\uC0AC\uD56D
|
|
21863
|
+
|
|
21864
|
+
### \uC131\uB2A5
|
|
21865
|
+
|
|
21866
|
+
- \uC751\uB2F5 \uC2DC\uAC04: [N]ms \uC774\uB0B4 (SHOULD)
|
|
21867
|
+
|
|
21868
|
+
### \uBCF4\uC548
|
|
21869
|
+
|
|
21870
|
+
- [\uBCF4\uC548 \uC694\uAD6C\uC0AC\uD56D] (SHALL)
|
|
21871
|
+
|
|
21872
|
+
---
|
|
21873
|
+
|
|
21874
|
+
## \uC81C\uC57D\uC0AC\uD56D
|
|
21875
|
+
|
|
21876
|
+
- \uC6D0\uBCF8 \uD30C\uC77C: ${spec.metadata.sourceFiles.join(", ") || "(\uC5C6\uC74C)"}
|
|
21877
|
+
- \uC5ED\uCD94\uCD9C \uC2E0\uB8B0\uB3C4: ${spec.confidence.grade} (${spec.confidence.score}%)
|
|
21878
|
+
|
|
21879
|
+
---
|
|
21880
|
+
|
|
21881
|
+
## \uC6A9\uC5B4 \uC815\uC758
|
|
21882
|
+
|
|
21883
|
+
| \uC6A9\uC5B4 | \uC815\uC758 |
|
|
21884
|
+
|------|------|
|
|
21885
|
+
| [\uC6A9\uC5B41] | [\uC815\uC7581] |
|
|
21886
|
+
`;
|
|
21817
21887
|
if (spec.relatedSpecs.length > 0) {
|
|
21818
|
-
|
|
21819
|
-
|
|
21888
|
+
content += `
|
|
21889
|
+
---
|
|
21890
|
+
|
|
21891
|
+
## \uAD00\uB828 \uC2A4\uD399
|
|
21892
|
+
|
|
21893
|
+
`;
|
|
21820
21894
|
for (const related of spec.relatedSpecs) {
|
|
21821
|
-
|
|
21895
|
+
content += `- [[${related}]]
|
|
21896
|
+
`;
|
|
21822
21897
|
}
|
|
21823
|
-
lines.push("");
|
|
21824
21898
|
}
|
|
21825
|
-
|
|
21826
|
-
lines.push("");
|
|
21827
|
-
lines.push("## \uBA54\uD0C0\uB370\uC774\uD130");
|
|
21828
|
-
lines.push("");
|
|
21829
|
-
lines.push("```yaml");
|
|
21830
|
-
lines.push(`id: ${spec.id}`);
|
|
21831
|
-
lines.push(`domain: ${spec.domain}`);
|
|
21832
|
-
lines.push(`version: ${spec.metadata.version}`);
|
|
21833
|
-
lines.push(`source: reverse-extraction`);
|
|
21834
|
-
lines.push(`extracted_at: ${spec.metadata.extractedAt.toISOString()}`);
|
|
21835
|
-
lines.push(`finalized_at: ${(/* @__PURE__ */ new Date()).toISOString()}`);
|
|
21836
|
-
lines.push(`confidence: ${spec.confidence.score}`);
|
|
21837
|
-
lines.push(`source_files:`);
|
|
21838
|
-
for (const file of spec.metadata.sourceFiles) {
|
|
21839
|
-
lines.push(` - ${file}`);
|
|
21840
|
-
}
|
|
21841
|
-
lines.push("```");
|
|
21842
|
-
lines.push("");
|
|
21843
|
-
return lines.join("\n");
|
|
21899
|
+
return content;
|
|
21844
21900
|
}
|
|
21845
21901
|
async function finalizeSpec(sddRoot, spec) {
|
|
21846
21902
|
try {
|