@specsafe/cli 0.8.0 → 2.0.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.
Files changed (242) hide show
  1. package/README.md +100 -279
  2. package/canonical/personas/bolt-zane.md +29 -0
  3. package/canonical/personas/forge-reva.md +29 -0
  4. package/canonical/personas/herald-cass.md +30 -0
  5. package/canonical/personas/mason-kai.md +30 -0
  6. package/canonical/personas/scout-elena.md +27 -0
  7. package/canonical/personas/warden-lyra.md +30 -0
  8. package/canonical/rules/.cursorrules.mdc +53 -0
  9. package/canonical/rules/.rules +48 -0
  10. package/canonical/rules/AGENTS.md +48 -0
  11. package/canonical/rules/CLAUDE.md +48 -0
  12. package/canonical/rules/CONVENTIONS.md +41 -0
  13. package/canonical/rules/GEMINI.md +50 -0
  14. package/canonical/rules/continue-config.yaml +5 -0
  15. package/canonical/skills/specsafe-archive/SKILL.md +63 -0
  16. package/canonical/skills/specsafe-code/SKILL.md +7 -0
  17. package/canonical/skills/specsafe-code/workflow.md +212 -0
  18. package/canonical/skills/specsafe-complete/SKILL.md +7 -0
  19. package/canonical/skills/specsafe-complete/workflow.md +130 -0
  20. package/canonical/skills/specsafe-doctor/SKILL.md +103 -0
  21. package/canonical/skills/specsafe-explore/SKILL.md +7 -0
  22. package/canonical/skills/specsafe-explore/workflow.md +100 -0
  23. package/canonical/skills/specsafe-init/SKILL.md +119 -0
  24. package/canonical/skills/specsafe-new/SKILL.md +7 -0
  25. package/canonical/skills/specsafe-new/workflow.md +156 -0
  26. package/canonical/skills/specsafe-qa/SKILL.md +7 -0
  27. package/canonical/skills/specsafe-qa/workflow.md +223 -0
  28. package/canonical/skills/specsafe-spec/SKILL.md +7 -0
  29. package/canonical/skills/specsafe-spec/workflow.md +158 -0
  30. package/canonical/skills/specsafe-status/SKILL.md +77 -0
  31. package/canonical/skills/specsafe-test/SKILL.md +7 -0
  32. package/canonical/skills/specsafe-test/workflow.md +210 -0
  33. package/canonical/skills/specsafe-verify/SKILL.md +7 -0
  34. package/canonical/skills/specsafe-verify/workflow.md +143 -0
  35. package/canonical/templates/project-state-template.md +33 -0
  36. package/canonical/templates/qa-report-template.md +55 -0
  37. package/canonical/templates/spec-template.md +52 -0
  38. package/canonical/templates/specsafe-config-template.json +10 -0
  39. package/generators/dist/adapters/aider.d.ts +2 -0
  40. package/generators/dist/adapters/aider.js +23 -0
  41. package/generators/dist/adapters/aider.js.map +1 -0
  42. package/generators/dist/adapters/antigravity.d.ts +2 -0
  43. package/generators/dist/adapters/antigravity.js +33 -0
  44. package/generators/dist/adapters/antigravity.js.map +1 -0
  45. package/generators/dist/adapters/claude-code.d.ts +2 -0
  46. package/generators/dist/adapters/claude-code.js +31 -0
  47. package/generators/dist/adapters/claude-code.js.map +1 -0
  48. package/generators/dist/adapters/continue.d.ts +2 -0
  49. package/generators/dist/adapters/continue.js +33 -0
  50. package/generators/dist/adapters/continue.js.map +1 -0
  51. package/generators/dist/adapters/cursor.d.ts +2 -0
  52. package/generators/dist/adapters/cursor.js +32 -0
  53. package/generators/dist/adapters/cursor.js.map +1 -0
  54. package/generators/dist/adapters/gemini.d.ts +2 -0
  55. package/generators/dist/adapters/gemini.js +36 -0
  56. package/generators/dist/adapters/gemini.js.map +1 -0
  57. package/generators/dist/adapters/index.d.ts +13 -0
  58. package/generators/dist/adapters/index.js +29 -0
  59. package/generators/dist/adapters/index.js.map +1 -0
  60. package/generators/dist/adapters/opencode.d.ts +2 -0
  61. package/generators/dist/adapters/opencode.js +32 -0
  62. package/generators/dist/adapters/opencode.js.map +1 -0
  63. package/generators/dist/adapters/types.d.ts +49 -0
  64. package/generators/dist/adapters/types.js +14 -0
  65. package/generators/dist/adapters/types.js.map +1 -0
  66. package/generators/dist/adapters/utils.d.ts +12 -0
  67. package/generators/dist/adapters/utils.js +68 -0
  68. package/generators/dist/adapters/utils.js.map +1 -0
  69. package/generators/dist/adapters/zed.d.ts +2 -0
  70. package/generators/dist/adapters/zed.js +31 -0
  71. package/generators/dist/adapters/zed.js.map +1 -0
  72. package/generators/dist/doctor.d.ts +10 -0
  73. package/generators/dist/doctor.js +123 -0
  74. package/generators/dist/doctor.js.map +1 -0
  75. package/generators/dist/index.d.ts +2 -0
  76. package/generators/dist/index.js +45 -0
  77. package/generators/dist/index.js.map +1 -0
  78. package/generators/dist/init.d.ts +9 -0
  79. package/generators/dist/init.js +167 -0
  80. package/generators/dist/init.js.map +1 -0
  81. package/generators/dist/install.d.ts +5 -0
  82. package/generators/dist/install.js +66 -0
  83. package/generators/dist/install.js.map +1 -0
  84. package/generators/dist/registry.d.ts +3 -0
  85. package/generators/dist/registry.js +8 -0
  86. package/generators/dist/registry.js.map +1 -0
  87. package/generators/dist/update.d.ts +5 -0
  88. package/generators/dist/update.js +40 -0
  89. package/generators/dist/update.js.map +1 -0
  90. package/package.json +31 -27
  91. package/dist/commands/apply.d.ts +0 -3
  92. package/dist/commands/apply.d.ts.map +0 -1
  93. package/dist/commands/apply.js +0 -182
  94. package/dist/commands/apply.js.map +0 -1
  95. package/dist/commands/archive.d.ts +0 -3
  96. package/dist/commands/archive.d.ts.map +0 -1
  97. package/dist/commands/archive.js +0 -99
  98. package/dist/commands/archive.js.map +0 -1
  99. package/dist/commands/capsule.d.ts +0 -8
  100. package/dist/commands/capsule.d.ts.map +0 -1
  101. package/dist/commands/capsule.js +0 -466
  102. package/dist/commands/capsule.js.map +0 -1
  103. package/dist/commands/complete.d.ts +0 -3
  104. package/dist/commands/complete.d.ts.map +0 -1
  105. package/dist/commands/complete.js +0 -140
  106. package/dist/commands/complete.js.map +0 -1
  107. package/dist/commands/constitution.d.ts +0 -3
  108. package/dist/commands/constitution.d.ts.map +0 -1
  109. package/dist/commands/constitution.js +0 -192
  110. package/dist/commands/constitution.js.map +0 -1
  111. package/dist/commands/create.d.ts +0 -10
  112. package/dist/commands/create.d.ts.map +0 -1
  113. package/dist/commands/create.js +0 -120
  114. package/dist/commands/create.js.map +0 -1
  115. package/dist/commands/delta.d.ts +0 -3
  116. package/dist/commands/delta.d.ts.map +0 -1
  117. package/dist/commands/delta.js +0 -82
  118. package/dist/commands/delta.js.map +0 -1
  119. package/dist/commands/diff.d.ts +0 -3
  120. package/dist/commands/diff.d.ts.map +0 -1
  121. package/dist/commands/diff.js +0 -102
  122. package/dist/commands/diff.js.map +0 -1
  123. package/dist/commands/doctor.d.ts +0 -3
  124. package/dist/commands/doctor.d.ts.map +0 -1
  125. package/dist/commands/doctor.js +0 -204
  126. package/dist/commands/doctor.js.map +0 -1
  127. package/dist/commands/done.d.ts +0 -3
  128. package/dist/commands/done.d.ts.map +0 -1
  129. package/dist/commands/done.js +0 -237
  130. package/dist/commands/done.js.map +0 -1
  131. package/dist/commands/explore.d.ts +0 -3
  132. package/dist/commands/explore.d.ts.map +0 -1
  133. package/dist/commands/explore.js +0 -236
  134. package/dist/commands/explore.js.map +0 -1
  135. package/dist/commands/export.d.ts +0 -7
  136. package/dist/commands/export.d.ts.map +0 -1
  137. package/dist/commands/export.js +0 -179
  138. package/dist/commands/export.js.map +0 -1
  139. package/dist/commands/extend.d.ts +0 -6
  140. package/dist/commands/extend.d.ts.map +0 -1
  141. package/dist/commands/extend.js +0 -167
  142. package/dist/commands/extend.js.map +0 -1
  143. package/dist/commands/init-old.d.ts +0 -3
  144. package/dist/commands/init-old.d.ts.map +0 -1
  145. package/dist/commands/init-old.js +0 -146
  146. package/dist/commands/init-old.js.map +0 -1
  147. package/dist/commands/init.d.ts +0 -3
  148. package/dist/commands/init.d.ts.map +0 -1
  149. package/dist/commands/init.js +0 -298
  150. package/dist/commands/init.js.map +0 -1
  151. package/dist/commands/list.d.ts +0 -3
  152. package/dist/commands/list.d.ts.map +0 -1
  153. package/dist/commands/list.js +0 -122
  154. package/dist/commands/list.js.map +0 -1
  155. package/dist/commands/memory.d.ts +0 -3
  156. package/dist/commands/memory.d.ts.map +0 -1
  157. package/dist/commands/memory.js +0 -166
  158. package/dist/commands/memory.js.map +0 -1
  159. package/dist/commands/new.d.ts +0 -3
  160. package/dist/commands/new.d.ts.map +0 -1
  161. package/dist/commands/new.js +0 -508
  162. package/dist/commands/new.js.map +0 -1
  163. package/dist/commands/qa.d.ts +0 -3
  164. package/dist/commands/qa.d.ts.map +0 -1
  165. package/dist/commands/qa.js +0 -179
  166. package/dist/commands/qa.js.map +0 -1
  167. package/dist/commands/rules.d.ts +0 -6
  168. package/dist/commands/rules.d.ts.map +0 -1
  169. package/dist/commands/rules.js +0 -232
  170. package/dist/commands/rules.js.map +0 -1
  171. package/dist/commands/shard.d.ts +0 -6
  172. package/dist/commands/shard.d.ts.map +0 -1
  173. package/dist/commands/shard.js +0 -199
  174. package/dist/commands/shard.js.map +0 -1
  175. package/dist/commands/spec.d.ts +0 -3
  176. package/dist/commands/spec.d.ts.map +0 -1
  177. package/dist/commands/spec.js +0 -302
  178. package/dist/commands/spec.js.map +0 -1
  179. package/dist/commands/status.d.ts +0 -3
  180. package/dist/commands/status.d.ts.map +0 -1
  181. package/dist/commands/status.js +0 -47
  182. package/dist/commands/status.js.map +0 -1
  183. package/dist/commands/test-apply.d.ts +0 -3
  184. package/dist/commands/test-apply.d.ts.map +0 -1
  185. package/dist/commands/test-apply.js +0 -228
  186. package/dist/commands/test-apply.js.map +0 -1
  187. package/dist/commands/test-create.d.ts +0 -3
  188. package/dist/commands/test-create.d.ts.map +0 -1
  189. package/dist/commands/test-create.js +0 -183
  190. package/dist/commands/test-create.js.map +0 -1
  191. package/dist/commands/test-guide.d.ts +0 -3
  192. package/dist/commands/test-guide.d.ts.map +0 -1
  193. package/dist/commands/test-guide.js +0 -190
  194. package/dist/commands/test-guide.js.map +0 -1
  195. package/dist/commands/test-report.d.ts +0 -3
  196. package/dist/commands/test-report.d.ts.map +0 -1
  197. package/dist/commands/test-report.js +0 -196
  198. package/dist/commands/test-report.js.map +0 -1
  199. package/dist/commands/test-submit.d.ts +0 -6
  200. package/dist/commands/test-submit.d.ts.map +0 -1
  201. package/dist/commands/test-submit.js +0 -236
  202. package/dist/commands/test-submit.js.map +0 -1
  203. package/dist/commands/verify.d.ts +0 -3
  204. package/dist/commands/verify.d.ts.map +0 -1
  205. package/dist/commands/verify.js +0 -288
  206. package/dist/commands/verify.js.map +0 -1
  207. package/dist/config.d.ts +0 -23
  208. package/dist/config.d.ts.map +0 -1
  209. package/dist/config.js +0 -44
  210. package/dist/config.js.map +0 -1
  211. package/dist/index.d.ts +0 -8
  212. package/dist/index.d.ts.map +0 -1
  213. package/dist/index.js +0 -129
  214. package/dist/index.js.map +0 -1
  215. package/dist/rules/downloader.d.ts +0 -40
  216. package/dist/rules/downloader.d.ts.map +0 -1
  217. package/dist/rules/downloader.js +0 -253
  218. package/dist/rules/downloader.js.map +0 -1
  219. package/dist/rules/index.d.ts +0 -8
  220. package/dist/rules/index.d.ts.map +0 -1
  221. package/dist/rules/index.js +0 -8
  222. package/dist/rules/index.js.map +0 -1
  223. package/dist/rules/registry.d.ts +0 -45
  224. package/dist/rules/registry.d.ts.map +0 -1
  225. package/dist/rules/registry.js +0 -158
  226. package/dist/rules/registry.js.map +0 -1
  227. package/dist/rules/types.d.ts +0 -86
  228. package/dist/rules/types.d.ts.map +0 -1
  229. package/dist/rules/types.js +0 -6
  230. package/dist/rules/types.js.map +0 -1
  231. package/dist/utils/detectTools.d.ts +0 -15
  232. package/dist/utils/detectTools.d.ts.map +0 -1
  233. package/dist/utils/detectTools.js +0 -54
  234. package/dist/utils/detectTools.js.map +0 -1
  235. package/dist/utils/generateToolConfig.d.ts +0 -12
  236. package/dist/utils/generateToolConfig.d.ts.map +0 -1
  237. package/dist/utils/generateToolConfig.js +0 -1179
  238. package/dist/utils/generateToolConfig.js.map +0 -1
  239. package/dist/utils/testRunner.d.ts +0 -39
  240. package/dist/utils/testRunner.d.ts.map +0 -1
  241. package/dist/utils/testRunner.js +0 -325
  242. package/dist/utils/testRunner.js.map +0 -1
@@ -0,0 +1,143 @@
1
+ # Verify — Lyra the QA Inspector
2
+
3
+ > **Persona:** Lyra the QA Inspector. Skeptical, thorough, evidence-based. Trusts data over assertions.
4
+ > **Principles:** No failing tests pass the gate. Every claim needs evidence. Coverage is non-negotiable.
5
+
6
+ ## Input
7
+
8
+ Spec ID (e.g., `SPEC-20260402-001`)
9
+
10
+ ## Preconditions
11
+
12
+ - [ ] A SPEC-ID is provided. If not, STOP and ask: "Which spec? Provide the SPEC-ID (e.g., SPEC-20260402-001)"
13
+ - [ ] `specsafe.config.json` exists in project root
14
+ - [ ] Spec file exists at `specs/active/<id>.md`
15
+ - [ ] Spec stage is **CODE** (check the spec file's `**Stage:**` field — this is the authoritative source)
16
+ - [ ] Test files exist for this spec
17
+
18
+ ## Workflow
19
+
20
+ ### Step 1: Load Context
21
+
22
+ 1. Read the spec file at `specs/active/<id>.md`
23
+ 2. Read `specsafe.config.json` to get `testCommand` and `coverageCommand`
24
+ 3. Read `PROJECT_STATE.md` to confirm the spec is in CODE stage
25
+ 4. If the spec is NOT in CODE stage, stop and report: "Spec `<id>` is in `<stage>` stage. It must be in CODE stage to verify. Run `/specsafe-code <id>` first."
26
+
27
+ ### Step 2: Run Full Test Suite
28
+
29
+ 1. Execute the `coverageCommand` from config (e.g., `pnpm test --coverage`)
30
+ 2. If no `coverageCommand` is configured, fall back to `testCommand`
31
+ 3. Capture the full output including pass/fail counts and coverage percentage
32
+
33
+ ### Step 3: Analyze Test Results
34
+
35
+ Evaluate the test output:
36
+
37
+ **If any tests FAIL:**
38
+ - List each failing test name and its error message
39
+ - Analyze failure patterns (common root cause, missing implementation, etc.)
40
+ - Suggest specific fixes based on the error messages
41
+ - Report to the user:
42
+ ```
43
+ VERIFY FAILED — <N> test(s) failing
44
+
45
+ Failures:
46
+ - <test name>: <error summary>
47
+ - <test name>: <error summary>
48
+
49
+ Suggested fixes:
50
+ - <fix suggestion>
51
+
52
+ Run `/specsafe-code <id>` to fix the failing tests, then re-verify.
53
+ ```
54
+ - **STOP HERE. Do NOT proceed to Step 4.**
55
+
56
+ **If ALL tests PASS:**
57
+ - Record the pass count and coverage percentage
58
+ - Proceed to Step 4
59
+
60
+ ### Step 4: Validate Coverage
61
+
62
+ 1. Parse the coverage percentage from test output
63
+ 2. Evaluate against thresholds:
64
+ - **Below 80%**: Flag as insufficient. Report the gap and suggest areas to add tests. Recommend running `/specsafe-code <id>` to add more tests before proceeding.
65
+ - **80%-89%**: Acceptable. Note that 90%+ is preferred.
66
+ - **90%+**: Excellent coverage.
67
+ 3. If coverage is below 80%, recommend improvement but allow the user to decide whether to proceed.
68
+
69
+ ### Step 5: Cross-Reference Against Spec
70
+
71
+ 1. Read the spec file and extract all requirements (lines with SHALL, MUST, SHOULD, or REQ- identifiers)
72
+ 2. For each requirement, verify:
73
+ - There is at least one test that validates it
74
+ - The test is passing
75
+ 3. Read the spec's scenarios section
76
+ 4. For each scenario, verify:
77
+ - There is a corresponding test
78
+ - The test is passing
79
+ 5. Check for edge cases mentioned in the spec that need test coverage
80
+ 6. Build a validation summary:
81
+ - Requirements: `<passed>/<total>` satisfied
82
+ - Scenarios: `<covered>/<total>` covered
83
+ - Edge cases: `<covered>/<total>` covered
84
+
85
+ ### Step 6: Determine Verdict
86
+
87
+ **PASS conditions (ALL must be true):**
88
+ - All tests passing
89
+ - Coverage >= 80%
90
+ - All P0/MUST requirements have passing tests
91
+ - All scenarios have passing tests
92
+
93
+ **FAIL conditions (ANY triggers fail):**
94
+ - Any test failing
95
+ - Any P0/MUST requirement without a passing test
96
+
97
+ If PASS: proceed to Step 7.
98
+ If FAIL: report the specific failures and recommend `/specsafe-code <id>` to fix.
99
+
100
+ ### Step 7: Update State and Report
101
+
102
+ 1. Update the spec file at `specs/active/<id>.md`: change `**Stage:** CODE` to `**Stage:** QA`
103
+ 2. Update the spec stage to **QA** in `PROJECT_STATE.md`:
104
+ - Change the spec's Stage column from CODE to QA
105
+ - Update the `Last Updated` timestamp
106
+ - Update the spec's Updated date
107
+ 3. Present the verification summary:
108
+ ```
109
+ VERIFY PASSED
110
+
111
+ Test Results: <passed>/<total> passing
112
+ Coverage: <percentage>%
113
+ Requirements: <passed>/<total> satisfied
114
+ Scenarios: <covered>/<total> covered
115
+
116
+ Stage updated: CODE -> QA
117
+ Next: Run `/specsafe-qa <id>` for full QA validation
118
+ ```
119
+
120
+ ## State Changes
121
+
122
+ Update spec file at `specs/active/<id>.md`:
123
+ - Change `**Stage:** CODE` to `**Stage:** QA`
124
+ - Update `Updated` date
125
+
126
+ Update `PROJECT_STATE.md`:
127
+ - Change spec `<id>` stage from `CODE` to `QA`
128
+ - Update `Last Updated` timestamp to current ISO date
129
+ - Update spec's `Updated` column to current date
130
+
131
+ ## Guardrails
132
+
133
+ - NEVER proceed to QA with any failing tests
134
+ - NEVER override or skip test failures
135
+ - NEVER auto-approve coverage below 80% without user acknowledgment
136
+ - ALWAYS run the full test suite, not a subset
137
+ - ALWAYS cross-reference against the spec requirements
138
+ - ALWAYS show the user exactly what failed and why
139
+
140
+ ## Handoff
141
+
142
+ - On **PASS**: `/specsafe-qa <id>`
143
+ - On **FAIL**: `/specsafe-code <id>`
@@ -0,0 +1,33 @@
1
+ # PROJECT_STATE
2
+
3
+ **Project:** {{project-name}}
4
+ **Version:** {{version}}
5
+ **Last Updated:** {{timestamp}}
6
+
7
+ ## Active Specs
8
+
9
+ | ID | Name | Stage | Created | Updated |
10
+ |----|------|-------|---------|---------|
11
+
12
+ ## Completed Specs
13
+
14
+ | ID | Name | Completed | QA Result |
15
+ |----|------|-----------|-----------|
16
+
17
+ ## Archived Specs
18
+
19
+ | ID | Name | Archived | Reason |
20
+ |----|------|----------|--------|
21
+
22
+ ## Metrics
23
+
24
+ - Total Specs: 0
25
+ - Active: 0
26
+ - Completed: 0
27
+ - Archived: 0
28
+ - Completion Rate: 0%
29
+
30
+ ## Decision Log
31
+
32
+ | Date | Decision | Rationale | Spec |
33
+ |------|----------|-----------|------|
@@ -0,0 +1,55 @@
1
+ # QA Report: {{spec-id}}
2
+
3
+ **Spec:** {{spec-name}}
4
+ **Date:** {{date}}
5
+ **Inspector:** Lyra (QA Inspector)
6
+
7
+ ## Summary
8
+
9
+ | Metric | Value |
10
+ |--------|-------|
11
+ | Total Tests | {{total}} |
12
+ | Passed | {{passed}} |
13
+ | Failed | {{failed}} |
14
+ | Skipped | {{skipped}} |
15
+ | Coverage | {{coverage}}% |
16
+
17
+ ## Recommendation: {{GO/NO-GO}}
18
+
19
+ {{One-sentence justification}}
20
+
21
+ ## Requirements Validation
22
+
23
+ | Req ID | Description | Priority | Verdict |
24
+ |--------|-------------|----------|---------|
25
+ | REQ-001 | ... | P0 | PASS |
26
+
27
+ - P0 Requirements: {{passed}}/{{total}}
28
+ - P1 Requirements: {{passed}}/{{total}}
29
+ - P2 Requirements: {{passed}}/{{total}}
30
+
31
+ ## Scenarios Validated
32
+
33
+ | Scenario | Verdict | Notes |
34
+ |----------|---------|-------|
35
+ | ... | PASS | ... |
36
+
37
+ - Scenarios Covered: {{covered}}/{{total}}
38
+
39
+ ## Edge Cases
40
+
41
+ | Case | Status | Notes |
42
+ |------|--------|-------|
43
+ | ... | Covered | ... |
44
+
45
+ ## Issues Found
46
+
47
+ {{List any issues, gaps, or concerns. If none: "No issues found."}}
48
+
49
+ ## GO Criteria
50
+
51
+ - [ ] All tests passing
52
+ - [ ] Coverage >= 80%
53
+ - [ ] All P0 requirements PASS
54
+ - [ ] All scenarios covered
55
+ - [ ] No critical issues found
@@ -0,0 +1,52 @@
1
+ # SPEC-YYYYMMDD-NNN: <Spec Name (Title Case)>
2
+
3
+ **ID:** SPEC-YYYYMMDD-NNN
4
+ **Name:** <spec-name>
5
+ **Stage:** SPEC
6
+ **Created:** <YYYY-MM-DD>
7
+ **Updated:** <YYYY-MM-DD>
8
+ **Author:** <user or "unspecified">
9
+
10
+ ## Purpose
11
+
12
+ <Why does this spec exist? What problem does it solve? 1-3 sentences.>
13
+
14
+ ## Scope
15
+
16
+ ### In Scope
17
+ - <What this spec covers>
18
+
19
+ ### Out of Scope
20
+ - <What this spec explicitly does NOT cover>
21
+
22
+ ## Requirements
23
+
24
+ ### REQ-001: <Requirement Name>
25
+ **Priority:** P0 | P1 | P2
26
+ **Description:** The system SHALL <do something specific>.
27
+
28
+ #### Acceptance Criteria
29
+ - **GIVEN** <precondition> **WHEN** <action> **THEN** <expected result>
30
+
31
+ #### Scenarios
32
+ - **Happy path:** <describe>
33
+ - **Edge case:** <describe>
34
+ - **Error case:** <describe>
35
+
36
+ ## Technical Approach
37
+
38
+ <High-level technical approach — to be filled in during /specsafe-spec>
39
+
40
+ ## Test Strategy
41
+
42
+ <Test approach — to be filled in during /specsafe-spec>
43
+
44
+ ## Implementation Plan
45
+
46
+ <Phased plan — to be filled in during /specsafe-spec>
47
+
48
+ ## Decision Log
49
+
50
+ | Date | Decision | Rationale |
51
+ |------|----------|-----------|
52
+ | <YYYY-MM-DD> | Spec created | Initial creation |
@@ -0,0 +1,10 @@
1
+ {
2
+ "project": "{{project-name}}",
3
+ "version": "1.0.0",
4
+ "tools": [],
5
+ "testFramework": "vitest",
6
+ "testCommand": "pnpm test",
7
+ "coverageCommand": "pnpm test --coverage",
8
+ "language": "typescript",
9
+ "specsafeVersion": "2.0.0"
10
+ }
@@ -0,0 +1,2 @@
1
+ import type { ToolAdapter } from './types.js';
2
+ export declare const aiderAdapter: ToolAdapter;
@@ -0,0 +1,23 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { readCanonicalRule } from './utils.js';
4
+ export const aiderAdapter = {
5
+ name: 'aider',
6
+ displayName: 'Aider',
7
+ async detect(projectRoot) {
8
+ return existsSync(join(projectRoot, '.aider.conf.yml'));
9
+ },
10
+ async generate(_skills, canonicalDir) {
11
+ const files = [];
12
+ files.push({
13
+ path: '.aider.conf.yml',
14
+ content: 'read:\n - CONVENTIONS.md\n - PROJECT_STATE.md\n',
15
+ });
16
+ const conventions = readCanonicalRule(canonicalDir, 'CONVENTIONS.md');
17
+ if (conventions) {
18
+ files.push({ path: 'CONVENTIONS.md', content: conventions });
19
+ }
20
+ return files;
21
+ },
22
+ };
23
+ //# sourceMappingURL=aider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aider.js","sourceRoot":"","sources":["../../src/adapters/aider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE/C,MAAM,CAAC,MAAM,YAAY,GAAgB;IACvC,IAAI,EAAE,OAAO;IACb,WAAW,EAAE,OAAO;IAEpB,KAAK,CAAC,MAAM,CAAC,WAAmB;QAC9B,OAAO,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAC,CAAC;IAC1D,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,OAAyB,EAAE,YAAoB;QAC5D,MAAM,KAAK,GAAoB,EAAE,CAAC;QAElC,KAAK,CAAC,IAAI,CAAC;YACT,IAAI,EAAE,iBAAiB;YACvB,OAAO,EAAE,mDAAmD;SAC7D,CAAC,CAAC;QAEH,MAAM,WAAW,GAAG,iBAAiB,CAAC,YAAY,EAAE,gBAAgB,CAAC,CAAC;QACtE,IAAI,WAAW,EAAE,CAAC;YAChB,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC;QAC/D,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;CACF,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { ToolAdapter } from './types.js';
2
+ export declare const antigravityAdapter: ToolAdapter;
@@ -0,0 +1,33 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { readCanonicalRule, reconstructSkillMd } from './utils.js';
4
+ export const antigravityAdapter = {
5
+ name: 'antigravity',
6
+ displayName: 'Antigravity',
7
+ async detect(projectRoot) {
8
+ return (existsSync(join(projectRoot, '.agent')) ||
9
+ existsSync(join(projectRoot, 'AGENTS.md')));
10
+ },
11
+ async generate(skills, canonicalDir) {
12
+ const files = [];
13
+ for (const skill of skills) {
14
+ files.push({
15
+ path: `.agent/skills/${skill.directory}/SKILL.md`,
16
+ content: reconstructSkillMd(skill),
17
+ });
18
+ if (skill.workflowContent) {
19
+ files.push({
20
+ path: `.agent/skills/${skill.directory}/workflow.md`,
21
+ content: skill.workflowContent,
22
+ });
23
+ }
24
+ }
25
+ const agentsMd = readCanonicalRule(canonicalDir, 'AGENTS.md');
26
+ if (agentsMd) {
27
+ files.push({ path: '.agent/rules/specsafe.md', content: agentsMd });
28
+ files.push({ path: 'AGENTS.md', content: agentsMd });
29
+ }
30
+ return files;
31
+ },
32
+ };
33
+ //# sourceMappingURL=antigravity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"antigravity.js","sourceRoot":"","sources":["../../src/adapters/antigravity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAEnE,MAAM,CAAC,MAAM,kBAAkB,GAAgB;IAC7C,IAAI,EAAE,aAAa;IACnB,WAAW,EAAE,aAAa;IAE1B,KAAK,CAAC,MAAM,CAAC,WAAmB;QAC9B,OAAO,CACL,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;YACvC,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC,CAC3C,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,MAAwB,EAAE,YAAoB;QAC3D,MAAM,KAAK,GAAoB,EAAE,CAAC;QAElC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,KAAK,CAAC,IAAI,CAAC;gBACT,IAAI,EAAE,iBAAiB,KAAK,CAAC,SAAS,WAAW;gBACjD,OAAO,EAAE,kBAAkB,CAAC,KAAK,CAAC;aACnC,CAAC,CAAC;YACH,IAAI,KAAK,CAAC,eAAe,EAAE,CAAC;gBAC1B,KAAK,CAAC,IAAI,CAAC;oBACT,IAAI,EAAE,iBAAiB,KAAK,CAAC,SAAS,cAAc;oBACpD,OAAO,EAAE,KAAK,CAAC,eAAe;iBAC/B,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,MAAM,QAAQ,GAAG,iBAAiB,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC;QAC9D,IAAI,QAAQ,EAAE,CAAC;YACb,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,0BAA0B,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;YACpE,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;QACvD,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;CACF,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { ToolAdapter } from './types.js';
2
+ export declare const claudeCodeAdapter: ToolAdapter;
@@ -0,0 +1,31 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { readCanonicalRule, reconstructSkillMd } from './utils.js';
4
+ export const claudeCodeAdapter = {
5
+ name: 'claude-code',
6
+ displayName: 'Claude Code',
7
+ async detect(projectRoot) {
8
+ return existsSync(join(projectRoot, '.claude'));
9
+ },
10
+ async generate(skills, canonicalDir) {
11
+ const files = [];
12
+ for (const skill of skills) {
13
+ files.push({
14
+ path: `.claude/skills/${skill.directory}/SKILL.md`,
15
+ content: reconstructSkillMd(skill),
16
+ });
17
+ if (skill.workflowContent) {
18
+ files.push({
19
+ path: `.claude/skills/${skill.directory}/workflow.md`,
20
+ content: skill.workflowContent,
21
+ });
22
+ }
23
+ }
24
+ const claudeMd = readCanonicalRule(canonicalDir, 'CLAUDE.md');
25
+ if (claudeMd) {
26
+ files.push({ path: 'CLAUDE.md', content: claudeMd });
27
+ }
28
+ return files;
29
+ },
30
+ };
31
+ //# sourceMappingURL=claude-code.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-code.js","sourceRoot":"","sources":["../../src/adapters/claude-code.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAEnE,MAAM,CAAC,MAAM,iBAAiB,GAAgB;IAC5C,IAAI,EAAE,aAAa;IACnB,WAAW,EAAE,aAAa;IAE1B,KAAK,CAAC,MAAM,CAAC,WAAmB;QAC9B,OAAO,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC,CAAC;IAClD,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,MAAwB,EAAE,YAAoB;QAC3D,MAAM,KAAK,GAAoB,EAAE,CAAC;QAElC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,KAAK,CAAC,IAAI,CAAC;gBACT,IAAI,EAAE,kBAAkB,KAAK,CAAC,SAAS,WAAW;gBAClD,OAAO,EAAE,kBAAkB,CAAC,KAAK,CAAC;aACnC,CAAC,CAAC;YACH,IAAI,KAAK,CAAC,eAAe,EAAE,CAAC;gBAC1B,KAAK,CAAC,IAAI,CAAC;oBACT,IAAI,EAAE,kBAAkB,KAAK,CAAC,SAAS,cAAc;oBACrD,OAAO,EAAE,KAAK,CAAC,eAAe;iBAC/B,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,MAAM,QAAQ,GAAG,iBAAiB,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC;QAC9D,IAAI,QAAQ,EAAE,CAAC;YACb,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;QACvD,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;CACF,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { ToolAdapter } from './types.js';
2
+ export declare const continueAdapter: ToolAdapter;
@@ -0,0 +1,33 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { readCanonicalRule } from './utils.js';
4
+ export const continueAdapter = {
5
+ name: 'continue',
6
+ displayName: 'Continue',
7
+ async detect(projectRoot) {
8
+ return existsSync(join(projectRoot, '.continue'));
9
+ },
10
+ async generate(skills, canonicalDir) {
11
+ const files = [];
12
+ for (const skill of skills) {
13
+ let body = skill.content;
14
+ if (skill.workflowContent) {
15
+ body += '\n' + skill.workflowContent;
16
+ }
17
+ const displayName = skill.name
18
+ .split('-')
19
+ .map((w) => w.charAt(0).toUpperCase() + w.slice(1))
20
+ .join(' ');
21
+ files.push({
22
+ path: `.continue/prompts/${skill.directory}.md`,
23
+ content: `---\nname: ${displayName}\ndescription: ${skill.description}\ninvokable: true\n---\n\n${body}`,
24
+ });
25
+ }
26
+ const config = readCanonicalRule(canonicalDir, 'continue-config.yaml');
27
+ if (config) {
28
+ files.push({ path: '.continue/agents/specsafe.yaml', content: config });
29
+ }
30
+ return files;
31
+ },
32
+ };
33
+ //# sourceMappingURL=continue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"continue.js","sourceRoot":"","sources":["../../src/adapters/continue.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE/C,MAAM,CAAC,MAAM,eAAe,GAAgB;IAC1C,IAAI,EAAE,UAAU;IAChB,WAAW,EAAE,UAAU;IAEvB,KAAK,CAAC,MAAM,CAAC,WAAmB;QAC9B,OAAO,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC,CAAC;IACpD,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,MAAwB,EAAE,YAAoB;QAC3D,MAAM,KAAK,GAAoB,EAAE,CAAC;QAElC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,IAAI,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC;YACzB,IAAI,KAAK,CAAC,eAAe,EAAE,CAAC;gBAC1B,IAAI,IAAI,IAAI,GAAG,KAAK,CAAC,eAAe,CAAC;YACvC,CAAC;YAED,MAAM,WAAW,GAAG,KAAK,CAAC,IAAI;iBAC3B,KAAK,CAAC,GAAG,CAAC;iBACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;iBAClD,IAAI,CAAC,GAAG,CAAC,CAAC;YAEb,KAAK,CAAC,IAAI,CAAC;gBACT,IAAI,EAAE,qBAAqB,KAAK,CAAC,SAAS,KAAK;gBAC/C,OAAO,EAAE,cAAc,WAAW,kBAAkB,KAAK,CAAC,WAAW,6BAA6B,IAAI,EAAE;aACzG,CAAC,CAAC;QACL,CAAC;QAED,MAAM,MAAM,GAAG,iBAAiB,CAAC,YAAY,EAAE,sBAAsB,CAAC,CAAC;QACvE,IAAI,MAAM,EAAE,CAAC;YACX,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,gCAAgC,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;QAC1E,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;CACF,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { ToolAdapter } from './types.js';
2
+ export declare const cursorAdapter: ToolAdapter;
@@ -0,0 +1,32 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { readCanonicalRule, reconstructSkillMd } from './utils.js';
4
+ export const cursorAdapter = {
5
+ name: 'cursor',
6
+ displayName: 'Cursor',
7
+ async detect(projectRoot) {
8
+ return (existsSync(join(projectRoot, '.cursor')) ||
9
+ existsSync(join(projectRoot, '.cursorrules')));
10
+ },
11
+ async generate(skills, canonicalDir) {
12
+ const files = [];
13
+ for (const skill of skills) {
14
+ files.push({
15
+ path: `.cursor/skills/${skill.directory}/SKILL.md`,
16
+ content: reconstructSkillMd(skill),
17
+ });
18
+ if (skill.workflowContent) {
19
+ files.push({
20
+ path: `.cursor/skills/${skill.directory}/workflow.md`,
21
+ content: skill.workflowContent,
22
+ });
23
+ }
24
+ }
25
+ const cursorRules = readCanonicalRule(canonicalDir, '.cursorrules.mdc');
26
+ if (cursorRules) {
27
+ files.push({ path: '.cursor/rules/specsafe.mdc', content: cursorRules });
28
+ }
29
+ return files;
30
+ },
31
+ };
32
+ //# sourceMappingURL=cursor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursor.js","sourceRoot":"","sources":["../../src/adapters/cursor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAEnE,MAAM,CAAC,MAAM,aAAa,GAAgB;IACxC,IAAI,EAAE,QAAQ;IACd,WAAW,EAAE,QAAQ;IAErB,KAAK,CAAC,MAAM,CAAC,WAAmB;QAC9B,OAAO,CACL,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;YACxC,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC,CAC9C,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,MAAwB,EAAE,YAAoB;QAC3D,MAAM,KAAK,GAAoB,EAAE,CAAC;QAElC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,KAAK,CAAC,IAAI,CAAC;gBACT,IAAI,EAAE,kBAAkB,KAAK,CAAC,SAAS,WAAW;gBAClD,OAAO,EAAE,kBAAkB,CAAC,KAAK,CAAC;aACnC,CAAC,CAAC;YACH,IAAI,KAAK,CAAC,eAAe,EAAE,CAAC;gBAC1B,KAAK,CAAC,IAAI,CAAC;oBACT,IAAI,EAAE,kBAAkB,KAAK,CAAC,SAAS,cAAc;oBACrD,OAAO,EAAE,KAAK,CAAC,eAAe;iBAC/B,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,MAAM,WAAW,GAAG,iBAAiB,CAAC,YAAY,EAAE,kBAAkB,CAAC,CAAC;QACxE,IAAI,WAAW,EAAE,CAAC;YAChB,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,4BAA4B,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC;QAC3E,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;CACF,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { ToolAdapter } from './types.js';
2
+ export declare const geminiAdapter: ToolAdapter;
@@ -0,0 +1,36 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { readCanonicalRule, reconstructSkillMd } from './utils.js';
4
+ export const geminiAdapter = {
5
+ name: 'gemini',
6
+ displayName: 'Gemini',
7
+ async detect(projectRoot) {
8
+ return (existsSync(join(projectRoot, '.gemini')) ||
9
+ existsSync(join(projectRoot, 'GEMINI.md')));
10
+ },
11
+ async generate(skills, canonicalDir) {
12
+ const files = [];
13
+ for (const skill of skills) {
14
+ files.push({
15
+ path: `.gemini/skills/${skill.directory}/SKILL.md`,
16
+ content: reconstructSkillMd(skill),
17
+ });
18
+ if (skill.workflowContent) {
19
+ files.push({
20
+ path: `.gemini/skills/${skill.directory}/workflow.md`,
21
+ content: skill.workflowContent,
22
+ });
23
+ }
24
+ files.push({
25
+ path: `.gemini/commands/${skill.directory}.toml`,
26
+ content: `description = "${skill.description}"\nprompt = "Activate the ${skill.name} skill. {{args}}"\n`,
27
+ });
28
+ }
29
+ const geminiMd = readCanonicalRule(canonicalDir, 'GEMINI.md');
30
+ if (geminiMd) {
31
+ files.push({ path: 'GEMINI.md', content: geminiMd });
32
+ }
33
+ return files;
34
+ },
35
+ };
36
+ //# sourceMappingURL=gemini.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gemini.js","sourceRoot":"","sources":["../../src/adapters/gemini.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAEnE,MAAM,CAAC,MAAM,aAAa,GAAgB;IACxC,IAAI,EAAE,QAAQ;IACd,WAAW,EAAE,QAAQ;IAErB,KAAK,CAAC,MAAM,CAAC,WAAmB;QAC9B,OAAO,CACL,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;YACxC,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC,CAC3C,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,MAAwB,EAAE,YAAoB;QAC3D,MAAM,KAAK,GAAoB,EAAE,CAAC;QAElC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,KAAK,CAAC,IAAI,CAAC;gBACT,IAAI,EAAE,kBAAkB,KAAK,CAAC,SAAS,WAAW;gBAClD,OAAO,EAAE,kBAAkB,CAAC,KAAK,CAAC;aACnC,CAAC,CAAC;YACH,IAAI,KAAK,CAAC,eAAe,EAAE,CAAC;gBAC1B,KAAK,CAAC,IAAI,CAAC;oBACT,IAAI,EAAE,kBAAkB,KAAK,CAAC,SAAS,cAAc;oBACrD,OAAO,EAAE,KAAK,CAAC,eAAe;iBAC/B,CAAC,CAAC;YACL,CAAC;YACD,KAAK,CAAC,IAAI,CAAC;gBACT,IAAI,EAAE,oBAAoB,KAAK,CAAC,SAAS,OAAO;gBAChD,OAAO,EAAE,kBAAkB,KAAK,CAAC,WAAW,6BAA6B,KAAK,CAAC,IAAI,qBAAqB;aACzG,CAAC,CAAC;QACL,CAAC;QAED,MAAM,QAAQ,GAAG,iBAAiB,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC;QAC9D,IAAI,QAAQ,EAAE,CAAC;YACb,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;QACvD,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;CACF,CAAC"}
@@ -0,0 +1,13 @@
1
+ export { claudeCodeAdapter } from './claude-code.js';
2
+ export { opencodeAdapter } from './opencode.js';
3
+ export { cursorAdapter } from './cursor.js';
4
+ export { continueAdapter } from './continue.js';
5
+ export { aiderAdapter } from './aider.js';
6
+ export { zedAdapter } from './zed.js';
7
+ export { geminiAdapter } from './gemini.js';
8
+ export { antigravityAdapter } from './antigravity.js';
9
+ export { loadCanonicalSkills, parseFrontmatter, readCanonicalRule, reconstructSkillMd } from './utils.js';
10
+ export type { ToolAdapter, CanonicalSkill, GeneratedFile, SpecSafeConfig, ToolName } from './types.js';
11
+ export { TOOL_NAMES } from './types.js';
12
+ import type { ToolAdapter } from './types.js';
13
+ export declare const adapters: Record<string, ToolAdapter>;
@@ -0,0 +1,29 @@
1
+ export { claudeCodeAdapter } from './claude-code.js';
2
+ export { opencodeAdapter } from './opencode.js';
3
+ export { cursorAdapter } from './cursor.js';
4
+ export { continueAdapter } from './continue.js';
5
+ export { aiderAdapter } from './aider.js';
6
+ export { zedAdapter } from './zed.js';
7
+ export { geminiAdapter } from './gemini.js';
8
+ export { antigravityAdapter } from './antigravity.js';
9
+ export { loadCanonicalSkills, parseFrontmatter, readCanonicalRule, reconstructSkillMd } from './utils.js';
10
+ export { TOOL_NAMES } from './types.js';
11
+ import { claudeCodeAdapter } from './claude-code.js';
12
+ import { opencodeAdapter } from './opencode.js';
13
+ import { cursorAdapter } from './cursor.js';
14
+ import { continueAdapter } from './continue.js';
15
+ import { aiderAdapter } from './aider.js';
16
+ import { zedAdapter } from './zed.js';
17
+ import { geminiAdapter } from './gemini.js';
18
+ import { antigravityAdapter } from './antigravity.js';
19
+ export const adapters = {
20
+ 'claude-code': claudeCodeAdapter,
21
+ opencode: opencodeAdapter,
22
+ cursor: cursorAdapter,
23
+ continue: continueAdapter,
24
+ aider: aiderAdapter,
25
+ zed: zedAdapter,
26
+ gemini: geminiAdapter,
27
+ antigravity: antigravityAdapter,
28
+ };
29
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/adapters/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAE1G,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAGxC,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAEtD,MAAM,CAAC,MAAM,QAAQ,GAAgC;IACnD,aAAa,EAAE,iBAAiB;IAChC,QAAQ,EAAE,eAAe;IACzB,MAAM,EAAE,aAAa;IACrB,QAAQ,EAAE,eAAe;IACzB,KAAK,EAAE,YAAY;IACnB,GAAG,EAAE,UAAU;IACf,MAAM,EAAE,aAAa;IACrB,WAAW,EAAE,kBAAkB;CAChC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { ToolAdapter } from './types.js';
2
+ export declare const opencodeAdapter: ToolAdapter;
@@ -0,0 +1,32 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { reconstructSkillMd } from './utils.js';
4
+ export const opencodeAdapter = {
5
+ name: 'opencode',
6
+ displayName: 'OpenCode',
7
+ async detect(projectRoot) {
8
+ return (existsSync(join(projectRoot, '.opencode')) ||
9
+ existsSync(join(projectRoot, 'OPENCODE.md')));
10
+ },
11
+ async generate(skills, _canonicalDir) {
12
+ const files = [];
13
+ for (const skill of skills) {
14
+ files.push({
15
+ path: `.opencode/skills/${skill.directory}/SKILL.md`,
16
+ content: reconstructSkillMd(skill),
17
+ });
18
+ if (skill.workflowContent) {
19
+ files.push({
20
+ path: `.opencode/skills/${skill.directory}/workflow.md`,
21
+ content: skill.workflowContent,
22
+ });
23
+ }
24
+ files.push({
25
+ path: `.opencode/command/${skill.directory}.md`,
26
+ content: `---\ndescription: ${skill.description}\n---\n\nFollow the instructions in the skill: ${skill.name}\n`,
27
+ });
28
+ }
29
+ return files;
30
+ },
31
+ };
32
+ //# sourceMappingURL=opencode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opencode.js","sourceRoot":"","sources":["../../src/adapters/opencode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAEhD,MAAM,CAAC,MAAM,eAAe,GAAgB;IAC1C,IAAI,EAAE,UAAU;IAChB,WAAW,EAAE,UAAU;IAEvB,KAAK,CAAC,MAAM,CAAC,WAAmB;QAC9B,OAAO,CACL,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;YAC1C,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC,CAC7C,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,MAAwB,EAAE,aAAqB;QAC5D,MAAM,KAAK,GAAoB,EAAE,CAAC;QAElC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,KAAK,CAAC,IAAI,CAAC;gBACT,IAAI,EAAE,oBAAoB,KAAK,CAAC,SAAS,WAAW;gBACpD,OAAO,EAAE,kBAAkB,CAAC,KAAK,CAAC;aACnC,CAAC,CAAC;YACH,IAAI,KAAK,CAAC,eAAe,EAAE,CAAC;gBAC1B,KAAK,CAAC,IAAI,CAAC;oBACT,IAAI,EAAE,oBAAoB,KAAK,CAAC,SAAS,cAAc;oBACvD,OAAO,EAAE,KAAK,CAAC,eAAe;iBAC/B,CAAC,CAAC;YACL,CAAC;YACD,KAAK,CAAC,IAAI,CAAC;gBACT,IAAI,EAAE,qBAAqB,KAAK,CAAC,SAAS,KAAK;gBAC/C,OAAO,EAAE,qBAAqB,KAAK,CAAC,WAAW,kDAAkD,KAAK,CAAC,IAAI,IAAI;aAChH,CAAC,CAAC;QACL,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;CACF,CAAC"}