-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Fix OpenCode command directory handling #675
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
JcMinarro
wants to merge
6
commits into
Fission-AI:main
Choose a base branch
from
JcMinarro:fix-opencode-commands-path
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.
+395
−12
Open
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
895d359
fix: align OpenCode command directory handling
JcMinarro 27e5c9f
test: cover OpenCode command migration
JcMinarro fdb6516
fix: typo on numeration
JcMinarro c97eda3
fix: address PR review feedback
JcMinarro 6aeb012
fix: address PR review feedback on migration order and unused variable
JcMinarro 460e965
fix: remove unused canPrompt variable in generateSkillsAndCommands
JcMinarro 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
2 changes: 2 additions & 0 deletions
2
openspec/changes/archive/2026-02-06-fix-opencode-commands-dir/.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-06 |
39 changes: 39 additions & 0 deletions
39
openspec/changes/archive/2026-02-06-fix-opencode-commands-dir/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,39 @@ | ||
| ## Context | ||
|
|
||
| OpenSpec integration scripts currently generate OpenCode AI command markdown files under `.opencode/command/`, but the official documentation specifies `.opencode/commands/`. This change focuses on the OpenSpec initialization script that writes those markdown files. | ||
|
|
||
| ## Goals / Non-Goals | ||
|
|
||
| **Goals:** | ||
| - Align generated command file locations with `.opencode/commands/`. | ||
| - Limit changes to OpenSpec init/update flows that generate or migrate command markdown files. | ||
|
|
||
| **Non-Goals:** | ||
| - Redesign the command format or command execution model. | ||
| - Change the existing command content or add new command types. | ||
| - Update CLI behavior unrelated to command generation or migration. | ||
|
|
||
| ## Decisions | ||
|
|
||
| - Use `.opencode/commands/` as the single source of truth for generated command files, matching documentation. | ||
| - Alternative: keep `.opencode/command/` as-is and update docs. Rejected because documentation is authoritative and users already rely on it. | ||
| - Update OpenSpec init/update to write command markdown files directly into `.opencode/commands/`. | ||
| - Alternative: keep `.opencode/command/` and update docs. Rejected because the documentation is the source of truth. | ||
| - If `.opencode/command/` exists, migrate its files into `.opencode/commands/` and prompt to delete the old directory when it is empty. | ||
| - Alternative: leave the old directory indefinitely. Rejected to avoid confusion and duplicated locations. | ||
|
|
||
| ## Risks / Trade-offs | ||
|
|
||
| - [Risk] Existing users may have custom tooling pointing at `.opencode/command/` → Mitigation: migrate files and communicate the new location in OpenSpec output. | ||
| - [Trade-off] Migration logic adds a small amount of complexity to initialization → Mitigation: keep migration to a straightforward move/copy step plus optional cleanup. | ||
|
|
||
| ## Migration Plan | ||
|
|
||
| - Update OpenSpec init/update to create `.opencode/commands/` and generate command files there. | ||
| - If `.opencode/command/` exists, move or copy known command files into `.opencode/commands/`. | ||
| - If `.opencode/command/` is empty after migration, prompt the user to delete it. | ||
| - Update tests and documentation to reference `.opencode/commands/`. | ||
|
|
||
| ## Open Questions | ||
|
|
||
| - Should the cleanup prompt be opt-in or on by default when `.opencode/command/` is empty? |
22 changes: 22 additions & 0 deletions
22
openspec/changes/archive/2026-02-06-fix-opencode-commands-dir/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,22 @@ | ||
| ## Why | ||
|
|
||
| The OpenSpec integration scripts currently generate command files under `.opencode/command/`, while the official documentation requires `.opencode/commands/`. This mismatch breaks expected tooling behavior and creates confusion for users following the docs. | ||
|
|
||
| ## What Changes | ||
|
|
||
| - Align OpenCode command generation and update behavior to use the documented `.opencode/commands/` directory. | ||
| - Normalize any references that assume the singular directory so the CLI and docs agree. | ||
|
|
||
| ## Capabilities | ||
|
|
||
| ### New Capabilities | ||
| - (none) | ||
|
|
||
| ### Modified Capabilities | ||
| - `cli-update`: Update the requirements to point to `.opencode/commands/` instead of `.opencode/command/`. | ||
|
|
||
| ## Impact | ||
|
|
||
| - OpenCode CLI command generation and update logic. | ||
| - Documentation references for command locations. | ||
| - Tests that assert command file paths. |
98 changes: 98 additions & 0 deletions
98
...c/changes/archive/2026-02-06-fix-opencode-commands-dir/specs/cli-update/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,98 @@ | ||
| ## MODIFIED Requirements | ||
|
|
||
| ### Requirement: Slash Command Updates | ||
|
|
||
| The update command SHALL refresh existing slash command files for configured tools without creating new ones, and ensure the OpenCode archive command accepts change ID arguments. | ||
|
|
||
| #### Scenario: Updating slash commands for Antigravity | ||
| - **WHEN** `.agent/workflows/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` | ||
| - **THEN** refresh the OpenSpec-managed portion of each file so the workflow copy matches other tools while preserving the existing single-field `description` frontmatter | ||
| - **AND** skip creating any missing workflow files during update, mirroring the behavior for Windsurf and other IDEs | ||
|
|
||
| #### Scenario: Updating slash commands for Claude Code | ||
| - **WHEN** `.claude/commands/openspec/` contains `proposal.md`, `apply.md`, and `archive.md` | ||
| - **THEN** refresh each file using shared templates | ||
| - **AND** ensure templates include instructions for the relevant workflow stage | ||
|
|
||
| #### Scenario: Updating slash commands for CodeBuddy Code | ||
| - **WHEN** `.codebuddy/commands/openspec/` contains `proposal.md`, `apply.md`, and `archive.md` | ||
| - **THEN** refresh each file using the shared CodeBuddy templates that include YAML frontmatter for the `description` and `argument-hint` fields | ||
| - **AND** use square bracket format for `argument-hint` parameters (e.g., `[change-id]`) | ||
| - **AND** preserve any user customizations outside the OpenSpec managed markers | ||
|
|
||
| #### Scenario: Updating slash commands for Cline | ||
| - **WHEN** `.clinerules/workflows/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` | ||
| - **THEN** refresh each file using shared templates | ||
| - **AND** include Cline-specific Markdown heading frontmatter | ||
| - **AND** ensure templates include instructions for the relevant workflow stage | ||
|
|
||
| #### Scenario: Updating slash commands for Continue | ||
| - **WHEN** `.continue/prompts/` contains `openspec-proposal.prompt`, `openspec-apply.prompt`, and `openspec-archive.prompt` | ||
| - **THEN** refresh each file using shared templates | ||
| - **AND** ensure templates include instructions for the relevant workflow stage | ||
|
|
||
| #### Scenario: Updating slash commands for Crush | ||
| - **WHEN** `.crush/commands/` contains `openspec/proposal.md`, `openspec/apply.md`, and `openspec/archive.md` | ||
| - **THEN** refresh each file using shared templates | ||
| - **AND** include Crush-specific frontmatter with OpenSpec category and tags | ||
| - **AND** ensure templates include instructions for the relevant workflow stage | ||
|
|
||
| #### Scenario: Updating slash commands for Cursor | ||
| - **WHEN** `.cursor/commands/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` | ||
| - **THEN** refresh each file using shared templates | ||
| - **AND** ensure templates include instructions for the relevant workflow stage | ||
|
|
||
| #### Scenario: Updating slash commands for Factory Droid | ||
| - **WHEN** `.factory/commands/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` | ||
| - **THEN** refresh each file using the shared Factory templates that include YAML frontmatter for the `description` and `argument-hint` fields | ||
| - **AND** ensure the template body retains the `$ARGUMENTS` placeholder so user input keeps flowing into droid | ||
| - **AND** update only the content inside the OpenSpec managed markers, leaving any unmanaged notes untouched | ||
| - **AND** skip creating missing files during update | ||
|
|
||
| #### Scenario: Updating slash commands for OpenCode | ||
| - **WHEN** `.opencode/commands/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` | ||
| - **THEN** refresh each file using shared templates | ||
| - **AND** ensure templates include instructions for the relevant workflow stage | ||
| - **AND** ensure the archive command includes `$ARGUMENTS` placeholder in frontmatter for accepting change ID arguments | ||
|
|
||
| #### Scenario: Updating slash commands for Windsurf | ||
| - **WHEN** `.windsurf/workflows/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` | ||
| - **THEN** refresh each file using shared templates wrapped in OpenSpec markers | ||
| - **AND** ensure templates include instructions for the relevant workflow stage | ||
| - **AND** skip creating missing files (the update command only refreshes what already exists) | ||
|
|
||
| #### Scenario: Updating slash commands for Kilo Code | ||
| - **WHEN** `.kilocode/workflows/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` | ||
| - **THEN** refresh each file using shared templates wrapped in OpenSpec markers | ||
| - **AND** ensure templates include instructions for the relevant workflow stage | ||
| - **AND** skip creating missing files (the update command only refreshes what already exists) | ||
|
|
||
| #### Scenario: Updating slash commands for Codex | ||
| - **GIVEN** the global Codex prompt directory contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` | ||
| - **WHEN** a user runs `openspec update` | ||
| - **THEN** refresh each file using the shared slash-command templates (including placeholder guidance) | ||
| - **AND** preserve any unmanaged content outside the OpenSpec marker block | ||
| - **AND** skip creation when a Codex prompt file is missing | ||
|
|
||
| #### Scenario: Updating slash commands for GitHub Copilot | ||
| - **WHEN** `.github/prompts/` contains `openspec-proposal.prompt.md`, `openspec-apply.prompt.md`, and `openspec-archive.prompt.md` | ||
| - **THEN** refresh each file using shared templates while preserving the YAML frontmatter | ||
| - **AND** update only the OpenSpec-managed block between markers | ||
| - **AND** ensure templates include instructions for the relevant workflow stage | ||
|
|
||
| #### Scenario: Updating slash commands for Gemini CLI | ||
| - **WHEN** `.gemini/commands/openspec/` contains `proposal.toml`, `apply.toml`, and `archive.toml` | ||
| - **THEN** refresh the body of each file using the shared proposal/apply/archive templates | ||
| - **AND** replace only the content between `<!-- OPENSPEC:START -->` and `<!-- OPENSPEC:END -->` markers inside the `prompt = """` block so the TOML framing (`description`, `prompt`) stays intact | ||
| - **AND** skip creating any missing `.toml` files during update; only pre-existing Gemini commands are refreshed | ||
|
|
||
| #### Scenario: Updating slash commands for iFlow CLI | ||
| - **WHEN** `.iflow/commands/` contains `openspec-proposal.md`, `openspec-apply.md`, and `openspec-archive.md` | ||
| - **THEN** refresh each file using shared templates | ||
| - **AND** preserve the YAML frontmatter with `name`, `id`, `category`, and `description` fields | ||
| - **AND** update only the OpenSpec-managed block between markers | ||
| - **AND** ensure templates include instructions for the relevant workflow stage | ||
|
|
||
| #### Scenario: Missing slash command file | ||
| - **WHEN** a tool lacks a slash command file | ||
| - **THEN** do not create a new file during update |
18 changes: 18 additions & 0 deletions
18
openspec/changes/archive/2026-02-06-fix-opencode-commands-dir/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,18 @@ | ||
| ## 1. Scope And Specs | ||
|
|
||
| - [x] 1.1 Confirm no new capabilities and only `cli-update` spec is modified | ||
| - [x] 1.2 Review `openspec/specs/cli-update/spec.md` to locate the existing OpenCode slash command scenario | ||
| - [x] 1.3 Update the delta spec to replace `.opencode/command/` with `.opencode/commands/` and remove the Windows path variant if not required | ||
|
|
||
| ## 2. OpenSpec Initialization Script Update | ||
|
|
||
| - [x] 2.1 Find the OpenSpec initialization script that generates OpenCode command markdown files | ||
| - [x] 2.2 Change the OpenCode command output directory to `.opencode/commands/` | ||
| - [x] 2.3 If `.opencode/command/` exists, migrate known OpenCode command files into `.opencode/commands/` | ||
| - [x] 2.4 If `.opencode/command/` is empty after migration, prompt the user to delete it and remove it on confirmation | ||
| - [x] 2.5 Ensure the cleanup prompt is visible (pause spinner before asking) | ||
|
|
||
| ## 3. Tests And Verification | ||
|
|
||
| - [x] 3.1 Update any tests or fixtures that assert the OpenCode command directory path | ||
| - [x] 3.2 Run existing tests related to OpenSpec init/update and ensure they pass |
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
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
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
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
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
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,54 @@ | ||
| import path from 'path'; | ||
| import * as fs from 'fs'; | ||
| import { FileSystemUtils } from '../../utils/file-system.js'; | ||
|
|
||
| export async function migrateOpenCodeCommands( | ||
| projectPath: string, | ||
| canPrompt: boolean | ||
| ): Promise<void> { | ||
| const legacyDir = path.join(projectPath, '.opencode', 'command'); | ||
| if (!await FileSystemUtils.directoryExists(legacyDir)) { | ||
| return; | ||
| } | ||
|
|
||
| const nextDir = path.join(projectPath, '.opencode', 'commands'); | ||
| await FileSystemUtils.createDirectory(nextDir); | ||
|
|
||
| const entries = await fs.promises.readdir(legacyDir, { withFileTypes: true }); | ||
| let changedAny = false; | ||
| for (const entry of entries) { | ||
| if (!entry.isFile()) continue; | ||
| const sourcePath = path.join(legacyDir, entry.name); | ||
| const destinationPath = path.join(nextDir, entry.name); | ||
| // Prefer the new location on conflicts: keep destination, discard legacy. | ||
| if (await FileSystemUtils.fileExists(destinationPath)) { | ||
| await fs.promises.unlink(sourcePath); | ||
| changedAny = true; | ||
| continue; | ||
| } | ||
|
|
||
| try { | ||
| await fs.promises.rename(sourcePath, destinationPath); | ||
| } catch (error: any) { | ||
| if (error?.code !== 'EXDEV') { | ||
| throw error; | ||
| } | ||
| // Fallback for cross-device moves. | ||
| await fs.promises.copyFile(sourcePath, destinationPath); | ||
| await fs.promises.unlink(sourcePath); | ||
| } | ||
| changedAny = true; | ||
| } | ||
JcMinarro marked this conversation as resolved.
Show resolved
Hide resolved
JcMinarro marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| const remaining = await fs.promises.readdir(legacyDir); | ||
| if (changedAny && remaining.length === 0 && canPrompt) { | ||
| const { confirm } = await import('@inquirer/prompts'); | ||
| const shouldRemove = await confirm({ | ||
| message: 'OpenCode commands have moved to .opencode/commands. The old .opencode/command directory is now empty and can be removed. Delete it?', | ||
| default: true, | ||
| }); | ||
| if (shouldRemove) { | ||
| await fs.promises.rm(legacyDir, { recursive: true, force: true }); | ||
| } | ||
| } | ||
| } | ||
JcMinarro marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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
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
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.