@ebowwa/claudecodehistory 1.5.1 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,248 @@
1
+ //! Type definitions matching the TypeScript history-service.ts API
2
+ //!
3
+ //! These types are designed to be serializable for NAPI bindings
4
+ //! and match the TypeScript interfaces exactly.
5
+
6
+ use serde::{Deserialize, Serialize};
7
+
8
+ /// Raw message from Claude Code JSONL files
9
+ #[derive(Debug, Clone, Serialize, Deserialize)]
10
+ pub struct ClaudeCodeMessage {
11
+ pub parent_uuid: Option<String>,
12
+ pub is_sidechain: bool,
13
+ pub user_type: String,
14
+ pub cwd: String,
15
+ pub session_id: String,
16
+ pub version: String,
17
+ #[serde(rename = "type")]
18
+ pub message_type: MessageType,
19
+ pub message: Option<MessageContent>,
20
+ pub uuid: String,
21
+ pub timestamp: String,
22
+ pub request_id: Option<String>,
23
+ }
24
+
25
+ /// Message type enum
26
+ #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
27
+ #[serde(rename_all = "lowercase")]
28
+ pub enum MessageType {
29
+ User,
30
+ Assistant,
31
+ System,
32
+ Result,
33
+ }
34
+
35
+ /// Message content structure
36
+ #[derive(Debug, Clone, Serialize, Deserialize)]
37
+ pub struct MessageContent {
38
+ pub role: String,
39
+ pub content: MessageContentValue,
40
+ pub model: Option<String>,
41
+ pub usage: Option<serde_json::Value>,
42
+ }
43
+
44
+ /// Message content can be string or array
45
+ #[derive(Debug, Clone, Serialize, Deserialize)]
46
+ #[serde(untagged)]
47
+ pub enum MessageContentValue {
48
+ String(String),
49
+ Array(Vec<ContentBlock>),
50
+ }
51
+
52
+ /// Content block for array messages
53
+ #[derive(Debug, Clone, Serialize, Deserialize)]
54
+ pub struct ContentBlock {
55
+ #[serde(rename = "type")]
56
+ pub block_type: Option<String>,
57
+ pub text: Option<String>,
58
+ }
59
+
60
+ /// Processed conversation entry for API responses
61
+ #[derive(Debug, Clone, Serialize, Deserialize)]
62
+ pub struct ConversationEntry {
63
+ pub session_id: String,
64
+ pub timestamp: String,
65
+ #[serde(rename = "type")]
66
+ pub entry_type: MessageType,
67
+ pub content: String,
68
+ pub project_path: String,
69
+ pub uuid: String,
70
+ pub formatted_time: Option<String>,
71
+ pub time_ago: Option<String>,
72
+ pub local_date: Option<String>,
73
+ pub metadata: Option<EntryMetadata>,
74
+ pub project_name: Option<String>,
75
+ }
76
+
77
+ /// Metadata for conversation entries
78
+ #[derive(Debug, Clone, Serialize, Deserialize)]
79
+ pub struct EntryMetadata {
80
+ pub usage: Option<serde_json::Value>,
81
+ pub total_cost_usd: Option<f64>,
82
+ pub num_turns: Option<u32>,
83
+ pub duration_ms: Option<u64>,
84
+ pub is_error: Option<bool>,
85
+ pub error_type: Option<String>,
86
+ pub model: Option<String>,
87
+ pub request_id: Option<String>,
88
+ }
89
+
90
+ /// Paginated response for conversation history
91
+ #[derive(Debug, Clone, Serialize, Deserialize)]
92
+ pub struct PaginatedConversationResponse {
93
+ pub entries: Vec<ConversationEntry>,
94
+ pub pagination: Pagination,
95
+ }
96
+
97
+ /// Pagination metadata
98
+ #[derive(Debug, Clone, Serialize, Deserialize)]
99
+ pub struct Pagination {
100
+ pub total_count: usize,
101
+ pub limit: usize,
102
+ pub offset: usize,
103
+ pub has_more: bool,
104
+ }
105
+
106
+ /// Options for querying conversation history
107
+ #[derive(Debug, Clone, Default, Serialize, Deserialize)]
108
+ pub struct HistoryQueryOptions {
109
+ pub session_id: Option<String>,
110
+ pub start_date: Option<String>,
111
+ pub end_date: Option<String>,
112
+ pub limit: Option<usize>,
113
+ pub offset: Option<usize>,
114
+ pub timezone: Option<String>,
115
+ pub message_types: Option<Vec<MessageType>>,
116
+ }
117
+
118
+ /// Options for listing sessions
119
+ #[derive(Debug, Clone, Default, Serialize, Deserialize)]
120
+ pub struct SessionListOptions {
121
+ pub project_path: Option<String>,
122
+ pub start_date: Option<String>,
123
+ pub end_date: Option<String>,
124
+ pub timezone: Option<String>,
125
+ }
126
+
127
+ /// Project information
128
+ #[derive(Debug, Clone, Serialize, Deserialize)]
129
+ pub struct ProjectInfo {
130
+ pub project_path: String,
131
+ pub session_count: usize,
132
+ pub message_count: usize,
133
+ pub last_activity_time: String,
134
+ }
135
+
136
+ /// Session information
137
+ #[derive(Debug, Clone, Serialize, Deserialize)]
138
+ pub struct SessionInfo {
139
+ pub session_id: String,
140
+ pub project_path: String,
141
+ pub start_time: String,
142
+ pub end_time: String,
143
+ pub message_count: usize,
144
+ pub user_message_count: usize,
145
+ pub assistant_message_count: usize,
146
+ pub first_user_message: Option<String>,
147
+ pub duration_ms: Option<u64>,
148
+ pub duration_formatted: Option<String>,
149
+ pub has_errors: Option<bool>,
150
+ pub project_name: Option<String>,
151
+ }
152
+
153
+ /// Search options
154
+ #[derive(Debug, Clone, Default, Serialize, Deserialize)]
155
+ pub struct SearchOptions {
156
+ pub limit: Option<usize>,
157
+ pub project_path: Option<String>,
158
+ pub start_date: Option<String>,
159
+ pub end_date: Option<String>,
160
+ pub timezone: Option<String>,
161
+ }
162
+
163
+ /// Current session information
164
+ #[derive(Debug, Clone, Serialize, Deserialize)]
165
+ pub struct CurrentSessionInfo {
166
+ pub session_id: String,
167
+ pub timestamp: String,
168
+ pub project_path: Option<String>,
169
+ pub display: Option<String>,
170
+ }
171
+
172
+ /// Session process information
173
+ #[derive(Debug, Clone, Serialize, Deserialize)]
174
+ pub struct SessionProcessInfo {
175
+ pub session_id: String,
176
+ pub pid: u32,
177
+ pub command: String,
178
+ pub alive: bool,
179
+ }
180
+
181
+ /// Recent activity options
182
+ #[derive(Debug, Clone, Default, Serialize, Deserialize)]
183
+ pub struct RecentActivityOptions {
184
+ pub limit: Option<usize>,
185
+ pub include_summaries: Option<bool>,
186
+ }
187
+
188
+ /// Recent activity item
189
+ #[derive(Debug, Clone, Serialize, Deserialize)]
190
+ pub struct RecentActivityItem {
191
+ pub session_id: String,
192
+ pub project_path: String,
193
+ pub project_name: String,
194
+ pub timestamp: String,
195
+ pub asked: String,
196
+ pub done: Option<String>,
197
+ pub time_ago: String,
198
+ }
199
+
200
+ /// Fast parsed entry (minimal fields for quick processing)
201
+ #[derive(Debug, Clone, Serialize, Deserialize)]
202
+ pub struct FastEntry {
203
+ pub uuid: String,
204
+ pub session_id: String,
205
+ pub timestamp: String,
206
+ pub role: Option<String>,
207
+ pub content: Option<String>,
208
+ }
209
+
210
+ /// Parsed entry from the fast parser
211
+ #[derive(Debug, Clone)]
212
+ pub struct ParsedEntry {
213
+ pub uuid: String,
214
+ pub session_id: String,
215
+ pub timestamp: String,
216
+ pub role: String,
217
+ pub content: String,
218
+ pub file_path: String,
219
+ }
220
+
221
+ impl Default for MessageType {
222
+ fn default() -> Self {
223
+ Self::User
224
+ }
225
+ }
226
+
227
+ impl std::fmt::Display for MessageType {
228
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
229
+ match self {
230
+ MessageType::User => write!(f, "user"),
231
+ MessageType::Assistant => write!(f, "assistant"),
232
+ MessageType::System => write!(f, "system"),
233
+ MessageType::Result => write!(f, "result"),
234
+ }
235
+ }
236
+ }
237
+
238
+ impl From<&str> for MessageType {
239
+ fn from(s: &str) -> Self {
240
+ match s.to_lowercase().as_str() {
241
+ "user" => MessageType::User,
242
+ "assistant" => MessageType::Assistant,
243
+ "system" => MessageType::System,
244
+ "result" => MessageType::Result,
245
+ _ => MessageType::User,
246
+ }
247
+ }
248
+ }
@@ -0,0 +1,210 @@
1
+ //! Utility functions for time formatting, path handling, and other helpers
2
+
3
+ use chrono::{DateTime, Local, TimeZone, Utc};
4
+
5
+ /// Format a timestamp into human-readable formats
6
+ ///
7
+ /// Returns (formatted_time, time_ago, local_date)
8
+ pub fn format_timestamp(timestamp: &str) -> (String, String, String) {
9
+ let dt = parse_timestamp(timestamp);
10
+
11
+ // Format in local timezone (Asia/Tokyo style for consistency with TS)
12
+ let formatted_time = dt
13
+ .with_timezone(&Local)
14
+ .format("%Y/%m/%d %H:%M:%S")
15
+ .to_string();
16
+
17
+ // Calculate time ago
18
+ let time_ago = get_time_ago(&dt);
19
+
20
+ // Local date in YYYY-MM-DD format
21
+ let local_date = dt.with_timezone(&Local).format("%Y-%m-%d").to_string();
22
+
23
+ (formatted_time, time_ago, local_date)
24
+ }
25
+
26
+ /// Parse ISO timestamp string into DateTime
27
+ pub fn parse_timestamp(timestamp: &str) -> DateTime<Utc> {
28
+ // Try parsing as ISO 8601
29
+ if let Ok(dt) = DateTime::parse_from_rfc3339(timestamp) {
30
+ return dt.with_timezone(&Utc);
31
+ }
32
+
33
+ // Fallback to current time if parsing fails
34
+ Utc::now()
35
+ }
36
+
37
+ /// Calculate human-readable "time ago" string
38
+ pub fn get_time_ago(dt: &DateTime<Utc>) -> String {
39
+ let now = Utc::now();
40
+ let diff = now.signed_duration_since(*dt);
41
+
42
+ let mins = diff.num_minutes();
43
+ let hours = diff.num_hours();
44
+ let days = diff.num_days();
45
+
46
+ if mins < 1 {
47
+ "just now".to_string()
48
+ } else if mins < 60 {
49
+ format!("{}m ago", mins)
50
+ } else if hours < 24 {
51
+ format!("{}h ago", hours)
52
+ } else if days < 7 {
53
+ format!("{}d ago", days)
54
+ } else if days < 30 {
55
+ format!("{}w ago", days / 7)
56
+ } else if days < 365 {
57
+ format!("{}mo ago", days / 30)
58
+ } else {
59
+ format!("{}y ago", days / 365)
60
+ }
61
+ }
62
+
63
+ /// Format duration in milliseconds to human-readable string
64
+ pub fn format_duration(ms: i64) -> String {
65
+ if ms < 1000 {
66
+ return format!("{}ms", ms);
67
+ }
68
+
69
+ let seconds = ms / 1000;
70
+ if seconds < 60 {
71
+ return format!("{}s", seconds);
72
+ }
73
+
74
+ let minutes = seconds / 60;
75
+ let remaining_seconds = seconds % 60;
76
+ if minutes < 60 {
77
+ if remaining_seconds > 0 {
78
+ return format!("{}m {}s", minutes, remaining_seconds);
79
+ }
80
+ return format!("{}m", minutes);
81
+ }
82
+
83
+ let hours = minutes / 60;
84
+ let remaining_minutes = minutes % 60;
85
+ if hours < 24 {
86
+ if remaining_minutes > 0 {
87
+ return format!("{}h {}m", hours, remaining_minutes);
88
+ }
89
+ return format!("{}h", hours);
90
+ }
91
+
92
+ let days = hours / 24;
93
+ let remaining_hours = hours % 24;
94
+ if remaining_hours > 0 {
95
+ format!("{}d {}h", days, remaining_hours)
96
+ } else {
97
+ format!("{}d", days)
98
+ }
99
+ }
100
+
101
+ /// Normalize a date string to ISO format with timezone support
102
+ ///
103
+ /// Takes a date like "2026-02-26" and converts it to ISO format
104
+ /// considering the timezone.
105
+ pub fn normalize_date(date_string: &str, is_end_date: bool, timezone: Option<&str>) -> String {
106
+ // If already ISO format, return as-is
107
+ if date_string.contains('T') {
108
+ return date_string.to_string();
109
+ }
110
+
111
+ let time_str = if is_end_date {
112
+ "23:59:59.999"
113
+ } else {
114
+ "00:00:00.000"
115
+ };
116
+
117
+ // For UTC, simple format
118
+ if timezone == Some("UTC") {
119
+ return format!("{}T{}Z", date_string, time_str);
120
+ }
121
+
122
+ // For other timezones, we need to calculate the offset
123
+ // This is a simplified version - full implementation would use chrono-tz
124
+ // For now, use local timezone
125
+ let parts: Vec<_> = date_string.split('-').collect();
126
+ if parts.len() != 3 {
127
+ return format!("{}T{}Z", date_string, time_str);
128
+ }
129
+
130
+ let year: i32 = parts[0].parse().unwrap_or(1970);
131
+ let month: u32 = parts[1].parse().unwrap_or(1);
132
+ let day: u32 = parts[2].parse().unwrap_or(1);
133
+
134
+ let hour = if is_end_date { 23 } else { 0 };
135
+ let minute = if is_end_date { 59 } else { 0 };
136
+ let second = if is_end_date { 59 } else { 0 };
137
+
138
+ // Create local datetime and convert to UTC
139
+ Local
140
+ .with_ymd_and_hms(year, month, day, hour, minute, second)
141
+ .single()
142
+ .map(|dt| dt.with_timezone(&Utc).to_rfc3339())
143
+ .unwrap_or_else(|| format!("{}T{}Z", date_string, time_str))
144
+ }
145
+
146
+ /// Decode project path from directory name
147
+ ///
148
+ /// Converts "-Users-ebowwa-Desktop-codespaces" to "/Users/ebowwa/Desktop/codespaces"
149
+ pub fn decode_project_path(project_dir: &str) -> String {
150
+ project_dir
151
+ .replace('-', "/")
152
+ .trim_start_matches('/')
153
+ .to_string()
154
+ }
155
+
156
+ /// Encode project path to directory name
157
+ ///
158
+ /// Converts "/Users/ebowwa/Desktop/codespaces" to "-Users-ebowwa-Desktop-codespaces"
159
+ pub fn encode_project_path(project_path: &str) -> String {
160
+ let trimmed = project_path.trim_start_matches('/');
161
+ if trimmed.is_empty() {
162
+ "-".to_string()
163
+ } else {
164
+ format!("-{}", trimmed.replace('/', "-"))
165
+ }
166
+ }
167
+
168
+ #[cfg(test)]
169
+ mod tests {
170
+ use super::*;
171
+
172
+ #[test]
173
+ fn test_format_duration() {
174
+ assert_eq!(format_duration(500), "500ms");
175
+ assert_eq!(format_duration(5000), "5s");
176
+ assert_eq!(format_duration(65000), "1m 5s");
177
+ assert_eq!(format_duration(3600000), "1h");
178
+ assert_eq!(format_duration(3661000), "1h 1m");
179
+ assert_eq!(format_duration(90061000), "1d 1h");
180
+ }
181
+
182
+ #[test]
183
+ fn test_decode_project_path() {
184
+ assert_eq!(
185
+ decode_project_path("-Users-ebowwa-Desktop-codespaces"),
186
+ "Users/ebowwa/Desktop/codespaces"
187
+ );
188
+ assert_eq!(decode_project_path("simple-path"), "simple/path");
189
+ }
190
+
191
+ #[test]
192
+ fn test_encode_project_path() {
193
+ assert_eq!(
194
+ encode_project_path("/Users/ebowwa/Desktop/codespaces"),
195
+ "-Users-ebowwa-Desktop-codespaces"
196
+ );
197
+ }
198
+
199
+ #[test]
200
+ fn test_get_time_ago() {
201
+ let now = Utc::now();
202
+ let one_min_ago = now - chrono::Duration::seconds(30);
203
+ let one_hour_ago = now - chrono::Duration::hours(1);
204
+ let one_day_ago = now - chrono::Duration::days(1);
205
+
206
+ assert!(get_time_ago(&one_min_ago).contains("m ago") || get_time_ago(&one_min_ago) == "just now");
207
+ assert!(get_time_ago(&one_hour_ago).contains("h ago"));
208
+ assert!(get_time_ago(&one_day_ago).contains("d ago"));
209
+ }
210
+ }
@@ -0,0 +1,187 @@
1
+ export interface ClaudeCodeMessage {
2
+ parentUuid: string | null;
3
+ isSidechain: boolean;
4
+ userType: string;
5
+ cwd: string;
6
+ sessionId: string;
7
+ version: string;
8
+ type: 'user' | 'assistant' | 'system' | 'result';
9
+ message?: {
10
+ role: string;
11
+ content: string | any[];
12
+ model?: string;
13
+ usage?: any;
14
+ };
15
+ uuid: string;
16
+ timestamp: string;
17
+ requestId?: string;
18
+ }
19
+ export interface ConversationEntry {
20
+ sessionId: string;
21
+ timestamp: string;
22
+ type: 'user' | 'assistant' | 'system' | 'result';
23
+ content: string;
24
+ projectPath: string;
25
+ uuid: string;
26
+ formattedTime?: string;
27
+ timeAgo?: string;
28
+ localDate?: string;
29
+ metadata?: {
30
+ usage?: any;
31
+ totalCostUsd?: number;
32
+ numTurns?: number;
33
+ durationMs?: number;
34
+ isError?: boolean;
35
+ errorType?: string;
36
+ model?: string;
37
+ requestId?: string;
38
+ };
39
+ }
40
+ export interface PaginatedConversationResponse {
41
+ entries: ConversationEntry[];
42
+ pagination: {
43
+ total_count: number;
44
+ limit: number;
45
+ offset: number;
46
+ has_more: boolean;
47
+ };
48
+ }
49
+ export interface HistoryQueryOptions {
50
+ sessionId?: string;
51
+ startDate?: string;
52
+ endDate?: string;
53
+ limit?: number;
54
+ offset?: number;
55
+ timezone?: string;
56
+ messageTypes?: ('user' | 'assistant' | 'system' | 'result')[];
57
+ }
58
+ export interface SessionListOptions {
59
+ projectPath?: string;
60
+ startDate?: string;
61
+ endDate?: string;
62
+ timezone?: string;
63
+ }
64
+ export interface ProjectInfo {
65
+ projectPath: string;
66
+ sessionCount: number;
67
+ messageCount: number;
68
+ lastActivityTime: string;
69
+ }
70
+ export interface SessionInfo {
71
+ sessionId: string;
72
+ projectPath: string;
73
+ startTime: string;
74
+ endTime: string;
75
+ messageCount: number;
76
+ userMessageCount: number;
77
+ assistantMessageCount: number;
78
+ /** First user message preview (truncated to ~100 chars) */
79
+ firstUserMessage?: string;
80
+ /** Duration in milliseconds */
81
+ durationMs?: number;
82
+ /** Human-readable duration (e.g., "5m 30s") */
83
+ durationFormatted?: string;
84
+ /** Session status indicators */
85
+ hasErrors?: boolean;
86
+ /** Project name extracted from path (basename) */
87
+ projectName?: string;
88
+ }
89
+ export interface SearchOptions {
90
+ limit?: number;
91
+ projectPath?: string;
92
+ startDate?: string;
93
+ endDate?: string;
94
+ timezone?: string;
95
+ }
96
+ export interface CurrentSessionInfo {
97
+ sessionId: string;
98
+ timestamp: string;
99
+ projectPath?: string;
100
+ display?: string;
101
+ }
102
+ export interface SessionProcessInfo {
103
+ sessionId: string;
104
+ pid: number;
105
+ command: string;
106
+ alive: boolean;
107
+ }
108
+ export interface RecentActivityOptions {
109
+ limit?: number;
110
+ includeSummaries?: boolean;
111
+ }
112
+ export interface RecentActivityItem {
113
+ sessionId: string;
114
+ projectPath: string;
115
+ projectName: string;
116
+ timestamp: string;
117
+ /** First user message - what was asked */
118
+ asked: string;
119
+ /** Brief summary from assistant messages - what was done */
120
+ done?: string;
121
+ /** Human-readable relative time */
122
+ timeAgo: string;
123
+ }
124
+ export declare class ClaudeCodeHistoryService {
125
+ private claudeDir;
126
+ constructor(claudeDir?: string);
127
+ /**
128
+ * Normalize date string to ISO format for proper comparison with timezone support
129
+ */
130
+ private normalizeDate;
131
+ getConversationHistory(options?: HistoryQueryOptions): Promise<PaginatedConversationResponse>;
132
+ searchConversations(searchQuery: string, options?: SearchOptions): Promise<ConversationEntry[]>;
133
+ listProjects(): Promise<ProjectInfo[]>;
134
+ listSessions(options?: SessionListOptions): Promise<SessionInfo[]>;
135
+ /**
136
+ * Fast path: List sessions using the Rust parser
137
+ * Groups entries by session_id from fast parser results
138
+ */
139
+ private listSessionsFast;
140
+ /**
141
+ * Get recent activity across all projects
142
+ * Returns what was asked, what was done, and when for the most recent sessions
143
+ */
144
+ getRecentActivity(options?: RecentActivityOptions): Promise<RecentActivityItem[]>;
145
+ /**
146
+ * Generate a brief summary of what was done in a session from assistant messages
147
+ */
148
+ private generateSessionSummary;
149
+ private loadClaudeHistoryEntries;
150
+ private parseJsonlFile;
151
+ private convertClaudeMessageToEntry;
152
+ private getTimeAgo;
153
+ /**
154
+ * Format duration in milliseconds to human-readable string
155
+ */
156
+ private formatDuration;
157
+ private decodeProjectPath;
158
+ /**
159
+ * Determines whether to skip reading a file based on its modification time
160
+ */
161
+ private shouldSkipFile;
162
+ /**
163
+ * Gets the current active Claude Code session by reading the last line from history.jsonl
164
+ */
165
+ getCurrentSession(): Promise<CurrentSessionInfo | null>;
166
+ /**
167
+ * Maps a process ID to a Claude Code session by examining the process tree
168
+ */
169
+ getSessionByPid(pid: number): Promise<SessionProcessInfo | null>;
170
+ /**
171
+ * Lists all session UUIDs from the session-env directory
172
+ */
173
+ listAllSessionUuids(): Promise<string[]>;
174
+ /**
175
+ * Reads only the last line from a file efficiently
176
+ */
177
+ private readLastLineFromFile;
178
+ /**
179
+ * Extracts session ID from a Claude Code process by examining command and environment
180
+ */
181
+ private extractSessionIdFromProcess;
182
+ /**
183
+ * Checks if a process is still alive
184
+ */
185
+ private isProcessAlive;
186
+ }
187
+ //# sourceMappingURL=history-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"history-service.d.ts","sourceRoot":"","sources":["../src/history-service.ts"],"names":[],"mappings":"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"}