-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcheckpoint.go
More file actions
740 lines (579 loc) · 30 KB
/
Copy pathcheckpoint.go
File metadata and controls
740 lines (579 loc) · 30 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
// Package checkpoint provides types and interfaces for checkpoint storage.
//
// A Checkpoint captures a point-in-time within a session, containing either
// full state (Temporary) or metadata with a commit reference (Committed).
//
// See docs/architecture/sessions-and-checkpoints.md for the full domain model.
package checkpoint
import (
"context"
"encoding/json"
"errors"
"time"
"github.com/GrayCodeAI/trace/cli/agent"
"github.com/GrayCodeAI/trace/cli/agent/types"
"github.com/GrayCodeAI/trace/cli/checkpoint/id"
"github.com/GrayCodeAI/trace/redact"
"github.com/go-git/go-git/v6/plumbing"
)
// Errors returned by checkpoint operations.
var (
// ErrCheckpointNotFound is returned when a checkpoint ID doesn't exist.
ErrCheckpointNotFound = errors.New("checkpoint not found")
// ErrNoTranscript is returned when a checkpoint exists but has no transcript.
ErrNoTranscript = errors.New("no transcript found for checkpoint")
)
// Checkpoint represents a save point within a session.
type Checkpoint struct {
// ID is the unique checkpoint identifier
ID string
// SessionID is the session this checkpoint belongs to
SessionID string
// Timestamp is when this checkpoint was created
Timestamp time.Time
// Type indicates temporary (full state) or committed (metadata only)
Type Type
// Message is a human-readable description of the checkpoint
Message string
}
// Type indicates the storage location and lifecycle of a checkpoint.
type Type int
const (
// Temporary checkpoints contain full state (code + metadata) and are stored
// on shadow branches (trace/<commit-hash>). Used for intra-session rewind.
Temporary Type = iota
// Committed checkpoints contain metadata + commit reference and are stored
// on the trace/checkpoints/v1 branch. They are the permanent record.
Committed
)
// Store provides low-level primitives for reading and writing checkpoints.
// This is used by strategies to implement their storage approach.
//
// The interface matches the GitStore implementation signatures directly:
// - WriteTemporary takes WriteTemporaryOptions and returns a result with commit hash and skip status
// - ReadTemporary takes baseCommit (not sessionID) since shadow branches are keyed by commit
// - List methods return implementation-specific info types for richer data
type Store interface {
// WriteTemporary writes a temporary checkpoint (full state) to a shadow branch.
// Shadow branches are named trace/<base-commit-short-hash>.
// Returns a result containing the commit hash and whether the checkpoint was skipped.
// Checkpoints are skipped (deduplicated) when the tree hash matches the previous checkpoint.
WriteTemporary(ctx context.Context, opts WriteTemporaryOptions) (WriteTemporaryResult, error)
// ReadTemporary reads the latest checkpoint from a shadow branch.
// baseCommit is the commit hash the session is based on.
// worktreeID is the internal git worktree identifier (empty for main worktree).
// Returns nil, nil if the shadow branch doesn't exist.
ReadTemporary(ctx context.Context, baseCommit, worktreeID string) (*ReadTemporaryResult, error)
// ListTemporary lists all shadow branches with their checkpoint info.
ListTemporary(ctx context.Context) ([]TemporaryInfo, error)
// WriteCommitted writes a committed checkpoint to the trace/checkpoints/v1 branch.
// Checkpoints are stored at sharded paths: <id[:2]>/<id[2:]>/
WriteCommitted(ctx context.Context, opts WriteCommittedOptions) error
// ReadCommitted reads a committed checkpoint's summary by ID.
// Returns only the CheckpointSummary (paths + aggregated stats), not actual content.
// Use ReadSessionContent to read actual transcript/prompts.
// Returns nil, nil if the checkpoint does not exist.
ReadCommitted(ctx context.Context, checkpointID id.CheckpointID) (*CheckpointSummary, error)
// ReadSessionContent reads the actual content for a specific session within a checkpoint.
// sessionIndex is 0-based (0 for first session, 1 for second, etc.).
// Returns the session's metadata, transcript, and prompts.
ReadSessionContent(ctx context.Context, checkpointID id.CheckpointID, sessionIndex int) (*SessionContent, error)
// ReadSessionContentByID reads a session's content by its session ID.
// Useful when you have the session ID but don't know its index within the checkpoint.
ReadSessionContentByID(ctx context.Context, checkpointID id.CheckpointID, sessionID string) (*SessionContent, error)
// ListCommitted lists all committed checkpoints.
ListCommitted(ctx context.Context) ([]CommittedInfo, error)
// UpdateCommitted replaces the transcript and prompts for an existing
// committed checkpoint. Used at stop time to finalize checkpoints with the full
// session transcript (prompt to stop event).
// Returns ErrCheckpointNotFound if the checkpoint doesn't exist.
UpdateCommitted(ctx context.Context, opts UpdateCommittedOptions) error
}
// WriteTemporaryResult contains the result of writing a temporary checkpoint.
type WriteTemporaryResult struct {
// CommitHash is the hash of the created or existing checkpoint commit
CommitHash plumbing.Hash
// Skipped is true if the checkpoint was skipped due to no changes
// (tree hash matched the previous checkpoint)
Skipped bool
}
// WriteTemporaryOptions contains options for writing a temporary checkpoint.
type WriteTemporaryOptions struct {
// SessionID is the session identifier
SessionID string
// BaseCommit is the commit hash this session is based on
BaseCommit string
// WorktreeID is the internal git worktree identifier (empty for main worktree)
// Used to create worktree-specific shadow branch names
WorktreeID string
// ModifiedFiles are files that have been modified (relative paths)
ModifiedFiles []string
// NewFiles are files that have been created (relative paths)
NewFiles []string
// DeletedFiles are files that have been deleted (relative paths)
DeletedFiles []string
// MetadataDir is the relative path to the metadata directory
MetadataDir string
// MetadataDirAbs is the absolute path to the metadata directory
MetadataDirAbs string
// CommitMessage is the commit subject line
CommitMessage string
// AuthorName is the name to use for commits
AuthorName string
// AuthorEmail is the email to use for commits
AuthorEmail string
// IsFirstCheckpoint indicates if this is the first checkpoint of the session
// When true, all working directory files are captured (not just modified)
IsFirstCheckpoint bool
}
// ReadTemporaryResult contains the result of reading a temporary checkpoint.
type ReadTemporaryResult struct {
// CommitHash is the hash of the checkpoint commit
CommitHash plumbing.Hash
// TreeHash is the hash of the tree containing the checkpoint state
TreeHash plumbing.Hash
// SessionID is the session identifier from the commit trailer
SessionID string
// MetadataDir is the metadata directory path from the commit trailer
MetadataDir string
// Timestamp is when the checkpoint was created
Timestamp time.Time
}
// TemporaryInfo contains summary information about a shadow branch.
type TemporaryInfo struct {
// BranchName is the full branch name (e.g., "trace/abc1234")
BranchName string
// BaseCommit is the short commit hash this branch is based on
BaseCommit string
// LatestCommit is the hash of the latest commit on the branch
LatestCommit plumbing.Hash
// SessionID is the session identifier from the latest commit
SessionID string
// Timestamp is when the latest checkpoint was created
Timestamp time.Time
}
// WriteCommittedOptions contains options for writing a committed checkpoint.
type WriteCommittedOptions struct {
// CheckpointID is the stable 12-hex-char identifier
CheckpointID id.CheckpointID
// SessionID is the session identifier
SessionID string
// CreatedAt is when the checkpoint was originally created.
// When zero, writers use the current time. Migration sets this to preserve
// the original v1 checkpoint time in v2 metadata and retention decisions.
CreatedAt time.Time
// Strategy is the name of the strategy that created this checkpoint
Strategy string
// Branch is the branch name where the checkpoint was created (empty if detached HEAD)
Branch string
// Transcript is the session transcript content (full.jsonl).
// Must be pre-redacted (via redact.JSONLBytes or redact.AlreadyRedacted for trusted sources).
Transcript redact.RedactedBytes
// Prompts contains user prompts from the session
Prompts []string
// FilesTouched are files modified during the session
FilesTouched []string
// CheckpointsCount is the number of checkpoints in this session
CheckpointsCount int
// EphemeralBranch is the shadow branch name (for manual-commit strategy)
EphemeralBranch string
// AuthorName is the name to use for commits
AuthorName string
// AuthorEmail is the email to use for commits
AuthorEmail string
// MetadataDir is a directory containing additional metadata files to copy
// If set, all files in this directory will be copied to the checkpoint path
// This is useful for copying task metadata files, subagent transcripts, etc.
MetadataDir string
// Task checkpoint fields (for task/subagent checkpoints)
IsTask bool // Whether this is a task checkpoint
ToolUseID string // Tool use ID for task checkpoints
// Additional task checkpoint fields for subagent checkpoints
AgentID string // Subagent identifier
CheckpointUUID string // UUID for transcript truncation when rewinding
TranscriptPath string // Path to session transcript file (alternative to in-memory Transcript)
SubagentTranscriptPath string // Path to subagent's transcript file
// Incremental checkpoint fields
IsIncremental bool // Whether this is an incremental checkpoint
IncrementalSequence int // Checkpoint sequence number
IncrementalType string // Tool type that triggered this checkpoint
IncrementalData []byte // Tool input payload for this checkpoint
// Commit message fields (used for task checkpoints)
CommitSubject string // Subject line for the metadata commit (overrides default)
// Agent identifies the agent that created this checkpoint (e.g., "Claude Code", "Cursor")
Agent types.AgentType
// Model is the LLM model used during the session (e.g., "claude-sonnet-4-20250514")
Model string
// TurnID correlates checkpoints from the same agent turn.
TurnID string
// Kind tags the session purpose (e.g., "agent_review", "agent_investigate").
Kind string
// ReviewSkills is the snapshot of configured review skills at session start.
ReviewSkills []string
// ReviewPrompt is the actual text of the review request.
ReviewPrompt string
// InvestigateRunID is the 12-hex-char ID of the parent investigation run.
InvestigateRunID string
// InvestigateTopic is the human-readable topic for the investigation run.
InvestigateTopic string
// Transcript position at checkpoint start - tracks what was added during this checkpoint
TranscriptIdentifierAtStart string // Last identifier when checkpoint started (UUID for Claude, message ID for Gemini)
CheckpointTranscriptStart int // Transcript line offset at start of this checkpoint's data
// CheckpointTranscriptStart is written to both CommittedMetadata.CheckpointTranscriptStart
// and the deprecated CommittedMetadata.TranscriptLinesAtStart for backward compatibility.
// CompactTranscriptStart is the transcript.jsonl line offset at checkpoint start.
// V2 /main writes this to checkpoint_transcript_start; v1 continues to use
// CheckpointTranscriptStart (full.jsonl).
CompactTranscriptStart int
// TokenUsage contains the token usage for this checkpoint
TokenUsage *agent.TokenUsage
// SessionMetrics contains hook-provided session metrics (duration, turns, context usage)
SessionMetrics *SessionMetrics
// InitialAttribution is line-level attribution calculated at commit time
// comparing checkpoint tree (agent work) to committed tree (may include human edits)
InitialAttribution *InitialAttribution
// PromptAttributionsJSON is the raw PromptAttributions data, JSON-encoded.
// Persisted for diagnostic purposes — shows exactly which prompt recorded
// which "user" lines, enabling root cause analysis of attribution bugs.
// Uses json.RawMessage to avoid importing session package.
PromptAttributionsJSON json.RawMessage
// CombinedAttribution is holistic attribution across all sessions.
// Used during migration to preserve v1 root summary attribution.
// During normal condensation this is nil (computed post-commit via UpdateCheckpointSummary).
CombinedAttribution *InitialAttribution
// Summary is an optional AI-generated summary for this checkpoint.
// This field may be nil when:
// - summarization is disabled in settings
// - summary generation failed (non-blocking, logged as warning)
// - the transcript was empty or too short to summarize
// - the checkpoint predates the summarization feature
Summary *Summary
// CompactTranscript is the Trace Transcript Format (transcript.jsonl) bytes.
// Written to v2 /main ref alongside metadata. May be nil if compaction
// was not performed (unknown agent, compaction error, empty transcript).
CompactTranscript []byte
}
// UpdateCommittedOptions contains options for updating an existing committed checkpoint.
// Uses replace semantics: the transcript and prompts are fully replaced,
// not appended. At stop time we have the complete session transcript and want every
// checkpoint to contain it identically.
type UpdateCommittedOptions struct {
// CheckpointID identifies the checkpoint to update
CheckpointID id.CheckpointID
// SessionID identifies which session slot to update within the checkpoint
SessionID string
// Transcript is the full session transcript (replaces existing).
// Must be pre-redacted (via redact.JSONLBytes or redact.AlreadyRedacted for trusted sources).
Transcript redact.RedactedBytes
// Prompts contains all user prompts (replaces existing)
Prompts []string
// Agent identifies the agent type (needed for transcript chunking)
Agent types.AgentType
// CompactTranscript is the updated Trace Transcript Format bytes.
// If non-nil, replaces the existing transcript.jsonl on v2 /main.
CompactTranscript []byte
// PrecomputedBlobs, if non-nil, provides chunk blob hashes and the
// content-hash blob hash computed once for this transcript. When set,
// UpdateCommitted skips the per-call ChunkTranscript + zlib work and
// reuses these hashes. Used by finalizeAllTurnCheckpoints to avoid
// re-compressing identical content N times.
PrecomputedBlobs *PrecomputedTranscriptBlobs
}
// PrecomputedTranscriptBlobs holds blob hashes for a transcript that was
// chunked and written to the object store once, for reuse across multiple
// UpdateCommitted calls sharing the same transcript content.
//
// Blob hashes are content-addressed (SHA-1 of chunk bytes), so the same
// PrecomputedTranscriptBlobs works for both v1 (full.jsonl) and v2
// (raw_transcript) paths — only the tree-entry filename differs.
//
// Callers should avoid constructing this for empty transcripts; agent.ChunkTranscript
// would otherwise produce a single zero-length chunk and a hash for an empty
// blob, which downstream stores would never reference.
type PrecomputedTranscriptBlobs struct {
// ChunkHashes are the blob hashes for each transcript chunk, in order.
// Always non-empty when built via PrecomputeTranscriptBlobs (a non-empty
// transcript chunks to at least one entry; callers should skip precompute
// for empty transcripts).
ChunkHashes []plumbing.Hash
// ContentHashBlob is the blob hash of the "sha256:<hex>" content-hash
// string for the transcript.
ContentHashBlob plumbing.Hash
// ContentHash is the "sha256:<hex>" string itself, so the short-circuit
// path can compare without re-reading the blob.
ContentHash string
}
// isUsable reports whether the precomputed blobs satisfy the invariants that
// consumers depend on: a non-zero content-hash blob and at least one chunk
// hash. Callers should fall back to the fresh-write path when this is false.
func (p *PrecomputedTranscriptBlobs) isUsable() bool {
return p != nil && !p.ContentHashBlob.IsZero() && len(p.ChunkHashes) > 0
}
// CommittedInfo contains summary information about a committed checkpoint.
type CommittedInfo struct {
// CheckpointID is the stable 12-hex-char identifier
CheckpointID id.CheckpointID
// SessionID is the session identifier (most recent session for multi-session checkpoints)
SessionID string
// CreatedAt is when the checkpoint was created
CreatedAt time.Time
// CheckpointsCount is the total number of checkpoints across all sessions
CheckpointsCount int
// FilesTouched are files modified during all sessions
FilesTouched []string
// Agent identifies the agent that created this checkpoint
Agent types.AgentType
// IsTask indicates if this is a task checkpoint
IsTask bool
// ToolUseID is the tool use ID for task checkpoints
ToolUseID string
// Multi-session support
SessionCount int // Number of sessions (1 if single session)
SessionIDs []string // All session IDs that contributed
}
// SessionContent contains the actual content for a session.
// This is used when reading full session data (transcript, prompts, context)
// as opposed to just the metadata/summary.
type SessionContent struct {
// Metadata contains the session-specific metadata
Metadata CommittedMetadata
// Transcript is the session transcript content
Transcript []byte
// Prompts contains user prompts from this session
Prompts string
}
// CommittedMetadata contains the metadata stored in metadata.json for each checkpoint.
type CommittedMetadata struct {
CLIVersion string `json:"cli_version,omitempty"`
CheckpointID id.CheckpointID `json:"checkpoint_id"`
SessionID string `json:"session_id"`
Strategy string `json:"strategy"`
CreatedAt time.Time `json:"created_at"`
Branch string `json:"branch,omitempty"` // Branch where checkpoint was created (empty if detached HEAD)
CheckpointsCount int `json:"checkpoints_count"`
FilesTouched []string `json:"files_touched"`
// Agent identifies the agent that created this checkpoint (e.g., "Claude Code", "Cursor")
Agent types.AgentType `json:"agent,omitempty"`
// Model is the LLM model used during the session (e.g., "claude-sonnet-4-20250514").
// Always written to metadata (empty string when unknown) so consumers can rely on the field's presence.
Model string `json:"model"`
// TurnID correlates checkpoints from the same agent turn.
// When a turn's work spans multiple commits, each gets its own checkpoint
// but they share the same TurnID for future aggregation/deduplication.
TurnID string `json:"turn_id,omitempty"`
// Kind tags the session purpose (e.g., "agent_review"). Empty for normal sessions.
Kind string `json:"kind,omitempty"`
// ReviewSkills is the snapshot of configured review skills at session start.
ReviewSkills []string `json:"review_skills,omitempty"`
// ReviewPrompt is the actual text of the review request (composed prompt
// for spawn, first user prompt for attach). Only set when Kind is a
// review kind.
ReviewPrompt string `json:"review_prompt,omitempty"`
// InvestigateRunID is the 12-hex-char ID of the parent investigation
// run. Only set when Kind is an investigate kind.
InvestigateRunID string `json:"investigate_run_id,omitempty"`
// InvestigateTopic is the human-readable topic for the investigation run.
InvestigateTopic string `json:"investigate_topic,omitempty"`
// Task checkpoint fields (only populated for task checkpoints)
IsTask bool `json:"is_task,omitempty"`
ToolUseID string `json:"tool_use_id,omitempty"`
// Transcript position at checkpoint start - tracks what was added during this checkpoint
TranscriptIdentifierAtStart string `json:"transcript_identifier_at_start,omitempty"` // Last identifier when checkpoint started (UUID for Claude, message ID for Gemini)
CheckpointTranscriptStart int `json:"checkpoint_transcript_start,omitempty"` // Transcript line offset at start of this checkpoint's data
// Deprecated: Use CheckpointTranscriptStart instead. Written for backward compatibility with older CLI versions.
TranscriptLinesAtStart int `json:"transcript_lines_at_start,omitempty"`
// Token usage for this checkpoint
TokenUsage *agent.TokenUsage `json:"token_usage,omitempty"`
// SessionMetrics contains hook-provided session metrics (duration, turns, context usage).
// Populated for agents that provide these metrics via hooks (e.g., Cursor).
SessionMetrics *SessionMetrics `json:"session_metrics,omitempty"`
// AI-generated summary of the checkpoint
Summary *Summary `json:"summary,omitempty"`
// InitialAttribution is line-level attribution calculated at commit time
InitialAttribution *InitialAttribution `json:"initial_attribution,omitempty"`
// PromptAttributions is the raw per-prompt attribution data used to compute InitialAttribution.
// Diagnostic field — shows which prompt recorded which "user" lines.
PromptAttributions json.RawMessage `json:"prompt_attributions,omitempty"`
}
// GetTranscriptStart returns the transcript line offset at which this checkpoint's data begins.
// Returns 0 for new checkpoints (start from beginning). For data written by older CLI versions,
// falls back to the deprecated TranscriptLinesAtStart field.
func (m CommittedMetadata) GetTranscriptStart() int {
if m.CheckpointTranscriptStart > 0 {
return m.CheckpointTranscriptStart
}
return m.TranscriptLinesAtStart
}
// SessionFilePaths contains the absolute paths to session files from the git tree root.
// Paths include the full checkpoint path prefix (e.g., "/a1/b2c3d4e5f6/1/metadata.json").
// Used in CheckpointSummary.Sessions to map session IDs to their file locations.
type SessionFilePaths struct {
Metadata string `json:"metadata"`
Transcript string `json:"transcript,omitempty"`
ContentHash string `json:"content_hash,omitempty"`
Prompt string `json:"prompt"`
}
// CheckpointSummary is the root-level metadata.json for a checkpoint.
// It contains aggregated statistics from all sessions and a map of session IDs
// to their file paths. Session-specific data (including initial_attribution)
// is stored in the session's subdirectory metadata.json.
//
// Structure on trace/checkpoints/v1 branch:
//
// <checkpoint-id[:2]>/<checkpoint-id[2:]>/
// ├── metadata.json # This CheckpointSummary
// ├── 1/ # First session
// │ ├── metadata.json # Session-specific CommittedMetadata
// │ ├── full.jsonl
// │ ├── prompt.txt
// │ └── content_hash.txt
// ├── 2/ # Second session
// └── 3/ # Third session...
//
//nolint:revive // Named CheckpointSummary to avoid conflict with existing Summary struct
type CheckpointSummary struct {
CLIVersion string `json:"cli_version,omitempty"`
CheckpointID id.CheckpointID `json:"checkpoint_id"`
Strategy string `json:"strategy"`
Branch string `json:"branch,omitempty"`
CheckpointsCount int `json:"checkpoints_count"`
FilesTouched []string `json:"files_touched"`
Sessions []SessionFilePaths `json:"sessions"`
TokenUsage *agent.TokenUsage `json:"token_usage,omitempty"`
CombinedAttribution *InitialAttribution `json:"combined_attribution,omitempty"`
// HasReview is the umbrella "any review happened" flag: true when at least
// one session in this checkpoint has Kind.IsReview(). Summary-level so
// queries can check the flag without scanning all session metadata.
HasReview bool `json:"has_review,omitempty"`
// HasInvestigation is true when this checkpoint was produced by
// `trace investigate`. Summary-level so the CLI can detect whether
// the current HEAD carries an investigate checkpoint without scanning
// all session metadata.
HasInvestigation bool `json:"has_investigation,omitempty"`
}
// SessionMetrics contains hook-provided session metrics from agents that report
// them via lifecycle hooks (e.g., Cursor). These supplement transcript-derived
// metrics for agents whose transcripts lack usage/timing data.
type SessionMetrics struct {
DurationMs int64 `json:"duration_ms,omitempty"`
TurnCount int `json:"turn_count,omitempty"`
ContextTokens int `json:"context_tokens,omitempty"`
ContextWindowSize int `json:"context_window_size,omitempty"`
}
// Summary contains AI-generated summary of a checkpoint.
type Summary struct {
Intent string `json:"intent"` // What user wanted to accomplish
Outcome string `json:"outcome"` // What was achieved
Learnings LearningsSummary `json:"learnings"` // Categorized learnings
Friction []string `json:"friction"` // Problems/annoyances encountered
OpenItems []string `json:"open_items"` // Tech debt, unfinished work
}
// LearningsSummary contains learnings grouped by scope.
type LearningsSummary struct {
Repo []string `json:"repo"` // Codebase-specific patterns/conventions
Code []CodeLearning `json:"code"` // File/module specific findings
Workflow []string `json:"workflow"` // General dev practices
}
// CodeLearning captures a learning tied to a specific code location.
type CodeLearning struct {
Path string `json:"path"` // File path
Line int `json:"line,omitempty"` // Start line number
EndLine int `json:"end_line,omitempty"` // End line for ranges (optional)
Finding string `json:"finding"` // What was learned
}
// InitialAttribution captures line-level attribution metrics at commit time.
// This is a point-in-time snapshot comparing the checkpoint tree (agent work)
// against the committed tree (may include human edits).
//
// Attribution Metrics:
// - TotalCommitted keeps the historical "net additions" view for compatibility
// - TotalLinesChanged measures total committed line changes (adds + modifies + removes)
// - AgentPercentage represents "of the lines changed in this commit, what percentage came from the agent"
// - AgentRemoved tracks committed deletions performed by the agent
type InitialAttribution struct {
CalculatedAt time.Time `json:"calculated_at"`
AgentLines int `json:"agent_lines"` // Lines added by agent that remain in the commit
AgentRemoved int `json:"agent_removed"` // Lines removed by agent that remain removed in the commit
HumanAdded int `json:"human_added"` // Lines added by human (excluding modifications)
HumanModified int `json:"human_modified"` // Lines modified by human (estimate: min(added, removed))
HumanRemoved int `json:"human_removed"` // Lines removed by human (excluding modifications)
TotalCommitted int `json:"total_committed"` // Net additions in commit (legacy additions-focused metric)
TotalLinesChanged int `json:"total_lines_changed"` // Total committed line changes (adds + modifies + removes)
AgentPercentage float64 `json:"agent_percentage"` // (agent_lines + agent_removed) / total_lines_changed * 100
MetricVersion int `json:"metric_version,omitempty"` // 0/absent = legacy (additions-only %), 2 = changed-lines %
BinaryFilesChanged int `json:"binary_files_changed"` // Number of binary files modified
}
// Info provides summary information for listing checkpoints.
// This is the generic checkpoint info type.
type Info struct {
// ID is the checkpoint identifier
ID string
// SessionID identifies the session
SessionID string
// Type indicates temporary or committed
Type Type
// CreatedAt is when the checkpoint was created
CreatedAt time.Time
// Message is a summary description
Message string
}
// WriteTemporaryTaskOptions contains options for writing a task checkpoint.
// Task checkpoints are created when a subagent completes and contain both
// code changes and task-specific metadata.
type WriteTemporaryTaskOptions struct {
// SessionID is the session identifier
SessionID string
// BaseCommit is the commit hash this session is based on
BaseCommit string
// WorktreeID is the internal git worktree identifier (empty for main worktree)
// Used to create worktree-specific shadow branch names
WorktreeID string
// ToolUseID is the unique identifier for this Task tool invocation
ToolUseID string
// AgentID is the subagent identifier
AgentID string
// ModifiedFiles are files that have been modified (relative paths)
ModifiedFiles []string
// NewFiles are files that have been created (relative paths)
NewFiles []string
// DeletedFiles are files that have been deleted (relative paths)
DeletedFiles []string
// TranscriptPath is the path to the main session transcript
TranscriptPath string
// SubagentTranscriptPath is the path to the subagent's transcript
SubagentTranscriptPath string
// CheckpointUUID is the UUID for transcript truncation when rewinding
CheckpointUUID string
// CommitMessage is the commit message (already formatted)
CommitMessage string
// AuthorName is the name to use for commits
AuthorName string
// AuthorEmail is the email to use for commits
AuthorEmail string
// IsIncremental indicates this is an incremental checkpoint
IsIncremental bool
// IncrementalSequence is the checkpoint sequence number
IncrementalSequence int
// IncrementalType is the tool that triggered this checkpoint
IncrementalType string
// IncrementalData is the tool_input payload for this checkpoint
IncrementalData []byte
}
// TemporaryCheckpointInfo contains information about a single commit on a shadow branch.
// Used by ListTemporaryCheckpoints to provide rewind point data.
type TemporaryCheckpointInfo struct {
// CommitHash is the hash of the checkpoint commit
CommitHash plumbing.Hash
// Message is the first line of the commit message
Message string
// SessionID is the session identifier from the Trace-Session trailer
SessionID string
// MetadataDir is the metadata directory path from trailers
MetadataDir string
// IsTaskCheckpoint indicates if this is a task checkpoint
IsTaskCheckpoint bool
// ToolUseID is the tool use ID for task checkpoints
ToolUseID string
// Timestamp is when the checkpoint was created
Timestamp time.Time
}