Commit Graph
57 Commits
Author SHA1 Message Date
oldschoola 14252e71cb fix: Windows test failures — path handling, EBUSY, SQLite handle leaks
Fix all Windows-specific test failures caused by path handling problems
and EBUSY errors from unclosed SQLite database handles.

Root causes fixed:
1. POSIX path assumptions: replaced hard-coded file:///tmp, /repo, etc.
   with pathToFileURL/path.resolve/path.join computed expectations
2. shortenPath() now normalizes backslashes to forward slashes after ~
   and respects home directory boundaries
3. HistoryStorage.resetInstance() leaked its Database — added #close()
   that finalizes all prepared statements and closes the DB
4. AgentStorage gained the same resetInstance()/#close() pattern
5. SqliteAuthCredentialStore.close() leaked one-off prepared statements
   from inline this.#db.prepare() calls — wrapped each in try/finally
6. model-cache.ts used a process-global DB even for custom dbPath —
   now opens/closes per-call via withModelCacheDb
7. createAgentSession leaked AuthStorage on construction failure —
   added ownsAuthStorage cleanup in catch block
8. MnemopiBackend.removeDbFiles() now truly best-effort (catches errors)
9. TempDir retry window expanded from 4x10ms to 40x25ms
10. TempDir prefix convention: non-@ prefixes created dirs relative to
    cwd instead of os.tmpdir() — all test temp dirs now use @ prefix
11. Shell-escaped interpolated paths in bash tool tests
12. git core.autocrlf false in autoresearch test repo init

All 522 previously-failing Windows tests now pass.
2026-06-18 21:32:38 -07:00
roboomp 9a8e625a44 fix(acp): listed local speech models
Added the ACP mobile speech.models.list method so voice settings can fetch static local STT, TTS, and voice catalog options without invoking setup/download paths.

Fixes #3011
2026-06-19 01:19:08 +00:00
can1357 a050474af7 feat: migrated validation schemas and tool definitions from Zod to ArkType
- Migrated all wire protocol, schema definitions, and tools validation from Zod to ArkType across multiple packages.
- Updated extension runtimes, custom tools loader, and TypeBox compatibility shim to expose and use ArkType instances.
- Added a comprehensive ArkType migration guide, validation parity tests, and helper utilities.
- Removed redundant PDF asset routing and parsing implementations from the read tool.
2026-06-18 00:59:53 +02:00
can1357 5691a039de refactor(packages/coding-agent): restructured acp 0.25 session state
- Removed `userMessageId` from `AcpAgent` prompt state and response payloads.
- Removed `models` from new/load/resume/fork session responses and deleted model-state building.
- Removed `unstable_setSessionModel` and routed model changes through `setSessionConfigOption`.
2026-06-13 00:20:05 +02:00
can1357 965c5d4000 Merge PR #2262: feat(rpc): expose slash command metadata 2026-06-11 17:59:40 +02:00
can1357 37e00b10c4 test(tui): stabilized ACP command tests and added TUI committed-rows coverage
- Replaced the ACP agent test's fixed bootstrap wait with a deterministic `/reload-plugins` flow and asserted against the latest available-commands advertisement.
- Added a TUI probe test that verifies native committed scrollback rows are passed to children before render.
2026-06-11 16:23:41 +02:00
danzaio 3351a15f80 fix(rpc): tolerate legacy command metadata 2026-06-10 16:04:26 -03:00
can1357 e3501e3f76 chore: fix merge issues 2026-06-10 08:35:51 +02:00
can1357 1c69483241 Merge pull request #2186: fix(acp): auto-cancel in-flight turn when new prompt arrives mid-flight 2026-06-10 08:26:59 +02:00
can1357 5187dc1a7b fix(acp): skip colon-namespaced extension commands shadowed by builtins
parseSlashCommand treats ':' as a name/args separator, so an extension
command like 'model:foo' was advertised in available_commands_update but
dispatched to the '/model' builtin. Filter such names via
isAcpBuiltinShadowedName, and fix the FakeAgentSession prompt stubs in
acp-agent.test.ts to return true now that AgentSession.prompt() reports
whether the agent was invoked (6 tests were failing against the new
early-finish path).

Addresses review feedback on #2052.
2026-06-10 08:26:08 +02:00
d8db20cb0d fix(acp): advertise extension commands before custom TS commands
Dispatch in AgentSession runs #tryExecuteExtensionCommand before
#tryExecuteCustomCommand, so the palette must reflect the same order.
Moving the extension-runner block before session.customCommands ensures
that on a name collision the advertised command matches what will
actually execute.

Update the test to assert the extension description wins over the
colliding custom TS description.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 08:26:07 +02:00
0d67407773 fix(acp): address review comments on extension-commands PR
- Update ordering comment in #buildAvailableCommands to document the
  extension tier and explain why skills/custom TS commands intentionally
  shadow extension commands (unlike interactive mode)
- Add CHANGELOG entry under [Unreleased]
- Add regression test: verifies extension commands surface in
  available_commands_update and that a builtin-colliding extension
  command is excluded via the reserved-set, with no duplicates

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 08:26:07 +02:00
can1357 bbd93437ca fix(acp): close session when implicit cancel cleanup times out
The implicit-cancel overlap path dropped the cleanup promise, so an
abort() that hung past the cleanup timeout left the managed session
registered with a still-streaming AgentSession — the explicit cancel()
path closes it in that case. Mirror that handling and cover it with a
regression test.

Addresses review feedback on #2186.
2026-06-10 08:26:01 +02:00
Theo Mathieuandcan1357 bebd9dffa1 review: remove unrelated changelog bullets; assert abort() barrier in test 2026-06-10 08:26:01 +02:00
Theo Mathieuandcan1357 094c6e5fdc fix(acp): auto-cancel in-flight turn when new prompt arrives mid-flight
When the user presses Stop in Zed and immediately types a new message,
the new session/prompt RPC can arrive before (or without) a preceding
session/cancel notification. The previous guard threw an error in that
case, leaving the session stuck and blocking further interaction.

Replace the throw with an implicit cancel: call #beginCancelCleanup on
the unsettled turn so it resolves with stopReason:"cancelled", then let
#queuePrompt serialize the new prompt behind the abort cleanup as it
already does when session/cancel is called explicitly. #beginCancelCleanup
is idempotent so a concurrent explicit cancel notification is a no-op.

Updated the test to assert the new contract: overlapping prompt
auto-cancels the first turn and the second is processed normally.
2026-06-10 08:26:01 +02:00
can1357 ae415199dc feat: added build-time compatibility in ModelSpec/buildModel pipeline
- Centralized catalog and registry handling on `ModelSpec` and `buildModel`, resolving compatibility at model build time.
- Removed runtime compatibility detectors and switched provider request flows to direct `model.compat` reads.
- Added compat fields (`supportsReasoningParams`, `alwaysSendMaxTokens`, `strictResponsesPairing`, `whenThinking`).
- Persisted explicit compatibility overrides through `compatConfig` in discovery and cache merge paths.
2026-06-10 06:20:51 +02:00
can1357 9d457f73d9 test: migrated test imports to package subpath exports
- Replaced relative `../src` imports with `@oh-my-pi/pi-ai` and `@oh-my-pi/pi-agent-core` subpaths.
2026-06-08 19:03:55 +02:00
can1357 0f043d4c29 fix(coding-agent): preserved approved plan paths during plan apply resolution
- Replaced approved-plan renaming with `resolveApprovedPlan` resolution and state/slug lookup.
- Updated ACP and interactive apply flows to propagate canonical `planFilePath` instead of renamed paths.
- Added local plan fallback lookup by mtime for unresolved slugs after plan approval.
- Restricted plan-mode writes to `local://` plan artifacts and simplified path handling.
2026-06-07 07:17:23 +02:00
roboompandcan1357 18338e2088 fix(acp): refused dismissed plan approval
#requestAcpPlanApprovalChoice returned 'value !== REFINE_OPTION' which
treats any non-refine outcome — explicit dismissal, transport failure,
abort, or timeout — as approval. That meant closing the elicitation
dialog (or the request failing) granted the agent write access without
explicit user consent.

Tighten to 'value === APPROVE_OPTION' so only the explicit approve
selection passes the gate. Refine, dismissal, and every other outcome
fall through to refine semantics: the caller keeps plan mode active and
returns guidance text instead of renaming the plan and exiting.

Adds a regression test that drives a form-capable harness with a
cancelled elicitation and asserts the plan file is preserved, plan
mode/handler stay active, plan reference stays unset, and no mode-exit
notifications are emitted.
2026-06-04 18:30:22 +02:00
roboomp 493f743958 fix(acp): synced config option after plan approval
ACP plan approval exited plan mode internally and emitted the current-mode
notification, but it did not push the matching mode config-option update.
Clients that cache or render the config selector could therefore keep
showing mode=plan after approval switched the session back to default.

The approval path now emits the same config_option_update used by other
mode transitions, and the regression test asserts that the approval-driven
exit updates both current_mode_update and the mode config option.
2026-06-04 15:37:38 +00:00
roboomp fdb6077b7b fix(acp): wired plan-mode standing resolve handler
ACP plan mode set the plan-mode state but never installed the standing
resolve handler that interactive mode wires in #enterPlanMode. The agent
in plan mode dutifully called resolve { action: 'apply', extra.title }
to submit its plan; ResolveTool.execute then consulted
peekQueueInvoker() ?? peekStandingResolveHandler(), found neither, and
threw 'No pending action to resolve. Nothing to apply or discard.' —
stranding the agent with no path out of plan mode in Zed (and any other
ACP client).

#applyModeChange now registers a standing handler when entering
mode: 'plan' and clears it when leaving. The handler:
 - validates the plan file exists at the configured '/data/workspaces/can1357__oh-my-pi__1869/.omp-session/2026-06-04T15-12-15-302Z_019e9331-31c6-7000-9bce-6be119505a1d/local' path,
 - normalizes the agent-supplied title to a safe filename stem,
 - asks the ACP client to confirm via unstable_createElicitation when
   the client advertises elicitation.form (auto-approves otherwise so
   the agent never gets stuck on a client without the surface),
 - renames the plan to '/data/workspaces/can1357__oh-my-pi__1869/.omp-session/2026-06-04T15-12-15-302Z_019e9331-31c6-7000-9bce-6be119505a1d/local/<title>.md,'
 - sets the plan reference path so the next turn injects the plan as
   context, then clears the standing handler + plan-mode state and
   emits current_mode_update so the client UI reflects the exit.

Refinement (user picks 'Refine plan') returns guidance text and leaves
plan mode active so the agent can iterate.

Fixes #1869
2026-06-04 15:30:27 +00:00
can1357 dc4aeb7b88 refactor(coding-agent): renamed todo_write tool to todo
- Renamed `TodoWriteTool` to `TodoTool` and its source/prompt files.
- Updated tool registration, schema, renderers, and gating to `todo`.
- Adjusted cursor provider native tool names and tests to match.
- Renamed strike-animation constants and `todo-error-reminder` type.
2026-06-04 02:45:30 +02:00
can1357 e831c2c758 chore: reformat 2026-05-30 18:08:51 +02:00
can1357 bfae4d46c3 fix(coding-agent): tracked acp tool args by session for replay
- Tracked ACP tool-call inputs per session and replayed them via `toolArgsById`/`getToolArgs` plumbing.
- Merged ACP tool execution end content from start and result events so command output replay preserves original args.
- Scoped ACP async-job draining by session `ownerId` and `agentId` with in-flight tracking and permission-gated deferred turns.
- Refactored compaction telemetry and async tests with per-test telemetry setup and asynchronous teardown resets.
2026-05-17 13:15:07 +02:00
Can BölükandGitHub 6331953dc8 Merge branch 'main' into acp-todo-plan-sync 2026-05-17 13:12:36 +02:00
Can BölükandGitHub 34ce96e42f Merge pull request #1138 from jiwangyihao/acp-autonomous-continuation
fix(coding-agent): keep ACP async continuations owned
2026-05-17 13:12:15 +02:00
Can BölükandGitHub 1e66bf8bf3 Merge pull request #1132 from jiwangyihao/acp-tool-call-details-pr-d
ACP: keep command details stable across updates and replay
2026-05-17 13:11:59 +02:00
jiwangyihao 05e1e702dd fix(coding-agent): keep ACP async continuations owned 2026-05-17 15:30:09 +08:00
jiwangyihao 3057cbc00d fix(coding-agent): defer ACP session startup 2026-05-17 07:37:25 +08:00
jiwangyihao 204f10ae08 fix(acp): 保留回放与更新中的工具详情 2026-05-17 05:13:50 +08:00
jiwangyihao 32a8f109d1 fix(coding-agent): sync ACP todo plans 2026-05-17 02:52:06 +08:00
can1357 a40c5b1bee refactor(coding-agent): restructured ACP cancel cleanup slot management
- Replaced `finishCleanup` callback with `isPromptTurnInFlight` predicate to unify settled+cleanup gating.
- Extracted `#beginCancelCleanup` (idempotent) and `#runCancelCleanup` to clarify ownership of slot eviction.
- Fork, queue, and close paths now all gate on the combined settled+cleanup window.
2026-05-16 18:18:46 +02:00
jiwangyihao aaddf0631c fix(coding-agent): gate ACP close during cancel cleanup 2026-05-16 21:46:13 +08:00
jiwangyihao 66bf82123e fix(coding-agent): reject stale ACP cancel prompts 2026-05-16 13:27:48 +08:00
jiwangyihao 917535da2b fix(coding-agent): bound ACP cancel cleanup 2026-05-16 12:38:55 +08:00
Gerben Meijer 694f5e9a54 Refresh SSH hosts without restart 2026-05-16 00:20:00 +02:00
Can BölükandGitHub e7cd859d9b Merge pull request #1070 from jiwangyihao/acp-prompt-idle-cleanup-fresh
fix(coding-agent): wait for ACP prompt idle cleanup
2026-05-15 05:11:33 +02:00
David Marshallandomp d47f55c7fd fix(coding-agent/acp): narrow CreateElicitationRequest variant before reading sessionId in live-getter test
`CreateElicitationRequest` is a discriminated union — even after
narrowing on `mode === "form"`, both `ElicitationRequestScope` (no
`sessionId`) and `ElicitationSessionScope` (with `sessionId`)
remain in the union. The new live-getter regression test was reading
`calls[N]!.sessionId` directly, which CI tsgo rejected with TS2339.

Per-element `if (!call || call.mode !== "form" || !("sessionId"
in call))` narrows to the session-scoped variant. Spelled three times
because loop-style narrows don't propagate to the assertions below.
Matches the discriminator pattern used in the older 'translates select'
test at line ~927.

Co-Authored-By: omp <noreply@oh-my-pi.dev>
2026-05-14 10:24:21 -05:00
David Marshallandomp d7e8a7358b style(coding-agent/acp): wrap long createAcpExtensionUiContext test call-sites
`biome check` enforces print-width on the two test-only call-sites that
`ast_edit` collapsed onto a single line during the sessionId-getter
rewrite. Auto-formatter wrap, no behavior change.

Co-Authored-By: omp <noreply@oh-my-pi.dev>
2026-05-14 10:16:26 -05:00
David Marshallandomp 6b63903cf2 refactor(coding-agent/acp): read sessionId lazily on every elicitation
`AgentSession.sessionId` is a getter that reads through to
`sessionManager.getSessionId()` and mutates when an extension command
calls `ctx.newSession` or `ctx.switchSession` (both exposed in the
same #configureExtensions block). Snapshotting the id once at factory
time routed later elicitations to the pre-switch id — diverging from
every other sessionUpdate call in this file, which already reads
record.session.sessionId live.

createAcpExtensionUiContext now takes `getSessionId: () => string` and
calls it per elicitation. Caller passes `() => record.session.sessionId`
so each select / confirm / input picks up the current id.

Also simplifies elicitFromAcpClient: `onAbort` and `finish` had
identical settlement bodies differing only by the resolve value, with a
hand-rolled `removeEventListener` symmetry comment to keep them in
sync. Collapsed to a single settle path — `onAbort = () =>
finish(undefined)` — so future changes to settlement apply to both
paths automatically. Doc-comment tightened to call out that late SDK
`accept` responses (not just rejections) after abort/timeout are also
dropped silently.

New regression test asserts that mutating the captured sessionId
between elicitations is reflected in the next request.

Co-Authored-By: omp <noreply@oh-my-pi.dev>
2026-05-14 09:59:43 -05:00
jiwangyihao 07ca844936 fix(coding-agent): reject overlapping ACP prompts before queueing 2026-05-14 22:25:47 +08:00
jiwangyihao 03d7acb804 fix(coding-agent): serialize ACP idle cleanup prompts 2026-05-14 21:41:38 +08:00
jiwangyihao b15eb064f0 fix(coding-agent): wait for ACP prompt idle cleanup 2026-05-14 20:55:53 +08:00
David Marshallandomp cf623e5748 feat(coding-agent/acp): bridged ExtensionUIContext to ACP unstable_createElicitation
Promotes the stub acpExtensionUiContext to a createAcpExtensionUiContext
factory invoked per session inside #configureExtensions. select / confirm
/ input each map to a single-property `value` schema and round-trip
through a shared elicitFromAcpClient helper that mirrors
RpcExtensionUIContext.#createDialogPromise:

  - capability gating on clientCapabilities.elicitation.form
  - runtime typeof narrowing on accept payloads (wrong-type / missing
    key / no content all fall back to the stub return values)
  - dialogOptions.signal: pre-aborted short-circuits before any SDK
    call; mid-flight abort races the in-flight elicitation. Symmetric
    removeEventListener on both onAbort and finish paths.
  - dialogOptions.timeout: setTimeout(.unref()) settles the promise via
    onTimeout + stub fallback. A throwing onTimeout is caught and
    logged so the elicitation promise still settles.
  - late SDK rejections after abort/timeout are dropped silently;
    transport failures log via logger.warn with { sessionId, method,
    error }.

Empty/whitespace-only placeholders on `input` and empty/whitespace-only
messages on `confirm` are treated as absent (trim-aware), matching the
behavior documented in the CHANGELOG bullet.

15 new tests cover request shape, decline/cancel, missing capability,
transport failure, pre-abort, mid-flight abort, wrong-typed accept,
missing `value` key, no content, timeout, whitespace placeholder,
empty-message join, and throwing onTimeout.

Co-Authored-By: omp <noreply@oh-my-pi.dev>
2026-05-14 00:36:43 -05:00
can1357 0b62f2971b fix(ci): restore @napi-rs/cli dep and align tests with current types
The earlier exports/cleanup refactor removed @napi-rs/cli from
packages/natives devDeps, breaking every native job. It also left two
test files calling private symbols and a stale KeyId literal:

- packages/natives: re-add @napi-rs/cli (catalog) so node_modules/.bin/napi
  exists for build-native.ts.
- test/acp-agent.test.ts: import ACP_BOOTSTRAP_RACE_GUARD_MS from
  modes/acp/acp-agent (previously implicit via mass-export refactor).
- test/silent-abort-overlay-render.test.ts: lowercase 'Ctrl+S' -> 'ctrl+s'
  to match the KeyId union.
2026-05-14 05:12:07 +02:00
Can BölükandGitHub 8f1d98fa38 Merge branch 'main' into fix/skill-chip-and-silent-abort 2026-05-14 04:51:41 +02:00
Can BölükandGitHub 3ad9255b18 Merge branch 'main' into dmarsh/acp-thinking-level-push 2026-05-14 04:43:55 +02:00
can1357 f1f6516056 refactor: reorganized exports and removed obsolete helper branches
- Removed export leakage by demoting many helper and const symbols to module-local scope.
- Renamed underscore-prefixed internals and cache fields, then updated related references and `satisfies never` checks.
- Deleted obsolete logic branches and helpers, including harmony-stream interruption flow and unused benchmark runtime helpers.
- Updated Biome config and manifests by broadening lint coverage and removing an unused `@napi-rs/cli` dev dependency.
- Adjusted tests and utilities to use renamed test helpers and remove redundant private test-only helpers/locals.
2026-05-14 04:36:19 +02:00
cognitive c118eacdaa fix: gate SILENT_ABORT_MARKER at three unguarded render sites
Codex review flagged that the silent-abort sentinel
("__omp.silent_abort__") persists into AssistantMessage.errorMessage
but three downstream consumers render errorMessage verbatim:

- session-observer-overlay.ts: renders "✗ Error: __omp.silent_abort__"
  when content is empty (confirmed user-visible today)
- print-mode.ts: writes marker to stderr and exits non-zero (latent;
  plan-mode→compact not reachable from print mode today, but unguarded)
- acp-agent.ts: emits marker as agent_message_chunk text to ACP
  clients when message has no other notifications (latent)

Add isSilentAbort() guard at each site. Extend the SILENT_ABORT_MARKER
consumer list in messages.ts doc comment to include all six consumers.
Add regression tests: overlay (2 tests), print-mode (2 tests), ACP
replay (1 test).

Op: correct
Restores: spec:silent-abort-marker-never-surfaces
2026-05-13 23:58:13 +00:00
David Marshallandomp b626609314 refactor(coding-agent/acp): extracted ACP_BOOTSTRAP_RACE_GUARD_MS and consolidated race notes
/simplify pass on 4882d1e38. Three small cleanups, no behavior change.

* Extracted the inline 50ms bootstrap-race guard into an exported
  ACP_BOOTSTRAP_RACE_GUARD_MS constant at the top of acp-agent.ts.
  Source uses it in the #scheduleBootstrapUpdates setTimeout. Tests import
  it and call a new waitForBootstrapGuard() helper (constant + 30ms slack
  for setTimeout drift) instead of three hardcoded Bun.sleep(80) sites —
  tests now bind to the source-of-truth instead of dueling magic numbers.
* Consolidated four block comments that all narrated the same race story
  into one canonical explanation at the install site (#scheduleBootstrapUpdates).
  Field declaration, #registerPreparedSession, and the setSessionConfigOption
  handler keep brief one/two-line pointers. Net change is roughly 30 lines
  of comments removed without losing the diagnosis.
* Trimmed the handler-site thinkingHandledBySubscription comment from six
  lines to three; the local-variable name carries the intent.

Verified:
* bun test test/acp-agent.test.ts: 11/11 pass
* biome check on touched files: clean
* No behavior change (no test had to be updated)

Co-Authored-By: omp <noreply@oh-my-pi.dev>
2026-05-13 16:43:45 -05:00