Skip to content

Commit ad507f6

Browse files
mjacobsclaude
authored andcommitted
fix(parser): carry promptSource through queued-command attachments
extractQueuedCommand dropped the top-level promptSource on type=attachment queued_command entries, so queued prompts stored an empty messages.prompt_source while standard user turns captured it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 80eb7a0 commit ad507f6

2 files changed

Lines changed: 25 additions & 4 deletions

File tree

internal/parser/claude.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,9 @@ type dagEntry struct {
5353
// of band and splice them into the message stream by timestamp
5454
// after DAG processing completes.
5555
type claudeQueuedCommand struct {
56-
prompt string
57-
timestamp time.Time
56+
prompt string
57+
promptSource string
58+
timestamp time.Time
5859
}
5960

6061
// claudeParseWithExclusions parses a Claude Code JSONL session file
@@ -1458,8 +1459,9 @@ func extractQueuedCommand(line string) (claudeQueuedCommand, bool) {
14581459
return claudeQueuedCommand{}, false
14591460
}
14601461
return claudeQueuedCommand{
1461-
prompt: prompt,
1462-
timestamp: extractTimestamp(line),
1462+
prompt: prompt,
1463+
promptSource: gjson.Get(line, "promptSource").Str,
1464+
timestamp: extractTimestamp(line),
14631465
}, true
14641466
}
14651467

@@ -1595,6 +1597,7 @@ func queuedCommandMessage(
15951597
ContentLength: len(q.prompt),
15961598
SourceType: "system",
15971599
SourceSubtype: subtype,
1600+
PromptSource: q.promptSource,
15981601
}
15991602
}
16001603
return ParsedMessage{
@@ -1604,6 +1607,7 @@ func queuedCommandMessage(
16041607
ContentLength: len(q.prompt),
16051608
SourceType: "user",
16061609
SourceSubtype: "queued_command",
1610+
PromptSource: q.promptSource,
16071611
}
16081612
}
16091613

internal/parser/claude_parser_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,23 @@ func TestParseClaudeSession_SkippedMessages(t *testing.T) {
386386
}
387387

388388
func TestParseClaudeSession_QueuedCommand(t *testing.T) {
389+
t.Run("carries top-level promptSource when present", func(t *testing.T) {
390+
queued := `{"type":"attachment","timestamp":"` + tsZeroS2 + `",` +
391+
`"promptSource":"queued","attachment":{"type":"queued_command",` +
392+
`"commandMode":"prompt","prompt":"also do X"}}`
393+
content := testjsonl.JoinJSONL(
394+
testjsonl.ClaudeUserJSON("first request", tsZero),
395+
testjsonl.ClaudeAssistantJSON([]map[string]any{
396+
{"type": "text", "text": "starting work"},
397+
}, tsZeroS1),
398+
queued,
399+
)
400+
_, msgs := runClaudeParserTest(t, "test.jsonl", content)
401+
require.Len(t, msgs, 3)
402+
assert.Equal(t, "queued_command", msgs[2].SourceSubtype)
403+
assert.Equal(t, "queued", msgs[2].PromptSource)
404+
})
405+
389406
t.Run("surfaces as user message between turns", func(t *testing.T) {
390407
content := testjsonl.JoinJSONL(
391408
testjsonl.ClaudeUserJSON("first request", tsZero),

0 commit comments

Comments
 (0)