Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions openspec/specs/ai-tool-paths/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,16 @@ The `AI_TOOLS` array SHALL include `skillsDir` for tools that support the Agent
- **WHEN** looking up the `cursor` tool
- **THEN** `skillsDir` SHALL be `.cursor`

#### Scenario: Windsurf paths defined
#### Scenario: Devin Desktop paths defined

- **WHEN** looking up the `windsurf` tool
- **THEN** `skillsDir` SHALL be `.windsurf`
- **WHEN** looking up the `devin` tool
- **THEN** `skillsDir` SHALL be `.devin`

#### Scenario: Legacy Windsurf tool ID

- **WHEN** initializing with `openspec init --tools windsurf`
- **THEN** the `windsurf` alias SHALL resolve to `devin`
- **AND** when skill delivery is enabled, skills SHALL be generated under `.devin/skills/`, not `.windsurf/skills/`

#### Scenario: Kimi Code paths defined

Expand Down
21 changes: 11 additions & 10 deletions openspec/specs/cli-artifact-workflow/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,8 @@ The system SHALL support an `apply` block in schema definitions that controls wh
#### Scenario: Schema without apply block

- **WHEN** a schema has no `apply` block
- **THEN** the system requires all artifacts to exist before apply is available
- **AND** uses default instruction: "All artifacts complete. Proceed with implementation."
- **THEN** the system requires all non-skipped artifacts to exist before apply is available
- **AND** once those artifacts exist, uses default instruction: "All required artifacts complete. Proceed with implementation."

### Requirement: Apply Instructions Command

Expand Down Expand Up @@ -275,23 +275,24 @@ The `artifact-experimental-setup` command SHALL accept a `--tool <tool-id>` flag

### Requirement: Output messaging

The setup command SHALL display clear output about what was generated.
The `openspec init` command SHALL display clear output about what was generated.

#### Scenario: Show target tool in output

- **WHEN** setup command runs successfully
- **THEN** output includes the target tool name (e.g., "Setting up for Cursor...")
- **WHEN** initialization creates or refreshes a tool configuration
- **THEN** output includes the tool name under `Created:` or `Refreshed:`, respectively

#### Scenario: Show generated paths

- **WHEN** setup command completes
- **THEN** output lists all generated skill file paths
- **AND** lists all generated command file paths (if applicable)
- **WHEN** initialization generates skills or commands
- **THEN** output summarizes their counts and destination directories
- **AND** only reports the types enabled by the selected profile and delivery mode

#### Scenario: Show skipped commands message

- **WHEN** command generation is skipped due to missing adapter
- **THEN** output includes message: "Command generation skipped - no adapter for <tool>"
- **WHEN** initialization skips command generation due to a missing adapter
- **THEN** output includes message: "Commands skipped for: <tools> (no adapter)"
- **AND** `<tools>` lists the skipped tool IDs separated by commas

### Requirement: Status JSON provides planning context
The status command SHALL provide machine-readable planning context for changes.
Expand Down
26 changes: 18 additions & 8 deletions openspec/specs/cli-change/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,19 +37,29 @@ The system SHALL provide a `change` command with subcommands for displaying, lis

### Requirement: Legacy Compatibility

The system SHALL maintain backward compatibility with the existing `list` command while showing deprecation notices.
The system SHALL retain `openspec change list` as a deprecated alias for listing active changes and direct users to `openspec list`.

#### Scenario: Legacy list command

- **WHEN** executing `openspec list`
- **THEN** display current list of changes (existing behavior)
- **AND** show deprecation notice: "Note: 'openspec list' is deprecated. Use 'openspec change list' instead."
- **WHEN** executing `openspec change list`
- **THEN** display the current list of active changes on stdout
- **AND** write `Warning: "openspec change list" is deprecated. Use "openspec list".` to stderr

#### Scenario: Legacy list with JSON output

- **WHEN** executing `openspec change list --json`
- **THEN** output the active changes as a JSON array on stdout
- **AND** write the deprecation warning to stderr without corrupting the JSON output

#### Scenario: Legacy list with --all flag
#### Scenario: Unsupported legacy list flag

- **WHEN** executing `openspec list --all`
- **THEN** display all changes (existing behavior)
- **AND** show same deprecation notice
- **WHEN** executing `openspec change list --all`
- **THEN** reject the unknown option with a nonzero exit code

#### Scenario: Preferred list command

- **WHEN** executing `openspec list`
- **THEN** display the current list of active changes without a deprecation warning

### Requirement: Interactive show selection

Expand Down
34 changes: 34 additions & 0 deletions test/cli-e2e/basic.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,40 @@ describe('openspec CLI e2e basics', () => {
expectJsonOnlyOutput(result);
});

describe('legacy change list compatibility', () => {
it.each([
{ args: [], output: 'c1\n' },
{ args: ['--long'], output: 'c1: Test Change [deltas 1]\n' },
])('preserves text output with $args and warns on stderr', async ({ args, output }) => {
const projectDir = await prepareFixture('tmp-init');
const result = await runCLI(['change', 'list', ...args], { cwd: projectDir });

expect(result.exitCode).toBe(0);
expect(result.stdout).toBe(output);
expect(result.stderr).toContain('Warning: "openspec change list" is deprecated. Use "openspec list".');
});

it('preserves JSON output and warns on stderr', async () => {
const projectDir = await prepareFixture('tmp-init');
const result = await runCLI(['change', 'list', '--json'], { cwd: projectDir });

expect(result.exitCode).toBe(0);
expect(JSON.parse(result.stdout)).toEqual([
{ id: 'c1', title: 'Test Change', deltaCount: 1, taskStatus: { total: 0, completed: 0 } },
]);
expect(result.stderr).toContain('Warning: "openspec change list" is deprecated. Use "openspec list".');
});

it('rejects the unsupported --all option', async () => {
const projectDir = await prepareFixture('tmp-init');
const result = await runCLI(['change', 'list', '--all'], { cwd: projectDir });

expect(result.exitCode).toBe(1);
expect(result.stdout).toBe('');
expect(result.stderr).toContain("error: unknown option '--all'");
});
});

it('keeps schemas --json free of spinner output', async () => {
const projectDir = await prepareFixture('tmp-init');
const result = await runCLI(['schemas', '--json'], { cwd: projectDir });
Expand Down
Loading