@cmdctrl/claude-code 0.1.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.
- package/dist/adapter/claude-cli.d.ts +41 -0
- package/dist/adapter/claude-cli.d.ts.map +1 -0
- package/dist/adapter/claude-cli.js +525 -0
- package/dist/adapter/claude-cli.js.map +1 -0
- package/dist/adapter/events.d.ts +52 -0
- package/dist/adapter/events.d.ts.map +1 -0
- package/dist/adapter/events.js +134 -0
- package/dist/adapter/events.js.map +1 -0
- package/dist/client/messages.d.ts +140 -0
- package/dist/client/messages.d.ts.map +1 -0
- package/dist/client/messages.js +6 -0
- package/dist/client/messages.js.map +1 -0
- package/dist/client/websocket.d.ts +115 -0
- package/dist/client/websocket.d.ts.map +1 -0
- package/dist/client/websocket.js +434 -0
- package/dist/client/websocket.js.map +1 -0
- package/dist/commands/register.d.ts +10 -0
- package/dist/commands/register.d.ts.map +1 -0
- package/dist/commands/register.js +175 -0
- package/dist/commands/register.js.map +1 -0
- package/dist/commands/start.d.ts +9 -0
- package/dist/commands/start.d.ts.map +1 -0
- package/dist/commands/start.js +54 -0
- package/dist/commands/start.js.map +1 -0
- package/dist/commands/status.d.ts +5 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +38 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/stop.d.ts +5 -0
- package/dist/commands/stop.d.ts.map +1 -0
- package/dist/commands/stop.js +59 -0
- package/dist/commands/stop.js.map +1 -0
- package/dist/commands/unregister.d.ts +5 -0
- package/dist/commands/unregister.d.ts.map +1 -0
- package/dist/commands/unregister.js +28 -0
- package/dist/commands/unregister.js.map +1 -0
- package/dist/config/config.d.ts +68 -0
- package/dist/config/config.d.ts.map +1 -0
- package/dist/config/config.js +193 -0
- package/dist/config/config.js.map +1 -0
- package/dist/handlers/context-handler.d.ts +37 -0
- package/dist/handlers/context-handler.d.ts.map +1 -0
- package/dist/handlers/context-handler.js +303 -0
- package/dist/handlers/context-handler.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +39 -0
- package/dist/index.js.map +1 -0
- package/dist/message-reader.d.ts +25 -0
- package/dist/message-reader.d.ts.map +1 -0
- package/dist/message-reader.js +454 -0
- package/dist/message-reader.js.map +1 -0
- package/dist/session-discovery.d.ts +48 -0
- package/dist/session-discovery.d.ts.map +1 -0
- package/dist/session-discovery.js +496 -0
- package/dist/session-discovery.js.map +1 -0
- package/dist/session-watcher.d.ts +92 -0
- package/dist/session-watcher.d.ts.map +1 -0
- package/dist/session-watcher.js +494 -0
- package/dist/session-watcher.js.map +1 -0
- package/dist/session-watcher.test.d.ts +9 -0
- package/dist/session-watcher.test.d.ts.map +1 -0
- package/dist/session-watcher.test.js +149 -0
- package/dist/session-watcher.test.js.map +1 -0
- package/jest.config.js +8 -0
- package/package.json +42 -0
- package/src/adapter/claude-cli.ts +591 -0
- package/src/adapter/events.ts +186 -0
- package/src/client/messages.ts +193 -0
- package/src/client/websocket.ts +509 -0
- package/src/commands/register.ts +201 -0
- package/src/commands/start.ts +70 -0
- package/src/commands/status.ts +47 -0
- package/src/commands/stop.ts +58 -0
- package/src/commands/unregister.ts +30 -0
- package/src/config/config.ts +163 -0
- package/src/handlers/context-handler.ts +337 -0
- package/src/index.ts +45 -0
- package/src/message-reader.ts +485 -0
- package/src/session-discovery.ts +557 -0
- package/src/session-watcher.test.ts +141 -0
- package/src/session-watcher.ts +560 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* JSONL message reader with pagination support
|
|
4
|
+
* Reads messages from Claude Code session files
|
|
5
|
+
*/
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
18
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
19
|
+
}) : function(o, v) {
|
|
20
|
+
o["default"] = v;
|
|
21
|
+
});
|
|
22
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
23
|
+
var ownKeys = function(o) {
|
|
24
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
25
|
+
var ar = [];
|
|
26
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
27
|
+
return ar;
|
|
28
|
+
};
|
|
29
|
+
return ownKeys(o);
|
|
30
|
+
};
|
|
31
|
+
return function (mod) {
|
|
32
|
+
if (mod && mod.__esModule) return mod;
|
|
33
|
+
var result = {};
|
|
34
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
35
|
+
__setModuleDefault(result, mod);
|
|
36
|
+
return result;
|
|
37
|
+
};
|
|
38
|
+
})();
|
|
39
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
exports.findSessionFile = findSessionFile;
|
|
41
|
+
exports.readMessages = readMessages;
|
|
42
|
+
const fs = __importStar(require("fs"));
|
|
43
|
+
const path = __importStar(require("path"));
|
|
44
|
+
const os = __importStar(require("os"));
|
|
45
|
+
// Size of chunks to read when scanning for messages
|
|
46
|
+
const CHUNK_SIZE = 64 * 1024; // 64KB
|
|
47
|
+
// Safety limits to prevent memory exhaustion from bloated sessions (e.g., sessions with many large images)
|
|
48
|
+
const MAX_FILE_SIZE = 20 * 1024 * 1024; // 20MB - warn threshold for large files
|
|
49
|
+
const MAX_LINE_SIZE = 100 * 1024; // 100KB - truncate lines larger than this (likely contain base64 images)
|
|
50
|
+
const LINE_TAIL_SIZE = 1024; // 1KB - also capture tail of long lines (uuid, timestamp are at the end)
|
|
51
|
+
const TRUNCATED_LINE_MARKER = '\x00TRUNCATED\x00'; // Marker added to truncated lines
|
|
52
|
+
const TRUNCATED_MID_MARKER = '\x00MID\x00'; // Separator between head and tail of truncated lines
|
|
53
|
+
/**
|
|
54
|
+
* Extract readable text from message content (handles string or array of content blocks)
|
|
55
|
+
*/
|
|
56
|
+
function extractReadableText(content) {
|
|
57
|
+
// Simple string
|
|
58
|
+
if (typeof content === 'string') {
|
|
59
|
+
return content.trim();
|
|
60
|
+
}
|
|
61
|
+
// Array of content blocks (Claude format)
|
|
62
|
+
if (Array.isArray(content)) {
|
|
63
|
+
const textParts = [];
|
|
64
|
+
for (const block of content) {
|
|
65
|
+
if (typeof block === 'string') {
|
|
66
|
+
textParts.push(block);
|
|
67
|
+
}
|
|
68
|
+
else if (block && typeof block === 'object') {
|
|
69
|
+
// Text block: { type: 'text', text: '...' }
|
|
70
|
+
if (block.type === 'text' && typeof block.text === 'string') {
|
|
71
|
+
textParts.push(block.text);
|
|
72
|
+
}
|
|
73
|
+
// Skip tool_use, tool_result, image blocks etc.
|
|
74
|
+
// Tool calls are shown as verbose output during execution, not as permanent messages
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return textParts.join(' ').trim();
|
|
78
|
+
}
|
|
79
|
+
// Object with text property
|
|
80
|
+
if (content && typeof content === 'object' && 'text' in content) {
|
|
81
|
+
const text = content.text;
|
|
82
|
+
if (typeof text === 'string') {
|
|
83
|
+
return text.trim();
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return '';
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Detect Claude Code compaction/summary messages and system notifications
|
|
90
|
+
* Note: Most bash-notification entries are type:"queue-operation" (filtered by type),
|
|
91
|
+
* but some appear as type:"user" with <bash-notification> content
|
|
92
|
+
*/
|
|
93
|
+
function isSystemMessage(content) {
|
|
94
|
+
const systemPrefixes = [
|
|
95
|
+
'This session is being continued from a previous conversation',
|
|
96
|
+
'This conversation is being continued from a previous session',
|
|
97
|
+
'<system-reminder>',
|
|
98
|
+
'<bash-notification>',
|
|
99
|
+
];
|
|
100
|
+
for (const prefix of systemPrefixes) {
|
|
101
|
+
if (content.startsWith(prefix)) {
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Find the JSONL file for a given session ID
|
|
109
|
+
*/
|
|
110
|
+
function findSessionFile(sessionId) {
|
|
111
|
+
const claudeDir = path.join(os.homedir(), '.claude', 'projects');
|
|
112
|
+
if (!fs.existsSync(claudeDir)) {
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
const fileName = `${sessionId}.jsonl`;
|
|
116
|
+
const entries = fs.readdirSync(claudeDir, { withFileTypes: true });
|
|
117
|
+
for (const entry of entries) {
|
|
118
|
+
if (!entry.isDirectory())
|
|
119
|
+
continue;
|
|
120
|
+
const filePath = path.join(claudeDir, entry.name, fileName);
|
|
121
|
+
if (fs.existsSync(filePath)) {
|
|
122
|
+
return filePath;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Parse a JSONL line into a MessageEntry if it's a displayable message
|
|
129
|
+
* For truncated lines (marked with TRUNCATED_LINE_MARKER), we extract UUID via regex
|
|
130
|
+
* and return a placeholder message instead of the full content
|
|
131
|
+
*/
|
|
132
|
+
function parseLineToMessage(line, index) {
|
|
133
|
+
try {
|
|
134
|
+
// Check if this line was truncated by the streaming reader
|
|
135
|
+
const isTruncated = line.endsWith(TRUNCATED_LINE_MARKER);
|
|
136
|
+
let entry;
|
|
137
|
+
if (isTruncated) {
|
|
138
|
+
// Truncated line format: {head}TRUNCATED_MID_MARKER{tail}TRUNCATED_LINE_MARKER
|
|
139
|
+
// - head contains: type (near start)
|
|
140
|
+
// - tail contains: uuid, timestamp (at end of original line)
|
|
141
|
+
const lineWithoutEndMarker = line.slice(0, -TRUNCATED_LINE_MARKER.length);
|
|
142
|
+
const midIndex = lineWithoutEndMarker.indexOf(TRUNCATED_MID_MARKER);
|
|
143
|
+
let headPart;
|
|
144
|
+
let tailPart;
|
|
145
|
+
if (midIndex >= 0) {
|
|
146
|
+
headPart = lineWithoutEndMarker.slice(0, midIndex);
|
|
147
|
+
tailPart = lineWithoutEndMarker.slice(midIndex + TRUNCATED_MID_MARKER.length);
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
// Old format (no mid marker) - only have head
|
|
151
|
+
headPart = lineWithoutEndMarker;
|
|
152
|
+
tailPart = '';
|
|
153
|
+
}
|
|
154
|
+
// Type is in the head
|
|
155
|
+
const typeMatch = headPart.match(/"type"\s*:\s*"([^"]+)"/);
|
|
156
|
+
// UUID is in the tail (or occasionally in head if line wasn't too long)
|
|
157
|
+
const uuidMatch = tailPart.match(/"uuid"\s*:\s*"([^"]+)"/)
|
|
158
|
+
|| headPart.match(/"uuid"\s*:\s*"([^"]+)"/);
|
|
159
|
+
// Timestamp is also in the tail
|
|
160
|
+
const timestampMatch = tailPart.match(/"timestamp"\s*:\s*"([^"]+)"/);
|
|
161
|
+
if (!uuidMatch || !typeMatch) {
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
const type = typeMatch[1];
|
|
165
|
+
if (type !== 'user' && type !== 'assistant') {
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
// Return a placeholder for truncated messages (they contain images we can't display anyway)
|
|
169
|
+
return {
|
|
170
|
+
uuid: uuidMatch[1],
|
|
171
|
+
role: type === 'user' ? 'USER' : 'AGENT',
|
|
172
|
+
content: '[Message contains large content]',
|
|
173
|
+
timestamp: timestampMatch ? timestampMatch[1] : new Date().toISOString(),
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
entry = JSON.parse(line);
|
|
177
|
+
// Only process user and assistant messages
|
|
178
|
+
if (entry.type !== 'user' && entry.type !== 'assistant') {
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
// Extract content
|
|
182
|
+
const text = entry.message?.content
|
|
183
|
+
? extractReadableText(entry.message.content)
|
|
184
|
+
: '';
|
|
185
|
+
// Skip entries with no displayable text
|
|
186
|
+
if (!text) {
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
// Determine role
|
|
190
|
+
let role = entry.type === 'user' ? 'USER' : 'AGENT';
|
|
191
|
+
// Detect system messages (compaction, bash notifications, etc.)
|
|
192
|
+
if (role === 'USER' && isSystemMessage(text)) {
|
|
193
|
+
role = 'SYSTEM';
|
|
194
|
+
}
|
|
195
|
+
return {
|
|
196
|
+
uuid: entry.uuid || `generated-${index}`,
|
|
197
|
+
role,
|
|
198
|
+
content: text,
|
|
199
|
+
timestamp: entry.timestamp || new Date().toISOString(),
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
catch {
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Truncate a line, keeping both head (for type) and tail (for uuid, timestamp)
|
|
208
|
+
* Format: {head}TRUNCATED_MID_MARKER{tail}TRUNCATED_LINE_MARKER
|
|
209
|
+
*/
|
|
210
|
+
function truncateLine(line) {
|
|
211
|
+
const head = line.substring(0, MAX_LINE_SIZE);
|
|
212
|
+
const tail = line.substring(Math.max(MAX_LINE_SIZE, line.length - LINE_TAIL_SIZE));
|
|
213
|
+
return head + TRUNCATED_MID_MARKER + tail + TRUNCATED_LINE_MARKER;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Read the last N lines from a file using backward reading (tail-like)
|
|
217
|
+
* This is much faster than reading the entire file for large files
|
|
218
|
+
*/
|
|
219
|
+
function readLastLines(filePath, maxLines) {
|
|
220
|
+
const fd = fs.openSync(filePath, 'r');
|
|
221
|
+
const stats = fs.fstatSync(fd);
|
|
222
|
+
const fileSize = stats.size;
|
|
223
|
+
if (fileSize === 0) {
|
|
224
|
+
fs.closeSync(fd);
|
|
225
|
+
return [];
|
|
226
|
+
}
|
|
227
|
+
const lines = [];
|
|
228
|
+
let position = fileSize;
|
|
229
|
+
let buffer = '';
|
|
230
|
+
// We need to read more lines than requested because many JSONL entries
|
|
231
|
+
// won't be displayable messages (tool_use, system events, etc.)
|
|
232
|
+
// Multiplier of 10x accounts for ~10% of entries being actual messages
|
|
233
|
+
const targetLines = maxLines * 10;
|
|
234
|
+
while (position > 0 && lines.length < targetLines) {
|
|
235
|
+
// Read in chunks from the end
|
|
236
|
+
const chunkSize = Math.min(CHUNK_SIZE, position);
|
|
237
|
+
position -= chunkSize;
|
|
238
|
+
const chunk = Buffer.alloc(chunkSize);
|
|
239
|
+
fs.readSync(fd, chunk, 0, chunkSize, position);
|
|
240
|
+
buffer = chunk.toString('utf-8') + buffer;
|
|
241
|
+
// Extract complete lines from buffer
|
|
242
|
+
const newlineIndex = buffer.lastIndexOf('\n');
|
|
243
|
+
if (newlineIndex !== -1) {
|
|
244
|
+
// Split into lines, keeping the incomplete first line in buffer
|
|
245
|
+
const completeLines = buffer.substring(0, newlineIndex).split('\n');
|
|
246
|
+
buffer = buffer.substring(newlineIndex + 1);
|
|
247
|
+
// Add lines in reverse order (we're reading backward)
|
|
248
|
+
for (let i = completeLines.length - 1; i >= 0; i--) {
|
|
249
|
+
const line = completeLines[i].trim();
|
|
250
|
+
if (line) {
|
|
251
|
+
// For oversized lines, keep both head and tail
|
|
252
|
+
if (line.length > MAX_LINE_SIZE) {
|
|
253
|
+
lines.unshift(truncateLine(line));
|
|
254
|
+
}
|
|
255
|
+
else {
|
|
256
|
+
lines.unshift(line);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
// Don't forget any remaining content in buffer
|
|
263
|
+
const trimmedBuffer = buffer.trim();
|
|
264
|
+
if (trimmedBuffer) {
|
|
265
|
+
if (trimmedBuffer.length > MAX_LINE_SIZE) {
|
|
266
|
+
lines.unshift(truncateLine(trimmedBuffer));
|
|
267
|
+
}
|
|
268
|
+
else {
|
|
269
|
+
lines.unshift(trimmedBuffer);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
fs.closeSync(fd);
|
|
273
|
+
return lines;
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Read all lines from a file (streaming approach)
|
|
277
|
+
* For oversized lines, keeps both head (for type) and tail (for uuid, timestamp)
|
|
278
|
+
* Format for truncated: {head}TRUNCATED_MID_MARKER{tail}TRUNCATED_LINE_MARKER
|
|
279
|
+
* Safer than fs.readFileSync for files with potentially huge lines
|
|
280
|
+
*/
|
|
281
|
+
function readAllLinesSafe(filePath) {
|
|
282
|
+
const stats = fs.statSync(filePath);
|
|
283
|
+
// For very large files, warn but still try to process
|
|
284
|
+
if (stats.size > MAX_FILE_SIZE) {
|
|
285
|
+
console.warn(`[MessageReader] File ${filePath} is ${(stats.size / 1024 / 1024).toFixed(1)}MB, exceeds ${MAX_FILE_SIZE / 1024 / 1024}MB limit. Processing may be slow.`);
|
|
286
|
+
}
|
|
287
|
+
const lines = [];
|
|
288
|
+
const fd = fs.openSync(filePath, 'r');
|
|
289
|
+
let position = 0;
|
|
290
|
+
let currentLineHead = ''; // First MAX_LINE_SIZE chars
|
|
291
|
+
let currentLineTail = ''; // Last LINE_TAIL_SIZE chars (sliding window)
|
|
292
|
+
let lineOverflowed = false;
|
|
293
|
+
try {
|
|
294
|
+
while (position < stats.size) {
|
|
295
|
+
const chunkSize = Math.min(CHUNK_SIZE, stats.size - position);
|
|
296
|
+
const chunk = Buffer.alloc(chunkSize);
|
|
297
|
+
fs.readSync(fd, chunk, 0, chunkSize, position);
|
|
298
|
+
position += chunkSize;
|
|
299
|
+
const text = chunk.toString('utf-8');
|
|
300
|
+
for (let i = 0; i < text.length; i++) {
|
|
301
|
+
const char = text[i];
|
|
302
|
+
if (char === '\n') {
|
|
303
|
+
const trimmedHead = currentLineHead.trim();
|
|
304
|
+
if (trimmedHead) {
|
|
305
|
+
// For truncated lines, include both head and tail with markers
|
|
306
|
+
if (lineOverflowed) {
|
|
307
|
+
lines.push(trimmedHead + TRUNCATED_MID_MARKER + currentLineTail.trim() + TRUNCATED_LINE_MARKER);
|
|
308
|
+
}
|
|
309
|
+
else {
|
|
310
|
+
lines.push(trimmedHead);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
currentLineHead = '';
|
|
314
|
+
currentLineTail = '';
|
|
315
|
+
lineOverflowed = false;
|
|
316
|
+
}
|
|
317
|
+
else {
|
|
318
|
+
// Keep building head up to MAX_LINE_SIZE
|
|
319
|
+
if (currentLineHead.length < MAX_LINE_SIZE) {
|
|
320
|
+
currentLineHead += char;
|
|
321
|
+
}
|
|
322
|
+
else {
|
|
323
|
+
// Once overflowed, start tracking the tail (sliding window)
|
|
324
|
+
lineOverflowed = true;
|
|
325
|
+
currentLineTail += char;
|
|
326
|
+
// Keep only the last LINE_TAIL_SIZE chars
|
|
327
|
+
if (currentLineTail.length > LINE_TAIL_SIZE) {
|
|
328
|
+
currentLineTail = currentLineTail.slice(-LINE_TAIL_SIZE);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
// Handle final line without newline
|
|
335
|
+
const trimmedHead = currentLineHead.trim();
|
|
336
|
+
if (trimmedHead) {
|
|
337
|
+
if (lineOverflowed) {
|
|
338
|
+
lines.push(trimmedHead + TRUNCATED_MID_MARKER + currentLineTail.trim() + TRUNCATED_LINE_MARKER);
|
|
339
|
+
}
|
|
340
|
+
else {
|
|
341
|
+
lines.push(trimmedHead);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
finally {
|
|
346
|
+
fs.closeSync(fd);
|
|
347
|
+
}
|
|
348
|
+
return lines;
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Read messages from a session JSONL file
|
|
352
|
+
*
|
|
353
|
+
* @param sessionId - The session ID to read
|
|
354
|
+
* @param limit - Maximum number of messages to return
|
|
355
|
+
* @param beforeUuid - Optional UUID cursor - returns messages before this one (for loading older)
|
|
356
|
+
* @param afterUuid - Optional UUID cursor - returns messages after this one (for loading newer)
|
|
357
|
+
* @returns Messages array, has_more flag, oldest/newest UUIDs
|
|
358
|
+
*/
|
|
359
|
+
function readMessages(sessionId, limit, beforeUuid, afterUuid) {
|
|
360
|
+
const filePath = findSessionFile(sessionId);
|
|
361
|
+
if (!filePath) {
|
|
362
|
+
return { messages: [], hasMore: false };
|
|
363
|
+
}
|
|
364
|
+
// Fast path: no cursor, just want last N messages
|
|
365
|
+
// Use tail-like reading to avoid loading entire file
|
|
366
|
+
if (!beforeUuid && !afterUuid) {
|
|
367
|
+
const lines = readLastLines(filePath, limit);
|
|
368
|
+
// Parse ALL lines to messages (lines are oldest-to-newest)
|
|
369
|
+
// We must process all lines to find the most recent displayable messages
|
|
370
|
+
const messages = [];
|
|
371
|
+
for (let i = 0; i < lines.length; i++) {
|
|
372
|
+
const msg = parseLineToMessage(lines[i], i);
|
|
373
|
+
if (msg) {
|
|
374
|
+
messages.push(msg);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
// Take the last 'limit' messages (they're in chronological order)
|
|
378
|
+
const resultMessages = messages.slice(-limit);
|
|
379
|
+
// We have "more" if we found more messages than the limit
|
|
380
|
+
const hasMore = messages.length > limit;
|
|
381
|
+
return {
|
|
382
|
+
messages: resultMessages,
|
|
383
|
+
hasMore,
|
|
384
|
+
oldestUuid: resultMessages.length > 0 ? resultMessages[0].uuid : undefined,
|
|
385
|
+
newestUuid: resultMessages.length > 0 ? resultMessages[resultMessages.length - 1].uuid : undefined,
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
// Slow path: cursor-based pagination requires reading the full file
|
|
389
|
+
// to find the cursor position accurately
|
|
390
|
+
// Use safe reader that skips oversized lines (e.g., base64 images)
|
|
391
|
+
const lines = readAllLinesSafe(filePath);
|
|
392
|
+
// Parse all message entries
|
|
393
|
+
const allMessages = [];
|
|
394
|
+
for (let i = 0; i < lines.length; i++) {
|
|
395
|
+
const msg = parseLineToMessage(lines[i], i);
|
|
396
|
+
if (msg) {
|
|
397
|
+
allMessages.push(msg);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
// Handle afterUuid - return messages AFTER the given UUID (for incremental updates)
|
|
401
|
+
if (afterUuid) {
|
|
402
|
+
const cursorIndex = allMessages.findIndex(m => m.uuid === afterUuid);
|
|
403
|
+
if (cursorIndex >= 0) {
|
|
404
|
+
// Get messages after the cursor
|
|
405
|
+
const startIndex = cursorIndex + 1;
|
|
406
|
+
const endIndex = Math.min(startIndex + limit, allMessages.length);
|
|
407
|
+
const resultMessages = allMessages.slice(startIndex, endIndex);
|
|
408
|
+
const hasMore = endIndex < allMessages.length;
|
|
409
|
+
return {
|
|
410
|
+
messages: resultMessages,
|
|
411
|
+
hasMore,
|
|
412
|
+
oldestUuid: resultMessages.length > 0 ? resultMessages[0].uuid : undefined,
|
|
413
|
+
newestUuid: resultMessages.length > 0 ? resultMessages[resultMessages.length - 1].uuid : undefined,
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
// Stale cursor (likely compacted away) - fall back to returning latest messages
|
|
417
|
+
// This ensures clients get current data even after session compaction
|
|
418
|
+
const endIndex = allMessages.length;
|
|
419
|
+
const beginIndex = Math.max(0, endIndex - limit);
|
|
420
|
+
const resultMessages = allMessages.slice(beginIndex, endIndex);
|
|
421
|
+
const hasMore = beginIndex > 0;
|
|
422
|
+
return {
|
|
423
|
+
messages: resultMessages,
|
|
424
|
+
hasMore,
|
|
425
|
+
oldestUuid: resultMessages.length > 0 ? resultMessages[0].uuid : undefined,
|
|
426
|
+
newestUuid: resultMessages.length > 0 ? resultMessages[resultMessages.length - 1].uuid : undefined,
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
// Handle beforeUuid - return messages BEFORE the given UUID (for loading older)
|
|
430
|
+
let startIndex = allMessages.length;
|
|
431
|
+
if (beforeUuid) {
|
|
432
|
+
const cursorIndex = allMessages.findIndex(m => m.uuid === beforeUuid);
|
|
433
|
+
if (cursorIndex >= 0) {
|
|
434
|
+
startIndex = cursorIndex;
|
|
435
|
+
}
|
|
436
|
+
else {
|
|
437
|
+
// Stale cursor (likely compacted away) - return empty for "load older"
|
|
438
|
+
// User's current view may be outdated; they should refresh to get current messages
|
|
439
|
+
return { messages: [], hasMore: false };
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
// Get messages before the cursor (or from end if no cursor)
|
|
443
|
+
const endIndex = startIndex;
|
|
444
|
+
const beginIndex = Math.max(0, endIndex - limit);
|
|
445
|
+
const resultMessages = allMessages.slice(beginIndex, endIndex);
|
|
446
|
+
const hasMore = beginIndex > 0;
|
|
447
|
+
return {
|
|
448
|
+
messages: resultMessages,
|
|
449
|
+
hasMore,
|
|
450
|
+
oldestUuid: resultMessages.length > 0 ? resultMessages[0].uuid : undefined,
|
|
451
|
+
newestUuid: resultMessages.length > 0 ? resultMessages[resultMessages.length - 1].uuid : undefined,
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
//# sourceMappingURL=message-reader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message-reader.js","sourceRoot":"","sources":["../src/message-reader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export interface ExternalSession {
|
|
2
|
+
session_id: string;
|
|
3
|
+
slug: string;
|
|
4
|
+
title: string;
|
|
5
|
+
project: string;
|
|
6
|
+
project_name: string;
|
|
7
|
+
file_path: string;
|
|
8
|
+
last_message: string;
|
|
9
|
+
last_activity: string;
|
|
10
|
+
is_active: boolean;
|
|
11
|
+
message_count: number;
|
|
12
|
+
}
|
|
13
|
+
export interface ExternalSessionsByProject {
|
|
14
|
+
project: string;
|
|
15
|
+
project_name: string;
|
|
16
|
+
sessions: ExternalSession[];
|
|
17
|
+
}
|
|
18
|
+
export interface SessionEntry {
|
|
19
|
+
type: string;
|
|
20
|
+
sessionId?: string;
|
|
21
|
+
slug?: string;
|
|
22
|
+
cwd?: string;
|
|
23
|
+
timestamp?: string;
|
|
24
|
+
message?: {
|
|
25
|
+
role?: string;
|
|
26
|
+
content?: string | any;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Discover all Claude Code sessions on this device
|
|
31
|
+
*
|
|
32
|
+
* Uses sessions-index.json for efficiency when available (one file read per project
|
|
33
|
+
* instead of 64KB per session). Falls back to parsing individual files if index
|
|
34
|
+
* is missing or stale.
|
|
35
|
+
*/
|
|
36
|
+
export declare function discoverSessions(excludeSessionIDs?: Set<string>): Promise<ExternalSession[]>;
|
|
37
|
+
/**
|
|
38
|
+
* Group sessions by project
|
|
39
|
+
*/
|
|
40
|
+
export declare function groupByProject(sessions: ExternalSession[]): ExternalSessionsByProject[];
|
|
41
|
+
/**
|
|
42
|
+
* Discover projects (directories in ~/.claude/projects/)
|
|
43
|
+
*/
|
|
44
|
+
export declare function discoverProjects(): {
|
|
45
|
+
path: string;
|
|
46
|
+
name: string;
|
|
47
|
+
}[];
|
|
48
|
+
//# sourceMappingURL=session-discovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-discovery.d.ts","sourceRoot":"","sources":["../src/session-discovery.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,eAAe,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE;QACR,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC;KACxB,CAAC;CACH;AAkJD;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CAAC,iBAAiB,GAAE,GAAG,CAAC,MAAM,CAAa,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CA0L7G;AAkID;;GAEG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,eAAe,EAAE,GAAG,yBAAyB,EAAE,CAiBvF;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,CAoBnE"}
|