@fission-ai/openspec 1.13.1 → 1.14.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.
Files changed (85) hide show
  1. package/README.md +15 -3
  2. package/dist/cli/index.js +39 -1
  3. package/dist/commands/spec.js +1 -0
  4. package/dist/commands/workflow/instructions.js +66 -18
  5. package/dist/commands/workflow/shared.d.ts +7 -0
  6. package/dist/commands/workflow/status.js +15 -2
  7. package/dist/core/archive.js +258 -78
  8. package/dist/core/artifact-graph/instruction-loader.d.ts +7 -0
  9. package/dist/core/artifact-graph/instruction-loader.js +18 -1
  10. package/dist/core/artifact-graph/outputs.d.ts +1 -1
  11. package/dist/core/artifact-graph/outputs.js +38 -8
  12. package/dist/core/change-metadata/schema.d.ts +3 -0
  13. package/dist/core/change-metadata/schema.js +10 -0
  14. package/dist/core/change-status-policy.d.ts +8 -0
  15. package/dist/core/change-status-policy.js +33 -2
  16. package/dist/core/command-generation/adapters/atomcode.d.ts +24 -0
  17. package/dist/core/command-generation/adapters/atomcode.js +46 -0
  18. package/dist/core/command-generation/adapters/codestudio.d.ts +13 -0
  19. package/dist/core/command-generation/adapters/codestudio.js +27 -0
  20. package/dist/core/command-generation/adapters/continue.js +4 -0
  21. package/dist/core/command-generation/adapters/easycode.d.ts +17 -0
  22. package/dist/core/command-generation/adapters/easycode.js +28 -0
  23. package/dist/core/command-generation/adapters/gemini.js +1 -35
  24. package/dist/core/command-generation/adapters/gigacode.d.ts +17 -0
  25. package/dist/core/command-generation/adapters/gigacode.js +31 -0
  26. package/dist/core/command-generation/adapters/index.d.ts +4 -0
  27. package/dist/core/command-generation/adapters/index.js +4 -0
  28. package/dist/core/command-generation/adapters/kilocode.d.ts +1 -1
  29. package/dist/core/command-generation/adapters/kilocode.js +2 -2
  30. package/dist/core/command-generation/registry.js +8 -0
  31. package/dist/core/command-generation/toml.d.ts +19 -0
  32. package/dist/core/command-generation/toml.js +39 -0
  33. package/dist/core/command-surface.js +1 -1
  34. package/dist/core/completions/command-registry.js +19 -0
  35. package/dist/core/completions/installers/zsh-installer.js +4 -2
  36. package/dist/core/config-prompts.js +6 -6
  37. package/dist/core/config.js +11 -1
  38. package/dist/core/init.js +44 -14
  39. package/dist/core/legacy-cleanup.d.ts +1 -1
  40. package/dist/core/legacy-cleanup.js +40 -11
  41. package/dist/core/list.d.ts +2 -0
  42. package/dist/core/list.js +49 -23
  43. package/dist/core/parsers/markdown-parser.js +5 -0
  44. package/dist/core/parsers/requirement-blocks.d.ts +40 -3
  45. package/dist/core/parsers/requirement-blocks.js +74 -25
  46. package/dist/core/project-config.js +45 -1
  47. package/dist/core/references.js +3 -1
  48. package/dist/core/root-selection.d.ts +6 -0
  49. package/dist/core/root-selection.js +16 -0
  50. package/dist/core/schemas/base.schema.d.ts +3 -0
  51. package/dist/core/schemas/base.schema.js +6 -0
  52. package/dist/core/schemas/change.schema.d.ts +8 -0
  53. package/dist/core/schemas/spec.schema.d.ts +2 -0
  54. package/dist/core/specs-apply.d.ts +20 -0
  55. package/dist/core/specs-apply.js +19 -6
  56. package/dist/core/templates/workflows/apply-change.js +5 -2
  57. package/dist/core/templates/workflows/archive-change.js +56 -20
  58. package/dist/core/templates/workflows/bulk-archive-change.js +34 -16
  59. package/dist/core/templates/workflows/continue-change.js +0 -2
  60. package/dist/core/templates/workflows/explore.js +2 -2
  61. package/dist/core/templates/workflows/ff-change.js +2 -2
  62. package/dist/core/templates/workflows/onboard.js +9 -4
  63. package/dist/core/templates/workflows/update-change.js +21 -9
  64. package/dist/core/templates/workflows/verify-change.js +115 -52
  65. package/dist/core/update.js +20 -7
  66. package/dist/core/validation/constants.d.ts +1 -1
  67. package/dist/core/validation/constants.js +1 -1
  68. package/dist/core/validation/purpose-placeholder.js +24 -9
  69. package/dist/core/validation/validator.js +15 -6
  70. package/dist/core/version-check.d.ts +23 -1
  71. package/dist/core/version-check.js +112 -26
  72. package/dist/core/view.d.ts +2 -0
  73. package/dist/core/view.js +62 -4
  74. package/dist/utils/change-metadata.d.ts +20 -1
  75. package/dist/utils/change-metadata.js +57 -1
  76. package/dist/utils/command-references.d.ts +1 -1
  77. package/dist/utils/command-references.js +2 -2
  78. package/dist/utils/file-system.js +20 -3
  79. package/dist/utils/index.d.ts +1 -1
  80. package/dist/utils/index.js +1 -1
  81. package/dist/utils/line-endings.d.ts +34 -0
  82. package/dist/utils/line-endings.js +46 -0
  83. package/package.json +2 -2
  84. package/schemas/spec-driven/schema.yaml +10 -1
  85. package/schemas/spec-driven/templates/proposal.md +6 -3
@@ -1,6 +1,6 @@
1
1
  export { validateChangeName, createChange } from './change-utils.js';
2
2
  export type { ValidationResult, CreateChangeOptions } from './change-utils.js';
3
- export { readChangeMetadata, writeChangeMetadata, resolveSchemaForChange, validateSchemaName, ChangeMetadataError, } from './change-metadata.js';
3
+ export { readChangeMetadata, writeChangeMetadata, resolveSchemaForChange, validateSchemaName, ChangeMetadataError, listUnknownChangeMetadataKeys, readUnknownChangeMetadataKeys, formatUnknownChangeMetadataKeysMessage, CHANGE_METADATA_KNOWN_KEYS, } from './change-metadata.js';
4
4
  export { FileSystemUtils, removeMarkerBlock } from './file-system.js';
5
5
  export { transformCommandInvocations, transformToSkillReferences, getSkillReferenceTransformer, getTransformerForTool, } from './command-references.js';
6
6
  //# sourceMappingURL=index.d.ts.map
@@ -1,7 +1,7 @@
1
1
  // Shared utilities
2
2
  export { validateChangeName, createChange } from './change-utils.js';
3
3
  // Change metadata utilities
4
- export { readChangeMetadata, writeChangeMetadata, resolveSchemaForChange, validateSchemaName, ChangeMetadataError, } from './change-metadata.js';
4
+ export { readChangeMetadata, writeChangeMetadata, resolveSchemaForChange, validateSchemaName, ChangeMetadataError, listUnknownChangeMetadataKeys, readUnknownChangeMetadataKeys, formatUnknownChangeMetadataKeysMessage, CHANGE_METADATA_KNOWN_KEYS, } from './change-metadata.js';
5
5
  // File system utilities
6
6
  export { FileSystemUtils, removeMarkerBlock } from './file-system.js';
7
7
  // Command reference utilities
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Line-ending helpers.
3
+ *
4
+ * Every parser in this codebase normalizes CRLF to LF on the way in, so all
5
+ * serialization logic can assume '\n'. That leaves the write side responsible
6
+ * for restoring whatever convention the file already used: without it, editing
7
+ * one requirement in a CRLF spec rewrites every line of the file and buries the
8
+ * real change in the diff.
9
+ */
10
+ export type LineEnding = '\n' | '\r\n';
11
+ /**
12
+ * The dominant line ending in `content`, or undefined when it holds no line
13
+ * break to judge from.
14
+ *
15
+ * Mixed files resolve to whichever ending is more common, with CRLF winning a
16
+ * tie: a file that is mostly CRLF is a CRLF file that picked up a stray LF, and
17
+ * settling the whole file on one ending is what keeps later diffs small.
18
+ */
19
+ export declare function detectLineEnding(content: string): LineEnding | undefined;
20
+ /**
21
+ * Re-apply `ending` to LF-normalized `content`.
22
+ *
23
+ * Normalizes to LF first, so the result is uniform even if the caller passed
24
+ * content that already contained CRLF.
25
+ */
26
+ export declare function applyLineEnding(content: string, ending: LineEnding): string;
27
+ /**
28
+ * Rewrite `content` to match the convention of `original`.
29
+ *
30
+ * When `original` has no line break to learn from, `content` is left as LF —
31
+ * the portable default this project writes new files with.
32
+ */
33
+ export declare function matchLineEnding(content: string, original: string): string;
34
+ //# sourceMappingURL=line-endings.d.ts.map
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Line-ending helpers.
3
+ *
4
+ * Every parser in this codebase normalizes CRLF to LF on the way in, so all
5
+ * serialization logic can assume '\n'. That leaves the write side responsible
6
+ * for restoring whatever convention the file already used: without it, editing
7
+ * one requirement in a CRLF spec rewrites every line of the file and buries the
8
+ * real change in the diff.
9
+ */
10
+ /**
11
+ * The dominant line ending in `content`, or undefined when it holds no line
12
+ * break to judge from.
13
+ *
14
+ * Mixed files resolve to whichever ending is more common, with CRLF winning a
15
+ * tie: a file that is mostly CRLF is a CRLF file that picked up a stray LF, and
16
+ * settling the whole file on one ending is what keeps later diffs small.
17
+ */
18
+ export function detectLineEnding(content) {
19
+ const crlf = content.match(/\r\n/g)?.length ?? 0;
20
+ // Count LFs not preceded by CR, so CRLF is never also counted as LF.
21
+ const lf = content.match(/(?<!\r)\n/g)?.length ?? 0;
22
+ if (crlf === 0 && lf === 0)
23
+ return undefined;
24
+ return crlf >= lf ? '\r\n' : '\n';
25
+ }
26
+ /**
27
+ * Re-apply `ending` to LF-normalized `content`.
28
+ *
29
+ * Normalizes to LF first, so the result is uniform even if the caller passed
30
+ * content that already contained CRLF.
31
+ */
32
+ export function applyLineEnding(content, ending) {
33
+ const normalized = content.replace(/\r\n/g, '\n');
34
+ return ending === '\n' ? normalized : normalized.replace(/\n/g, '\r\n');
35
+ }
36
+ /**
37
+ * Rewrite `content` to match the convention of `original`.
38
+ *
39
+ * When `original` has no line break to learn from, `content` is left as LF —
40
+ * the portable default this project writes new files with.
41
+ */
42
+ export function matchLineEnding(content, original) {
43
+ const ending = detectLineEnding(original);
44
+ return ending === undefined ? content : applyLineEnding(content, ending);
45
+ }
46
+ //# sourceMappingURL=line-endings.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fission-ai/openspec",
3
- "version": "1.13.1",
3
+ "version": "1.14.0",
4
4
  "description": "AI-native system for spec-driven development",
5
5
  "keywords": [
6
6
  "openspec",
@@ -52,7 +52,7 @@
52
52
  "vitest": "^4.1.11"
53
53
  },
54
54
  "dependencies": {
55
- "@inquirer/core": "^11.2.1",
55
+ "@inquirer/core": "^12.0.0",
56
56
  "@inquirer/prompts": "^8.5.2",
57
57
  "chalk": "^5.6.2",
58
58
  "commander": "^14.0.0",
@@ -13,7 +13,7 @@ artifacts:
13
13
  - **Why**: 1-2 sentences on the problem or opportunity. What problem does this solve? Why now?
14
14
  - **What Changes**: Bullet list of changes. Be specific about new capabilities, modifications, or removals. Mark breaking changes with **BREAKING**.
15
15
  - **Capabilities**: Identify which specs will be created or modified:
16
- - **New Capabilities**: List capabilities being introduced. Each becomes a new `specs/<capability-path>/spec.md`. Use kebab-case for path segments you introduce (e.g., `user-auth` or `identity/user-auth`) and follow the project's existing spec organization.
16
+ - **New Capabilities**: List capabilities being introduced. Each becomes a new `specs/<capability-path>/spec.md`. Name each capability for a durable system behavior (for example, `user-auth`), not the work in this change (for example, `add-login-endpoint`). Choose a cohesive boundary that can own related requirements as the system evolves; avoid broad catch-all capabilities. Use kebab-case for path segments you introduce (e.g., `user-auth` or `identity/user-auth`) and follow the project's existing spec organization.
17
17
  - **Modified Capabilities**: List existing capabilities whose REQUIREMENTS are changing. Only include if spec-level behavior changes (not just implementation details). Each needs a delta spec file. Use the exact existing path under `openspec/specs/`. Leave empty if no requirement changes.
18
18
  - **Impact**: Affected code, APIs, dependencies, or systems.
19
19
 
@@ -94,6 +94,7 @@ artifacts:
94
94
  - Each scenario: `#### Scenario: <name>` with WHEN/THEN format
95
95
  - **CRITICAL**: Scenarios MUST use exactly 4 hashtags (`####`). Using 3 hashtags or bullets will fail silently.
96
96
  - Every requirement MUST have at least one scenario.
97
+ - Keep each requirement's description (the text between `### Requirement:` and its first scenario) to 500 characters or fewer. `openspec validate` flags longer descriptions once they reach the main spec. This is an informational hint, not an error. When writing a new requirement, state one behavior per requirement: move examples and edge cases into scenarios, and split a requirement that covers several behaviors into separate `### Requirement:` blocks, each with its own scenarios. Under MODIFIED, keep the existing requirement block whole; never split, trim or rewrite existing text just to meet the length.
97
98
 
98
99
  New capabilities only: the delta spec's first section is `## Purpose` -
99
100
  one or two sentences (50+ characters, or `openspec validate --strict`
@@ -210,6 +211,13 @@ artifacts:
210
211
  that task's checkbox description. Use a separate verification task only
211
212
  when it checks broader integration or system behavior that spans
212
213
  multiple implementation tasks.
214
+ - Each task group MUST land the tests and documentation its own work
215
+ calls for. Do NOT collect testing or documentation into a final group -
216
+ when a late group first exercises work from an early one, the failures
217
+ cascade back through every group in between and force rework. A group
218
+ whose work calls for neither, such as scaffolding or dependency setup,
219
+ carries neither. A final group is for integration checks only, not for
220
+ the tests and docs an earlier group owed.
213
221
 
214
222
  Example:
215
223
  ```
@@ -224,6 +232,7 @@ artifacts:
224
232
 
225
233
  - [ ] 2.1 Implement data export function and verify the export test passes
226
234
  - [ ] 2.2 Add CSV formatting utilities and verify unit tests cover quoting and delimiters
235
+ - [ ] 2.3 Document the export API in docs/export.md and verify the documented command runs as written
227
236
  ```
228
237
 
229
238
  Reference specs for what needs to be built, design for how to build it.
@@ -11,9 +11,12 @@
11
11
  ## Capabilities
12
12
 
13
13
  ### New Capabilities
14
- <!-- Capabilities being introduced. Use kebab-case for path segments you introduce
15
- (e.g., user-auth or identity/user-auth) that follow the project's existing
16
- spec organization. Each creates specs/<capability-path>/spec.md. -->
14
+ <!-- Capabilities being introduced. Name each capability for a cohesive system
15
+ behavior that can own related requirements as the system evolves. Do not name
16
+ implementation tasks or proposal sections. Avoid broad catch-all names. Use
17
+ kebab-case for path segments you introduce (e.g., user-auth or identity/user-auth)
18
+ that follow the project's existing spec organization. Each creates
19
+ specs/<capability-path>/spec.md. -->
17
20
  - `<capability-path>`: <brief description of what this capability covers>
18
21
 
19
22
  ### Modified Capabilities