π― Use case
This file lives under βtypes/β, which covers shared TypeScript types and generated typings. On the API surface it exposes SerializedMessage, LogOption, SummaryMessage, CustomTitleMessage, and AiTitleMessage (and more) β mainly types, interfaces, or factory objects. Dependencies touch crypto and src. It composes internal code from ids, message, and messageQueueTypes (relative imports).
Generated from folder role, exports, dependency roots, and inline comments β not hand-reviewed for every path.
π§ Inline summary
import type { UUID } from 'crypto' import type { FileHistorySnapshot } from 'src/utils/fileHistory.js' import type { ContentReplacementRecord } from 'src/utils/toolResultStorage.js' import type { AgentId } from './ids.js' import type { Message } from './message.js'
π€ Exports (heuristic)
SerializedMessageLogOptionSummaryMessageCustomTitleMessageAiTitleMessageLastPromptMessageTaskSummaryMessageTagMessageAgentNameMessageAgentColorMessageAgentSettingMessagePRLinkMessageModeEntryPersistedWorktreeSessionWorktreeStateEntryContentReplacementEntryFileHistorySnapshotMessageFileAttributionStateAttributionSnapshotMessageTranscriptMessageSpeculationAcceptMessageContextCollapseCommitEntryContextCollapseSnapshotEntryEntrysortLogs
π External import roots
Package roots from from "β¦" (relative paths omitted).
cryptosrc
π₯οΈ Source preview
import type { UUID } from 'crypto'
import type { FileHistorySnapshot } from 'src/utils/fileHistory.js'
import type { ContentReplacementRecord } from 'src/utils/toolResultStorage.js'
import type { AgentId } from './ids.js'
import type { Message } from './message.js'
import type { QueueOperationMessage } from './messageQueueTypes.js'
export type SerializedMessage = Message & {
cwd: string
userType: string
entrypoint?: string // CLAUDE_CODE_ENTRYPOINT β distinguishes cli/sdk-ts/sdk-py/etc.
sessionId: string
timestamp: string
version: string
gitBranch?: string
slug?: string // Session slug for files like plans (used for resume)
}
export type LogOption = {
date: string
messages: SerializedMessage[]
fullPath?: string
value: number
created: Date
modified: Date
firstPrompt: string
messageCount: number
fileSize?: number // File size in bytes (for display)
isSidechain: boolean
isLite?: boolean // True for lite logs (messages not loaded)
sessionId?: string // Session ID for lite logs
teamName?: string // Team name if this is a spawned agent session
agentName?: string // Agent's custom name (from /rename or swarm)
agentColor?: string // Agent's color (from /rename or swarm)
agentSetting?: string // Agent definition used (from --agent flag or settings.agent)
isTeammate?: boolean // Whether this session was created by a swarm teammate
leafUuid?: UUID // If given, this uuid must appear in the DB
summary?: string // Optional conversation summary
customTitle?: string // Optional user-set custom title
tag?: string // Optional tag for the session (searchable in /resume)
fileHistorySnapshots?: FileHistorySnapshot[] // Optional file history snapshots
attributionSnapshots?: AttributionSnapshotMessage[] // Optional attribution snapshots
contextCollapseCommits?: ContextCollapseCommitEntry[] // Ordered β commit B may reference commit A's summary
contextCollapseSnapshot?: ContextCollapseSnapshotEntry // Last-wins β staged queue + spawn state
gitBranch?: string // Git branch at the end of the session
projectPath?: string // Original project directory path
prNumber?: number // GitHub PR number linked to this session
prUrl?: string // Full URL to the linked PR
prRepository?: string // Repository in "owner/repo" format
mode?: 'coordinator' | 'normal' // Session mode for coordinator/normal detection
worktreeSession?: PersistedWorktreeSession | null // Worktree state at session end (null = exited, undefined = never entered)
contentReplacements?: ContentReplacementRecord[] // Replacement decisions for resume reconstruction
}
export type SummaryMessage = {
type: 'summary'
leafUuid: UUID
summary: string
}
export type CustomTitleMessage = {
type: 'custom-title'
sessionId: UUID
customTitle: string
}
/**
* AI-generated session title. Distinct from CustomTitleMessage so that:
* - User renames (custom-title) always win over AI titles in read preference
* - reAppendSessionMetadata never re-appends AI titles (they're ephemeral/
* regeneratable; re-appending would clobber user renames on resume)
* - VS Code's onlyIfNoCustomTitle CAS check only matches user titles,
* allowing AI to overwrite its own previous AI title but not user titles
*/
export type AiTitleMessage = {
type: 'ai-title'
sessionId: UUID
aiTitle: string
}
export type LastPromptMessage = {
type: 'last-prompt'
sessionId: UUID
lastPrompt: string
}
/**
* Periodic fork-generated summary of what the agent is currently doing.
* Written every min(5 steps, 2min) by forking the main thread mid-turn so
* `claude ps` can show something more useful than the last user prompt
* (which is often "ok go" or "fix it").
*/
export type TaskSummaryMessage = {
type: 'task-summary'
sessionId: UUID
summary: string
timestamp: string
}
export type TagMessage = {
type: 'tag'
sessionId: UUID
tag: string
}
export type AgentNameMessage = {
type: 'agent-name'
sessionId: UUID
agentName: string
}
export type AgentColorMessage = {
type: 'agent-color'
sessionId: UUID
agentColor: string
}
export type AgentSettingMessage = {
type: 'agent-setting'
sessionId: UUID
agentSetting: string
}
/**
* PR link message stored in session transcript.
* Links a session to a GitHub pull request for tracking and navigation.
*/
export type PRLinkMessage = {
type: 'pr-link'
sessionId: UUID
prNumber: number
prUrl: string
prRepository: string // e.g., "owner/repo"
timestamp: string // ISO timestamp when linked
}
export type ModeEntry = {
type: 'mode'
sessionId: UUID
mode: 'coordinator' | 'normal'
}
/**
* Worktree session state persisted to the transcript for resume.
* Subset of WorktreeSession from utils/worktree.ts β excludes ephemeral
* fields (creationDurationMs, usedSparsePaths) that are only used for
* first-run analytics.
*/
export type PersistedWorktreeSession = {
originalCwd: string
worktreePath: string
worktreeName: string
worktreeBranch?: string
originalBranch?: string
originalHeadCommit?: string
sessionId: string
tmuxSessionName?: string
hookBased?: boolean
}
/**
* Records whether the session is currently inside a worktree created by
* EnterWorktree or --worktree. Last-wins: an enter writes the session,
* an exit writes null. On --resume, restored only if the worktreePath
* still exists on disk (the /exit dialog may have removed it).
*/
export type WorktreeStateEntry = {
type: 'worktree-state'
sessionId: UUID
worktreeSession: PersistedWorktreeSession | null
}
/**
* Records content blocks whose in-context representation was replaced with a
* smaller stub (the full content was persisted elsewhere). Replayed on resume
* for prompt cache stability. Written once per enforcement pass that replaces
* at least one block. When agentId is set, the record belongs to a subagent
* sidechain (AgentTool resume reads these); when absent, it's main-thread
* (/resume reads these).
*/
export type ContentReplacementEntry = {
type: 'content-replacement'
sessionId: UUID
agentId?: AgentId
replacements: ContentReplacementRecord[]
}
export type FileHistorySnapshotMessage = {
type: 'file-history-snapshot'
messageId: UUID
snapshot: FileHistorySnapshot
isSnapshotUpdate: boolean
}
/**
* Per-file attribution state tracking Claude's character contributions.
*/
export type FileAttributionState = {
contentHash: string // SHA-256 hash of file content
claudeContribution: number // Characters written by Claude
mtime: number // File modification time
}
/**
* Attribution snapshot message stored in session transcript.
* Tracks character-level contributions by Claude for commit attribution.
*/
export type AttributionSnapshotMessage = {
type: 'attribution-snapshot'
messageId: UUID
surface: string // Client surface (cli, ide, web, api)
fileStates: Record<string, FileAttributionState>
promptCount?: number // Total prompts in session
promptCountAtLastCommit?: number // Prompts at last commit
permissionPromptCount?: number // Total permission prompts shown
permissionPromptCountAtLastCommit?: number // Permission prompts at last commit
escapeCount?: number // Total ESC presses (cancelled permission prompts)
escapeCountAtLastCommit?: number // ESC presses at last commit
}
export type TranscriptMessage = SerializedMessage & {
parentUuid: UUID | null
logicalParentUuid?: UUID | null // Preserves logical parent when parentUuid is nullified for session breaks
isSidechain: boolean
gitBranch?: string
agentId?: string // Agent ID for sidechain transcripts to enable resuming agents
teamName?: string // Team name if this is a spawned agent session
agentName?: string // Agent's custom name (from /rename or swarm)
agentColor?: string // Agent's color (from /rename or swarm)
promptId?: string // Correlates with OTel prompt.id for user prompt messages
}
export type SpeculationAcceptMessage = {
type: 'speculation-accept'
timestamp: string
timeSavedMs: number
}
/**
* Persisted context-collapse commit. The archived messages themselves are
* NOT persisted β they're already in the transcript as ordinary user/
* assistant messages. We only persist enough to reconstruct the splice
* instruction (boundary uuids) and the summary placeholder (which is NOT
* in the transcript because it's never yielded to the REPL).
*
* On restore, the store reconstructs CommittedCollapse with archived=[];
* projectView lazily fills the archive the first time it finds the span.
*
* Discriminator is obfuscated to match the gate name. sessionStorage.ts
* isn't feature-gated (it's the generic transcript plumbing used by every
* entry type), so a descriptive string here would leak into external builds
* via the appendEntry dispatch / loadTranscriptFile parser even though
* nothing in an external build ever writes or reads this entry.
*/
export type ContextCollapseCommitEntry = {
type: 'marble-origami-commit'
sessionId: UUID
/** 16-digit collapse ID. Max across entries reseeds the ID counter. */
collapseId: string
/** The summary placeholder's uuid β registerSummary() needs it. */
summaryUuid: string
/** Full <collapsed id="...">text</collapsed> string for the placeholder. */
summaryContent: string
/** Plain summary text for ctx_inspect. */
summary: string
/** Span boundaries β projectView finds these in the resumed Message[]. */
firstArchivedUuid: string
lastArchivedUuid: string
}
/**
* Snapshot of the staged queue and spawn trigger state. Unlike commits
* (append-only, replay-all), snapshots are last-wins β only the most
* recent snapshot entry is applied on restore. Written after every
* ctx-agent spawn resolves (when staged contents may have changed).
*
* Staged boundaries are UUIDs (session-stable), not collapse IDs (which
* reset with the uuidToId bimap). Restoring a staged span issues fresh
* collapse IDs for those messages on the next decorate/display, but the
* span itself resolves correctly.
*/
export type ContextCollapseSnapshotEntry = {
type: 'marble-origami-snapshot'
sessionId: UUID
staged: Array<{
startUuid: string
endUuid: string
summary: string
risk: number
stagedAt: number
}>
/** Spawn trigger state β so the +interval clock picks up where it left off. */
armed: boolean
lastSpawnTokens: number
}
export type Entry =
| TranscriptMessage
| SummaryMessage
| CustomTitleMessage
| AiTitleMessage
| LastPromptMessage
| TaskSummaryMessage
| TagMessage
| AgentNameMessage
| AgentColorMessage
| AgentSettingMessage
| PRLinkMessage
| FileHistorySnapshotMessage
| AttributionSnapshotMessage
| QueueOperationMessage
| SpeculationAcceptMessage
| ModeEntry
| WorktreeStateEntry
| ContentReplacementEntry
| ContextCollapseCommitEntry
| ContextCollapseSnapshotEntry
export function sortLogs(logs: LogOption[]): LogOption[] {
return logs.sort((a, b) => {
// Sort by modified date (newest first)
const modifiedDiff = b.modified.getTime() - a.modified.getTime()
if (modifiedDiff !== 0) {
return modifiedDiff
}
// If modified dates are equal, sort by created date (newest first)
return b.created.getTime() - a.created.getTime()
})
}