feat(coding-agent): removed recipe tool and all runner implementations

- Deleted RecipeTool, runner logic, and all task runner backends (just, make, cargo, pkg, task).
- Removed recipe from BUILTIN_TOOLS, auto-injection in createTools, and HTML export renderer.
- Deleted recipe tool prompt template and runner module exports.
This commit is contained in:
can1357
2026-05-31 01:41:01 +02:00
parent a1ba50b4da
commit dfa6007f36
21 changed files with 7 additions and 1303 deletions
-155
View File
@@ -1,155 +0,0 @@
# recipe
> Run a task exposed by a detected project task runner.
## Source
- Entry: `packages/coding-agent/src/tools/recipe/index.ts`
- Model-facing prompt: `packages/coding-agent/src/prompts/tools/recipe.md`
- Key collaborators:
- `packages/coding-agent/src/tools/recipe/runner.ts` — op parsing, task resolution, prompt model.
- `packages/coding-agent/src/tools/recipe/render.ts` — shell-style call/result rendering.
- `packages/coding-agent/src/tools/recipe/runners/index.ts` — runner registration order.
- `packages/coding-agent/src/tools/recipe/runners/just.ts` — detect `just` recipes from justfiles.
- `packages/coding-agent/src/tools/recipe/runners/pkg.ts` — detect `package.json` scripts and workspaces.
- `packages/coding-agent/src/tools/recipe/runners/cargo.ts` — detect Cargo run/test targets.
- `packages/coding-agent/src/tools/recipe/runners/make.ts` — parse make targets from makefiles.
- `packages/coding-agent/src/tools/recipe/runners/task.ts` — detect Taskfile tasks via `task --list-all`.
- `packages/coding-agent/src/tools/bash.ts` — actual command execution, truncation, cwd/env handling.
## Inputs
| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `op` | `string` | Yes | Single string containing the task selector plus trailing arguments. The first whitespace-delimited token selects the task; the remainder is appended verbatim to the resolved runner command. Examples from schema/prompt: `test`, `build --release`, `pkg-a/test`, `crate/bin/server`, `pkg:test --watch`. |
### `op` grammar
```text
op := S* head (S+ tail)?
head := explicit-runner / implicit-task
explicit-runner := runner-id ":" task-token
implicit-task := task-token
runner-id := detected runner id (`just` | `pkg` | `cargo` | `make` | `task`)
task-token := first non-whitespace token; may contain `/`
tail := remaining characters after the first whitespace run
```
Resolution rules from `resolveRunnerAndTask()`:
- Leading whitespace is ignored; an empty `op` throws `ToolError` with the available task list.
- Only the first token is parsed structurally. Everything after the first whitespace run becomes `tail` and is appended to the command unchanged.
- If `head` contains `:` and the prefix matches a detected runner id, the suffix must exactly match a task in that runner.
- Otherwise `head` is treated as a task name and matched across all detected runners.
- If exactly one runner has that task, it is used.
- If multiple runners have that task, the call is rejected and the error tells the model to use `<runner-id>:<task>`.
- Namespaced task names generated by runners use `/`, not `:`. `/` is part of the task name, not a parser separator.
## Outputs
- Delegates directly to `BashTool.execute()` and returns the same `AgentToolResult<BashToolDetails>` shape.
- Success path: one text content block containing merged command output (`result.output` from bash execution, or `(no output)`), plus any timeout clamp notice appended after a blank line.
- Recipe does not return separate `stdout`, `stderr`, or `exitCode` fields. `stdout`/`stderr` are already merged into the text block by bash execution; `exitCode` is only observed indirectly (success requires `0`, non-zero becomes an error).
- Error path: throws `ToolError`; for non-zero exits the message is the merged output followed by `Command exited with code <n>`.
- `details` may include:
- `timeoutSeconds`: effective timeout used by bash.
- `requestedTimeoutSeconds`: only when bash clamped a requested timeout; recipe never sets one itself.
- `meta`: output truncation metadata from bash execution.
- `async`: defined by bash background execution paths, but recipe does not expose an `async` input.
- When bash output is truncated, the full text is stored in an artifact and referenced via bash truncation metadata.
- Call/result rendering in the TUI uses bash shell rendering with a resolved title, command preview, and optional task cwd.
## Flow
1. `RecipeTool.createIf()` in `packages/coding-agent/src/tools/recipe/index.ts` checks `session.settings.get("recipe.enabled")`; disabled returns `null`.
2. It probes every runner in `RUNNERS` from `packages/coding-agent/src/tools/recipe/runners/index.ts` with `Promise.all(...)` in this order: `just`, `pkg`, `cargo`, `make`, `task`.
3. Each runner returns either `null` or a `DetectedRunner { id, label, commandPrefix, tasks }`; runners with zero tasks are discarded.
4. If no runners remain, the tool is not registered.
5. Constructor stores detected runners, instantiates `BashTool`, renders the model-facing description by passing `buildPromptModel(runners)` into `packages/coding-agent/src/prompts/tools/recipe.md`, and builds shell renderers from `createRecipeToolRenderer()`.
6. On execution, `RecipeTool.execute()` calls `resolveCommand(op, this.#runners)`.
7. `resolveCommand()` in `packages/coding-agent/src/tools/recipe/runner.ts`:
1. `parseOp()` trims only leading whitespace, extracts the first non-whitespace token as `head`, and keeps the remainder as `tail`.
2. `resolveRunnerAndTask()` resolves `head` either as `runnerId:taskName` or as an unqualified task name.
3. It throws `ToolError` for empty ops, missing explicit tasks, ambiguous task names, or unknown tasks; all error variants include the available task list.
4. It builds the final shell command with `buildCommand(commandPrefix, commandName, tail)`, joining non-empty parts with spaces.
5. If the task defines `cwd`, that relative path is returned alongside the command.
8. `RecipeTool.execute()` forwards `{ command, cwd }` into `BashTool.execute()`; recipe does not pass timeout, env, async, or pty options.
9. `BashTool.execute()` resolves internal URLs, validates/normalizes cwd against `session.cwd`, clamps timeout, applies bash interception rules, runs the command, and formats the final result.
## Modes / Variants
- Tool enablement:
- Disabled by `recipe.enabled` setting: tool is absent.
- Enabled but no detected tasks: tool is absent.
- Task selection:
- Unqualified task name: succeeds only when exactly one detected runner owns that task.
- Explicit runner-qualified task: `<runner-id>:<task>`.
- Runner detection paths:
- `just`: requires `just` on `PATH`, a justfile, and successful `just --dump --dump-format=json`.
- `pkg`: requires a readable root `package.json`; picks a package manager command from lockfiles or `bun` availability; discovers root scripts and workspace package scripts.
- `cargo`: requires `cargo` on `PATH`, `Cargo.toml`, and successful `cargo metadata --no-deps --format-version=1`.
- `make`: requires `make` on `PATH` and a makefile; parses targets statically.
- `task`: requires `task` on `PATH`, a Taskfile, and successful `task --list-all --json`.
- Execution path:
- Always the synchronous `bash` call surface from recipe inputs.
- Bash may still auto-background long-running work if `bash.autoBackground.enabled` and session async job support are enabled.
## Side Effects
- Filesystem
- Reads manifests from the session cwd during detection: justfiles, `package.json`, workspace `package.json` files, `Cargo.toml`, makefiles, `Taskfile.yml` / `Taskfile.yaml`.
- Command execution runs in `session.cwd` or a task-specific relative cwd resolved under it.
- Bash may allocate output artifacts for truncated command output.
- Subprocesses / native bindings
- Detection may spawn `just --dump --dump-format=json`, `cargo metadata --no-deps --format-version=1`, and `task --list-all --json`.
- Execution spawns the resolved shell command through `BashTool` / `executeBash()`.
- Session state (transcript, memory, jobs, checkpoints, registries)
- Tool availability depends on session settings.
- Constructor prompt text is specialized to detected runners/tasks.
- Bash execution may create async job records and output artifacts if bash auto-background triggers.
- User-visible prompts / interactive UI
- The model-facing tool description lists detected runners and up to 20 tasks per runner.
- TUI rendering shows a shell-style preview using the resolved title/command/cwd.
- Background work / cancellation
- Detection is parallelized across runners.
- Runtime command execution honors the passed abort signal through `BashTool`.
## Limits & Caps
- Prompt task listing is capped at `PROMPT_TASK_LIMIT = 20` per runner in `packages/coding-agent/src/tools/recipe/runner.ts`; this affects the rendered tool description, not execution.
- Recipe itself defines no timeout input; delegated bash execution therefore uses bash's default `timeout = 300` seconds from `packages/coding-agent/src/tools/bash.ts`.
- Bash clamps timeouts to the configured bash range (`clampTimeout("bash", ...)` in `packages/coding-agent/src/tools/bash.ts`), but recipe cannot request a custom value.
- `pkg` workspace discovery normalizes workspace globs to `.../package.json` and sorts matched package files lexicographically before task generation.
- `cargo` deduplicates generated task names with a `Set`, so duplicate targets collapse to one recipe task.
## Errors
- Detection failures in runner modules are mostly soft-failed:
- Missing binaries, missing manifests, parse failures, or non-zero probe exits usually return `null` and log with `logger.debug(...)`.
- Result: the affected runner disappears instead of surfacing an error to the model.
- Invocation failures are hard errors from `resolveRunnerAndTask()`:
- Empty `op`.
- Explicit runner prefix with missing/empty task.
- Ambiguous unqualified task name across runners.
- Unknown task name.
- Execution failures come from `BashTool.execute()`:
- Invalid cwd.
- Bash interceptor blocks.
- Aborts/timeouts.
- Non-zero exit codes.
- Missing exit status.
- All `resolveRunnerAndTask()` errors include the current available task list to help the model retry.
## Notes
- `RecipeTool` sets `concurrency = "exclusive"`; calls do not run concurrently with other exclusive tools.
- Tool registration is all-or-nothing per runner: a detected runner with zero tasks is dropped.
- Runner ids are fixed string literals from the runner modules: `just`, `pkg`, `cargo`, `make`, `task`.
- `buildPromptModel()` includes each task's rendered command (`commandPrefix` + `commandName`) and relative cwd when present; the prompt therefore exposes the exact shell form recipe will run.
- `pkg` task names:
- Root `package.json` scripts keep bare names like `test`.
- Workspace scripts are always namespaced as `<package-name-or-dir>/<script>` and set `cwd` to that package directory.
- Script names are shell-quoted into `commandName`, so a task like `build` becomes `bun run 'build'` / `npm run 'build'` / similar.
- `pkg` command prefix selection prefers lockfiles in this order: `bun.lock`/`bun.lockb`, `pnpm-lock.yaml`, `yarn.lock`, `package-lock.json`/`npm-shrinkwrap.json`; otherwise it falls back to `bun run` if `bun` exists, else `npm run`.
- `cargo` task names are generated from metadata targets:
- Single-package manifests: `bin/<name>`, `example/<name>`, `test/<name>`.
- Multi-package workspaces: `<package>/bin/<name>`, `<package>/example/<name>`, `<package>/test/<name>`.
- Each task overrides `commandPrefix` to the full `cargo run ... --bin|--example` or `cargo test ... --test` prefix, and `commandName` to the quoted target name.
- `make` target parsing is static text parsing, not `make -qp` output:
- Recognizes makefiles named `Makefile`, `makefile`, `GNUmakefile`.
- Uses `.PHONY` lines to decide whether to include undocumented file targets; without any `.PHONY`, all parsed targets are exposed.
- If `.PHONY` exists, documented non-phony targets are kept with ` (file target)` appended to `doc`.
- `just` detection ignores private recipes and preserves declared parameter names only for prompt display; execution still accepts arbitrary `tail` text.
- `task` detection uses `desc` first, then `summary`, for task documentation.
- Recipe has no env input of its own. Commands inherit whatever environment `BashTool` supplies for normal bash execution in the session.