diff --git a/packages/opencode/src/command/index.ts b/packages/opencode/src/command/index.ts index 057754cd9ef8..d2764c71c3bc 100644 --- a/packages/opencode/src/command/index.ts +++ b/packages/opencode/src/command/index.ts @@ -9,6 +9,7 @@ import { MCP } from "../mcp" import { Skill } from "../skill" import PROMPT_INITIALIZE from "./template/initialize.txt" import PROMPT_REVIEW from "./template/review.txt" +import PROMPT_BUG from "./template/bug.txt" import { LegacyEvent } from "@opencode-ai/schema/legacy-event" type State = { @@ -46,6 +47,7 @@ export function hints(template: string) { export const Default = { INIT: "init", REVIEW: "review", + BUG: "bug", } as const export interface Interface { @@ -86,6 +88,15 @@ const layer = Layer.effect( subtask: true, hints: hints(PROMPT_REVIEW), } + commands[Default.BUG] = { + name: Default.BUG, + description: "file a bug report [description], asks if omitted", + source: "command", + get template() { + return PROMPT_BUG + }, + hints: hints(PROMPT_BUG), + } for (const [name, command] of Object.entries(cfg.command ?? {})) { commands[name] = { diff --git a/packages/opencode/src/command/template/bug.txt b/packages/opencode/src/command/template/bug.txt new file mode 100644 index 000000000000..adc8139b48d1 --- /dev/null +++ b/packages/opencode/src/command/template/bug.txt @@ -0,0 +1,39 @@ +File a bug report for bolt (this CLI) based on what happened in this session. + +User-provided description (may be empty): +$ARGUMENTS + +## Step 1: Understand the bug + +If the description above is empty, ask the user one short question: what went wrong and what did they expect instead. Do not ask anything else. + +If the description is present, do not ask questions; work from it plus the session context. + +## Step 2: Collect environment context + +Gather these facts with quick commands, tolerating failures: +- bolt version: run `bolt --version` (fall back to the version in the running process if the binary is not on PATH) +- OS and architecture: run `uname -sm` (or read process.platform/arch on Windows) +- The model and agent in use for this session, if visible in context +- The last error output relevant to the bug, if any appeared in this session + +Never include API keys, tokens, environment variable values, file contents unrelated to the bug, or private conversation content. Quote only the minimal error text needed to reproduce. + +## Step 3: Draft the report + +Compose a markdown report with exactly these sections: +- **Description**: one or two sentences, from the user's words +- **Steps to reproduce**: numbered, minimal, from what actually happened +- **Expected behavior** +- **Actual behavior**: include the minimal error output in a fenced block if there is one +- **Environment**: bolt version, OS/arch, model + +Show the drafted report to the user and ask for confirmation before submitting. If they ask for edits, apply them and confirm again. + +## Step 4: Submit + +After confirmation, file the report: +1. Preferred: `gh issue create --repo bolt-builder/bolt-cli --title "" --body ""` and print the returned issue URL. +2. If `gh` is missing or unauthenticated: print a prefilled new-issue link `https://github.com/bolt-builder/bolt-cli/issues/new?title=&body=` plus the raw markdown so the user can paste it manually. + +End by telling the user exactly where the report went. diff --git a/packages/opencode/test/command/bug.test.ts b/packages/opencode/test/command/bug.test.ts new file mode 100644 index 000000000000..ac5c73a8fda0 --- /dev/null +++ b/packages/opencode/test/command/bug.test.ts @@ -0,0 +1,21 @@ +import { describe, expect, test } from "bun:test" +import PROMPT_BUG from "@/command/template/bug.txt" +import { Command } from "@/command" + +describe("bug command", () => { + test("is a registered default", () => { + expect(Command.Default.BUG).toBe("bug") + }) + + test("template takes the description as $ARGUMENTS", () => { + expect(Command.hints(PROMPT_BUG)).toEqual(["$ARGUMENTS"]) + }) + + test("template carries the report contract", () => { + for (const section of ["Description", "Steps to reproduce", "Expected behavior", "Actual behavior", "Environment"]) + expect(PROMPT_BUG).toContain(section) + expect(PROMPT_BUG).toContain("gh issue create --repo bolt-builder/bolt-cli") + expect(PROMPT_BUG).toContain("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/bolt-builder/bolt-cli/issues/new") + expect(PROMPT_BUG).toContain("Never include API keys") + }) +})