fix(auto-slash-command): resolve project commands from session dir
Use the plugin session directory instead of process.cwd() when resolving project slash commands. This restores project and opencode-project slashcommand behavior when the runtime cwd differs from the actual session workspace. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -42,11 +42,12 @@ export interface ExecutorOptions {
|
||||
pluginsEnabled?: boolean
|
||||
enabledPluginsOverride?: Record<string, boolean>
|
||||
agent?: string
|
||||
directory?: string
|
||||
}
|
||||
|
||||
|
||||
async function discoverAllCommands(options?: ExecutorOptions): Promise<CommandInfo[]> {
|
||||
const discoveredCommands = discoverCommandsSync(process.cwd(), {
|
||||
const discoveredCommands = discoverCommandsSync(options?.directory ?? process.cwd(), {
|
||||
pluginsEnabled: options?.pluginsEnabled,
|
||||
enabledPluginsOverride: options?.enabledPluginsOverride,
|
||||
})
|
||||
|
||||
@@ -68,6 +68,7 @@ export interface AutoSlashCommandHookOptions {
|
||||
skills?: LoadedSkill[]
|
||||
pluginsEnabled?: boolean
|
||||
enabledPluginsOverride?: Record<string, boolean>
|
||||
directory?: string
|
||||
}
|
||||
|
||||
export function createAutoSlashCommandHook(options?: AutoSlashCommandHookOptions) {
|
||||
@@ -75,6 +76,7 @@ export function createAutoSlashCommandHook(options?: AutoSlashCommandHookOptions
|
||||
skills: options?.skills,
|
||||
pluginsEnabled: options?.pluginsEnabled,
|
||||
enabledPluginsOverride: options?.enabledPluginsOverride,
|
||||
directory: options?.directory,
|
||||
}
|
||||
const sessionProcessedCommands = createProcessedCommandStore()
|
||||
const sessionProcessedCommandExecutions = createProcessedCommandStore()
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { describe, expect, it, beforeEach, mock, spyOn } from "bun:test"
|
||||
import { describe, expect, it, beforeEach, afterEach, spyOn } from "bun:test"
|
||||
import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs"
|
||||
import { tmpdir } from "node:os"
|
||||
import { join } from "node:path"
|
||||
import type { LoadedSkill } from "../../features/opencode-skill-loader/types"
|
||||
import type {
|
||||
AutoSlashCommandHookInput,
|
||||
@@ -39,11 +42,45 @@ function createMockOutput(text: string): AutoSlashCommandHookOutput {
|
||||
}
|
||||
|
||||
describe("createAutoSlashCommandHook", () => {
|
||||
let tempDir = ""
|
||||
let originalWorkingDirectory = ""
|
||||
|
||||
beforeEach(() => {
|
||||
logMock.mockClear()
|
||||
tempDir = mkdtempSync(join(tmpdir(), "omo-auto-slash-hook-test-"))
|
||||
originalWorkingDirectory = process.cwd()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
process.chdir(originalWorkingDirectory)
|
||||
rmSync(tempDir, { recursive: true, force: true })
|
||||
})
|
||||
|
||||
describe("slash command replacement", () => {
|
||||
it("should resolve project commands from provided directory even when cwd differs", async () => {
|
||||
// given
|
||||
const projectDir = join(tempDir, "project")
|
||||
const commandDir = join(projectDir, ".claude", "commands")
|
||||
mkdirSync(commandDir, { recursive: true })
|
||||
writeFileSync(
|
||||
join(commandDir, "project-only-command.md"),
|
||||
`---\ndescription: Project command\n---\nExecute from project directory.\n`,
|
||||
)
|
||||
process.chdir("/tmp")
|
||||
|
||||
const hook = createAutoSlashCommandHook({ directory: projectDir })
|
||||
const input = createMockInput(`test-session-project-${Date.now()}`)
|
||||
const output = createMockOutput("/project-only-command")
|
||||
|
||||
// when
|
||||
await hook["chat.message"](input, output)
|
||||
|
||||
// then
|
||||
expect(output.parts[0].text).toContain("<auto-slash-command>")
|
||||
expect(output.parts[0].text).toContain("Execute from project directory.")
|
||||
expect(output.parts[0].text).toContain("**Scope**: project")
|
||||
})
|
||||
|
||||
it("should not modify message when command not found", async () => {
|
||||
// given a slash command that doesn't exist
|
||||
const hook = createAutoSlashCommandHook()
|
||||
|
||||
@@ -42,6 +42,7 @@ export function createSkillHooks(args: {
|
||||
skills: mergedSkills,
|
||||
pluginsEnabled: pluginConfig.claude_code?.plugins ?? true,
|
||||
enabledPluginsOverride: pluginConfig.claude_code?.plugins_override,
|
||||
directory: ctx.directory,
|
||||
}))
|
||||
: null
|
||||
|
||||
|
||||
@@ -60,4 +60,32 @@ describe("slashcommand discovery and execution compatibility", () => {
|
||||
expect(result.replacementText).toContain("Execute from parent config.")
|
||||
expect(result.replacementText).toContain("**Scope**: opencode")
|
||||
})
|
||||
|
||||
it("executes project commands using the provided directory even when cwd differs", async () => {
|
||||
// given
|
||||
const projectDir = join(tempDir, "project")
|
||||
const commandDir = join(projectDir, ".claude", "commands")
|
||||
const commandName = "project-only-command"
|
||||
|
||||
mkdirSync(commandDir, { recursive: true })
|
||||
writeFileSync(
|
||||
join(commandDir, `${commandName}.md`),
|
||||
`---\ndescription: Project command\n---\nExecute from project directory.\n`,
|
||||
)
|
||||
process.chdir("/tmp")
|
||||
|
||||
expect(discoverCommandsSync(projectDir).some(command => command.name === commandName)).toBe(true)
|
||||
|
||||
// when
|
||||
const result = await executeSlashCommand({
|
||||
command: commandName,
|
||||
args: "",
|
||||
raw: `/${commandName}`,
|
||||
}, { skills: [], directory: projectDir })
|
||||
|
||||
// then
|
||||
expect(result.success).toBe(true)
|
||||
expect(result.replacementText).toContain("Execute from project directory.")
|
||||
expect(result.replacementText).toContain("**Scope**: project")
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user