@fission-ai/openspec 1.3.0 → 1.4.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/README.md +9 -6
- package/bin/openspec.js +3 -1
- package/dist/cli/index.d.ts +4 -1
- package/dist/cli/index.js +46 -2
- package/dist/commands/completion.js +7 -0
- package/dist/commands/config.js +64 -5
- package/dist/commands/context-store.d.ts +3 -0
- package/dist/commands/context-store.js +475 -0
- package/dist/commands/initiative.d.ts +13 -0
- package/dist/commands/initiative.js +318 -0
- package/dist/commands/workflow/index.d.ts +2 -0
- package/dist/commands/workflow/index.js +1 -0
- package/dist/commands/workflow/initiative-link.d.ts +24 -0
- package/dist/commands/workflow/initiative-link.js +47 -0
- package/dist/commands/workflow/instructions.d.ts +1 -1
- package/dist/commands/workflow/instructions.js +46 -83
- package/dist/commands/workflow/new-change.d.ts +6 -0
- package/dist/commands/workflow/new-change.js +114 -17
- package/dist/commands/workflow/set-change.d.ts +13 -0
- package/dist/commands/workflow/set-change.js +87 -0
- package/dist/commands/workflow/shared.d.ts +5 -3
- package/dist/commands/workflow/shared.js +6 -6
- package/dist/commands/workflow/status.js +24 -9
- package/dist/commands/workflow/templates.js +5 -4
- package/dist/commands/workspace/context-status.d.ts +4 -0
- package/dist/commands/workspace/context-status.js +59 -0
- package/dist/commands/workspace/open-target-selection.d.ts +13 -0
- package/dist/commands/workspace/open-target-selection.js +146 -0
- package/dist/commands/workspace/open-view.d.ts +62 -0
- package/dist/commands/workspace/open-view.js +249 -0
- package/dist/commands/workspace/open.d.ts +37 -0
- package/dist/commands/workspace/open.js +110 -0
- package/dist/commands/workspace/opener-selection.d.ts +11 -0
- package/dist/commands/workspace/opener-selection.js +98 -0
- package/dist/commands/workspace/operations.d.ts +29 -0
- package/dist/commands/workspace/operations.js +543 -0
- package/dist/commands/workspace/prompt-theme.d.ts +29 -0
- package/dist/commands/workspace/prompt-theme.js +24 -0
- package/dist/commands/workspace/registration.d.ts +13 -0
- package/dist/commands/workspace/registration.js +84 -0
- package/dist/commands/workspace/selection.d.ts +9 -0
- package/dist/commands/workspace/selection.js +115 -0
- package/dist/commands/workspace/setup-prompts.d.ts +13 -0
- package/dist/commands/workspace/setup-prompts.js +121 -0
- package/dist/commands/workspace/types.d.ts +103 -0
- package/dist/commands/workspace/types.js +36 -0
- package/dist/commands/workspace.d.ts +6 -0
- package/dist/commands/workspace.js +587 -0
- package/dist/core/artifact-graph/index.d.ts +3 -1
- package/dist/core/artifact-graph/index.js +1 -0
- package/dist/core/artifact-graph/instruction-loader.d.ts +41 -1
- package/dist/core/artifact-graph/instruction-loader.js +51 -9
- package/dist/core/artifact-graph/outputs.d.ts +14 -0
- package/dist/core/artifact-graph/outputs.js +39 -0
- package/dist/core/artifact-graph/state.js +2 -25
- package/dist/core/artifact-graph/types.d.ts +0 -5
- package/dist/core/artifact-graph/types.js +0 -14
- package/dist/core/change-metadata/index.d.ts +2 -0
- package/dist/core/change-metadata/index.js +2 -0
- package/dist/core/change-metadata/schema.d.ts +18 -0
- package/dist/core/change-metadata/schema.js +28 -0
- package/dist/core/change-status-policy.d.ts +50 -0
- package/dist/core/change-status-policy.js +70 -0
- package/dist/core/collections/index.d.ts +3 -0
- package/dist/core/collections/index.js +3 -0
- package/dist/core/collections/initiatives/collection.d.ts +4 -0
- package/dist/core/collections/initiatives/collection.js +17 -0
- package/dist/core/collections/initiatives/index.d.ts +6 -0
- package/dist/core/collections/initiatives/index.js +6 -0
- package/dist/core/collections/initiatives/operations.d.ts +49 -0
- package/dist/core/collections/initiatives/operations.js +175 -0
- package/dist/core/collections/initiatives/resolution.d.ts +87 -0
- package/dist/core/collections/initiatives/resolution.js +374 -0
- package/dist/core/collections/initiatives/schema.d.ts +41 -0
- package/dist/core/collections/initiatives/schema.js +134 -0
- package/dist/core/collections/initiatives/templates.d.ts +12 -0
- package/dist/core/collections/initiatives/templates.js +90 -0
- package/dist/core/collections/runtime.d.ts +46 -0
- package/dist/core/collections/runtime.js +194 -0
- package/dist/core/completions/command-registry.d.ts +1 -5
- package/dist/core/completions/command-registry.js +532 -32
- package/dist/core/completions/completion-provider.d.ts +11 -0
- package/dist/core/completions/completion-provider.js +27 -0
- package/dist/core/completions/generators/bash-generator.d.ts +3 -0
- package/dist/core/completions/generators/bash-generator.js +60 -4
- package/dist/core/completions/generators/fish-generator.js +3 -0
- package/dist/core/completions/generators/powershell-generator.d.ts +3 -0
- package/dist/core/completions/generators/powershell-generator.js +63 -4
- package/dist/core/completions/generators/zsh-generator.d.ts +3 -0
- package/dist/core/completions/generators/zsh-generator.js +46 -22
- package/dist/core/completions/installers/zsh-installer.d.ts +0 -8
- package/dist/core/completions/installers/zsh-installer.js +3 -31
- package/dist/core/completions/shared-flags.d.ts +12 -0
- package/dist/core/completions/shared-flags.js +28 -0
- package/dist/core/completions/templates/bash-templates.d.ts +1 -1
- package/dist/core/completions/templates/bash-templates.js +6 -0
- package/dist/core/completions/templates/fish-templates.d.ts +1 -1
- package/dist/core/completions/templates/fish-templates.js +6 -0
- package/dist/core/completions/templates/powershell-templates.d.ts +1 -1
- package/dist/core/completions/templates/powershell-templates.js +9 -0
- package/dist/core/completions/templates/zsh-templates.d.ts +1 -1
- package/dist/core/completions/templates/zsh-templates.js +9 -0
- package/dist/core/completions/types.d.ts +23 -1
- package/dist/core/config.js +3 -1
- package/dist/core/context-store/binding.d.ts +53 -0
- package/dist/core/context-store/binding.js +197 -0
- package/dist/core/context-store/errors.d.ts +20 -0
- package/dist/core/context-store/errors.js +22 -0
- package/dist/core/context-store/foundation.d.ts +55 -0
- package/dist/core/context-store/foundation.js +321 -0
- package/dist/core/context-store/index.d.ts +6 -0
- package/dist/core/context-store/index.js +6 -0
- package/dist/core/context-store/operations.d.ts +85 -0
- package/dist/core/context-store/operations.js +528 -0
- package/dist/core/context-store/registry.d.ts +45 -0
- package/dist/core/context-store/registry.js +229 -0
- package/dist/core/global-config.d.ts +6 -1
- package/dist/core/global-config.js +15 -16
- package/dist/core/index.d.ts +5 -1
- package/dist/core/index.js +4 -0
- package/dist/core/parsers/change-parser.js +7 -3
- package/dist/core/parsers/markdown-parser.d.ts +4 -0
- package/dist/core/parsers/markdown-parser.js +41 -1
- package/dist/core/parsers/requirement-blocks.js +5 -5
- package/dist/core/parsers/spec-structure.d.ts +9 -0
- package/dist/core/parsers/spec-structure.js +88 -0
- package/dist/core/planning-home.d.ts +21 -0
- package/dist/core/planning-home.js +108 -0
- package/dist/core/profiles.d.ts +1 -1
- package/dist/core/profiles.js +1 -1
- package/dist/core/specs-apply.js +9 -1
- package/dist/core/templates/workflows/apply-change.js +10 -4
- package/dist/core/templates/workflows/archive-change.js +21 -15
- package/dist/core/templates/workflows/bulk-archive-change.js +14 -10
- package/dist/core/templates/workflows/continue-change.js +6 -4
- package/dist/core/templates/workflows/explore.js +8 -10
- package/dist/core/templates/workflows/ff-change.js +8 -6
- package/dist/core/templates/workflows/new-change.js +6 -6
- package/dist/core/templates/workflows/onboard.js +13 -15
- package/dist/core/templates/workflows/propose.js +8 -6
- package/dist/core/templates/workflows/sync-specs.js +28 -10
- package/dist/core/templates/workflows/verify-change.js +16 -10
- package/dist/core/update.d.ts +5 -0
- package/dist/core/update.js +20 -0
- package/dist/core/validation/validator.d.ts +11 -0
- package/dist/core/validation/validator.js +28 -2
- package/dist/core/workspace/foundation.d.ts +67 -0
- package/dist/core/workspace/foundation.js +295 -0
- package/dist/core/workspace/index.d.ts +8 -0
- package/dist/core/workspace/index.js +8 -0
- package/dist/core/workspace/legacy-state.d.ts +28 -0
- package/dist/core/workspace/legacy-state.js +200 -0
- package/dist/core/workspace/link-input.d.ts +9 -0
- package/dist/core/workspace/link-input.js +32 -0
- package/dist/core/workspace/open-surface.d.ts +45 -0
- package/dist/core/workspace/open-surface.js +215 -0
- package/dist/core/workspace/openers.d.ts +21 -0
- package/dist/core/workspace/openers.js +124 -0
- package/dist/core/workspace/registry.d.ts +24 -0
- package/dist/core/workspace/registry.js +146 -0
- package/dist/core/workspace/skills.d.ts +57 -0
- package/dist/core/workspace/skills.js +334 -0
- package/dist/core/workspace/state-io.d.ts +10 -0
- package/dist/core/workspace/state-io.js +119 -0
- package/dist/telemetry/config.d.ts +7 -1
- package/dist/telemetry/config.js +87 -19
- package/dist/telemetry/index.js +19 -0
- package/dist/utils/change-metadata.d.ts +5 -2
- package/dist/utils/change-metadata.js +7 -13
- package/dist/utils/change-utils.d.ts +9 -0
- package/dist/utils/change-utils.js +7 -5
- package/dist/utils/file-system.d.ts +5 -0
- package/dist/utils/file-system.js +21 -1
- package/package.json +2 -1
- package/schemas/workspace-planning/schema.yaml +72 -0
- package/schemas/workspace-planning/templates/design.md +33 -0
- package/schemas/workspace-planning/templates/proposal.md +28 -0
- package/schemas/workspace-planning/templates/spec.md +9 -0
- package/schemas/workspace-planning/templates/tasks.md +15 -0
|
@@ -167,7 +167,7 @@ Now let's create a change to hold our work.
|
|
|
167
167
|
\`\`\`
|
|
168
168
|
## Creating a Change
|
|
169
169
|
|
|
170
|
-
A "change" in OpenSpec is a container for all the thinking and planning around a piece of work. It lives
|
|
170
|
+
A "change" in OpenSpec is a container for all the thinking and planning around a piece of work. It lives at the \`changeRoot\` reported by \`openspec status --change "<name>" --json\` and holds your artifacts—proposal, specs, design, tasks.
|
|
171
171
|
|
|
172
172
|
Let me create one for our task.
|
|
173
173
|
\`\`\`
|
|
@@ -179,11 +179,11 @@ openspec new change "<derived-name>"
|
|
|
179
179
|
|
|
180
180
|
**SHOW:**
|
|
181
181
|
\`\`\`
|
|
182
|
-
Created:
|
|
182
|
+
Created: <changeRoot from status JSON>
|
|
183
183
|
|
|
184
184
|
The folder structure:
|
|
185
185
|
\`\`\`
|
|
186
|
-
|
|
186
|
+
<changeRoot>/
|
|
187
187
|
├── proposal.md ← Why we're doing this (empty, we'll fill it)
|
|
188
188
|
├── design.md ← How we'll build it (empty)
|
|
189
189
|
├── specs/ ← Detailed requirements (empty)
|
|
@@ -245,7 +245,7 @@ After approval, save the proposal:
|
|
|
245
245
|
\`\`\`bash
|
|
246
246
|
openspec instructions proposal --change "<name>" --json
|
|
247
247
|
\`\`\`
|
|
248
|
-
Then write the content to \`openspec
|
|
248
|
+
Then write the content to the \`resolvedOutputPath\` from \`openspec instructions proposal --change "<name>" --json\`.
|
|
249
249
|
|
|
250
250
|
\`\`\`
|
|
251
251
|
Proposal saved. This is your "why" document—you can always come back and refine it as understanding evolves.
|
|
@@ -266,12 +266,10 @@ Specs define **what** we're building in precise, testable terms. They use a requ
|
|
|
266
266
|
For a small task like this, we might only need one spec file.
|
|
267
267
|
\`\`\`
|
|
268
268
|
|
|
269
|
-
**DO:**
|
|
269
|
+
**DO:** Resolve where the spec file should be created:
|
|
270
270
|
\`\`\`bash
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
# Windows (PowerShell)
|
|
274
|
-
# New-Item -ItemType Directory -Force -Path "openspec/changes/<name>/specs/<capability-name>"
|
|
271
|
+
openspec instructions specs --change "<name>" --json
|
|
272
|
+
# Use resolvedOutputPath from the JSON. If it is a glob, choose the concrete file path using the schema instruction and workspace planning context.
|
|
275
273
|
\`\`\`
|
|
276
274
|
|
|
277
275
|
Draft the spec content:
|
|
@@ -298,7 +296,7 @@ Here's the spec:
|
|
|
298
296
|
This format—WHEN/THEN/AND—makes requirements testable. You can literally read them as test cases.
|
|
299
297
|
\`\`\`
|
|
300
298
|
|
|
301
|
-
Save to \`
|
|
299
|
+
Save to the concrete file path chosen from \`resolvedOutputPath\`.
|
|
302
300
|
|
|
303
301
|
---
|
|
304
302
|
|
|
@@ -343,7 +341,7 @@ Here's the design:
|
|
|
343
341
|
For a small task, this captures the key decisions without over-engineering.
|
|
344
342
|
\`\`\`
|
|
345
343
|
|
|
346
|
-
Save to \`openspec
|
|
344
|
+
Save to the \`resolvedOutputPath\` from \`openspec instructions design --change "<name>" --json\`.
|
|
347
345
|
|
|
348
346
|
---
|
|
349
347
|
|
|
@@ -381,7 +379,7 @@ Each checkbox becomes a unit of work in the apply phase. Ready to implement?
|
|
|
381
379
|
|
|
382
380
|
**PAUSE** - Wait for user to confirm they're ready to implement.
|
|
383
381
|
|
|
384
|
-
Save to \`openspec
|
|
382
|
+
Save to the \`resolvedOutputPath\` from \`openspec instructions tasks --change "<name>" --json\`.
|
|
385
383
|
|
|
386
384
|
---
|
|
387
385
|
|
|
@@ -425,7 +423,7 @@ The change is implemented! One more step—let's archive it.
|
|
|
425
423
|
\`\`\`
|
|
426
424
|
## Archiving
|
|
427
425
|
|
|
428
|
-
When a change is complete, we archive it.
|
|
426
|
+
When a change is complete, we archive it. The archive path is derived from \`planningHome.changesDir\` and the date.
|
|
429
427
|
|
|
430
428
|
Archived changes become your project's decision history—you can always find them later to understand why something was built a certain way.
|
|
431
429
|
\`\`\`
|
|
@@ -437,7 +435,7 @@ openspec archive "<name>"
|
|
|
437
435
|
|
|
438
436
|
**SHOW:**
|
|
439
437
|
\`\`\`
|
|
440
|
-
Archived to:
|
|
438
|
+
Archived to: \`<planningHome.changesDir>/archive/YYYY-MM-DD-<name>/\`
|
|
441
439
|
|
|
442
440
|
The change is now part of your project's history. The code is in your codebase, the decision record is preserved.
|
|
443
441
|
\`\`\`
|
|
@@ -500,7 +498,7 @@ Try \`/opsx:propose\` on something you actually want to build. You've got the rh
|
|
|
500
498
|
If the user says they need to stop, want to pause, or seem disengaged:
|
|
501
499
|
|
|
502
500
|
\`\`\`
|
|
503
|
-
No problem! Your change is saved at \`openspec
|
|
501
|
+
No problem! Your change is saved at the \`changeRoot\` reported by \`openspec status --change "<name>" --json\`.
|
|
504
502
|
|
|
505
503
|
To pick up where we left off later:
|
|
506
504
|
- \`/opsx:continue <name>\` - Resume artifact creation
|
|
@@ -30,7 +30,7 @@ When ready to implement, run /opsx:apply
|
|
|
30
30
|
\`\`\`bash
|
|
31
31
|
openspec new change "<name>"
|
|
32
32
|
\`\`\`
|
|
33
|
-
This creates a scaffolded change
|
|
33
|
+
This creates a scaffolded change in the planning home resolved by the CLI with \`.openspec.yaml\`.
|
|
34
34
|
|
|
35
35
|
3. **Get the artifact build order**
|
|
36
36
|
\`\`\`bash
|
|
@@ -39,6 +39,7 @@ When ready to implement, run /opsx:apply
|
|
|
39
39
|
Parse the JSON to get:
|
|
40
40
|
- \`applyRequires\`: array of artifact IDs needed before implementation (e.g., \`["tasks"]\`)
|
|
41
41
|
- \`artifacts\`: list of all artifacts with their status and dependencies
|
|
42
|
+
- \`planningHome\`, \`changeRoot\`, \`artifactPaths\`, and \`actionContext\`: path and scope context. Use these instead of assuming repo-local paths.
|
|
42
43
|
|
|
43
44
|
4. **Create artifacts in sequence until apply-ready**
|
|
44
45
|
|
|
@@ -56,10 +57,10 @@ When ready to implement, run /opsx:apply
|
|
|
56
57
|
- \`rules\`: Artifact-specific rules (constraints for you - do NOT include in output)
|
|
57
58
|
- \`template\`: The structure to use for your output file
|
|
58
59
|
- \`instruction\`: Schema-specific guidance for this artifact type
|
|
59
|
-
- \`
|
|
60
|
+
- \`resolvedOutputPath\`: Resolved path or pattern to write the artifact
|
|
60
61
|
- \`dependencies\`: Completed artifacts to read for context
|
|
61
62
|
- Read any completed dependency files for context
|
|
62
|
-
- Create the artifact file using \`template\` as the structure
|
|
63
|
+
- Create the artifact file using \`template\` as the structure and write it to \`resolvedOutputPath\`
|
|
63
64
|
- Apply \`context\` and \`rules\` as constraints - but do NOT copy them into the file
|
|
64
65
|
- Show brief progress: "Created <artifact-id>"
|
|
65
66
|
|
|
@@ -140,7 +141,7 @@ When ready to implement, run /opsx:apply
|
|
|
140
141
|
\`\`\`bash
|
|
141
142
|
openspec new change "<name>"
|
|
142
143
|
\`\`\`
|
|
143
|
-
This creates a scaffolded change
|
|
144
|
+
This creates a scaffolded change in the planning home resolved by the CLI with \`.openspec.yaml\`.
|
|
144
145
|
|
|
145
146
|
3. **Get the artifact build order**
|
|
146
147
|
\`\`\`bash
|
|
@@ -149,6 +150,7 @@ When ready to implement, run /opsx:apply
|
|
|
149
150
|
Parse the JSON to get:
|
|
150
151
|
- \`applyRequires\`: array of artifact IDs needed before implementation (e.g., \`["tasks"]\`)
|
|
151
152
|
- \`artifacts\`: list of all artifacts with their status and dependencies
|
|
153
|
+
- \`planningHome\`, \`changeRoot\`, \`artifactPaths\`, and \`actionContext\`: path and scope context. Use these instead of assuming repo-local paths.
|
|
152
154
|
|
|
153
155
|
4. **Create artifacts in sequence until apply-ready**
|
|
154
156
|
|
|
@@ -166,10 +168,10 @@ When ready to implement, run /opsx:apply
|
|
|
166
168
|
- \`rules\`: Artifact-specific rules (constraints for you - do NOT include in output)
|
|
167
169
|
- \`template\`: The structure to use for your output file
|
|
168
170
|
- \`instruction\`: Schema-specific guidance for this artifact type
|
|
169
|
-
- \`
|
|
171
|
+
- \`resolvedOutputPath\`: Resolved path or pattern to write the artifact
|
|
170
172
|
- \`dependencies\`: Completed artifacts to read for context
|
|
171
173
|
- Read any completed dependency files for context
|
|
172
|
-
- Create the artifact file using \`template\` as the structure
|
|
174
|
+
- Create the artifact file using \`template\` as the structure and write it to \`resolvedOutputPath\`
|
|
173
175
|
- Apply \`context\` and \`rules\` as constraints - but do NOT copy them into the file
|
|
174
176
|
- Show brief progress: "Created <artifact-id>"
|
|
175
177
|
|
|
@@ -18,9 +18,18 @@ This is an **agent-driven** operation - you will read delta specs and directly e
|
|
|
18
18
|
|
|
19
19
|
**IMPORTANT**: Do NOT guess or auto-select a change. Always let the user choose.
|
|
20
20
|
|
|
21
|
-
2. **
|
|
21
|
+
2. **Resolve change context**
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
Run:
|
|
24
|
+
\`\`\`bash
|
|
25
|
+
openspec status --change "<name>" --json
|
|
26
|
+
\`\`\`
|
|
27
|
+
|
|
28
|
+
If status reports \`actionContext.mode: "workspace-planning"\`, explain that workspace spec sync is not supported in this slice and STOP. Do not fall back to repo-local paths or edit linked repos.
|
|
29
|
+
|
|
30
|
+
3. **Find delta specs**
|
|
31
|
+
|
|
32
|
+
Use \`artifactPaths.specs.existingOutputPaths\` from the status JSON as the list of delta spec files.
|
|
24
33
|
|
|
25
34
|
Each delta spec file contains sections like:
|
|
26
35
|
- \`## ADDED Requirements\` - New requirements to add
|
|
@@ -30,9 +39,9 @@ This is an **agent-driven** operation - you will read delta specs and directly e
|
|
|
30
39
|
|
|
31
40
|
If no delta specs found, inform user and stop.
|
|
32
41
|
|
|
33
|
-
|
|
42
|
+
4. **For each delta spec, apply changes to main specs**
|
|
34
43
|
|
|
35
|
-
For each capability
|
|
44
|
+
For each repo-local capability delta spec path returned by the CLI:
|
|
36
45
|
|
|
37
46
|
a. **Read the delta spec** to understand the intended changes
|
|
38
47
|
|
|
@@ -63,7 +72,7 @@ This is an **agent-driven** operation - you will read delta specs and directly e
|
|
|
63
72
|
- Add Purpose section (can be brief, mark as TBD)
|
|
64
73
|
- Add Requirements section with the ADDED requirements
|
|
65
74
|
|
|
66
|
-
|
|
75
|
+
5. **Show summary**
|
|
67
76
|
|
|
68
77
|
After applying all changes, summarize:
|
|
69
78
|
- Which capabilities were updated
|
|
@@ -156,9 +165,18 @@ This is an **agent-driven** operation - you will read delta specs and directly e
|
|
|
156
165
|
|
|
157
166
|
**IMPORTANT**: Do NOT guess or auto-select a change. Always let the user choose.
|
|
158
167
|
|
|
159
|
-
2. **
|
|
168
|
+
2. **Resolve change context**
|
|
169
|
+
|
|
170
|
+
Run:
|
|
171
|
+
\`\`\`bash
|
|
172
|
+
openspec status --change "<name>" --json
|
|
173
|
+
\`\`\`
|
|
174
|
+
|
|
175
|
+
If status reports \`actionContext.mode: "workspace-planning"\`, explain that workspace spec sync is not supported in this slice and STOP. Do not fall back to repo-local paths or edit linked repos.
|
|
176
|
+
|
|
177
|
+
3. **Find delta specs**
|
|
160
178
|
|
|
161
|
-
|
|
179
|
+
Use \`artifactPaths.specs.existingOutputPaths\` from the status JSON as the list of delta spec files.
|
|
162
180
|
|
|
163
181
|
Each delta spec file contains sections like:
|
|
164
182
|
- \`## ADDED Requirements\` - New requirements to add
|
|
@@ -168,9 +186,9 @@ This is an **agent-driven** operation - you will read delta specs and directly e
|
|
|
168
186
|
|
|
169
187
|
If no delta specs found, inform user and stop.
|
|
170
188
|
|
|
171
|
-
|
|
189
|
+
4. **For each delta spec, apply changes to main specs**
|
|
172
190
|
|
|
173
|
-
For each capability
|
|
191
|
+
For each repo-local capability delta spec path returned by the CLI:
|
|
174
192
|
|
|
175
193
|
a. **Read the delta spec** to understand the intended changes
|
|
176
194
|
|
|
@@ -201,7 +219,7 @@ This is an **agent-driven** operation - you will read delta specs and directly e
|
|
|
201
219
|
- Add Purpose section (can be brief, mark as TBD)
|
|
202
220
|
- Add Requirements section with the ADDED requirements
|
|
203
221
|
|
|
204
|
-
|
|
222
|
+
5. **Show summary**
|
|
205
223
|
|
|
206
224
|
After applying all changes, summarize:
|
|
207
225
|
- Which capabilities were updated
|
|
@@ -24,15 +24,18 @@ export function getVerifyChangeSkillTemplate() {
|
|
|
24
24
|
\`\`\`
|
|
25
25
|
Parse the JSON to understand:
|
|
26
26
|
- \`schemaName\`: The workflow being used (e.g., "spec-driven")
|
|
27
|
+
- \`planningHome\`, \`changeRoot\`, \`artifactPaths\`, and \`actionContext\`: path and scope context
|
|
27
28
|
- Which artifacts exist for this change
|
|
28
29
|
|
|
29
|
-
|
|
30
|
+
If status reports \`actionContext.mode: "workspace-planning"\`, explain that full workspace implementation verification is not supported in this slice and STOP. Do not infer repo-local implementation ownership or edit linked repos.
|
|
31
|
+
|
|
32
|
+
3. **Get planning context and load artifacts**
|
|
30
33
|
|
|
31
34
|
\`\`\`bash
|
|
32
35
|
openspec instructions apply --change "<name>" --json
|
|
33
36
|
\`\`\`
|
|
34
37
|
|
|
35
|
-
This returns the change directory and
|
|
38
|
+
This returns the change directory and \`contextFiles\` (artifact ID -> array of concrete file paths). Read all available artifacts from \`contextFiles\`.
|
|
36
39
|
|
|
37
40
|
4. **Initialize verification report structure**
|
|
38
41
|
|
|
@@ -46,7 +49,7 @@ export function getVerifyChangeSkillTemplate() {
|
|
|
46
49
|
5. **Verify Completeness**
|
|
47
50
|
|
|
48
51
|
**Task Completion**:
|
|
49
|
-
- If tasks
|
|
52
|
+
- If \`contextFiles.tasks\` exists, read every file path in it
|
|
50
53
|
- Parse checkboxes: \`- [ ]\` (incomplete) vs \`- [x]\` (complete)
|
|
51
54
|
- Count complete vs total tasks
|
|
52
55
|
- If incomplete tasks exist:
|
|
@@ -54,7 +57,7 @@ export function getVerifyChangeSkillTemplate() {
|
|
|
54
57
|
- Recommendation: "Complete task: <description>" or "Mark as done if already implemented"
|
|
55
58
|
|
|
56
59
|
**Spec Coverage**:
|
|
57
|
-
- If delta specs exist in \`
|
|
60
|
+
- If delta specs exist in \`contextFiles.specs\`:
|
|
58
61
|
- Extract all requirements (marked with "### Requirement:")
|
|
59
62
|
- For each requirement:
|
|
60
63
|
- Search codebase for keywords related to the requirement
|
|
@@ -85,7 +88,7 @@ export function getVerifyChangeSkillTemplate() {
|
|
|
85
88
|
7. **Verify Coherence**
|
|
86
89
|
|
|
87
90
|
**Design Adherence**:
|
|
88
|
-
- If design
|
|
91
|
+
- If \`contextFiles.design\` exists:
|
|
89
92
|
- Extract key decisions (look for sections like "Decision:", "Approach:", "Architecture:")
|
|
90
93
|
- Verify implementation follows those decisions
|
|
91
94
|
- If contradiction detected:
|
|
@@ -192,15 +195,18 @@ export function getOpsxVerifyCommandTemplate() {
|
|
|
192
195
|
\`\`\`
|
|
193
196
|
Parse the JSON to understand:
|
|
194
197
|
- \`schemaName\`: The workflow being used (e.g., "spec-driven")
|
|
198
|
+
- \`planningHome\`, \`changeRoot\`, \`artifactPaths\`, and \`actionContext\`: path and scope context
|
|
195
199
|
- Which artifacts exist for this change
|
|
196
200
|
|
|
197
|
-
|
|
201
|
+
If status reports \`actionContext.mode: "workspace-planning"\`, explain that full workspace implementation verification is not supported in this slice and STOP. Do not infer repo-local implementation ownership or edit linked repos.
|
|
202
|
+
|
|
203
|
+
3. **Get planning context and load artifacts**
|
|
198
204
|
|
|
199
205
|
\`\`\`bash
|
|
200
206
|
openspec instructions apply --change "<name>" --json
|
|
201
207
|
\`\`\`
|
|
202
208
|
|
|
203
|
-
This returns the change directory and
|
|
209
|
+
This returns the change directory and \`contextFiles\` (artifact ID -> array of concrete file paths). Read all available artifacts from \`contextFiles\`.
|
|
204
210
|
|
|
205
211
|
4. **Initialize verification report structure**
|
|
206
212
|
|
|
@@ -214,7 +220,7 @@ export function getOpsxVerifyCommandTemplate() {
|
|
|
214
220
|
5. **Verify Completeness**
|
|
215
221
|
|
|
216
222
|
**Task Completion**:
|
|
217
|
-
- If tasks
|
|
223
|
+
- If \`contextFiles.tasks\` exists, read every file path in it
|
|
218
224
|
- Parse checkboxes: \`- [ ]\` (incomplete) vs \`- [x]\` (complete)
|
|
219
225
|
- Count complete vs total tasks
|
|
220
226
|
- If incomplete tasks exist:
|
|
@@ -222,7 +228,7 @@ export function getOpsxVerifyCommandTemplate() {
|
|
|
222
228
|
- Recommendation: "Complete task: <description>" or "Mark as done if already implemented"
|
|
223
229
|
|
|
224
230
|
**Spec Coverage**:
|
|
225
|
-
- If delta specs exist in \`
|
|
231
|
+
- If delta specs exist in \`contextFiles.specs\`:
|
|
226
232
|
- Extract all requirements (marked with "### Requirement:")
|
|
227
233
|
- For each requirement:
|
|
228
234
|
- Search codebase for keywords related to the requirement
|
|
@@ -253,7 +259,7 @@ export function getOpsxVerifyCommandTemplate() {
|
|
|
253
259
|
7. **Verify Coherence**
|
|
254
260
|
|
|
255
261
|
**Design Adherence**:
|
|
256
|
-
- If design
|
|
262
|
+
- If \`contextFiles.design\` exists:
|
|
257
263
|
- Extract key decisions (look for sections like "Decision:", "Approach:", "Architecture:")
|
|
258
264
|
- Verify implementation follows those decisions
|
|
259
265
|
- If contradiction detected:
|
package/dist/core/update.d.ts
CHANGED
|
@@ -38,6 +38,11 @@ export declare class UpdateCommand {
|
|
|
38
38
|
* Displays a note about extra workflows installed that aren't in the current profile.
|
|
39
39
|
*/
|
|
40
40
|
private displayExtraWorkflowsNote;
|
|
41
|
+
/**
|
|
42
|
+
* Suggest opting back into core when a custom profile still matches the old
|
|
43
|
+
* pre-sync core set. Keep custom profiles user-owned; do not mutate them.
|
|
44
|
+
*/
|
|
45
|
+
private displayOldCoreCustomProfileNote;
|
|
41
46
|
/**
|
|
42
47
|
* Removes skill directories for workflows when delivery changed to commands-only.
|
|
43
48
|
* Returns the number of directories removed.
|
package/dist/core/update.js
CHANGED
|
@@ -23,6 +23,7 @@ import { WORKFLOW_TO_SKILL_DIR, getCommandConfiguredTools, getConfiguredToolsFor
|
|
|
23
23
|
import { scanInstalledWorkflows as scanInstalledWorkflowsShared, migrateIfNeeded as migrateIfNeededShared, } from './migration.js';
|
|
24
24
|
const require = createRequire(import.meta.url);
|
|
25
25
|
const { version: OPENSPEC_VERSION } = require('../../package.json');
|
|
26
|
+
const OLD_CORE_WORKFLOWS = ['propose', 'explore', 'apply', 'archive'];
|
|
26
27
|
/**
|
|
27
28
|
* Scans installed workflow artifacts (skills and managed commands) across all configured tools.
|
|
28
29
|
* Returns the union of detected workflow IDs that match ALL_WORKFLOWS.
|
|
@@ -95,6 +96,7 @@ export class UpdateCommand {
|
|
|
95
96
|
// Still check for new tool directories and extra workflows
|
|
96
97
|
this.detectNewTools(resolvedProjectPath, configuredTools);
|
|
97
98
|
this.displayExtraWorkflowsNote(resolvedProjectPath, configuredTools, desiredWorkflows);
|
|
99
|
+
this.displayOldCoreCustomProfileNote(profile, globalConfig.workflows);
|
|
98
100
|
return;
|
|
99
101
|
}
|
|
100
102
|
// 8. Display update plan
|
|
@@ -201,6 +203,7 @@ export class UpdateCommand {
|
|
|
201
203
|
this.detectNewTools(resolvedProjectPath, configuredAndNewTools);
|
|
202
204
|
// 14. Display note about extra workflows not in profile
|
|
203
205
|
this.displayExtraWorkflowsNote(resolvedProjectPath, configuredAndNewTools, desiredWorkflows);
|
|
206
|
+
this.displayOldCoreCustomProfileNote(profile, globalConfig.workflows);
|
|
204
207
|
// 15. List affected tools
|
|
205
208
|
if (updatedTools.length > 0) {
|
|
206
209
|
const toolDisplayNames = updatedTools;
|
|
@@ -264,6 +267,23 @@ export class UpdateCommand {
|
|
|
264
267
|
console.log(chalk.dim(`Note: ${extraWorkflows.length} extra workflows not in profile (use \`openspec config profile\` to manage)`));
|
|
265
268
|
}
|
|
266
269
|
}
|
|
270
|
+
/**
|
|
271
|
+
* Suggest opting back into core when a custom profile still matches the old
|
|
272
|
+
* pre-sync core set. Keep custom profiles user-owned; do not mutate them.
|
|
273
|
+
*/
|
|
274
|
+
displayOldCoreCustomProfileNote(profile, workflows) {
|
|
275
|
+
if (profile !== 'custom' || !workflows) {
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
const workflowSet = new Set(workflows);
|
|
279
|
+
const matchesOldCore = workflowSet.size === OLD_CORE_WORKFLOWS.length &&
|
|
280
|
+
OLD_CORE_WORKFLOWS.every((workflow) => workflowSet.has(workflow));
|
|
281
|
+
if (!matchesOldCore) {
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
console.log(chalk.dim('Note: The core profile now includes sync. Your custom profile is preserving the old core workflow set.'));
|
|
285
|
+
console.log(chalk.dim('Run `openspec config profile core` and then `openspec update` to add sync.'));
|
|
286
|
+
}
|
|
267
287
|
/**
|
|
268
288
|
* Removes skill directories for workflows when delivery changed to commands-only.
|
|
269
289
|
* Returns the number of directories removed.
|
|
@@ -27,6 +27,17 @@ export declare class Validator {
|
|
|
27
27
|
isValid(report: ValidationReport): boolean;
|
|
28
28
|
private extractRequirementText;
|
|
29
29
|
private containsShallOrMust;
|
|
30
|
+
/**
|
|
31
|
+
* Build an error message for a requirement block whose body lacks SHALL/MUST.
|
|
32
|
+
*
|
|
33
|
+
* When the SHALL/MUST keyword already appears in the requirement header (e.g.
|
|
34
|
+
* `### Requirement: The system SHALL ...`) the original generic error
|
|
35
|
+
* ("must contain SHALL or MUST") is confusing because the keyword is visibly
|
|
36
|
+
* present in the spec. Per the OpenSpec conventions the keyword has to live
|
|
37
|
+
* on the requirement body line (the line right after the header), so we point
|
|
38
|
+
* the author at that exact fix when the keyword is found in the header only.
|
|
39
|
+
*/
|
|
40
|
+
private buildMissingShallOrMustMessage;
|
|
30
41
|
private countScenarios;
|
|
31
42
|
private formatSectionList;
|
|
32
43
|
}
|
|
@@ -5,6 +5,7 @@ import { MarkdownParser } from '../parsers/markdown-parser.js';
|
|
|
5
5
|
import { ChangeParser } from '../parsers/change-parser.js';
|
|
6
6
|
import { MIN_PURPOSE_LENGTH, MAX_REQUIREMENT_TEXT_LENGTH, VALIDATION_MESSAGES } from './constants.js';
|
|
7
7
|
import { parseDeltaSpec, normalizeRequirementName } from '../parsers/requirement-blocks.js';
|
|
8
|
+
import { findMainSpecStructureIssues } from '../parsers/spec-structure.js';
|
|
8
9
|
import { FileSystemUtils } from '../../utils/file-system.js';
|
|
9
10
|
export class Validator {
|
|
10
11
|
strictMode;
|
|
@@ -149,7 +150,7 @@ export class Validator {
|
|
|
149
150
|
issues.push({ level: 'ERROR', path: entryPath, message: `ADDED "${block.name}" is missing requirement text` });
|
|
150
151
|
}
|
|
151
152
|
else if (!this.containsShallOrMust(requirementText)) {
|
|
152
|
-
issues.push({ level: 'ERROR', path: entryPath, message:
|
|
153
|
+
issues.push({ level: 'ERROR', path: entryPath, message: this.buildMissingShallOrMustMessage('ADDED', block.name) });
|
|
153
154
|
}
|
|
154
155
|
const scenarioCount = this.countScenarios(block.raw);
|
|
155
156
|
if (scenarioCount < 1) {
|
|
@@ -171,7 +172,7 @@ export class Validator {
|
|
|
171
172
|
issues.push({ level: 'ERROR', path: entryPath, message: `MODIFIED "${block.name}" is missing requirement text` });
|
|
172
173
|
}
|
|
173
174
|
else if (!this.containsShallOrMust(requirementText)) {
|
|
174
|
-
issues.push({ level: 'ERROR', path: entryPath, message:
|
|
175
|
+
issues.push({ level: 'ERROR', path: entryPath, message: this.buildMissingShallOrMustMessage('MODIFIED', block.name) });
|
|
175
176
|
}
|
|
176
177
|
const scenarioCount = this.countScenarios(block.raw);
|
|
177
178
|
if (scenarioCount < 1) {
|
|
@@ -270,6 +271,14 @@ export class Validator {
|
|
|
270
271
|
}
|
|
271
272
|
applySpecRules(spec, content) {
|
|
272
273
|
const issues = [];
|
|
274
|
+
for (const structuralIssue of findMainSpecStructureIssues(content)) {
|
|
275
|
+
issues.push({
|
|
276
|
+
level: 'ERROR',
|
|
277
|
+
path: 'file',
|
|
278
|
+
line: structuralIssue.line,
|
|
279
|
+
message: structuralIssue.message,
|
|
280
|
+
});
|
|
281
|
+
}
|
|
273
282
|
if (spec.overview.length < MIN_PURPOSE_LENGTH) {
|
|
274
283
|
issues.push({
|
|
275
284
|
level: 'WARNING',
|
|
@@ -392,6 +401,23 @@ export class Validator {
|
|
|
392
401
|
containsShallOrMust(text) {
|
|
393
402
|
return /\b(SHALL|MUST)\b/.test(text);
|
|
394
403
|
}
|
|
404
|
+
/**
|
|
405
|
+
* Build an error message for a requirement block whose body lacks SHALL/MUST.
|
|
406
|
+
*
|
|
407
|
+
* When the SHALL/MUST keyword already appears in the requirement header (e.g.
|
|
408
|
+
* `### Requirement: The system SHALL ...`) the original generic error
|
|
409
|
+
* ("must contain SHALL or MUST") is confusing because the keyword is visibly
|
|
410
|
+
* present in the spec. Per the OpenSpec conventions the keyword has to live
|
|
411
|
+
* on the requirement body line (the line right after the header), so we point
|
|
412
|
+
* the author at that exact fix when the keyword is found in the header only.
|
|
413
|
+
*/
|
|
414
|
+
buildMissingShallOrMustMessage(action, blockName) {
|
|
415
|
+
const base = `${action} "${blockName}" must contain SHALL or MUST`;
|
|
416
|
+
if (this.containsShallOrMust(blockName)) {
|
|
417
|
+
return `${base} in the requirement body, not only in the header. Move the SHALL/MUST statement to the line immediately after the "### Requirement: ..." header.`;
|
|
418
|
+
}
|
|
419
|
+
return base;
|
|
420
|
+
}
|
|
395
421
|
countScenarios(blockRaw) {
|
|
396
422
|
const matches = blockRaw.match(/^####\s+/gm);
|
|
397
423
|
return matches ? matches.length : 0;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { type ContextStoreBinding, type ContextStoreSelector } from '../context-store/index.js';
|
|
2
|
+
export declare const WORKSPACE_METADATA_DIR_NAME = ".openspec-workspace";
|
|
3
|
+
export declare const WORKSPACE_VIEW_STATE_FILE_NAME = "workspace.yaml";
|
|
4
|
+
export declare const WORKSPACE_CHANGES_DIR_NAME = "changes";
|
|
5
|
+
export declare const WORKSPACE_CODE_WORKSPACE_EXTENSION = ".code-workspace";
|
|
6
|
+
export declare const WORKSPACE_SUPPORTED_OPENER_VALUES: readonly ["codex-cli", "claude", "github-copilot", "editor"];
|
|
7
|
+
export declare const WORKSPACE_AGENT_OPENER_IDS: readonly ["codex-cli", "claude", "github-copilot"];
|
|
8
|
+
export declare const WORKSPACE_EDITOR_OPENER_IDS: readonly ["vscode"];
|
|
9
|
+
export type WorkspaceSupportedOpenerValue = typeof WORKSPACE_SUPPORTED_OPENER_VALUES[number];
|
|
10
|
+
export type WorkspaceAgentOpenerId = typeof WORKSPACE_AGENT_OPENER_IDS[number];
|
|
11
|
+
export type WorkspaceEditorOpenerId = typeof WORKSPACE_EDITOR_OPENER_IDS[number];
|
|
12
|
+
export type WorkspacePreferredOpener = {
|
|
13
|
+
kind: 'agent';
|
|
14
|
+
id: WorkspaceAgentOpenerId;
|
|
15
|
+
} | {
|
|
16
|
+
kind: 'editor';
|
|
17
|
+
id: WorkspaceEditorOpenerId;
|
|
18
|
+
};
|
|
19
|
+
export interface WorkspaceContextState {
|
|
20
|
+
kind: 'initiative';
|
|
21
|
+
store: ContextStoreBinding;
|
|
22
|
+
initiative: {
|
|
23
|
+
id: string;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export interface WorkspaceViewState {
|
|
27
|
+
version: 1;
|
|
28
|
+
name: string;
|
|
29
|
+
context: WorkspaceContextState | null;
|
|
30
|
+
links: Record<string, string | null>;
|
|
31
|
+
preferred_opener?: WorkspacePreferredOpener;
|
|
32
|
+
tools?: string[];
|
|
33
|
+
workspace_skills?: WorkspaceSkillState;
|
|
34
|
+
}
|
|
35
|
+
export interface WorkspaceSkillState {
|
|
36
|
+
selected_agents: string[];
|
|
37
|
+
last_applied_profile?: 'core' | 'custom';
|
|
38
|
+
last_applied_delivery?: 'both' | 'skills' | 'commands';
|
|
39
|
+
last_applied_workflow_ids?: string[];
|
|
40
|
+
last_applied_at?: string;
|
|
41
|
+
}
|
|
42
|
+
export declare function getWorkspaceMetadataDir(workspaceRoot: string): string;
|
|
43
|
+
export declare function getWorkspaceViewStatePath(workspaceRoot: string): string;
|
|
44
|
+
export declare function getWorkspaceChangesDir(workspaceRoot: string): string;
|
|
45
|
+
export declare function getWorkspaceCodeWorkspaceFileName(workspaceName: string): string;
|
|
46
|
+
export declare function getWorkspaceCodeWorkspacePath(workspaceRoot: string, workspaceName: string): string;
|
|
47
|
+
/**
|
|
48
|
+
* @deprecated Managed workspaces no longer create portable ignore rules.
|
|
49
|
+
* This compatibility shim remains for callers that still ask which ignore
|
|
50
|
+
* patterns OpenSpec owns for workspace-local generated files.
|
|
51
|
+
*/
|
|
52
|
+
export declare function getWorkspacePortableIgnorePatterns(_workspaceName?: string): string[];
|
|
53
|
+
export declare function validateWorkspaceName(name: string): string;
|
|
54
|
+
export declare function validateWorkspaceLinkName(name: string): string;
|
|
55
|
+
export declare function isValidWorkspaceName(name: string): boolean;
|
|
56
|
+
export declare function isValidWorkspaceLinkName(name: string): boolean;
|
|
57
|
+
export declare function isWorkspaceAgentOpenerId(value: string): value is WorkspaceAgentOpenerId;
|
|
58
|
+
export declare function isWorkspaceSupportedOpenerValue(value: string): value is WorkspaceSupportedOpenerValue;
|
|
59
|
+
export declare function parseWorkspacePreferredOpenerValue(value: string): WorkspacePreferredOpener;
|
|
60
|
+
export declare function validateWorkspacePreferredOpener(opener: WorkspacePreferredOpener): WorkspacePreferredOpener;
|
|
61
|
+
export declare function createWorkspaceInitiativeContext(store: ContextStoreBinding, initiativeId: string): WorkspaceContextState;
|
|
62
|
+
export declare function getWorkspaceContextStoreId(context: WorkspaceContextState): string;
|
|
63
|
+
export declare function getWorkspaceContextStoreSelector(context: WorkspaceContextState): ContextStoreSelector;
|
|
64
|
+
export declare function getWorkspaceContextInitiativeId(context: WorkspaceContextState): string;
|
|
65
|
+
export declare function parseWorkspaceViewState(content: string): WorkspaceViewState;
|
|
66
|
+
export declare function serializeWorkspaceViewState(state: WorkspaceViewState): string;
|
|
67
|
+
//# sourceMappingURL=foundation.d.ts.map
|