@oh-my-pi/pi-coding-agent 14.9.9 → 15.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +123 -0
- package/examples/extensions/plan-mode.ts +0 -1
- package/package.json +9 -9
- package/scripts/build-binary.ts +5 -0
- package/scripts/format-prompts.ts +1 -1
- package/src/autoresearch/helpers.ts +17 -0
- package/src/autoresearch/tools/log-experiment.ts +9 -17
- package/src/autoresearch/tools/run-experiment.ts +2 -17
- package/src/capability/skill.ts +7 -0
- package/src/cli/args.ts +2 -2
- package/src/cli/list-models.ts +1 -1
- package/src/cli/shell-cli.ts +3 -13
- package/src/cli/update-cli.ts +1 -1
- package/src/cli.ts +11 -29
- package/src/commands/acp.ts +24 -0
- package/src/commands/launch.ts +6 -4
- package/src/commit/agentic/prompts/system.md +1 -1
- package/src/commit/agentic/tools/propose-changelog.ts +8 -1
- package/src/commit/analysis/conventional.ts +8 -66
- package/src/commit/map-reduce/reduce-phase.ts +6 -65
- package/src/commit/pipeline.ts +2 -2
- package/src/commit/shared-llm.ts +89 -0
- package/src/config/config-file.ts +210 -0
- package/src/config/model-equivalence.ts +8 -11
- package/src/config/model-registry.ts +13 -2
- package/src/config/model-resolver.ts +31 -4
- package/src/config/settings-schema.ts +102 -1
- package/src/config/settings.ts +1 -1
- package/src/config.ts +3 -219
- package/src/edit/index.ts +22 -1
- package/src/edit/modes/patch.ts +10 -0
- package/src/edit/modes/replace.ts +3 -0
- package/src/edit/renderer.ts +17 -1
- package/src/eval/js/context-manager.ts +1 -1
- package/src/eval/js/executor.ts +3 -0
- package/src/eval/js/shared/rewrite-imports.ts +122 -50
- package/src/eval/js/shared/runtime.ts +31 -4
- package/src/eval/js/tool-bridge.ts +43 -21
- package/src/eval/py/executor.ts +5 -0
- package/src/exa/factory.ts +2 -2
- package/src/exa/mcp-client.ts +74 -1
- package/src/exec/bash-executor.ts +5 -1
- package/src/export/html/template.generated.ts +1 -1
- package/src/export/html/template.js +0 -11
- package/src/extensibility/extensions/runner.ts +55 -2
- package/src/extensibility/extensions/types.ts +98 -221
- package/src/extensibility/hooks/types.ts +89 -314
- package/src/extensibility/shared-events.ts +343 -0
- package/src/extensibility/skills.ts +42 -1
- package/src/goals/index.ts +3 -0
- package/src/goals/runtime.ts +500 -0
- package/src/goals/state.ts +37 -0
- package/src/goals/tools/goal-tool.ts +237 -0
- package/src/hashline/anchors.ts +2 -2
- package/src/hindsight/mental-models.ts +1 -1
- package/src/internal-urls/agent-protocol.ts +1 -20
- package/src/internal-urls/artifact-protocol.ts +1 -19
- package/src/internal-urls/docs-index.generated.ts +9 -10
- package/src/internal-urls/index.ts +1 -0
- package/src/internal-urls/issue-pr-protocol.ts +577 -0
- package/src/internal-urls/registry-helpers.ts +25 -0
- package/src/internal-urls/router.ts +6 -3
- package/src/internal-urls/types.ts +22 -1
- package/src/main.ts +24 -11
- package/src/mcp/oauth-flow.ts +20 -0
- package/src/modes/acp/acp-agent.ts +412 -71
- package/src/modes/acp/acp-client-bridge.ts +152 -0
- package/src/modes/acp/acp-event-mapper.ts +180 -15
- package/src/modes/acp/terminal-auth.ts +37 -0
- package/src/modes/components/assistant-message.ts +14 -8
- package/src/modes/components/bash-execution.ts +24 -63
- package/src/modes/components/custom-message.ts +14 -40
- package/src/modes/components/eval-execution.ts +27 -57
- package/src/modes/components/execution-shared.ts +102 -0
- package/src/modes/components/hook-message.ts +17 -49
- package/src/modes/components/mcp-add-wizard.ts +26 -5
- package/src/modes/components/message-frame.ts +88 -0
- package/src/modes/components/model-selector.ts +1 -1
- package/src/modes/components/read-tool-group.ts +29 -1
- package/src/modes/components/session-observer-overlay.ts +6 -2
- package/src/modes/components/session-selector.ts +1 -1
- package/src/modes/components/status-line/segments.ts +55 -4
- package/src/modes/components/status-line/types.ts +4 -0
- package/src/modes/components/status-line.ts +28 -10
- package/src/modes/components/tool-execution.ts +7 -8
- package/src/modes/controllers/command-controller-shared.ts +108 -0
- package/src/modes/controllers/command-controller.ts +27 -10
- package/src/modes/controllers/event-controller.ts +60 -18
- package/src/modes/controllers/extension-ui-controller.ts +8 -2
- package/src/modes/controllers/input-controller.ts +85 -39
- package/src/modes/controllers/mcp-command-controller.ts +56 -61
- package/src/modes/controllers/ssh-command-controller.ts +18 -57
- package/src/modes/interactive-mode.ts +675 -39
- package/src/modes/print-mode.ts +16 -86
- package/src/modes/rpc/rpc-mode.ts +30 -88
- package/src/modes/runtime-init.ts +115 -0
- package/src/modes/theme/defaults/dark-poimandres.json +2 -0
- package/src/modes/theme/defaults/light-poimandres.json +2 -0
- package/src/modes/theme/theme.ts +18 -6
- package/src/modes/types.ts +20 -5
- package/src/modes/utils/context-usage.ts +13 -13
- package/src/modes/utils/ui-helpers.ts +25 -6
- package/src/plan-mode/approved-plan.ts +35 -1
- package/src/prompts/agents/designer.md +5 -5
- package/src/prompts/agents/explore.md +7 -7
- package/src/prompts/agents/init.md +9 -9
- package/src/prompts/agents/librarian.md +14 -14
- package/src/prompts/agents/plan.md +4 -4
- package/src/prompts/agents/reviewer.md +5 -5
- package/src/prompts/agents/task.md +10 -10
- package/src/prompts/commands/orchestrate.md +2 -2
- package/src/prompts/compaction/branch-summary.md +3 -3
- package/src/prompts/compaction/compaction-short-summary.md +7 -7
- package/src/prompts/compaction/compaction-summary-context.md +1 -1
- package/src/prompts/compaction/compaction-summary.md +5 -5
- package/src/prompts/compaction/compaction-turn-prefix.md +3 -3
- package/src/prompts/compaction/compaction-update-summary.md +11 -11
- package/src/prompts/goals/goal-budget-limit.md +16 -0
- package/src/prompts/goals/goal-continuation.md +28 -0
- package/src/prompts/goals/goal-mode-active.md +23 -0
- package/src/prompts/memories/consolidation.md +2 -2
- package/src/prompts/memories/read-path.md +1 -1
- package/src/prompts/memories/stage_one_input.md +1 -1
- package/src/prompts/memories/stage_one_system.md +5 -5
- package/src/prompts/review-request.md +4 -4
- package/src/prompts/system/agent-creation-architect.md +17 -17
- package/src/prompts/system/agent-creation-user.md +2 -2
- package/src/prompts/system/commit-message-system.md +2 -2
- package/src/prompts/system/custom-system-prompt.md +2 -2
- package/src/prompts/system/eager-todo.md +6 -6
- package/src/prompts/system/handoff-document.md +1 -1
- package/src/prompts/system/plan-mode-active.md +25 -24
- package/src/prompts/system/plan-mode-approved.md +4 -4
- package/src/prompts/system/plan-mode-compact-instructions.md +16 -0
- package/src/prompts/system/plan-mode-reference.md +2 -2
- package/src/prompts/system/plan-mode-subagent.md +8 -8
- package/src/prompts/system/plan-mode-tool-decision-reminder.md +3 -3
- package/src/prompts/system/project-prompt.md +4 -4
- package/src/prompts/system/subagent-system-prompt.md +7 -7
- package/src/prompts/system/subagent-yield-reminder.md +4 -4
- package/src/prompts/system/system-prompt.md +72 -71
- package/src/prompts/system/ttsr-interrupt.md +1 -1
- package/src/prompts/tools/apply-patch.md +1 -1
- package/src/prompts/tools/ast-edit.md +3 -3
- package/src/prompts/tools/ast-grep.md +3 -3
- package/src/prompts/tools/bash.md +6 -0
- package/src/prompts/tools/browser.md +3 -3
- package/src/prompts/tools/checkpoint.md +3 -3
- package/src/prompts/tools/find.md +3 -3
- package/src/prompts/tools/github.md +2 -5
- package/src/prompts/tools/goal.md +13 -0
- package/src/prompts/tools/hashline.md +104 -116
- package/src/prompts/tools/image-gen.md +3 -3
- package/src/prompts/tools/irc.md +1 -1
- package/src/prompts/tools/lsp.md +2 -2
- package/src/prompts/tools/patch.md +6 -6
- package/src/prompts/tools/read.md +8 -7
- package/src/prompts/tools/replace.md +5 -5
- package/src/prompts/tools/resolve.md +6 -5
- package/src/prompts/tools/retain.md +1 -1
- package/src/prompts/tools/rewind.md +2 -2
- package/src/prompts/tools/search.md +2 -2
- package/src/prompts/tools/ssh.md +2 -2
- package/src/prompts/tools/task.md +12 -6
- package/src/prompts/tools/web-search.md +2 -2
- package/src/prompts/tools/write.md +3 -3
- package/src/sdk.ts +81 -17
- package/src/session/agent-session.ts +656 -125
- package/src/session/blob-store.ts +36 -3
- package/src/session/client-bridge.ts +81 -0
- package/src/session/compaction/errors.ts +31 -0
- package/src/session/compaction/index.ts +1 -0
- package/src/session/messages.ts +67 -2
- package/src/session/session-manager.ts +131 -12
- package/src/session/session-storage.ts +33 -15
- package/src/session/streaming-output.ts +309 -13
- package/src/slash-commands/acp-builtins.ts +46 -0
- package/src/slash-commands/builtin-registry.ts +717 -116
- package/src/slash-commands/helpers/context-report.ts +39 -0
- package/src/slash-commands/helpers/format.ts +23 -0
- package/src/slash-commands/helpers/marketplace-manager.ts +25 -0
- package/src/slash-commands/helpers/mcp.ts +532 -0
- package/src/slash-commands/helpers/parse.ts +85 -0
- package/src/slash-commands/helpers/ssh.ts +193 -0
- package/src/slash-commands/helpers/todo.ts +279 -0
- package/src/slash-commands/helpers/usage-report.ts +91 -0
- package/src/slash-commands/types.ts +126 -0
- package/src/ssh/ssh-executor.ts +5 -0
- package/src/system-prompt.ts +4 -2
- package/src/task/executor.ts +27 -10
- package/src/task/index.ts +20 -1
- package/src/task/render.ts +27 -18
- package/src/task/types.ts +4 -0
- package/src/tools/ast-edit.ts +21 -120
- package/src/tools/ast-grep.ts +21 -119
- package/src/tools/bash-interactive.ts +9 -1
- package/src/tools/bash.ts +203 -6
- package/src/tools/browser/attach.ts +3 -3
- package/src/tools/browser/launch.ts +81 -18
- package/src/tools/browser/registry.ts +1 -5
- package/src/tools/browser/tab-supervisor.ts +51 -14
- package/src/tools/conflict-detect.ts +21 -10
- package/src/tools/eval.ts +3 -1
- package/src/tools/fetch.ts +15 -4
- package/src/tools/find.ts +39 -39
- package/src/tools/gh-renderer.ts +0 -12
- package/src/tools/gh.ts +689 -182
- package/src/tools/github-cache.ts +548 -0
- package/src/tools/index.ts +25 -11
- package/src/tools/inspect-image.ts +3 -10
- package/src/tools/output-meta.ts +176 -37
- package/src/tools/path-utils.ts +125 -2
- package/src/tools/read.ts +605 -239
- package/src/tools/render-utils.ts +92 -0
- package/src/tools/renderers.ts +2 -0
- package/src/tools/resolve.ts +72 -44
- package/src/tools/search.ts +120 -186
- package/src/tools/write.ts +67 -10
- package/src/tui/code-cell.ts +70 -2
- package/src/utils/file-mentions.ts +1 -1
- package/src/utils/image-loading.ts +7 -3
- package/src/utils/image-resize.ts +32 -43
- package/src/vim/parser.ts +0 -17
- package/src/vim/render.ts +1 -1
- package/src/vim/types.ts +1 -1
- package/src/web/search/providers/gemini.ts +35 -95
- package/src/prompts/tools/exit-plan-mode.md +0 -6
- package/src/tools/exit-plan-mode.ts +0 -97
- package/src/utils/fuzzy.ts +0 -108
- package/src/utils/image-convert.ts +0 -27
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,129 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [15.0.1] - 2026-05-14
|
|
6
|
+
### Breaking Changes
|
|
7
|
+
|
|
8
|
+
- Removed the dedicated `exit_plan_mode` tool and its prompt, requiring plan-mode completion to use the existing `resolve` tool path instead
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Added optional `extra` metadata object to the `resolve` tool so callers can pass context-specific payloads, including plan approval titles
|
|
13
|
+
- Added `hide: true` frontmatter option for skill `SKILL.md` files. Hidden skills are still loaded and remain reachable via `skill://<name>` URLs and (when enabled) `/skill:<name>` slash commands, but are omitted from the rendered system prompt's `<skills>` listing so the model won't auto-discover them. Use for skills the user opts into explicitly rather than ones the model should pick up from descriptions.
|
|
14
|
+
- Added middle elision for streaming tool outputs (bash, ssh, python, js eval) and post-execution tool result spill. When `tools.artifactHeadBytes` is set (default 20 KB), large outputs now keep both the first N KB and the last N KB with an inline `[… N lines elided (M KB) …]` marker between them, instead of dropping everything before the trailing tail. Setting `tools.artifactHeadBytes = 0` reverts to the previous tail-only behavior. The full output is still mirrored to the session artifact (`artifact://<id>`) regardless of elision mode. Exposes `truncateMiddle` and `formatMiddleElisionMarker` from `@oh-my-pi/pi-coding-agent/session/streaming-output`, extends `OutputSinkOptions` with `headBytes`, and adds `direction: "middle"` plus `headRange` / `tailRange` / `elidedLines` / `elidedBytes` to `TruncationMeta`.
|
|
15
|
+
- Added per-line column cap shared across streaming tool outputs (`bash`, `ssh`, `python`, `js eval`) and the `read` tool. Lines wider than `tools.outputMaxColumns` bytes (default **768**) are ellipsis-truncated at write time and remaining bytes up to the next `\n` are dropped — bounded memory even on multi-MB single-line outputs (e.g. `cat /dev/urandom`). The cap lives on `OutputSink` as the new `maxColumns` option, persists state across chunk boundaries so split-mid-line writes still respect the budget, and exposes `columnDroppedBytes` / `columnTruncatedLines` on `OutputSummary`. Middle-elision byte math subtracts column drops so the "elided from middle" count stays honest. `read` reuses the same setting but trims its already-collected lines via `truncateLine`. Skipped when the read selector is `:raw`. The artifact file (`artifact://<id>`) keeps the full uncapped stream. Set `tools.outputMaxColumns = 0` to disable.
|
|
16
|
+
- Added Bun HTTP/2 fetch opt-in. Dev scripts (`bun run dev`, `bun run stats`) now pass `bun --experimental-http2-fetch` so every `fetch()` advertises `h2` in the TLS ALPN list and falls back to HTTP/1.1 when the server doesn't select it. Multiplexing collapses parallel requests to the same origin onto one TLS connection. For the installed `omp` binary, export `BUN_FEATURE_FLAG_EXPERIMENTAL_HTTP2_CLIENT=1` in your shell to enable the same behavior (the flag has to be set before Bun starts; `process.env` from inside JS is too late). Requires Bun **1.3.14**.
|
|
17
|
+
- Added per-subagent cost display (`$X.XX` in the task progress tree and the session-observer stats line). Cost is accumulated incrementally from `message_end` events and shown only when non-zero, using the `statusLineCost` theme color. Providers that do not report per-turn cost data (e.g. subscription/OAuth usage) continue to show nothing.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- Changed plan-mode completion to use `resolve { action: "apply", reason, extra: { title } }` to request plan approval rather than calling `exit_plan_mode`
|
|
22
|
+
- Changed resolve pending-action previews to trim and truncate long `reason` text for cleaner status-line rendering
|
|
23
|
+
- Raised the image downscaling default JPEG quality from 75 to 80 in `resizeImage` output generation
|
|
24
|
+
- Changed image resize metadata notes from coordinate-scale hints to a simple `Image resized from <original> to <displayed>` message and hide the note when the resized dimensions are unchanged
|
|
25
|
+
- Removed `utils/image-convert.ts` and its `convertToPng` helper; callers now inline `new Bun.Image(bytes).png().toBase64()` from [`Bun.Image`](https://bun.com/docs/runtime/image) (Bun 1.3.14+).
|
|
26
|
+
- Changed image decode/resize/encode in `utils/image-resize.ts` from the native `PhotonImage` binding to [`Bun.Image`](https://bun.com/docs/runtime/image). Same PNG/JPEG/WebP quality+dimension ladder, but pipelines run off-thread on Bun's statically-linked codecs with no native-addon round-trip. Bumped the minimum Bun runtime requirement to **1.3.14**.
|
|
27
|
+
- Changed `search` pagination in multi-file scopes so `skip` now skips entire files and pages results in groups of up to 20 files, with output guiding the next `skip` value via `Showing files X-Y of N`
|
|
28
|
+
- Changed multi-file search result selection to cap each file at 20 matches and round-robin across files, so one noisy file no longer suppresses visibility of hits in other files and truncation now reports per-file limits
|
|
29
|
+
- Changed search truncation metadata/renderer output from match/result-based limits to file-based limits (`fileLimitReached`, `perFileLimitReached`) and updated truncation labels accordingly
|
|
30
|
+
- Lowered `read.defaultLimit` default from `500` to `300` lines, and split the per-range context padding into asymmetric `RANGE_LEADING_CONTEXT_LINES = 1` / `RANGE_TRAILING_CONTEXT_LINES = 3` (was symmetric `RANGE_CONTEXT_LINES = 3`). Replay analysis over post-summarizer sessions (`scripts/session-stats/optimize_read_config.py`) showed that bare-path reads are over-provisioned at the median (file p50 = 220 lines) and that most follow-up reads are disjoint hops rather than adjacent extensions — so a smaller default plus narrower leading context reclaims tokens without measurably changing first-cover rate. Trailing context stays at 3 lines to keep anchor-stale recovery on narrow reads. Explicit `read.defaultLimit` overrides in settings are honoured unchanged.
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
|
|
34
|
+
- Fixed abrupt process termination data loss during session persistence by moving steady-state session writes to a synchronous path that writes each entry to the kernel page cache before returning
|
|
35
|
+
- Fixed `--help` startup to avoid a config/model-registry load cycle so the root CLI help command now exits successfully in a clean environment
|
|
36
|
+
- Queued `/skill:<name> [args]` invocations now show as compact `Steer: /skill:<name> [args]` / `Follow-up: /skill:<name> [args]` chips in the pending-messages bar and disappear when the agent consumes the queued message (parity with plain-text steer/follow-up). Previously the queued skill was invisible while queued and rendered as a full skill block at consumption with no chip ever appearing.
|
|
37
|
+
- Plan-mode "Approve and compact context" no longer surfaces a red "Operation aborted" line on the plan-mode assistant message; the silent transition into compaction now renders cleanly on both live and replay paths. Real user-cancel aborts on unrelated turns and the existing "Compaction cancelled" path are unchanged.
|
|
38
|
+
- Auto-recover conflict-resolution `write`/`read` paths that the agent malformed as `<file>:conflict://<N>` (or `<file>:conflict://*`) by mixing the `:conflicts` read selector with the `conflict://` scheme. The stripped `<file>:` prefix is stored on `ParsedConflictUri.recoveredPrefix` and, for writes, surfaces as a trailing note in the result text so the agent learns the correct shape. Clean `conflict://…` URIs are unchanged.
|
|
39
|
+
- Fixed hashline edit renderer leaving a stray `@` in the displayed file path when the agent emitted a canonical `@@ PATH` header (or any `@`-run longer than one). Titles like `Edit: @ packages/foo.ts` now render as `Edit: packages/foo.ts`, matching the actual parser in `hashline/input.ts` which already strips every leading `@` before resolving the path. Purely cosmetic — the edit itself was always routed to the correct file.
|
|
40
|
+
- Fixed model contextWindow and maxTokens defaulting to `UNK_CONTEXT_WINDOW` (222222) / `UNK_MAX_TOKENS` (8888) when cached or freshly-discovered provider models replace bundled models through `ModelRegistry.#mergeResolvedModels`. The merge now preserves the bundled model's values when the replacement only has sentinel fallbacks.
|
|
41
|
+
- Fixed headless `browser.open` tab startup on slow Chromium target enumeration by making worker-side stealth user-agent target setup selective, bounded, and best-effort for non-active targets. Worker startup errors are now surfaced directly instead of degrading into the generic tab worker initialization timeout.
|
|
42
|
+
- Fixed token display for sessions and subagents inflating far beyond the context window. `token_total` status-line segment and the subagent overlay token counter now show `input + output + cacheWrite` instead of `input + output + cacheRead + cacheWrite`. With prompt caching, `cacheRead` per turn equals the full cached context — summing it across all turns produces a cumulative total that is N×context_size (e.g. a 5-turn session with a 1 M-token context reported ~5 M tokens). Cache activity is still visible via the dedicated `cache_read`/`cache_write` status-line segments; billing cost is unaffected.
|
|
43
|
+
- Fixed ACP clients missing `config_option_update` notifications when the thinking level changed via any path other than the client's own `session/set_session_config_option` call (slash commands, model auto-adjust, extension UI). `AgentSession` now emits a `thinking_level_changed` event from `setThinkingLevel`, and `AcpAgent` subscribes to each managed session for the session's lifetime and pushes a fresh `config_option_update` whenever the effective level changes — independent of any active prompt turn. The subscription is installed inside `#scheduleBootstrapUpdates`'s 50 ms timer so it shares the same race guard that prevents Zed's `Received session notification for unknown session` drop when notifications fire before `session/new` (or fork) returns; the pre-bootstrap thinking level is reported in the response's `configOptions`. The `session/set_session_config_option` handler keeps its own push only when the subscription has not yet been installed, so client-driven thinking changes still notify pre-bootstrap, post-bootstrap they flow through the subscription exactly once. Subscriptions are released in `#disposeSessionRecord`.
|
|
44
|
+
- Fixed MCP OAuth refresh failing with `HTTP 401 invalid_client` for servers that require Dynamic Client Registration (RFC 7591) and have no `oauth.clientId` configured (e.g. `mcp.linear.app`). `MCPOAuthFlow` registered a fresh public PKCE client on each authorize and discarded the issued `client_id` once the flow object went out of scope; refresh then called the provider's `/token` endpoint without a `client_id`. The flow now exposes `resolvedClientId` / `registeredClientSecret` getters, `MCPCommandController#handleOAuthFlow` returns them alongside `credentialId`, and both the initial-connect and `/mcp reauth` paths persist them into `auth.{clientId,clientSecret}` (used at refresh) and `oauth.{clientId,clientSecret}` (used by subsequent `/mcp reauth` to skip re-registration). The `MCPAddWizard` `onOAuth` callback type is now `Promise<MCPAddWizardOAuthResult>` and `#launchOAuthFlow` folds the registered credentials into wizard state. Servers with a statically-configured `oauth.clientId` (Notion, Slack, Datadog) are unaffected — `#tryRegisterClient` short-circuits and the write-back is a no-op. ([#1061](https://github.com/can1357/oh-my-pi/pull/1061) by [@ldx](https://github.com/ldx)).
|
|
45
|
+
|
|
46
|
+
## [15.0.0] - 2026-05-13
|
|
47
|
+
### Breaking Changes
|
|
48
|
+
|
|
49
|
+
- Removed `op: issue_view` and `op: pr_view` from the `github` tool. Read single issues/PRs via the `read` tool against `issue://<N>` / `pr://<N>` (or the long form `issue://<owner>/<repo>/<N>` / `pr://<owner>/<repo>/<N>`); append `?comments=0` to drop the comments section. The `issue` and `comments` parameters were removed from the tool schema since no remaining op consumes them. Mutating ops (`pr_create`, `pr_checkout`, `pr_push`), `repo_view`, `search_*`, and `run_watch` are unchanged.
|
|
50
|
+
- Removed `op: pr_diff` (along with the `nameOnly` and `exclude` schema fields) from the `github` tool. Read PR diffs through the new `pr://` URL family: `pr://<N>/diff` for the changed-file listing, `pr://<N>/diff/<i>` for a single file slice (1-indexed), and `pr://<N>/diff/all` for the verbatim unified diff. Long-form `pr://<owner>/<repo>/<N>/diff[/…]` works the same way. All three variants share one `gh pr diff` invocation through a new `pr-diff` cache row, so the listing and per-file slices reconstruct from cached bytes without re-shelling. Diff content is served as `text/plain` so the `read` tool's line selectors (e.g. `pr://<N>/diff/all:200-400`) page the cached output without falsely advertising hashline anchors.
|
|
51
|
+
- Renamed ACP custom extension methods from `omp/*` to `_omp/*` to comply with the ACP spec's `_`-prefix requirement for non-spec methods; existing callers must update method names
|
|
52
|
+
|
|
53
|
+
### Added
|
|
54
|
+
|
|
55
|
+
- Added markdown rendering for `read` results when content type is `text/markdown`, so GitHub internal-URL outputs are shown as formatted markdown instead of plain code blocks
|
|
56
|
+
- Added `pr://<N>/diff`, `pr://<N>/diff/<i>`, and `pr://<N>/diff/all` internal-URL shapes covering changed-file listings, per-file slices, and the full unified diff. They share one `pr-diff` SQLite cache row with the same TTL knobs as `pr://<N>` views (`github.cache.softTtlSec` / `github.cache.hardTtlSec` / `github.cache.enabled`). Single PR views now advertise the diff entry point via a `Diff: pr://<owner>/<repo>/<N>/diff` note. Cache schema bumped to `user_version = 3`; older rows are dropped on first open to add credential-scoped keys and relax the `kind` CHECK constraint.
|
|
57
|
+
- Added `issue://` / `pr://` internal-URL schemes that share a SQLite-backed cache with the rest of the `github` tool. Single-item reads (`issue://<N>`, `issue://<owner>/<repo>/<N>`) return rendered markdown and within `github.cache.softTtlSec` (default 5 minutes) skip the `gh` round-trip entirely; within `github.cache.hardTtlSec` (default 7 days) the cached row is returned and a background refresh is scheduled. Root and repo-scoped reads (`issue://`, `pr://owner/repo`) issue a live `gh issue list` / `gh pr list` for browsing, supporting `?state=open|closed|all` for issues, `?state=open|closed|merged|all` for PRs, and `?limit=`, `?author=`, `?label=` query params. Rendered output lands in `~/.omp/cache/github-cache.db` (override via `OMP_GITHUB_CACHE_DB`); disable the cache entirely with `github.cache.enabled = false`. Cwd→default-repo lookups (`gh repo view`) are memoized per-process.
|
|
58
|
+
- Added new `Approve and compact context` choice to the ExitPlanMode approval selector. Sits between `Approve and execute` (purge session) and `Approve and keep context` (full transcript) — runs `/compact` on the plan-mode transcript with a planning-specific summarization hint, then dispatches the plan-approved execution turn so it lands on a fresh cache anchor with the summarized rationale carried over. Cancelling the compaction (Esc or any other abort source) defers the execution dispatch and surfaces a warning so the operator can resubmit manually; non-abort failures proceed best-effort.
|
|
59
|
+
- Added `CompactionCancelledError` typed sentinel and `CompactionOutcome` (`"ok" | "cancelled" | "failed"`) return type to `@oh-my-pi/pi-coding-agent/session/compaction`. `CommandController.executeCompaction` and `handleCompactCommand` now return the outcome instead of `void` so callers can discriminate user-driven aborts from generic failures without inspecting error messages.
|
|
60
|
+
- Added a `credential_disabled` extension event so extensions can subscribe via `pi.on("credential_disabled", handler)` and react when `AuthStorage` automatically soft-disables a credential (e.g. OAuth `invalid_grant`). Replaces the current `agent_end` errorMessage regex pattern downstream extensions have to match against. Handler payload is `{ type, provider, disabledCause }`. `createAgentSession()` subscribes the per-session extension runner to the shared `AuthStorage` via `authStorage.onCredentialDisabled(...)` at the very top of session creation — before any startup model probes run — so events fire on every disable regardless of whether the embedder also has a constructor `onCredentialDisabled` handler attached. The SDK forwards through `ExtensionRunner.emitCredentialDisabled(event)`, which buffers events until `runner.initialize(...)` runs in the mode controller and then flushes them through `emit()` so extension handlers see populated UI/runtime context (rather than the constructor's no-op default with `hasUI=false`, an unset model, and no-op runtime actions). On `session.dispose()` the subscription is unsubscribed; the embedder's constructor-attached listener keeps firing through its own permanent subscription. The outer `createAgentSession()` catch also releases the subscription if startup throws before the dispose-wrap is wired, so repeated retries don't accumulate dead listeners.
|
|
61
|
+
- Added `omp acp` subcommand for launching as an ACP (Agent Client Protocol) server over stdio
|
|
62
|
+
- Added explicit `type` discriminators to ACP `initialize` auth methods, including a `terminal` setup method gated on `clientCapabilities.auth.terminal`
|
|
63
|
+
- Added ACP equivalents for the remaining TUI slash commands (`/jobs`, `/changelog`, `/dump`, `/copy`, `/hotkeys`, `/extensions`, `/agents`, `/model`, `/plan`, `/loop`, `/btw`, `/login`, `/logout`, `/resume`, `/tree`, `/branch`, `/new`, `/drop`, `/handoff`, `/fork`, `/session delete`, `/export`, `/share`, `/todo`, `/memory`, `/move`, `/mcp`, `/ssh`, `/marketplace`, `/plugins`) so ACP clients reach feature parity with the TUI for non-interactive flows
|
|
64
|
+
- Added ACP `plan` mode: when `plan.enabled` setting is on, ACP `session/new`/`load`/`resume`/`fork` advertise a `plan` mode alongside `default`; `session/set_mode` toggles plan-mode state so the next agent turn injects the plan-mode system prompt
|
|
65
|
+
- Added ACP `ClientBridge` abstraction (`packages/coding-agent/src/session/client-bridge.ts`) that routes tool I/O through the connected client when capabilities are advertised at `initialize`; populated from `AgentSideConnection` in ACP mode
|
|
66
|
+
- Added ACP `terminal/*` routing for `bash`: when the client advertises `terminal: true`, the tool creates a client-side terminal, embeds its `terminalId` on the live tool card, polls output, and releases the handle on exit or abort
|
|
67
|
+
- Added ACP `fs/read_text_file` and `fs/write_text_file` routing for the `read` and `write` tools: when the client advertises `fs.readTextFile` / `fs.writeTextFile`, plain-text reads/writes go through the editor (surfacing unsaved buffer content and letting the editor track agent writes); falls back to disk only for reads, throws on bridge write failures
|
|
68
|
+
- Added ACP `session/request_permission` gate around `bash`, `edit`, `write`, and `ast_edit` when an ACP client is connected; remembers `allow_always` / `reject_always` decisions per tool for the session lifetime
|
|
69
|
+
- Added `diff` `ToolCallContent` emission for edit tool results: per-file `oldText`/`newText` is threaded through `EditToolPerFileResult` / `EditToolDetails` so ACP clients can render inline diffs
|
|
70
|
+
- Added richer ACP `StopReason` mapping (`max_tokens`, `refusal`, `cancelled`) derived from the last assistant message's internal stop reason; previously only `end_turn`/`cancelled` were emitted
|
|
71
|
+
- Added `_meta.messageCount` and `_meta.size` on `session/list` `SessionInfo` entries
|
|
72
|
+
- Added ACP `tool_call_update` `locations` refresh from in-flight tool args and final result details so clients can "follow along" multi-file edits in real time
|
|
73
|
+
|
|
74
|
+
### Changed
|
|
75
|
+
|
|
76
|
+
- Changed issue and pull-request list entries to link to repository-qualified URLs (for example `issue://owner/repo/<N>`) so list items open correctly outside the default repo
|
|
77
|
+
- Aligned prompt instruction language by defining `NEVER` and `AVOID` as strict aliases for `MUST NOT` and `SHOULD NOT` in the system prompt, and standardized agent, tool, and system prompt templates to use those terms consistently
|
|
78
|
+
- Changed `--mode acp` to apply the same stdout-quiet overrides as `--mode rpc` so no banner or status text leaks into the JSON-RPC channel
|
|
79
|
+
- Changed ACP startup to no longer require a configured model so registry validators and clients can complete `initialize` and `authenticate` before any model is selected
|
|
80
|
+
### Fixed
|
|
81
|
+
|
|
82
|
+
- Deferred flushing of buffered `credential_disabled` events during extension runner initialization to a microtask so handler failures are now routed through `onError()` registrations made immediately after `initialize()`, preserving extension error reporting
|
|
83
|
+
- Fixed `eval` tool dynamic `await import("./relative.ts")` calls failing with `Cannot find module ... from .../eval/js/shared/runtime.ts`. The static-import rewriter only handled `ImportDeclaration` nodes, so dynamic-import call expressions resolved their specifier against the worker module's URL instead of the session cwd. The rewriter now walks the full AST and additionally swaps `import` callees in `CallExpression` nodes for `__omp_import__`, which forwards the optional options bag verbatim to native `import()` so `{ with: { type: "json" } }` round-trips. Renamed `rewriteStaticImports` → `rewriteImports`.
|
|
84
|
+
- Fixed `pr://<owner>/<repo>/diff` URLs for repositories named `diff` to continue resolving to PR list lookups instead of being parsed as short-form diff links
|
|
85
|
+
- Fixed `issue://<N>/diff` short form previously misparsing as a repo named `<N>/diff` and surfacing a confusing GraphQL "Could not resolve to a Repository" error. The numeric-host disambiguation that already routed `pr://<N>/diff` through the diff path now applies to both schemes, so `issue://<N>/diff[/…]` falls through to the existing "Issue views do not have a diff; use pr://<owner>/<repo>/<n>/diff for pull requests." rejection — matching the long-form `issue://<owner>/<repo>/<N>/diff` behavior. `<scheme>://<owner>/diff` listings for a repo literally named `diff` are unchanged.
|
|
86
|
+
- Fixed PR unified diff parsing so changed-file headers with quoted paths (such as paths containing spaces) are now detected correctly and hunk content lines beginning with `---`/`+++` are counted in additions/deletions
|
|
87
|
+
- Fixed GitHub view caching to account for active credential identity and avoid serving cached issue/PR data across different account/token contexts
|
|
88
|
+
- Fixed `read` call tracking so calls without an explicit path or URL target no longer appear as regular file reads in the execution tracker
|
|
89
|
+
- Fixed `createAgentSession()` subscribing the `credential_disabled` bridge to a freshly discovered `AuthStorage` orphan when an embedder supplied only `options.modelRegistry` (no `options.authStorage`). Refresh failures emitted by `modelRegistry.getApiKey()` flow through `modelRegistry.authStorage`, so a divergent local instance silently swallowed every disable event and also leaked into the `mcpManager` and session result. The SDK now reconciles `authStorage` to `modelRegistry.authStorage` up front and rejects mismatched `options.authStorage`/`options.modelRegistry.authStorage` pairs at session construction.
|
|
90
|
+
- Fixed `runSubagent` (subagent task executor) carrying the same latent `AuthStorage`/`ModelRegistry` divergence as `createAgentSession()`: when only `options.modelRegistry` was supplied, the executor previously fell through to a fresh `discoverAuthStorage()` and handed that orphan into `createAgentSession()` alongside a registry whose `.authStorage` was a different instance. The executor now reconciles to `modelRegistry.authStorage` before any further work and rejects mismatched `options.authStorage`/`options.modelRegistry.authStorage` pairs the same way the SDK does, so subagents can no longer silently observe a different storage view than their parent.
|
|
91
|
+
- Fixed `github` tool's `search_issues`/`search_prs`/`search_code`/`search_commits`/`search_repos` ops always returning 0 results when the query contained more than one qualifier (e.g. `is:merged is:pr`, `is:open author:foo`). `gh search …` since the `advanced_search=true` rollout in gh 2.92 silently wraps multi-token positional queries in parentheses and quotes everything after the first qualifier as that qualifier's value (`is:"merged is:pr"`), which GitHub then matches as a literal state filter that no PR can satisfy. The tool now calls `gh api -X GET /search/<endpoint> -f q=… -F per_page=…` directly so the qualifiers reach GitHub's search API verbatim. `is:issue`/`is:pr` and `repo:<owner>/<repo>` are appended internally to preserve the previous CLI-flag behavior; the user-facing query string in the formatted output is unchanged. `state` for merged PRs is derived from `pull_request.merged_at` so the rendered `State:` line stays `merged`/`closed`/`open` as before.
|
|
92
|
+
- Fixed `read` tool renderer rendering failed reads with a success check (`✓`) and styling the error message as file content while the surrounding box was red. The renderer now branches on `isError` for both file and URL paths: header shows `✘ Read <path>` with a proper error icon and the underlying message is rendered as an error line. `renderReadUrlResult` got the same treatment so failed URL reads also get the cross icon instead of falling through to the `"No response data"` Text fallback. Mirrors the `bash`/`find` renderer error pattern.
|
|
93
|
+
- Fixed ACP mode to advertise and handle non-TUI builtin slash commands and `/skill:<name>` commands
|
|
94
|
+
- Fixed ACP `session/resume` and `session/close` to dispatch correctly under SDK 0.21 by renaming `unstable_resumeSession` / `unstable_closeSession` to the stable `resumeSession` / `closeSession` method names the SDK now routes to
|
|
95
|
+
- Fixed ACP `tool_call` / `tool_call_update` `locations` to always emit absolute paths (resolved against the session cwd) so editor clients can reliably open or focus the referenced file
|
|
96
|
+
- Fixed ACP edit `diff` metadata for moves to point at the destination path rather than the now-deleted source so post-edit "open file" actions land on the new file
|
|
97
|
+
- Fixed ACP `session/request_permission` `locations` to be absolute and to honor the `requestPermission` capability bit instead of only checking for the method, matching the read/write/bash capability gating
|
|
98
|
+
- Fixed ACP `authenticate` to reject `methodId` values that were not advertised by `initialize` so malformed clients fail fast instead of being treated as authenticated
|
|
99
|
+
- Fixed ACP mode changes made via `session/set_session_config_option` (`MODE_CONFIG_ID`) to also emit a `current_mode_update` notification, matching `session/set_mode` so clients tracking `modes.currentModeId` stay in sync
|
|
100
|
+
- Fixed `/model` ACP builtin to emit a `config_option_update` after switching models so clients show the new model in config selectors immediately
|
|
101
|
+
- Fixed `/mcp list` (ACP) to redact query strings and userinfo from server URLs before emitting them, so API keys embedded in URLs (e.g. `?exaApiKey=…`) are not leaked to clients
|
|
102
|
+
- Fixed `/mcp test|resources|prompts` (ACP) to wire the auth storage before `prepareConfig` so OAuth-backed MCP servers can refresh tokens and inject `Authorization` headers
|
|
103
|
+
- Fixed `/mcp list`, `/mcp test`, `/mcp resources`, `/mcp prompts`, `/mcp enable`, and `/mcp disable` (ACP) to preserve project-over-user precedence when the same server name is defined in both scopes, matching the runtime capability merge so toggling the duplicated name flips the effective entry
|
|
104
|
+
- Fixed `/ssh add --port` parsing to reject non-integer values (e.g. `22oops`) instead of silently coercing them via `Number.parseInt`
|
|
105
|
+
- Fixed `/ssh list` to deduplicate hosts shared between project and user scopes, listing project entries first to match capability-loader precedence
|
|
106
|
+
- Fixed `/export` (ACP) to reject clipboard aliases (`--copy`, `clipboard`, `copy`) instead of using them as the output filename
|
|
107
|
+
- Fixed ACP builtin commands (`/compact`, `/force`, `/move`, `/browser`) to surface underlying failures via `output()` instead of swallowing them
|
|
108
|
+
- Fixed `/session save|delete` (ACP) to route through the active `SessionManager` so the persist writer is consulted and stale storage references are removed
|
|
109
|
+
- Fixed `/reload-plugins`, `/marketplace install|uninstall|upgrade`, and `/plugins enable|disable` (ACP) to refresh slash command registries and emit `available_commands_update` after plugin state changes
|
|
110
|
+
- Fixed ACP `usage()` text emission to be awaited so help and error output is not dropped or reordered when commands return immediately
|
|
111
|
+
- Fixed ACP `bash` tool to release the client terminal handle on `terminal/output` or `waitForExit` failures, and to race output polling against abort so a stuck RPC cannot delay cancellation
|
|
112
|
+
- Fixed ACP `resource` content blocks with `image/*` MIME types to be routed into the LLM `images` array instead of being dropped as opaque blobs
|
|
113
|
+
- Fixed `pr://` and `issue://` URLs accepting empty, `.`, or `..` path segments. `pr://owner//77`, `pr://owner/repo/77/diff//2`, and `pr://owner/../77/diff` previously slipped past the `.filter(Boolean)` split and were forwarded to `gh`; now they throw `Invalid <scheme>:// URL: empty or unsafe path segment` before any subprocess work.
|
|
114
|
+
- Fixed `read` of `issue://` / `pr://` URLs ignoring the read tool's `AbortSignal`. Aborting a long `pr://<N>/diff/all` or stale issue fetch now propagates into the resolver and short-circuits at the handler entry; previously the `gh` round-trip and cache write ran to completion.
|
|
115
|
+
- Fixed `read <path>:raw` (and the `raw: true` arg) still rendering markdown internal-URL content through the formatted markdown renderer. The TUI now respects the raw selector and falls back to the code-cell renderer so verbatim bytes are shown when requested.
|
|
116
|
+
- Fixed `eval` tool JS cells crashing with a `structuredClone` error when an awaited final expression returned a non-cloneable value (module namespace, function, symbol, etc.). `displayValue` now falls back to a text representation and logs at debug instead of throwing.
|
|
117
|
+
- Fixed `eval` tool JS rewriter missing the final expression when followed by trailing empty statements (e.g. `await Promise.resolve(1);;`). `returnFinalExpression` now scans backward past `EmptyStatement` nodes before deciding there is no final expression.
|
|
118
|
+
- Fixed `github` view cache evicting valid rows on open whenever a longer-than-default `github.cache.hardTtlSec` was configured. `openDb()` no longer sweeps with the 7-day default before settings load; the per-lookup `sweepIfDue()` enforces the configured retention exclusively.
|
|
119
|
+
- Fixed extension `ctx.shutdown()` being a no-op in the primary interactive path. The handler in `initHooksAndCustomTools` now sets `shutdownRequested` (mirroring the backgrounded-reinit path), and the main REPL loop drains the flag at the post-stream idle boundary so queued steering messages still flush before teardown.
|
|
120
|
+
- Fixed plan-mode "Approve and compact context" dispatching queued user input against the stale plan-mode reference path. `setPlanReferencePath(finalPlanFilePath)` now runs before `handleCompactCommand` flushes the compaction queue, so any message typed during compaction is delivered with the approved plan context attached.
|
|
121
|
+
- Fixed `.omp/commands/fix-issues.md` and `.omp/commands/review-prs.md` still instructing agents to call the removed `github issue_view` / `pr_view` / `pr_diff` ops; they now reference `read issue://<N>` and `read pr://<N>[/diff[/all|<i>]]`.
|
|
122
|
+
- Fixed `ExtensionRunner.initialize()` flushing buffered `credential_disabled` events before mode controllers had a chance to register their `onError` listener. Mode controllers call `runner.initialize(...)` immediately followed by `runner.onError(...)` synchronously; the flush now runs in a microtask after splicing the buffer, so a synchronously throwing `credential_disabled` handler is routed through the registered error listener instead of being silently dropped.
|
|
123
|
+
|
|
124
|
+
### Security
|
|
125
|
+
|
|
126
|
+
- Secured the GitHub cache store with strict file permissions (`0600` files) and private permissions for newly created cache directories (`0700`) to reduce local cache exposure
|
|
127
|
+
|
|
5
128
|
## [14.9.9] - 2026-05-12
|
|
6
129
|
|
|
7
130
|
### Added
|
|
@@ -334,7 +334,6 @@ export default function planModeExtension(pi: ExtensionAPI) {
|
|
|
334
334
|
}
|
|
335
335
|
|
|
336
336
|
// Remove any previous plan-mode-context messages
|
|
337
|
-
const _beforeCount = event.messages.length;
|
|
338
337
|
const filtered = event.messages.filter(m => {
|
|
339
338
|
if (m.role === "user" && Array.isArray(m.content)) {
|
|
340
339
|
const hasOldContext = m.content.some(
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/pi-coding-agent",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "15.0.1",
|
|
5
5
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
6
6
|
"homepage": "https://github.com/can1357/oh-my-pi",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -47,12 +47,12 @@
|
|
|
47
47
|
"@agentclientprotocol/sdk": "0.21.0",
|
|
48
48
|
"@babel/parser": "^7.29.3",
|
|
49
49
|
"@mozilla/readability": "^0.6.0",
|
|
50
|
-
"@oh-my-pi/omp-stats": "
|
|
51
|
-
"@oh-my-pi/pi-agent-core": "
|
|
52
|
-
"@oh-my-pi/pi-ai": "
|
|
53
|
-
"@oh-my-pi/pi-natives": "
|
|
54
|
-
"@oh-my-pi/pi-tui": "
|
|
55
|
-
"@oh-my-pi/pi-utils": "
|
|
50
|
+
"@oh-my-pi/omp-stats": "15.0.1",
|
|
51
|
+
"@oh-my-pi/pi-agent-core": "15.0.1",
|
|
52
|
+
"@oh-my-pi/pi-ai": "15.0.1",
|
|
53
|
+
"@oh-my-pi/pi-natives": "15.0.1",
|
|
54
|
+
"@oh-my-pi/pi-tui": "15.0.1",
|
|
55
|
+
"@oh-my-pi/pi-utils": "15.0.1",
|
|
56
56
|
"@puppeteer/browsers": "^2.13.0",
|
|
57
57
|
"@sinclair/typebox": "^0.34.49",
|
|
58
58
|
"@types/turndown": "5.0.6",
|
|
@@ -71,10 +71,10 @@
|
|
|
71
71
|
"zod": "4.4.3"
|
|
72
72
|
},
|
|
73
73
|
"devDependencies": {
|
|
74
|
-
"@types/bun": "^1.3.
|
|
74
|
+
"@types/bun": "^1.3.14"
|
|
75
75
|
},
|
|
76
76
|
"engines": {
|
|
77
|
-
"bun": ">=1.3.
|
|
77
|
+
"bun": ">=1.3.14"
|
|
78
78
|
},
|
|
79
79
|
"files": [
|
|
80
80
|
"src",
|
package/scripts/build-binary.ts
CHANGED
|
@@ -33,6 +33,11 @@ async function main(): Promise<void> {
|
|
|
33
33
|
"bun",
|
|
34
34
|
"build",
|
|
35
35
|
"--compile",
|
|
36
|
+
"--no-compile-autoload-bunfig",
|
|
37
|
+
"--no-compile-autoload-dotenv",
|
|
38
|
+
"--no-compile-autoload-tsconfig",
|
|
39
|
+
"--no-compile-autoload-package-json",
|
|
40
|
+
"--keep-names",
|
|
36
41
|
"--define",
|
|
37
42
|
'process.env.PI_COMPILED="true"',
|
|
38
43
|
"--external",
|
|
@@ -25,7 +25,7 @@ const PROMPT_DIRS = [PROMPTS_DIR, COMMIT_PROMPTS_DIR, AGENTIC_PROMPTS_DIR];
|
|
|
25
25
|
const PROMPT_FORMAT_OPTIONS = {
|
|
26
26
|
renderPhase: "pre-render",
|
|
27
27
|
replaceAsciiSymbols: true,
|
|
28
|
-
|
|
28
|
+
normalizeRfc2119: true,
|
|
29
29
|
} as const;
|
|
30
30
|
|
|
31
31
|
async function main() {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as git from "../utils/git";
|
|
1
2
|
import type { ASIData, ASIValue, MetricDirection, NumericMetricMap } from "./types";
|
|
2
3
|
|
|
3
4
|
export const METRIC_LINE_PREFIX = "METRIC";
|
|
@@ -199,3 +200,19 @@ function sanitizeAsiValue(value: unknown): ASIValue | undefined {
|
|
|
199
200
|
}
|
|
200
201
|
return undefined;
|
|
201
202
|
}
|
|
203
|
+
|
|
204
|
+
export async function tryGitStatus(cwd: string): Promise<string> {
|
|
205
|
+
try {
|
|
206
|
+
return await git.status(cwd, { porcelainV1: true, untrackedFiles: "all", z: true });
|
|
207
|
+
} catch {
|
|
208
|
+
return "";
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
export async function tryGitPrefix(cwd: string): Promise<string> {
|
|
213
|
+
try {
|
|
214
|
+
return await git.show.prefix(cwd);
|
|
215
|
+
} catch {
|
|
216
|
+
return "";
|
|
217
|
+
}
|
|
218
|
+
}
|
|
@@ -8,7 +8,15 @@ import type { Theme } from "../../modes/theme/theme";
|
|
|
8
8
|
import { replaceTabs, truncateToWidth } from "../../tools/render-utils";
|
|
9
9
|
import * as git from "../../utils/git";
|
|
10
10
|
import { computeRunModifiedPaths, getCurrentAutoresearchBranch, parseWorkDirDirtyPaths } from "../git";
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
ensureNumericMetricMap,
|
|
13
|
+
formatNum,
|
|
14
|
+
mergeAsi,
|
|
15
|
+
pathMatchesSpec,
|
|
16
|
+
sanitizeAsi,
|
|
17
|
+
tryGitPrefix,
|
|
18
|
+
tryGitStatus,
|
|
19
|
+
} from "../helpers";
|
|
12
20
|
import {
|
|
13
21
|
buildExperimentState,
|
|
14
22
|
computeConfidence,
|
|
@@ -445,22 +453,6 @@ async function tryReadHeadSha(cwd: string): Promise<string | null> {
|
|
|
445
453
|
}
|
|
446
454
|
}
|
|
447
455
|
|
|
448
|
-
async function tryGitStatus(cwd: string): Promise<string> {
|
|
449
|
-
try {
|
|
450
|
-
return await git.status(cwd, { porcelainV1: true, untrackedFiles: "all", z: true });
|
|
451
|
-
} catch {
|
|
452
|
-
return "";
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
async function tryGitPrefix(cwd: string): Promise<string> {
|
|
457
|
-
try {
|
|
458
|
-
return await git.show.prefix(cwd);
|
|
459
|
-
} catch {
|
|
460
|
-
return "";
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
|
|
464
456
|
function buildLogText(
|
|
465
457
|
state: ExperimentState,
|
|
466
458
|
experiment: ExperimentResult,
|
|
@@ -18,6 +18,8 @@ import {
|
|
|
18
18
|
killTree,
|
|
19
19
|
parseAsiLines,
|
|
20
20
|
parseMetricLines,
|
|
21
|
+
tryGitPrefix,
|
|
22
|
+
tryGitStatus,
|
|
21
23
|
} from "../helpers";
|
|
22
24
|
import { buildExperimentState } from "../state";
|
|
23
25
|
import { openAutoresearchStorageIfExists } from "../storage";
|
|
@@ -265,23 +267,6 @@ export function createRunExperimentTool(
|
|
|
265
267
|
},
|
|
266
268
|
};
|
|
267
269
|
}
|
|
268
|
-
|
|
269
|
-
async function tryGitStatus(cwd: string): Promise<string> {
|
|
270
|
-
try {
|
|
271
|
-
return await git.status(cwd, { porcelainV1: true, untrackedFiles: "all", z: true });
|
|
272
|
-
} catch {
|
|
273
|
-
return "";
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
async function tryGitPrefix(cwd: string): Promise<string> {
|
|
278
|
-
try {
|
|
279
|
-
return await git.show.prefix(cwd);
|
|
280
|
-
} catch {
|
|
281
|
-
return "";
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
|
|
285
270
|
async function executeProcess(opts: {
|
|
286
271
|
command: string[];
|
|
287
272
|
cwd: string;
|
package/src/capability/skill.ts
CHANGED
|
@@ -14,6 +14,13 @@ export interface SkillFrontmatter {
|
|
|
14
14
|
description?: string;
|
|
15
15
|
globs?: string[];
|
|
16
16
|
alwaysApply?: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* When `true`, the skill is loaded and accessible via `skill://<name>` (and
|
|
19
|
+
* `/skill:<name>` slash commands), but is omitted from the rendered system
|
|
20
|
+
* prompt's skill listing. Use for skills the user opts into explicitly
|
|
21
|
+
* rather than ones the model should auto-discover.
|
|
22
|
+
*/
|
|
23
|
+
hide?: boolean;
|
|
17
24
|
[key: string]: unknown;
|
|
18
25
|
}
|
|
19
26
|
|
package/src/cli/args.ts
CHANGED
|
@@ -7,7 +7,7 @@ import chalk from "chalk";
|
|
|
7
7
|
import { parseEffort } from "../thinking";
|
|
8
8
|
import { BUILTIN_TOOLS } from "../tools";
|
|
9
9
|
|
|
10
|
-
export type Mode = "text" | "json" | "rpc" | "acp";
|
|
10
|
+
export type Mode = "text" | "json" | "rpc" | "acp" | "rpc-ui";
|
|
11
11
|
|
|
12
12
|
export interface Args {
|
|
13
13
|
cwd?: string;
|
|
@@ -79,7 +79,7 @@ export function parseArgs(args: string[], extensionFlags?: Map<string, { type: "
|
|
|
79
79
|
result.allowHome = true;
|
|
80
80
|
} else if (arg === "--mode" && i + 1 < args.length) {
|
|
81
81
|
const mode = args[++i];
|
|
82
|
-
if (mode === "text" || mode === "json" || mode === "rpc" || mode === "acp") {
|
|
82
|
+
if (mode === "text" || mode === "json" || mode === "rpc" || mode === "acp" || mode === "rpc-ui") {
|
|
83
83
|
result.mode = mode;
|
|
84
84
|
}
|
|
85
85
|
} else if (arg === "--continue" || arg === "-c") {
|
package/src/cli/list-models.ts
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
* List available models with optional fuzzy search
|
|
3
3
|
*/
|
|
4
4
|
import { type Api, getSupportedEfforts, type Model } from "@oh-my-pi/pi-ai";
|
|
5
|
+
import { fuzzyFilter } from "@oh-my-pi/pi-tui";
|
|
5
6
|
import { formatNumber } from "@oh-my-pi/pi-utils";
|
|
6
7
|
import type { ModelRegistry } from "../config/model-registry";
|
|
7
8
|
import { discoverAndLoadExtensions, loadExtensions } from "../extensibility/extensions";
|
|
8
9
|
import { EventBus } from "../utils/event-bus";
|
|
9
|
-
import { fuzzyFilter } from "../utils/fuzzy";
|
|
10
10
|
|
|
11
11
|
interface ProviderRow {
|
|
12
12
|
provider: string;
|
package/src/cli/shell-cli.ts
CHANGED
|
@@ -5,10 +5,11 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import * as path from "node:path";
|
|
7
7
|
import { createInterface } from "node:readline/promises";
|
|
8
|
-
import {
|
|
8
|
+
import { Shell } from "@oh-my-pi/pi-natives";
|
|
9
9
|
import { APP_NAME, getProjectDir } from "@oh-my-pi/pi-utils";
|
|
10
10
|
import chalk from "chalk";
|
|
11
|
-
import { Settings
|
|
11
|
+
import { Settings } from "../config/settings";
|
|
12
|
+
import { buildMinimizerOptions } from "../exec/bash-executor";
|
|
12
13
|
import { getOrCreateSnapshot } from "../utils/shell-snapshot";
|
|
13
14
|
|
|
14
15
|
export interface ShellCommandArgs {
|
|
@@ -41,17 +42,6 @@ export function parseShellArgs(args: string[]): ShellCommandArgs | undefined {
|
|
|
41
42
|
return result;
|
|
42
43
|
}
|
|
43
44
|
|
|
44
|
-
function buildMinimizerOptions(group: ShellMinimizerSettings): MinimizerOptions | undefined {
|
|
45
|
-
if (!group.enabled) return undefined;
|
|
46
|
-
return {
|
|
47
|
-
enabled: true,
|
|
48
|
-
settingsPath: group.settingsPath || undefined,
|
|
49
|
-
only: group.only.length > 0 ? group.only : undefined,
|
|
50
|
-
except: group.except.length > 0 ? group.except : undefined,
|
|
51
|
-
maxCaptureBytes: group.maxCaptureBytes,
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
|
|
55
45
|
export async function runShellCommand(cmd: ShellCommandArgs): Promise<void> {
|
|
56
46
|
if (!process.stdin.isTTY) {
|
|
57
47
|
process.stderr.write("Error: shell console requires an interactive TTY.\n");
|
package/src/cli/update-cli.ts
CHANGED
|
@@ -91,7 +91,7 @@ function resolveUpdateMethod(ompPath: string, bunBinDir: string | undefined): "b
|
|
|
91
91
|
return isPathInDirectory(ompPath, bunBinDir) ? "bun" : "binary";
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
export function
|
|
94
|
+
export function resolveUpdateMethodForTest(ompPath: string, bunBinDir: string | undefined): "bun" | "binary" {
|
|
95
95
|
return resolveUpdateMethod(ompPath, bunBinDir);
|
|
96
96
|
}
|
|
97
97
|
async function resolveUpdateTarget(): Promise<UpdateTarget> {
|
package/src/cli.ts
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
+
import { installH2Fetch } from "@oh-my-pi/pi-ai";
|
|
2
3
|
import { APP_NAME, MIN_BUN_VERSION, procmgr, VERSION } from "@oh-my-pi/pi-utils";
|
|
3
4
|
|
|
5
|
+
// Activate HTTP/2 for all `fetch()` calls (provider streams, OAuth, model
|
|
6
|
+
// discovery, web tools). Bun's HTTP/2 client is gated on a startup flag we
|
|
7
|
+
// can't toggle from JS, so we patch globalThis.fetch to pass
|
|
8
|
+
// `protocol: "http2"` per request, with transparent HTTP/1.1 fallback on
|
|
9
|
+
// `HTTP2Unsupported`. See @oh-my-pi/pi-ai/utils/h2-fetch for details.
|
|
10
|
+
installH2Fetch();
|
|
11
|
+
|
|
4
12
|
// Strip macOS malloc-stack-logging env vars before any subprocess is spawned.
|
|
5
13
|
// Otherwise every child bun process (subagents, plugin installs, ptree spawns,
|
|
6
14
|
// etc.) prints a `MallocStackLogging: can't turn off …` warning to stderr.
|
|
@@ -12,44 +20,18 @@ procmgr.scrubProcessEnv();
|
|
|
12
20
|
*/
|
|
13
21
|
import { type CommandEntry, run } from "@oh-my-pi/pi-utils/cli";
|
|
14
22
|
|
|
15
|
-
|
|
16
|
-
function toint(value: string): number {
|
|
17
|
-
const int = Number.parseInt(value, 10);
|
|
18
|
-
if (Number.isNaN(int) || !Number.isFinite(int)) return 0;
|
|
19
|
-
return int;
|
|
20
|
-
}
|
|
21
|
-
const [majorRaw, minorRaw, patchRaw] = version.split(".").map(toint);
|
|
22
|
-
return [majorRaw, minorRaw, patchRaw];
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function isAtLeastBunVersion(minimum: string): boolean {
|
|
26
|
-
const ver = parseSemver(Bun.version);
|
|
27
|
-
const min = parseSemver(minimum);
|
|
28
|
-
for (let i = 0; i < 3; i++) {
|
|
29
|
-
if (ver[i] !== min[i]) {
|
|
30
|
-
return ver[i] > min[i];
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
return true;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if (typeof Bun.JSONL?.parseChunk !== "function" || !isAtLeastBunVersion(MIN_BUN_VERSION)) {
|
|
23
|
+
if (Bun.semver.order(Bun.version, MIN_BUN_VERSION) < 0) {
|
|
37
24
|
process.stderr.write(
|
|
38
|
-
`error: Bun runtime must be >= ${MIN_BUN_VERSION} (found v${Bun.version}). Please
|
|
25
|
+
`error: Bun runtime must be >= ${MIN_BUN_VERSION} (found v${Bun.version}). Please upgrade: bun upgrade\n`,
|
|
39
26
|
);
|
|
40
27
|
process.exit(1);
|
|
41
28
|
}
|
|
42
29
|
|
|
43
|
-
// Detect known Bun errata that cause TUI crashes (e.g. Bun.stringWidth mishandling OSC sequences).
|
|
44
|
-
if (Bun.stringWidth("\x1b[0m\x1b]8;;\x07") !== 0) {
|
|
45
|
-
process.stderr.write(`error: Bun runtime errata detected (v${Bun.version}). Please update Bun: bun upgrade\n`);
|
|
46
|
-
process.exit(1);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
30
|
process.title = APP_NAME;
|
|
50
31
|
|
|
51
32
|
const commands: CommandEntry[] = [
|
|
52
33
|
{ name: "launch", load: () => import("./commands/launch").then(m => m.default) },
|
|
34
|
+
{ name: "acp", load: () => import("./commands/acp").then(m => m.default) },
|
|
53
35
|
{ name: "agents", load: () => import("./commands/agents").then(m => m.default) },
|
|
54
36
|
{ name: "commit", load: () => import("./commands/commit").then(m => m.default) },
|
|
55
37
|
{ name: "config", load: () => import("./commands/config").then(m => m.default) },
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run Oh My Pi as an ACP (Agent Client Protocol) server over stdio.
|
|
3
|
+
*
|
|
4
|
+
* Thin wrapper around the launch flow that forces `mode: "acp"` unless the
|
|
5
|
+
* ACP terminal-auth flag asks the same command to open the interactive TUI.
|
|
6
|
+
*/
|
|
7
|
+
import { Command } from "@oh-my-pi/pi-utils/cli";
|
|
8
|
+
import { parseArgs } from "../cli/args";
|
|
9
|
+
import { runRootCommand } from "../main";
|
|
10
|
+
import { prepareAcpTerminalAuthArgs } from "../modes/acp/terminal-auth";
|
|
11
|
+
|
|
12
|
+
export default class Acp extends Command {
|
|
13
|
+
static description = "Run Oh My Pi as an ACP (Agent Client Protocol) server over stdio";
|
|
14
|
+
static strict = false;
|
|
15
|
+
|
|
16
|
+
async run(): Promise<void> {
|
|
17
|
+
const { args, terminalAuth } = prepareAcpTerminalAuthArgs(this.argv);
|
|
18
|
+
const parsed = parseArgs(args);
|
|
19
|
+
if (!terminalAuth) {
|
|
20
|
+
parsed.mode = "acp";
|
|
21
|
+
}
|
|
22
|
+
await runRootCommand(parsed, args);
|
|
23
|
+
}
|
|
24
|
+
}
|
package/src/commands/launch.ts
CHANGED
|
@@ -7,6 +7,7 @@ import { APP_NAME } from "@oh-my-pi/pi-utils";
|
|
|
7
7
|
import { Args, Command, Flags } from "@oh-my-pi/pi-utils/cli";
|
|
8
8
|
import { parseArgs } from "../cli/args";
|
|
9
9
|
import { runRootCommand } from "../main";
|
|
10
|
+
import { prepareAcpTerminalAuthArgs } from "../modes/acp/terminal-auth";
|
|
10
11
|
|
|
11
12
|
export default class Index extends Command {
|
|
12
13
|
static description = "AI coding assistant";
|
|
@@ -49,8 +50,8 @@ export default class Index extends Command {
|
|
|
49
50
|
description: "Allow starting in ~ without auto-switching to a temp dir",
|
|
50
51
|
}),
|
|
51
52
|
mode: Flags.string({
|
|
52
|
-
description: "Output mode: text (default), json, or rpc",
|
|
53
|
-
options: ["text", "json", "rpc"],
|
|
53
|
+
description: "Output mode: text (default), json, rpc, or rpc-ui",
|
|
54
|
+
options: ["text", "json", "rpc", "acp", "rpc-ui"],
|
|
54
55
|
}),
|
|
55
56
|
print: Flags.boolean({
|
|
56
57
|
char: "p",
|
|
@@ -135,7 +136,8 @@ export default class Index extends Command {
|
|
|
135
136
|
static strict = false;
|
|
136
137
|
|
|
137
138
|
async run(): Promise<void> {
|
|
138
|
-
const
|
|
139
|
-
|
|
139
|
+
const { args } = prepareAcpTerminalAuthArgs(this.argv);
|
|
140
|
+
const parsed = parseArgs(args);
|
|
141
|
+
await runRootCommand(parsed, args);
|
|
140
142
|
}
|
|
141
143
|
}
|
|
@@ -34,5 +34,5 @@ Tool guidance:
|
|
|
34
34
|
|
|
35
35
|
## Changelog Requirements
|
|
36
36
|
|
|
37
|
-
If changelog targets provided, you
|
|
37
|
+
If changelog targets provided, you MUST call `propose_changelog` before finishing.
|
|
38
38
|
If you propose split commit plan, include changelog target files in relevant commit changes.
|
|
@@ -130,8 +130,15 @@ export function createProposeChangelogTool(
|
|
|
130
130
|
state.changelogProposal = { entries: normalized };
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
+
let text = response.valid ? "Changelog entries accepted." : "Changelog validation failed.";
|
|
134
|
+
if (response.errors.length > 0) {
|
|
135
|
+
text += `\n\nErrors:\n${response.errors.map(e => `- ${e}`).join("\n")}`;
|
|
136
|
+
}
|
|
137
|
+
if (response.warnings.length > 0) {
|
|
138
|
+
text += `\n\nWarnings:\n${response.warnings.map(w => `- ${w}`).join("\n")}`;
|
|
139
|
+
}
|
|
133
140
|
return {
|
|
134
|
-
content: [{ type: "text", text
|
|
141
|
+
content: [{ type: "text", text }],
|
|
135
142
|
details: response,
|
|
136
143
|
};
|
|
137
144
|
},
|