* fix(agent-core): mark auto-approved plan exits as not user-reviewed
In auto permission mode ExitPlanMode is approved without user
involvement, but its result read "## Approved Plan:" exactly like a
genuine user approval and the transcript showed a green "Approved"
chip. The model treated that as a signal to start executing, even
when the user had asked it to stop after planning.
- Emit an "auto-approved, not user-reviewed" result with a note that
execution follows the user's original instructions (v1 + v2).
- Extend the auto-mode reminder: plan approvals are automatic and are
not a user signal to proceed (v1 + v2).
- Render an "Auto-approved" warning-toned chip in the TUI, keeping
backward compatibility with the old result marker.
- Document the Auto mode plan-exit behavior in interaction guides.
* fix(agent-core): only mark plan exits as auto-approved in auto permission mode
Address review feedback on the auto-approved plan exit change:
- Branch the direct-execution output on the permission mode in both
engines: only auto mode yields the "auto-approved, not
user-reviewed" result and telemetry outcome. In manual / yolo modes
the direct path means a configured or session allow/ask rule let the
call through — an explicit user decision that keeps the user-approved
output, the Approved transcript chip, and the approved outcome.
- Move the v2 rationale out of the method body into the file header,
per the agent-core-v2 comment convention.
- Drop the absolute "only Auto mode" wording from the interaction
guides (en/zh).
* feat(tui): include shell commands in input history
Shell commands entered through the `!` prompt are now saved to input history. Recalling one restores bash mode, and in bash mode Up only cycles through previous shell commands while a normal prompt browses all history.
* docs(interaction): document shell command recall in input history
Note that shell commands are now saved to input history and can be recalled in Shell mode, in both the English and Chinese interaction guides.
* feat(pi-tui): add setHistoryFilter and onRecall to editor history
Add two first-class hooks to the editor's history navigation: setHistoryFilter to limit which entries Up/Down visit, and onRecall to decorate a recalled entry before it is shown. Draft restore, direction-aware cursor placement, and undo behavior are unchanged.
* refactor(tui): use pi-tui history filter for shell command recall
Replace the CustomEditor navigateHistory shadow with pi-tui's setHistoryFilter + onRecall hooks, wired in the editor-keyboard controller. This keeps pi-tui's draft-restore and direction-aware cursor behavior intact (the shadow dropped both) and moves the shell/prompt filtering and mode-restore logic into the business layer.
* feat(pi-tui): save and restore host state with the history draft
Add onHistoryDraftSave/onHistoryDraftRestore hooks so hosts can stash their own state when entering history browsing and restore it when the user navigates back to the draft. The saved host state is discarded when browsing ends any other way (typing, submit), mirroring the editor draft lifecycle.
* fix(tui): restore input mode when returning to the history draft
Wire pi-tui's history draft save/restore hooks to the editor input mode. Without this, recalling a shell entry and then pressing Down back to an empty draft left the editor in bash mode, so the next typed message was submitted as a shell command.
* fix(pi-tui): capture host draft state before running the history filter
Fire onHistoryDraftSave before the history filter runs when entering browse, so the host's filter can read the browse-entry mode rather than a mode that changes as entries are recalled. The captured state is still only committed once a matching entry is found.
* fix(tui): lock history filter to the browse-entry mode
Lock the history filter to the input mode captured when entering browse. Previously the filter read inputMode live, so after recalling a shell entry (which flips to bash mode) a second Up would only show shell commands.
* feat: add shell mode (`!`) to the CLI
Add shell mode, letting users run shell commands directly from the prompt
with `!`. Output streams live into the transcript, supports backgrounding
(ctrl+b), cancellation (Esc / Ctrl+C), input queuing while running, and
enters the conversation context with resume support.
* feat(kimi-code): show shell mode label on editor border and add tip
Render a "! shell mode" label on the top-left of the editor border while the editor is in `!` bash mode, so the active mode is visible at a glance. Also add a rotating toolbar tip (`! to run a shell command`) to surface the feature.
* feat(kimi-code): refine shell mode queue, history, and display
- Keep `!` commands out of input history so they never resurface as bare text stripped of their `!`.
- Make `!` commands non-steerable: Ctrl-S skips them (they stay queued to run after the current task) and the steer hint is only shown when something is actually steerable.
- Render queued `!` commands with a `$` prompt and the shell-mode hue so they read as commands, not as text to send to the model.
- Echo executed shell commands with a `$` prompt instead of `!`.
* fix(kimi-code): sanitize shell output and harden rendering
Captured shell command output can contain terminal control sequences (colours, cursor moves, alternate-screen switches, OSC hyperlinks, carriage-return spinners, bells). pi-tui's Text passes strings straight to the terminal, so any unhandled sequence was executed by the terminal and fought with pi-tui's own cursor control, producing the blank-screen-plus-leftover-characters mess after running commands like pnpm dev or a nested TUI.
- Sanitize CSI (incl. private modes), OSC, single-char ESC and C0 control chars (keeping newline and tab) in both the finished/resume view (previously unsanitized) and the running tail.
- Make the sanitize, format, and ShellRunComponent render paths never-throw, and cap the live running buffer, so a misbehaving command cannot crash the TUI.
- Dispose transcript children on clear so ShellRunComponent's timer is released on /clear or session switch.
* fix(kimi-code): render shell command echo with $ instead of sparkles
The shell command echo is a 'user' transcript entry, so UserMessageComponent prefixed it with the USER_MESSAGE_BULLET (sparkles), producing 'sparkles $ command'.
Add an optional bullet override to UserMessageComponent / TranscriptEntry and set it to an empty string for the shell echo (both live and resume), so the '$ command' content sits at the leading column where the sparkles marker used to be. Normal user messages keep the sparkles bullet.
* fix(kimi-code): enter shell mode when pasting a !-prefixed command
The bash-mode trigger only handled the single ! keystroke, so a pasted !cmd was inserted as literal text in prompt mode and submitted as a normal message.
After pi-tui inserts pasted content, detect an empty-prompt buffer that now starts with !, switch to bash mode, and strip the leading ! so the buffer holds only the command, matching the typed ! path.
* fix(kimi-code): restore shell mode when recalling a queued command
recallLastQueued() dropped the queued item's mode, and the Up-arrow recall only restored the text. A queued ! command (queued while another command runs, which resets the editor to prompt mode) therefore came back as a normal prompt and was submitted as a message instead of a shell command.
Return the full QueuedMessage from recallLastQueued() and restore editor.inputMode (plus the onInputModeChange sync) from the recalled item's mode.
* feat(kimi-code): use violet as the shell mode color
Replace the claude-code-style magenta/rose shellMode token with a violet that is distinct from plan-mode blue, the user role amber, success green, error red, and the teal accent.
Custom themes that omit the token fall back to this new default via the base+overrides merge, so existing custom themes keep working unchanged.
* chore: refine the shell mode changeset
* docs: document shell mode
Add a Shell mode section to the interaction guide and list the ! and Ctrl+B shortcuts in the keyboard reference, in both English and Chinese.
* test(protocol): include shell events in volatile classification check
shell.output and shell.started were added as volatile event types for shell mode; update the snapshot test's volatile-type list and count accordingly.
* fix(agent-core): surface shell command failure reason with no output
When a ! shell command fails without producing stdout/stderr (non-zero exit with no output, timeout, spawn failure), the failure reason lived only in the tool result's output and the TUI showed '(no output)'. Fold it into stderr so the live view and replay show what went wrong.
* fix(kimi-code): decode CSI-u ! to enter shell mode
In terminals with the Kitty keyboard protocol (VSCode integrated terminal, Kitty), pressing ! arrives as a CSI-u sequence, so the raw normalized === '!' comparison never matched and shell mode could not be entered by typing !. Decode with printableChar before comparing, matching every other printable-key check in the TUI.
* fix(kimi-code): do not steer while a shell command is running
Ctrl-S steers queued input into the running turn, but a shell command is not an agent turn, so steering during streamingPhase === 'shell' would launch a turn before the command output is recorded. Keep Ctrl-S a no-op during shell runs; queued messages stay queued.
* fix(agent-core): escape bash tag delimiters in shell output
Shell command output is arbitrary text; if it contains a bash tag delimiter such as </bash-stdout>, the recorded pseudo-XML wrapper breaks and replay extracts the wrong slice. Escape the content when wrapping it in agent-core and unescape when extracting during replay, so output survives round-trip intact.
* docs: document the shellMode theme token
The shellMode color token was added to the palette but not propagated to its mirrors. Add it to the custom-theme docs token table, the theme JSON schema, and the custom-theme skill token list.
* feat(agent-core): reset background task deadline on detach
Add a resettable deadline timer to BackgroundManager and let tasks register a detach timeout; when a foreground task is moved to the background, its deadline resets to the background default counted from the detach moment.
Wire this into shell mode so ! commands run with a 3-minute foreground timeout and get 10 minutes once detached to the background, instead of staying bounded by the original 60-second foreground deadline.
* feat(agent-core): lower shell mode foreground timeout to 2 minutes
* feat(skill): qualify sub-skill names with parent prefix
- qualify sub-skill names with parent prefix and set isSubSkill metadata\n- hide sub-skills from the model skill listing
- expose sub-skills as dotted slash commands in TUI
- update slash command docs for English and Chinese
- align built-in sub-skill local names with their directories