From aa0d0ad4ed63cde228bb3ff1808be4348769ebc4 Mon Sep 17 00:00:00 2001 From: can1357 Date: Mon, 11 May 2026 00:38:35 +0200 Subject: [PATCH] docs: tool behaviour --- docs/tools/ask.md | 85 +++++++++ docs/tools/ast-edit.md | 121 +++++++++++++ docs/tools/ast-grep.md | 112 ++++++++++++ docs/tools/bash.md | 149 ++++++++++++++++ docs/tools/browser.md | 229 ++++++++++++++++++++++++ docs/tools/calc.md | 71 ++++++++ docs/tools/checkpoint.md | 84 +++++++++ docs/tools/debug.md | 289 ++++++++++++++++++++++++++++++ docs/tools/edit.md | 205 +++++++++++++++++++++ docs/tools/eval.md | 242 +++++++++++++++++++++++++ docs/tools/exit_plan_mode.md | 68 +++++++ docs/tools/find.md | 106 +++++++++++ docs/tools/github.md | 313 +++++++++++++++++++++++++++++++++ docs/tools/inspect_image.md | 120 +++++++++++++ docs/tools/irc.md | 118 +++++++++++++ docs/tools/job.md | 143 +++++++++++++++ docs/tools/lsp.md | 313 +++++++++++++++++++++++++++++++++ docs/tools/read.md | 300 +++++++++++++++++++++++++++++++ docs/tools/recall.md | 79 +++++++++ docs/tools/recipe.md | 155 ++++++++++++++++ docs/tools/reflect.md | 73 ++++++++ docs/tools/render_mermaid.md | 82 +++++++++ docs/tools/resolve.md | 72 ++++++++ docs/tools/retain.md | 98 +++++++++++ docs/tools/rewind.md | 96 ++++++++++ docs/tools/search.md | 143 +++++++++++++++ docs/tools/search_tool_bm25.md | 117 ++++++++++++ docs/tools/ssh.md | 127 +++++++++++++ docs/tools/task.md | 224 +++++++++++++++++++++++ docs/tools/todo_write.md | 161 +++++++++++++++++ docs/tools/web_search.md | 224 +++++++++++++++++++++++ docs/tools/write.md | 177 +++++++++++++++++++ 32 files changed, 4896 insertions(+) create mode 100644 docs/tools/ask.md create mode 100644 docs/tools/ast-edit.md create mode 100644 docs/tools/ast-grep.md create mode 100644 docs/tools/bash.md create mode 100644 docs/tools/browser.md create mode 100644 docs/tools/calc.md create mode 100644 docs/tools/checkpoint.md create mode 100644 docs/tools/debug.md create mode 100644 docs/tools/edit.md create mode 100644 docs/tools/eval.md create mode 100644 docs/tools/exit_plan_mode.md create mode 100644 docs/tools/find.md create mode 100644 docs/tools/github.md create mode 100644 docs/tools/inspect_image.md create mode 100644 docs/tools/irc.md create mode 100644 docs/tools/job.md create mode 100644 docs/tools/lsp.md create mode 100644 docs/tools/read.md create mode 100644 docs/tools/recall.md create mode 100644 docs/tools/recipe.md create mode 100644 docs/tools/reflect.md create mode 100644 docs/tools/render_mermaid.md create mode 100644 docs/tools/resolve.md create mode 100644 docs/tools/retain.md create mode 100644 docs/tools/rewind.md create mode 100644 docs/tools/search.md create mode 100644 docs/tools/search_tool_bm25.md create mode 100644 docs/tools/ssh.md create mode 100644 docs/tools/task.md create mode 100644 docs/tools/todo_write.md create mode 100644 docs/tools/web_search.md create mode 100644 docs/tools/write.md diff --git a/docs/tools/ask.md b/docs/tools/ask.md new file mode 100644 index 000000000..ae9ce9c35 --- /dev/null +++ b/docs/tools/ask.md @@ -0,0 +1,85 @@ +# ask + +> Prompts the interactive user for one or more choices or free-form answers. + +## Source +- Entry: `packages/coding-agent/src/tools/ask.ts` +- Model-facing prompt: `packages/coding-agent/src/prompts/tools/ask.md` +- Key collaborators: + - `packages/coding-agent/src/config/settings-schema.ts` — `ask.timeout` / `ask.notify` defaults + - `packages/coding-agent/src/modes/theme/theme.ts` — checkbox and tree glyphs for TUI rendering + - `packages/coding-agent/src/tui.ts` — status-line rendering + +## Inputs + +| Field | Type | Required | Description | +| --- | --- | --- | --- | +| `questions` | `Question[]` | Yes | One or more questions. Empty arrays are rejected by schema and also guarded at runtime. | + +### `Question` + +| Field | Type | Required | Description | +| --- | --- | --- | --- | +| `id` | `string` | Yes | Stable identifier used in multi-question results. | +| `question` | `string` | Yes | Prompt text shown to the user. | +| `options` | `{ label: string }[]` | Yes | Explicit options. The UI always appends `Other (type your own)`; callers must not include it. | +| `multi` | `boolean` | No | Enables multi-select mode. Default: `false`. | +| `recommended` | `number` | No | Zero-based recommended option index. In single-select mode the label gets ` (Recommended)` appended in the UI. | + +## Outputs +- Single-shot result. +- `content[0].text` is plain text: + - single question: `User selected: ...` and/or `User provided custom input: ...` + - multiple questions: `User answers:` followed by one line per `id` +- `details`: + - single question: `{ question, options, multi, selectedOptions, customInput? }` + - multiple questions: `{ results: QuestionResult[] }`, where each item includes `id`, `question`, `options`, `multi`, `selectedOptions`, and optional `customInput` +- Cancellation and headless cases throw instead of returning a structured success result. + +## Flow +1. `AskTool.createIf()` only registers the tool when `session.hasUI` is true; headless sessions never get it. +2. `execute()` requires `context.ui`; if missing it aborts the context and throws `ToolAbortError("Ask tool requires interactive mode")`. +3. It reads `ask.timeout` from settings, converts seconds to milliseconds, and disables timeout entirely while plan mode is enabled (`packages/coding-agent/src/tools/ask.ts`). +4. If `ask.notify` is not `off`, it sends a terminal notification: `Waiting for input`. +5. For each question, `askSingleQuestion()` drives either: + - single-select list + optional editor for `Other` + - multi-select checkbox loop + `Done selecting` sentinel + optional editor for `Other` +6. In multi-question mode, left/right arrow handlers enable back/forward navigation between questions and preserve prior selections. +7. If a timeout fires before any selection/custom input, the tool auto-selects the recommended option, or the first option when no valid `recommended` index exists. +8. If the user cancels without timeout, `execute()` aborts the tool context and throws `ToolAbortError("Ask tool was cancelled by the user")`. +9. On success it formats human-readable text plus structured `details`; the TUI renderer uses `details` for rich display. + +## Modes / Variants +- Single question: returns flattened `details` fields for one question. +- Multiple questions: returns `details.results[]` and allows back/forward navigation across questions. +- Single-select: one option or custom input. +- Multi-select: toggled checkbox list, `Done selecting` sentinel only when forward navigation is not active. + +## Side Effects +- User-visible prompts / interactive UI + - Opens a selection dialog via `context.ui.select(...)`. + - Opens a text editor dialog via `context.ui.editor(...)` for `Other`. + - Sends a terminal notification unless `ask.notify=off`. +- Session state + - Reads plan-mode state to disable timeouts. + - Calls `context.abort()` on headless use or user cancellation. +- Background work / cancellation + - Wraps UI waits in `untilAborted(...)` so abort signals interrupt pending dialogs. + +## Limits & Caps +- `questions` must contain at least 1 item (`askSchema` in `packages/coding-agent/src/tools/ask.ts`). +- `ask.timeout` default is `30` seconds; `0` disables timeout (`packages/coding-agent/src/config/settings-schema.ts`). +- Prompt guidance says provide 2-5 options, but code does not enforce that (`packages/coding-agent/src/prompts/tools/ask.md`). +- Timeout only applies to the option picker; once the user chooses `Other`, the editor has no timeout (`packages/coding-agent/src/prompts/tools/ask.md`). + +## Errors +- Missing interactive UI: throws `ToolAbortError("Ask tool requires interactive mode")`. +- User cancels picker/editor without timeout: throws `ToolAbortError("Ask tool was cancelled by the user")`. +- Abort signal during input: converted to `ToolAbortError("Ask input was cancelled")`. +- Empty `questions` at runtime returns a text error payload instead of throwing: `Error: questions must not be empty`. + +## Notes +- `recommended` is only a UI hint; invalid indexes are ignored. +- In single-select mode the returned `selectedOptions` value strips the appended ` (Recommended)` suffix. +- Multi-select results preserve selection order by `Set` insertion order, not original option order after arbitrary toggles. +- Option labels and prompt text are returned verbatim in `details`; the tool does not interpret them beyond UI affordances like `Other` and ` (Recommended)`. diff --git a/docs/tools/ast-edit.md b/docs/tools/ast-edit.md new file mode 100644 index 000000000..cc96c42cc --- /dev/null +++ b/docs/tools/ast-edit.md @@ -0,0 +1,121 @@ +# ast_edit + +> Preview and apply structural rewrites over source files via native ast-grep. + +## Source +- Entry: `packages/coding-agent/src/tools/ast-edit.ts` +- Model-facing prompt: `packages/coding-agent/src/prompts/tools/ast-edit.md` +- Key collaborators: + - `crates/pi-natives/src/ast.rs` — native rewrite planning and file mutation + - `crates/pi-natives/src/language/mod.rs` — language aliases and extension inference + - `packages/coding-agent/src/tools/path-utils.ts` — path/glob parsing and multi-path resolution + - `packages/coding-agent/src/tools/resolve.ts` — preview/apply queueing + - `packages/coding-agent/src/tools/render-utils.ts` — parse-error dedupe and display caps + - `packages/coding-agent/src/utils/file-display-mode.ts` — hashline vs line-number diff references + - `packages/coding-agent/src/hashline/hash.ts` — stable hashline diff anchors + - `packages/natives/native/index.d.ts` — JS-visible native binding contract + +## Inputs + +| Field | Type | Required | Description | +| --- | --- | --- | --- | +| `ops` | `{ pat: string; out: string }[]` | Yes | One or more rewrite rules. `pat` must be non-empty. Duplicate `pat` values fail before native execution. Empty `out` deletes the matched node. | +| `paths` | `string[]` | Yes | One or more files, directories, globs, or internal URLs with backing files. Empty entries are rejected. Globs are forbidden for internal URLs. | + +Shared AST pattern grammar and language catalog: see [`ast_grep`](./ast-grep.md#inputs). + +- `ast_edit` uses the same `$NAME`, `$_`, `$$$NAME`, and `$$$` metavariable semantics. +- The tool prompt adds rewrite-specific constraints: + - metavariable names must be uppercase and must stand for whole AST nodes, + - captures from `pat` are substituted into `out`, + - each rewrite is a 1:1 structural substitution; one capture cannot expand into multiple sibling nodes unless the grammar itself permits that expansion at that position. + +## Outputs +- Single-shot preview result from `ast_edit` itself. +- Model-facing `content` is one text block showing proposed edits, grouped by file for directory/multi-file runs. + - Each change renders as two lines: `-REF|before` and `+REF|after` in hashline mode, or `-LINE:COLUMN before` / `+LINE:COLUMN after` when hashlines are off. + - Only the first line of each `before`/`after` snippet is shown, truncated to 120 characters in the wrapper. + - `Limit reached; narrow paths.` and formatted parse issues are appended when applicable. +- If no rewrites match, text is `No replacements made` plus formatted parse issues when present. +- `details` includes aggregate preview metadata: + - `totalReplacements`, `filesTouched`, `filesSearched`, `applied`, `limitReached` + - optional `parseErrors`, `scopePath`, `files`, `fileReplacements`, `displayContent`, `meta` +- The tool always previews first (`applied: false` in the direct result). Actual file writes happen only later through `resolve(action: "apply", ...)`. +- When preview produced replacements, `ast_edit` also queues a pending `resolve` action. Successful apply returns a separate `resolve` result, not another `ast_edit` result. + +## Flow +1. `AstEditTool.execute()` validates each op in `packages/coding-agent/src/tools/ast-edit.ts`: + - empty `pat` fails, + - at least one op is required, + - duplicate `pat` values fail, + - ops are converted to a `Record`. +2. The wrapper reads `PI_MAX_AST_FILES` via `$envpos(..., 1000)` and uses that as the native `maxFiles` cap for both preview and apply. +3. Path normalization, internal URL handling, missing-path partitioning, and multi-path resolution follow the same `path-utils.ts` flow as `ast_grep`. +4. The wrapper stats the resolved base path to decide whether to render grouped directory output. +5. `runAstEditOnce(...)` always runs native `astEdit(...)` with `dryRun: true` and `failOnParseError: false` on the first pass. +6. Native `ast_edit` in `crates/pi-natives/src/ast.rs`: + - normalizes the rewrite map and sorts rules by pattern string, + - resolves strictness (`smart` by default), + - collects candidate files from a file or gitignore-aware directory scan, + - infers a single language for the whole call unless `lang` was supplied, + - compiles every rewrite pattern for that language, + - parses each file, skips files with syntax-error trees, collects `replace_by(...)` edits for every match, enforces replacement and file caps, and returns textual before/after slices plus source ranges. +7. The TS wrapper deduplicates parse errors, groups changes by file, and renders preview diff lines. +8. If preview found replacements and `applied` is false, `queueResolveHandler(...)` registers a forced `resolve` action and injects a `resolve-reminder` steering message. +9. On `resolve(action: "apply")`, the queued callback reruns the same rewrite set with `dryRun: false`, recomputes counts, and rejects the apply as an error if the live result no longer matches the preview (`stalePreview`). +10. On a non-stale apply, the callback returns `Applied N replacements in M files.`; on discard, `resolve` returns a discard message without mutating files. + +## Modes / Variants +- Single file: preview or apply against one file. +- Directory + optional glob: native scan walks the directory, then filters by compiled glob. +- Multiple explicit paths/globs: wrapper unions them into one synthetic scope or runs per-target native calls when paths only meet at root. +- Internal URL inputs: only supported when the router resolves them to a backing file path. +- Preview mode: always the direct `ast_edit` tool result. +- Apply mode: only reachable through the queued `resolve` callback after a preview. +- Hashline output mode vs plain line/column mode: controlled by `resolveFileDisplayMode()`. + +## Side Effects +- Filesystem + - Preview reads files and scans directories. + - Apply rewrites files in place with `std::fs::write(...)`, but only when the computed output differs from the original source. +- Session state (transcript, memory, jobs, checkpoints, registries) + - Queues a one-shot forced `resolve` tool choice through `queueResolveHandler(...)`. + - Adds a `resolve-reminder` steering message. +- User-visible prompts / interactive UI + - Direct `ast_edit` results are previews. + - Follow-up apply/discard is exposed through the hidden `resolve` tool. +- Background work / cancellation + - Native preview/apply work runs on a blocking worker via `task::blocking(...)`. + - Cancellation and optional native timeout are cooperative through `CancelToken::heartbeat()`. + +## Limits & Caps +- File cap exposed by the wrapper: `PI_MAX_AST_FILES`, default `1000`, in `packages/coding-agent/src/tools/ast-edit.ts`. +- Native `maxFiles` and `maxReplacements` are both clamped to at least `1` when provided in `crates/pi-natives/src/ast.rs`. +- The wrapper never sets `maxReplacements`; native behavior therefore defaults to effectively unbounded replacements for a run. +- Parse issues are rendered with at most `PARSE_ERRORS_LIMIT = 20` lines in `packages/coding-agent/src/tools/render-utils.ts`; `details.parseErrors` is deduplicated but not capped. +- Directory scans use `include_hidden: true`, `use_gitignore: true`, and skip `node_modules` unless the glob text explicitly mentions `node_modules` in `crates/pi-natives/src/ast.rs`. +- No separate glob-expansion count cap exists. Candidate count is whatever the resolved path/glob expands to after gitignore filtering, then native `maxFiles` stops mutations after the configured number of touched files. +- Preview text truncates each rendered `before` and `after` first line to 120 characters in `packages/coding-agent/src/tools/ast-edit.ts`. + +## Errors +- TS wrapper throws `ToolError` for empty patterns, duplicate rewrite patterns, empty path entries, unsupported internal-URL globs, internal URLs without `sourcePath`, and missing paths. +- Native code returns hard errors for: + - inability to infer one language across all candidates when `lang` is absent, + - unsupported explicit `lang`, + - bad glob compilation or unreadable search roots, + - overlapping computed edits (`Overlapping replacements detected; refine pattern to avoid ambiguous edits`), + - out-of-bounds edit ranges or non-UTF-8 replacement text, + - write failures during apply, + - cancellation or timeout. +- With `failOnParseError: false` (the wrapper always uses this), pattern compile failures and file parse failures become `parseErrors` instead of aborting the whole run. +- If every rewrite pattern fails to compile, native `ast_edit` returns a successful zero-replacement result with `parseErrors` populated. +- Files containing tree-sitter error nodes are skipped for rewriting; they do not get partial edits. +- Apply can fail after a successful preview if the preview becomes stale. The resolve callback compares replacement totals and per-file counts and returns an error result rather than applying a mismatched preview silently. + +## Notes +- `ast_edit` does not expose the native `lang`, `strictness`, `selector`, `maxReplacements`, `failOnParseError`, or `timeoutMs` fields to the model. The runtime fixes the call shape to a preview-first, smart-strictness, best-effort parse mode. +- Because the wrapper does not expose `lang`, mixed-language rewrites only succeed when every candidate infers to the same canonical language. This is stricter than `ast_grep`. +- Idempotency is not enforced syntactically. A rewrite like `foo($A) -> foo($A)` previews zero changes because output equals input; a rewrite that keeps matching its own output may still produce replacements on repeated calls. +- Rewrites are accumulated per file, then applied from the end of the file backward after an overlap check. Independent matches can coexist; overlapping matches abort the run. +- Native rewrite rule order is by pattern-string sort, not by the original `ops` array order, because `normalize_rewrite_map(...)` sorts the `(pattern, rewrite)` pairs. +- Preview/apply parity is validated only by totals and per-file counts, not by a byte-for-byte diff of every replacement payload. \ No newline at end of file diff --git a/docs/tools/ast-grep.md b/docs/tools/ast-grep.md new file mode 100644 index 000000000..97282d6ef --- /dev/null +++ b/docs/tools/ast-grep.md @@ -0,0 +1,112 @@ +# ast_grep + +> Structural code search over supported source files via native ast-grep. + +## Source +- Entry: `packages/coding-agent/src/tools/ast-grep.ts` +- Model-facing prompt: `packages/coding-agent/src/prompts/tools/ast-grep.md` +- Key collaborators: + - `crates/pi-natives/src/ast.rs` — native scan, parse, match engine + - `crates/pi-natives/src/language/mod.rs` — language aliases and extension inference + - `packages/coding-agent/src/tools/path-utils.ts` — path/glob parsing and multi-path resolution + - `packages/coding-agent/src/tools/render-utils.ts` — parse-error dedupe and display caps + - `packages/coding-agent/src/tools/match-line-format.ts` — anchor-prefixed match rendering + - `packages/coding-agent/src/utils/file-display-mode.ts` — hashline vs line-number output mode + - `packages/natives/native/index.d.ts` — JS-visible native binding contract + +## Inputs + +| Field | Type | Required | Description | +| --- | --- | --- | --- | +| `pat` | `string` | Yes | Single AST pattern. The wrapper trims it and rejects empty strings. | +| `paths` | `string[]` | Yes | One or more files, directories, globs, or internal URLs with backing files. Empty entries are rejected. Globs are forbidden for internal URLs. | +| `skip` | `number` | No | Match offset. Defaults to `0`, then `Math.floor(...)`; negatives and non-finite values fail. | + +Pattern grammar and language support exposed to the model: +- `$NAME` — capture one AST node. +- `$_` — match one AST node without binding. +- `$$$NAME` — capture zero or more AST nodes; ast-grep stops lazily at the next satisfiable node. +- `$$$` — match zero or more AST nodes without binding. +- Metavariable names must be uppercase and must stand for whole AST nodes, not partial tokens or string fragments. +- Reusing the same metavariable requires identical code at each occurrence. +- Patterns must parse as one valid AST node for the inferred target language. +- Supported canonical languages come from `SupportLang::all_langs()` in `crates/pi-natives/src/language/mod.rs`: `astro`, `bash`, `c`, `cmake`, `cpp`, `csharp`, `dart`, `clojure`, `css`, `diff`, `dockerfile`, `elixir`, `erlang`, `go`, `graphql`, `haskell`, `hcl`, `html`, `ini`, `java`, `javascript`, `json`, `just`, `julia`, `kotlin`, `lua`, `make`, `markdown`, `nix`, `objc`, `ocaml`, `odin`, `perl`, `php`, `powershell`, `protobuf`, `python`, `r`, `regex`, `ruby`, `rust`, `scala`, `solidity`, `sql`, `starlark`, `svelte`, `swift`, `toml`, `tlaplus`, `tsx`, `typescript`, `verilog`, `vue`, `xml`, `yaml`, `zig`. + +## Outputs +- Single-shot tool result. +- Model-facing `content` is one text block: + - grouped by file for directory/multi-file searches, + - match lines rendered as `*LINE+HASH|text` in hashline mode or `*LINE|text` otherwise, + - continuation lines for multi-line matches rendered with a leading space, + - optional `meta: NAME=value` lines when ast-grep captured metavariables. +- If no matches are found, text is `No matches found` or `No matches found. Parse issues mean the query may be mis-scoped; narrow paths before concluding absence.` plus formatted parse issues. +- If the wrapper truncates visible results, the text ends with `Result limit reached; narrow paths or increase limit.` +- `details` includes counts and metadata, not full match payloads: + - `matchCount`, `fileCount`, `filesSearched`, `limitReached` + - optional `parseErrors`, `scopePath`, `files`, `fileMatches`, `displayContent`, `meta` +- Native ranges (`byteStart`, `byteEnd`, `startLine`, `startColumn`, `endLine`, `endColumn`) exist only inside the native result; the wrapper does not emit them directly to the model. + +## Flow +1. `AstGrepTool.execute()` validates `pat`, normalizes `skip`, and normalizes each `paths` entry in `packages/coding-agent/src/tools/ast-grep.ts`. +2. Internal URLs are resolved through `session.internalRouter`; entries without `sourcePath` fail, and internal-URL globs fail early. +3. For multiple path inputs, `partitionExistingPaths()` drops missing bases only when at least one surviving base remains; if all bases are missing the call fails. +4. `parseSearchPath()` splits a single path into `basePath` plus optional `glob`. `resolveExplicitSearchPaths()` collapses multiple inputs into a common base plus a brace-union glob, or separate `targets` when the only common base is a filesystem root. +5. The wrapper stats the resolved base path to decide whether output should be grouped as a directory result. +6. Execution dispatches to either: + - one native `astGrep(...)` call for a single resolved base, or + - `runMultiTargetAstGrep(...)`, which calls the native binding once per target, rebases paths back to the common root, sorts globally, then applies `skip` and the wrapper limit. +7. Native `ast_grep` in `crates/pi-natives/src/ast.rs`: + - normalizes and deduplicates patterns, + - resolves a `MatchStrictness` (`smart` by default), + - collects candidate files from a file or gitignore-aware directory scan, + - infers language per candidate from extension unless `lang` was provided, + - compiles the pattern separately for each language present, + - reads each file, reports syntax-error trees as parse issues, runs `find_all`, and optionally captures metavariable bindings. +8. Native results are sorted by path and source position, then paged by `offset`/`limit`. +9. The TS wrapper normalizes parse-error strings, deduplicates them, groups matches by formatted path, renders anchor lines, appends limit/parse notices, and returns `toolResult(...).text(...).done()`. + +## Modes / Variants +- Single file: native path is the file; output is a flat list of rendered match lines. +- Directory + optional glob: native scan walks the directory, then filters by compiled glob. +- Multiple explicit paths/globs: wrapper unions them into one synthetic scope or runs per-target native calls when paths only meet at root. +- Internal URL inputs: only supported when the router can resolve them to a backing file path. +- Hashline output mode vs plain line-number mode: controlled by `resolveFileDisplayMode()`; hashline mode requires the edit tool and non-raw, mutable sources. + +## Side Effects +- Filesystem + - Stats input paths in the TS wrapper. + - Native code reads matched files and scans directories through `fs_cache`. +- Session state (transcript, memory, jobs, checkpoints, registries) + - None beyond normal tool transcript/result metadata. +- Background work / cancellation + - Native work runs on a blocking worker via `task::blocking(...)`. + - Cancellation and optional native timeout are cooperative through `CancelToken::heartbeat()`. + +## Limits & Caps +- Wrapper-visible result cap: `DEFAULT_AST_LIMIT = 50` in `packages/coding-agent/src/tools/ast-grep.ts`. + - Single-target calls rely on the native default limit of 50 in `crates/pi-natives/src/ast.rs`. + - Multi-target calls fetch `skip + 50 + 1` matches per target, then re-page after global sort. +- Native `limit` is clamped to at least `1`; omitted `offset` defaults to `0` in `crates/pi-natives/src/ast.rs`. +- Parse issues are rendered with at most `PARSE_ERRORS_LIMIT = 20` lines in `packages/coding-agent/src/tools/render-utils.ts`; `details.parseErrors` itself is only deduplicated, not capped. +- Directory scans use `include_hidden: true`, `use_gitignore: true`, and skip `node_modules` unless the glob text explicitly mentions `node_modules` in `crates/pi-natives/src/ast.rs`. +- No hard file-count cap is applied by the wrapper or native `ast_grep`; candidate count is whatever the resolved path/glob expands to after gitignore filtering. +- Multi-path union deduplicates identical path inputs before resolution in `resolveExplicitSearchPaths()`. + +## Errors +- TS wrapper throws `ToolError` for empty patterns, invalid `skip`, empty path entries, unsupported internal-URL globs, internal URLs without `sourcePath`, and missing paths. +- Native code returns hard errors for: + - unsupported explicit `lang`, + - inability to infer language for a candidate when `lang` is not supplied, + - invalid AST pattern compilation for every relevant language, + - unreadable search roots or bad glob compilation, + - cancellation (`Aborted: Signal`) or timeout (`Aborted: Timeout`). +- File-level parse failures and many per-language pattern compile failures are non-fatal: they are accumulated in `parseErrors` and surfaced alongside successful matches. +- `no matches` is not an error, even when parse issues were recorded. + +## Notes +- `pat` is always wrapped into a one-element `patterns` array by the TS tool; the model cannot send multiple patterns through `ast_grep` even though the native binding supports it. +- `ast_grep` can search mixed-language trees because native compilation happens per discovered language, but the prompt still tells the model to keep calls single-language when possible to reduce parse noise. +- Pattern compilation is per language present in the candidate set. One pattern can succeed for some languages and generate per-file parse errors for others in the same run. +- A file with tree-sitter error nodes still gets searched; the syntax warning is additive, not a skip condition. +- For glob semantics, `*.ts` matches only direct children while `**/*.ts` recurses; this is covered by native tests in `crates/pi-natives/src/ast.rs`. +- Output anchors are intended for follow-up tools, but the exact anchor format depends on session edit mode (`hashline` vs line-number mode). \ No newline at end of file diff --git a/docs/tools/bash.md b/docs/tools/bash.md new file mode 100644 index 000000000..843c82067 --- /dev/null +++ b/docs/tools/bash.md @@ -0,0 +1,149 @@ +# bash + +> Execute a shell command in the session workspace, with optional PTY or background-job handling. + +## Source +- Entry: `packages/coding-agent/src/tools/bash.ts` +- Model-facing prompt: `packages/coding-agent/src/prompts/tools/bash.md` +- Key collaborators: + - `packages/coding-agent/src/tools/bash-interactive.ts` — PTY/TUI execution path. + - `packages/coding-agent/src/tools/bash-interceptor.ts` — blocks tool-better shell patterns. + - `packages/coding-agent/src/tools/bash-skill-urls.ts` — expands internal URLs to paths. + - `packages/coding-agent/src/exec/bash-executor.ts` — non-PTY shell execution. + - `packages/coding-agent/src/session/streaming-output.ts` — tail buffer, truncation, artifact spill. + - `packages/coding-agent/src/tools/tool-timeouts.ts` — timeout clamp bounds. + - `packages/coding-agent/src/config/settings-schema.ts` — default interceptor rules. + - `docs/bash-tool-runtime.md` — deeper executor/runtime notes; use as the companion doc for shell-session internals. + +## Inputs + +| Field | Type | Required | Description | +| --- | --- | --- | --- | +| `command` | `string` | Yes | Shell command text to execute. A leading `cd && ...` is rewritten into `cwd` only when `cwd` was omitted. | +| `env` | `Record` | No | Extra environment variables. Keys must match `^[A-Za-z_][A-Za-z0-9_]*$` or the tool throws. Values also go through internal-URL expansion. | +| `timeout` | `number` | No | Timeout in seconds. Default `300`; clamped to `1..3600` by `clampTimeout("bash", ...)`. | +| `cwd` | `string` | No | Working directory, resolved against `session.cwd` via `resolveToCwd`. Must exist and be a directory. | +| `pty` | `boolean` | No | Request PTY mode. Default `false`. PTY is used only when `pty: true`, `PI_NO_PTY !== "1"`, and the tool context has a UI. | +| `async` | `boolean` | No | Background execution request. Present only when `async.enabled` is true for the session. Returns immediately with a job id instead of waiting. | + +## Outputs +The tool returns a single `text` content block plus optional `details`. + +- Success, foreground: + - `content[0].text`: command output, or `(no output)` when the command produced nothing. + - `details.timeoutSeconds`: effective timeout after clamping. + - `details.requestedTimeoutSeconds`: only present when the requested timeout was clamped. + - `details.meta.truncation`: present when output was truncated in memory; includes `artifactId` when full output spilled to an artifact. +- Success, background start (`async: true` or auto-background): + - `content[0].text`: optional preview tail, timeout notice if any, then `Background job started: