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:
@@ -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.
|
||||
Reference in New Issue
Block a user