[BUG] VS Code: prompt history drops slash-command arguments
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
Bug Description
In the VS Code extension chat, a prompt made of a slash command / skill plus arguments
is recalled from history without its arguments. Stopping the next run then restores
the old arguments without the command.
Evidence
Step 1 reached the skill with ARGUMENTS: some args; the prompt recalled in step 2
reached it with no arguments. Sending works; the history entry and the interrupt
restore are wrong. No cancel is needed for step 2.
Environment
- VS Code: 1.135.0
- Claude Code extension: 2.1.294 (darwin-arm64)
- OS: macOS 14.8.2
- Terminal CLI: not tested
- Reproduces with no UserPromptSubmit hooks active (the only plugin with one was disabled, window reloaded)
- The session transcript stores the original prompt with its
<command-args>, so the
arguments are lost in the input box's ↑ history, not in the saved session
Related: #54610
What Should Happen?
Expected behavior
- ↑ recalls a prompt exactly as it was sent, command and arguments together
(/my-skill some args). Sending it again runs the skill with the same arguments.
- After Stop, the input box holds the prompt that was interrupted, exactly as sent
(/my-skill in step 3). It never holds text from an earlier prompt.
- Slash-command prompts behave like plain-text prompts, which are already recalled and
restored in full.
Error Messages/Logs
Steps to Reproduce
- Send
/my-skill some args(reproduced with a project skill). Let the run finish. - Press ↑ in the empty input.
- Expected:
/my-skill some args - Actual:
/my-skill(arguments gone). Sending it runs the skill with no arguments.
- Send that recalled
/my-skilland click Stop while it runs.
- Expected: the input box is restored with
/my-skill(the interrupted prompt) - Actual: the input box is restored with
some args: the arguments from step 1,
without the command.
Claude Model
Opus
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.1.197 (Claude Code)
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
Terminal.app (macOS)
Additional Information
Where it likely breaks
Read from the shipped 2.1.294 webview/index.js. Minified names are from that build;
search for the quoted property names instead.
- ↑ history is rebuilt from session messages, not from what was typed.
The input hook that returns { cycleMessage, resetHistory } builds its list from
messages (+ heldPrompts): non-synthetic user messages with no parent tool use, each
text block run through the user-message content parser and joined.
(2.1.294: nx() / qD0().)
- The tag parser is fine. The function that turns
<command-name>/<command-args>
into { name, args, line } (2.1.294: ev1() via rk0()) returns /my-skill some args
for the line stored in the session transcript. Checked by running the bundle's own
function on the stored entry.
- The local message is overwritten when the CLI echoes the prompt back.
send()
pushes a local user message with the typed text and, for slash commands, adds its uuid
to slashSendUuids. When the echo arrives (isReplay: true, same uuid), the merge
function (2.1.294: gv1()) replaces that message's last text block with only the
last text block of the echoed content (content.findLast(b => b.type === "text")).
If the echo for a slash command spreads the tags over several text blocks, or has no
<command-args>, the arguments are lost from the in-memory message, and ↑ shows
/my-skill. Not confirmed: the echoed stream-json message was not captured.
- Stop restore: not located. It returns the previous send's arguments without the
command, which suggests it reads the same command/argument split from a stale source.
Suggested fix
- When
send()creates the local message, store the exact submitted text on it (e.g. a
submittedText field). Have the replay merge keep that field, and have the ↑ history
builder and the Stop restore use it first. History then no longer depends on the
format of the echo.
- Minimum fix: in the replay merge, keep the local text for uuids in
slashSendUuids, or
parse the whole echoed content (all text blocks joined) instead of only the last block.
- Regression test: send
/skill a b, deliver anisReplayecho in the slash-command tag
format, and assert that ↑ returns /skill a b. Then interrupt and assert the input is
restored to /skill a b.