@fission-ai/openspec 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/README.md +285 -77
- package/dist/cli/index.js +14 -14
- package/dist/core/config.d.ts +7 -5
- package/dist/core/config.js +3 -4
- package/dist/core/configurators/agents.d.ts +8 -0
- package/dist/core/configurators/agents.js +15 -0
- package/dist/core/configurators/registry.js +3 -0
- package/dist/core/configurators/slash/base.d.ts +17 -0
- package/dist/core/configurators/slash/base.js +61 -0
- package/dist/core/configurators/slash/claude.d.ts +9 -0
- package/dist/core/configurators/slash/claude.js +37 -0
- package/dist/core/configurators/slash/cursor.d.ts +9 -0
- package/dist/core/configurators/slash/cursor.js +37 -0
- package/dist/core/configurators/slash/registry.d.ts +8 -0
- package/dist/core/configurators/slash/registry.js +21 -0
- package/dist/core/init.d.ts +28 -0
- package/dist/core/init.js +387 -47
- package/dist/core/templates/agents-template.d.ts +2 -0
- package/dist/core/templates/agents-template.js +455 -0
- package/dist/core/templates/claude-template.d.ts +1 -1
- package/dist/core/templates/claude-template.js +1 -95
- package/dist/core/templates/index.d.ts +4 -0
- package/dist/core/templates/index.js +10 -3
- package/dist/core/templates/slash-command-templates.d.ts +4 -0
- package/dist/core/templates/slash-command-templates.js +40 -0
- package/dist/core/update.js +39 -6
- package/dist/core/view.d.ts +8 -0
- package/dist/core/view.js +148 -0
- package/dist/utils/file-system.d.ts +1 -0
- package/dist/utils/file-system.js +16 -0
- package/package.json +2 -2
- package/dist/core/diff.d.ts +0 -11
- package/dist/core/diff.js +0 -193
- package/dist/core/templates/readme-template.d.ts +0 -2
- package/dist/core/templates/readme-template.js +0 -519
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 OpenSpec Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
package/README.md
CHANGED
|
@@ -1,119 +1,327 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://github.com/Fission-AI/OpenSpec">
|
|
3
|
+
<picture>
|
|
4
|
+
<source srcset="assets/openspec_pixel_dark.svg" media="(prefers-color-scheme: dark)">
|
|
5
|
+
<source srcset="assets/openspec_pixel_light.svg" media="(prefers-color-scheme: light)">
|
|
6
|
+
<img src="assets/openspec_pixel_light.svg" alt="OpenSpec logo" height="64">
|
|
7
|
+
</picture>
|
|
8
|
+
</a>
|
|
9
|
+
|
|
10
|
+
</p>
|
|
11
|
+
<p align="center">Spec-driven development for AI coding assistants.</p>
|
|
12
|
+
<p align="center">
|
|
13
|
+
<a href="https://github.com/Fission-AI/OpenSpec/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/Fission-AI/OpenSpec/actions/workflows/ci.yml/badge.svg" /></a>
|
|
14
|
+
<a href="https://www.npmjs.com/package/@fission-ai/openspec"><img alt="npm version" src="https://img.shields.io/npm/v/@fission-ai/openspec?style=flat-square" /></a>
|
|
15
|
+
<a href="https://nodejs.org/"><img alt="node version" src="https://img.shields.io/node/v/@fission-ai/openspec?style=flat-square" /></a>
|
|
16
|
+
<a href="./LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square" /></a>
|
|
17
|
+
<a href="https://conventionalcommits.org"><img alt="Conventional Commits" src="https://img.shields.io/badge/Conventional%20Commits-1.0.0-yellow.svg?style=flat-square" /></a>
|
|
18
|
+
</p>
|
|
19
|
+
|
|
20
|
+
<p align="center">
|
|
21
|
+
<img src="assets/openspec_dashboard.png" alt="OpenSpec dashboard preview" width="90%">
|
|
22
|
+
</p>
|
|
23
|
+
|
|
24
|
+
<p align="center">
|
|
25
|
+
Follow <a href="https://x.com/0xTab">@0xTab on X</a> for updates.
|
|
26
|
+
</p>
|
|
27
|
+
|
|
1
28
|
# OpenSpec
|
|
2
29
|
|
|
3
|
-
|
|
30
|
+
OpenSpec aligns humans and AI coding assistants with spec-driven development so you agree on what to build before any code is written. **No API keys required.**
|
|
31
|
+
|
|
32
|
+
## Why OpenSpec?
|
|
33
|
+
|
|
34
|
+
AI coding assistants are powerful but unpredictable when requirements live in chat history. OpenSpec adds a lightweight specification workflow that locks intent before implementation, giving you deterministic, reviewable outputs.
|
|
35
|
+
|
|
36
|
+
Key outcomes:
|
|
37
|
+
- Human and AI stakeholders agree on specs before work begins.
|
|
38
|
+
- Structured change folders (proposals, tasks, and spec updates) keep scope explicit and auditable.
|
|
39
|
+
- Shared visibility into what's proposed, active, or archived.
|
|
40
|
+
- Works with the AI tools you already use: custom slash commands where supported, context rules everywhere else.
|
|
41
|
+
|
|
42
|
+
## How It Works
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
┌────────────────────┐
|
|
46
|
+
│ Draft Change │
|
|
47
|
+
│ Proposal │
|
|
48
|
+
└────────┬───────────┘
|
|
49
|
+
│ share intent with your AI
|
|
50
|
+
▼
|
|
51
|
+
┌────────────────────┐
|
|
52
|
+
│ Review & Align │
|
|
53
|
+
│ (edit specs/tasks) │◀──── feedback loop ──────┐
|
|
54
|
+
└────────┬───────────┘ │
|
|
55
|
+
│ approved plan │
|
|
56
|
+
▼ │
|
|
57
|
+
┌────────────────────┐ │
|
|
58
|
+
│ Implement Tasks │──────────────────────────┘
|
|
59
|
+
│ (AI writes code) │
|
|
60
|
+
└────────┬───────────┘
|
|
61
|
+
│ ship the change
|
|
62
|
+
▼
|
|
63
|
+
┌────────────────────┐
|
|
64
|
+
│ Archive & Update │
|
|
65
|
+
│ Specs (source) │
|
|
66
|
+
└────────────────────┘
|
|
67
|
+
|
|
68
|
+
1. Draft a change proposal that captures the spec updates you want.
|
|
69
|
+
2. Review the proposal with your AI assistant until everyone agrees.
|
|
70
|
+
3. Implement tasks that reference the agreed specs.
|
|
71
|
+
4. Archive the change to merge the approved updates back into the source-of-truth specs.
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Getting Started
|
|
4
75
|
|
|
5
|
-
|
|
76
|
+
### Supported AI Tools
|
|
77
|
+
|
|
78
|
+
#### Native Slash Commands
|
|
79
|
+
These tools have built-in OpenSpec commands. Select the OpenSpec integration when prompted.
|
|
80
|
+
|
|
81
|
+
| Tool | Commands |
|
|
82
|
+
|------|----------|
|
|
83
|
+
| **Claude Code** | `/openspec:proposal`, `/openspec:apply`, `/openspec:archive` |
|
|
84
|
+
| **Cursor** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` |
|
|
85
|
+
|
|
86
|
+
#### AGENTS.md Compatible
|
|
87
|
+
These tools automatically read workflow instructions from `openspec/AGENTS.md`. Ask them to follow the OpenSpec workflow if they need a reminder. Learn more about the [AGENTS.md convention](https://agents.md/).
|
|
88
|
+
|
|
89
|
+
| Tools |
|
|
90
|
+
|-------|
|
|
91
|
+
| Codex • Amp • Jules • OpenCode • Gemini CLI • GitHub Copilot • Others |
|
|
92
|
+
|
|
93
|
+
### Install & Initialize
|
|
94
|
+
|
|
95
|
+
#### Prerequisites
|
|
96
|
+
- **Node.js >= 20.19.0** - Check your version with `node --version`
|
|
97
|
+
|
|
98
|
+
#### Step 1: Install the CLI globally
|
|
6
99
|
|
|
7
100
|
```bash
|
|
8
|
-
npm install -g openspec
|
|
101
|
+
npm install -g @fission-ai/openspec@latest
|
|
9
102
|
```
|
|
10
103
|
|
|
11
|
-
|
|
104
|
+
Verify installation:
|
|
105
|
+
```bash
|
|
106
|
+
openspec --version
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
#### Step 2: Initialize OpenSpec in your project
|
|
110
|
+
|
|
111
|
+
Navigate to your project directory:
|
|
112
|
+
```bash
|
|
113
|
+
cd my-project
|
|
114
|
+
```
|
|
12
115
|
|
|
116
|
+
Run the initialization:
|
|
13
117
|
```bash
|
|
14
|
-
# Initialize OpenSpec in your project
|
|
15
118
|
openspec init
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**What happens during initialization:**
|
|
122
|
+
- You'll be prompted to select your AI tool (Claude Code, Cursor, etc.)
|
|
123
|
+
- OpenSpec automatically configures slash commands or `AGENTS.md` based on your selection
|
|
124
|
+
- A new `openspec/` directory structure is created in your project
|
|
125
|
+
|
|
126
|
+
**After setup:**
|
|
127
|
+
- Primary AI tools can trigger `/openspec` workflows without additional configuration
|
|
128
|
+
- Run `openspec list` to verify the setup and view any active changes
|
|
129
|
+
|
|
130
|
+
### Create Your First Change
|
|
131
|
+
|
|
132
|
+
Here's a real example showing the complete OpenSpec workflow. This works with any AI tool. Those with native slash commands will recognize the shortcuts automatically.
|
|
133
|
+
|
|
134
|
+
#### 1. Draft the Proposal
|
|
135
|
+
Start by asking your AI to create a change proposal:
|
|
136
|
+
|
|
137
|
+
```text
|
|
138
|
+
You: Create an OpenSpec change proposal for adding profile search filters by role and team
|
|
139
|
+
(Shortcut for tools with slash commands: /openspec:proposal Add profile search filters)
|
|
140
|
+
|
|
141
|
+
AI: I'll create an OpenSpec change proposal for profile filters.
|
|
142
|
+
*Scaffolds openspec/changes/add-profile-filters/ with proposal.md, tasks.md, spec deltas.*
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
#### 2. Verify & Review
|
|
146
|
+
Check that the change was created correctly and review the proposal:
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
$ openspec list # Confirm the change folder exists
|
|
150
|
+
$ openspec validate add-profile-filters # Validate spec formatting
|
|
151
|
+
$ openspec show add-profile-filters # Review proposal, tasks, and spec delta
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
#### 3. Refine the Specs
|
|
155
|
+
Iterate on the specifications until they match your needs:
|
|
16
156
|
|
|
17
|
-
|
|
18
|
-
|
|
157
|
+
```text
|
|
158
|
+
You: Can you add acceptance criteria for the role and team filters?
|
|
159
|
+
|
|
160
|
+
AI: I'll update the spec delta with scenarios for role and team filters.
|
|
161
|
+
*Edits openspec/changes/add-profile-filters/specs/profile/spec.md and tasks.md.*
|
|
162
|
+
```
|
|
19
163
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
openspec change list # changes (IDs by default; use --long for details)
|
|
164
|
+
#### 4. Implement the Change
|
|
165
|
+
Once specs look good, start implementation:
|
|
23
166
|
|
|
24
|
-
|
|
25
|
-
|
|
167
|
+
```text
|
|
168
|
+
You: The specs look good. Let's implement this change.
|
|
169
|
+
(Shortcut for tools with slash commands: /openspec:apply add-profile-filters)
|
|
26
170
|
|
|
27
|
-
|
|
28
|
-
|
|
171
|
+
AI: I'll work through the tasks in the add-profile-filters change.
|
|
172
|
+
*Implements tasks from openspec/changes/add-profile-filters/tasks.md*
|
|
173
|
+
*Marks tasks complete: Task 1.1 ✓, Task 1.2 ✓, Task 2.1 ✓...*
|
|
29
174
|
```
|
|
30
175
|
|
|
31
|
-
|
|
176
|
+
#### 5. Archive the Completed Change
|
|
177
|
+
After implementation is complete, archive the change:
|
|
32
178
|
|
|
33
|
-
|
|
179
|
+
```text
|
|
180
|
+
AI: All tasks are complete. The implementation is ready.
|
|
34
181
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
- `openspec/README.md` with OpenSpec instructions
|
|
38
|
-
- AI tool configuration files (based on your selection)
|
|
182
|
+
You: Please archive the change
|
|
183
|
+
(Shortcut for tools with slash commands: /openspec:archive add-profile-filters)
|
|
39
184
|
|
|
40
|
-
|
|
185
|
+
AI: I'll archive the add-profile-filters change.
|
|
186
|
+
*Runs: openspec archive add-profile-filters*
|
|
187
|
+
✓ Change archived successfully. Specs updated. Ready for the next feature!
|
|
188
|
+
```
|
|
41
189
|
|
|
42
|
-
|
|
190
|
+
Or run the command yourself in terminal:
|
|
191
|
+
```bash
|
|
192
|
+
$ openspec archive add-profile-filters # Archive the completed change
|
|
193
|
+
```
|
|
43
194
|
|
|
44
|
-
|
|
45
|
-
- **Only updates existing AI tool configuration files** (e.g., CLAUDE.md, CURSOR.md)
|
|
46
|
-
- **Never creates new AI tool configuration files**
|
|
47
|
-
- Preserves content outside of OpenSpec markers in AI tool files
|
|
195
|
+
**Note:** Tools with native slash commands (Claude Code, Cursor) can use the shortcuts shown. All other tools work with natural language requests to "create an OpenSpec proposal", "apply the OpenSpec change", or "archive the change".
|
|
48
196
|
|
|
49
|
-
|
|
197
|
+
## Command Reference
|
|
50
198
|
|
|
51
|
-
|
|
199
|
+
```bash
|
|
200
|
+
openspec list # View active change folders
|
|
201
|
+
openspec view # Interactive dashboard of specs and changes
|
|
202
|
+
openspec show <change> # Display change details (proposal, tasks, spec updates)
|
|
203
|
+
openspec validate <change> # Check spec formatting and structure
|
|
204
|
+
openspec archive <change> # Move a completed change into archive/
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## Example: How AI Creates OpenSpec Files
|
|
52
208
|
|
|
53
|
-
|
|
209
|
+
When you ask your AI assistant to "add two-factor authentication", it creates:
|
|
54
210
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
211
|
+
```
|
|
212
|
+
openspec/
|
|
213
|
+
├── specs/
|
|
214
|
+
│ └── auth/
|
|
215
|
+
│ └── spec.md # Current auth spec (if exists)
|
|
216
|
+
└── changes/
|
|
217
|
+
└── add-2fa/ # AI creates this entire structure
|
|
218
|
+
├── proposal.md # Why and what changes
|
|
219
|
+
├── tasks.md # Implementation checklist
|
|
220
|
+
├── design.md # Technical decisions (optional)
|
|
221
|
+
└── specs/
|
|
222
|
+
└── auth/
|
|
223
|
+
└── spec.md # Delta showing additions
|
|
224
|
+
```
|
|
66
225
|
|
|
67
|
-
### `openspec
|
|
226
|
+
### AI-Generated Spec (created in `openspec/specs/auth/spec.md`):
|
|
68
227
|
|
|
69
|
-
|
|
228
|
+
```markdown
|
|
229
|
+
# Auth Specification
|
|
70
230
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
- Text mode: prints raw `proposal.md` content
|
|
74
|
-
- JSON mode (`--json`): `{ id, title, deltaCount, deltas }`
|
|
75
|
-
- Filtering is JSON-only: `--deltas-only` (alias: `--requirements-only`, deprecated)
|
|
76
|
-
- `openspec change list`
|
|
77
|
-
- Prints IDs only by default
|
|
78
|
-
- Use `--long` to include `title` and counts `[deltas N] [tasks x/y]`
|
|
79
|
-
- `openspec change validate <change-id>`
|
|
80
|
-
- Text: human-readable result
|
|
81
|
-
- `--json` for structured report
|
|
231
|
+
## Purpose
|
|
232
|
+
Authentication and session management.
|
|
82
233
|
|
|
83
|
-
|
|
234
|
+
## Requirements
|
|
235
|
+
### Requirement: User Authentication
|
|
236
|
+
The system SHALL issue a JWT on successful login.
|
|
84
237
|
|
|
85
|
-
|
|
86
|
-
-
|
|
87
|
-
-
|
|
88
|
-
|
|
238
|
+
#### Scenario: Valid credentials
|
|
239
|
+
- WHEN a user submits valid credentials
|
|
240
|
+
- THEN a JWT is returned
|
|
241
|
+
```
|
|
89
242
|
|
|
90
|
-
### `openspec
|
|
243
|
+
### AI-Generated Change Delta (created in `openspec/changes/add-2fa/specs/auth/spec.md`):
|
|
91
244
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
- Adds a date prefix to the archived change
|
|
95
|
-
- Updates specs to reflect the new state
|
|
96
|
-
- Use `--skip-specs` to archive without updating specs (for abandoned changes)
|
|
245
|
+
```markdown
|
|
246
|
+
# Delta for Auth
|
|
97
247
|
|
|
98
|
-
##
|
|
248
|
+
## ADDED Requirements
|
|
249
|
+
### Requirement: Two-Factor Authentication
|
|
250
|
+
The system MUST require a second factor during login.
|
|
99
251
|
|
|
100
|
-
|
|
252
|
+
#### Scenario: OTP required
|
|
253
|
+
- WHEN a user submits valid credentials
|
|
254
|
+
- THEN an OTP challenge is required
|
|
255
|
+
```
|
|
101
256
|
|
|
102
|
-
|
|
103
|
-
2. **Non-Invasive Updates**: The `update` command only modifies existing files, never forcing tools on team members
|
|
104
|
-
3. **Specification Sharing**: The `openspec/` directory contains shared specifications that all team members work from
|
|
105
|
-
4. **Change Tracking**: Proposed changes are visible to all team members for review before implementation
|
|
257
|
+
### AI-Generated Tasks (created in `openspec/changes/add-2fa/tasks.md`):
|
|
106
258
|
|
|
107
|
-
|
|
259
|
+
```markdown
|
|
260
|
+
## 1. Database Setup
|
|
261
|
+
- [ ] 1.1 Add OTP secret column to users table
|
|
262
|
+
- [ ] 1.2 Create OTP verification logs table
|
|
108
263
|
|
|
109
|
-
|
|
264
|
+
## 2. Backend Implementation
|
|
265
|
+
- [ ] 2.1 Add OTP generation endpoint
|
|
266
|
+
- [ ] 2.2 Modify login flow to require OTP
|
|
267
|
+
- [ ] 2.3 Add OTP verification endpoint
|
|
110
268
|
|
|
111
|
-
##
|
|
269
|
+
## 3. Frontend Updates
|
|
270
|
+
- [ ] 3.1 Create OTP input component
|
|
271
|
+
- [ ] 3.2 Update login flow UI
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
**Important:** You don't create these files manually. Your AI assistant generates them based on your requirements and the existing codebase.
|
|
275
|
+
|
|
276
|
+
## Understanding OpenSpec Files
|
|
277
|
+
|
|
278
|
+
### Delta Format
|
|
279
|
+
|
|
280
|
+
Deltas are "patches" that show how specs change:
|
|
281
|
+
|
|
282
|
+
- **`## ADDED Requirements`** - New capabilities
|
|
283
|
+
- **`## MODIFIED Requirements`** - Changed behavior (include complete updated text)
|
|
284
|
+
- **`## REMOVED Requirements`** - Deprecated features
|
|
285
|
+
|
|
286
|
+
**Format requirements:**
|
|
287
|
+
- Use `### Requirement: <name>` for headers
|
|
288
|
+
- Every requirement needs at least one `#### Scenario:` block
|
|
289
|
+
- Use SHALL/MUST in requirement text
|
|
290
|
+
|
|
291
|
+
## How OpenSpec Compares
|
|
292
|
+
|
|
293
|
+
### vs. Kiro.dev
|
|
294
|
+
OpenSpec groups every change for a feature in one folder (`openspec/changes/feature-name/`), making it easy to track related specs, tasks, and designs together. Kiro spreads updates across multiple spec folders, which can make feature tracking harder.
|
|
295
|
+
|
|
296
|
+
### vs. No Specs
|
|
297
|
+
Without specs, AI coding assistants generate code from vague prompts, often missing requirements or adding unwanted features. OpenSpec brings predictability by agreeing on the desired behavior before any code is written.
|
|
298
|
+
|
|
299
|
+
## Team Adoption
|
|
300
|
+
|
|
301
|
+
1. **Initialize OpenSpec** – Run `openspec init` in your repo.
|
|
302
|
+
2. **Start with new features** – Ask your AI to capture upcoming work as change proposals.
|
|
303
|
+
3. **Grow incrementally** – Each change archives into living specs that document your system.
|
|
304
|
+
4. **Stay flexible** – Different teammates can use Claude Code, Cursor, or any AGENTS.md-compatible tool while sharing the same specs.
|
|
305
|
+
|
|
306
|
+
Run `openspec update` whenever someone switches tools so your agents pick up the latest instructions and slash-command bindings.
|
|
307
|
+
|
|
308
|
+
## Updating OpenSpec
|
|
309
|
+
|
|
310
|
+
1. **Upgrade the package**
|
|
311
|
+
```bash
|
|
312
|
+
npm install -g @fission-ai/openspec@latest
|
|
313
|
+
```
|
|
314
|
+
2. **Refresh agent instructions**
|
|
315
|
+
- Run `openspec update` inside each project to regenerate AI guidance and ensure the latest slash commands are active.
|
|
316
|
+
|
|
317
|
+
## Contributing
|
|
112
318
|
|
|
113
|
-
-
|
|
114
|
-
-
|
|
115
|
-
-
|
|
319
|
+
- Install dependencies: `pnpm install`
|
|
320
|
+
- Build: `pnpm run build`
|
|
321
|
+
- Test: `pnpm test`
|
|
322
|
+
- Develop CLI locally: `pnpm run dev` or `pnpm run dev:cli`
|
|
323
|
+
- Conventional commits (one-line): `type(scope): subject`
|
|
116
324
|
|
|
117
325
|
## License
|
|
118
326
|
|
|
119
|
-
MIT
|
|
327
|
+
MIT
|
package/dist/cli/index.js
CHANGED
|
@@ -5,9 +5,9 @@ import path from 'path';
|
|
|
5
5
|
import { promises as fs } from 'fs';
|
|
6
6
|
import { InitCommand } from '../core/init.js';
|
|
7
7
|
import { UpdateCommand } from '../core/update.js';
|
|
8
|
-
import { DiffCommand } from '../core/diff.js';
|
|
9
8
|
import { ListCommand } from '../core/list.js';
|
|
10
9
|
import { ArchiveCommand } from '../core/archive.js';
|
|
10
|
+
import { ViewCommand } from '../core/view.js';
|
|
11
11
|
import { registerSpecCommand } from '../commands/spec.js';
|
|
12
12
|
import { ChangeCommand } from '../commands/change.js';
|
|
13
13
|
import { ValidateCommand } from '../commands/validate.js';
|
|
@@ -78,12 +78,15 @@ program
|
|
|
78
78
|
}
|
|
79
79
|
});
|
|
80
80
|
program
|
|
81
|
-
.command('
|
|
82
|
-
.description('
|
|
83
|
-
.
|
|
81
|
+
.command('list')
|
|
82
|
+
.description('List items (changes by default). Use --specs to list specs.')
|
|
83
|
+
.option('--specs', 'List specs instead of changes')
|
|
84
|
+
.option('--changes', 'List changes explicitly (default)')
|
|
85
|
+
.action(async (options) => {
|
|
84
86
|
try {
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
+
const listCommand = new ListCommand();
|
|
88
|
+
const mode = options?.specs ? 'specs' : 'changes';
|
|
89
|
+
await listCommand.execute('.', mode);
|
|
87
90
|
}
|
|
88
91
|
catch (error) {
|
|
89
92
|
console.log(); // Empty line for spacing
|
|
@@ -92,15 +95,12 @@ program
|
|
|
92
95
|
}
|
|
93
96
|
});
|
|
94
97
|
program
|
|
95
|
-
.command('
|
|
96
|
-
.description('
|
|
97
|
-
.
|
|
98
|
-
.option('--changes', 'List changes explicitly (default)')
|
|
99
|
-
.action(async (options) => {
|
|
98
|
+
.command('view')
|
|
99
|
+
.description('Display an interactive dashboard of specs and changes')
|
|
100
|
+
.action(async () => {
|
|
100
101
|
try {
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
await listCommand.execute('.', mode);
|
|
102
|
+
const viewCommand = new ViewCommand();
|
|
103
|
+
await viewCommand.execute('.');
|
|
104
104
|
}
|
|
105
105
|
catch (error) {
|
|
106
106
|
console.log(); // Empty line for spacing
|
package/dist/core/config.d.ts
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
export declare const OPENSPEC_DIR_NAME = "openspec";
|
|
2
|
-
export interface OpenSpecConfig {
|
|
3
|
-
aiTools: string[];
|
|
4
|
-
}
|
|
5
2
|
export declare const OPENSPEC_MARKERS: {
|
|
6
3
|
start: string;
|
|
7
4
|
end: string;
|
|
8
5
|
};
|
|
9
|
-
export
|
|
6
|
+
export interface OpenSpecConfig {
|
|
7
|
+
aiTools: string[];
|
|
8
|
+
}
|
|
9
|
+
export interface AIToolOption {
|
|
10
10
|
name: string;
|
|
11
11
|
value: string;
|
|
12
12
|
available: boolean;
|
|
13
|
-
|
|
13
|
+
successLabel?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare const AI_TOOLS: AIToolOption[];
|
|
14
16
|
//# sourceMappingURL=config.d.ts.map
|
package/dist/core/config.js
CHANGED
|
@@ -4,9 +4,8 @@ export const OPENSPEC_MARKERS = {
|
|
|
4
4
|
end: '<!-- OPENSPEC:END -->'
|
|
5
5
|
};
|
|
6
6
|
export const AI_TOOLS = [
|
|
7
|
-
{ name: 'Claude Code', value: 'claude', available: true },
|
|
8
|
-
{ name: 'Cursor', value: 'cursor', available:
|
|
9
|
-
{ name: '
|
|
10
|
-
{ name: 'Continue', value: 'continue', available: false }
|
|
7
|
+
{ name: 'Claude Code (✅ OpenSpec custom slash commands available)', value: 'claude', available: true, successLabel: 'Claude Code' },
|
|
8
|
+
{ name: 'Cursor (✅ OpenSpec custom slash commands available)', value: 'cursor', available: true, successLabel: 'Cursor' },
|
|
9
|
+
{ name: 'AGENTS.md (works with Codex, Amp, Copilot, …)', value: 'agents', available: true, successLabel: 'your AGENTS.md-compatible assistant' }
|
|
11
10
|
];
|
|
12
11
|
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ToolConfigurator } from './base.js';
|
|
2
|
+
export declare class AgentsStandardConfigurator implements ToolConfigurator {
|
|
3
|
+
name: string;
|
|
4
|
+
configFileName: string;
|
|
5
|
+
isAvailable: boolean;
|
|
6
|
+
configure(projectPath: string, _openspecDir: string): Promise<void>;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=agents.d.ts.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { FileSystemUtils } from '../../utils/file-system.js';
|
|
3
|
+
import { TemplateManager } from '../templates/index.js';
|
|
4
|
+
import { OPENSPEC_MARKERS } from '../config.js';
|
|
5
|
+
export class AgentsStandardConfigurator {
|
|
6
|
+
name = 'AGENTS.md standard';
|
|
7
|
+
configFileName = 'AGENTS.md';
|
|
8
|
+
isAvailable = true;
|
|
9
|
+
async configure(projectPath, _openspecDir) {
|
|
10
|
+
const filePath = path.join(projectPath, this.configFileName);
|
|
11
|
+
const content = TemplateManager.getAgentsStandardTemplate();
|
|
12
|
+
await FileSystemUtils.updateFileWithMarkers(filePath, content, OPENSPEC_MARKERS.start, OPENSPEC_MARKERS.end);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=agents.js.map
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { ClaudeConfigurator } from './claude.js';
|
|
2
|
+
import { AgentsStandardConfigurator } from './agents.js';
|
|
2
3
|
export class ToolRegistry {
|
|
3
4
|
static tools = new Map();
|
|
4
5
|
static {
|
|
5
6
|
const claudeConfigurator = new ClaudeConfigurator();
|
|
7
|
+
const agentsConfigurator = new AgentsStandardConfigurator();
|
|
6
8
|
// Register with the ID that matches the checkbox value
|
|
7
9
|
this.tools.set('claude', claudeConfigurator);
|
|
10
|
+
this.tools.set('agents', agentsConfigurator);
|
|
8
11
|
}
|
|
9
12
|
static register(tool) {
|
|
10
13
|
this.tools.set(tool.name.toLowerCase().replace(/\s+/g, '-'), tool);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { SlashCommandId } from '../../templates/index.js';
|
|
2
|
+
export interface SlashCommandTarget {
|
|
3
|
+
id: SlashCommandId;
|
|
4
|
+
path: string;
|
|
5
|
+
kind: 'slash';
|
|
6
|
+
}
|
|
7
|
+
export declare abstract class SlashCommandConfigurator {
|
|
8
|
+
abstract readonly toolId: string;
|
|
9
|
+
abstract readonly isAvailable: boolean;
|
|
10
|
+
getTargets(): SlashCommandTarget[];
|
|
11
|
+
generateAll(projectPath: string, _openspecDir: string): Promise<string[]>;
|
|
12
|
+
updateExisting(projectPath: string, _openspecDir: string): Promise<string[]>;
|
|
13
|
+
protected abstract getRelativePath(id: SlashCommandId): string;
|
|
14
|
+
protected abstract getFrontmatter(id: SlashCommandId): string | undefined;
|
|
15
|
+
private updateBody;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=base.d.ts.map
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { FileSystemUtils } from '../../../utils/file-system.js';
|
|
3
|
+
import { TemplateManager } from '../../templates/index.js';
|
|
4
|
+
import { OPENSPEC_MARKERS } from '../../config.js';
|
|
5
|
+
const ALL_COMMANDS = ['proposal', 'apply', 'archive'];
|
|
6
|
+
export class SlashCommandConfigurator {
|
|
7
|
+
getTargets() {
|
|
8
|
+
return ALL_COMMANDS.map((id) => ({
|
|
9
|
+
id,
|
|
10
|
+
path: this.getRelativePath(id),
|
|
11
|
+
kind: 'slash'
|
|
12
|
+
}));
|
|
13
|
+
}
|
|
14
|
+
async generateAll(projectPath, _openspecDir) {
|
|
15
|
+
const createdOrUpdated = [];
|
|
16
|
+
for (const target of this.getTargets()) {
|
|
17
|
+
const body = TemplateManager.getSlashCommandBody(target.id).trim();
|
|
18
|
+
const filePath = path.join(projectPath, target.path);
|
|
19
|
+
if (await FileSystemUtils.fileExists(filePath)) {
|
|
20
|
+
await this.updateBody(filePath, body);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
const frontmatter = this.getFrontmatter(target.id);
|
|
24
|
+
const sections = [];
|
|
25
|
+
if (frontmatter) {
|
|
26
|
+
sections.push(frontmatter.trim());
|
|
27
|
+
}
|
|
28
|
+
sections.push(`${OPENSPEC_MARKERS.start}\n${body}\n${OPENSPEC_MARKERS.end}`);
|
|
29
|
+
const content = sections.join('\n') + '\n';
|
|
30
|
+
await FileSystemUtils.writeFile(filePath, content);
|
|
31
|
+
}
|
|
32
|
+
createdOrUpdated.push(target.path);
|
|
33
|
+
}
|
|
34
|
+
return createdOrUpdated;
|
|
35
|
+
}
|
|
36
|
+
async updateExisting(projectPath, _openspecDir) {
|
|
37
|
+
const updated = [];
|
|
38
|
+
for (const target of this.getTargets()) {
|
|
39
|
+
const filePath = path.join(projectPath, target.path);
|
|
40
|
+
if (await FileSystemUtils.fileExists(filePath)) {
|
|
41
|
+
const body = TemplateManager.getSlashCommandBody(target.id).trim();
|
|
42
|
+
await this.updateBody(filePath, body);
|
|
43
|
+
updated.push(target.path);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return updated;
|
|
47
|
+
}
|
|
48
|
+
async updateBody(filePath, body) {
|
|
49
|
+
const content = await FileSystemUtils.readFile(filePath);
|
|
50
|
+
const startIndex = content.indexOf(OPENSPEC_MARKERS.start);
|
|
51
|
+
const endIndex = content.indexOf(OPENSPEC_MARKERS.end);
|
|
52
|
+
if (startIndex === -1 || endIndex === -1 || endIndex <= startIndex) {
|
|
53
|
+
throw new Error(`Missing OpenSpec markers in ${filePath}`);
|
|
54
|
+
}
|
|
55
|
+
const before = content.slice(0, startIndex + OPENSPEC_MARKERS.start.length);
|
|
56
|
+
const after = content.slice(endIndex);
|
|
57
|
+
const updatedContent = `${before}\n${body}\n${after}`;
|
|
58
|
+
await FileSystemUtils.writeFile(filePath, updatedContent);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=base.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { SlashCommandConfigurator } from './base.js';
|
|
2
|
+
import { SlashCommandId } from '../../templates/index.js';
|
|
3
|
+
export declare class ClaudeSlashCommandConfigurator extends SlashCommandConfigurator {
|
|
4
|
+
readonly toolId = "claude";
|
|
5
|
+
readonly isAvailable = true;
|
|
6
|
+
protected getRelativePath(id: SlashCommandId): string;
|
|
7
|
+
protected getFrontmatter(id: SlashCommandId): string;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=claude.d.ts.map
|