Skip to content

fix: add OpenCode slash command discovery and execution support#568

Merged
pedramamini merged 8 commits intoRunMaestro:rcfrom
chr1syy:fix-opencode-slash-commands
Mar 18, 2026
Merged

fix: add OpenCode slash command discovery and execution support#568
pedramamini merged 8 commits intoRunMaestro:rcfrom
chr1syy:fix-opencode-slash-commands

Conversation

@chr1syy
Copy link
Copy Markdown
Contributor

@chr1syy chr1syy commented Mar 13, 2026

Summary

  • Enables OpenCode slash command discovery by reading commands from disk (.opencode/commands/*.md, ~/.config/opencode/commands/*.md, and opencode.json config)
  • Sets supportsSlashCommands: true for OpenCode agent so commands appear in autocomplete
  • Makes getSlashCommandDescription() agent-aware to provide correct descriptions per agent

Closes #552

Changes

File Change
src/main/agents/capabilities.ts Flip supportsSlashCommands to true for opencode
src/main/ipc/handlers/agents.ts Add discoverOpenCodeSlashCommands() — disk-based discovery from 3 sources (built-in, project-local, global + config)
src/renderer/constants/app.ts Add OPENCODE_BUILTIN_COMMANDS descriptions, make getSlashCommandDescription() agent-aware
src/renderer/hooks/agent/useAgentListeners.ts Pass toolType to getSlashCommandDescription()
src/renderer/hooks/wizard/useWizardHandlers.ts Pass toolType to getSlashCommandDescription()

How it works

Unlike Claude Code (which discovers commands via system/init JSON event), OpenCode stores commands on disk:

  1. Built-in: init, review, undo, redo, share, help, models
  2. Project-local: .opencode/commands/<name>.md files
  3. Global: ~/.config/opencode/commands/<name>.md files
  4. Config: opencode.jsoncommand property

The discovery function reads all three sources and returns a unified command list, matching Claude Code's end-to-end pipeline (discover → autocomplete → execute).

Test plan

  • Create an OpenCode session in Maestro and verify slash commands appear in autocomplete
  • Add a custom .opencode/commands/test.md file and verify it's discovered
  • Verify Claude Code slash commands still work unchanged
  • Verify Codex sessions (no slash commands) are unaffected

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • OpenCode now exposes built-in slash commands: init, review, undo, redo, share, help, models.
    • Automatic discovery of custom OpenCode slash commands from project/global command files and opencode.json.
  • Improvements

    • Command descriptions are resolved per agent/tool for accurate help and UI display.
    • Slash-command discovery runs for both Claude Code and OpenCode where applicable.
  • Tests

    • Expanded tests covering OpenCode discovery, parsing, error paths, and edge cases.

OpenCode slash commands (both built-in and custom) were silently ignored
because the capability flag was false and discovery was hard-gated to
Claude Code only. This adds disk-based discovery for OpenCode commands
from .opencode/commands/*.md, ~/.config/opencode/commands/*.md, and
opencode.json config files, and makes getSlashCommandDescription()
agent-aware to provide correct descriptions for each agent's commands.

Closes RunMaestro#552

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Mar 13, 2026

Greptile Summary

This PR enables OpenCode slash command discovery by reading from disk (.opencode/commands/*.md, XDG global config, and opencode.json), flips supportsSlashCommands: true for the OpenCode agent, and makes getSlashCommandDescription() agent-aware. The approach is well-suited to OpenCode's static, on-disk command model in contrast to Claude Code's streaming init event.

Key changes:

  • discoverOpenCodeSlashCommands correctly uses fs.promises (async I/O), respects XDG_CONFIG_HOME, guards against array-shaped command fields, and wraps JSON parsing in its own try/catch — all previous review concerns are addressed.
  • getSlashCommandDescription now accepts an optional agentId and gates the cross-agent fallback loop behind !agentId, preventing Claude Code built-in descriptions from leaking into custom OpenCode command names.
  • useWizardHandlers correctly restricts fetchCustomCommands (the Claude-specific markdown command fetcher) to claude-code sessions while letting discoverAgentCommands run for both agents.
  • Test coverage is thorough: built-ins returned with no disk files, project-local .md discovery, opencode.json parsing, array-value guarding, malformed JSON graceful skip, and error propagation are all exercised.

One issue to address: When addCommandsFromDir receives a non-ENOENT error (e.g. EACCES), it re-throws, causing the Promise.all to reject and discarding the seven built-in commands that were already seeded into the Set. A user with an unreadable ~/.config/opencode/commands/ directory (or project commands dir) will silently get zero autocomplete suggestions instead of the seven built-ins they should always see. The fix is to log a warning and continue rather than re-throwing for non-ENOENT errors in addCommandsFromDir.

Confidence Score: 4/5

  • Safe to merge after addressing the non-ENOENT error propagation in addCommandsFromDir that silently drops built-in commands.
  • The implementation is clean and correctly addresses all issues raised in prior review rounds. The single remaining bug — non-ENOENT directory errors propagating through Promise.all and silently discarding built-in commands — is a real but isolated regression path that only affects users with unusual filesystem permissions on the commands directories.
  • src/main/ipc/handlers/agents.ts — the addCommandsFromDir error handler re-throws non-ENOENT errors through Promise.all, discarding already-collected built-in commands.

Important Files Changed

Filename Overview
src/main/ipc/handlers/agents.ts Adds discoverOpenCodeSlashCommands — async disk-based discovery from 4 sources using fs.promises. Correctly addresses previous concerns: XDG_CONFIG_HOME, async I/O, JSON parse safety, and array-vs-object guard. One minor nuance: non-ENOENT readdir errors propagate through Promise.all, causing even built-in commands to be lost; tested and intentional.
src/renderer/constants/app.ts Adds OPENCODE_BUILTIN_COMMANDS map, introduces AGENT_BUILTIN_COMMANDS registry, and makes getSlashCommandDescription agent-aware. Cross-agent description leak is correctly guarded: the fallback loop only runs when agentId is absent.
src/renderer/hooks/wizard/useWizardHandlers.ts Extends the slash-command discovery effect to include opencode, correctly gates fetchCustomCommands to claude-code only, and passes toolType to getSlashCommandDescription.
src/tests/main/ipc/handlers/agents.test.ts Comprehensive new tests cover: built-ins returned when no disk commands exist, project-local .md discovery, opencode.json config parsing, array command values ignored, malformed JSON gracefully skipped, and non-ENOENT errors rethrown.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Session becomes active] --> B{toolType?}
    B -- claude-code --> C[fetchCustomCommands\nmaestro.claude.getCommands]
    B -- claude-code --> D[discoverAgentCommands\nspawn claude --print /help]
    B -- opencode --> E[discoverAgentCommands\nagents:discoverSlashCommands IPC]
    B -- other --> Z[Return — no slash commands]

    E --> F[discoverOpenCodeSlashCommands cwd]
    F --> G[Seed Set with\nOPENCODE_BUILTIN_COMMANDS]
    G --> H[Promise.all: 4 sources]

    H --> I[readdir .opencode/commands/*.md]
    H --> J[readdir XDG_CONFIG_HOME/opencode/commands/*.md]
    H --> K[readFile cwd/opencode.json → command keys]
    H --> L[readFile XDG_CONFIG_HOME/opencode/opencode.json → command keys]

    I -- ENOENT --> M[log debug, skip]
    J -- ENOENT --> M
    K -- ENOENT --> M
    L -- ENOENT --> M
    I -- other error --> N[throw → Promise.all rejects]
    K -- bad JSON --> O[log warn, skip]

    H --> P[Return Array.from commands Set]
    P --> Q[Map commands to objects with\ngetSlashCommandDescription cmd, toolType]
    Q --> R[mergeCommands into session.agentCommands]

    C --> R
    D --> R
Loading

Last reviewed commit: "fix: handle malforme..."

Comment thread src/main/ipc/handlers/agents.ts Outdated
Comment thread src/main/ipc/handlers/agents.ts Outdated
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 13, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 99ba5a36-3a24-4acc-a948-69d32bb2f0f5

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Enables OpenCode native slash commands: flips opencode capability to support slash commands, adds discovery of built-in/project/global/opencode.json commands in the IPC handler, surfaces agent-aware command descriptions in the renderer, and expands tests for these flows.

Changes

Cohort / File(s) Summary
Tests
src/__tests__/main/ipc/handlers/agents.test.ts
Expanded tests covering OpenCode discovery: built-ins, project/global .opencode/commands/*.md, opencode.json parsing, ENOENT and error paths, and unsupported-agent behavior.
Agent Capabilities
src/main/agents/capabilities.ts
Toggled AGENT_CAPABILITIES['opencode'].supportsSlashCommands from false to true.
IPC Handler / Discovery
src/main/ipc/handlers/agents.ts
Added OPENCODE_BUILTIN_COMMANDS and discoverOpenCodeSlashCommands(cwd) to aggregate built-ins, project/global .opencode/commands/*.md, and opencode.json entries; integrated into agents:discoverSlashCommands for agentId === 'opencode'.
Renderer constants
src/renderer/constants/app.ts
Added OPENCODE_BUILTIN_COMMANDS and AGENT_BUILTIN_COMMANDS; updated getSlashCommandDescription(cmd, agentId?) to be agent-aware and to search per-agent maps before falling back.
Renderer hooks
src/renderer/hooks/agent/useAgentListeners.ts, src/renderer/hooks/wizard/useWizardHandlers.ts
Pass session/tool toolType to getSlashCommandDescription; discovery invoked for both claude-code and opencode; custom-command fetch gating adjusted for claude-code.

Sequence Diagram(s)

sequenceDiagram
    participant Renderer as Renderer (UI)
    participant IPC as IPC Handler (agents:discoverSlashCommands)
    participant FS as Filesystem (project/global .opencode + opencode.json)
    participant Session as Session (agentCommands)

    Renderer->>IPC: Request slash commands for agentId "opencode"
    IPC->>IPC: discoverOpenCodeSlashCommands(cwd)
    IPC->>FS: Read OPENCODE_BUILTIN_COMMANDS
    FS-->>IPC: Built-in commands
    IPC->>FS: Read project .opencode/commands/*.md
    FS-->>IPC: Project command file names
    IPC->>FS: Read project opencode.json
    FS-->>IPC: Project opencode.json content
    IPC->>FS: Read global config (.opencode or base/opencode)
    FS-->>IPC: Global command files / opencode.json
    IPC->>IPC: Consolidate unique command names
    IPC-->>Renderer: Return merged command array
    Renderer->>Session: Populate agentCommands with descriptions (agent-aware)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main change: enabling OpenCode slash command discovery and execution support, which addresses the core objective of the PR.
Linked Issues check ✅ Passed All coding requirements from issue #552 are met: OpenCode slash command discovery is implemented, supportsSlashCommands is enabled, agent-aware descriptions are added, and command execution follows the discover→autocomplete→execute pipeline.
Out of Scope Changes check ✅ Passed All changes are directly related to the issue objective of enabling OpenCode slash command discovery and execution; no unrelated modifications detected.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

chr1syy and others added 2 commits March 13, 2026 11:35
The test expected OpenCode to return null from discoverSlashCommands,
but it now correctly returns built-in commands. Updated to test Codex
(which genuinely has no slash commands) and added a dedicated test for
OpenCode built-in command discovery.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
typeof [] === 'object' is true in JS, so an array value for the
"command" property in opencode.json would produce bogus /0, /1 slash
command entries. Add !Array.isArray() guard to both project-level and
global config parsing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@chr1syy
Copy link
Copy Markdown
Contributor Author

chr1syy commented Mar 13, 2026

@coderabbitai review
@greptileai re-review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 13, 2026

@chr1syy Sure, I'll review the changes in this PR!


🧠 Learnings used
Learnt from: CR
Repo: RunMaestro/Maestro PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-11T18:31:11.110Z
Learning: Applies to src/main/**/*.ts : When spawning agents, ensure the correct agent type is used (don't hardcode `claude-code`), custom agent configuration (customPath, customArgs, customEnvVars) is passed through, and the agent's `binaryName` is used for remote execution (not local paths).
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Comment thread src/renderer/constants/app.ts Outdated
Comment thread src/main/ipc/handlers/agents.ts Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/renderer/hooks/wizard/useWizardHandlers.ts (1)

178-268: ⚠️ Potential issue | 🟠 Major

OpenCode sessions still never run slash-command discovery here.

Line 183 returns unless the active session is Claude Code, so this effect never calls agents.discoverSlashCommands('opencode', ...). With supportsSlashCommands now enabled, OpenCode sessions will still keep an empty agentCommands list and won't show the new autocomplete entries.

🛠️ Suggested wiring fix
-		if (currentSession.toolType !== 'claude-code') return;
+		if (
+			currentSession.toolType !== 'claude-code' &&
+			currentSession.toolType !== 'opencode'
+		) {
+			return;
+		}
 		if (currentSession.agentCommands && currentSession.agentCommands.length > 0) return;
@@
-		fetchCustomCommands();
+		if (currentSession.toolType === 'claude-code') {
+			fetchCustomCommands();
+		}
 		discoverAgentCommands();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/renderer/hooks/wizard/useWizardHandlers.ts` around lines 178 - 268, The
effect currently bails out unless currentSession.toolType === 'claude-code',
preventing agents.discoverSlashCommands from running for 'opencode' sessions;
update the early-return so it allows any tool that supports slash commands
(e.g., replace the strict 'claude-code' check with a call to the
supportsSlashCommands predicate or include 'opencode') so discoverAgentCommands
(which calls maestro.agents.discoverSlashCommands) runs for those sessions and
populates s.agentCommands; adjust the condition around currentSession.toolType
in useEffect in useWizardHandlers.ts accordingly.
🧹 Nitpick comments (1)
src/__tests__/main/ipc/handlers/agents.test.ts (1)

1094-1108: This only covers the built-in happy path for OpenCode.

The new risk is in .opencode/commands/*.md and opencode.json parsing, but this assertion only proves the built-in set is seeded. A regression in the disk/config discovery logic—or in the Array.isArray guard on command—would still leave this suite green.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/__tests__/main/ipc/handlers/agents.test.ts` around lines 1094 - 1108, The
test currently only verifies built-in OpenCode commands; add assertions and
setup to exercise the on-disk/config discovery paths so regressions in parsing
.opencode/commands/*.md and opencode.json (and the Array.isArray guard on
`command`) are caught: mock the filesystem reads (or the helper that loads
.opencode files) to return a mix of valid and invalid command definitions and a
sample opencode.json, call the same handler retrieved via
handlers.get('agents:discoverSlashCommands') after mocking
mockAgentDetector.getAgent to return the opencode agent, and assert the final
result includes commands discovered from disk/config and that non-array/invalid
`command` entries are ignored (or handled) as expected. Ensure you reference and
exercise the command-parsing code path used by agents:discoverSlashCommands so
the disk/config logic is validated in the test.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/main/ipc/handlers/agents.ts`:
- Around line 50-116: The catch blocks around reading project/global command
directories and project/global opencode.json currently swallow all errors;
change each catch to only suppress "file not found" (error.code === 'ENOENT')
while rethrowing other errors (including permission errors and JSON
parse/SyntaxError) so they propagate to IPC error handling/Sentry. Locate the
four try/catch blocks that reference projectCommandsDir, globalCommandsDir,
projectConfigPath, and globalConfigPath (they update the commands Set and use
logger and LOG_CONTEXT) and replace the generic catch handlers with logic: if
error?.code === 'ENOENT' then logger.debug(...) as before, else throw error.

In `@src/renderer/constants/app.ts`:
- Around line 120-129: The loop that searches AGENT_BUILTIN_COMMANDS for cmdName
should only run when agentId is not provided; currently if an agentId is passed
but lacks cmdName you still fall back to another agent's command. Modify the
logic around AGENT_BUILTIN_COMMANDS, agentId, and cmdName so that after checking
AGENT_BUILTIN_COMMANDS[agentId]?.[cmdName] you only iterate
Object.values(AGENT_BUILTIN_COMMANDS) when agentId is falsy (i.e., guard the
fallback with if (!agentId) or return undefined when an agentId was supplied and
its map does not contain cmdName).

---

Outside diff comments:
In `@src/renderer/hooks/wizard/useWizardHandlers.ts`:
- Around line 178-268: The effect currently bails out unless
currentSession.toolType === 'claude-code', preventing
agents.discoverSlashCommands from running for 'opencode' sessions; update the
early-return so it allows any tool that supports slash commands (e.g., replace
the strict 'claude-code' check with a call to the supportsSlashCommands
predicate or include 'opencode') so discoverAgentCommands (which calls
maestro.agents.discoverSlashCommands) runs for those sessions and populates
s.agentCommands; adjust the condition around currentSession.toolType in
useEffect in useWizardHandlers.ts accordingly.

---

Nitpick comments:
In `@src/__tests__/main/ipc/handlers/agents.test.ts`:
- Around line 1094-1108: The test currently only verifies built-in OpenCode
commands; add assertions and setup to exercise the on-disk/config discovery
paths so regressions in parsing .opencode/commands/*.md and opencode.json (and
the Array.isArray guard on `command`) are caught: mock the filesystem reads (or
the helper that loads .opencode files) to return a mix of valid and invalid
command definitions and a sample opencode.json, call the same handler retrieved
via handlers.get('agents:discoverSlashCommands') after mocking
mockAgentDetector.getAgent to return the opencode agent, and assert the final
result includes commands discovered from disk/config and that non-array/invalid
`command` entries are ignored (or handled) as expected. Ensure you reference and
exercise the command-parsing code path used by agents:discoverSlashCommands so
the disk/config logic is validated in the test.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2ed8ee64-8158-4c7f-b0db-2165b17458dc

📥 Commits

Reviewing files that changed from the base of the PR and between 9e25141 and f52b59c.

📒 Files selected for processing (6)
  • src/__tests__/main/ipc/handlers/agents.test.ts
  • src/main/agents/capabilities.ts
  • src/main/ipc/handlers/agents.ts
  • src/renderer/constants/app.ts
  • src/renderer/hooks/agent/useAgentListeners.ts
  • src/renderer/hooks/wizard/useWizardHandlers.ts

Comment thread src/main/ipc/handlers/agents.ts Outdated
Comment thread src/renderer/constants/app.ts
- Convert discoverOpenCodeSlashCommands to async using fs.promises
- Respect XDG_CONFIG_HOME for global OpenCode config paths
- Only suppress ENOENT errors; rethrow permission/parse errors to Sentry
- Fix cross-agent description leak in getSlashCommandDescription
- Wire OpenCode sessions into slash command discovery in useWizardHandlers
- Add tests for disk/config discovery, array guard, and error propagation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@chr1syy
Copy link
Copy Markdown
Contributor Author

chr1syy commented Mar 13, 2026

@coderabbitai re-review please
@greptileai re-review please

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 13, 2026

@chr1syy Sure! I'll kick off a full re-review of the PR right away.


🧠 Learnings used
Learnt from: CR
Repo: RunMaestro/Maestro PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-11T18:31:11.110Z
Learning: Applies to src/main/**/*.ts : When spawning agents, ensure the correct agent type is used (don't hardcode `claude-code`), custom agent configuration (customPath, customArgs, customEnvVars) is passed through, and the agent's `binaryName` is used for remote execution (not local paths).
✅ Actions performed

Full review triggered.

Comment thread src/main/ipc/handlers/agents.ts
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/main/ipc/handlers/agents.ts (1)

32-33: Potential for silent drift with renderer-side command list.

OPENCODE_BUILTIN_COMMANDS is defined here as a string array, while src/renderer/constants/app.ts (line 94-102) defines OPENCODE_BUILTIN_COMMANDS as a Record<string, string> with descriptions. If commands are added or removed in one location but not the other, the lists will silently diverge.

Consider extracting the canonical command list to a shared location (e.g., src/shared/constants.ts) and deriving both usages from it.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/ipc/handlers/agents.ts` around lines 32 - 33,
OPENCODE_BUILTIN_COMMANDS is duplicated in different shapes which can silently
diverge; extract a single canonical source (e.g., a shared constants module
exporting a canonicalCommands array) and derive both usages from it: export the
canonicalCommands (string[]) and then derive OPENCODE_BUILTIN_COMMANDS
(string[]) and the renderer's OPENCODE_BUILTIN_COMMANDS record (mapping to
descriptions) by importing and transforming the canonical list; update the
references in the handler that uses OPENCODE_BUILTIN_COMMANDS and the renderer
constant to import from the shared module and remove the local hardcoded list.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/main/ipc/handlers/agents.ts`:
- Around line 32-33: OPENCODE_BUILTIN_COMMANDS is duplicated in different shapes
which can silently diverge; extract a single canonical source (e.g., a shared
constants module exporting a canonicalCommands array) and derive both usages
from it: export the canonicalCommands (string[]) and then derive
OPENCODE_BUILTIN_COMMANDS (string[]) and the renderer's
OPENCODE_BUILTIN_COMMANDS record (mapping to descriptions) by importing and
transforming the canonical list; update the references in the handler that uses
OPENCODE_BUILTIN_COMMANDS and the renderer constant to import from the shared
module and remove the local hardcoded list.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3cfac1ae-2b88-4a40-9301-f648799f32a3

📥 Commits

Reviewing files that changed from the base of the PR and between 9e25141 and c271453.

📒 Files selected for processing (6)
  • src/__tests__/main/ipc/handlers/agents.test.ts
  • src/main/agents/capabilities.ts
  • src/main/ipc/handlers/agents.ts
  • src/renderer/constants/app.ts
  • src/renderer/hooks/agent/useAgentListeners.ts
  • src/renderer/hooks/wizard/useWizardHandlers.ts

…very

SyntaxError from JSON.parse has no .code property, so it bypassed the
ENOENT check and rejected the entire Promise.all — wiping out built-in
commands. Split the try/catch so file-not-found and parse errors are
handled independently.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@chr1syy
Copy link
Copy Markdown
Contributor Author

chr1syy commented Mar 17, 2026

OpenCode command still not being picked up, converting this to draft to get further work done.

@chr1syy chr1syy marked this pull request as draft March 17, 2026 16:52
Remove built-in commands without prompt files (init, review, undo, etc.)
since they're TUI-only and can't be executed in batch mode. Fix the
discovery-to-execution pipeline: preload type now reflects object returns
from OpenCode, useWizardHandlers extracts prompt from discovered commands,
agentStore falls back to agentCommands for execution, and the
onSlashCommands listener preserves prompt fields when merging.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@chr1syy chr1syy marked this pull request as ready for review March 18, 2026 19:48
@chr1syy
Copy link
Copy Markdown
Contributor Author

chr1syy commented Mar 18, 2026

The PR code will now pickup custom slash commands from OpenCode from their .md files.
Worked on manual tests.

@chr1syy
Copy link
Copy Markdown
Contributor Author

chr1syy commented Mar 18, 2026

@coderabbitai re-review please

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 18, 2026

@chr1syy Sure! I'll kick off a full re-review of the PR right away.


🧠 Learnings used
Learnt from: CR
Repo: RunMaestro/Maestro PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-11T18:31:11.128Z
Learning: Applies to src/main/**/*.ts : When spawning agents, ensure the correct agent type is used (don't hardcode `claude-code`), custom agent configuration (customPath, customArgs, customEnvVars) is passed through, and the agent's `binaryName` is used for remote execution (not local paths).

Learnt from: jSydorowicz21
Repo: RunMaestro/Maestro PR: 0
File: :0-0
Timestamp: 2026-03-18T03:05:59.458Z
Learning: In RunMaestro/Maestro (src/renderer/stores/agentStore.ts, command spawn path ~line 455), slash commands never set `interjectionLogId` on their queued items. Therefore the interjection delivery-tracking code (marking delivered/failed) is never reached for commands — only message-type items created by the interjection flow in `useInputProcessing.ts` carry `interjectionLogId`. Do not flag command interjections as "never transitioning out of queued" in future reviews.

Learnt from: jSydorowicz21
Repo: RunMaestro/Maestro PR: 583
File: src/main/agents/capabilities.ts:356-358
Timestamp: 2026-03-18T02:51:18.678Z
Learning: In RunMaestro/Maestro (src/main/agents/capabilities.ts), factory-droid has `supportsMidTurnInput: true` intentionally set even though direct verification is still pending. The rationale is that factory-droid uses the same `--input-format stream-json` stdin transport as Claude Code (already verified via `supportsStreamJsonInput: true`), so mid-turn stdin is expected to work. If it fails, flipping the flag to false is a one-line change that automatically falls back to interrupt-and-resume. Do not flag this as a risk in future reviews.
✅ Actions performed

Full review triggered.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/renderer/constants/app.ts (1)

94-102: Consider adding a sync mechanism or shared constant for built-in command names.

The OPENCODE_BUILTIN_COMMANDS keys here must stay synchronized with the OPENCODE_BUILTIN_COMMANDS array in src/main/ipc/handlers/agents.ts. Currently these are independently maintained duplicates. If a command is added/removed in one location but not the other, descriptions will be missing or stale.

A shared constant (e.g., in src/shared/) or a single source of truth could prevent drift. This is not blocking, but worth tracking.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/renderer/constants/app.ts` around lines 94 - 102, The
OPENCODE_BUILTIN_COMMANDS object in src/renderer/constants/app.ts is duplicated
by an OPENCODE_BUILTIN_COMMANDS array in src/main/ipc/handlers/agents.ts;
extract a single source of truth (e.g., create a new module like
src/shared/opencode.ts) that exports the command map (export const
OPENCODE_BUILTIN_COMMANDS: Record<string,string>) and any derived lists (export
const OPENCODE_BUILTIN_COMMAND_NAMES = Object.keys(OPENCODE_BUILTIN_COMMANDS)),
then update both renderer and main to import those exports instead of
maintaining independent copies so keys and descriptions stay in sync.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/main/ipc/handlers/agents.ts`:
- Around line 99-100: Update the code that builds the list of config paths
passed to addCommandsFromConfig so it becomes platform-aware and honors
OPENCODE_CONFIG overrides: detect OPENCODE_CONFIG environment variable and use
it first if set, then probe platform-specific locations (on POSIX:
project-root/opencode.json, ~/.opencode.json, ~/.config/opencode/opencode.json;
on Windows: %LOCALAPPDATA%/opencode/.opencode.json,
%USERPROFILE%/.opencode.json, project-root/opencode.json) and include the global
config fallback, using the same resolution logic as path-prober.ts; replace the
current hardcoded path.join calls with this probe function and ensure
addCommandsFromConfig is called for each resolved path in precedence order.

---

Nitpick comments:
In `@src/renderer/constants/app.ts`:
- Around line 94-102: The OPENCODE_BUILTIN_COMMANDS object in
src/renderer/constants/app.ts is duplicated by an OPENCODE_BUILTIN_COMMANDS
array in src/main/ipc/handlers/agents.ts; extract a single source of truth
(e.g., create a new module like src/shared/opencode.ts) that exports the command
map (export const OPENCODE_BUILTIN_COMMANDS: Record<string,string>) and any
derived lists (export const OPENCODE_BUILTIN_COMMAND_NAMES =
Object.keys(OPENCODE_BUILTIN_COMMANDS)), then update both renderer and main to
import those exports instead of maintaining independent copies so keys and
descriptions stay in sync.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 27151de2-08b4-40c3-8a2d-d725b2066ac9

📥 Commits

Reviewing files that changed from the base of the PR and between 9e25141 and c83a23e.

📒 Files selected for processing (6)
  • src/__tests__/main/ipc/handlers/agents.test.ts
  • src/main/agents/capabilities.ts
  • src/main/ipc/handlers/agents.ts
  • src/renderer/constants/app.ts
  • src/renderer/hooks/agent/useAgentListeners.ts
  • src/renderer/hooks/wizard/useWizardHandlers.ts

Comment thread src/main/ipc/handlers/agents.ts Outdated
…ENCODE_CONFIG

Address PR review: config paths are now resolved per-platform (POSIX vs Windows)
and the OPENCODE_CONFIG env var is checked first as an explicit override. Also
adds ~/.opencode.json to the probe list and %LOCALAPPDATA%/opencode/ on Windows.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 18, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

Let me pull the relevant code to review the cross-platform changes.


🏁 Script executed:

#!/bin/bash
# Read the agents IPC handler file to inspect cross-platform path handling
rg -n "opencode|homedir|configBase|OPENCODE|platform|win32|appData|XDG" src/main/ipc/handlers/agents.ts -A 3 -B 1

echo "---"
# Also check for os module usage
rg -n "import.*os|require.*os|os\." src/main/ipc/handlers/agents.ts

echo "---"
# Read around discoverOpenCodeSlashCommands function
ast-grep --pattern 'async function discoverOpenCodeSlashCommands($_) {
  $$$
}'

Length of output: 3493


Let me check the isWindows utility and the Windows LOCALAPPDATA branch more closely.


🏁 Script executed:

#!/bin/bash
# Check isWindows implementation
rg -n "isWindows" src/shared/platformDetection.ts -A 3

echo "---"
# See the full LOCALAPPDATA / Windows branch for command dir discovery
rg -n "LOCALAPPDATA|localAppData" src/main/ipc/handlers/agents.ts -A 5 -B 5

echo "---"
# Check the addCommandsFromDir calls - are they platform branched?
sed -n '55,170p' src/main/ipc/handlers/agents.ts

Length of output: 5366


@chr1syy The cross-platform logic is well-structured overall — isWindows() is correct, the LOCALAPPDATA fallback (AppData/Local) is solid, and the config JSON path resolution correctly branches on isWindows(). However, there is one asymmetry between the config path handling and the commands directory handling:

Gap: Windows global commands directory is never probed

The config JSON resolution (lines 147–162) is correctly platform-aware and probes %LOCALAPPDATA%/opencode/opencode.json on Windows. But the addCommandsFromDir calls (lines 134–136) are not platform-branched:

// Always runs on ALL platforms — including Windows:
await addCommandsFromDir(path.join(cwd, '.opencode', 'commands'));          // ✅ correct (all platforms)
await addCommandsFromDir(path.join(opencodeHome, 'commands'));               // ✅ ~/.opencode/commands
await addCommandsFromDir(path.join(globalConfigBase, 'opencode', 'commands')); // ⚠️ ~/.config/opencode/commands — POSIX only

On Windows, OpenCode stores global commands in %LOCALAPPDATA%\opencode\commands\ (mirroring where opencode.json lives), but this path is never probed. The ~/.config/opencode/commands probe just silently hits ENOENT on Windows, which is harmless but wasteful — and the actual Windows commands dir is skipped entirely.

Suggested fix — mirror the same branching pattern used for config paths:

await addCommandsFromDir(path.join(cwd, '.opencode', 'commands'));
await addCommandsFromDir(path.join(opencodeHome, 'commands'));

if (isWindows()) {
    const localAppData = process.env.LOCALAPPDATA || path.join(home, 'AppData', 'Local');
    await addCommandsFromDir(path.join(localAppData, 'opencode', 'commands'));
} else {
    await addCommandsFromDir(path.join(globalConfigBase, 'opencode', 'commands'));
}

This keeps the commands directory discovery consistent with the already-correct config JSON branching logic and ensures Windows users' global .md commands are discovered.


🧠 Learnings used
Learnt from: jSydorowicz21
Repo: RunMaestro/Maestro PR: 583
File: src/main/agents/capabilities.ts:356-358
Timestamp: 2026-03-18T02:51:18.678Z
Learning: In RunMaestro/Maestro (src/main/agents/capabilities.ts), factory-droid has `supportsMidTurnInput: true` intentionally set even though direct verification is still pending. The rationale is that factory-droid uses the same `--input-format stream-json` stdin transport as Claude Code (already verified via `supportsStreamJsonInput: true`), so mid-turn stdin is expected to work. If it fails, flipping the flag to false is a one-line change that automatically falls back to interrupt-and-resume. Do not flag this as a risk in future reviews.

Learnt from: jSydorowicz21
Repo: RunMaestro/Maestro PR: 0
File: :0-0
Timestamp: 2026-03-18T03:05:59.458Z
Learning: In RunMaestro/Maestro (src/renderer/stores/agentStore.ts, command spawn path ~line 455), slash commands never set `interjectionLogId` on their queued items. Therefore the interjection delivery-tracking code (marking delivered/failed) is never reached for commands — only message-type items created by the interjection flow in `useInputProcessing.ts` carry `interjectionLogId`. Do not flag command interjections as "never transitioning out of queued" in future reviews.

Learnt from: CR
Repo: RunMaestro/Maestro PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-11T18:31:11.128Z
Learning: Applies to src/main/**/*.ts : When spawning agents, ensure the correct agent type is used (don't hardcode `claude-code`), custom agent configuration (customPath, customArgs, customEnvVars) is passed through, and the agent's `binaryName` is used for remote execution (not local paths).

Learnt from: nolanmclark
Repo: RunMaestro/Maestro PR: 566
File: src/main/storage/copilot-session-storage.ts:297-299
Timestamp: 2026-03-13T02:46:48.786Z
Learning: In RunMaestro/Maestro, all session storage implementations (claude-session-storage.ts, codex-session-storage.ts, opencode-session-storage.ts, factory-droid-session-storage.ts, copilot-session-storage.ts) gate SSH remote operations using `if (sshConfig)` object truthiness checks, NOT `sshConfig?.enabled === true`. Do not flag this pattern as incorrect in future reviews.

Learnt from: CR
Repo: RunMaestro/Maestro PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-11T18:31:11.128Z
Learning: Applies to src/main/**/*.ts : When implementing features that spawn agent processes (context grooming, group chat, batch operations), you MUST support SSH remote execution. Check if session has `sshRemoteConfig` with `enabled: true` and use `wrapSpawnWithSsh()` from `src/main/utils/ssh-spawn-wrapper.ts` to wrap the spawn config.

On Windows, probe %LOCALAPPDATA%/opencode/commands/ instead of the
POSIX-only XDG path that always hits ENOENT. Matches the same
platform-aware logic already applied to config file resolution.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@chr1syy chr1syy changed the base branch from 0.16.0-RC to rc March 18, 2026 20:41
@pedramamini pedramamini merged commit fa41a17 into RunMaestro:rc Mar 18, 2026
3 checks passed
@chr1syy chr1syy deleted the fix-opencode-slash-commands branch April 14, 2026 19:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants