Skip to content

Latest commit

 

History

History
729 lines (691 loc) · 171 KB

File metadata and controls

729 lines (691 loc) · 171 KB

First And Second Batch Parity Audit

本文件记录第一批地基模块和第二批运行时核心对 Claude Code 源快照的重新扫描结果。

目标标准是 100% 行为兼容;当前状态不是完成态,而是持续补齐过程中的审计清单。

Scope

第一批:

  • internal/contracts
  • internal/bootstrap
  • internal/platform
  • internal/config
  • internal/auth
  • internal/model
  • internal/messages
  • internal/session

第二批:

  • internal/permissions
  • internal/tool
  • internal/api/anthropic
  • internal/conversation

Source Areas Rescanned

权限:

  • src/types/permissions.ts
  • src/utils/permissions/*
  • src/hooks/toolPermission/*
  • src/components/permissions/*

工具运行时:

  • src/Tool.ts
  • src/tools.ts
  • src/services/tools/toolExecution.ts
  • src/services/tools/toolOrchestration.ts
  • src/services/tools/StreamingToolExecutor.ts
  • src/services/tools/toolHooks.ts

Anthropic API 和 conversation:

  • src/services/api/client.ts
  • src/services/api/claude.ts
  • src/services/api/errors.ts
  • src/services/api/errorUtils.ts
  • src/services/api/promptCacheBreakDetection.ts
  • src/query/*
  • src/cli/print.ts
  • src/entrypoints/sdk/*

地基:

  • src/utils/settings/*
  • src/utils/model/*
  • src/services/oauth/*
  • src/history.ts
  • src/assistant/sessionHistory.ts
  • src/bootstrap/state.ts
  • src/constants/*

Implemented During This Rescan

  • Permission rule parser now supports escaped parentheses, escaped wildcards, legacy tool names, legacy :* shell prefix rules, addRules/replaceRules/removeRules/setMode/directory updates, and rule validation.
  • Permission path checks now cover working-directory scope, additional working directories, dangerous root paths for mutating operations, symlink-resolved permission paths, symlink escape prevention for new children, sensitive .git/.claude/IDE/shell-config write targets, suspicious Windows path-pattern blocking, internal readable paths such as session memory/tool-results/tasks, and internal editable paths such as scratchpad/plan/job/agent-memory paths with job symlink escape guards. The permission engine now applies sensitive-path safety before broad allow rules while still allowing explicit internal harness paths.
  • Sandbox filesystem policy from settings now merges into the permission context: denyRead blocks reads unless a narrower allowRead path applies, denyWrite blocks writes, and allowWrite can permit extra write directories after dangerous-root and sensitive-path safety checks. Request cwd-relative paths now resolve against the permission request working directory rather than the process cwd.
  • Internal path context now includes skill directories. Runner metadata can pass skill/bundled-skill roots to tools so SKILL.md files and adjacent resources are readable as internal files, while the same allowlist does not grant write access to skill directories.
  • internal/skills now has project skill directory discovery for .claude/skills/<skill>/SKILL.md roots, including cwd-to-git-root/home startup discovery and file-path-triggered nested discovery below cwd. Runner tool metadata now includes project skill roots discovered from the working directory.
  • File tools now wire the nested skill discovery helper into Read, Write, Edit, and NotebookEdit paths, appending newly discovered skill roots to the shared internal read allowlist for later tool calls.
  • internal/skills now loads directory-style <skill>/SKILL.md files into prompt command metadata, including description/frontmatter fallback, allowed tools, argument hints/names, when-to-use aliases, version/model with inherit treated as no override, context: fork, agent and effort metadata, path triggers, content length, hidden state for non-user-invocable skills, and disable-model-invocation.
  • Project legacy .claude/commands/**/*.md files now load as commands_DEPRECATED prompt commands, covering regular markdown names, directory-style SKILL.md namespaced commands, frontmatter metadata, SkillTool visibility, prompt expansion, and base-directory handling for directory-style legacy commands.
  • internal/commands now has a metadata registry that merges command sources in the official order, loads project skill commands from the working directory, deduplicates dynamic skills, resolves commands by canonical name/display name/alias, filters visible commands, exposes SkillTool/slash-skill command subsets, and applies the bridge-safe predicate for prompt/local/local-jsx commands.
  • Built-in slash command metadata now preserves official aliases for the currently declared Go builtins such as settings, continue, reset, and new, plus argument hints and immediate markers for mcp, resume, status, and model.
  • The command registry now retains local skill prompt templates and can expand prompt commands into meta user messages, including $ARGUMENTS, indexed/shorthand arguments, frontmatter named arguments, ${CLAUDE_SESSION_ID} substitution, and non-MCP ${CLAUDE_SKILL_DIR} substitution.
  • Slash command execution now has a basic local command result abstraction, /clear follows a no-query local text-result path, and the REPL screen can consume the cleared result by resetting transcript viewport/selection/reverse-search while preserving prompt input history; broader local command result handling remains incomplete.
  • /status <section> now shares the same section-alias normalization as /status show <section>, so direct invocations such as /status integrations and /status diagnostics take the no-query local status path instead of falling into the unsupported-subcommand branch.
  • /cost status, /cost current, and /cost usage now share the no-query totals path with /cost, while /cost breakdown/show continue to return per-message usage details and unknown subcommands remain explicit.
  • /summary, /release-notes, and /files are now registered as bridge-safe built-in local commands and take no-query local result paths: /summary reports deterministic session/history counts and previews, /release-notes reports the bundled release-notes availability state, and /files lists first-level workspace entries without reading file contents.
  • /config <section> now shares the same section-alias normalization as /config show <section> for non-mutating direct section invocations such as /config env, /config permissions, and /config integrations, while preserving existing mutating forms such as /config model <name> and /config output-style <name>.
  • /memory list, /memory files, and /memory ls now take the no-query local file-list path used by /memory show, while /memory status continues to report the session/relevant-memory summary.
  • /native clipboard status|show now takes a no-query local status path that reports the session clipboard state and adapter availability without reading, writing, or displaying clipboard text.
  • /native status|show now takes the same no-query local status path as /status show native, reporting the session native manifest, platform, capability counts, clipboard adapter availability, file index, and clipboard state without invoking external adapters or the model.
  • /native voice status|show and /native computer status|show now take no-query local status paths that report the session plan path, adapter availability, selected commands, and voice/computer-use runtime parameters without starting capture or input actions.
  • /mcp refresh and /mcp reload now take a no-query local refresh path that checks settings-file changes, refreshes plugin MCP server app-state, and reports configured/plugin MCP server counts instead of falling into the unsupported-subcommand branch.
  • /mcp <server-name> now takes the no-query local server-detail path used by /mcp show <server-name> when the name matches a configured settings or plugin MCP server, while unknown one-word subcommands still report unsupported.
  • /plugin help|--help|-h now returns the official plugin command usage text without querying the model, /plugin manage reuses the installed-plugin summary path, /plugin i aliases install, and the built-in command registry now exposes the official /plugins and /marketplace aliases.
  • /plugin uninstall|remove|rm [--scope project|user|local] <plugin> now takes a no-query safe uninstall path that only removes plugin roots discovered from installed plugin directories, reports removed path/scope, and refreshes plugin MCP server app-state.
  • /plugin validate <path> now takes a no-query local validation path backed by a shared plugin manifest validator also used by CLI plugin validate <path>, covering official .claude-plugin marketplace/plugin directory detection, current Go root manifest layouts, JSON/type/unknown-key/path-traversal diagnostics, common plugin warnings, marketplace entry summaries, and CLI-side official-layout content scans for skills/agents/commands frontmatter plus hooks/hooks.json.
  • CLI plugin uninstall|remove|rm [--scope user|project|local] [--keep-data] <plugin> now reuses the same safe uninstall API, defaults to user scope like the official CLI, and reports removed path/scope/status.
  • CLI plugin list now surfaces installed plugin load failures instead of silently dropping bad plugin roots: JSON entries include errors, and text output marks the plugin as failed to load with the error message.
  • CLI plugin marketplace add now accepts repeatable --sparse <path> for github/git sources, writes sparsePaths, and rejects sparse paths on non-git marketplace sources.
  • /plugin <plugin-name> now takes the no-query local plugin-detail path used by /plugin show <plugin-name> when the name matches a local plugin manifest, while unknown one-word subcommands still report unsupported.
  • /model show, /model info, and /model current now take the no-query current-model path instead of treating those words as custom model names and mutating the runner model.
  • A basic Skill tool wrapper is now registered with the default built-in tool set. It can invoke local project and plugin-directory prompt skills through the command registry, returns the official-style Launching skill: ... result plus structured command metadata, preserves command source/display/root/frontmatter metadata for plugin skills, and passes expanded meta user messages through ToolResult.NewMessages; the conversation runner now appends those new messages to transcripts and subsequent model requests.
  • A basic ToolSearch tool is now registered with the default built-in tool set. The executor exposes the current registry through tool metadata, and ToolSearch can search available definitions by name, alias, description, prompt, search hint, and input/output schema fields, supports select:ToolA,ToolB direct selection, and returns tool-reference content plus BM25/select structured results with read-only/concurrency/destructive, input/output schema, deferred/loading/request-hint metadata, and query/limit aliases.
  • Conversation request construction now scans previous tool_result blocks for tool_reference content from ToolSearch; referenced tools are copied into the next API request without defer_loading, including both in-memory ToolReference values and decoded transcript map forms.
  • Compact planning now snapshots discovered tool_reference names into compactMetadata.preCompactDiscoveredTools; resume/transcript conversion preserves that metadata and request construction reloads those tools after compacted tool_result messages have been summarized away.
  • When ToolSearch is available and deferred tools exist, request construction now follows dynamic tool loading: undiscovered deferred schemas are omitted from tools, discovered deferred tools are loaded, ToolSearch stays callable, and an <available-deferred-tools> user meta message advertises the deferred tool names; if no deferred tools exist, ToolSearch is omitted from the request.
  • Request construction now also applies the official ToolSearch enablement gates before emitting beta defer_loading / tool_reference shapes: Haiku models, CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS, falsy ENABLE_TOOL_SEARCH, ENABLE_TOOL_SEARCH=auto:100, unset ToolSearch behind non-first-party ANTHROPIC_BASE_URL, and ENABLE_TOOL_SEARCH=auto requests below the deferred-tool size threshold all fall back to standard inline tool schemas; explicit ENABLE_TOOL_SEARCH=true can still opt a custom gateway back in. Auto mode now uses the Anthropic /v1/messages/count_tokens endpoint when the client supports it, subtracts the official fixed tool overhead, falls back to Haiku message-create usage when count-tokens fails, and then falls back to the official character threshold when token counting is unavailable, including auto:N percentages, 1M context suffixes, and ant-only context-window overrides.
  • ToolSearch enablement decisions now emit the official tengu_tool_search_mode_decision conversation/telemetry event with enabled/mode/reason/checked-model/MCP-count/user-type plus auto token/char threshold metrics, without tool names or message text.
  • Deferred tool token counts in ToolSearch auto mode are now memoized in-process by the official deferred tool name list key, including both successful counts and unavailable/null-equivalent results.
  • MCP tools now follow the official deferred-tool rule: they are deferred unless explicitly marked always_load, Anthropic tool schema serialization emits defer_loading for MCP tools, ToolSearch auto token counting includes MCP tools as loaded schemas, and configured MCP toolset attach/close invalidates the in-process deferred-tool token-count cache.
  • ToolSearch deferred tool announcements now support the official deferred_tools_delta attachment path when USER_TYPE=ant or settings advanced.tengu_glacier_2xr/advanced.tenguGlacier2xr is enabled: the runner diffs deferred tools against prior delta attachments, persists a new attachment, API normalization renders added/removed tool reminders, delta mode skips the ephemeral <available-deferred-tools> prepend, and changes emit the official tengu_deferred_tools_pool_change conversation/telemetry event with count/call-site/query-source/attachment-type diagnostics but no tool names or message text.
  • When ToolSearch is inactive for a request, API message normalization strips historical tool_reference blocks from user tool_result content and replaces pure-reference results with the official placeholder text, while preserving history scanning before stripping so discovered tools can still be loaded when ToolSearch is active.
  • Anthropic request tool conversion now preserves contract-level strict, eager_input_streaming, cache_control, and API-level defer_loading hints from deferred tool definitions, with always_load overriding should_defer; it also falls back from description to prompt to searchHint when building API tool descriptions. Runner request construction preserves these fields for tools such as Task.
  • Tool validation now appends an official-style schema-not-sent recovery hint when an undiscovered deferred tool is invoked with invalid typed input and ToolSearch is available, including compact-boundary discovered-tool metadata so already loaded tools do not get a false hint.
  • Basic slash prompt command invocation is now wired for local project prompt skills: /skill args is parsed before the model request, converted into official-shaped command metadata plus expanded meta prompt messages, appended to transcript parent chains, and can override the turn model from skill frontmatter.
  • Local prompt-skill slash commands and the Skill tool now emit command_permissions attachments, parse allowed-tools into command-scoped permission rules, and merge those rules into the engine permission decider for the current turn so authorized follow-up tool calls can pass without leaking into later turns.
  • Settings schema coverage was expanded for major Claude Code settings keys: auth helpers, model allowlists/overrides, MCP policy, hooks policy, worktree, shell, output style, language, thinking/effort, plugins, remote, spinner, sandbox, and related flags. Settings parsing now also coerces env values to strings, filters invalid permission rules into warnings, validates key permission fields, applies WebSearch/WebFetch-specific permission-rule validation, validates marketplace source union basics across extraKnownMarketplaces, strictKnownMarketplaces, and blockedMarketplaces including settings-source map key/source name consistency, plugin item path shape, and installLocation user/project/local values, derives runtime marketplace allow/block decisions from strict and blocked settings, loads installed plugins from project-chain and user plugin roots with project precedence, loads marketplace-only plugin listings for headless /plugin available and /plugin marketplace plugins|search|show while preserving installed plugin available/update state, exposes installed/available marketplace JSON through CLI plugin list --json --available, exposes configured marketplace list JSON/text including git/github sparsePaths through CLI plugin marketplace list, writes and removes configured marketplaces to user/project/local settings scopes through CLI plugin marketplace add/remove --scope ..., triggers marketplace cache refresh through CLI plugin marketplace update [name], shares marketplace install copy/conflict/symlink-safety code between headless /plugin install [--scope project|user|local] and CLI plugin install --scope project|user|local with marketplace installLocation defaults, shares marketplace update/replace code between headless /plugin update [--scope project|user|local|all] [name] and CLI plugin update --scope project|user|local|all <plugin> with the same named-plugin defaulting, writes plugin enable/disable state to user/project/local settings scopes through CLI plugin enable|disable --scope ..., loads managed policy from macOS MDM plist / Windows HKLM, platform managed-settings.json, sorted managed-settings.d/*.json drop-ins, optional remote managed-settings GET sources, and Windows HKCU fallback, refreshes remote managed policy at turn start and during daemon heartbeat ticks with merged-settings/plugin-server app-state propagation, honors allowManagedPermissionRulesOnly for permission-rule merging, enforces strictPluginOnlyCustomization for the implemented skills, mcp, and hooks surfaces so user/project/local customizations are skipped while plugin/admin sources remain, strips untrusted prompt-command agent/context: fork/effort metadata when the agents surface is policy-locked while preserving plugin/bundled/admin sources, includes a path-keyed settings file cache plus a snapshot-based settings change detector that classifies created/modified/deleted settings files and resets cached reads on change, refreshes local user/project/local settings at turn start with plugin-server app-state propagation, and now generates a JSON Schema from contracts.Settings with /config show schema summary visibility.
  • Model registry now uses current Claude model IDs and aliases from the source snapshot, including Sonnet 4.6, Opus 4.6, Haiku 4.5, canonical-name rendering, and [1m] context variants.
  • OAuth support now includes production OAuth config, scope parsing, Claude.ai scope detection, auth URL construction, PKCE verifier/challenge, state generation, and expiry checks.
  • Session/history support now includes CC-compatible prompt history references, pasted text/image placeholder parsing, paste-cache hashing and retrieval, history.jsonl append/load, current-session-first up-arrow ordering, ctrl+r-style deduped timestamped history, CLAUDE_CODE_SKIP_PROMPT_HISTORY, remote session event pagination helpers, lenient transcript loading, legacy progress parent-bridge recovery, compact-boundary pruning, snip removal/relink replay, metadata entry collection, leaf UUID calculation, conversation-chain reconstruction, orphaned parallel tool-result recovery, content-replacement record loading/reconstruction, tombstone metadata delete/relink replay, and tombstone-style transcript message removal with a size guard.
  • Anthropic API layer now covers streaming accumulation, safe pre-event streaming-to-non-streaming fallback in the conversation runner, usage update/accumulation semantics, non-streaming max token cap, thinking-budget adjustment, retry/backoff with Retry-After and x-should-retry, context-overflow max_tokens retry adjustment, OAuth access-token refresh and retry on unauthorized non-streaming/streaming requests when a refresh provider is configured, beta-header dedupe, request-content beta latching for prompt-cache/cache-editing payloads, strict tool structured-output requests, and [1m] context models, custom request headers including CLI/env gateway/proxy header injection, basic prompt cache breakpoint/cache-reference/cache-edits placement, prompt dump JSONL capture for init/new user messages/non-streaming responses/stream chunks, no-query /issue local context summaries for recent prompt dumps without prompt-body leakage, /cost session transcript usage restore with UUID/ID dedupe, and CC-compatible USD cost calculation for known Claude models including cache read/write, web search requests, and Opus 4.6 fast-tier pricing.
  • Tool runtime now includes concurrency partitioning, ordered concurrent execution, interrupt behavior/defaults, max result size metadata, oversized result persistence, pre/post/permission-denied/permission-request hook dispatch, settings and local-plugin command-backed/HTTP hook execution for synchronous tool and conversation lifecycle hooks, hook-driven input updates/blocking/permission-request allow-deny, prompt/compact context injection, executor hook phase progress events, lifecycle progress events, retry/fallback model breadcrumbs, final-result/structured-error model attempt lists, structured API error status/type/request-id fields, headless stream-json progress events, snake_case token warning NDJSON payloads, lightweight compact NDJSON metadata, and pre-call cancellation checks.
  • Conversation runner can now use streaming clients, aggregate stream events into assistant messages, run tool calls through the orchestrator, preserve transcript append behavior, and apply CC-style per-message aggregate tool-result budget replacement before API requests with persisted replacement records for resume.

Still Missing For 100% Compatibility

The following items remain incomplete and must not be treated as done:

  • Full permission hook flow gaps that remain: deeper async/background hook runtime policy beyond explicit background command hooks, richer hook telemetry, and full TUI/control-protocol surfacing beyond the current executor/conversation hook phase progress and headless stream-json events.
  • Auto mode / YOLO classifier: transcript construction, two-stage classifier, XML/tool-use parsing, prompt dump, denial circuit breaker, model gating, and fallback behavior.
  • Interactive permission prompt flow: REPL dialogs, bridge/channel/swarm permission relays, user feedback images, prompt race handling, cancellation.
  • Full filesystem permission parity gaps that remain: skill-scope allow suggestions, remaining local/local-jsx slash-command execution wiring beyond the currently covered no-query builtins, command permission UI/SDK surfacing, forked/remote/MCP/bundled SkillTool behavior and remaining plugin SkillTool UI/SDK polish beyond current metadata preservation, skill prompt shell injection, complete auto-memory override policy, and deeper platform-specific Windows/WSL bypass handling.
  • Full tool execution parity gaps that remain: complete hook runtime policy beyond the current settings command hook path, MCP elicitation, complete SDK control event surface beyond current progress NDJSON, full deferred/lazy tool discovery beyond current local registry BM25 search, remaining ToolSearch model/env/proxy edge gates, remaining ENABLE_TOOL_SEARCH=auto edge behavior such as official token-count VCR, mid-call cancellation for concrete tools beyond the current Bash/PowerShell foreground coverage, background task behavior beyond the current Bash/PowerShell start/finish progress events, telemetry, and concrete tool-specific semantics.
  • Complete Anthropic API parity gaps that remain: dynamic beta-header latching for any remaining provider-specific feature gates beyond prompt-cache/cache-editing/strict-output/1M-context requests, ant-only dump gating and remote /issue submission integration beyond the current local context summary, full official cost tracker/session restore lifecycle beyond current transcript usage restore, post-handshake streaming failure semantics, deeper gateway/proxy auth and routing behavior beyond static custom headers, first-party/Bedrock/Vertex/Foundry client setup, deeper OAuth account/profile lifecycle beyond request-time refresh retry, fast-mode retry/cooldown semantics, persistent unattended retry heartbeats, full prompt-cache editing lifecycle, and provider-specific cache behavior.
  • Full conversation/query loop: stop hooks, compact/auto-compact, token budget escalation, resume, SDK JSON/NDJSON control events, status updates, rate-limit handling, model switch breadcrumbs, side questions.
  • Full settings parity gaps that remain: complete Zod-equivalent validation messages, full remote managed-settings watcher/non-daemon background refresh lifecycle beyond current turn-start and daemon-heartbeat refresh, remaining forked agent/frontmatter execution and UI edge cases beyond current policy metadata filtering, complete marketplace TUI/UI/background lifecycle beyond current local/settings/directory/file/URL catalog/git/github/npm cache manifest load, URL catalog cache fallback, git/github fetch/pull cache refresh, npm pack cache refresh, and background watcher/continuous app-state sync beyond current turn-start local settings reload.
  • Full session/history parity gaps that remain: large-file optimized transcript loading, preserved-segment edge cases beyond current relink/prune support, content-replacement feature-flag/runtime override and inherited subagent gap-fill details, complete async prompt-history lifecycle parity beyond current lock/buffer/undo paths, full pasted-image processing/runtime integration beyond current prompt image-cache/image-block/metadata path, remaining remote-history edge cases, sidechain/subagent transcript layout, and all session metadata entry types.

Current Verification

The current Go implementation compiles and passes:

go test ./...

This is evidence that the current strengthened implementation is internally consistent. It is not proof of 100% Claude Code parity.

M5 Initial Progress

After the first/second batch hardening, the Go rewrite now includes initial internal/tools/file, internal/tools/bash, internal/tools/powershell, internal/tools/todo, and internal/tools/web packages with text-file Read, Write, Edit, search, shell, PowerShell, session todo, and web fetch tools.

Covered behavior:

  • Glob/Grep initial pure-Go file search tools, including recursive ** glob matching, Glob absolute-pattern base-dir extraction, Glob official pattern/path-only strict schema, Glob/Grep working-directory-relative result paths, Glob default no-ignore/hidden search plus CLAUDE_CODE_GLOB_NO_IGNORE/CLAUDE_CODE_GLOB_HIDDEN env switches, Grep official VCS metadata directory exclusion (.git/.svn/.hg/.bzr/.jj/.sl), Grep hierarchical .gitignore/.ignore/.rgignore, Glob oldest-first modified/path sorting, Glob truncated tool-result hinting, regex and fixed-string grep (fixed_strings/-F), Grep regex/regexp/--regexp/-e pattern aliases, multiline dotall grep, glob/type filtering, Grep glob whitespace/comma multi-pattern and brace alternation, Glob/Grep path existence validation plus Glob directory-only path validation, output_mode/outputMode files_with_matches/content/count output modes, Grep count/--count/-c count-mode aliases, Grep files_with_matches file-count summaries, Grep count-mode occurrence/file summaries, Grep --max-columns 500 long matching/context line omission placeholders, context/before_context/after_context and -C/-B/-A content context lines with official precedence and non-content modes ignoring context, line_numbers/lineNumbers/-n line-number control, max_count/maxCount/-m per-file match limiting, offset/head_limit pagination and content-mode pagination tool-result hinting, default 250-entry Grep head limit, head_limit=0 unlimited behavior, ignore_case/case_insensitive/caseInsensitive/-i case-insensitive search aliases, case_sensitive/--case-sensitive/-s and smart_case/--smart-case/-S search policy aliases, and quoted semantic string coercion for Grep numeric/boolean inputs.
  • Bash initial shell execution, including command/timeout/description validation, /bin/sh -c execution, stdout/stderr/exit-code/timeout/cancel structured results, foreground and BashOutput oversized tool-result truncation/persistence, dynamic read-only/concurrency-safe/destructive classification, Git diff/log/show/status/ls-files/grep/rev-parse/branch/tag/ls-remote safe-flag validation, Git remote/push/reflog/stash/worktree/merge-base/describe/cat-file/for-each-ref/rev-list/blame/shortlog/config query-family argument-aware safety classification, conservative read-only sed and awk classification for safe print/delete/quit/line-number or field-print scripts over relative paths, safe relative-path head/tail/cut/uniq reads with tail follow modes and indirect path-list options such as wc/du --files0-from and find -files0-from excluded from read-only auto-allow, simple safe sort reads, destructive find -delete/-exec rm and xargs rm classification, safe-wrapper/env prefix normalization for Bash read-only/destructive classification (time/nohup/timeout/nice/stdbuf/env), destructive command detection after temporary environment assignments, permission-rule matching through the existing tool permission adapter, background command start, same-session BashOutput reads, and KillBash cancellation.
  • TodoWrite initial todo state, including full-list writes, status/priority validation, duplicate-id rejection, one in_progress guard, structured result payloads, tool metadata state storage, and session-scoped local persistence/restore.
  • WebFetch initial URL fetch behavior, including URL/timeout/max-byte validation, HTTP GET, HEAD preflight, metadata/raw skipWebFetchPreflight skip-preflight, binary preflight GET skipping from content type or attachment filename, text/binary detection, truncation, non-2xx error marking, structured result payloads, HTML-to-text rendering, prompt-focused excerpts, prompt phrase scoring/metadata, and WebFetch(domain:...) permission-rule adaptation.
  • WebFetch HTML-to-text rendering now preserves anchor href values as link context and emits visible image text from img alt/title/aria-label plus src, the first usable img srcset candidate, common lazy image data-src/data-srcset candidates, or a <picture><source srcset> candidate, allowing prompt-focused excerpts to match image descriptions while avoiding duplicate URL link text, unsafe javascript:/data:/blob:/vbscript: hrefs, and data: image placeholders.
  • WebFetch HTML-to-text rendering now preserves visible form-control text from input placeholders, values, alt text, and accessibility labels, icon-only button labels, empty textarea placeholders, and selected/default select options including option label attributes and select multiple selected option lists, while skipping hidden, password, file, option-value, and non-selected option text so prompt-focused excerpts can match form actions without leaking non-visible secrets.
  • WebFetch GET records the redirect-resolved final_url, and HTML rendering resolves relative anchor/image URLs against that final URL or the document's first valid <base href> so redirected pages expose browser-visible link and image targets.
  • WebFetch text bodies now decode common web charsets from BOM, Content-Type, or HTML <meta charset>/http-equiv declarations, including UTF-8/UTF-16LE/UTF-16BE, Latin-1, and Windows-1252, and structured results expose the normalized charset.
  • WebSearch initial HTML/JSON-search adapter, including query/max-result/timeout/domain-filter validation, injectable search endpoint, DuckDuckGo HTML link parsing, HTML JSON-LD ItemList extraction, DuckDuckGo subdomain and common /url/redirect/out result redirect unwrapping, common JSON result shapes plus nested backend wrappers such as web/response/hits/documents, DuckDuckGo result snippet extraction, domain allow/block filtering, structured result payloads, and query-based permission-rule matching.
  • WebSearch HTML result parsing now resolves relative result anchors against the search page's first valid <base href> when present, matching browser-visible result URLs for mirrored/custom search pages.
  • WebSearch HTML result parsing now reads application/ld+json JSON-LD result payloads, recursively extracts @graph and ItemList.itemListElement.item, accepts JSON-LD @id URL aliases, and deduplicates those URLs against following anchor results.
  • WebSearch JSON result parsing now accepts additional backend aliases such as pageUrl/targetUrl/source_url/formattedUrl, cleans HTML-bearing title/snippet fields like htmlTitle/htmlSnippet, unwraps nested URL objects, and recursively collects deepLinks/siteLinks child results.
  • WebSearch JSON result parsing now also unwraps answer/knowledge/news/people-also-ask style backend containers such as answerBox, knowledgeGraph, news_results, topStories, peopleAlsoAsk, and related_questions, while accepting website/sourceLink, question, answer, and excerpt result aliases.
  • Grep now accepts whole-word matching through word_regexp/wordRegexp/word-regexp/-w, applying word-boundary filtering for both regex and fixed-string patterns and preserving quoted boolean coercion.
  • Grep now accepts ripgrep-style pattern files through pattern_file/--file/-f, reading one pattern per line, combining file patterns with explicit patterns, preserving empty-line matching semantics, and applying fixed-string, smart-case, word-regexp, and line-regexp handling to the combined set.
  • Grep now accepts inverted matching through invert_match/invertMatch/invert-match/-v, applying the inverted line set consistently for files-with-matches, content, count, and multiline span output modes while preserving quoted boolean coercion.
  • PowerShell read-only classification now canonicalizes common pipeline aliases such as select/sort/group/where/?, ft/fl/fw/fc, and measure, while preserving the existing expression/scriptblock guards and excluding interactive Out-Host -Paging from read-only auto-allow.
  • PowerShell read-only classification now globally rejects remote/job/credential control parameters such as -CimSession, -ComputerName, -Credential, -AsJob, -JobName, and -ThrottleLimit, including for allow-all system-info cmdlets.
  • PowerShell file-content read-only classification allows bounded relative-path Get-Content -Tail reads while excluding Get-Content -Wait and docker logs --follow/-f long-running follow modes from read-only auto-allow.
  • Grep content output now accepts ripgrep-style no-line-number controls such as --no-line-number and -N, plus snake/camel adjacent aliases, to disable default line-number output with structured state preserved.
  • Grep content output now accepts column/column_numbers/columnNumbers/column-number/--column, emitting path:line:column:text for matching lines while preserving context-line formatting and structured column metadata.
  • Grep files-with-matches output now mirrors the official modified-time sort: newest files first, path tie-breaker, and pagination applied after sorting.
  • Grep now accepts ripgrep-style file listing through files/--files and output_mode:"files", not requiring a pattern and listing paths after traversal, ignore, glob/iglob, type/type-not, hidden, and binary/text filters without reading file contents.
  • Grep now accepts ripgrep-style result ordering through sort/--sort, sortr/--sortr, and deprecated sort_files/--sort-files, covering path, modified-time, and none ordering for files/content/count modes with structured sort metadata.
  • Grep now accepts ripgrep-style traversal depth limiting through max_depth/maxDepth/max-depth/--max-depth/-d, including quoted numeric input and --max-depth 0 directory no-op behavior.
  • Grep now accepts ripgrep-style negative type filtering through type_not/typeNot/type-not/--type-not/-T, applying it after any positive type filter and preserving structured filter metadata.
  • Grep now accepts ripgrep-style case-insensitive glob filtering through iglob/--iglob, sharing positive and ! negative glob rule semantics with glob while preserving structured filter metadata.
  • Grep now accepts ripgrep-style glob_case_insensitive/--glob-case-insensitive plus no-override aliases, making ordinary glob/--glob/-g filters match paths case-insensitively while preserving iglob behavior.
  • Grep glob filtering now accepts ripgrep-style negated !pattern rules, including combinations with positive patterns, comma/whitespace splitting, and brace-expanded globs.
  • Grep now accepts text/--text/-a to disable NUL-based binary filtering and search binary content as text; no_text/--no-text disables text mode when both are present.
  • Grep binary filtering now uses ripgrep-style NUL content detection instead of extension-based skipping; default search skips NUL-containing files, binary/--binary reports matching binary files, text/--text/-a searches them as text, and no_binary/--no-binary restores binary filtering.
  • Grep now accepts line_regexp/line-regexp/--line-regexp/-x to require whole-line matches, with fixed-string and word-regexp precedence covered.
  • Grep content output now accepts passthru/passthrough/--passthru/--passthrough, printing all searched lines while preserving matched-line markers and overriding context counts.
  • Grep content output now accepts vimgrep/--vimgrep, repeating matching lines once per match with column metadata while preserving context-line output and -N formatting.
  • Grep content and count output now accept with_filename/--with-filename/-H plus no_filename/--no-filename/-I, while file-list modes continue to emit paths.
  • Grep content output now accepts replace/--replace/-r, applying display-only replacements to matching lines and only-matching/vimgrep output without changing context lines or count/list modes.
  • Grep count output now accepts include_zero/--include-zero, including zero-count files for both line counts and count_matches occurrence counts while preserving --no-filename output.
  • Grep content output now accepts heading/--heading plus no_heading/--no-heading, grouping output by file while keeping vimgrep/count modes ungrouped.
  • Grep path-bearing output now accepts path_separator/--path-separator, replacing visible / separators in content, count, file-list, and heading output while validating one-byte separators.
  • Grep path-bearing output now accepts null/--null/-0, using NUL after path fields for content/count/heading and NUL-terminated paths in file-list modes.
  • Grep content output now accepts field_match_separator/fieldMatchSeparator/field-match-separator/--field-match-separator plus field_context_separator/fieldContextSeparator/field-context-separator/--field-context-separator, preserving separate match/context field separators including empty values and --null path-field output.
  • Grep content context output now accepts context_separator/contextSeparator/context-separator/--context-separator plus no_context_separator/noContextSeparator/no-context-separator/--no-context-separator, inserting the default -- or a custom group separator between disjoint context groups and suppressing it when requested.
  • Grep content output now accepts byte_offset/byteOffset/byte-offset/--byte-offset/-b, emitting line-start byte offsets for normal/context lines and match-start byte offsets for only-matching and vimgrep output.
  • Grep traversal now accepts hidden/--hidden plus no_hidden/noHidden/no-hidden/--no-hidden, preserving the current hidden-inclusive default while allowing callers to suppress hidden files/directories without disabling ignore-file or VCS metadata filtering.
  • Grep traversal now accepts ripgrep-style follow/--follow/-L plus no_follow/--no-follow, skipping symlinks by default and following symlink files/directories with real-path loop protection when requested.
  • Grep input now accepts ripgrep-style threads/--threads, line_buffered/--line-buffered, block_buffered/--block-buffered, no_line_buffered/--no-line-buffered, plus mmap/--mmap and no_mmap/--no-mmap backend/output hints, keeping the Go reader path while exposing the final state in structured results.
  • Grep content output now accepts trim/--trim plus no_trim/--no-trim, trimming leading ASCII whitespace from printed line text while preserving original match columns.
  • Grep output now accepts stats/--stats plus no_stats/--no-stats, appending ripgrep-style aggregate statistics for matches, matched lines, searched files, searched/printed bytes, and durations while exposing the same counters in structured results.
  • Grep output now accepts quiet/--quiet/-q plus no_quiet/--no-quiet, suppressing textual output while preserving structured matches and counters; quiet suppresses stats text output.
  • Grep output now accepts basic json/--json plus no_json/--no-json, emitting NDJSON begin/match/context/end/summary events with implicit summary stats, per-file and summary bytes_printed, summary-only output for --json --quiet, binary_offset on --json --binary end events, bytes base64 payloads for non-UTF-8 JSON text, original-line lines.text for only_matching/vimgrep, submatch replacement fields for --replace, and ripgrep-style suppression of JSON events when explicit count/files output modes are selected; every ripgrep JSON flag interaction remains deeper parity work.
  • Grep long-line output now accepts max_columns_preview/--max-columns-preview plus no_max_columns_preview/--no-max-columns-preview, showing a ripgrep-style truncated preview when max_columns is exceeded.
  • Grep file filtering now accepts ripgrep-style max_filesize/--max-filesize with optional K/M/G suffixes, skipping files larger than the parsed byte limit before content reads or file-list output.
  • Grep search now accepts ripgrep-style crlf/--crlf plus no_crlf/--no-crlf, preserving default CRLF anchor behavior while allowing CRLF-aware anchors with original byte offsets.
  • Grep search now accepts ripgrep-style null_data/--null-data plus no_null_data/--no-null-data, treating NUL as the input line terminator, implying text search, overriding CRLF mode, and preserving NUL record separators for content/count/matching-file output.
  • Grep text loading now follows ripgrep-style auto BOM detection for UTF-8/UTF-16 inputs and accepts encoding/--encoding/-E for auto, none, utf-8, utf-16, utf-16le, and utf-16be, with no_encoding/--no-encoding restoring auto detection.
  • Glob/Grep traversal now applies Read(...) deny rules from the permission context as extra search ignore rules, hiding denied basename, path, and directory patterns from search results.
  • Glob/Grep hierarchical ignore loading now includes ripgrep-specific .rgignore files in addition to .gitignore and .ignore.
  • Grep now accepts ripgrep-style ignore_dot/--ignore-dot and no_ignore_dot/--no-ignore-dot, letting .ignore/.rgignore rules be disabled while .gitignore remains active.
  • Grep now accepts ripgrep-style ignore_file/--ignore-file for one explicit gitignore-formatted rules file matched relative to the current working directory; no_ignore_files/--no-ignore-files disables those explicit ignore-file inputs without changing .gitignore, .ignore, or .rgignore loading.
  • Grep now accepts ripgrep-style ignore_vcs/--ignore-vcs and no_ignore_vcs/--no-ignore-vcs, letting .gitignore rules be disabled while .ignore/.rgignore remain active.
  • Grep now accepts ripgrep-style unrestricted/--unrestricted/-u levels, mapping level 1 to no-ignore traversal and level 3 to text-mode binary searching while exposing the effective level in structured results.
  • Read/Edit now coerce quoted semantic strings for offset/limit and replace_all, including whole-decimal numeric strings such as "2.0" for integer fields while keeping fractional values rejected.
  • Bash/BashOutput now coerce quoted semantic strings for timeout, run_in_background/runInBackground, and tail_lines/tailLines, matching official SDK-style number/boolean inputs without relaxing unknown-field validation.
  • PowerShell/PowerShellOutput now coerce quoted semantic strings for timeout, run_in_background/runInBackground, and tail_lines/tailLines, matching the official PowerShell tool's semantic number/boolean schema without relaxing unknown-field validation.
  • Bash/PowerShell foreground validation now blocks leading long sleep/Start-Sleep statements (2 seconds or more) with the official-style run_in_background guidance while preserving short sleeps, fractional sleeps, PowerShell millisecond sleeps, and explicit background execution.
  • Bash/PowerShell foreground execution now distinguishes caller cancellation from timeout and ordinary nonzero exit in structured results: cancelled commands return cancelled=true, timed_out=false, exit_code=-1, and visible cancelled status text.
  • Bash and Unix PowerShell process cancellation now sends SIGTERM to the managed process group first and uses a short WaitDelay SIGKILL fallback, allowing cooperative shell cleanup while still bounding ignored-signal commands.
  • BashOutput now has the same 100k result budget surface as foreground Bash, so oversized background output is truncated in the visible tool result and persisted with full_output_path metadata.
  • Bash and PowerShell background commands now emit tool progress events when the background task starts and finishes, carrying only task IDs, shell/status fields, exit/timed-out/cancelled state, duration, timestamps, and output byte counts without command text; completed, timed-out, and cancelled finish paths are covered.
  • Bash/PowerShell now accept the official dangerouslyDisableSandbox semantic boolean input and record it in structured results; full sandbox adapter and override execution semantics remain a separate incomplete parity area.
  • Bash/PowerShell now surface dangerouslyDisableSandbox to the permission engine: normal/default/auto/plan/acceptEdits modes ask for confirmation, dontAsk denies it, and only available bypassPermissions mode allows it, preventing read-only classification or allow rules from silently approving sandbox override requests.
  • Settings now propagate sandbox.allowUnsandboxedCommands into the permission context; when it is false, sandbox override requests are denied even in bypassPermissions, and settings validation flags non-boolean values for the known sandbox boolean fields.
  • Settings now propagate sandbox.filesystem.allowWrite/denyWrite/denyRead/allowRead into the permission context; read and write path decisions honor those lists with allowRead overriding narrower denied read regions and allowWrite still running after dangerous-root and sensitive-path write safety checks.
  • Tool metadata can now carry skill/bundled-skill directories into the internal path policy, allowing read access to SKILL.md and adjacent skill resources without granting write access to those roots.
  • Project skill roots are now discovered from the Runner working directory and added to the internal read allowlist; the discovery helper also supports nested file-path-triggered skill root discovery for future file-tool activation wiring.
  • Read/Write/Edit/NotebookEdit now trigger nested skill discovery from touched file paths and update shared tool metadata so later permission checks can read newly discovered skill roots.
  • Directory-style SKILL.md files can now be loaded into prompt command metadata, preserving common frontmatter fields and hidden/non-user-invocable state for later command registry and SkillTool integration.
  • Command registry metadata now merges project skill commands with built-in command metadata, follows the upstream source ordering for future plugin/workflow/MCP sources, and exposes the SkillTool/slash-skill filters needed by later invocation wiring.
  • Prompt command expansion now produces meta user messages from local skill templates and applies the core argument/session substitutions used by official skill prompt commands.
  • The default built-in tool registry now includes a basic Skill tool for local project prompt skills, and the conversation runner consumes ToolResult.NewMessages so expanded skill prompts become transcript-backed meta user messages in the next model request.
  • The conversation runner now handles local project prompt-skill slash commands before querying the model, replacing raw /skill args input with command metadata and expanded meta prompt messages while preserving transcript parent links and model override metadata.
  • Command-scoped skill permissions now round-trip through command_permissions attachments and current-turn engine permission rules, covering both user-invoked slash skills and model-invoked Skill tool expansions.
  • WebFetch/WebSearch now coerce quoted semantic strings for local numeric options such as timeout, max_bytes/maxBytes, and max_results/maxResults; WebSearch also rejects requests that specify both allowed_domains and blocked_domains, matching the official validation rule.
  • PowerShell initial command execution, including command/timeout/description/run-in-background validation, pwsh/powershell executable detection, foreground execution, background start/output/kill tools, stdout/stderr/exit-code/timeout/cancel structured results, foreground/background output tool-result truncation/persistence test coverage, missing-executable structured errors, dynamic read-only/concurrency-safe/destructive classification for common inspection and mutating commands, common mutating alias canonicalization, path-free git/git.exe/git.cmd external Git command classification through the Bash Git safety policy, Docker ps/images/logs/inspect external read-only classification with variable/unknown-flag guards, read-only PowerShell cmdlet safe-flag allowlists with path-argument guards, data-conversion/object-inspection/system-info cmdlet read-only allowlists, pipeline-tail formatting/object-selection cmdlet read-only allowlists with variable/hashtable/scriptblock guards, network/event/CIM metadata cmdlet read-only allowlists with remote/XML/hashtable risk-parameter exclusions, native/external command read-only allowlists (ipconfig/netstat/systeminfo/tasklist/where.exe/hostname/whoami/route print/file/findstr/dotnet) with mutating-form rejections, basic relative-path guards for file-reading commands, and default built-in tool registration.
  • Bash/PowerShell read-only classification now rejects incomplete quoted or trailing-escape commands before token-level allowlist checks, reducing false read-only results for malformed shell input.
  • Bash/PowerShell lightweight tokenizers now keep escape handling disabled inside single-quoted literals, so Bash \ and PowerShell backtick characters inside single quotes no longer corrupt quote, segment, or token state.
  • Bash/PowerShell classification now treats unquoted newlines as command segment boundaries and strips unquoted line comments, while still classifying commands on following lines independently.
  • Bash destructive classification now treats an unquoted single & background separator as a command boundary, so destructive commands after a backgrounded read-only command remain visible to safety classification.
  • Bash destructive classification now recursively checks un-single-quoted command substitution, backtick substitution, and subshell bodies so nested destructive commands still produce destructive safety metadata.
  • PowerShell destructive classification now recursively checks un-single-quoted parenthesized expressions, $() subexpressions, and scriptblock bodies so nested mutating cmdlets still produce destructive safety metadata.
  • Bash read-only classification now applies a basic relative-path guard to common file-reading and search commands, excluding absolute, home, parent-directory, variable, command-substitution, Windows-drive, UNC, and URI/provider-like path forms from read-only auto-allow.
  • Bash rg read-only classification now rejects --pre/--pre=... external preprocessor commands so ripgrep invocations that can execute another command do not enter read-only auto-allow.
  • Bash go list read-only classification now uses an argument-level allowlist, allowing common query flags and -mod=readonly/vendor while rejecting -mod=mod, -modfile, -overlay, unknown or missing-value flags, and non-local package patterns.
  • Bash find read-only classification now rejects deleting or file-writing actions such as -delete, -fprint, -fprint0, -fprintf, and -fls, avoiding commands that mutate files being auto-allowed as read-only.
  • Bash safety classification now excludes find -exec* forms from read-only auto-allow and detects destructive commands passed through find -exec*/xargs, including shell -c scripts and safe-wrapper/env/assignment forms such as env rm, timeout rm, and xargs -I{} env sh -c ....
  • Bash file read-only classification now rejects indirect -f/--files-from path-list reads and -C/--compile magic compilation forms while preserving ordinary relative-path file inspection.
  • Bash date read-only classification now allows only display, date-string parsing, and safe relative --reference/--file reads while rejecting -s/--set, legacy positional system-time setting, and absolute/parent date-file references.
  • PowerShell native/external file-reading/search read-only classification now applies relative-path guards to where.exe /R, file, tree, and findstr path positionals and path-valued flags, rejecting Windows-drive, UNC, URI/provider-like, parent-directory, and missing path-flag values before read-only auto-allow; where.exe no longer uses allow-all flag acceptance.
  • PowerShell native path guards now validate findstr /D: semicolon-separated directory lists item by item and treat file -p as a switch instead of a value-taking flag, closing path-guard bypasses through quoted directory lists or short-flag value misclassification.
  • PowerShell native file classification now rejects -f, attached -ffile, and --files-from indirect path-list reads, avoiding auto-allow for list-file contents that the classifier cannot inspect.
  • Read line-number formatting, offset/limit slicing, mtime-based same-range dedup, text/binary/device guards, initial PDF text extraction with page-selection parsing, common Page/Contents indirect-object mapping, Pages/Kids page-order recovery, FlateDecode text streams, UTF-16 BOM PDF string decoding, PNG/JPEG/GIF/WebP image content-block reads, Jupyter notebook cell rendering with visible/structured cell_id values for real IDs and cell-N fallbacks, large text tool-result truncation/persistence, and read-state recording.
  • Write create/update behavior, read-before-write validation for existing files, mtime stale detection, .claude/settings.json and settings.local.json JSON/semantic validation before writes, structured diff hunks, and post-write read-state refresh.
  • Edit exact replacement, nonexistent-file creation with empty old_string, unique-match enforcement, replace_all, quote-style preservation for curly quotes, CRLF preservation, .claude/settings.json and settings.local.json final-content validation before writes, structured diff hunks, and post-edit read-state refresh.
  • NotebookEdit initial notebook mutation behavior, including official input field names, replace/insert/delete modes, real cell IDs and cell-N fallback indexes, code-cell output/execution reset on replace, read-before-edit/stale guards, read-state refresh, notebook_path permission path extraction, structured result payloads, and cell-level diff/hunks.
  • conversation.Runner now preserves tool metadata across tool rounds so a Read in one tool round can authorize a later Edit/Write.
  • Bash safety classification now treats git reflog, git reflog show, and ref/date display variants as read-only while keeping git reflog expire/delete/exists out of read-only auto-allow and marking expire/delete as destructive.
  • Bash safety classification now also treats git stash list, git stash show, and git worktree list as read-only while keeping stash/worktree mutating subcommands out of read-only auto-allow and marking stash drop/pop/clear plus worktree remove/prune as destructive.
  • Bash safety classification now also treats git merge-base, git describe, git cat-file, and git for-each-ref metadata/object inspection commands as read-only with explicit safe-flag allowlists.
  • Bash safety classification now also treats git rev-list, git blame, git shortlog, and git config --get/--get-all/--get-color/--get-colorbool/--get-regexp/--get-urlmatch/--list read-only query forms as read-only with explicit safe-flag allowlists.
  • Bash safety classification now validates git diff, git log, git show, git status, git ls-files, and git grep against explicit safe-flag allowlists instead of treating every invocation of those subcommands as read-only; file-output and external-pager style flags remain outside read-only auto-allow.
  • Bash safety classification now also validates git rev-parse against an explicit safe-flag allowlist and limits git remote show/get-url to constrained remote-name forms.
  • Bash safety classification now also validates git branch and git tag against explicit safe-flag allowlists and keeps bare positional branch/tag creation out of read-only auto-allow.
  • Bash safety classification now also validates git ls-remote against explicit safe flags while rejecting URL/SSH remote specifications, variable-looking positionals, and --server-option/-o protocol write channels.

Still missing from full M5 parity:

  • Fuller PDF parity, fuller notebook render/edit parity, fuller token-budget parity, and fuller media parity in Read/NotebookEdit.
  • Fuller git/notebook diff parity plus LSP/IDE notifications/file-history integration for Write/Edit/NotebookEdit.
  • Skill activation, full permission prompt rendering, and broader secret guard parity beyond the current team-memory write guard.
  • Complete Bash parser/sandbox/signal lifecycle/golden parity, PowerShell full parser/full permission/path validation/background lifecycle edge cases/golden parity, WebFetch browser rendering/full prompt-aware summarization/golden parity, WebSearch official backend/ranking/golden parity, NotebookEdit UI/golden/file-history parity and MCP concrete tool semantics, plus remaining ripgrep parity/output behavior for Glob/Grep and TUI/golden compatibility for TodoWrite.

M6/M7 Initial Progress

M6 progress now includes:

  • internal/memory: recursive .md memory scanning, frontmatter parsing, newest-first capped manifests, root-to-leaf CLAUDE.md discovery/loading, and team-memory secret detection.
  • internal/compact: effective context window calculations, auto-compact thresholds, token warning state, compact summary prompt construction, compact API runner, compact boundary/summary plan generation, auto-compact window env override application, microcompact/cache primitives, persistent cached microcompact storage, structural/rich-content microcompact cache digests, cache version/TTL/prune handling for disk and in-memory caches, memory-cache write-through to disk, atomic cache writes, corrupt-cache fail-open behavior, and filename/digest mismatch pruning.
  • internal/compact: microcompact disk cache loading now accepts Go default, camelCase, snake_case, and adjacent cache field aliases/wrappers such as result/data/cache/value objects, content/text summary, cacheKey/key/hash digest including JSON-number string-like fields, cache-hit aliases, numeric strings and whole-number JSON/string numbers for count fields, RFC3339/Unix-seconds/Unix-millis time fields, and relative TTL fields such as ttlSeconds, ttlMs, expiresIn, and maxAge, so cached microcompact records from adjacent implementations remain usable.
  • internal/compact: microcompact disk cache loading also accepts adjacent cache-entry wrappers and aliases such as cacheEntry/cache_entry, micro_compact/micro_compact_result, summaryMarkdown/resultSummary/compressedText, cacheDigest/digestHash/fingerprint, summarizedCount/retainedCount, formatVersion, and millisecond TTL aliases such as ttlMilliseconds, expiresInMilliseconds, and maxAgeMilliseconds.
  • internal/compact: microcompact disk cache loading now also accepts adjacent timestamp aliases such as cachedAt, cacheCreatedAt, storedAt, generatedAt, updatedAt, timestamp, expiry, expirationTime, validUntil, notAfter, and relative TTL aliases such as timeToLiveSeconds and validForMs.
  • internal/compact: microcompact disk cache relative TTL loading now also accepts minute, hour, and day aliases such as ttlMinutes, expiresInHours, and validForDays, including adjacent snake/camel forms.
  • internal/compact: microcompact disk cache relative TTL strings now also accept fixed-unit ISO-8601 durations such as PT1H30M, P1D, and P1DT2H, while rejecting ambiguous year/month durations.
  • internal/compact: microcompact disk cache field and wrapper lookup now normalizes case, snake_case, and kebab-case spellings, so adjacent exports such as cache-entry with summary-text, cache-key, cache-version, created-at, and ttl-seconds recover the same cache entry.
  • internal/compact: microcompact disk cache direct-payload detection now uses the same normalized summary aliases, so top-level summary-text, snake_case, or kebab-case summary fields still win when data or payload sidecar objects are present.
  • internal/compact: microcompact disk cache loading now fills missing cache metadata from sidecar objects such as metadata, meta, cacheInfo, cacheDetails, cacheEntry, entry, record, and cache, preserving primary result fields while recovering digest/version/cache-hit/timestamp/TTL/count aliases stored outside the summary payload.
  • internal/compact: microcompact disk cache loading and pruning now use the <digest>.json filename as a digest fallback when a cache entry omits an internal digest, while preserving explicit digest mismatch pruning/errors.
  • internal/compact: microcompact disk cache loading now accepts non-strict cache-hit booleans for cached/fromCache/cacheHit/isCached, including yes/no, on/off, 1/0 JSON number or string values, and whole-number numeric strings such as "1.0"/"0.0".
  • internal/compact: microcompact disk cache loading now accepts JSON:API/resource-style resource/attributes/properties wrappers, with summary payloads inside attributes/properties and outer resource IDs used as digest fallback when needed.
  • internal/compact: microcompact disk cache loading now also recurses through GraphQL-style viewer/edge/node/attrs wrappers, preserving node IDs as digest fallback while recovering summary, version, timestamp, and TTL aliases.
  • internal/compact: microcompact disk cache loading now also traverses collection wrappers such as edges, nodes, and included, skipping non-cache resources without summaries while recovering GraphQL connection or JSON:API included cache entries.
  • internal/compact: microcompact disk cache summary payloads now accept text content-block objects, text content-block arrays, and string arrays, joining visible text blocks into the recovered summary for official/SDK-style cached microcompact files and unwrapping JSON/fenced summary payloads embedded inside text blocks.
  • internal/compact: microcompact disk cache summary arrays now also recover provider-style item text from parts, content.parts, and output wrappers before rejecting non-standard array elements.
  • internal/compact: microcompact disk cache summary payloads now also accept full contract message objects and unwrap message/assistantMessage/resultMessage/outputMessage/completionMessage response wrappers before extracting visible text summary.
  • internal/compact: microcompact disk cache summary arrays now also accept full contract message objects mixed with content blocks, extracting visible message text while skipping non-visible blocks.
  • internal/compact: microcompact disk cache loading now treats a value text content-block object as a direct summary payload while still recovering digest, version, timestamp, and related cache metadata from that same value sidecar object when present.
  • internal/compact: microcompact disk cache loading now accepts provider-style response array wrappers such as choices, outputs, candidates, generations, and results, recovering summaries from nested message.content, output.content, output_text/outputText, content.parts[].text, and fenced json code blocks while keeping outer cache metadata.
  • internal/contracts/internal/compact: provider output_text content blocks now canonicalize as visible text, so OpenAI Responses-style output[].content[].type="output_text" cached microcompact payloads can recover summaries while non-visible blocks remain skipped.
  • internal/compact: compact runner summary responses now also unwrap provider-style choices, outputs, candidates, and generations payloads, recovering visible summary text from nested message.content, content-block arrays, content.parts[].text, and fenced json code blocks before building the compact plan.
  • internal/conversation: optional auto-compact can now run before the main request, fail open with a consecutive-failure circuit breaker, emit runtime token_warning events from compact warning state, persist compact boundary metadata to transcript, write a session-memory summary, inject recalled session-memory snippets into API request context when enabled, and optionally extract turn-end memory facts into session memory.
  • internal/memory: session-memory summaries can now be loaded with frontmatter field aliases, rolled up/pruned into an archive summary with prior rollup archives excluded from candidate compaction and merged across archive IDs, rune-safe rollup truncation, recalled by query with deterministic scoring and recency ordering, ranked through a model-assisted candidate/session-id selection path with fallback when selected IDs are invalid or excluded, alternate/camel response-key parsing, fenced/prose JSON extraction, scalar session-id parsing, nested/wrapped/collection-alias selection parsing including JSON:API included and collection/list wrappers, summary URI/link/path aliases such as sessionUri and summaryPath, non-memory/session typed resource id filtering, and nested selected-memory item parsing, and injected into resume context through the same optional recall agent path; deterministic and model-backed memory fact extraction can summarize user preferences, requests, decisions, and tool-use facts, including fenced/prose JSON, wrapped facts responses, provider-style response wrappers, alternate and structured fact field names, nested source objects, nested fact response shapes, and fact kind aliases.
  • internal/memory: session-memory summary frontmatter timestamps now accept Unix seconds, Unix milliseconds, and adjacent aliases such as updatedAtMs, timestampMs, and createdAtUnix, preserving recall ordering for non-RFC3339 summary files.
  • internal/memory: session-memory summary frontmatter session/message IDs now accept aliases such as sessionUUID, conversationId, threadId, transcriptId, messageID, and leafID, preserving current-summary and recall candidate metadata across adjacent summary writers.
  • internal/memory: session-memory summary text now falls back to frontmatter aliases such as summaryText, summary, content, text, resultSummary, and finalSummary when the markdown body is empty, while preserving body precedence.
  • internal/memory: session-memory recall and relevant-memory model selectors now recurse through GraphQL/JSON:API selection wrappers such as data, payload, body, resource, attributes, properties, attrs, viewer, edge, node, nodes, and edges, preserving model-ranked session IDs and memory paths from API-shaped responses.
  • internal/memory: session-memory recall and relevant-memory model selectors now also unwrap provider-style choices, outputs, candidates, and generations responses plus top-level message/content/text/output_text envelopes, recovering JSON selection payloads from nested message.content, content-block arrays, content.parts[].text, and fenced json code blocks.
  • internal/memory: session-memory recall and relevant-memory model selectors now preserve rewritten search text from adjacent query aliases such as user_query, question, prompt, input, search, and search_text, not only canonical query/search_query keys.
  • internal/memory: relevant-memory model selection now accepts URI/link path aliases such as uri, url, href, fileUri, and fileUrl, matching file:// URIs and API URL path basenames back to candidate memory files; top-level memories, matches, and filesList collections are also scanned when a response includes query.
  • internal/memory: relevant-memory model selection now also treats file-selection aliases such as selectedFiles, relevantFiles, candidateFiles, selectedFilePaths, relevantFilePaths, sourcePath, and documentPath as memory selections, including nested file objects and link objects.
  • internal/memory: session-memory recall model selection now accepts summary collection aliases such as summaries, selectedSummaries, relevantSummaries, and candidateSummaries, including nested summary.sessionId and summaryId fields.
  • internal/memory: session-memory recall model selection now also accepts conversation/thread/transcript aliases such as conversationId, threadId, transcriptId, selectedConversations, relevantThreads, and candidateTranscripts, including nested wrapper objects.
  • internal/memory: session-memory recall model selection now accepts summary URI/link aliases such as sessionUri, sessionUrl, uri, url, and href, matching file://.../summary.md and API URL path segments back to session summary IDs.
  • internal/memory: session-memory recall model selection now also accepts direct summary/transcript path aliases such as sessionPath, sessionSummaryPath, summaryPath, sessionFilePath, and transcriptPath, matching returned summary or session JSONL paths back to session IDs through the existing lookup.
  • internal/memory: session-memory recall and relevant-memory model selectors now also accept HAL/JSON:API-style links and _links relation objects, extracting href/url/uri/link paths while ignoring relation metadata.
  • internal/memory: model-backed memory fact extraction now also unwraps provider-style choices, outputs, candidates, and generations responses plus top-level message/content/text/output_text envelopes, recovering JSON facts payloads from nested message.content, content-block arrays, content.parts[].text, and fenced json code blocks.
  • internal/memory: session-memory recall, relevant-memory selection, and model-backed fact extraction now unwrap inline/glued fenced JSON where the language marker and JSON appear on the same line, so provider/model outputs without a newline still recover selection and fact payloads.
  • internal/memory: model-backed memory fact extraction now also traverses API-shaped fact collections such as observations, notes, findings, records, resources, data.resource.attributes, and edge.node, while accepting text aliases such as note, description, body, message, observation, and finding.
  • internal/memory: model-backed memory fact extraction now accepts additional text aliases such as fact, statement, insight, result, and output, preserving fact content from non-canonical model responses.
  • internal/memory: model-backed memory fact extraction now accepts additional kind aliases such as user_pref, constraint, user_rule, guideline, standing_instruction, requirement, action_item, outcome, conclusion, tool_usage, and command_run, normalizing them into preference/request/decision/tool facts.
  • internal/memory: model-backed memory fact extraction now accepts additional source aliases such as sourceMessageUUID, source_message_uuid, sourceEventId, source_event_id, originId, and nested turn/event source objects, preserving numeric source IDs as strings.
  • internal/session: remote-history response parsing now also unwraps provider-style choices, outputs, candidates, and generations responses plus top-level message/content/text/output_text envelopes, recovering event page JSON plus pagination from nested message.content, content-block arrays, content.parts[].text, and fenced json code blocks.
  • internal/session: remote-history provider-wrapper fenced JSON extraction now accepts inline/glued fence forms where the language marker and JSON object appear on the same line, so model/SDK outputs without a newline still recover event pages.
  • internal/session: remote-history pagination now accepts starting_after/startingAfter/after* cursor aliases from page fields and link URL query parameters when deriving the next before_id.
  • internal/session: project session listing and pagination, prompt-history lock/buffered flush/field aliases, lightweight transcript index/title/text-preview inference, line-offset transcript indexing/window/byte-budget-window/parent-chain/resume/tail/byte-budget-tail loading, AI-title/last-prompt/task/agent/PR/worktree transcript metadata loading and type/field aliases, transcript message/session UUID field aliases, tombstone metadata loading with target/session/reason aliases and delete/relink replay, agent-scoped content replacement metadata/record field-alias loading, session-scoped metadata reappend including AI-title/last-prompt/task-summary, streaming transcript search snippets for resume/search UI, official subagents/agent-*.jsonl transcript layout with legacy sidechain listing, agent metadata sidecar read/write/field aliases, sidechain runtime start/append/finish/cancel/fail summary bridging plus parent-chain append/finish, sidechain manager orchestration for spawn/append/finish/cancel/fail/list/resume, sidechain state/list/resume support with content-field aliases, sidechain resume context construction, sidechain conversation and agent-scoped content-replacement reconstruction, transcript tail/window loading and byte-budget tail loading for bounded-memory resume/UI paths, lightweight transcript metadata loading, remote-history token refresh retry, page-field/event-list/records/entries/last-id/cursor/event-id/has-next aliases plus wrapped-data/links/paging/bare-array/keyed-event-map responses, before_id resume, fallback field fill, and duplicate-aware parent linking during transcript materialization.
  • internal/session: typed transcript metadata records now recursively read field values from nested payload, data, result, metadata, body, resource.attributes, and collection wrappers, so full transcript loading, lightweight metadata loading, and transcript indexing preserve session metadata even when the record itself keeps the canonical type at the top level.
  • internal/session: sidechain/subagent lifecycle state loading now accepts wrapped startedAt/startTime and endedAt/completedAt/finishedAt payload time aliases, preferring lifecycle payload times while preserving transcript timestamps as a fallback.
  • internal/session: sidechain/subagent failure and cancellation summaries now accept result aliases such as errorMessage, errorText, failureReason, cancelReason, and cancellationReason, preserving human-readable terminal causes in state/resume summaries.
  • internal/session: transcript full loader and line-offset index now accept top-level record UUID aliases such as messageUuid, messageUUID, message_id, messageId, and id, plus parent message UUID/ID aliases for progress bridge and indexed resume paths.
  • internal/session: indexed resume chains now distinguish budget-truncated parents from genuinely missing parents, exposing both markers while preserving bounded transcript reads.
  • internal/session: transcript full loader and line-offset index now accept entry type aliases such as role, entry_type, and messageType, plus createdAt/created_at timestamp aliases.
  • internal/contracts/internal/session: contract messages, session entries, and transcript loaders now canonicalize message-type aliases such as assistant_message, userMessage, system-event, attachmentMessage, progress_update, and tombstone_event; full transcript loading, line indexes, and indexed resume use canonical user/assistant/system/attachment types while preserving progress bridge semantics.
  • internal/session: tail, byte-tail, window, and metadata-only transcript loaders now also use canonical message types for progress bridge and compact-boundary handling, so aliases such as progress_update and system-event behave like canonical progress and system.
  • internal/session: tail, byte-tail, window, and streaming transcript search now unwrap the same JSON:API/resource, GraphQL edge/node, and collection/list wrapper records as the full/index loaders, preserving progress bridge behavior for wrapped transcript batches.
  • internal/contracts/internal/session: transcript resume now accepts nested content block aliases for toolUseId/toolUseID, isError, cacheControl, cacheReference, and cache edit cacheReference; tool-use content block IDs also accept JSON numbers and preserve them as strings.
  • internal/contracts/internal/session: nested contract message content now accepts string text, single content-block objects, and mixed string/content-block arrays; string content is normalized into text blocks, while text/body/message/value/output body aliases and role/messageType type aliases are preserved.
  • internal/contracts/internal/session: nested contract messages now accept parent aliases such as parentUUID, parentId/parentID/parent_id, parentMessageId/parentMessageID/parent_message_id, and parent-message UUID aliases, preserving payload-supplied parents in transcript and remote-history resume paths.
  • internal/contracts/internal/session: nested contract messages now accept messageId/messageID/message_id and messageUuid/messageUUID/message_uuid as their own ID/UUID aliases, and primary id accepts JSON numbers, preserving payload-supplied nested message IDs in indexed resume output.
  • internal/contracts/internal/session: the base SessionEntry JSONL loader now accepts role/type, message ID/UUID, parent ID/UUID, and session ID/UUID aliases so older entry files keep type, parent, and session metadata when loaded through session.Load.
  • internal/session: tombstone metadata target/parent loading now accepts target/deleted/message ID aliases and parent ID/message ID aliases, preserving tombstone delete/relink replay across older field spellings.
  • internal/session: transcript metadata loading now accepts broader ID aliases for summary leaves, content-replacement agent/tool/block IDs, and context-collapse commit IDs across the full loader and lightweight metadata loader.
  • internal/session: worktree-state metadata now accepts additional wrapper aliases such as worktreeState, worktree, and workspace in both full and lightweight metadata loaders.
  • internal/session: PR link metadata now accepts pull-request number/URL and repository full-name aliases in both full and lightweight metadata loaders.
  • internal/session: task-summary metadata now accepts alternate summary and timestamp field names in both full and lightweight metadata loaders.
  • internal/session: summary/title/last-prompt metadata now accepts alternate value field names across the full loader, lightweight metadata loader, and transcript index.
  • internal/session: tag, agent, and mode metadata now accepts alternate value field names across the full loader, lightweight metadata loader, and transcript index.
  • internal/session: content-replacement metadata now accepts alternate record wrapper and record value/hash field names across the full loader, lightweight metadata loader, and transcript index.
  • internal/session: remote-history parsing now also accepts connection-style history/messages wrappers with nodes/edges[].node event lists and pageInfo/page_info hasNextPage/endCursor/startCursor pagination aliases.
  • internal/session: remote-history connection edges now use edges[].cursor as the event cursor when the nested node lacks an event ID, preserving pagination even when pageInfo omits a cursor.
  • internal/session: remote-history pagination now accepts hasMoreResults/hasMoreItems/hasMorePages, isTruncated/truncated, and keyset cursor aliases such as nextKey/lastEvaluatedKey/lastKey in response fields and link URL query parameters.
  • internal/session: remote-history parsing now also accepts eventList/event_list, sessionEvents/session_events, and connection aliases such as connection, eventConnection, and sessionEventsConnection.
  • internal/session: remote-history parsing now also accepts value, values, resources, and collection event-list aliases, plus edges[].resource/edges[].value node payload aliases.
  • internal/session: remote-history parsing now unwraps generic response envelopes such as payload, response, result, and body when they contain event lists and pagination fields.
  • internal/session: remote-history event-list fields such as data, result, event, item, and record now accept a single SDK event object directly, preserving non-array single-event pages instead of treating them only as wrappers.
  • internal/contracts/internal/session: remote-history event materialization now accepts eventType/event_type/role type aliases, createdAt/created_at timestamp aliases, and message payload aliases such as payload, data, body, metadata, meta, attributes, properties, and serializedMessage, including role/content-only payloads.
  • internal/contracts/internal/session: remote-history SDK event types now canonicalize provider-style aliases such as assistant_message, userMessage, system-event, result_event, errorEvent, and status_update/progress, so wrapped or single-object event pages materialize transcript messages instead of being skipped as unknown types.
  • internal/session: remote-history pageInfo parsing now accepts previous/older pagination signals such as hasPrevious/hasPreviousPage, hasOlder/more, and before-id cursors such as previousCursor/prevCursor/beforeCursor/olderCursor.
  • internal/session: remote-history pagination bool parsing now accepts numeric, whole-number JSON numbers or numeric strings, and yes/no-style bool values in addition to JSON bools and true/false strings.
  • internal/session: remote-history pagination cursor/id parsing now accepts JSON numbers and preserves them as string cursors for page fields and edges[].cursor.
  • internal/session: remote-history pagination now accepts token aliases such as nextPageToken, nextToken, pageToken, and continuationToken in response fields and link query parameters, including _/- query-parameter variants in links.
  • internal/session: remote-history pagination now also accepts generic continuation aliases such as paginationToken, cursorToken, and token in response fields, link objects, and link query parameters.
  • internal/session: remote-history pagination now also accepts previous/older token aliases such as previousPageToken, prevPageToken, olderPageToken, and matching snake_case/token forms in response fields, link objects, and link query parameters.
  • internal/session: remote-history pagination now also accepts adjacent before-cursor aliases such as before, beforeID, olderThan, endingBefore, and untilId in response fields, link objects, and link URL query parameters.
  • internal/session: remote-history pagination now also accepts OData next-link fields such as @odata.nextLink, odata.nextLink, and __next, extracting $skiptoken/skipToken link query values as continuation cursors.
  • internal/session: remote-history fetch now treats HTTP 204 and 200 responses with empty bodies as empty terminal pages instead of incomplete fetches or JSON EOF errors.
  • internal/session: remote-history fetch now treats HTTP 404/410 missing or deleted session responses as empty terminal pages while leaving other non-OK responses as nil incomplete pages.
  • internal/contracts: ID JSON decoding now accepts JSON numbers/null so remote-history event, message, session, and parent ID aliases can preserve numeric IDs as strings during transcript materialization.
  • internal/session: remote-history response parsing now recursively unwraps GraphQL/session/HAL containers such as data.session.events, data.projectSession.eventConnection, conversation, remoteHistory, and _embedded before applying nodes/edges[].node event-list and pageInfo pagination parsing.
  • internal/session: remote-history response parsing now also unwraps GraphQL viewer and node containers, covering shapes such as data.viewer.session.events and data.node.eventConnection while preserving the same cursor pagination behavior.
  • internal/session: remote-history link pagination now accepts links/_links next/previous/prev/older string URLs or {href,url,uri,link} objects and extracts before/cursor query parameters for continuation.
  • internal/session: remote-history link pagination now also accepts link objects and link-array items that carry cursor fields directly, such as cursor, beforeId, and lastEvaluatedKey, including _/- field-name variants, instead of requiring href/url links.
  • internal/session: remote-history event selection now prefers materialized event payloads over JSON:API relationship identifier lists, so relationships.events.data {type,id} links can resolve through top-level included resources instead of yielding empty SDK events.
  • internal/session: remote-history event-list arrays now also flatten JSON:API/session resource wrappers that contain nested relationship event pages, merge their nested pagination fields, and skip clearly non-event resources such as tool/task records instead of materializing empty SDK events.
  • internal/session: remote-history link pagination now also accepts RFC/JSON:API-style links arrays with relation values from rel, relation, name, type, kind, or label, such as previous, prev, older, and next, including _/- page/link/cursor suffix variants.
  • internal/session: remote-history pagination now also accepts HTTP Link header URLs with previous/prev/older/next rels as continuation cursor fallbacks, including _/- page/link/cursor suffix variants and headers whose bracketed URLs or quoted parameters contain commas.
  • internal/session: sidechain state loading now accepts legacy subagent/agent/task start and finish subtype aliases, broader sidechain/subagent ID and type fields, summary aliases, and common running/completed/cancelled/failed status aliases.
  • internal/session: sidechain agent metadata sidecar loading now accepts broader agent type, workspace/worktree path, and task-description field aliases such as subagentType, agentName, workspacePath, taskDescription, prompt, and title.
  • internal/session: sidechain lifecycle content loading now recurses through wrapper objects such as payload, data, result, response, and metadata, preserving nested subagent IDs, status, summaries, agent type, worktree path, and task descriptions during state/list/resume recovery.
  • internal/session: sidechain lifecycle content loading now also accepts JSON:API/resource-style resource/attributes/properties wrappers, preserving outer resource IDs as sidechain ID fallback while recovering nested metadata, status, and summary fields.
  • internal/session: sidechain lifecycle content loading now also recurses through GraphQL/JSON:API edge/node/attrs wrappers, preserving wrapped start and summary event fields during state/list/resume recovery.
  • internal/session: sidechain lifecycle field extraction now also traverses collection wrappers such as edges, nodes, and included, plus array elements, so GraphQL connection or JSON:API included start/summary payloads can still recover state/list/resume fields.
  • internal/session: sidechain lifecycle scalar fields now accept JSON number values for IDs and other string-like fields, preserving numeric subagent IDs as strings across state/list/resume recovery.
  • internal/session: sidechain lifecycle and metadata sidecar loading now accept adjacent runtime aliases such as jobId, threadId, workflowId, operationId, requestId, workerType, taskType, workspaceRoot, projectPath, instructions, operationName, commandName, displayTitle, jobStatus, resultState, outputText, and millisecond start/end time fields under runtime/context/state or JSON:API/resource wrappers.
  • internal/session: sidechain lifecycle start/end time loading now also accepts timestamp and Unix-style aliases such as startTimestamp, startTimestampMs, startedAtUnix, endTimestamp, completedTimestamp, and completedAtUnixMs, preserving lifecycle times from adjacent runtime transcript writers.
  • internal/session: sidechain lifecycle and metadata sidecar summary/description loading now accepts visible text payloads, including text content blocks, message objects, content block arrays, and provider-style message.content/parts/outputText wrappers while ignoring hidden thinking/tool/image blocks.
  • internal/session: sidechain runtime finish now canonicalizes status aliases such as success, error, and canceled before writing summary records, keeping sidechain and main transcript lifecycle output stable.
  • internal/session: sidechain runtime now rejects duplicate starts while the same sidechain ID is running, and state loading treats a later start as a fresh lifecycle by clearing stale summary/end metadata.
  • internal/session: sidechain lifecycle state loading now accepts adjacent subtype aliases such as subagent_started, agentStarted, task_failed, and sidechainCompleted, with broader task/worker/run ID fields plus resultText/finalMessage summaries and subtype-derived failed/cancelled defaults.
  • internal/session: sidechain lifecycle status normalization now accepts compact/camel aliases such as inProgress, completedSuccessfully, cancelledByUser/canceledByUser, failedError/failedWithError, and timedOut, while still writing canonical running/completed/cancelled/failed states.
  • internal/session: transcript metadata loading now indexes file-history and attribution snapshots by message ID, with aliases such as message_id, messageUuid, and id, while preserving raw snapshot lists.
  • internal/session: transcript indexes and session search now recover message gitBranch values, accept git_branch/branch aliases, and can match sessions by branch name.
  • internal/session: full transcript title derivation now matches indexed/lite fallback order: custom title, AI title, first user prompt, last-prompt metadata, then summary.
  • internal/session: lightweight transcript indexes now scope content-replacement counts to the requested session id, matching other session metadata filters used by session list/search summaries.
  • internal/session: transcript indexes and session search now recover message cwd as project path, accept project/working-directory aliases, and can match sessions by project path.
  • internal/session: transcript message loading now preserves structured SerializedMessage metadata such as userType, entrypoint, version, and slug, including common alias spellings.
  • internal/session: lightweight transcript metadata loading now clears stale context-collapse commit/snapshot state after compact-boundary messages, matching the full loader and official sessionStorage restore semantics.
  • internal/session: transcript metadata loading now accepts sessionID and session as session-scoped ID aliases and tolerates numeric strings for counters such as prNumber, timeSavedMs, and lastSpawnTokens.
  • internal/session: transcript metadata ID helpers now reuse contract ID JSON decoding so metadata IDs such as messageID and sessionID can be JSON numbers preserved as strings.
  • internal/session: context-collapse commit metadata now routes collapse, summary, and archived ID fields through metadata ID decoding so JSON number IDs are preserved in full and lightweight metadata loaders.
  • internal/session: content-replacement metadata now preserves JSON number agent, tool-use, and block IDs as strings in full and lightweight metadata loaders.
  • internal/session: context-collapse snapshot metadata now accepts alternate armed, token-count, and staged payload field names in both full and lightweight metadata loaders.
  • internal/session: transcript metadata loading now unwraps JSON:API/resource, GraphQL edge/node, included, and collection/list/value wrappers before metadata classification, so full transcripts, lightweight metadata, and transcript indexes recover wrapped title/task/tag/worktree/content-replacement/context-collapse entries consistently.
  • internal/session: transcript metadata type normalization now accepts compact/camel aliases such as aiTitle, lastPrompt, taskSummary, contentReplacement, fileHistorySnapshot, speculationAccept, and contextCollapseSnapshot across full transcripts, lightweight metadata, and transcript indexes.
  • internal/session: transcript metadata field lookup now normalizes case, snake_case, kebab-case, and space-separated variants, so fields such as Session-ID, Custom-Title, and Pull-Request-Number recover across full transcripts, lightweight metadata, and transcript indexes.
  • internal/session and internal/contracts: transcript message/envelope and nested contract message field lookup now use the same case, snake_case, kebab-case, and space-separated normalization, so fields such as Message-Type, Message ID, Parent-Message-ID, Session-ID, Git-Branch, and Message Text recover through full transcript loading, progress bridge handling, line indexes, and indexed resume.
  • internal/session and internal/contracts: legacy session JSONL SessionEntry loading now reuses normalized field lookup too, so fields such as Entry Type, Message-ID, Parent Message ID, Session-ID, and Created At recover through session.Load with nested messages intact.
  • internal/contracts/internal/session: remote-history SDKEvent decoding now reuses normalized field lookup, so fields such as Event Type, Event-ID, Parent Message ID, Created At, Message-Payload, Status Message, Failure Reason, and Final Output recover event type, IDs, parent, timestamp, status/error/result text, and transcript materialization messages.
  • internal/session and internal/contracts: transcript records and nested contract messages now accept top-level sessionID as a session id alias, preserving it through LoadTranscript, LoadTranscriptIndex, and indexed resume (TestLoadTranscriptAcceptsSessionIDUpperAlias).
  • internal/contracts/internal/session: remote-history SDKEvent decoding now accepts top-level sessionID as an event session id alias and preserves it during transcript materialization (TestRemoteHistoryTranscriptMessagesAcceptsSessionIDUpperAlias).
  • internal/contracts/internal/session: remote-history SDKEvent decoding now accepts parent aliases such as parentUUID, parentId/parentID/parent_id, and parentMessageId/parentMessageID/parent_message_id, preserving parent chains during transcript materialization (TestRemoteHistoryTranscriptMessagesAcceptsParentIDAliases).
  • internal/contracts/internal/session: remote-history SDKEvent decoding now accepts event/message ID aliases such as eventID, messageId/messageID/message_id, and messageUuid/messageUUID/message_uuid, using them as transcript UUID fallbacks during materialization (TestRemoteHistoryTranscriptMessagesAcceptsEventMessageIDAliases).
  • internal/contracts/internal/session: remote-history SDKEvent timestamp decoding now accepts adjacent aliases such as created, createdTime/created_time, date_time, eventTime/event_time, and occurredAt/occurred_at, and tolerates JSON number timestamp fields before transcript materialization (TestSDKEventUnmarshalAcceptsTimestampAliases, TestRemoteHistoryTranscriptMessagesAcceptsEventTimestampAliases).
  • internal/contracts/internal/session: remote-history SDKEvent.message now accepts top-level string and content-block array payloads, wrapping them as message content before event decoding so provider-shaped assistant/user events still materialize into transcript messages (TestSDKEventUnmarshalAcceptsScalarMessagePayload, TestRemoteHistoryTranscriptMessagesAcceptsScalarEventMessagePayload).
  • internal/contracts/internal/session: remote-history SDKEvent status/error/result payloads now accept adjacent field aliases such as statusMessage, progress_message, stateMessage, updateText, messageText, errorMessage, failure_reason, failureMessage, exceptionMessage, diagnosticMessage, resultText, outputText, summaryText, finalOutput, and result object aliases including output, response, value, completion, summary, and final, scoped to the matching canonical event type (TestSDKEventUnmarshalAcceptsStatusErrorResultAliases, TestRemoteHistoryEventsAcceptStatusErrorResultAliases).
  • internal/contracts/internal/session: remote-history SDKEvent type canonicalization now also accepts adjacent stream/provider aliases such as assistant_delta, humanMessage, finalResult, response.completed, failureEvent, and statusMessage, keeping transcript materialization stable across SDK event spellings.
  • internal/session: sidechain runtime start now persists agent type, worktree path, and task description into the lifecycle transcript payload as well as the metadata sidecar, so resume/list can recover subagent metadata even if the sidecar is missing.
  • internal/memory: memory age/freshness helpers now match official stale-memory guidance, and document loading can prefix old memory files with a system-reminder that they are point-in-time observations.
  • internal/memory: relevant-memory attachment primitives now match the official relevant_memories shape for stable headers, system-reminder rendering, surfaced path/byte scanning, 200-line/4096-byte surfacing reads with truncation notices, mark-after-filter duplicate attachment handling, last-non-meta-user/single-word/session-byte-cap prefetch gating, top-5 candidate filtering after read-state/surfaced de-dup, and recent successful tools collection excluding pending/failed/same-name-failed tools.
  • internal/conversation: request building now expands relevant_memories attachment messages into user/meta system-reminders before Anthropic API normalization.
  • internal/conversation: runners can now opt into a configured relevant-memory directory, deterministically select matching memory files, surface them as relevant_memories, and inject them into the next request while leaving default behavior unchanged.
  • internal/conversation: configured relevant-memory directories are now propagated to tool metadata as internal auto-memory paths so file-tool freshness and permission checks share the same context.
  • internal/session: transcript resume now preserves raw attachment payloads for fallback attachment messages, keeping resumed relevant_memories expandable in request construction.
  • internal/tools/file: Read now prefixes old auto-memory file reads with the same freshness system-reminder when internal auto-memory directory metadata is available.
  • internal/tools/file: Write/Edit now call the memory secret guard for team-memory paths.

M7 progress now includes:

  • internal/tui: lightweight terminal frame renderer using ANSI clear/home/cursor control, message/status/prompt/dialog components, prompt input editing including shared kill-ring state, shift-enter multiline prompt input, line-local multiline prompt ctrl-a/ctrl-e/ctrl-u/ctrl-k editing plus multiline prompt wrap/render/cursor placement, ctrl-b/ctrl-f/ctrl-u/ctrl-k/ctrl-w line editing, ctrl-p/ctrl-n prompt and reverse-search navigation, alt-b/alt-f/alt-d/alt-backspace word editing, ctrl-left/ctrl-right/alt-left/alt-right word motion, ctrl-y yank, and alt-y yank-pop initial support, reverse-search cursor/word editing/kill/yank/yank-pop initial support, ctrl-c interrupt/double-press exit events, ctrl-d delete-forward and empty-input double-press exit events, ctrl-l redraw events, ctrl-o/ctrl-t global toggle events, ctrl-g/ctrl-s/ctrl-x chord chat events, prompt history navigation, reverse-search state/rendering/selection/script assertions including empty/cancel paths and cursor position, paste/image hint input handling with OSC ST terminators and base64 filename decoding, text/image pasted-content references with expanded submit text, metadata script assertions, and history entry restoration, SGR mouse parsing, alternate terminal navigation key sequences including modified Home/End/Delete/PageUp/PageDown, wheel scrolling with modifiers, primary clicks with modifiers, primary drag viewport selection, configurable viewport half-page/top/bottom scrolling, viewport line selection and dialog action clicks, focus/blur events, resize scroll preservation, default and configurable keybinding resolver with chord pending/null-unbind behavior, key/action camelCase aliases, keybinding JSON config loading, and focus/mouse/paste/image key names, vim insert/normal word, WORD, ge/gE, operator ge/gE, line-local ^/$/0/|/I/A/D, quote, bracket, and j/k linewise motions/text objects, persistent yank/register/paste paths, last-change dot-repeat, G/gg line navigation, toggle-case, join, open-line, indent, substitute, delete/count/replace/undo/find/till/repeat/matching-pair % actions, normal-mode arrow/backspace/delete mappings, and operator character ranges, permission/task dialog builders with kind/id routing/runtime resolution/status line, stale dialog race guards, active dialog cancellation, permission id/bulk cancellation, queued permission promotion, active task dialog refresh, task lifecycle state transitions and bulk cancellation, idempotent alternate screen lifecycle/reset/reassert-interactive sequences, mouse/focus/bracketed-paste terminal mode lifecycle/reconciliation and reassertion sequences, ANSI snapshot capture/stripping, snapshot corpus write/compare/script-file compare/missing-baseline/diff/batch/strict unexpected-baseline status, scripted interaction runner with JSON/JSONL/wrapper loading and file-runner entrypoints, JSON/runtime/task camel field aliases, keybinding mutations, permission-cancel runtime mutations, and assertions including vim mode/register/task state/dialog result/runtime mutation/task bulk-cancel/status negative/snapshot negative/screen size/event-sequence/event-count/no-event/dialog-result-count/no-dialog-result plus multi-key/text/paste/image/pasted-content metadata and named-key input, REPL screen model, viewport scrolling, and selection focus model.
  • internal/tui: configurable keybindings now treat VS Code-style dash-prefixed command names such as -workbench.action.clearScreen and wrapped -claude.action.killAgents as explicit unbinds instead of normalizing them into live actions.
  • internal/tui: configurable keybinding action parsing now accepts more VS Code-style editor/workbench action names such as cursorWordLeft, cursorLineEnd, editor.action.deleteLeft, deleteAllRight, and workbench.action.terminal.clear, mapping them onto the existing prompt movement, delete, and redraw actions.
  • internal/tui: Vim prompt editing now includes basic visual and visual-line mode support with v/V, motion-extended selections, active-end toggle with visual o/O, visual </> line indent/outdent, visual ~/g~ case toggling, visual u/U plus gu/gU lower/upper-case conversion, y/d/c range operators plus common visual x/s aliases, Escape return-to-normal behavior, and script expectation aliases for visual/visualLine modes.
  • internal/tui: Vim prompt editing now supports normal-mode gv reselecting the previous characterwise or linewise visual selection before applying another visual operator.
  • internal/tui: Vim prompt editing now includes gu/gU/g~ case-conversion operators across motion, linewise, find/till, text-object, and dot-repeat paths without updating the yank register.
  • internal/tui: Vim prompt editing now includes normal-mode gJ raw line joins that do not insert or normalize whitespace and can be dot-repeated.
  • internal/tui: Vim prompt editing now supports normal, operator, and visual +/-/_ first-nonblank line motions, including linewise operator ranges and dot-repeat replay.
  • internal/tui: Vim prompt editing now supports normal, operator, and visual g_ last-nonblank line motions, preserving charwise operator ranges for commands such as dg_.
  • internal/tui: Vim prompt editing now supports prompt-local H/M/L screen-line motions across normal, visual, and linewise operator paths, including counted top/bottom targeting and dot-repeat replay for operators.
  • internal/tui: Vim prompt editing now includes visual and visual-line J/gJ joins across selected line ranges, sharing the normal whitespace-normalized and raw join semantics plus undo, gv, and dot-repeat recording.
  • internal/tui: Vim prompt editing now includes visual and visual-line p/P paste-over-selection behavior for characterwise and linewise registers, updating the unnamed register with the replaced text and avoiding extra trailing blank lines for end-of-buffer line replacements.
  • internal/tui: Vim prompt editing now includes visual and visual-line r{char} selection replacement, replacing non-newline characters while preserving line structure, supporting undo, and remembering the previous visual range for gv.
  • internal/tui: Vim prompt editing now includes normal-mode R replace mode, overwriting from the current cursor, appending past the end of text, and supporting undo plus dot-repeat.
  • internal/tui: Vim prompt editing now includes prompt-local marks with m{mark}, exact `` {mark} jumps, linewise `'{mark}` jumps, and mark-based operator motions for `d`/`c`/`y` style operators.
  • internal/tui: Vim prompt editing now includes basic macro recording and replay with q{reg}, normal-mode q stop, counted @{reg}, and @@ repeat-last-macro support.
  • internal/tui: Vim prompt editing now includes prompt-local / and ? search modes with Enter execution, Escape cancellation, Backspace query editing, wraparound matching, and n/N repeat or reverse-repeat search.
  • internal/tui: Vim prompt editing now treats / and ? as operator motions for actions such as d/search and c?search, including search counts, pending-state cleanup on cancel, register updates, and dot-repeat recording for search operators.
  • internal/tui: Vim prompt editing now supports /, ?, n, and N in visual and visual-line modes, returning from the search prompt to the active selection on Enter and preserving the original selection on Escape cancellation.
  • internal/tui: Vim prompt editing now supports "{reg} named register prefixes across normal/operator/visual yank, delete, and paste paths, including uppercase append registers, black-hole no-op handling, and cleanup of unused register selections after non-register commands.
  • internal/tui: Vim prompt editing now updates unnamed or selected named registers for normal-mode x/X character deletions while preserving dot-repeat replay for those delete commands.
  • internal/tui: Vim prompt editing now supports visual and visual-line Y/D/C/X/S linewise aliases, forcing characterwise selections to operate on whole selected lines while preserving linewise unnamed or named register contents.
  • internal/session: prompt history now persists image pasted-content metadata such as media type, filename, dimensions, and image-cache source path while still omitting inline base64 image bytes and text-paste hashes for images.
  • internal/session: prompt history loading now backfills missing image source paths from existing per-session image-cache files and refreshes the in-memory image path cache when those files exist.
  • internal/session: cached image restore now accepts session image-cache relative source paths such as 4.webp, while keeping the same root, basename, regular-file, and symlink escape validation as absolute/file URL source paths.
  • internal/tui: interaction script key fields now accept DOM-style key event objects with key/code including Numpad*, extended numpad paren/hash/backspace codes, and punctuation key codes, legacy keyIdentifier, numeric keyCode/which/charCode including punctuation and numpad operators, keypress.which char-code replay, modifier booleans such as ctrlKey/altKey/metaKey/shiftKey, and modifier arrays, including wrapper payloads and modifier-only event filtering.
  • internal/tui: interaction script key event objects now accept numeric repeat/count aliases such as repeatCount, count, and times, expanding compressed keydown recordings into repeated key replay with a bounded cap.
  • internal/tui: interaction script key event objects now treat DOM keyup/keyUp/key-release payloads as no-op replay events, so browser/Playwright recordings that include both keydown and keyup do not duplicate prompt input.
  • internal/tui: interaction script key event replay now also skips DOM Dead/Process/IME key names, isComposing payloads, and composition event types, preventing IME/dead-key recording artifacts from being inserted as literal prompt text.
  • internal/tui: interaction script action replay now accepts DOM beforeinput/input events with data payloads, mapping text insertion to prompt typing and insertFromPaste/drop variants to the existing pasted-content path.
  • internal/tui: interaction script DOM input replay now maps deletion and line-break inputType values such as deleteContentBackward, deleteWordBackward, deleteHardLineForward, and insertLineBreak onto existing prompt key actions.
  • internal/tui: interaction script mouse payloads now infer release state from event type aliases such as mouseup, pointerUp, and touchend, while explicit release booleans still take precedence.
  • internal/tui: interaction script mouse payloads now infer SGR wheel buttons from DOM/compact wheel inputs such as wheel, mousewheel, scrollUp/scrollDown, direction, deltaY, and legacy wheelDelta, allowing recorded wheel events to drive viewport scrolling.
  • internal/tui: interaction script mouse payloads now accept DOM which and buttons/buttonState bitmasks and map them to SGR left/middle/right buttons so recorded secondary or auxiliary clicks are not treated as primary clicks.
  • internal/tui: interaction script mouse payloads now map buttonless DOM mousemove/pointermove events to SGR buttonless motion and pressed move/drag events to SGR motion buttons, preventing hover/move recordings from firing dialog or viewport primary-click actions.
  • internal/tui: interaction script touch payloads now recover coordinates from the first touches/targetTouches/changedTouches touch point, map touchmove to SGR drag motion, and map touchcancel to release events for DOM touch recording fixtures.
  • internal/tui: REPL dialogs now ignore SGR motion/drag mouse buttons and only act on real press/click events, preventing pointer or touch move replay from closing permission/task dialogs.
  • internal/tui: interaction script paste payloads now accept DOM clipboardData/dataTransfer objects and recover pasted text from text/plain, plainText, and items[].text fields for ClipboardEvent recording fixtures.
  • internal/tui: interaction script paste payloads now also recover text from ClipboardItem-style items[].getAsString/get_as_string plus adjacent stringData/textData fields, so DOM clipboard recordings do not need to flatten item text first.
  • internal/tui: interaction script paste payloads now also recover image/* file items from DOM clipboardData.items and dataTransfer.files as image paste events while avoiding accidental base64-as-text insertion from image data payloads.
  • internal/tui: interaction script clipboard/dataTransfer image paste now prefers nested file payloads such as items[].file, items[].blob, and items[].getAsFile, preserving filename, media type, base64 data, and source path instead of stopping at the outer MIME.
  • internal/tui: interaction script resize payloads now accept DOM/window size aliases such as innerWidth/innerHeight, clientWidth/clientHeight, offsetWidth/offsetHeight, plus ResizeObserver-style contentRect and target wrappers.
  • internal/tui: interaction script resize payloads now accept ResizeObserver contentBoxSize/borderBoxSize array entries using inlineSize/blockSize, covering modern browser box-size event shapes.
  • internal/tui: interaction script event expectations now normalize camel/dash/provider-style event names such as promptSubmitted, dialogAction, messageSubmitted, and focusOut to canonical screen event types, and accept value aliases such as eventPayload, eventValue, actionValue, and result.
  • internal/tui: task runtime now canonicalizes state aliases such as active/inProgress/in_progress, success/done/completedSuccessfully, error/failedWithError, and canceled/cancelledByUser before status-line summaries, task dialogs, ordering, cancellation, and scripted task expectations.
  • internal/tui: scripted task runtime payloads and task expectations now accept adjacent fields such as taskID, jobId, runId, label, displayName/displayTitle, operationName/commandName, phase/taskState/jobStatus/resultState, message/currentStep/statusMessage/outputText/resultText, percent/percentage/pct/completionPercent, and numeric/string task IDs or progress values.
  • internal/tui: scripted task runtime payloads, task expectations, and remove-task mutations now also share adjacent task ID aliases such as operationId, requestId, threadId, workflowId, and toolUseId, so recorded runtime actions can address tasks through operation/request-style IDs.
  • internal/tui: permission runtime now treats action aliases such as Reject, deny, decline, disallow, and no as denied results, Cancel/abort as cancelled results, and keeps allowed aliases canonical for scripted dialog-result status checks.
  • internal/tui: scripted permission payloads, dialog expectations, events, cancellation, and dialog-result expectations now accept adjacent ID and field aliases such as permissionID, requestID, toolUseID, operationID, operation, commandName, resourcePath, body, reasonText, allowedActions, buttons, and numeric request IDs.
  • internal/tui: configurable keybinding names now accept macOS/DOM-style cmd/command/super modifier aliases for the same prompt-editing keys already covered by meta/option, including word motions, yank-pop, delete-word-back, and modified left/right arrows.
  • internal/tui: scripted runtime permission/task payloads now recursively unwrap JSON:API/GraphQL-style envelopes such as value, payload, data, resource, attributes, properties, attrs, edge, node, included, collection, list, and values, while carrying resource/node IDs into nested permission/task objects, skipping explicitly non-permission/task typed included resources, and avoiding empty objects created from wrapper-only payloads.
  • internal/tui: scripted runtime mutations now recursively unwrap wrapped IDs/details for removeTask, cancelPermission, and cancelTasks, so action fixtures can carry task IDs, permission IDs, and cancellation reasons inside payload.resource.attributes, edge.node, or adjacent API envelopes.
  • internal/tui: scripted runtime mutation alias fields now accept object payloads directly, so removeTask, cancelPermission, and cancelTasks can carry wrapped resource/edge payloads without failing early on string/bool-only unmarshalling.
  • internal/tui: scripted runtime action booleans now recurse through wrapped payloads, letting cancelTasks, openTasks, and related action-discriminator steps honor JSON:API/GraphQL enabled:false or open:false flags instead of falling back to true for object payloads.
  • internal/tui: scripted interaction boolean aliases now accept non-strict bool payloads ("true"/"false", yes/no, on/off, and numeric 1/0) for mouse release, dialog visibility/result checks, prompt empty checks, vim state checks, reverse-search checks, and top-level step controls such as focus, cancellation, task dialog open, and negative event assertions.
  • internal/tui: scripted interaction steps now accept expectation wrapper objects such as expect, expected, assertions, checks, verify, then, and after, mapping nested prompt/event/dialog/snapshot/screen/task/vim/viewport assertions onto the existing expect* fields.
  • internal/tui: scripted interaction expectation wrappers now also accept assertion/check arrays with type/kind/name/target discriminators and value/payload assertion bodies, covering official fixture styles that list checks separately.
  • internal/tui: scripted interaction assertion/check array bodies now also accept JSON:API/resource-style aliases such as resource, node, attributes, properties, result, response, and output for prompt/event/dialog/snapshot/screen/task/vim/viewport expectations.
  • internal/tui: interaction scripts can now set status/baseStatus via status, setStatus, statusLine, or baseStatus, and runtime-aware scripts retain that base while layering permission/task status counts.
  • internal/tui: terminal lifecycle can now manage extended-key reporting with Kitty keyboard protocol plus xterm modifyOtherKeys, including disable ordering and pop-before-push reassertion to avoid Kitty stack leaks.
  • internal/tui: renderer and ANSI snapshots now have an opt-in DEC 2026 synchronized-output wrapper for official BSU/ESU frame fixtures without changing default rendering.
  • internal/tui: terminal OSC helpers can generate sanitized OSC 0 title/icon sequences, and ANSI stripping now skips OSC/DCS-style payloads so invisible terminal controls do not leak into visible snapshot text.
  • internal/tui: terminal OSC helpers now cover OSC 21337 tab-status generation/clear sequences and tmux/screen passthrough wrapping with official status-text escaping.
  • internal/tui: terminal OSC helpers now generate OSC 8 hyperlink start/end sequences with official URL-derived id parameters and explicit param overrides.
  • internal/tui: terminal OSC helpers now generate OSC 9;4 progress clear/set/error/indeterminate sequences with official 0..100 percentage clamping.
  • internal/tui: terminal OSC helpers now generate iTerm2, Kitty, and Ghostty notification sequences plus raw BEL notifications for caller-managed emission.
  • internal/tui: terminal OSC helpers now generate OSC 52 clipboard sequences using UTF-8 base64 payloads, support explicit clipboard selections and clear sequences, and still leave native clipboard and tmux buffer runtime for future work.
  • internal/tui: terminal OSC helpers now support explicit ST (ESC \\) terminators for Kitty-style no-BEL OSC output while preserving BEL as the default.
  • internal/tui: terminal OSC helpers now parse #RRGGBB and XParseColor-style rgb:R/G/B colors, scaling 1-4 digit hex components to 8-bit RGB like the official parser.
  • internal/tui: terminal OSC parsing now exposes OSC 10-19 dynamic color set/query sequences as structured color actions, including repeated payload parameters that advance to subsequent dynamic color targets while keeping visible text clean.
  • internal/tui: terminal OSC parsing now exposes OSC 110-119 dynamic color reset sequences as structured color reset actions for foreground/background/cursor, pointer, Tektronix, and highlight color targets.
  • internal/tui: terminal OSC parsing now exposes OSC 4 palette color set/query sequences and OSC 104 palette reset sequences as structured palette actions, including repeated index/color pairs and indexed resets.
  • internal/tui: terminal OSC parsing now exposes OSC 5 special color set/query sequences and OSC 105 special color reset sequences as structured specialColor actions, validating special indexes 0-4.
  • internal/tui: terminal OSC helpers now parse OSC 21337 tab-status payloads with escaped separators, clear/null semantics, unknown-key ignore behavior, and parsed indicator/status colors.
  • internal/tui: terminal OSC helpers now parse OSC 8 hyperlink payloads, including params, semicolon-containing URLs, and empty-URL link-end sequences.
  • internal/tui: terminal OSC helpers now expose a lightweight ParseOSCContent covering title, hyperlink, tab-status, and unknown action branches.
  • internal/tui: terminal OSC helpers now parse complete BEL- or ST-terminated OSC sequences into ParseOSCContent actions.
  • internal/tui: terminal OSC parsing now dispatches clipboard, progress, and common notification sequences as structured actions while keeping visible-text stripping behavior intact.
  • internal/tui: terminal OSC parsing now recognizes OSC 7 current-directory URI payloads and exposes raw URI, scheme, host, and path as a structured directory action while keeping visible text clean.
  • internal/tui: terminal CSI scroll-region parsing now preserves ANSI default semantics for reset/omitted parameters instead of treating CSI r as a one-line region.
  • internal/tui: terminal ESC parsing now recognizes HTS (ESC H) as a structured tab-set cursor action.
  • internal/tui: terminal renderer constants now include clear-scrollback and legacy Windows cursor-home helpers for official clear-terminal sequence parity without platform auto-detection.
  • internal/tui: terminal CSI helpers now generate cursor movement/position and erase sequences with official zero-move and horizontal-first cursorMove semantics.
  • internal/tui: terminal CSI helpers now generate scroll up/down and scroll-region sequences with official zero-scroll behavior.
  • internal/tui: terminal CSI helpers now generate DECSCUSR cursor-style sequences for block, underline, and bar cursors with blinking variants.
  • internal/tui: terminal CSI helpers now expose bracketed-paste and focus input marker constants aligned with the existing key parser.
  • internal/tui: terminal CSI helpers now generate official eraseLines(n)-style multi-line erase sequences ending at column 1.
  • internal/tui: terminal CSI helpers now expose official CSI param/intermediate/final byte-range classifiers for parser parity.
  • internal/tui: terminal CSI parsing now accepts multi-parameter mode set/reset sequences such as CSI ?1000;1006;2004h and exposes the full mode list while preserving the first mode for existing single-mode callers.
  • internal/tui: terminal CSI parser now emits structured edit actions for insert/delete chars and insert/delete lines, plus forward/back tab cursor actions; output CSI M is parsed as delete-lines while input tokenization still keeps X10 mouse payload handling separate.
  • internal/tui: terminal CSI parser now emits report actions for DSR CSI n, including device-status, cursor-position, and private-mode unknown reports.
  • internal/tui: terminal CSI parsing now preserves complete DSR/device-status parameter lists such as CSI ?6;1n while keeping the existing first-code and private-marker fields.
  • internal/tui: terminal CSI parser now emits report actions for CPR cursor-position responses such as CSI row;col R and DEC private CSI ? row;col R, preserving row/column metadata while keeping visible text clean.
  • internal/tui: terminal CSI parser now treats DEC private CSI ?6n as a cursor-position report query and preserves the optional page field from CSI ?row;col;page R CPR responses.
  • internal/tui: terminal CSI parsing now preserves complete CPR cursor-position response parameter lists such as CSI ?12;34;2R while keeping the existing structured row/column/page fields.
  • internal/tui: terminal sequence dispatcher and parser now classify DCS/APC/PM/SOS string-control sequences as stringControl actions with payload, terminator, and incomplete-flush state while keeping visible text extraction free of those invisible payloads.
  • internal/tui: terminal CSI parser now recognizes DEC X10, highlight, UTF-8, urxvt numeric, and xterm SGR-pixels mouse modes (?9h/l, ?1001h/l, ?1005h/l, ?1015h/l, ?1016h/l) as mouse-tracking mode actions.
  • internal/tui: terminal CSI parser now recognizes xterm alternate scroll mode (?1007h/l) as a structured mode action instead of an unknown sequence.
  • internal/tui: terminal CSI parser now recognizes DEC application cursor mode (?1h/l) as a structured mode action, pairing with SS3 application cursor key parsing.
  • internal/tui: terminal CSI parser now recognizes DEC 132/80-column mode (?3h/l) as a structured columnMode action.
  • internal/tui: terminal CSI parser now recognizes DEC allow-column-switching mode (?40h/l) as a structured allowColumnSwitch mode action.
  • internal/tui: terminal CSI parser now recognizes DEC no-clear-on-column-switch mode (?95h/l) as a structured noClearOnColumnSwitch mode action.
  • internal/tui: terminal CSI parser now recognizes DEC reverse video/screen mode (?5h/l) as a structured reverseVideo mode action.
  • internal/tui: terminal CSI parser now recognizes ordinary ECMA insert/replace mode (CSI 4h/l) as a structured insertMode action.
  • internal/tui: terminal CSI parser now recognizes ordinary ECMA line-feed/new-line mode (CSI 20h/l) as a structured lineFeedMode action.
  • internal/tui: terminal CSI parser now recognizes DEC origin mode (?6h/l) and auto-wrap mode (?7h/l) as structured mode actions.
  • internal/tui: terminal CSI parser now recognizes DEC auto-repeat mode (?8h/l) as a structured autoRepeat mode action.
  • internal/tui: terminal CSI parser now recognizes DEC cursor blink mode (?12h/l) as a structured cursorBlink mode action.
  • internal/tui: terminal CSI parser now recognizes DEC margin bell mode (?44h/l) as a structured marginBell mode action.
  • internal/tui: terminal CSI parser now recognizes xterm/DEC reverse-wraparound mode (?45h/l) as a structured reverseWrap mode action.
  • internal/tui: terminal CSI parser now recognizes DEC logging mode (?46h/l) as a structured logging mode action.
  • internal/tui: terminal CSI parser now recognizes DEC application keypad mode (?66h/l) as a structured applicationKeypad mode action.
  • internal/tui: terminal ESC parser now maps VT100 ESC =/ESC > application/numeric keypad mode controls onto the same structured applicationKeypad mode action as CSI ?66h/l.
  • internal/tui: terminal CSI parser now recognizes DEC backarrow key mode (?67h/l) as a structured backarrowKey mode action.
  • internal/tui: terminal CSI parser now recognizes DEC left/right margin mode (?69h/l) as a structured leftRightMarginMode action.
  • internal/tui: terminal CSI parsing now distinguishes parameterized CSI Pl;Pr s left/right horizontal margin regions from bare CSI s save-cursor semantics.
  • internal/tui: terminal CSI parsing now recognizes intermediate-space CSI Ps SP @ / CSI Ps SP A scroll-left/right sequences instead of misclassifying them as insert-characters or cursor-up.
  • internal/tui: terminal ESC parsing now exposes DEC line/screen attribute controls (ESC # 3/4/5/6/8) as structured screen actions instead of falling back to unknown.
  • internal/tui: terminal ESC parsing now maps DECID identify-terminal (ESC Z) to the existing device-attributes report action, matching the CSI c query path.
  • internal/tui: terminal CSI parsing now marks DEC selective erase CSI ? Ps J / CSI ? Ps K separately from ordinary ED/EL erase actions.
  • internal/tui: terminal CSI parsing now exposes ECMA CSI Ps N / CSI Ps O erase-in-field and erase-in-area actions with the same to-end/to-start/all regions used by other erase operations.
  • internal/tui: terminal CSI parsing now treats explicit zero count/position params as ANSI defaults for cursor movement/position/column, insert/repeat/erase chars, and scroll actions while preserving raw zero selector semantics for mode/report/erase selector sequences.
  • internal/tui: terminal tokenizer, sequence dispatcher, CSI parser, and visible-text stripping now accept 8-bit C1 CSI (0x9b) sequences, including chunked SGR input and X10 mouse payload boundaries.
  • internal/tui: terminal key parser now accepts 8-bit C1 CSI (0x9b) bracketed paste, focus, direct/numbered/modified navigation, function-key, CSI-u/Kitty key, SGR/URXVT mouse, and X10 mouse input forms.
  • internal/tui: terminal tokenizer, SS3 parser, and key parser now accept 8-bit C1 SS3 (0x8f) application cursor, modified navigation, and F1-F4 function-key sequences.
  • internal/tui: terminal tokenizer, OSC parser, string-control dispatcher, and visible-text stripping now accept 8-bit C1 OSC/DCS/APC/PM/SOS with C1 ST (0x9c) terminators while preserving valid UTF-8 text bytes.
  • internal/tui: keybinding config, keymap resolution, and interaction script named-key input now accept terminal aliases for ctrl-h/ctrl-i/ctrl-j/ctrl-m, ctrl-[, and ctrl-?, including control-* and compact/camel variants.
  • internal/tui: keybinding config now accepts page/navigation/editing aliases such as pgup, pg-up, prior, pageUpKey, pgdn, pg-down, next, pageDownKey, homeKey, endKey, deleteForward, forwardDelete, and deleteBackward.
  • internal/tui: keybinding config and named-key script input now accept DOM/fixture control-key aliases such as enterKey, returnKey, numpadEnter, escapeKey, escKey, tabKey, shiftEnterKey, shiftNumpadEnter, shiftTabKey, and backtabKey.
  • internal/tui: keybinding config and named-key script input now accept DOM-style arrow key aliases such as arrowLeft, arrowRight, arrowUp, arrowDown, and modifier-arrow variants.
  • internal/tui: keybinding action parsing now accepts broader editor/global-style aliases and namespaced editor.action.*/workbench.action.*/terminal.action.*/chat.action.* aliases such as cursorLeft, previousWord, nextWord, lineStart, lineEnd, moveToBeginningOfLine, moveToEndOfLine, deletePreviousChar, deleteNextChar, backwardDelete, forwardDelete, deleteToStartOfLine, deleteToEndOfLine, killLine, pasteKillRing, clearScreen, openExternalEditor, toggleTasks, cancelAgents, focusPrev, acceptSelection, and search.
  • internal/tui: keybinding config and named-key script input now accept short modifier aliases such as c-left, cA, m-b, a-right, optF, s-tab, and sEnter.
  • internal/tui: keybinding config and named-key script input now accept Shift-Tab terminfo aliases such as backtab, back-tab, and btab, mapping them to the existing focus-previous key surface.
  • internal/tui: scripted interaction keys entries now accept printable text chunks and whitespace-separated named key sequences such as ctrl-x ctrl-k.
  • internal/tui: scripted interaction key input now accepts press-style aliases such as press, keyPress, keypress, shortcutKey, presses, keyPresses, and shortcuts.
  • internal/tui: interaction script loading now flattens suite/case arrays such as cases, tests, testCases, scenarios, and fixtures, expanding nested steps, timeline, or scriptSteps arrays in order while still allowing top-level arrays to mix direct steps and case objects.
  • internal/tui: interaction script loading now also unwraps provider-style choices, outputs, candidates, and generations responses, recovering script JSON from nested message.content, content-block arrays, and content.parts[].text.
  • internal/tui: interaction script provider responses now strip fenced json code blocks before parsing, so model/SDK-generated scripts do not require manual fence removal.
  • internal/tui: interaction script provider fenced JSON extraction now accepts inline/glued fence forms where the language marker and script JSON appear on the same line, so model/SDK outputs without a newline still load scripted interactions.
  • internal/tui: scripted key and key-sequence action payloads now recursively unwrap JSON:API/GraphQL-style wrappers, preserving wrapped single keys and key sequence arrays from API-shaped interaction fixtures.
  • internal/tui: direct scripted key alias fields such as key, keyPress, and keyPresses now accept JSON:API/GraphQL-style wrapper objects without failing strong string/list decoding.
  • internal/tui: direct scripted string alias fields such as text, pasteText, setStatus, and snapshotName now accept JSON:API/GraphQL-style wrapper objects without failing strong scalar decoding.
  • internal/tui: direct scripted resize aliases such as resizeWidth/resizeHeight and screenWidth/screenHeight now recursively unwrap numeric JSON:API/GraphQL-style wrapper objects.
  • internal/tui: direct scripted focus aliases such as focus, focused, focusIn, focusOut, and blurred now recursively unwrap boolean JSON:API/GraphQL-style wrapper objects.
  • internal/tui: scripted focus/blur action discriminators now honor wrapped boolean payloads such as payload.focused:false, payload.blurred:false, data.focus:false, and non-strict string booleans for action:"focus", kind:"blur", operation:"focusState", and name:"setFocus".
  • internal/tui: direct scripted expectation bool aliases such as expectNoEvent, expectNoDialogResult(s), and expectFocused now recursively unwrap JSON:API/GraphQL-style wrapper objects.
  • internal/tui: direct scripted expectation count aliases such as expectEventCount, expectTotalEventCount, expectDialogResultCount, and expectTotalDialogResultCount now recursively unwrap numeric JSON:API/GraphQL-style wrapper objects.
  • internal/tui: direct scripted expectation string-list aliases such as expectStatusContains, expectStatusNotContains, expectSnapshotContains, and expectSnapshotNotContains now recursively unwrap JSON:API/GraphQL-style wrapper objects.
  • internal/tui: direct scripted expectation collection aliases such as expectEvents and expectDialogResults now recursively unwrap JSON:API/GraphQL-style wrapper objects.
  • internal/tui: direct scripted single expectation aliases such as expectEvent and expectDialogResult now recursively unwrap JSON:API/GraphQL-style wrapper objects.
  • internal/tui: terminal key parsing now accepts CSI-u/kitty keyboard protocol sequences for existing ctrl/alt editing keys, shift-enter, shift-tab, shift-backspace, and printable shift-only runes.
  • internal/tui: terminal CSI-u/kitty keyboard parsing now also accepts colon-suffixed alternate codepoint and modifier event-type fields such as CSI 97:65;5:1u.
  • internal/tui: terminal CSI-u/kitty keyboard parsing now also accepts base/unmodified sequences such as CSI 97u and CSI 13;1u, mapping printable runes plus Enter, Tab, Esc, and Backspace instead of treating ordinary extended-key reports as unknown.
  • internal/tui: terminal CSI parsing now emits report actions for DA/device attributes queries such as CSI c, CSI >c, and CSI =c, preserving the private marker and code through the terminal parser dispatcher.
  • internal/tui: terminal CSI parsing now accepts ECMA/xterm cursor alias final bytes CSI a, CSI e, and `CSI `` as cursor-forward, cursor-down, and cursor-column actions.
  • internal/tui: terminal CSI parsing now accepts ECMA HPB/VPB final bytes CSI Ps j / CSI Ps k as cursor-back and cursor-up actions.
  • internal/tui: terminal CSI parsing now accepts DEC private mode ?1046h/l alternate-screen switching, ?1047h/l alternate-screen buffer, and ?1048h/l save/restore cursor variants using distinct mode/cursor action surfaces.
  • internal/tui: terminal CSI parsing now emits report actions for DECREQTPARM terminal-parameters queries such as CSI x, preserving code and private marker fields.
  • internal/tui: terminal CSI parsing now preserves the complete parameter list from DECREPTPARM/terminal-parameter responses such as CSI 2;1;1;112;112;1;0x instead of dropping fields after the report code.
  • internal/tui: terminal CSI parsing now preserves the complete code list from multi-parameter DA/device-attributes responses such as CSI ?62;1;2;6c instead of dropping capability flags after the first code.
  • internal/tui: terminal CSI parsing now emits report actions for DECRQM mode requests such as CSI 4$p and CSI ?25$p, preserving mode code and private marker fields.
  • internal/tui: terminal CSI parsing now preserves complete DECRQM mode-request parameter lists such as CSI ?25;1000$p while keeping the existing first-code field.
  • internal/tui: terminal CSI parsing now emits report actions for xterm window manipulation/report queries such as CSI 14t and CSI 18t, preserving code/private marker fields and structured dimensions for CSI 4;height;width t and CSI 8;rows;cols t.
  • internal/tui: terminal CSI parsing now preserves complete xterm window report parameter lists such as CSI 3;x;y t, CSI 4;height;width t, and CSI 8;rows;cols t while keeping the existing structured size fields.
  • internal/tui: terminal CSI parsing now preserves complete DECRPM mode-status parameter lists such as CSI ?25;2$y while keeping the existing structured code/status fields.
  • internal/tui: terminal CSI parsing now emits cursor actions for TBC tab-clear sequences such as CSI g and CSI 3g, preserving the clear-current/all code.
  • internal/tui: terminal CSI parsing now emits edit actions for REP repeat-preceding-character sequences such as CSI b and CSI 4b, and the visible-text/snapshot plus ANSI message wrapping/trim paths expand the previous repeatable grapheme by the requested count.
  • internal/tui: terminal CSI parsing now emits reset actions for DECSTR soft reset CSI !p, and the terminal parser clears SGR/link state through the existing reset path.
  • internal/tui: terminal sequence dispatch now parses SS3 application cursor sequences such as ESC OA/OB/OC/OD as structured cursor move actions.
  • internal/tui: terminal sequence dispatch now also parses modified SS3 application cursor sequences such as ESC O 1;2A, ESC O 1;5B, and ESC O 1;16D as structured cursor move actions instead of unknown SS3 sequences.
  • internal/tui: terminal tokenizer now keeps SS3 parameter bytes buffered until a final byte, so modified SS3 cursor sequences such as ESC O 1;5D can cross chunk boundaries and still reach the dispatcher as one sequence token.
  • internal/tui: terminal grapheme width now keeps base+combining-mark clusters at the base glyph width while preserving wide treatment for emoji presentation, ZWJ, regional-indicator, and tag sequences.
  • internal/tui: terminal grapheme segmentation now keeps emoji tag sequences such as subdivision flags as one wide grapheme across full input and streaming chunks split after the black-flag base or tag characters.
  • internal/tui: terminal grapheme segmentation now keeps emoji modifier sequences such as 👋🏽 as one wide grapheme across full input and streaming chunks split after the modifier base.
  • internal/tui: terminal grapheme segmentation now keeps VS16 emoji ZWJ sequences such as ❤️‍🔥 as one wide grapheme across streaming chunks split after the emoji presentation base.
  • internal/tui: terminal grapheme segmentation now treats emoji keycap sequences such as 1️⃣ and 2⃣ as single wide graphemes, including streaming chunks split after the keycap base or variation selector.
  • internal/tui: terminal grapheme segmentation now applies Hangul L/V/T jamo joining, keeping decomposed syllables such as 한 as one wide grapheme across full input and streaming chunk boundaries.
  • internal/tui: terminal grapheme segmentation now keeps CRLF as a single zero-width line-break grapheme across full input and streaming chunks split between \r and \n, and wrap/trim/render width paths share the same line-break check.
  • internal/tui: terminal grapheme segmentation now uses Unicode mark categories for nonspacing/enclosing/spacing marks and handles Prepend characters, keeping clusters such as Devanagari का and Arabic prepend-mark plus base text together while treating a lone prepend mark as zero width.
  • internal/tui: terminal grapheme segmentation now keeps common Indic virama conjuncts such as Devanagari क्ष as one narrow grapheme across full input and streaming chunks split after the virama.
  • internal/tui: image hint parsing now accepts OSC ST terminators and base64 name= filenames while preserving prompt pasted-content metadata.
  • internal/session: prompt history writing now skips image pasted-content records like official history.ts, while the reader still accepts older image metadata entries.
  • internal/session: paste-cache now has a best-effort cutoff-mtime cleanup helper for old .txt paste files, matching official cleanupOldPastes behavior.
  • internal/session: buffered prompt-history writing now supports removing the latest pending entry before flush and skipping the latest flushed entry by timestamp in the same writer, matching the fast and slow paths of official removeLastFromHistory.
  • internal/session: image-cache now supports session-scoped path caching, base64 image writes, image-only bulk storage, stored-path lookup, cache clearing, and cleanup of non-current session cache directories.
  • internal/session/internal/contracts: prompt pasted-content conversion can now build Anthropic image source content blocks from image paste metadata, expand text paste refs, and append source-path meta messages for cached images.
  • internal/session/internal/tui: pasted image metadata now carries dimensions and sourcePath, accepts common source/dimension aliases, and renders official-style image metadata text with source path plus original/display dimensions and coordinate scale.
  • internal/tui: image hint parsing now reads iTerm2 OSC File width/height, original/display dimension aliases, and sourcePath/source_path/path, normalizing metadata key case plus _/- separators, then preserves those fields through prompt pasted image metadata.
  • internal/tui: PromptInput/REPL screen can enable a session-scoped image-cache so image hint paste caches the image path and writes the base64 image file while inserting the [Image #N] prompt reference.
  • internal/tui: image paste cache now writes generated cache paths back into PastedContent.SourcePath when no original source path exists, so prompt metadata/history restore paths do not depend only on global image-id cache lookup.
  • internal/tui: PromptInput paste now strips ANSI, normalizes carriage returns, expands tabs, and uses the official 800-character plus min(rows-10, 2) visible-line threshold to decide whether pasted text stays inline or becomes a pasted-content reference.
  • internal/session/internal/tui: orphan image pasted-content entries are now pruned after prompt edits and filtered again during prompt-message construction, so deleted image pills do not leak into Anthropic image blocks or image metadata.
  • internal/tui: image paste pills now follow the official lazy-space behavior for consecutive image pastes and image-then-text input without adding duplicate spaces before explicit whitespace/newlines.
  • internal/tui: REPL messages now preserve imagePasteIds, and prompt state advances NextPastedID from existing user-message image ids and pasted refs so resumed screens do not reuse paste IDs.
  • internal/tui: reverse-search now matches full history entries and restores text/image pasted-content metadata on selection, so the next submit still carries display text and image metadata.
  • internal/session: prompt-history pasted-content loading now accepts mimeType/mime_type/contentType, fileName/file_name/name, and filePath/file_path/path metadata aliases so restored image/text paste metadata matches the image hint/parser compatibility surface.
  • internal/session: prompt-history log entries now accept sessionID/session/sessionUuid/sessionUUID/session_uuid session id aliases so current-session-first history ordering survives field spelling differences.
  • internal/tui: REPL message restore can now rebuild prompt text and image pasted contents from user-message content blocks, imagePasteIds, and pasted-content metadata.
  • internal/tui: Ctrl-S prompt stash now preserves and restores prompt text, cursor position, and pasted-content metadata.
  • internal/tui: prompt submitted events now retain display text and pasted-content metadata, so downstream runtime code can build text/image content-block messages instead of receiving only the expanded prompt string.
  • internal/tui: keybinding JSON loading now accepts wrapper object maps, shortcuts/shortcutBindings, object action fields such as commandName/commandId, key fields such as accelerator/keystroke/hotKey/keyCombo/keyChord, string-array key sequences/chords, and null/false unbind entries.
  • internal/tui: keybinding JSON loading now also recursively unwraps direct key/action scalar fields, so key, keys, shortcut, action, command, and commandName can carry {value}, JSON:API/resource, or GraphQL node-style wrapper payloads while preserving wrapped false unbinds.
  • internal/tui: keybinding JSON loading now recurses through outer wrappers such as data, payload, settings, config, keyboard, and keymap, so nested official or third-party preference exports can expose bindings/shortcuts without manual flattening.
  • internal/tui: keybinding JSON loading now also recurses through JSON:API/resource-style resource, attributes, properties, and attrs wrappers so API/preference envelopes can expose keybindings or keymap without manual flattening.
  • internal/tui: keybinding JSON loading now accepts API/GraphQL collection arrays under data, payload, body, result, response, resources, included, collection, list, children, values, nodes, and items, with resource-style binding items unwrapped before parsing.
  • internal/tui: keybinding JSON loading now accepts GraphQL connection-style edges binding lists, including edges[].node and edge.node item wrappers plus nested viewer/node/*Connection containers.
  • internal/tui: keybinding JSON loading now accepts collection aliases such as keymap, keymaps, keyboardShortcuts, hotkeys, userKeybindings, and customKeybindings, including both direct object maps and nested bindings wrappers.
  • internal/tui: keybinding JSON loading now also unwraps provider-style choices, outputs, candidates, and generations responses, recovering binding arrays or maps from nested message.content, content-block arrays, and content.parts[].text.
  • internal/tui: keybinding provider responses now strip fenced json code blocks before parsing, so model/SDK-generated keybinding configs do not require manual fence removal.
  • internal/tui: keybinding provider fenced JSON extraction now accepts inline/glued fence forms where the language marker and binding JSON appear on the same line, so model/SDK outputs without a newline still load keybinding configs.
  • internal/tui: interaction script keybinding mutation fields now reuse the same collection aliases, object-map parsing, and JSON:API/resource wrapper handling, so scripted steps can set keymap, keyboardShortcuts, hotkeys, keyboard, preferences, or keybindingConfig directly.
  • internal/tui: configurable keybindings and interaction scripts now recognize raw, named, compact, and CSI-u Ctrl-Q, Ctrl-V, and Ctrl-Z inputs, so user keymaps can bind those standard terminal control keys without falling through to unknown-key handling.
  • internal/tui: mouse parsing now accepts legacy X10/normal tracking ESC[M... press/release/wheel sequences in addition to SGR mouse events.
  • internal/tui: mouse parsing now accepts urxvt/xterm 1015 numeric mouse CSI button;x;yM sequences and normalizes button codes to the existing SGR/X10 mouse surface.
  • internal/tui: SGR mouse parsing now rejects negative buttons and zero/negative coordinates, matching the existing URXVT/X10 coordinate guard and preventing invalid terminal mouse packets from producing click events.
  • internal/tui: interaction scripts now accept structured mouse/mouse_event steps with expanded button aliases such as buttonMask/btn/code, coordinate aliases such as mouseX/clientX/screenX/pageX/offsetX/viewportX and Y/row/line variants, release aliases such as mouseUp/isRelease/mouseRelease/releaseEvent, and dispatch them through the normal screen event path.
  • internal/tui: interaction script steps now accept resize aliases such as resize/terminalSize object or [width,height] array forms, focus/blur aliases such as focus/focused/blur/focusIn/focusOut, and snapshot name aliases such as snapshot/snapshotId/snapshotLabel.
  • internal/tui: runtime-aware interaction scripts now accept mutation aliases such as permission/permissionRequest, task/taskStatus, removeTask/deleteTask, cancelPermission, cancelTasks/cancelReason, and openTasks/showTasks.
  • internal/tui: interaction script JSON now accepts string keys plus input/input_text/keys_text/raw_key/paste_text aliases for text entry, raw key sequences, and pasted text.
  • internal/tui: interaction script contains assertions now accept a single string as well as string arrays for status, snapshot, viewport, and pasted-content checks, including camelCase viewport aliases.
  • internal/tui: interaction script keybindings, expectEvents, and expectDialogResults fields now accept a single object as well as object arrays.
  • internal/tui: prompt pasted-content expectations now accept a single pastedContents object as well as an array.
  • internal/tui: interaction script task expectations now accept a single contains object as well as an array for expected task matches.
  • internal/tui: interaction script message steps now accept chat/transcript-style type/speaker role aliases and content/body/message text aliases.
  • internal/tui: interaction script message injection now accepts messages, append_messages/appendMessages, and transcript_messages/transcriptMessages object or object-array aliases, plus pasted-content attachment aliases such as pastedContent, attachments, single imagePasteId, and kind/value/data pasted-content fields.
  • internal/tui: interaction script image steps and iTerm2 image hints now accept filename aliases such as fileName/file_name/name, media-type aliases such as mimeType/mime_type/contentType, source path/URL aliases, and content aliases such as data/base64.
  • internal/tui: interaction script direct dialog steps now accept ID, kind, title/body, action-list, and focused-index aliases aligned with dialog expectations.
  • internal/tui: interaction script permission request steps now accept request/permission/tool-use ID aliases, path aliases, description aliases, action-list aliases, and single-string actions.
  • internal/tui: interaction script prompt expectations now accept text, expanded text, cursor, and empty aliases such as value/input/content/message, expandedText/fullText, cursorIndex/cursorPosition, and isEmpty/blank.
  • internal/tui: interaction script Vim expectations now accept enabled, mode, register, and linewise aliases such as vimEnabled/isEnabled, vimMode/modeName/currentMode, vimRegister/registerValue/yankRegister, and registerLinewise/linewise.
  • internal/tui: interaction script task expectations now accept count and state-count aliases such as taskCount/total/size/length and statusCounts/countsByState.
  • internal/tui: interaction script screen and viewport expectations now accept size and scroll aliases such as columns/rows, screenWidth/screenHeight, scrollOffset/viewportOffset, and visibleRows/lineCount.
  • internal/tui: interaction script reverse-search expectations now accept state, query, cursor, current result, result-count, and no-match aliases such as isActive/visible/open, search/term/pattern, currentResult, matchCount, and noMatches.
  • internal/tui: interaction script pasted-content expectations now accept ID, kind, content, media-type, filename, and contains aliases such as pastedId/pastedContentId, kind/pastedType, value/data/base64, contentType/mimeType, fileName/name, and contains.
  • internal/tui: interaction script dialog expectations now support body contains/not-contains, exact actions, action contains/not-contains, action count, and focused action assertions, with runtime-aware scripts preserving dialog focused action across steps.
  • internal/tui: interaction script dialog expectations now accept active, ID, kind, title, and body aliases such as isActive/visible, dialogId/dialogID, dialogKind, heading/header, and content/text/message.
  • internal/tui: interaction script event and dialog-result expectations now accept aliases such as eventType/event/name, payload/text/message, dialogId/dialogID/dialogKind, actionValue/resultStatus, and found/stale aliases.
  • internal/tui: interaction script loading now accepts scriptSteps/script_steps, interactionSteps/interaction_steps, and nested scenario/test/case/fixture/interaction wrapper objects.
  • internal/tui: interaction script JSONL loading now allows 50MiB records so large paste/image/snapshot fixture lines do not hit scanner token limits.
  • internal/tui: snapshot corpus comparison now accepts .ansi-only baselines by stripping ANSI text on load, and strict unexpected-baseline checks include both .txt and .ansi.
  • internal/contracts/internal/session: content block decoding now accepts text aliases such as body/message/value/output/contentText/content_text and string content for text/thinking blocks, so transcript resume preserves these nested block variants.
  • internal/tui: interaction script steps now accept action/type/kind/name/operation discriminator aliases for common actions such as key press, key sequences, text input, paste, status updates, resize, mouse/image, and focus/blur.
  • internal/tui: interaction script action discriminators now accept compact/camel fixture names such as typeText, inputText, insertText, keyPress, pressKey, keySequence, pasteText, pastedText, clipboardText, setStatus, statusLine, terminalSize, and screenSize.
  • internal/tui: string action payloads for type, paste, status, and snapshot capture now recursively unwrap JSON:API/GraphQL-style wrappers, preserving wrapped prompt text, paste text, status text, and snapshot names from API-shaped interaction fixtures.
  • internal/tui: resize, terminal-size, and screen-size action payloads now recursively unwrap JSON:API/GraphQL-style wrappers such as resource.attributes and edge.node.attrs, preserving columns/rows from API-shaped interaction fixtures.
  • internal/tui: interaction script action discriminators now also accept compact event/media fixture names such as focusIn, focusOut, mouseEvent, pasteImage, and imagePaste.
  • internal/tui: interaction script direct prompt expectation fields now recursively unwrap JSON:API/GraphQL-style resource.attributes and edge.node.attrs payloads for expectPrompt/expect_prompt, preserving prompt text, cursor, empty, pasted-content count, and next pasted ID assertions.
  • internal/tui: interaction script direct Vim expectation fields now recursively unwrap JSON:API/GraphQL-style resource.attributes and edge.node.attrs payloads for expectVim/expect_vim, preserving enabled, mode, register, and register-linewise assertions.
  • internal/tui: interaction script direct screen and viewport expectation fields now recursively unwrap JSON:API/GraphQL-style resource.attributes and edge.node.attrs payloads for expectScreen/expect_screen and expectViewport/expect_viewport, preserving columns/rows, scroll offset, visible line count, and visible contains/not-contains assertions.
  • internal/tui: interaction script direct task and reverse-search expectation fields now recursively unwrap JSON:API/GraphQL-style resource.attributes and edge.node.attrs payloads for expectTasks/expect_tasks and expectReverseSearch/expect_reverse_search, preserving task count/stateCounts/contains, reverse active/query/cursor/current/result-count assertions, wrapped active:false, and wrapped taskCount:0.
  • internal/tui: interaction script direct dialog expectation fields now recursively unwrap JSON:API/GraphQL-style resource.attributes and edge.node.attrs payloads for expectDialog/expect_dialog, preserving active, ID/kind, title/body, body/action contains, action count, focused index assertions, and wrapped active:false.
  • internal/tui: interaction script direct single event/dialog-result expectation fields now use raw payload parsing, so singular expectEvent and expectDialogResult fields can accept single-element arrays and choose the first expectation without failing base step unmarshal.
  • internal/tui: mouse and image action payloads now recursively unwrap JSON:API/GraphQL-style wrappers, preserving wrapped mouse button/coordinate fields and image filename/media/content fields for scripted dialog clicks and paste-image prompts.
  • internal/tui: interaction script action discriminators can now drive runtime/dialog mutations such as requestPermission, taskStatus, showTasks, cancelTasks, removeTask, and showDialog, using value/payload/data/body payloads for objects, IDs, and cancel reasons.
  • internal/tui: interaction script direct runtime mutation fields now use raw payload parsing, so singular requestPermission/request_permission and upsertTask/upsert_task fields can accept single-element arrays and choose the first payload without failing base step unmarshal.
  • internal/tui: interaction script direct mouse fields now use raw payload parsing, so singular mouse/mouse_event/mouseEvent fields can accept single-element arrays and JSON:API/GraphQL-style wrappers such as resource.attributes or edge.node.attrs without failing base step unmarshal.
  • internal/tui: interaction script direct message-list fields now use raw payload parsing, so messages/appendMessages/transcriptMessages can unwrap API/GraphQL envelopes such as resource.attributes, data[], and edge.node.attrs while preserving message metadata such as image paste IDs.
  • internal/tui: interaction script direct single-message fields now reuse the raw message parser, so message/Message can unwrap resource.attributes or edge.node.attrs, and array-shaped single-message payloads fall back to appending multiple messages instead of producing an empty decoded message.
  • internal/tui: interaction script direct dialog fields now use raw payload parsing, so dialog/Dialog and showDialog action payloads can unwrap resource.attributes, edge.node.attrs, and single-element arrays instead of decoding wrapper-only dialogs as empty popups.
  • internal/tui: interaction script direct image fields now use raw payload parsing, so image/Image can reuse pasteImage action wrapper parsing for resource.attributes, edge.node.attrs, and single-element arrays while preserving filename/media/content/source-path metadata before prompt image insertion.
  • internal/tui: interaction script direct keybinding mutation fields now use raw-only parsing, so keybindings/key_bindings/keyBindings/keybindingSpecs/Keybindings avoid early []BindingSpec decoding and consistently reuse object-map, resource-wrapper, and edge/node collection parsing from the keybinding loader.
  • internal/tui: Vim macro recording now treats uppercase macro registers such as qA as append-to-lowercase register operations, matching the existing named-register append behavior while keeping @a/@@ playback on the canonical lowercase macro.
  • internal/tui: key parsing and configurable keybindings now expose ctrl+space from raw NUL and Kitty/CSI-u 0u, 32;5u, 64;5u, and 50;5u forms, with ctrl-space/ctrl-@/ctrl-2 and compact cSpace/c@/c2 aliases available for user keymaps and scripts.
  • internal/tui: key parsing and configurable keybindings now expose Ctrl-backslash, Ctrl-], Ctrl-^/Ctrl-6, and Ctrl-_/Ctrl-/ from raw terminal control bytes and Kitty/CSI-u forms, with symbol, named, and compact aliases available for user keymaps and scripts.
  • internal/tui: key parsing and configurable keybindings now expose F1-F12 from common SS3, modified SS3, legacy Linux-console, tilde CSI, and modified CSI function-key sequences, plus xterm F13-F20 tilde CSI sequences, with f1, function-key-1, fn1, and extended f13/function-key-20 style aliases available for user keymaps and scripts; navigation input also accepts explicit-default CSI 1 A/B/C/D/H/F forms while leaving counted cursor controls such as CSI 2A as unknown.
  • internal/tui: terminal key parsing now accepts modified SS3 application-cursor navigation sequences such as ESC O 1;2A, ESC O 1;5D, and ESC O 1;16C, mapping shift to the plain navigation surface and alt/meta/ctrl combinations to the existing word-motion key surfaces.
  • internal/tui: terminal ESC parsing now recognizes charset selection sequences such as ESC ( B, ESC ) 0, ESC * B, ESC / A, and ESC % G as structured charset actions and consumes them in visible-text parsing instead of surfacing them as unknown terminal output.
  • internal/tui: terminal ESC parsing now also recognizes ISO-2022 charset shift controls such as ESC N, ESC n, ESC o, ESC |, ESC }, and ESC ~ as structured charset-shift actions and consumes them in visible-text parsing instead of surfacing them as unknown terminal output.
  • internal/contracts/internal/session: image content blocks now normalize source aliases such as mediaType/mimeType/contentType and base64/payload, including top-level image block fields, into canonical ImageSource values during transcript resume.
  • internal/tui: interaction script single-step JSON now unwraps step/scriptStep/interactionStep/record/entry/item/event objects in arrays, JSONL records, and wrapper-object step lists.
  • internal/tui: interaction script single-step JSON now also unwraps JSON:API/resource-style resource/node/attributes/properties/attrs step items, so API fixture arrays and JSONL records can keep step resource envelopes.
  • internal/tui: interaction script top-level wrappers now accept record-array aliases such as records/recordedSteps/events/entries/items/actions/timeline.
  • internal/tui: interaction script loading now recurses through outer API/fixture wrappers such as data/payload/body/result/response/recording/session/run.
  • internal/tui: interaction script loading now also recurses through JSON:API/resource-style resource/attributes/properties wrappers, so API envelopes can expose steps/records/timeline without manual flattening.
  • internal/tui: interaction script loading now accepts API/GraphQL collection arrays under data, payload, body, result, response, resources, and nodes, while preserving single-step data payload fallback.
  • internal/tui: interaction script loading now accepts GraphQL connection-style edges step lists and JSON:API/HAL collection-style included, collection, list, children, and values step lists, including edges[].node, edge.node, and resource item wrappers plus nested viewer/node/*Connection containers.
  • internal/contracts/internal/session: remote history SDKEvent message extraction now recurses through nested payload wrappers such as record/entry/item/event/result/response/output.
  • internal/session: remote-history event arrays now unwrap element-level wrappers such as event/record/entry/item/resource/value and wrapper-only data/payload/body, using element cursors as event ID fallback outside GraphQL edges.
  • internal/session: remote-history event arrays now accept JSON:API/resource-style elements with event payloads inside attributes or properties, preserving the outer resource id as the SDK event ID fallback.
  • internal/session: remote-history GraphQL edge lists now reuse the same wrapper-aware event decoder as ordinary event arrays, so edges[].node.resource.attributes and edges[].node.value.properties event payloads preserve IDs, session IDs, and status/message fields instead of becoming empty edge events.
  • internal/session: remote-history response parsing now recurses through page-level JSON:API/resource attributes/properties wrappers, accepts list/object/objects as event-list aliases, and treats a single data.attributes resource payload as one SDK event.
  • internal/session: remote-history response parsing now accepts JSON:API included collections, filters out non-event resources, and recursively unwraps resource/attributes/properties plus GraphQL-style edge/node/attrs event payloads while preserving resource or edge IDs as fallbacks.
  • internal/contracts/internal/session: content block type decoding now normalizes camel/kebab/compact aliases such as toolUse, tool-result, cacheEdits, inputImage, and chain-of-thought.
  • internal/session: image history dimensions now default display size to original size when only width/height or original dimensions are present, preserving source metadata for single-size image fixtures.
  • internal/session: pasted-content history type decoding now normalizes aliases such as inputImage/pasted-image/input_text/pasted-text to canonical image/text for runtime and stored history.
  • internal/session/internal/tui: pasted-content ID decoding now accepts aliases such as pastedContentId/attachmentID/contentID/imageID and numeric strings for runtime/stored history and script attachments.
  • internal/session: prompt-history HistoryEntry/LogEntry and pastedContents/pasted_contents items now accept wrappers such as entry/record/item/payload; pasted contents also accept map, list, and single-object shapes for runtime and stored history, rebuilding maps from content IDs and aliases.
  • internal/session: prompt-history HistoryEntry/LogEntry and pasted-content items now also recursively unwrap GraphQL/JSON:API-style edge/node/resource/attributes/properties/attrs wrappers, while preserving outer log metadata fallbacks such as project, session, and timestamp.
  • internal/session/internal/tui: pasted-content reference parsing now accepts case differences and placeholders such as pasted image/input-image/input_text, sharing that recognition across text expansion, image filtering, and next pasted ID seeding.
  • internal/session: prompt-history LogEntry loading now accepts project aliases such as projectPath/cwd/workingDirectory/workspacePath and timestamp aliases such as createdAt/unixTimestamp, including RFC3339 timestamp normalization to Unix milliseconds.
  • internal/session: prompt-history display text loading now accepts aliases such as prompt/text/input/content/value for runtime and stored history.
  • internal/session: prompt-history pasted-content containers now accept aliases such as pastedContent/pasted_content, pasteContents/paste_contents, pastes, and attachments/attachment, matching interaction script fixture shapes for runtime and stored history.
  • internal/session: prompt-history pasted image loading now accepts content-block-style source/imageSource objects, nested JSON:API/GraphQL-style source wrappers, data URL aliases, and source URL/URI/cache-path aliases; stored image entries with inline source data or a current-session image-cache file now restore base64 content into prompt image blocks instead of keeping only metadata, including same-ID cache fallback, media-type inference when history metadata omits the original MIME type, symlink escape guards before reading cached image bytes, and restored path re-indexing for later image metadata/source lookup.
  • internal/compact: microcompact disk cache loading now accepts broader summary-like direct and provider aliases including body, markdown, description/details, finalSummary, summaryContent, plainText/displayText, answerText, refusal, resultText, completionText, responseText, and messageText; provider summary recovery also follows wrapper-only value/payload/data chains without failing on non-summary metadata, preserving visible summaries through nested cache entries, JSON:API/resource envelopes, and provider-style response wrappers.
  • internal/compact: microcompact provider summary and wrapper field lookup now uses the same case/snake/kebab normalization as cache fields, so provider summary arrays can recover aliases such as output-text and message-text.
  • internal/compact: microcompact provider and cache summary extraction now unwraps inline fenced JSON payloads where the fence language and JSON object are on the same line, including glued json{...} fences, so SDK/model outputs no longer preserve the whole code fence as visible summary text.
  • internal/compact: microcompact count field loading now accepts whole-number JSON numbers and whole-number numeric strings, while fractional count values still fail validation.
  • internal/compact: microcompact string-like cache fields such as digest/cache key and version now accept JSON numbers by preserving their original numeric text as the stored string value.
  • internal/tui: terminal tokenizer, sequence dispatcher, ESC parser, and visible-text stripping now accept C1 IND/NEL/HTS/RI (0x84/0x85/0x88/0x8d) single-byte controls, mapping them to the existing ESC D/ESC E/ESC H/ESC M cursor/tab-set semantics.

Still missing for full M6/M7 parity:

  • M6: full official microcompact/cached microcompact parity, official session memory compaction/recall policy beyond current rollup/archive merge, complete memory recall agent strategy, complete sidechain/subagent runtime beyond current storage/metadata/resume context bridge, richer large transcript indexed loading beyond current offset/byte-budget windows, parent chains, and tails, remaining remote-history edge cases, and remaining niche metadata entry semantics.
  • M7: custom Ink-compatible layout/reconciler parity, complete configurable keybinding/vim systems beyond current normal/operator/visual prompt editing and repeat find/till coverage, full permission/task runtime parity beyond current stale/cancel/queue/dialog-refresh/lifecycle guards, full alternate screen lifecycle management beyond current idempotent reset and terminal mode paths, complete mouse behavior beyond current wheel/action-click/viewport-select/modifier/drag paths, full focus/resize parity beyond current events, full paste/image cache/history integration beyond current text refs and image metadata/cache-path refs, official ANSI snapshot corpus, and official scripted interaction parity tests.