- Added `ToolTier`, `ToolApproval`, and `ToolApprovalDecision` types and exported approval APIs.
- Updated approval-mode options from `auto|prompt|custom` to `always-ask|write|yolo` and defaulted mode to `yolo`.
- Changed approval resolution to apply per-tool decisions first, then mode-tier limits, with legacy-mode migration.
- Assigned read/write/exec `approval` and approval-detail prompts across built-in, custom, extension, and MCP tools.
clampTimeout silently floored the caller-supplied timeout to 30s, so a
requested 120s for a slow waitForResponse came back as a 30s failure
indistinguishable from the default. Raise the cap and document the new
max in the schema field description.
- Replaced all StringEnum(...) usages with z.enum([...]) across tools, examples, and tests.
- Removed StringEnum re-export from @oh-my-pi/pi-coding-agent public API.
- Condensed verbose tool parameter descriptions to minimal lowercase phrases.
- Renamed AuthCredentialStore to SqliteAuthCredentialStore at usage sites.
- Added canonical `pi.zod` schema API exports and removed TypeBox package exports/imports.
- Migrated Tool schema typing from TypeBox to shared `TSchema`/Zod flow with legacy TypeBox compatibility.
- Updated AI provider adapters and MCP/agent builders to convert tool params through `toolWireSchema()`.
- Reworked schema validation from AJV to Zod-safe parsing with `fromTypeBox`, `toolWireSchema`, and meta schema checks.
- Added optional `loadMode` and `summary` fields to `AgentTool` and related type declarations.
- Added `loadMode` and `summary` metadata to built-in tool classes for discoverable/essential behavior.
- Replaced `BUILTIN_TOOL_METADATA` with per-tool fields in discovery code paths.
- Updated `search_tool_bm25` and discovery indexing to use each tool's `summary` text.
- Updated discovery tests to validate tool `loadMode` and summary completeness.
- Consolidated AI provider imports through register-builtins and moved Gemini/Antigravity header helpers to a shared module.
- Added lazy loading for heavy providers and SDK-backed modules with cached initialization to trim startup cost.
- Converted markdown conversion helpers to async and awaited htmlToBasicMarkdown in affected scraper and kernel output paths.
- Parsed bundled agent definitions on-demand and moved BrowserTool prompt rendering behind a memoized getter.
- Added cached validation/error handling paths by replacing AJV runtime checks with Value.Check and trimming validation error output.
- Added a unified eval framework with parser grammar, backend interfaces, and JS/Python execution result types.
- Added eval tool docs and updated prompts for fenced cells, `eval.py`/`eval.js`, and fallback behavior.
- Replaced the built-in `python` tool with `eval` across registry, rendering, interactive modes, and tool settings.
- Migrated Python execution runtime from `src/ipy` to `src/eval/py`, renamed state fields, and removed legacy introspection.
- Refactored browser tooling from in-process VM helpers to worker-managed tab supervisors and protocol transport.
- Added eval parser fallback and JS tool-bridge tests, updated imports, and removed obsolete python-mode suites.
- Added support for `viewport.scale` and `open` `dialogs` options when launching/reusing browser tabs.
- Applied configurable dialog auto-handling policies to acquired tabs and cleaned up handlers when tabs are disposed.
- Added new tab APIs (`evaluate`, `scrollIntoView`, `select`, `uploadFile`, `waitForUrl`, `waitForResponse`) and updated browser tool docs.
- Removed legacy actions and reworked tool schema to open/run/close with required open-before-run async-JS flow.
- Added named tab reuse with browser-kind checks and close options all/kill with ref-counted disposal.
- Implemented launch/CDP hardening by finding free ports, reusing live targets, waiting for readiness, and killing process trees.
- Added readable result extraction, selector and action visibility checks, and screenshot/observation support in run execution.
- Added `Process` class with pidfd (Linux), libproc (macOS), and handle (Windows) ownership for race-free signaling.
- Replaced `killTree`/`listDescendants` free functions with `Process.fromPid`, `fromPath`, `terminate`, and `waitForExit`.
- Added `TerminationTargets` for batching pgid+pid sets across pty and shell job teardown.
- Migrated `procmgr` and `ptree` to use the new native API, removing the `setNativeKillTree` injection pattern.
- Replaced Puppeteer imports and package references with puppeteer-core, adding @puppeteer/browsers where needed for explicit browser management.
- Updated the browser tool to prefer a detected system Chrome/Chromium executable and respect PUPPETEER_EXECUTABLE_PATH before launch.
- Implemented lazy, on-demand Chromium download via @puppeteer/browsers with cached executable resolution and fallback error handling.
Fixes#797
- Limited strict tool candidates to a named allowlist instead of all opt-in tools.
- Fixed `minItems` stripping to target object-typed schema nodes, not just arrays.
- Enabled strict mode on all remaining coding-agent tools now that the allowlist guards eligibility.
- Added an optional strict field to CustomTool definitions to support non-strict execution mode.
- Set strict to false across built-in AgentTool and custom tool registrations, including browser, calculator, GitHub, image generation, and related utilities.
- Updated inspect-image tests to reflect the relaxed strict setting on the tool.
- Added `CodeFrameMarker` and `formatCodeFrameLine()` to centralize code-frame gutter formatting.
- Extended diff rendering to preserve `|` and `│` separators, aligning gutter markers and line numbers.
- Reworked AST, grep, hashline, Vim, and diff renderers to use shared line formatting with computed `lineNumberWidth`.
- Updated atom editing flow and tests, including `resolveAtomEntryPaths` migration and new loc-based/edge-case coverage.
- Adjusted benchmark runner early-stop configuration by passing `buildEarlyStop` through prompt collection.
- Added `examples` support to `StringEnum` schemas and propagated it to tool metadata.
- Added concise descriptions and example values across coding-agent tool schemas for clearer guidance.
- Documented the new StringEnum examples capability in `packages/ai/CHANGELOG.md`.
- Cast `real` to `HASHLINE_BIGRAMS` elements in `staleBigramFor` test setup.
- Reduced default image size limits to 1568px and 500KB to match Anthropic's internal thresholds.
- Optimized screenshot compression with 1024px max dimensions, 150KB budget, and 70% JPEG quality for aggressive payload reduction.
- Added fast-path optimization to skip re-encoding when images fit dimensions and are within 25% of byte budget.
- Refactored image encoding strategy to JPEG-only in quality/dimension reduction loops with improved quality ladder steps.
- Added `extractReadableFromHtml()` utility function with dual-path content extraction using Readability library and CSS selector fallback.
- Integrated Turndown library with GitHub Flavored Markdown plugin for improved HTML-to-markdown conversion supporting tables, strikethrough, and task lists.
- Refactored `getPageReadable()` action to use new extraction function, consolidating content parsing logic and improving maintainability.
- Added TypeScript type declarations for turndown-plugin-gfm module with custom Turndown rules for enhanced markdown formatting.
- Extracted prompt rendering and formatting utilities from coding-agent to centralized pi-utils package with new API surface (prompt.render, prompt.format, prompt.registerHelper).
- Migrated parseFrontmatter utility from coding-agent to pi-utils package; updated 8 files to import from @oh-my-pi/pi-utils.
- Removed 170-line prompt-format.ts module and consolidated 192 lines of Handlebars helper registrations into pi-utils prompt module.
- Updated 60+ files across coding-agent and typescript-edit-benchmark to use new prompt.render() and prompt.format() API from pi-utils.
- Simplified prompt-templates.ts by delegating core functionality to pi-utils while retaining custom helper registrations (jtdToTypeScript, jsonStringify, etc.).
- Replaced all Bun.which() calls with $which() utility from @oh-my-pi/pi-utils across 22 files.
- Removed findBashOnPath() wrapper function from procmgr.ts, consolidating binary path resolution.
- Updated AGENTS.md documentation to reflect new $which() API usage pattern.
- Centralized binary detection logic through shared utility, reducing code duplication.
Puppeteer's bundled Chromium is a dynamically-linked FHS binary that
cannot run on NixOS. On startup, resolveSystemChromium() checks for
/etc/NIXOS and searches for a usable binary in order:
1. chromium on PATH
2. chromium-browser on PATH
3. ~/.nix-profile/bin/chromium
4. /run/current-system/sw/bin/chromium
The resolved path is passed as executablePath to puppeteer.launch().
Result is cached per process. On non-NixOS systems the function returns
undefined immediately, leaving Puppeteer's default resolution intact.
- Added root path alias feature to resolve bare `/` to session working directory in path resolution.
- Updated browser tool to use `resolveToCwd()` for consistent workspace-relative path handling.
- Added comprehensive test suite validating root path alias resolution across grep, read, find, ast_grep, and ast_edit tools.
- Extracted screenshot formatting logic into dedicated `formatScreenshot()` function with options support.
- Consolidated prompt source deduplication into `dedupePromptSource()` helper to prevent rule duplication.
- Refactored editor text sanitization to use `replaceTabs()` utility for consistent tab width handling.
- Added test coverage verifying editor respects configured tab width when loading text programmatically.
- Simplified null/empty checks across TypeScript codebase using optional chaining operator (?.) for improved readability.
- Replaced explicit null checks in validation logic with optional chaining in oauth-discovery, gemini-cli, claude, zai, and lsp modules.
- Updated error handling in Rust command invocation to use double question mark operator (??) for cmd_result.
- Consolidated null validation patterns across tools (bash-skill-urls, browser, gemini-image, resolve) and keybindings using optional chaining.
screenshotDir is a default save location, not an anchor for explicit
paths. A relative params.path should always resolve against cwd so its
semantics are stable and predictable regardless of user settings.
When screenshotDir or params.path is set, the full-resolution PNG buffer
is written to disk. Previously mimeType/bytes in details still reflected
the resized payload sent to the model, making metadata inconsistent with
the actual saved file.
Now savedBuffer/savedMimeType track what is written, and details reflects
that. Display output distinguishes 'Saved' vs 'Model' when full-res is
used, and collapses to a single Format/Dimensions line for temp-only.
Previously wrote to /tmp unconditionally then copied to user path,
resulting in two files. Now resolves a single destination upfront:
1. params.path (absolute, or relative to screenshotDir/cwd)
2. screenshotDir + auto-timestamp filename
3. /tmp fallback (original behaviour, unchanged)
Also: user-defined destinations receive the full-res buffer;
/tmp fallback retains the API-compressed copy as before.
Users can now configure browser.screenshotDir as ~/Downloads or
~/Pictures and use params.path as ~/screenshots/foo.png without
needing to supply fully-qualified paths.
- Add `browser.screenshotDir` setting (tools tab) for a persistent
default screenshot directory, configurable via /settings
- Honour the existing `path` parameter in the screenshot action,
which was declared in the schema but never consumed by the implementation
- Resolution order: params.path (abs) > join(screenshotDir, params.path)
> join(screenshotDir, screenshot-<timestamp>.png) > /tmp only
- Writes full-resolution buffer to disk (not the API-compressed copy)
- Creates destination directory recursively if it doesn't exist
- details.screenshotPath reflects the actual saved location
Fixes: path param silently ignored since removal in v11.5.0
* fix(browser): route localhost through proxy when PUPPETEER_PROXY is set
Chrome bypasses proxies for localhost/loopback by default (since v72).
Add --proxy-bypass-list=<-loopback> so localhost traffic reaches mitmdump,
enabling proxy_traffic.log to capture auth flows for local targets.
Made-with: Cursor
* fix(browser): make proxy loopback bypass opt-in via PUPPETEER_PROXY_BYPASS_LOOPBACK
Made-with: Cursor
* Add PUPPETEER_PROXY and PUPPETEER_PROXY_IGNORE_CERT_ERRORS env vars
- PUPPETEER_PROXY: routes browser traffic through specified proxy
- PUPPETEER_PROXY_IGNORE_CERT_ERRORS: ignore HTTPS cert errors when set
Made-with: Cursor
* fix(browser): gate PUPPETEER_PROXY_IGNORE_CERT_ERRORS on explicit truthy parse
Previously any non-empty value (including 'false', '0') enabled
--ignore-certificate-errors, silently disabling TLS verification when
operators intended to keep it on. Now only 'true', '1', 'yes', 'on'
(case-insensitive) enable the flag.
Made-with: Cursor
- Added `tools.maxTimeout` setting to enforce global timeout ceiling across all tool calls.
- Centralized per-tool timeout constants and clamping logic into `tool-timeouts.ts` module.
- Extracted `clampTimeout()` function to standardize timeout enforcement across bash, python, browser, ssh, and fetch tools.
- Consolidated @oh-my-pi/pi-utils subpath imports into single package root import across 100+ files.
- Moved tryParseJson utility from local web scrapers module to @oh-my-pi/pi-utils package for centralized JSON parsing.
- Renamed loadSkillsFromDir to scanSkillsFromDir and refactored skill discovery to use fs.promises.readdir instead of glob-based approach.
- Replaced custom parseJSON with tryParseJson across discovery modules for consistent error handling.
- Removed emitCustomToolSessionEvent method and cleanupSshResources function, consolidating shutdown logic into dispose method.
- Updated glob pattern construction to use GlobBuilder with literal_separator(true) for improved path handling.
- Renamed `file` parameter to `path` in edit tool schemas and all test cases for consistency.
- Removed `file` property fallback from EditRenderArgs interface and path resolution methods.
- Refactored browser viewport schema to use snake_case `device_scale_factor` with explicit camelCase mapping for Puppeteer API.
- Added hashline edit rule requiring `end` tag to include closing braces/brackets when replacing blocks.
- Refactored INTENT_FIELD injection logic to conditionally reorder schema properties and update required array.
Puppeteer uses cosmiconfig to search for its configuration at import time. cosmiconfig walks up from CWD parsing every package.json it finds. If any package.json in the search path has invalid JSON, the strict parse-json parser throws synchronously
during module evaluation, surfacing as an uncaught exception that crashes the entire process.
- Replaced jsdom with linkedom for HTML parsing in browser tool, improving performance and reducing memory footprint.
- Removed @types/jsdom from devDependencies as jsdom is no longer used.
- Simplified HTML document parsing by removing VirtualConsole error handling and direct window cleanup.
- Fixed resource leak in browser query handler by properly disposing owned proxy elements for non-winning candidates.
- Fixed script evaluation to support async functions and await expressions in browser evaluate operations.
- Removed unused maxLines parameter from buildMutationPreviewAgainstOriginal function and simplified preview generation logic.
- Improved browser script evaluation to handle both expression and statement forms by adding fallback evaluation logic, fixing failures for certain script types.
- Migrated console.error() calls to structured logger.warn() and logger.error() throughout codebase.
- Updated os.tmpdir() import style in browser tool from destructured to namespace import.
- Removed unused import of resolveToCwd from path-utils module.
- Removed unused resolveArtifactsDir function that was not called elsewhere.
- Prefixed unused ctx parameter with underscore to indicate intentional non-usage.