From e64c7db3a32d5e5ebbf4eefbe03bc5b9a7ff52f0 Mon Sep 17 00:00:00 2001 From: Conner Dunn Date: Thu, 2 Apr 2026 17:22:40 -0700 Subject: [PATCH] fix: treat slash commands as warning --- integration_test.go | 23 ++++++++++++++++ pkg/codingcontext/context.go | 13 ++++++--- pkg/codingcontext/context_test.go | 44 ++++++++++++++++++++++--------- 3 files changed, 64 insertions(+), 16 deletions(-) diff --git a/integration_test.go b/integration_test.go index 8773cbea..ee6e4b19 100644 --- a/integration_test.go +++ b/integration_test.go @@ -2006,3 +2006,26 @@ task_name: whitespace-task }) } } + +// TestNonExistentSlashCommandPassesThrough verifies that a task referencing a +// slash command that does not exist passes through the text as-is instead of erroring. +func TestNonExistentSlashCommandPassesThrough(t *testing.T) { + t.Parallel() + dirs := setupTestDirs(t) + + // Create a task that references a non-existent slash command + taskContent := `# My Task with a File Path + + /home/coder/.config should be ignored + ` + taskFile := filepath.Join(dirs.tasksDir, "bad-command-task.md") + if err := os.WriteFile(taskFile, []byte(taskContent), 0o600); err != nil { + t.Fatalf("failed to write task file: %v", err) + } + + output := runTool(t, "-C", dirs.tmpDir, "bad-command-task") + + if !strings.Contains(output, "/home/coder/.config should be ignored") { + t.Errorf("expected non-existent slash command to pass through as-is, got: %s", output) + } +} diff --git a/pkg/codingcontext/context.go b/pkg/codingcontext/context.go index 7895406c..211a3434 100644 --- a/pkg/codingcontext/context.go +++ b/pkg/codingcontext/context.go @@ -465,11 +465,16 @@ func (cc *Context) processTaskBlock(block taskparser.Block, path string, expandP if block.SlashCommand != nil { commandContent, err := cc.findCommand(block.SlashCommand.Name, block.SlashCommand.Params()) if err != nil { - if cc.lintMode && errors.Is(err, ErrCommandNotFound) { - cc.lintCollector.recordError(path, LintErrorKindMissingCommand, - "command not found: "+block.SlashCommand.Name) + if errors.Is(err, ErrCommandNotFound) { + if cc.lintMode { + cc.lintCollector.recordError(path, LintErrorKindMissingCommand, + "command not found: "+block.SlashCommand.Name) + } else { + cc.logger.Warn("Command not found, passing through as-is", + "command", block.SlashCommand.Name) + } - return "/" + block.SlashCommand.Name, nil + return block.SlashCommand.String(), nil } return "", fmt.Errorf("failed to find command %s: %w", block.SlashCommand.Name, err) diff --git a/pkg/codingcontext/context_test.go b/pkg/codingcontext/context_test.go index 9ad5b020..5c294581 100644 --- a/pkg/codingcontext/context_test.go +++ b/pkg/codingcontext/context_test.go @@ -957,14 +957,19 @@ func TestContext_Run_Commands(t *testing.T) { check: checkTaskNotEmpty, }, { - name: "command not found returns error", + name: "command not found passes through as-is", setup: func(t *testing.T, dir string) { t.Helper() createTask(t, dir, "missing-cmd", "", "/nonexistent") }, - taskName: "missing-cmd", - wantErr: true, - errContains: "command not found", + taskName: "missing-cmd", + wantErr: false, + check: func(t *testing.T, result *Result) { + t.Helper() + if !strings.Contains(result.Prompt, "/nonexistent") { + t.Errorf("expected pass-through of /nonexistent, got %q", result.Prompt) + } + }, }, { name: "command parameter overrides context parameter", @@ -1249,16 +1254,22 @@ func TestContext_Run_Errors(t *testing.T) { taskName string wantErr bool errContains string + check func(t *testing.T, result *Result) }{ { - name: "command not found in task", + name: "command not found in task passes through as-is", setup: func(t *testing.T, dir string) { t.Helper() createTask(t, dir, "bad-cmd", "", "/missing-command\n") }, - taskName: "bad-cmd", - wantErr: true, - errContains: "command not found", + taskName: "bad-cmd", + wantErr: false, + check: func(t *testing.T, result *Result) { + t.Helper() + if !strings.Contains(result.Prompt, "/missing-command") { + t.Errorf("expected pass-through of /missing-command, got %q", result.Prompt) + } + }, }, { name: "invalid agent in task frontmatter", @@ -1298,6 +1309,10 @@ func TestContext_Run_Errors(t *testing.T) { t.Errorf("expected error to contain %q, got %v", tt.errContains, err) } } + + if !tt.wantErr && tt.check != nil { + tt.check(t, result) + } }) } } @@ -1839,7 +1854,7 @@ func TestUserPrompt(t *testing.T) { check: checkTaskContains("${issue_number}"), // expand:false applies to user_prompt too }, { - name: "user_prompt with invalid slash command", + name: "user_prompt with invalid slash command passes through as-is", setup: func(t *testing.T, dir string) { t.Helper() createTask(t, dir, "invalid", "", "Task content\n") @@ -1847,9 +1862,14 @@ func TestUserPrompt(t *testing.T) { opts: []Option{ WithUserPrompt("/nonexistent-command\n"), }, - taskName: "invalid", - wantErr: true, - errContains: "command not found", + taskName: "invalid", + wantErr: false, + check: func(t *testing.T, result *Result) { + t.Helper() + if !strings.Contains(result.Prompt, "/nonexistent-command") { + t.Errorf("expected pass-through of /nonexistent-command, got %q", result.Prompt) + } + }, }, { name: "both task prompt and user prompt parse correctly",