Commit Graph

426 Commits

Author SHA1 Message Date
can1357 c64e7146e0 refactor(coding-agent): consolidated jujutsu logic into a centralized utility module
- Consolidated Jujutsu (jj) integration logic into a centralized utility module with working-copy and status handling.
- Removed deprecated jj-info helper modules and their corresponding test files.
- Updated status line component and associated tests to consume the new centralized jj utility API.
- Added comprehensive test coverage for working-copy label parsing, status summary mapping, and repository root resolution.
2026-07-23 20:47:42 +02:00
can1357 8490654df3 refactor(coding-agent): expressed run state via the title separator instead of prefix glyphs
Kept the bare 'π' brand per owner direction: the separator between the
brand and the session label now carries the state — '>' when it's the
user's turn (idle), animated spinner frames while working, '!' when the
agent is blocked on the user. Disabled ('tui.titleState' off) renders the
pre-state 'π: label' layout. Updated the state/runtime tests to the new
contract.
2026-07-23 17:31:30 +02:00
can1357 0dac3d45b5 Merge PR #4451: feat(coding-agent): reflect agent run state in terminal title (@mattwilkinsonn)
# Conflicts:
#	packages/coding-agent/src/modes/controllers/event-controller.ts
#	packages/coding-agent/src/modes/interactive-mode.ts
2026-07-23 17:31:30 +02:00
can1357 42a3da21de Merge PR #4001: feat(coding-agent): opt-in Markdown read previews (@oldschoola) 2026-07-23 17:30:33 +02:00
can1357 8a9aa0342d chore: format evaluator fix commits and suppress intentional DAP placeholder lint 2026-07-22 21:16:38 +02:00
can1357 9720c091ff Merge PR #6235: fix(coding-agent): show changelog in standalone binaries (@roboomp) 2026-07-22 21:13:22 +02:00
can1357 a07d72f638 fix(git): report missing cwd distinctly from missing git binary
A deleted/nonexistent cwd also makes Bun.spawn throw ENOENT; only claim
'git is not installed.' when the working directory actually exists, else
name the missing directory. Addresses the Codex P2 review on #6237.
2026-07-22 21:13:21 +02:00
roboomp d0f1cd1b77 fix(git): degrade gracefully when git binary is missing
The read-only git helpers spawned `git` directly and only inspected the
result exit code. When git is absent from PATH, Bun's spawn throws ENOENT
(uv_spawn 'git') at launch, which escaped as an unhandled rejection and
crashed the process (e.g. Windows without git, relying on WSL git).

Translate a missing-binary launch failure into a non-zero GitCommandResult
in the async git() wrapper and into a null degrade in the sync reftable ref
readers, matching the existing non-zero-exit handling. Mutating/checked
commands keep surfacing the clean "git is not installed." error.

Fixes #6169
2026-07-21 22:07:42 +00:00
roboomp b3ec980da4 fix(coding-agent): embedded changelog in standalone binaries
Bundled the release history as a fallback when package assets cannot be resolved, while preserving external package-directory overrides.

Added regression coverage for the compiled-binary fallback.

Fixes #6172
2026-07-21 22:06:46 +00:00
oldschoola 4a065e3d89 fix(status-line): aggregate vibe worker tok/s into the status-line badge
In /vibe mode the director is often idle while workers stream, so the
status-line tok/s badge showed a stale/zero rate even while parallel
workers were actively generating tokens. The badge now aggregates the
main session's live tok/s with every live vibe worker's tok/s, and
falls back to the main session's own cached rate when no workers are
streaming.

- Extract calculateTokensPerSecond to utils/token-rate.ts (neutral
  location) so vibe/runtime.ts can depend on it without the render
  layer depending on the heavy vibe/task graph.
- Add aggregateVibeWorkerTokensPerSecond to vibe/runtime.ts: sums
  each live worker's rate via the shared calculator, returns null
  when no workers are streaming so the main rate shines through.
- StatusLineComponent takes the aggregator via an injected
  setVibeWorkerTokenRateProvider callback (wired in interactive-mode)
  keeping the render layer off the vibe/task dependency graph.
- #getTokensPerSecond splits into #getMainSessionTokensPerSecond
  (preserves the sticky per-assistant-message cache) plus the
  worker-aggregation path, so the director-idle case no longer
  short-circuits to null.
2026-07-19 13:03:38 -07:00
can1357 8f2cd23e39 Revert "Merge PR #5812: fix(read): honor exact line selector bounds (@roboomp)"
This reverts commit 58c71d5b50, reversing
changes made to 7c7227bc8e.
2026-07-18 22:04:43 +02:00
can1357 58c71d5b50 Merge PR #5812: fix(read): honor exact line selector bounds (@roboomp) 2026-07-18 20:12:46 +02:00
can1357 df9b04a0eb fix(task): canonicalize the shared-common-dir gate in detachGitDir
rev-parse --git-common-dir resolves symlinks while ensureIsolation derives
sourceCommonDir lexically from the session cwd (resolveRepository walks
path.resolve'd components). On any symlinked repo path (macOS /tmp,
symlinked project dirs) the lexical comparison missed, detachGitDir
returned "independent", and the parent-mutation leak silently survived.
Realpath both sides before comparing; regression test drives the gate
through a symlink alias.
2026-07-18 19:42:36 +02:00
can1357 53437aff3d fix(task): harden detachGitDir edge handling
- Match the rcopy worktree-add registration via realpath: git canonicalizes
  the admin gitdir back-reference (macOS /var -> /private/var), so the
  lexical comparison missed it and left a stale registration in the source
  repo's worktree list.
- Carry core.fileMode so an explicit filemode=false source does not read as
  mode-changed files in the detached isolation.
- Carry core.splitIndex and the sharedindex.* files referenced by a split
  source index; restoring the raw index without them broke every git read.
- Carry the source shallow boundary file so history traversal over the
  borrowed object DB stops at the boundary instead of failing.
- Regression test covering all three carries.
2026-07-18 19:42:36 +02:00
roboomp 970043bd8a fix(task): preserve sparse-checkout state when detaching isolation
A fresh `git init` in detachGitDir dropped core.sparseCheckout and the
sparse-checkout patterns, and rebuilding the index via write-tree/
read-tree discarded skip-worktree bits. Files intentionally absent from
a sparse working tree then read as deletions, which delta capture could
apply back to the parent.

detachGitDir now restores the index verbatim (preserving skip-worktree,
assume-unchanged, and exact stage entries) and carries
core.sparseCheckout, core.sparseCheckoutCone, and info/sparse-checkout
into the detached .git before restoring the index. Falls back to
read-tree HEAD only when the source had no index.

Fixes #6003
2026-07-18 17:04:40 +00:00
roboomp 37304a12a3 fix(task): detach unborn linked worktrees from parent checkout
A linked git worktree with an unborn HEAD (a fresh/orphan branch with no
commits) still shares the parent's common dir, so an isolated task's
first branch and commit would write into the parent repo. The previous
early return on a missing HEAD SHA left that shared metadata intact.

detachGitDir now severs unborn worktrees too: `git init -b <branch>`
preserves the checked-out branch name, ref freezing is gated on a born
HEAD, and the rcopy worktree registration is still removed.

Fixes #6003
2026-07-18 16:57:41 +00:00
roboomp afea682b7f fix(task): detach isolated worktree git dir from parent checkout
Copy isolation backends (reflink/apfs/btrfs/zfs/block-clone/rcopy)
materialise the worktree by duplicating its `.git` verbatim. When the
parent is a linked git worktree its `.git` is a pointer file, so the
isolation shared the parent's HEAD/index/ref namespace: a task's
`git checkout`/`commit` moved the parent's branch, and the rcopy
`git worktree add` path stacked task branches in the shared namespace.

`ensureIsolation` now runs `git.detachGitDir` after `isoStart`, turning
each isolation into a standalone repo with a frozen HEAD/refs/index
snapshot that borrows the source object database via
`objects/info/alternates`. Isolated git ops stay private, every task
branch is parented on the requested base, and patch/branch capture
(`git fetch <merged>`) still resolves objects.

Fixes #6003
2026-07-18 16:48:33 +00:00
roboomp 22a8524058 fix(tools): recognized zip-family archives and pruned unconvertible extensions
- Treated ZIP-based .jar/.war/.ear/.apk as zip archives in archiveFormatFromPath and parseArchivePathCandidates so read/write member access works.
- Shared one archive-extension alternation between format detection and path splitting to stop them drifting.
- Derived the markit convertible-extension set from a single source of truth (utils/markit) matching the registered converters (pdf/docx/pptx/xlsx/epub), dropping legacy .doc/.ppt/.xls/.rtf that had no converter and only produced Unsupported format errors.
- Updated read/write tool prompts to document the zip-family extensions.

Fixes #5808
2026-07-17 08:04:10 +00:00
roboomp e5d5aec189 fix(read): enforced exact line selector bounds
- Removed implicit padding and syntactic boundary expansion from explicit ranges.
- Covered local, converted, multi-range, and artifact reads.

Fixes #5802
2026-07-17 07:45:39 +00:00
can1357 1074332098 fix(task): abort background label generation 2026-07-17 04:15:40 +02:00
roboomp 3cb9258875 fix(session): aborted title generation during dispose
- Routed automatic first-input and replan title requests through AgentSession lifecycle cancellation.
- Propagated disposal aborts to online provider and local tiny-model title generation.
- Added a regression test proving an in-flight title request settles when disposal begins.

Fixes #5666
2026-07-16 07:17:27 +00:00
can1357 c897f54a07 Merge PR #5459: fix(coding-agent): reject prose thinking session titles (@roboomp) 2026-07-14 22:58:46 +02:00
roboomp 3666cb93d2 fix(coding-agent): rejected prose thinking session titles
Rejected markerless prose thinking preambles while preserving marked titles and plain markerless title responses.

Fixes #5252
2026-07-14 17:48:15 +00:00
can1357 f9f6ed9e8d feat(coding-agent): replaced legacy pi/ role alias prefix with
- Replaced legacy `pi/` role alias prefix with canonical `@` syntax across model resolution, documentation, and tests.
- Added support for bare `*` default alias and multiple alias prefix detection with custom role resolution in `resolveConfiguredRolePattern()`.
- Enhanced thinking suffix parsing to accept unambiguous abbreviations (minimum 2 characters) for effort and level selectors.
- Extended `resolveCliModel()` and `filterAvailableModelsByEnabledPatterns()` to accept settings parameter for role alias resolution from `--model` flag.
2026-07-13 23:26:33 +02:00
can1357 93635e7b6a feat(coding-agent): centralized preprocessing and guidance for small models
- Centralized message preprocessing for tiny models to handle noise removal, code block stripping, and context formatting.
- Updated title generation logic to support self-closing tags and improved robustness against partial markers.
- Added structured guidance and system prompts for small models to prioritize output consistency.
- Implemented a title-generation benchmark harness and expanded test coverage for message preprocessing.
2026-07-11 12:28:18 +02:00
can1357 95f2bb3e93 Merge remote-tracking branch 'origin/farm/872f49e0/fix-commit-false-success' 2026-07-11 07:41:28 +02:00
can1357 c148c49bdf Merge remote-tracking branch 'origin/farm/9d12b947/strip-title-thinking' 2026-07-11 07:41:10 +02:00
roboomp 449310eb16 fix(coding-agent): kept startup changelog version current
- Preserved newest-first ordering for startup changelog markdown so collapsed notices report the current release.
- Kept default changelog rendering oldest-first for explicit recent/full views.
- Added regression assertions for both startup and full-history heading order.
2026-07-11 02:43:25 +00:00
roboomp f534112957 fix(coding-agent): bound startup changelog rendering
- Treated missing or invalid changelog markers as first install and persisted the current version without replaying historical notes.
- Shared bounded changelog rendering between startup and recent changelog views, with a 64 KiB startup cap and full-history hint on truncation.
- Added marker, truncation, recent/full rendering, and PTY startup regression coverage.

Fixes #5135
2026-07-11 02:28:27 +00:00
roboomp 159484ca6f fix(commit): created commits before agent teardown
- Ran commit host completion before commit-agent session disposal so mnemopi/autolearn teardown cannot preempt a valid proposal.

- Converted missing commit-agent host outputs and split-plan gaps into thrown errors so omp commit cannot resolve into exit 0 without creating a commit.

- Preserved caller GPG_TTY state instead of forcing a bogus signing TTY in git and non-interactive subprocess environments.

Fixes #4794
2026-07-11 00:58:34 +00:00
roboomp a16c60014c fix(coding-agent): hid reasoning envelope title markers
- Applied the known reasoning envelope filter when deciding whether a title marker is visible.

- Added title extraction regressions for reasoning tag and reasoning fence envelopes before the visible title.

Fixes #5122
2026-07-10 23:27:00 +00:00
roboomp 65b0f05326 fix(coding-agent): preserved markerless thinking titles
- Limited markerless fallback cleanup to leading leaked-thinking envelopes so literal reasoning syntax in plain titles survives.

- Added markerless regression coverage for think tags and thinking-fence titles.

Fixes #5122
2026-07-10 23:12:42 +00:00
roboomp 0420d44d3f fix(coding-agent): preserved reasoning syntax in titles
- Parse only title markers that remain visible after leaked-thinking cleanup so markers inside leaked reasoning are skipped.

- Preserve literal reasoning tag syntax inside the chosen title and cover it with a regression test.

Fixes #5122
2026-07-10 23:00:22 +00:00
roboomp 851186f5de fix(coding-agent): stripped thinking from session titles
- Reused the leaked-thinking healer before parsing title markers so visible reasoning envelopes cannot win extraction.

- Added regression coverage for <thinking> and <think> envelopes that contain internal title tags before the real title.

Fixes #5122
2026-07-10 22:41:27 +00:00
can1357 6dbbfbe1e0 feat(coding-agent): renamed explore agent to scout
- Renamed the `explore` agent to `scout` throughout prompt templates, agent definitions, and configuration schemas.
- Updated documentation and internal tool references to reflect the new agent identity.
2026-07-10 12:51:50 +02:00
Matt Wilkinson 55630876f5 fix(coding-agent): reconcile terminal title run-state with session lifecycle
Reset the run-state title to idle when focusing an idle session (was inheriting the previous session's stuck spinner); drive the title to attention while a tool blocks on an approval prompt (not just ask), returning to working at its end; let an extension setTitle() own the terminal verbatim so neither the run-state prefix nor the spinner tick clobbers it, cleared when the app sets an authoritative session title; use NodeJS.Timeout for the spinner timer field.
2026-07-09 22:51:32 -04:00
Matt Wilkinson 997f2c5e8b feat(coding-agent): reflect agent run state in terminal title
The terminal title (OSC 0) now carries a run-state prefix: an animated spinner while the agent is working and a steady dot when idle, so a backgrounded tab/pane shows which session is busy vs done. `setTerminalTitleState` also exposes an `attention` ([!]) state for callers; rendering is gated by `tui.titleState` (default on), dedups writes, and is TTY-guarded.
Refs can1357/oh-my-pi#3587
2026-07-09 22:51:32 -04:00
can1357 0e74c85c08 fix(coding-agent/utils): filtered gpt-5 reasoning comment noise
- Removed literal HTML comment sentinels (`<!-- -->`) from thinking block displays.
- Added logic to hide blocks that consist entirely of reasoning noise and updated display validation to omit empty formatted output.
- Refactored the memoization cache to maintain separate slots for prose and raw modes.
2026-07-09 20:09:15 +02:00
can1357 c641e11790 merge PR #4643: fix(coding-agent): use local date in system prompt 2026-07-08 15:19:36 +02:00
can1357 3673b16684 merge PR #4638: fix(open): report Windows opener failures via Start-Process exit codes 2026-07-08 15:19:35 +02:00
can1357 04783381b4 feat(coding-agent): transitioned session title generation to xml markers
- Replaced tool-based `set_title` invocation with XML-style `<title>` marker tags for session title discovery.
- Implemented robust JSON-unwrapping logic to handle and sanitize title generation outputs.
- Updated model registry in catalog with new model support, provider prefixes, and metadata adjustments.
- Synchronized system prompt documentation and test suites to reflect the new marker-based generation flow.
2026-07-06 17:38:00 +02:00
Christian Stewart 722a06abce fix(coding-agent): use local date in system prompt
Signed-off-by: Christian Stewart <christian@aperture.us>
2026-07-05 16:03:44 -07:00
Dylan Bohlender 862f821d76 fix(open): report Windows opener failures via Start-Process exit codes
Follow-up to the #4420 opener hardening: absolute-path rundll32 fixes the
stripped-PATH spawn throw, but rundll32 exits 0 unconditionally, so the
delayed-failure telemetry added there can never observe a Windows launch
failure. Replace it with %SystemRoot%-resolved PowerShell Start-Process
via -EncodedCommand:

- failures ShellExecute itself reports (missing target, no handler
  executable, access denied) surface as exit code 1 and reach the
  existing non-zero-exit logging (verified live on Windows 11: missing
  file exits 1; unregistered schemes exit 0 on any opener because the
  OS hands them to the app-picker — documented limitation);
- the UTF-16LE/base64 payload keeps OAuth query strings opaque to
  cmd/PowerShell metacharacter parsing; embedded single quotes are
  doubled into a PS literal;
- %SystemRoot% anchoring with a bare-name PATH fallback preserves the
  stripped-PATH resilience from #4420.

Also pins the WSL-mount test's path.resolve against Windows dev hosts
so the mocked linux platform stays deterministic.

Refs #4418
2026-07-05 15:53:36 -06:00
can1357 91db5eb661 Merge PR #4265: fix(bash): delete pre-created snapshot file on creation failure (@metaphorics) 2026-07-05 13:39:08 +02:00
can1357 600191b6f5 Merge PR #4356: fix(coding-agent): size title budget for backends that ignore disableReasoning (@roboomp) 2026-07-05 13:25:25 +02:00
can1357 a96f2f9292 Merge remote-tracking branch 'origin/farm/ab9741c2/fix-mcp-oauth-windows-opener-and-url-truncation' 2026-07-04 05:14:28 +02:00
roboomp 3b135eead8 style: bun run fix 2026-07-03 14:19:32 +00:00
roboomp 12acf7e645 fix(task): auto-skipped empty commits during task-branch cherry-pick
An intermediate commit whose net effect is already on HEAD (redundant
change, or 3-way merged to HEAD by "theirs == ours") stopped the
sequencer with "The previous cherry-pick is now empty" and was
treated as a hard conflict. mergeTaskBranches aborted the whole range,
marked the branch failed, and dropped every remaining non-overlapping
commit.

Add cherryPick.skip and cherryPick.isEmptyError to the git namespace,
then in mergeTaskBranches' catch classify the failure before aborting:
loop --skip while the error stderr matches the "now empty" phrase so
consecutive empties advance the sequencer; fall through to abort/fail
on the first non-empty error (genuine conflict with unmerged files).

Fixes #4438
2026-07-03 14:19:16 +00:00
roboomp 97c1d08cce fix(mcp): surface a short launch URL and log Windows opener failures for OAuth
Two independent defects broke /mcp reauth against S256-only providers on
Windows boxes whose PATH no longer references System32:

1. openPath spawned bare rundll32 and swallowed the
   `Executable not found in $PATH` throw with a bare `catch {}`, so the MCP
   controller's outer try/catch was dead and the transcript unconditionally
   claimed "Opening browser automatically...".
2. TUI#prepareLine silently truncates any composed row wider than the
   viewport. MCPAuthorizationLinkPrompt rendered `Copy URL: <full URL>` as a
   single ~271-column line whose trailing parameter is
   code_challenge_method=S256. On the reporter's 270-col terminal the cut
   landed inside that parameter, dropping the method while keeping
   code_challenge — which RFC 7636 §4.3 treats as plain PKCE, which Linear
   correctly rejects with "The plain PKCE method is not allowed. Use S256
   instead."

OAuthCallbackFlow now hosts a `GET /launch` route on the same loopback
callback server it already runs; the route 302-redirects to the pending
authorization URL and is advertised as `OAuthAuthInfo.launchUrl` — a
~30-char copy target no viewport can meaningfully truncate. The MCP OAuth
fallback, /login, setup wizard, auth-broker CLI, and login-dialog all
prefer the launch URL for the visible copy target, keep the full URL in
the OSC 8 hyperlink for click-through, and the MCP flow additionally
stages the copy target on the clipboard via OSC 52 (same pattern the
setup wizard uses).

openPath now resolves rundll32.exe through %SystemRoot%\System32 (with a
C:\Windows fallback when SystemRoot is unset) and logs both synchronous
spawn throws and non-zero exits via the shared logger, so silent
misconfigurations show up in ~/.omp/logs/omp.*.log. The dead try/catch
around openPath in the MCP controller is removed.

Fixes #4418
2026-07-03 08:19:14 +00:00
roboomp 8886a528dc fix(coding-agent): size title/commit/speech/classifier budgets for backends that ignore disableReasoning
Sizing `maxTokens` off the static `model.reasoning` catalog flag cannot
distinguish a thinking model catalogued `reasoning: false` (e.g. Qwen3
served locally via llama.cpp, whose bundled jinja chat template defaults
`enable_thinking: true`) from a model that never emits thinking. The
tight non-reasoning budget was consumed by the thinking preamble before
the useful output could be emitted, so every affected call silently
failed with `stopReason: "length"`.

Drop the `model.reasoning` conditional across every affected online call
site and always reserve the reasoning-safe budget. `maxTokens` is a hard
cap, not a target — non-thinking completions still return in the tiny
happy-path budget.

Sites fixed:
- utils/title-generator.ts       (30   -> 1024)
- utils/commit-message-generator (60   -> 1024)
- tts/speech-enhancer            (512  -> 1536)
- auto-thinking/classifier       online path (8  -> 1024); classifyLocal
                                  keeps its separate LOCAL_ANSWER_MAX_TOKENS
- session/unexpected-stop-classifier online path (16 -> 1024);
                                  classifyLocal keeps ANSWER_MAX_TOKENS

Fixes #4355
2026-07-03 00:47:20 +00:00