Commit Graph

97 Commits

Author SHA1 Message Date
can1357 da636e3f51 feat(coding-agent): enabled clickable image and path links across chat and tools
- Added image-reference rendering to make `[Image #N]` placeholders clickable in chat.
- Added MIME-aware image blob materialization with extensioned sidecar paths.
- Added clickable path, line, and URL hyperlinks for read, search, and fetch outputs.
- Hardened OSC8 hyperlink emission with URI validation and control-byte/idempotency checks.
2026-06-05 23:38:22 +02:00
can1357 7124dbae93 fix(coding-agent): fixed session resume to reconcile modes and preserve model state
- Registered and triggered a session-switch reconciler during init and after switch.
- Rebuilt resume flow to restore plan/goal mode state and clear stale mode flags.
- Marked fallback and context-promotion model switches ephemeral and skipped them on restore.
- Added regression tests for temporary model ordering, fallback precedence, and mode cleanup.
2026-06-04 17:22:19 +02:00
can1357 5e17edf1ec refactor(coding-agent): restructured session text slicing to use unified head/tail reads
- Replaced SessionStorage readTextPrefix/readTextSuffix with readTextSlices.
- Added peekFileEnds utility to read bounded file head/tail in one handle.
- Updated session-manager list/recent reads to consume unified head/tail slices.
- Expanded storage tests for head/tail and UTF-8-boundary slice extraction.
2026-06-04 02:07:34 +02:00
can1357 e6716d086d feat(coding-agent): added lifecycle status to session picker
- Classified each session's final message as done, interrupted, aborted, error, or pending from a 32 KiB tail read.
- Rendered the status as a colored segment on the session metadata line.
- Added `peekFileTail` and `readTextSuffix` across storage backends to read file tails in one pass.
- Simplified `MemorySessionStorage` to a string array mirror with a sidecar mtime map.
2026-06-04 01:58:25 +02:00
roboomp cf9eb5b0f9 fix(coding-agent): skipped temporary resume models
Treat temporary model_change roles as non-restorable when resuming sessions so context-promotion and retry-fallback models do not override the saved default.\n\nFixes #1649
2026-06-02 09:15:45 +02:00
roboomp 00adc9c5d6 fix(coding-agent): fell back to saved default on resume
Try the last active role model first, then the saved default model when the role model cannot be restored during session switching or startup resume.\n\nFixes #1649
2026-06-02 09:15:45 +02:00
roboomp bb0991e6f3 fix(coding-agent): restored last active role model
Use the last model_change role when resuming an existing session instead of always restoring models.default. Covered both /resume switchSession and startup continue paths.\n\nFixes #1649
2026-06-02 09:15:44 +02:00
can1357 7b3ea248d4 feat(coding-agent): enabled cross-project resume with folder/all scope fallback
- Enabled resume picker to preload sessions and toggle folder/all scope with Tab.
- Enabled resume flow to fall back to all-project sessions and switch cwd on resume.
- Added centralized applyCwdChange to refresh caches, commands, and UI after cwd updates.
- Updated session restoration to adopt restored session cwd and sessionDir when present.
2026-06-02 05:53:57 +02:00
can1357 2ddc9c5bc9 feat(coding-agent): added turn-budget parsing, multipliers and hard caps
- Added +Nk/+Nm turn-budget parsing with whitespace-boundary matching, multipliers, and hard `!` indicator.
- Added per-turn budget lifecycle plus APIs (`getTurnBudget`, `recordEvalSubagentUsage`) and hard-cap checks in eval runs.
- Added hard budget observability in eval preludes and docs by exposing `budget.hard` and documenting ceiling modes.
- Fixed streaming preview stutter with max-row tracking and padding, with tests for preview height and budget parsing.
2026-05-31 08:03:45 +02:00
can1357 420429df9c fix(session): extended dangling tool_use stripping to all mid-path assistant turns
- Previously only stripped dangling tool_use blocks from the trailing assistant turn; now scans all assistant turns on the resolved path.
- Builds a set of paired tool result IDs upfront to identify dangling calls anywhere in the message list.
- Adds a test covering a mid-path dangling turn alongside a correctly paired turn that must be preserved.
2026-05-30 03:52:55 +02:00
can1357 f6bf17d8cc fix(session): neutralized signed thinking blocks on dangling tool-use cleanup
- Stripped `redactedThinking` blocks (encrypted, no downgradeable plaintext) from trailing assistant turns during context rebuild.
- Cleared `thinkingSignature` on `thinking` blocks so the encoder downgrades them to plain text, avoiding Anthropic's "modified latest assistant message" rejection.
- Extended existing test to cover signed/redacted thinking alongside dangling tool calls.
2026-05-30 02:06:29 +02:00
can1357 684af3321f fix(coding-agent/session): patched session dangling tool-call cleanup
- BuildSessionContext now normalized a trailing assistant turn by removing dangling `toolCall` blocks when rewound or restored onto that turn.
- It dropped the assistant turn entirely when only tool calls remained to prevent reconstruction from reintroducing synthetic aborted tool results.
2026-05-30 01:16:33 +02:00
can1357 79f6bf4f76 fix(session-manager): added orphaned backup recovery after EPERM rename
- Added `recoverOrphanedBackups` to promote `.jsonl..bak` files back to their primary path when the primary is missing, preventing data loss after a mid-rename crash.
- Changed backup filename from dot-prefixed to plain `..bak` so the shared `*.bak` glob can find it on both real and in-memory storage backends.
- Surfaced the original EPERM as the error `cause` and included both original and retry messages when rollback also fails.
2026-05-25 14:05:41 +02:00
roboomp 84eb837b00 fix(session): handled eperm during session rewrite
Replaced overwrite-style session rewrites with an EPERM fallback that moves the old session file aside before retrying and restores it if the retry fails.

Added regression coverage for active-session rewrite recovery so the session remains writable after the fallback.

Fixes #1337
2026-05-24 18:00:42 +00:00
can1357 35beac2972 fix(coding-agent): defer persist when writer is mid-close
`SessionManager.close()` queues `#closePersistWriterInternal()` on the
persist chain. The task awaits `#persistWriter.close()`, which flips
`#closing = true` synchronously before yielding on its inner writer
`close()`. A concurrent `appendMessage()` landing in that yield window
hit the hot path, got the still-cached (but closing) writer back from
`#ensurePersistWriter()`, and threw `Error("Writer closed")` from
`writeSync`. The throw was stashed into `#persistError`; the next async
caller (`flush()` or a later `appendMessage()`) re-threw it as an
unhandled rejection with the original line-1282 stack.

Expose `NdjsonFileWriter.isOpen()` and treat a mid-close cached writer
as a miss in `#ensurePersistWriter()`. `_persist` now falls back to the
async `#rewriteFile()` cold path so the entry — already in
`#fileEntries` — still lands on disk once the close drains.
2026-05-15 17:00:18 +02:00
can1357 71f3997afa fix(session): resolved session persistence flow to use sync write/read APIs
- Added sync truncation helpers to recursively prepare session entries and externalize image data.
- Reworked session persistence to use synchronous preparation plus `writeSync` with close-state checks.
- Added synchronous session-storage APIs and rerouted write paths to `writeLineSync`/`readTextSync`.
- Added `BlobStore.putSync`, migrated hashing to `Bun.SHA256`, and updated hash tests accordingly.
2026-05-14 06:12:41 +02:00
cognitive 44e5e0bb80 fix(coding-agent/tui): rendered queued /skill: as compact pending chip 2026-05-13 08:17:15 +00:00
can1357 9ed81977f7 feat(coding-agent): shared artifact manager and flat output directory across subagent sessions
- Added parent-to-subagent artifact manager adoption so subagents reuse the parent `ArtifactManager` and write artifacts into a shared directory with shared IDs.
- Passed the shared artifact manager through tool/session context into subagent executor startup and exposed it via `SessionManager` and `ToolSession` for lookup.
- Updated kernel environment and artifact-resolution paths to prefer `PI_ARTIFACTS_DIR`, falling back to existing session-file-based behavior when absent.
2026-05-12 05:17:53 +02:00
can1357 c2a0253028 feat(coding-agent): added unsent editor draft persistence for resumed sessions
- Added session-draft persistence methods in SessionManager to write unsent editor text to an artifacts-sidecar draft file and delete it after single-shot consumption.
- Persisted editor text during interactive shutdown and restored that draft on resume when the editor was empty, enabling Ctrl+D draft recovery.
- Updated Ctrl+D handling in the editor/controller path and added tests covering draft round-trip, artifact cleanup, stale-draft eviction, and in-memory no-op behavior.
2026-05-04 02:20:29 +02:00
can1357 7467add484 refactor(coding-agent): unified session title and accent handling around session names
- Removed title-source aware branching from session terminal-title and accent helpers, and updated callers to use session name plus cwd only.
- Dropped UUID-based recent-session naming by preferring explicit header titles or first user prompts and generating an "Untitled · <time>" fallback.
- Adjusted welcome session-row rendering for width-aware name truncation and disabled reasoning in title generation requests to keep terminal titles concise.
2026-05-02 01:42:06 +02:00
can1357 08403be71f fix(coding-agent): preserve explicit default model on session resume
buildSessionContext walked the entry path and unconditionally overwrote
models.default from every assistant message's reported model. Temporary
fallbacks (retry fallback, context promotion) and codex-side model
downgrades both produce assistant messages tagged with a different model
id, which clobbered the user's explicit /model pick on resume and made
the session silently revert to the older model.

Treat assistant-message inference as a legacy fallback that only fills
in models.default when no explicit `model_change` with role="default"
has been seen on the path.

Fixes #849
2026-04-30 04:51:23 +02:00
Miroslav Drbal 4ad7a9d754 fix(coding-agent): address /drop reviewer findings
- dropSession: close persist writer before deletion to prevent EPERM
  on Windows where an open file handle blocks unlink
- #runNewSessionFlow: guard UI reset on newSession return value;
  session_before_switch hook cancellation now prevents chat state
  being cleared and success banner being shown
2026-04-26 10:36:38 +02:00
Miroslav Drbal d9d870bab4 feat(coding-agent): add /drop command to delete current session and start fresh
/drop works like /new but permanently deletes the current session file
and artifacts instead of flushing (saving) it. Useful when the session
should not be kept.

- add drop?: boolean to NewSessionOptions
- branch in AgentSession.newSession(): skip flush, delete via
  FileSessionStorage.deleteSessionWithArtifacts when drop=true;
  deletion failure is non-fatal (logged, new session still starts)
- wire handleDropCommand() through InteractiveModeContext interface,
  InteractiveMode delegation, and CommandController implementation
- guard: shows error if session has not been saved yet (no file to drop)
- register /drop in builtin-registry adjacent to /new
2026-04-26 10:00:48 +02:00
can1357 5de4774f16 fix: session listing
- Session metadata now stores on-disk size bytes, populated from file stats when collecting sessions.
- The session selector metadata line now renders file size using formatBytes instead of message counts.
- Session test fixtures were updated with the new size property so they match the revised SessionInfo shape.
2026-04-26 06:59:47 +02:00
can1357 ac76f0d66a perf(coding-agent/session): reduced session listing via strided workers
- Parallelized `collectSessionsFromFiles` via strided workers sized by file count and CPU parallelism, reducing large-list latency.
- Read only a fixed 1024-byte prefix per session file in `collectSessionFromFile`, avoiding full-file scans.
- Added partial-prefix fallbacks to extract session title and first user message when JSONL parsing is incomplete.
2026-04-24 13:57:39 +02:00
can1357 caef52f5e2 fix(coding-agent/session): switched session listing to async glob scanning
- Updated SessionManager.listAll to retrieve session files with Bun.Glob.scan instead of scanSync.
- Awaited the async glob scan results via Array.fromAsync before collecting session metadata.
2026-04-24 13:50:51 +02:00
can1357 2921332c44 fix(coding-agent/session): swallow fire-and-forget persist rejections
When persist writes race with test-level tempDir cleanup (e.g. in agent-session-auto-compaction-queue.test.ts), fs.rename can fail with ENOENT during the atomic swap inside #writeEntriesAtomically. The error is already routed through #persistChain so #persistError surfaces it to future persist calls, but the awaited rejection returned by #queuePersistTask was bubbling out of the fire-and-forget callers (#rewriteFile path and the incremental writer path) and Bun's test runner reported it as an 'Unhandled error between tests' even though the test itself passed. Attach a silent .catch on both void paths so the rejection is considered handled at the callsite while the persistChain retains the error state.
2026-04-17 19:44:44 +02:00
can1357 22b1685394 fix(ai): resolved OpenAI cache routing
- Replaced Snowflake session IDs with UUIDv7 for created, forked, branched, and resumed sessions.
- Derived cache session IDs from OpenAI request options and passed them into Responses client creation.
- Used derived session IDs for OpenAI `session_id`/`x-client-request-id` headers and `prompt_cache_key`; omitted headers when retention was none.
- Added tests for UUIDv7 session creation/branching and OpenAI cache-affinity default, override, and disabled-header modes.
- Documented UUIDv7 session handling and OpenAI cache-routing fixes in package Unreleased changelogs.
2026-04-15 08:18:21 +02:00
can1357 d2202d0b0b fix(coding-agent): ignore auto titles for session accent 2026-04-13 00:42:24 +02:00
can1357 78c888ec16 merge: PR #687 2026-04-13 00:31:39 +02:00
Christoph Gross 09810120ba feat(coding-agent): add /rename command with session accent coloring
- Add /rename <title> slash command to set an explicit session name,
  updating the session header, terminal tab title, and status line
- Add session_name status segment: displays the session name on the
  right side of the status bar with a stable djb2-hash-derived accent
  color unique to each name; shown in all presets when a name is set
- Add setSessionName source tracking ('user' vs 'auto'): auto-generated
  titles are silently ignored once the user has explicitly set a name,
  preventing the async title generation from overwriting a /rename
- Sanitize session names at storage time: strip C0/C1 control characters
  (including ANSI ESC) via static #sanitizeName before storing, blocking
  escape sequence injection into the TUI, terminal title, and session file
- Extend sanitizeStatusText to cover the full C0/C1 range as
  defense-in-depth (superset of the previous \r\n\t-only strip)
- Use stored (sanitized) name for showStatus message and terminal title
  in handleRenameCommand, not the raw user input
- Guard terminal title update in auto-title path via titleSource === 'auto'
  so a user rename is never overwritten by a late-resolving LLM call
- Reset #titleSource in #newSessionSync so each new session starts fresh
- Thread source parameter through AgentSession.setSessionName wrapper;
  extension API and RPC set_session_name treated as 'user' intent

Closes #658
2026-04-11 13:49:01 +02:00
djdembeck 72e9e20441 feat: add session name getter/setter to extension API
- Document session name getter/setter methods in extensions.md
- Add stub methods to ExtensionProxy that throw if called before init
- Add delegating implementations to ExtensionProxyInit
- Wire up getSessionName and setSessionName in extension runtime
- Add method signatures to ExtensionContext interface and type
- Add getSessionName to session manager API
- Add getSessionName and setSessionName to all mode contexts:
  - ACP agent
  - Extension UI controller (also updates terminal title)
  - Print mode
  - RPC mode
2026-04-11 01:09:08 -05:00
can1357 3d29a48e7a fix(coding-agent): fixed memory leak by cancelling idle compaction
- Fixed memory leak by cancelling idle compaction timer on event controller disposal.
- Fixed session resumption to preserve last non-empty session when starting fresh.
- Fixed stash detection to use git ref resolution instead of output parsing for reliability.
- Fixed secret obfuscation to deobfuscate restored session messages locally while keeping LLM messages obfuscated.
- Fixed stash pop operation to preserve staged changes with --index flag after task branch merges.
- Changed idle compaction settings from enum to numeric type for flexible configuration.
2026-04-05 03:50:52 +02:00
can1357 b9df71db18 fix: ensure full persistence on ensureOnDisk and treat autoResume as continue 2026-04-05 01:19:18 +02:00
DeprecatedLuke 2cddf02c2c feat(coding-agent): add auto-resume setting 2026-04-04 11:52:24 +01:00
can1357 68cf52de3c fix(session): corrected artifact storage fallback for non-persistent sessions
- Fixed artifact storage for non-persistent sessions to use in-memory fallback instead of returning undefined, enabling proper spill truncation for all session types.
- Added in-memory artifact map and counter to SessionManager for fallback storage when file-based ArtifactManager is unavailable.
- Updated saveArtifact() JSDoc to reflect new behavior of returning artifact IDs for all sessions.
2026-04-01 19:08:48 +02:00
can1357 8e5cc87f00 revert: 535 due to TUI regressions 2026-03-26 19:56:49 +01:00
can1357 306ea795dc Merge review/pr-535-fix 2026-03-26 19:14:23 +01:00
daandden b8c423e319 Fix stale OpenAI Responses replay across session boundaries (#534)
* Fix stale OpenAI Responses replay across session boundaries

Fixes #505

* Fix CI tests for session replay change

* Harden session reload and switch rollback

* Guard session switch snapshots

* fix(coding-agent): preserve responses replay snapshots
2026-03-26 15:27:58 +01:00
Vu Anh Nguyen 0d979cc187 fix(coding-agent): preserve new-session approval state 2026-03-26 16:52:30 +07:00
zamorakpds 870232104c Fix/resume timestamp mutation (#528)
* fix(coding-agent): kept resumed sessions from reordering

* fix(coding-agent): corrected resume state restoration
2026-03-25 12:40:08 +01:00
can1357 b64b6b8a79 feat(modes): introduced ACP mode for headless agent operation with session management and event streaming
- Added ACP (Agent Client Protocol) mode for headless agent operation via --mode acp flag.
- Integrated Agent Client Protocol SDK with session management, streaming communication, and event mapping.
- Added ensureOnDisk() method to SessionManager for immediate session persistence without requiring assistant messages.
- Changed session persistence to use atomic file rewrite for unflushed sessions.
- Implemented AcpAgent class with session management, prompt handling, MCP server configuration, and event streaming.
2026-03-22 01:35:20 +01:00
maximhar e27ceb2f96 fix: persist MCP discovery tool selections across session lifecycle (#453)
* fix: persist MCP discovery selections across session lifecycle

* fix: restore MCP discovery state on branch switches

* fix: preserve explicit MCP baseline on old branch contexts

* fix(coding-agent): preserve cleared MCP selections on resume

* fix(coding-agent): isolate MCP defaults across session switches

* fix(coding-agent): preserve MCP defaults across outages

---------

Co-authored-by: can1357 <me@can.ac>
2026-03-17 14:49:54 +01:00
can1357 9148ec01ec feat(session-manager): added optional sessionDir with multi-root migration support
- Made sessionDir parameter optional in SessionManager.create(), forkFrom(), continueRecent(), and list() methods with automatic default computation.
- Updated SessionManager.getDefaultSessionDir() to accept optional agentDir parameter for custom sessions root configuration.
- Changed SessionManager.list() signature to require cwd parameter as first argument with sessionDir now optional.
- Implemented multi-root session migration support by replacing global migration state with per-root tracking and extracting session directory encoding logic.
- Added resolveManagedSessionRoot() function to determine if session directory is managed and extract its root.
2026-03-16 16:06:04 +01:00
can1357 2cc53e86f1 feat(coding-agent): required sessionDir parameter to enforce explicit session path resolution
- Made sessionDir parameter required in SessionManager.create(), continueRecent(), and forkFrom() methods.
- Added SessionManager.getDefaultSessionDir() static method to explicitly resolve canonical default session directory.
- Changed SessionManager.list() signature to accept sessionDir directly instead of computing from cwd.
- Fixed SDK-created default sessions to honor configured agentDir for session storage and symlink-equivalent path resolution.
2026-03-16 15:46:06 +01:00
can1357 78177af8bc feat(coding-agent): added symlink resolution and path alias handling for consistent directory behavior
- Added symlink and path alias resolution to session directory handling for consistent behavior across aliased home and temp directories.
- Improved status line path display to strip display roots using canonical path resolution, correctly handling symlink-equivalent directory aliases.
- Added support for quoted paths in grep, ast_grep, and find tools to properly handle directory names with spaces.
- Improved ast_grep error messaging when no matches found with parse errors to suggest narrowing path/glob or setting language.
- Extracted path utility functions (resolveEquivalentPath, normalizePathForComparison, pathIsWithin, relativePathWithinRoot) to shared utils package.
- Added comprehensive test coverage for symlink alias resolution in status line path rendering and session directory handling.
2026-03-16 15:24:18 +01:00
can1357 bdcc08a50c feat(coding-agent/session): added automatic migration of legacy session directories
- Added automatic migration of legacy absolute-path session directories with double-dash format to new canonical locations.
- Enhanced session directory encoding to use `-tmp-` prefix for temporary directories instead of legacy double-dash format for improved clarity.
- Extracted session directory migration logic into reusable helper functions for better maintainability.
- Updated test setup to mock home directory and verify session migration behavior with temporary paths.
2026-03-15 22:56:18 +01:00
can1357 dbc1c4af1d feat(coding-agent): added attribution option to control billing and initiator tracking
- Added `attribution` option to `PromptOptions` for controlling billing and initiator attribution.
- Updated subagent prompts to explicitly set `attribution: "agent"` for accurate billing attribution.
- Refactored message attribution logic to use configurable `promptAttribution` with fallback defaults.
- Added test coverage for `attribution` option in subagent reminder prompts.
Fixes #439.

feat(coding-agent): added attribution option and explicit session directory control

- Added `attribution` option to `PromptOptions` for explicit billing and initiator attribution control.
- Updated `SessionManager.create()` to require both `cwd` and `sessionDir` parameters for explicit session directory control.
- Changed session directory naming for temporary working directories from `--` format to `-tmp-` prefix.
- Made `cwd` and `sessionDir` fields mutable in SessionManager to support session relocation.
- Fixed automatic migration of legacy session directories to new `-tmp-` prefixed naming scheme.
- Updated all test fixtures to pass both `cwd` and `sessionDir` parameters to `SessionManager.create()`.
2026-03-15 22:56:18 +01:00
can1357 92c4ff99ff refactor(coding-agent/session): eliminated redundant guard in flush method
- Removed redundant early return guard in flush() method, relying on existing null check within queued task.
2026-03-15 17:26:53 +01:00
can1357 07389a4da0 chore: reformat 2026-03-15 16:43:17 +01:00