Commit Graph

17510 Commits

Author SHA1 Message Date
Muhammad Mustaqeem 077b6af2fb test(ci): pin how a chunk's SIGKILL cause is reported
Drives real subprocesses so the 137 under test is a genuine SIGKILL
rather than a hand-written constant: `kill -9 $$` for the OOM-killer
shape, and a watchdog-killed `sleep` for the timeout shape.
2026-08-13 23:19:59 +05:00
Muhammad Mustaqeem bf99f9ce5b test(tui): lock the paired OSC 133 command zone instead of its absence
The existing assertion encoded the exact behaviour #8030 reports as the bug:
it required that no `133;C` ever be emitted, which is what leaves Ghostty's
sticky `.input` cursor semantic latched for the rest of the session.

Rewrite it around the property the fix actually guarantees. The marker must
now be present, but it must be immediately followed by `133;D;0` and appear
exactly once per bubble, so the command zone is opened and closed within the
same render and later assistant/tool output is still never grouped under the
submitted prompt. That was the real concern behind the original assertion,
and it is now checked directly rather than by proxy.

Refs #8030
2026-08-11 10:47:01 +05:00
Muhammad Mustaqeem d5e2bb9299 fix(tui): close the OSC 133 prompt zone so terminals clear input state
OSC 133;B latches a sticky `.input` cursor semantic in Ghostty (and
Ghostty-derived terminals such as cmux) that only a command-start marker
clears. UserMessageComponent emitted A/B and never C, so for the rest of
the session `cursorIsAtPrompt()` stayed true and every painted cell was
tagged `.input`. With `cursor-click-to-move = true` (Ghostty's default)
every left-click released inside the pane injects a burst of arrow keys
into omp's pty and the editor caret jumps to column 0.

Emit C immediately followed by D;0 at the end of the bubble. The zone is
opened and closed within the same render, so the sticky input state is
cleared while the grouping behaviour the original comment protected is
preserved: no later assistant/tool output can be grouped under this
prompt because the command zone never stays open.

Refs #8030, #6115
2026-08-11 10:29:38 +05:00
Muhammad Mustaqeem f4811ce7c4 Merge pull request #4 from can1357/main
latest
2026-08-09 15:27:19 +05:00
can1357 45e12e5bb7 test(mnemopi): awaited detached shared-bank flush in lock-wait test
dispose({ timeoutMs }) legitimately detaches the consolidate pass when
the shutdown budget expires mid-flight (#3641), so asserting the shared
bank flush synchronously after dispose raced the detached pass on slow
CI runners (0 calls observed on run 31287979000). Signal the flush call
through a deferred and await it after releasing the lock; the bounded
<500ms return assertion is unchanged.
2026-08-09 03:39:03 +02:00
can1357 311c32eaf5 fix(natives): repaired win32 build and bazel feature drift
- Synced pi-builtins bazel crate_features with cargo's resolved default
  set: bazel features are literal, so the meta-features never expanded
  and the procs/rg cluster (nohup, pgrep, pidwait, pkill, proc-match,
  ps, rg, sleep, timeout, top) was silently compiled out, leaving the
  process builtins unregistered under bazel and failing pi-shell tests.
- Repaired windows compilation of pi-builtins: cfg-gated the
  uucore::mode import in mkdir, imported std::env in sort's non-unix
  locale probe, mapped ProcInfo::pid through a closure in kill, brought
  MetadataExt into scope in wc, and replaced stat's unstable
  windows_by_handle metadata with a stable GetFileInformationByHandle
  query (volume serial, link count, file index, no-dereference aware).
- Imported HashSet for pi-shell's windows-only PATH merge.
- Added a clippy-ported bazel config + CI bucket so pi-builtins keeps
  its manifest-declared clippy allows under the bazel aspect while rustc
  warnings stay denied, and zeroed the remaining windows-target rustc
  warnings (unused params/imports in find, mv, rm, proc_match, ps).
2026-08-09 03:17:34 +02:00
can1357 896bf5f33e fix(natives): repaired linux pi-builtins release build
- Added util.procs to the bazel crate_features: cargo resolves the
  builtin.kill -> util.procs implication automatically, but bazel
  crate_features are literal, so kill.rs failed with E0432 on
  proc_snapshot once HostProcesses became unconditional.
- Imported std::os::fd::AsFd in the linux/android splice path of the wc
  builtin (E0405); the import is target-gated like its callers.
- Verified with cargo check -p pi-builtins --no-default-features using
  the exact bazel feature list on both the host and (via zig cc)
  x86_64-unknown-linux-gnu targets.
2026-08-08 21:06:10 +02:00
can1357 6fb07028fd chore: bump version to 17.2.12 2026-08-08 20:57:55 +02:00
can1357 60d4cb997e test(catalog): pinned copilot grok-4.5 migration to the responses route
- The regenerated bundle (merged with PR #8021) now ships a
  responses-route github-copilot/grok-4.5, so the id legitimately
  resurfaces from the bundle when the migration refresh fails; the
  contract worth defending is that the stale cached completions route
  never returns and the unbundled long-context variant stays dropped.
2026-08-08 20:57:10 +02:00
can1357 bf04fbfc8d fix(catalog): routed opencode-go deepseek-v4-flash through the responses api
- The OpenCode Go gateway does not serve DSV4-Flash at
  /zen/go/v1/chat/completions; /zen/go/v1/responses works (user-verified
  against the live gateway). Added a per-id override in
  OPENCODE_GO_API_RESOLUTION so both bundled generation and the runtime
  /v1/models refresh route it to openai-responses; deepseek-v4-pro keeps
  chat completions.
- Regenerated models.json from the resolver source.
2026-08-08 20:57:10 +02:00
can1357 d85dde52c4 fix(session): fence in-flight disk work behind the terminal seal
- seal() now runs before the final dispose close() and bumps the disk
  epoch: work an event handler enqueues while dispose awaits the closing
  tail is superseded, and an already-running fenced or authoritative
  rewrite fails its commit guard at the rename fence instead of
  publishing over a file a revival reopened.
- The authoritative repair path resets the disk tail itself, escaping the
  close() serialization, and would atomically publish the emptied entry
  list; it now no-ops once sealed and commit guards also check the seal.
- Execution-time gates cover the queued title persist and fenced rewrite
  callbacks; setSessionName/appendCustomEntry attempted by a handler that
  outlives dispose are dropped and covered by the seal regression, and a
  failed atomic batch across the seal can no longer truncate the file.
2026-08-08 20:49:28 +02:00
can1357 22b5ccd978 test(coding-agent): assert exact transcript contents in seal regression
- Replaced count-only assertions with the exact ordered message set:
  revival sees only the seed, the reread holds seed + post-revive, and
  the sealed manager's late persist text appears nowhere in the file.
2026-08-08 20:08:07 +02:00
can1357 63aa8cf6f8 fix(session): seal the manager at terminal release against revival races
- AgentLifecycleManager.park() resolves as soon as dispose() returns, so
  ensureLive() may reopen the same JSONL through a new manager while a
  timed-out event handler still holds the old one; a late append reopened
  a second writer on that file and the deferred finalize then closed it.
- A post-release rewrite was worse: it persisted the emptied entry list,
  truncating the transcript on disk.
- releaseRetainedEntries() now seals the manager: appends, title changes,
  and rewrites become dropped no-ops and the append writer is closed, so
  the deferred dispose pass is in-memory only and can never touch the file.
- File-backed regression: dispose on the drain deadline, revive the JSONL
  immediately, unpark the late handler, and prove the file is byte-stable
  and the revival writer owns it exclusively.
2026-08-08 20:04:09 +02:00
can1357 31d7655477 fix(agent): re-finalize dispose after the drain deadline
- The dispose drain deadline does not cancel in-flight event handlers: one
  parked in a slow extension hook resumed after close/release, reopened the
  append writer for its late persist, and repopulated the released state.
- Track whether the drain settled; on deadline, redo the final close +
  release once the pipeline genuinely settles (hook runtime is bounded by
  the extension runner).
- Expose drainTimeoutMs on AgentSessionDisposeOptions for bounded teardown
  paths and deterministic coverage of the deadline branch.
2026-08-08 19:54:33 +02:00
can1357 b9ddc81f06 test(coding-agent): assert dispose-persisted state from the reopened file
- PR #8004 dispose() now releases the session manager in-memory transcript;
  snapcompact-budget rebuilt a session over the closed manager and the exit
  diagnostics read released entries.
- Snapcompact reopens the persisted file for its replacement session; exit
  diagnostics move to disk-backed managers and assert the exit marker from a
  reopened manager, proving actual durability.
2026-08-08 19:50:59 +02:00
can1357 cab4c4520b test(coding-agent): reopen persisted session after terminal dispose
- PR #8004 made dispose() release the session manager in-memory transcript;
  three handoff tests reused the closed manager for a replacement session.
- Reopen the persisted session file via SessionManager.open, matching
  production revival paths.
2026-08-08 19:47:10 +02:00
can1357 a85e23d156 chore(changelog): normalized unreleased spacing after merges 2026-08-08 19:38:55 +02:00
can1357 f87a8ecc19 Merge PR #7994: fix(session): surface empty handoff generation as failure not cancel (@roboomp) 2026-08-08 19:38:32 +02:00
can1357 3cf1e42a05 fix(tui): preserve unbraced math continuations 2026-08-08 19:38:32 +02:00
can1357 78cd70bb94 Merge PR #7997: fix(tui): keep display-math fractions intact across source newlines (@roboomp) 2026-08-08 19:38:32 +02:00
can1357 afa54d87f0 Merge PR #8002: fix(web-search): parse double-encoded Z.AI results (@roboomp) 2026-08-08 19:38:32 +02:00
can1357 b2d0ade665 fix(agent): finish session disposal after event drain 2026-08-08 19:38:32 +02:00
can1357 bca8d5281b Merge PR #8004: fix(agent): release parked subagent session memory on dispose (@roboomp) 2026-08-08 19:38:32 +02:00
can1357 ba8e4dabd4 Merge PR #8014: fix(tui): bound WSL idle animation CPU (@roboomp) 2026-08-08 19:38:31 +02:00
can1357 ac55ea7697 fix(catalog): toggle qwen3.8 max thinking on wire 2026-08-08 19:38:31 +02:00
can1357 b28c2da29a Merge PR #8021: fix(catalog): correct qwen3.8 max discovery metadata (@roboomp) 2026-08-08 19:38:31 +02:00
can1357 025c1c4df6 Merge PR #8023: fix(task): record subagent model performance (@roboomp) 2026-08-08 19:38:17 +02:00
can1357 7ca140f66e fix(ai): routed policy-rejected accounts through sibling rotation
- Added account-scoped policy error detection to correctly identify Codex cyber-policy rejections.
- Updated credential storage and retry logic to route denied accounts through sibling rotation instead of bypassing it.
- Ensured coding-agent sessions exhaust all sibling accounts before falling back on cyber denials.
- Added comprehensive test coverage for credential rotation and retry behavior on policy errors.
2026-08-08 19:29:49 +02:00
can1357 abf80e4f74 feat(hashline): secured boundary repairs with parse checks and added warnings
- Gate closer-spare boundary repairs on tree-sitter parse validation to prevent incorrect rewrites on unrecognized languages or pathless edits.
- Add a warning when a `+` body row matches a valid hunk header format to flag accidental literal text insertion.
2026-08-08 19:02:11 +02:00
roboomp 506f57fbf2 fix(task): recorded subagent model performance
Shared the parent AgentStorage handle with isolated task settings while keeping setting overrides non-persistent.

Added regression coverage for task samples reaching the shared TPS/TTFT aggregate.

Fixes #8022
2026-08-08 15:59:27 +00:00
roboomp c0eda613c8 fix(catalog): kept qwen3.8 max preview on enable_thinking
Restored the preview to its main compat so the reasoning_effort dialect is scoped to qwen3.8-max, leaving the preview ladder unchanged.
2026-08-08 14:54:29 +00:00
roboomp 4d2c6e37f1 fix(catalog): preserved token plan preview vision
Applied curated Alibaba Token Plan seeds after generic models.dev fallback so bundled capabilities cannot be overwritten by incomplete upstream metadata.
2026-08-08 14:45:44 +00:00
roboomp 155fdaedba fix(catalog): corrected qwen3.8 max discovery metadata
Curated reasoning, multimodal input, context limits, and the provider-specific effort ladder for the discovered Alibaba Token Plan model.

Fixes #8019
2026-08-08 14:37:24 +00:00
can1357 731c051733 feat(pi-shell/minimizer): implemented length threshold and empty preservation
- Add minimum character threshold to bypass minimization for short outputs.
- Add preserve-if-empty configuration and pipeline support for filters.
- Update test fixtures and integration tests to meet length thresholds.
2026-08-08 16:27:03 +02:00
can1357 a30cbbb75d feat(hashline): implemented syntax validation and veto checks for patch application
- Add a tree-sitter syntax probe and parser veto to prevent syntax-unaware boundary repairs.
- Reject span pastes from empty named registers instead of deleting ranges.
- Reject duplicate top-level snapshot row line numbers during parsing.
- Export new syntax module symbols and add associated tests and changelog updates.
2026-08-08 16:18:34 +02:00
can1357 2728675ba3 docs: documented provider compatibility flags and specific quirks
- Added comprehensive reference documentation for OpenAI compatibility flags, reasoning levels, and tool handling policies.
- Detailed provider-specific quirks covering stream handling, authentication, quotas, and catalog model behaviors.
- Updated provider endpoint constraints with cross-references to the new compatibility and quirks references.
2026-08-08 16:18:17 +02:00
roboomp a6aa462a60 fix(tui): bounded WSL idle animation CPU
- Removed the Loader backpressure cap so slow ConPTY paints retain the documented proportional duty cycle.

- Made WSL terminal-title working state static to avoid a second periodic OSC write loop.

Fixes #8012
2026-08-08 13:17:01 +00:00
roboomp 88021b90ea fix(agent): drained in-flight session event handlers on dispose
agent-core dispatches the session's event subscriber fire-and-forget (agent.ts #emit), so a message_end/agent_end handler can still be awaiting extension/subscriber/maintenance work — and its sessionManager/agent.state append — after agent.waitForIdle() resolves. The earlier settle waited only on the core run, so a late handler could append the finished message/entries back into the disposed session and re-pin the transcript.

Track every #handleAgentEvent dispatch in #inFlightEventHandlers and drain it (alongside agent.waitForIdle) inside the bounded settle before reset/clear/release. Added a regression test using a real extension whose message_end hook blocks before persistence, asserting dispose does not release memory until the in-flight handler settles.
2026-08-08 10:26:41 +00:00
roboomp a7a32f35dd fix(agent): settled active turn before clearing session memory
dispose() only *signalled* the agent loop via abort(); it never awaited the run, so a mid-turn dispose (Ctrl-C/timeout/hard-killed subagent) could let the loop unwind after the release ran — its response/SSE interceptors re-recording wire frames into rawSseDebugBuffer and its terminal message re-appending to agent.state.messages, repopulating the disposed session with exactly the retained state the release drops.

Detach the response/SSE interceptors and await a bounded agent.waitForIdle() before the reset/clear so it lands on a quiescent session. Added a deterministic regression test that gates the active turn and asserts dispose blocks on it before clearing.
2026-08-08 10:06:55 +00:00
roboomp 4ca6c376b4 fix(agent): detached append-only context on dispose
Disposed sessions remained reachable through lifecycle reviver closures. Agent.reset() cleared the live message array but left AppendOnlyContextManager attached, retaining its normalized provider transcript and stable prompt/tool prefix.

Detach the append-only manager during terminal disposal and extend the memory-release regression test to cover that second transcript copy.
2026-08-08 09:52:15 +00:00
roboomp ed6300b35e fix(agent): release parked subagent session memory on dispose
Keep-alive subagents are handed to AgentLifecycleManager.adopt, which stores
their reviver closure in the process-global #adopted map. The closure is
defined inside runSubagent's scope, which also captures the live AgentSession
(extension-runner callbacks, buildSubagentSessionOptions), so its lexical
environment pins the whole session graph. park() disposes and detaches the
session but leaves the adoption record indefinitely, and #doDispose never
dropped the in-memory transcript, session-manager entries, or the raw-SSE
debug buffer (whose trimmed records retain slice() views of full wire frames),
so every completed subagent's heavy state leaked for the process lifetime.

dispose() is terminal and every revival path reopens from disk, so #doDispose
now sheds retained conversation memory via agent.reset(),
RawSseDebugBuffer.clear(), and SessionManager.releaseRetainedEntries(). The
adoption record can still reference the session, but only as a husk.

Fixes #8003
2026-08-08 09:42:35 +00:00
roboomp a709a6604f fix(web-search): parsed double-encoded zai results
Decoded the extra JSON string layer returned by Z.AI MCP search and kept structured payloads out of answer text.

Added regression coverage for source extraction and plain prose preservation.

Fixes #8000
2026-08-08 09:04:04 +00:00
roboomp fe86512268 fix(tui): parsed spaced nested command arguments
Share display-command arity with readArg and consume exactly that many
required arguments across whitespace. This keeps continuation newlines
collapsed to spaces without separating a nested command from its own
argument or letting it absorb the outer command's next argument.

Cover adjacent, spaced, and source-line-split sqrt and nested-fraction
numerators.

Fixes #7996
2026-08-08 09:03:00 +00:00
roboomp 7914e7c451 fix(session): preserved harness handoff abort reasons
Harness-initiated session aborts previously cancelled compaction before the handoff reason was recorded. The handoff catch then saw only an aborted signal and replaced the harness reason with "Handoff cancelled".

Abort the handoff first with the session reason, forward caller-signal reasons, and reserve "Handoff cancelled" for direct or unreasoned cancellation. Add a regression test for an in-flight handoff aborted through AgentSession.abort.

Fixes #7993
2026-08-08 09:02:28 +00:00
roboomp 9757a7b160 fix(tui): preserved outer arity through command arguments
Track pending command arities as nested frames instead of replacing the
outer frame when an unbraced command supplies an argument. Match readArg
by treating each command and its attached groups as one outer atom, while
retaining only that command's own missing arguments.

This keeps fractions such as `\frac\sqrt{a}\n{b}` waiting for their
denominator without folding standalone braced rows.

Fixes #7996
2026-08-08 08:52:02 +00:00
can1357 d1eafe7a62 feat(pi-builtins): prevented kill builtin from targeting ancestor processes
- Added `HostProcesses` snapshot and `ChainNode` validation to track ancestry and prevent pid recycling.
- Updated process matching and signal handling to refuse signalling the shell or its ancestor processes.
- Added regression tests verifying that kill builtins safely block ancestor targeting while permitting unrelated processes.
- Added the `smallvec` dependency to support efficient process snapshot tracking.
2026-08-08 10:42:55 +02:00
roboomp 2504800a4b fix(tui): only suppress a math row break when a command owes an argument
The first pass suppressed the top-level newline split whenever the next
row opened with `{`, folding a genuine braced row (`a\n{b+c}`) into the
row above. Gate the continuation on bracesOwed(): a newline joins to the
next row only when the current row ends with a command still awaiting a
brace argument (`\frac{num}\n{den}`, `\frac\n{a}{b}`, `x^\n{2}`); a row
that merely opens with a braced group stays a real row break.

Fixes #7996
2026-08-08 08:40:07 +00:00
roboomp 0f7e379006 fix(tui): keep display-math fractions intact across source newlines
latexToBlock pre-split display math on top-level newlines to stack a
`lhs =` line above its block, but a newline between `\frac{num}` and
`{den}` falls at brace-depth 0 and was treated as a row break, severing
the fraction from its denominator and rendering it as fragmented text.

Treat a top-level newline whose next non-space token opens a `{…}`
argument group as an argument continuation rather than a row break, and
collapse those interior newlines to a space so the argument reader parses
both brace groups.

Fixes #7996
2026-08-08 08:30:48 +00:00
roboomp 92e574cb02 fix(session): surface empty handoff generation as failure not cancel
The #7904 fix stopped masking provider errors as "Handoff cancelled", but
an empty or whitespace-only generation still fell through: whitespace-only
text passed the `!handoffText` guard and produced a bogus handoff, while
empty text returned undefined which the interactive /handoff caller mapped
to "Handoff cancelled" with no detail and no log entry.

Treat empty/whitespace-only output as a real failure: a user-initiated
handoff throws "Handoff generation produced no content" (surfaced as
"Handoff failed: ...") and logs it; auto-handoff keeps returning undefined
so maintenance falls back to context-full compaction. Also log genuine
handoff failures in the command controller so they persist for debugging.

Fixes #7993
2026-08-08 08:21:16 +00:00
can1357 2ee9943563 refactor: unify builtins in one place 2026-08-08 10:19:25 +02:00