-
Notifications
You must be signed in to change notification settings - Fork 1.7k
feat: list cmd support json for specs and archive #700
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
RandyZ
wants to merge
6
commits into
Fission-AI:main
Choose a base branch
from
RandyZ:feature/list-cmd-support-json-for-specs-and-archive
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+860
−28
Open
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
fefbbcc
Update .gitignore
RandyZ 6d789cc
Add --archive and specs JSON to list
RandyZ 3195ae4
Archive 'add-list-specs-json-and-archive'
RandyZ 09840b8
Merge branch 'main' into feature/list-cmd-support-json-for-specs-and-…
RandyZ 57ccbe2
Add spec title and list JSON detail
RandyZ 66b977a
Merge branch 'main' into feature/list-cmd-support-json-for-specs-and-…
RandyZ File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -146,6 +146,9 @@ vite.config.ts.timestamp-* | |
| CLAUDE.md | ||
| .DS_Store | ||
|
|
||
| # Cursor | ||
| .cursor/ | ||
|
|
||
| # Pnpm | ||
| .pnpm-store/ | ||
| result | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 2 additions & 0 deletions
2
openspec/changes/archive/2025-02-12-add-spec-title-and-list-json-fields/.openspec.yaml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| schema: spec-driven | ||
| created: 2026-02-13 |
68 changes: 68 additions & 0 deletions
68
openspec/changes/archive/2025-02-12-add-spec-title-and-list-json-fields/design.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| # Design: Add Spec title and list JSON fields | ||
|
|
||
| ## Context | ||
|
|
||
| The Spec type is defined in `src/core/schemas/spec.schema.ts` (name, overview, requirements, metadata). `MarkdownParser.parseSpec(name)` in `src/core/parsers/markdown-parser.ts` builds a Spec from spec.md: it requires `## Purpose` and `## Requirements`, maps Purpose content to `overview`, and passes through the `name` argument (spec id) as the spec’s `name`. The document’s first `# H1` is not currently parsed or stored. Multiple callers depend on the Spec shape: validation (SpecSchema.safeParse), list command (parseSpec for specs mode), view dashboard, deprecated spec show/list, and json-converter. Changing the schema or parser return shape can break any of these if not updated consistently. | ||
|
|
||
| ## Goals / Non-Goals | ||
|
|
||
| **Goals:** | ||
|
|
||
| - Add a required `title` field to the Spec type, set from the first `# H1` in the spec document, with fallback to the spec id (`name`) when H1 is missing or unparseable. | ||
| - Keep `openspec list --specs --json` output unchanged (each item: `id`, `requirementCount` only). Add a `--detail` flag so that when used (e.g. `openspec list --specs --json --detail`), each spec entry additionally includes `title` and `overview`, enabling LLMs and scripts to optionally discover and select specs without reading each file. | ||
| - Ensure all existing callers of SpecSchema and `parseSpec()` are identified, updated if they construct or consume Spec, and verified so that existing behavior is preserved and new behavior is consistent. | ||
|
|
||
| **Non-Goals:** | ||
|
|
||
| - Adding a separate `summary` field (overview remains the description). | ||
| - Changing required sections (Purpose, Requirements) or validation rules beyond accommodating `title`. | ||
| - Frontmatter or other overrides for title in this change. | ||
|
|
||
| ## Call-site audit (mandatory before implementation) | ||
|
|
||
| Before changing the schema or parser, every consumer of the Spec type or `parseSpec()` must be checked and updated as needed so that existing functionality is not broken. | ||
|
|
||
| | Location | Usage | Required change / check | | ||
| |----------|--------|---------------------------| | ||
| | `src/core/schemas/spec.schema.ts` | Defines Spec type | Add required `title: z.string().min(1, …)`. | | ||
| | `src/core/parsers/markdown-parser.ts` | `parseSpec(name): Spec` | Extract first level-1 heading; set `title` to that or `name`. Return `title` in the Spec object. | | ||
| | `src/core/validation/validator.ts` | `parser.parseSpec(specName)` then `SpecSchema.safeParse(spec)`; `applySpecRules(spec)` uses `spec.overview` | Parser will always return `title`. Validator only needs to pass through; confirm no code builds a Spec manually without `title`. | | ||
| | `src/core/list.ts` | `parser.parseSpec(id)`; uses `spec.requirements.length` for specs mode JSON | Default (no `--detail`): keep current shape (id, requirementCount only). When `options.json` and `options.detail` are both true, add `title: spec.title` and `overview: spec.overview` to each item in the `specs` array. CLI: add `--detail` option to list command. | | ||
| | `src/core/view.ts` | `parser.parseSpec(entry.name)`; uses `spec.requirements.length` | No change required for this change; optional later: show `spec.title` in dashboard. | | ||
| | `src/commands/spec.ts` | `parseSpecFromFile` → `parseSpec`; `show` uses `parsed.name` as `title`, `parsed.overview`; `list` uses `spec.name` as `title` | **show**: Use `parsed.title` for the output `title` field instead of `parsed.name`. **list**: Use `spec.title` instead of `spec.name` for the displayed/list title. | | ||
| | `src/core/converters/json-converter.ts` | `parser.parseSpec(specName)` then spreads `...spec` into JSON | No code change; once parser returns `title`, the converted JSON will include it. | | ||
|
|
||
| **Implementation order:** (1) Schema + parser (so every Spec has `title`), (2) list.ts (add `--detail` option and conditional title/overview in specs JSON), (3) spec.ts (deprecated show/list use `title`), (4) run tests and any code that constructs Spec or validates with SpecSchema to confirm no regressions. | ||
|
|
||
| ## Decisions | ||
|
|
||
| 1. **Title required in schema** | ||
| `title` is a required field so that every Spec is guaranteed to have a display name. The parser is the single place that sets it (H1 or fallback to name), so no caller has to handle missing title. | ||
|
|
||
| 2. **H1 extraction in parser** | ||
| Reuse the existing section parse: the first top-level section with `level === 1` from `parseSections()` is the document title. Use its `title` property (the heading text). If there is no level-1 section, use the `name` argument. This avoids a separate first-line regex and keeps parsing in one place. | ||
|
|
||
| 3. **List JSON: default unchanged; `--detail` adds title and overview** | ||
| Default `openspec list --specs --json` is unchanged: each element in `specs` has only `id` and `requirementCount`. When `--detail` is passed (e.g. `openspec list --specs --json --detail`), each element additionally includes `title` and `overview`. Use `overview` (not a new name like `purpose`) so the field name matches the Spec type and existing `openspec spec show --json` output. | ||
|
|
||
| 4. **Deprecated spec list / show** | ||
| `openspec spec show --json` already outputs `title` and `overview`; switch the source of `title` from `parsed.name` to `parsed.title`. `openspec spec list` (and --long/--json) currently use `spec.name` as the display title; use `spec.title` so behavior aligns with the new model and with list --specs --json. | ||
|
|
||
| ## Risks / Trade-offs | ||
|
|
||
| - **[Risk]** Existing tests or code that build a Spec object manually (e.g. mocks) may omit `title` and fail validation. | ||
| **Mitigation:** Grep for `Spec` construction and `SpecSchema.safeParse`/`parseSpec`; add `title` to any fixture or mock that returns a Spec. | ||
|
|
||
| - **[Risk]** Specs with no `# H1` (only `## Purpose`, etc.) will get `title = name`; that may be less readable than a proper H1. | ||
| **Mitigation:** Acceptable; conventions can recommend adding an H1. No change to required sections. | ||
|
|
||
| - **[Trade-off]** Parser does slightly more work (scan for first H1). Cost is one pass over already-parsed sections; negligible. | ||
|
|
||
| ## Migration Plan | ||
|
|
||
| - No data migration. Existing spec.md files need no change; missing H1 is handled by fallback to name. | ||
| - After implementation: run full test suite; manually run `openspec list --specs --json` (confirm unchanged: id, requirementCount only), `openspec list --specs --json --detail` (confirm title and overview present), `openspec spec show <id> --json`, and `openspec spec list --json` to confirm shape and that title/overview appear as expected where applicable. | ||
|
|
||
| ## Open Questions | ||
|
|
||
| - None for this change. Optional follow-up: document in openspec-conventions that the first `# H1` is the canonical display title and is used in list/APIs. |
27 changes: 27 additions & 0 deletions
27
...spec/changes/archive/2025-02-12-add-spec-title-and-list-json-fields/proposal.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| ## Why | ||
|
|
||
| `openspec list --specs --json` currently returns only `id` and `requirementCount` per spec. LLMs and scripts sometimes need a human-readable title and a short description (e.g. from the spec document) to discover and select relevant specs without opening each spec file. The spec document already has a top-level heading (`# H1`) and a Purpose section (`## Purpose`). We should (1) add a required `title` to the Spec model and (2) allow list JSON to optionally include `title` and `overview` via a new flag, without changing the default list output. | ||
|
|
||
| ## What Changes | ||
|
|
||
| - **Spec schema**: Add a required `title` field to the Spec type. When parsing a spec, set `title` from the document's first `# H1`; when that is missing or unparseable, fall back to the spec id (`name`). No new `summary` field — keep using `overview` (## Purpose) for description. | ||
| - **Parser**: In `MarkdownParser.parseSpec()` (or the code that builds the Spec object), extract the first level-1 heading and assign it to `title`; otherwise use the passed-in `name`. | ||
| - **List JSON**: Keep `openspec list --specs --json` unchanged: each spec entry continues to have only `id` and `requirementCount`. Add a new `--detail` flag; when used with `--specs --json` (e.g. `openspec list --specs --json --detail`), include `title` and `overview` in each spec entry so tooling can optionally get display name and Purpose text. | ||
| - **Deprecated `spec list`**: Align with the new model: `openspec spec list --long` and its JSON output should use the parsed `title` (from H1 or name) so behavior is consistent. | ||
|
|
||
| ## Capabilities | ||
|
|
||
| ### New Capabilities | ||
|
|
||
| None. This change extends the existing spec model and list command only. | ||
|
|
||
| ### Modified Capabilities | ||
|
|
||
| - **openspec-conventions**: Document that a spec's document title (first `# H1`) is the canonical display title and is exposed in list/APIs; when H1 is absent, the spec id is used. No change to required sections (Purpose, Requirements). | ||
| - **cli-list**: Extend the list command specification: (1) `openspec list --specs --json` remains unchanged (each item has `id`, `requirementCount` only). (2) Add a `--detail` option; when `openspec list --specs --json --detail` is used, each item in the `specs` array additionally includes `title` (string) and `overview` (string). | ||
|
|
||
| ## Impact | ||
|
|
||
| - **Code**: `src/core/schemas/spec.schema.ts` (add required `title`), `src/core/parsers/markdown-parser.ts` (extract first H1, set title; fallback to name), `src/core/list.ts` (add `--detail`; when `--specs --json --detail`, include `title` and `overview` in each spec entry; default list --specs --json unchanged), `src/commands/spec.ts` (use parsed title in deprecated spec list when available). | ||
| - **Validation**: Ensure validators that construct or validate Spec objects supply `title`; existing specs without an explicit H1 will get `title = name` after the parser fallback. | ||
| - **Tests**: Update or add tests for parser (H1 → title, no H1 → name), list JSON without --detail (unchanged shape), list JSON with --detail (title, overview), and deprecated spec list output. |
60 changes: 60 additions & 0 deletions
60
...s/archive/2025-02-12-add-spec-title-and-list-json-fields/specs/cli-list/spec.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| ## MODIFIED Requirements | ||
|
|
||
| ### Requirement: Output Format | ||
| The command SHALL display items in a clear, readable table format with mode-appropriate progress or counts when `--json` is not provided, or output JSON when `--json` is provided. | ||
|
|
||
| #### Scenario: Displaying change list (default) | ||
| - **WHEN** displaying the list of changes without `--json` | ||
| - **THEN** show a table with columns: | ||
| - Change name (directory name) | ||
| - Task progress (e.g., "3/5 tasks" or "✓ Complete") | ||
|
|
||
| #### Scenario: Displaying spec list | ||
| - **WHEN** displaying the list of specs without `--json` | ||
| - **THEN** show a table with columns: | ||
| - Spec id (directory name) | ||
| - Requirement count (e.g., "requirements 12") | ||
|
|
||
| #### Scenario: JSON output for specs | ||
| - **WHEN** `openspec list --specs --json` is executed without `--detail` | ||
| - **THEN** output a JSON object with key `specs` and an array of objects with `id` and `requirementCount` only | ||
| - **AND** output `{ "specs": [] }` when no specs exist | ||
|
|
||
| #### Scenario: JSON output for specs with detail | ||
| - **WHEN** `openspec list --specs --json --detail` is executed | ||
| - **THEN** output a JSON object with key `specs` and an array of objects with `id`, `requirementCount`, `title`, and `overview` | ||
| - **AND** `title` SHALL be the spec's display title (from document H1 or spec id) | ||
| - **AND** `overview` SHALL be the spec's Purpose section content | ||
| - **AND** output `{ "specs": [] }` when no specs exist | ||
|
|
||
| #### Scenario: Displaying archive list | ||
| - **WHEN** displaying the list of archived changes without `--json` | ||
| - **THEN** show a table with columns: archived change name (directory name), task progress, and last modified (e.g. relative time) | ||
|
|
||
| #### Scenario: JSON output for archive | ||
| - **WHEN** `openspec list --archive --json` is executed | ||
| - **THEN** output a JSON object with key `archivedChanges` and an array of objects with `name`, `completedTasks`, `totalTasks`, `lastModified` (ISO string), and `status` | ||
|
|
||
| ### Requirement: Flags | ||
| The command SHALL accept flags to select the noun being listed. When more than one of `--changes`, `--specs`, or `--archive` is provided, the effective mode SHALL be determined by precedence: `--archive` overrides `--specs`, `--specs` overrides default (changes). The command SHALL accept a `--detail` flag that, when used with `--specs --json`, causes each spec entry to include `title` and `overview`. | ||
|
|
||
| #### Scenario: Selecting specs | ||
| - **WHEN** `--specs` is provided | ||
| - **THEN** list specs instead of changes | ||
|
|
||
| #### Scenario: Selecting changes | ||
| - **WHEN** `--changes` is provided | ||
| - **THEN** list changes explicitly (same as default behavior) | ||
|
|
||
| #### Scenario: Selecting archive | ||
| - **WHEN** `--archive` is provided | ||
| - **THEN** list archived changes (directories under openspec/changes/archive/) | ||
|
|
||
| #### Scenario: Mode precedence | ||
| - **WHEN** more than one of `--changes`, `--specs`, or `--archive` is provided | ||
| - **THEN** the effective mode SHALL be determined by precedence: `--archive` overrides `--specs`, `--specs` overrides default (changes) | ||
|
|
||
| #### Scenario: Requesting detail for spec list JSON | ||
| - **WHEN** `--detail` is provided together with `--specs --json` | ||
| - **THEN** each object in the `specs` array SHALL include `title` and `overview` in addition to `id` and `requirementCount` | ||
| - **AND** when `--detail` is omitted, spec list JSON SHALL remain unchanged (id and requirementCount only) |
17 changes: 17 additions & 0 deletions
17
...25-02-12-add-spec-title-and-list-json-fields/specs/openspec-conventions/spec.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| ## ADDED Requirements | ||
|
|
||
| ### Requirement: Spec document title as canonical display title | ||
|
|
||
| A spec's document title SHALL be the first level-1 heading (`# H1`) in the spec file. This title SHALL be the canonical display title for the spec and SHALL be exposed in list output and APIs (e.g. when listing specs with a detail option). When the document has no level-1 heading or it cannot be parsed, the spec id (directory name) SHALL be used as the display title. Required sections (Purpose, Requirements) SHALL remain unchanged. | ||
|
|
||
| #### Scenario: Document with H1 | ||
|
|
||
| - **WHEN** a spec file has a first level-1 heading (e.g. `# List Command Specification`) | ||
| - **THEN** that heading text SHALL be used as the spec's display title | ||
| - **AND** tooling that exposes spec titles (e.g. list with detail) SHALL show this title | ||
|
|
||
| #### Scenario: Document without H1 | ||
|
|
||
| - **WHEN** a spec file has no level-1 heading (e.g. only `## Purpose`, `## Requirements`) | ||
| - **THEN** the spec id (capability directory name) SHALL be used as the display title | ||
| - **AND** tooling that exposes spec titles SHALL show the spec id | ||
RandyZ marked this conversation as resolved.
Show resolved
Hide resolved
|
||
22 changes: 22 additions & 0 deletions
22
openspec/changes/archive/2025-02-12-add-spec-title-and-list-json-fields/tasks.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| ## 1. Schema and parser | ||
|
|
||
| - [x] 1.1 Add required `title` field to Spec type in `src/core/schemas/spec.schema.ts` | ||
| - [x] 1.2 In `markdown-parser.parseSpec()`, extract first level-1 heading and set `title`; fallback to `name` when H1 is missing or unparseable | ||
| - [x] 1.3 Add `title` to any fixtures or mocks that construct a Spec (grep for SpecSchema.safeParse / parseSpec / Spec construction) | ||
|
|
||
| ## 2. List command and --detail | ||
|
|
||
| - [x] 2.1 Add `--detail` option to list command (CLI flag and options type passed to list) | ||
| - [x] 2.2 In `src/core/list.ts` specs-mode JSON: when `options.json` and `options.detail` are true, include `title` and `overview` in each spec entry; when `--detail` is omitted, keep output shape unchanged (id, requirementCount only) | ||
|
|
||
| ## 3. Deprecated spec command | ||
|
|
||
| - [x] 3.1 In `openspec spec show`: use `parsed.title` for the output title field instead of `parsed.name` | ||
| - [x] 3.2 In `openspec spec list` (and --long/--json): use `spec.title` for the displayed/list title instead of `spec.name` | ||
|
|
||
| ## 4. Tests and verification | ||
|
|
||
| - [x] 4.1 Add or update parser tests: document with H1 → title set from heading; document without H1 → title equals name | ||
| - [x] 4.2 Add or update list tests: `openspec list --specs --json` output shape unchanged (id, requirementCount only); `openspec list --specs --json --detail` includes title and overview per spec | ||
| - [x] 4.3 Update or add tests for deprecated spec list/show to assert title comes from parsed title | ||
| - [x] 4.4 Run full test suite; manually run `openspec list --specs --json`, `openspec list --specs --json --detail`, `openspec spec show <id> --json`, and `openspec spec list --json` to confirm shapes and title/overview where applicable |
2 changes: 2 additions & 0 deletions
2
openspec/changes/archive/2026-02-12-add-list-specs-json-and-archive/.openspec.yaml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| schema: spec-driven | ||
| created: 2026-02-12 |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fenced code block missing language specifier.
The static analysis tool (markdownlint MD040) flags this code block. Add a language identifier for consistency with the rest of the file.
Proposed fix
In
@docs/cli.mdaround lines 197 - 203, The fenced code block under the "Output(text):" section lacks a language specifier which triggers markdownlint MD040;
update the opening fence to include a language identifier (e.g., change ``` to