@specsafe/cli 0.8.0 → 2.0.3
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 +100 -279
- package/canonical/personas/bolt-zane.md +29 -0
- package/canonical/personas/forge-reva.md +29 -0
- package/canonical/personas/herald-cass.md +30 -0
- package/canonical/personas/mason-kai.md +30 -0
- package/canonical/personas/scout-elena.md +27 -0
- package/canonical/personas/warden-lyra.md +30 -0
- package/canonical/rules/.cursorrules.mdc +53 -0
- package/canonical/rules/.rules +48 -0
- package/canonical/rules/AGENTS.md +48 -0
- package/canonical/rules/CLAUDE.md +48 -0
- package/canonical/rules/CONVENTIONS.md +41 -0
- package/canonical/rules/GEMINI.md +50 -0
- package/canonical/rules/continue-config.yaml +5 -0
- package/canonical/skills/specsafe-archive/SKILL.md +63 -0
- package/canonical/skills/specsafe-code/SKILL.md +7 -0
- package/canonical/skills/specsafe-code/workflow.md +212 -0
- package/canonical/skills/specsafe-complete/SKILL.md +7 -0
- package/canonical/skills/specsafe-complete/workflow.md +130 -0
- package/canonical/skills/specsafe-doctor/SKILL.md +103 -0
- package/canonical/skills/specsafe-explore/SKILL.md +7 -0
- package/canonical/skills/specsafe-explore/workflow.md +100 -0
- package/canonical/skills/specsafe-init/SKILL.md +119 -0
- package/canonical/skills/specsafe-new/SKILL.md +7 -0
- package/canonical/skills/specsafe-new/workflow.md +156 -0
- package/canonical/skills/specsafe-qa/SKILL.md +7 -0
- package/canonical/skills/specsafe-qa/workflow.md +223 -0
- package/canonical/skills/specsafe-spec/SKILL.md +7 -0
- package/canonical/skills/specsafe-spec/workflow.md +158 -0
- package/canonical/skills/specsafe-status/SKILL.md +77 -0
- package/canonical/skills/specsafe-test/SKILL.md +7 -0
- package/canonical/skills/specsafe-test/workflow.md +210 -0
- package/canonical/skills/specsafe-verify/SKILL.md +7 -0
- package/canonical/skills/specsafe-verify/workflow.md +143 -0
- package/canonical/templates/project-state-template.md +33 -0
- package/canonical/templates/qa-report-template.md +55 -0
- package/canonical/templates/spec-template.md +52 -0
- package/canonical/templates/specsafe-config-template.json +10 -0
- package/generators/dist/adapters/aider.d.ts +2 -0
- package/generators/dist/adapters/aider.js +23 -0
- package/generators/dist/adapters/aider.js.map +1 -0
- package/generators/dist/adapters/antigravity.d.ts +2 -0
- package/generators/dist/adapters/antigravity.js +33 -0
- package/generators/dist/adapters/antigravity.js.map +1 -0
- package/generators/dist/adapters/claude-code.d.ts +2 -0
- package/generators/dist/adapters/claude-code.js +31 -0
- package/generators/dist/adapters/claude-code.js.map +1 -0
- package/generators/dist/adapters/continue.d.ts +2 -0
- package/generators/dist/adapters/continue.js +33 -0
- package/generators/dist/adapters/continue.js.map +1 -0
- package/generators/dist/adapters/cursor.d.ts +2 -0
- package/generators/dist/adapters/cursor.js +32 -0
- package/generators/dist/adapters/cursor.js.map +1 -0
- package/generators/dist/adapters/gemini.d.ts +2 -0
- package/generators/dist/adapters/gemini.js +36 -0
- package/generators/dist/adapters/gemini.js.map +1 -0
- package/generators/dist/adapters/index.d.ts +13 -0
- package/generators/dist/adapters/index.js +29 -0
- package/generators/dist/adapters/index.js.map +1 -0
- package/generators/dist/adapters/opencode.d.ts +2 -0
- package/generators/dist/adapters/opencode.js +32 -0
- package/generators/dist/adapters/opencode.js.map +1 -0
- package/generators/dist/adapters/types.d.ts +49 -0
- package/generators/dist/adapters/types.js +14 -0
- package/generators/dist/adapters/types.js.map +1 -0
- package/generators/dist/adapters/utils.d.ts +12 -0
- package/generators/dist/adapters/utils.js +68 -0
- package/generators/dist/adapters/utils.js.map +1 -0
- package/generators/dist/adapters/zed.d.ts +2 -0
- package/generators/dist/adapters/zed.js +31 -0
- package/generators/dist/adapters/zed.js.map +1 -0
- package/generators/dist/doctor.d.ts +10 -0
- package/generators/dist/doctor.js +123 -0
- package/generators/dist/doctor.js.map +1 -0
- package/generators/dist/index.d.ts +2 -0
- package/generators/dist/index.js +45 -0
- package/generators/dist/index.js.map +1 -0
- package/generators/dist/init.d.ts +9 -0
- package/generators/dist/init.js +167 -0
- package/generators/dist/init.js.map +1 -0
- package/generators/dist/install.d.ts +5 -0
- package/generators/dist/install.js +66 -0
- package/generators/dist/install.js.map +1 -0
- package/generators/dist/registry.d.ts +3 -0
- package/generators/dist/registry.js +8 -0
- package/generators/dist/registry.js.map +1 -0
- package/generators/dist/update.d.ts +5 -0
- package/generators/dist/update.js +40 -0
- package/generators/dist/update.js.map +1 -0
- package/package.json +31 -27
- package/dist/commands/apply.d.ts +0 -3
- package/dist/commands/apply.d.ts.map +0 -1
- package/dist/commands/apply.js +0 -182
- package/dist/commands/apply.js.map +0 -1
- package/dist/commands/archive.d.ts +0 -3
- package/dist/commands/archive.d.ts.map +0 -1
- package/dist/commands/archive.js +0 -99
- package/dist/commands/archive.js.map +0 -1
- package/dist/commands/capsule.d.ts +0 -8
- package/dist/commands/capsule.d.ts.map +0 -1
- package/dist/commands/capsule.js +0 -466
- package/dist/commands/capsule.js.map +0 -1
- package/dist/commands/complete.d.ts +0 -3
- package/dist/commands/complete.d.ts.map +0 -1
- package/dist/commands/complete.js +0 -140
- package/dist/commands/complete.js.map +0 -1
- package/dist/commands/constitution.d.ts +0 -3
- package/dist/commands/constitution.d.ts.map +0 -1
- package/dist/commands/constitution.js +0 -192
- package/dist/commands/constitution.js.map +0 -1
- package/dist/commands/create.d.ts +0 -10
- package/dist/commands/create.d.ts.map +0 -1
- package/dist/commands/create.js +0 -120
- package/dist/commands/create.js.map +0 -1
- package/dist/commands/delta.d.ts +0 -3
- package/dist/commands/delta.d.ts.map +0 -1
- package/dist/commands/delta.js +0 -82
- package/dist/commands/delta.js.map +0 -1
- package/dist/commands/diff.d.ts +0 -3
- package/dist/commands/diff.d.ts.map +0 -1
- package/dist/commands/diff.js +0 -102
- package/dist/commands/diff.js.map +0 -1
- package/dist/commands/doctor.d.ts +0 -3
- package/dist/commands/doctor.d.ts.map +0 -1
- package/dist/commands/doctor.js +0 -204
- package/dist/commands/doctor.js.map +0 -1
- package/dist/commands/done.d.ts +0 -3
- package/dist/commands/done.d.ts.map +0 -1
- package/dist/commands/done.js +0 -237
- package/dist/commands/done.js.map +0 -1
- package/dist/commands/explore.d.ts +0 -3
- package/dist/commands/explore.d.ts.map +0 -1
- package/dist/commands/explore.js +0 -236
- package/dist/commands/explore.js.map +0 -1
- package/dist/commands/export.d.ts +0 -7
- package/dist/commands/export.d.ts.map +0 -1
- package/dist/commands/export.js +0 -179
- package/dist/commands/export.js.map +0 -1
- package/dist/commands/extend.d.ts +0 -6
- package/dist/commands/extend.d.ts.map +0 -1
- package/dist/commands/extend.js +0 -167
- package/dist/commands/extend.js.map +0 -1
- package/dist/commands/init-old.d.ts +0 -3
- package/dist/commands/init-old.d.ts.map +0 -1
- package/dist/commands/init-old.js +0 -146
- package/dist/commands/init-old.js.map +0 -1
- package/dist/commands/init.d.ts +0 -3
- package/dist/commands/init.d.ts.map +0 -1
- package/dist/commands/init.js +0 -298
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/list.d.ts +0 -3
- package/dist/commands/list.d.ts.map +0 -1
- package/dist/commands/list.js +0 -122
- package/dist/commands/list.js.map +0 -1
- package/dist/commands/memory.d.ts +0 -3
- package/dist/commands/memory.d.ts.map +0 -1
- package/dist/commands/memory.js +0 -166
- package/dist/commands/memory.js.map +0 -1
- package/dist/commands/new.d.ts +0 -3
- package/dist/commands/new.d.ts.map +0 -1
- package/dist/commands/new.js +0 -508
- package/dist/commands/new.js.map +0 -1
- package/dist/commands/qa.d.ts +0 -3
- package/dist/commands/qa.d.ts.map +0 -1
- package/dist/commands/qa.js +0 -179
- package/dist/commands/qa.js.map +0 -1
- package/dist/commands/rules.d.ts +0 -6
- package/dist/commands/rules.d.ts.map +0 -1
- package/dist/commands/rules.js +0 -232
- package/dist/commands/rules.js.map +0 -1
- package/dist/commands/shard.d.ts +0 -6
- package/dist/commands/shard.d.ts.map +0 -1
- package/dist/commands/shard.js +0 -199
- package/dist/commands/shard.js.map +0 -1
- package/dist/commands/spec.d.ts +0 -3
- package/dist/commands/spec.d.ts.map +0 -1
- package/dist/commands/spec.js +0 -302
- package/dist/commands/spec.js.map +0 -1
- package/dist/commands/status.d.ts +0 -3
- package/dist/commands/status.d.ts.map +0 -1
- package/dist/commands/status.js +0 -47
- package/dist/commands/status.js.map +0 -1
- package/dist/commands/test-apply.d.ts +0 -3
- package/dist/commands/test-apply.d.ts.map +0 -1
- package/dist/commands/test-apply.js +0 -228
- package/dist/commands/test-apply.js.map +0 -1
- package/dist/commands/test-create.d.ts +0 -3
- package/dist/commands/test-create.d.ts.map +0 -1
- package/dist/commands/test-create.js +0 -183
- package/dist/commands/test-create.js.map +0 -1
- package/dist/commands/test-guide.d.ts +0 -3
- package/dist/commands/test-guide.d.ts.map +0 -1
- package/dist/commands/test-guide.js +0 -190
- package/dist/commands/test-guide.js.map +0 -1
- package/dist/commands/test-report.d.ts +0 -3
- package/dist/commands/test-report.d.ts.map +0 -1
- package/dist/commands/test-report.js +0 -196
- package/dist/commands/test-report.js.map +0 -1
- package/dist/commands/test-submit.d.ts +0 -6
- package/dist/commands/test-submit.d.ts.map +0 -1
- package/dist/commands/test-submit.js +0 -236
- package/dist/commands/test-submit.js.map +0 -1
- package/dist/commands/verify.d.ts +0 -3
- package/dist/commands/verify.d.ts.map +0 -1
- package/dist/commands/verify.js +0 -288
- package/dist/commands/verify.js.map +0 -1
- package/dist/config.d.ts +0 -23
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js +0 -44
- package/dist/config.js.map +0 -1
- package/dist/index.d.ts +0 -8
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -129
- package/dist/index.js.map +0 -1
- package/dist/rules/downloader.d.ts +0 -40
- package/dist/rules/downloader.d.ts.map +0 -1
- package/dist/rules/downloader.js +0 -253
- package/dist/rules/downloader.js.map +0 -1
- package/dist/rules/index.d.ts +0 -8
- package/dist/rules/index.d.ts.map +0 -1
- package/dist/rules/index.js +0 -8
- package/dist/rules/index.js.map +0 -1
- package/dist/rules/registry.d.ts +0 -45
- package/dist/rules/registry.d.ts.map +0 -1
- package/dist/rules/registry.js +0 -158
- package/dist/rules/registry.js.map +0 -1
- package/dist/rules/types.d.ts +0 -86
- package/dist/rules/types.d.ts.map +0 -1
- package/dist/rules/types.js +0 -6
- package/dist/rules/types.js.map +0 -1
- package/dist/utils/detectTools.d.ts +0 -15
- package/dist/utils/detectTools.d.ts.map +0 -1
- package/dist/utils/detectTools.js +0 -54
- package/dist/utils/detectTools.js.map +0 -1
- package/dist/utils/generateToolConfig.d.ts +0 -12
- package/dist/utils/generateToolConfig.d.ts.map +0 -1
- package/dist/utils/generateToolConfig.js +0 -1179
- package/dist/utils/generateToolConfig.js.map +0 -1
- package/dist/utils/testRunner.d.ts +0 -39
- package/dist/utils/testRunner.d.ts.map +0 -1
- package/dist/utils/testRunner.js +0 -325
- 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,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,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,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,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,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,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,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"}
|