genbox-agent 1.0.134 → 1.0.136

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.
Files changed (70) hide show
  1. package/dist/logging/activity-logger.d.ts +159 -0
  2. package/dist/logging/activity-logger.d.ts.map +1 -0
  3. package/dist/logging/activity-logger.js +513 -0
  4. package/dist/logging/activity-logger.js.map +1 -0
  5. package/dist/logging/index.d.ts +7 -0
  6. package/dist/logging/index.d.ts.map +1 -0
  7. package/dist/logging/index.js +15 -0
  8. package/dist/logging/index.js.map +1 -0
  9. package/dist/providers/base-provider.d.ts +1 -1
  10. package/dist/providers/base-provider.d.ts.map +1 -1
  11. package/dist/providers/base-provider.js +32 -3
  12. package/dist/providers/base-provider.js.map +1 -1
  13. package/dist/providers/claude-provider.d.ts.map +1 -1
  14. package/dist/providers/claude-provider.js +11 -11
  15. package/dist/providers/claude-provider.js.map +1 -1
  16. package/dist/providers/gemini-provider.d.ts +1 -0
  17. package/dist/providers/gemini-provider.d.ts.map +1 -1
  18. package/dist/providers/gemini-provider.js +23 -18
  19. package/dist/providers/gemini-provider.js.map +1 -1
  20. package/dist/readers/claude-jsonl-reader.d.ts.map +1 -1
  21. package/dist/readers/claude-jsonl-reader.js +56 -0
  22. package/dist/readers/claude-jsonl-reader.js.map +1 -1
  23. package/dist/readers/claude-session-reader.d.ts +2 -0
  24. package/dist/readers/claude-session-reader.d.ts.map +1 -1
  25. package/dist/readers/claude-session-reader.js +51 -0
  26. package/dist/readers/claude-session-reader.js.map +1 -1
  27. package/dist/server/index.d.ts +39 -0
  28. package/dist/server/index.d.ts.map +1 -1
  29. package/dist/server/index.js +490 -84
  30. package/dist/server/index.js.map +1 -1
  31. package/dist/storage/manager.d.ts +2 -0
  32. package/dist/storage/manager.d.ts.map +1 -1
  33. package/dist/storage/manager.js +126 -10
  34. package/dist/storage/manager.js.map +1 -1
  35. package/dist/storage/repositories/messages.d.ts +5 -0
  36. package/dist/storage/repositories/messages.d.ts.map +1 -1
  37. package/dist/storage/repositories/messages.js +24 -0
  38. package/dist/storage/repositories/messages.js.map +1 -1
  39. package/dist/storage/repositories/sessions.d.ts +3 -0
  40. package/dist/storage/repositories/sessions.d.ts.map +1 -1
  41. package/dist/storage/repositories/sessions.js +6 -3
  42. package/dist/storage/repositories/sessions.js.map +1 -1
  43. package/dist/storage/schema.d.ts +1 -1
  44. package/dist/storage/schema.d.ts.map +1 -1
  45. package/dist/storage/schema.js +3 -0
  46. package/dist/storage/schema.js.map +1 -1
  47. package/dist/streaming/index.d.ts +40 -0
  48. package/dist/streaming/index.d.ts.map +1 -0
  49. package/dist/streaming/index.js +49 -0
  50. package/dist/streaming/index.js.map +1 -0
  51. package/dist/streaming/realtime-file-watcher.d.ts +84 -0
  52. package/dist/streaming/realtime-file-watcher.d.ts.map +1 -0
  53. package/dist/streaming/realtime-file-watcher.js +238 -0
  54. package/dist/streaming/realtime-file-watcher.js.map +1 -0
  55. package/dist/streaming/realtime-jsonl-streamer.d.ts +151 -0
  56. package/dist/streaming/realtime-jsonl-streamer.d.ts.map +1 -0
  57. package/dist/streaming/realtime-jsonl-streamer.js +659 -0
  58. package/dist/streaming/realtime-jsonl-streamer.js.map +1 -0
  59. package/dist/streaming/terminal-output-streamer.d.ts +106 -0
  60. package/dist/streaming/terminal-output-streamer.d.ts.map +1 -0
  61. package/dist/streaming/terminal-output-streamer.js +325 -0
  62. package/dist/streaming/terminal-output-streamer.js.map +1 -0
  63. package/dist/sync/continuous-jsonl-sync.d.ts +5 -0
  64. package/dist/sync/continuous-jsonl-sync.d.ts.map +1 -1
  65. package/dist/sync/continuous-jsonl-sync.js +141 -31
  66. package/dist/sync/continuous-jsonl-sync.js.map +1 -1
  67. package/dist/unified-daemon.d.ts.map +1 -1
  68. package/dist/unified-daemon.js +281 -12
  69. package/dist/unified-daemon.js.map +1 -1
  70. package/package.json +1 -1
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Activity Logger
3
+ *
4
+ * Comprehensive logging system for tracking all daemon activities.
5
+ * Supports two logging levels:
6
+ * - "basic": Session events, prompts (truncated), state changes
7
+ * - "rich": Full prompts, complete tool I/O, timing metrics, all details
8
+ *
9
+ * Logs are written to ~/.genbox/activity.log with automatic rotation.
10
+ */
11
+ export type LogLevel = 'off' | 'basic' | 'rich';
12
+ export interface LogEntry {
13
+ timestamp: string;
14
+ level: 'INFO' | 'DEBUG' | 'WARN' | 'ERROR';
15
+ category: string;
16
+ sessionId?: string;
17
+ message: string;
18
+ data?: Record<string, any>;
19
+ durationMs?: number;
20
+ }
21
+ export interface ActivityLoggerConfig {
22
+ /** Logging level: 'off', 'basic', or 'rich' */
23
+ logLevel: LogLevel;
24
+ /** Log file path (default: ~/.genbox/activity.log) */
25
+ logPath?: string;
26
+ /** Max file size in bytes before rotation (default: 10MB) */
27
+ maxFileSize?: number;
28
+ /** Number of rotated files to keep (default: 5) */
29
+ maxFiles?: number;
30
+ /** Also output to console (default: false) */
31
+ consoleOutput?: boolean;
32
+ }
33
+ declare class ActivityLogger {
34
+ private config;
35
+ private writeStream;
36
+ private currentFileSize;
37
+ private sessionTimers;
38
+ constructor(config?: Partial<ActivityLoggerConfig>);
39
+ /**
40
+ * Load log level from daemon config file
41
+ */
42
+ private loadConfigFromFile;
43
+ /**
44
+ * Update logging level at runtime
45
+ */
46
+ setLogLevel(level: LogLevel): void;
47
+ /**
48
+ * Get current log level
49
+ */
50
+ getLogLevel(): LogLevel;
51
+ /**
52
+ * Initialize the write stream
53
+ */
54
+ private ensureStream;
55
+ /**
56
+ * Rotate log files when size limit is reached
57
+ */
58
+ private rotateIfNeeded;
59
+ /**
60
+ * Write a log entry
61
+ */
62
+ private write;
63
+ /**
64
+ * Format a log entry as a single line
65
+ */
66
+ private formatEntry;
67
+ /**
68
+ * Get current timestamp
69
+ */
70
+ private now;
71
+ /**
72
+ * Truncate text for basic logging
73
+ */
74
+ private truncate;
75
+ /**
76
+ * Close the log file
77
+ */
78
+ close(): void;
79
+ info(category: string, message: string, data?: Record<string, any>, sessionId?: string): void;
80
+ debug(category: string, message: string, data?: Record<string, any>, sessionId?: string): void;
81
+ warn(category: string, message: string, data?: Record<string, any>, sessionId?: string): void;
82
+ error(category: string, message: string, error?: Error | any, sessionId?: string): void;
83
+ sessionCreated(sessionId: string, data: {
84
+ provider: string;
85
+ projectPath: string;
86
+ model?: string;
87
+ dtachSocket?: string;
88
+ }): void;
89
+ sessionEnded(sessionId: string, data?: {
90
+ reason?: string;
91
+ messageCount?: number;
92
+ totalTokens?: number;
93
+ costCents?: number;
94
+ }): void;
95
+ sessionStateChanged(sessionId: string, oldState: string | null, newState: string, toolName?: string): void;
96
+ /**
97
+ * Log when a turn is completed (Stop hook fired, Claude ready for new input)
98
+ */
99
+ turnCompleted(sessionId: string, data?: {
100
+ messageCount?: number;
101
+ toolUseCount?: number;
102
+ }): void;
103
+ /**
104
+ * Log when terminal output detects a state change
105
+ * This is the DEFINITIVE source for idle state detection
106
+ */
107
+ terminalStateDetected(sessionId: string, terminalState: string, mappedState: string): void;
108
+ promptReceived(sessionId: string, prompt: string, source: 'user' | 'api' | 'hook'): void;
109
+ promptSent(sessionId: string, prompt: string, success: boolean): void;
110
+ responseReceived(sessionId: string, data: {
111
+ role: 'user' | 'assistant';
112
+ contentPreview?: string;
113
+ inputTokens?: number;
114
+ outputTokens?: number;
115
+ costCents?: number;
116
+ hasToolUse?: boolean;
117
+ }): void;
118
+ toolStarted(sessionId: string, toolName: string, input?: any): void;
119
+ toolCompleted(sessionId: string, toolName: string, data?: {
120
+ success?: boolean;
121
+ durationMs?: number;
122
+ output?: any;
123
+ error?: string;
124
+ }): void;
125
+ subagentStarted(sessionId: string, agentId: string, description?: string): void;
126
+ subagentCompleted(sessionId: string, agentId: string, durationMs?: number): void;
127
+ jsonlSyncStarted(sessionId: string, filePath: string): void;
128
+ jsonlSyncCompleted(sessionId: string, data: {
129
+ messagesAdded: number;
130
+ bytesRead?: number;
131
+ durationMs?: number;
132
+ }): void;
133
+ hookEventReceived(sessionId: string, eventType: string, data?: any): void;
134
+ daemonStarted(genboxId: string, mode: 'native' | 'cloud'): void;
135
+ daemonStopped(): void;
136
+ serverStarted(port: number): void;
137
+ clientConnected(clientId: string): void;
138
+ clientDisconnected(clientId: string): void;
139
+ syncError(sessionId: string, error: Error | string, context?: string): void;
140
+ hookError(sessionId: string, error: Error | string, hookType?: string): void;
141
+ }
142
+ /**
143
+ * Get the activity logger singleton
144
+ */
145
+ export declare function getActivityLogger(config?: Partial<ActivityLoggerConfig>): ActivityLogger;
146
+ /**
147
+ * Update log level at runtime (called when user changes settings)
148
+ */
149
+ export declare function setActivityLogLevel(level: LogLevel): void;
150
+ /**
151
+ * Get current log level
152
+ */
153
+ export declare function getActivityLogLevel(): LogLevel;
154
+ /**
155
+ * Close the activity logger (on shutdown)
156
+ */
157
+ export declare function closeActivityLogger(): void;
158
+ export { ActivityLogger };
159
+ //# sourceMappingURL=activity-logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"activity-logger.d.ts","sourceRoot":"","sources":["../../src/logging/activity-logger.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,513 @@
1
+ "use strict";
2
+ /**
3
+ * Activity Logger
4
+ *
5
+ * Comprehensive logging system for tracking all daemon activities.
6
+ * Supports two logging levels:
7
+ * - "basic": Session events, prompts (truncated), state changes
8
+ * - "rich": Full prompts, complete tool I/O, timing metrics, all details
9
+ *
10
+ * Logs are written to ~/.genbox/activity.log with automatic rotation.
11
+ */
12
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ var desc = Object.getOwnPropertyDescriptor(m, k);
15
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
16
+ desc = { enumerable: true, get: function() { return m[k]; } };
17
+ }
18
+ Object.defineProperty(o, k2, desc);
19
+ }) : (function(o, m, k, k2) {
20
+ if (k2 === undefined) k2 = k;
21
+ o[k2] = m[k];
22
+ }));
23
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
24
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
25
+ }) : function(o, v) {
26
+ o["default"] = v;
27
+ });
28
+ var __importStar = (this && this.__importStar) || (function () {
29
+ var ownKeys = function(o) {
30
+ ownKeys = Object.getOwnPropertyNames || function (o) {
31
+ var ar = [];
32
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
33
+ return ar;
34
+ };
35
+ return ownKeys(o);
36
+ };
37
+ return function (mod) {
38
+ if (mod && mod.__esModule) return mod;
39
+ var result = {};
40
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
41
+ __setModuleDefault(result, mod);
42
+ return result;
43
+ };
44
+ })();
45
+ Object.defineProperty(exports, "__esModule", { value: true });
46
+ exports.ActivityLogger = void 0;
47
+ exports.getActivityLogger = getActivityLogger;
48
+ exports.setActivityLogLevel = setActivityLogLevel;
49
+ exports.getActivityLogLevel = getActivityLogLevel;
50
+ exports.closeActivityLogger = closeActivityLogger;
51
+ const fs = __importStar(require("fs"));
52
+ const path = __importStar(require("path"));
53
+ const os = __importStar(require("os"));
54
+ const DEFAULT_CONFIG = {
55
+ logLevel: 'off',
56
+ logPath: path.join(os.homedir(), '.genbox', 'activity.log'),
57
+ maxFileSize: 10 * 1024 * 1024, // 10MB
58
+ maxFiles: 5,
59
+ consoleOutput: false,
60
+ };
61
+ class ActivityLogger {
62
+ config;
63
+ writeStream = null;
64
+ currentFileSize = 0;
65
+ sessionTimers = new Map();
66
+ constructor(config) {
67
+ this.config = { ...DEFAULT_CONFIG, ...config };
68
+ this.loadConfigFromFile();
69
+ }
70
+ /**
71
+ * Load log level from daemon config file
72
+ */
73
+ loadConfigFromFile() {
74
+ const configPath = path.join(os.homedir(), '.genbox', 'daemon.config.json');
75
+ try {
76
+ if (fs.existsSync(configPath)) {
77
+ const data = fs.readFileSync(configPath, 'utf-8');
78
+ const daemonConfig = JSON.parse(data);
79
+ if (daemonConfig.logLevel) {
80
+ this.config.logLevel = daemonConfig.logLevel;
81
+ }
82
+ }
83
+ }
84
+ catch (err) {
85
+ // Ignore - use default
86
+ }
87
+ }
88
+ /**
89
+ * Update logging level at runtime
90
+ */
91
+ setLogLevel(level) {
92
+ this.config.logLevel = level;
93
+ if (level === 'off') {
94
+ this.close();
95
+ }
96
+ this.info('config', 'Log level changed', { level });
97
+ }
98
+ /**
99
+ * Get current log level
100
+ */
101
+ getLogLevel() {
102
+ return this.config.logLevel;
103
+ }
104
+ /**
105
+ * Initialize the write stream
106
+ */
107
+ ensureStream() {
108
+ if (this.config.logLevel === 'off') {
109
+ return null;
110
+ }
111
+ if (this.writeStream) {
112
+ return this.writeStream;
113
+ }
114
+ try {
115
+ // Ensure directory exists
116
+ const logDir = path.dirname(this.config.logPath);
117
+ if (!fs.existsSync(logDir)) {
118
+ fs.mkdirSync(logDir, { recursive: true });
119
+ }
120
+ // Check current file size
121
+ if (fs.existsSync(this.config.logPath)) {
122
+ const stats = fs.statSync(this.config.logPath);
123
+ this.currentFileSize = stats.size;
124
+ }
125
+ this.writeStream = fs.createWriteStream(this.config.logPath, { flags: 'a' });
126
+ return this.writeStream;
127
+ }
128
+ catch (err) {
129
+ console.error('[ActivityLogger] Failed to create log file:', err);
130
+ return null;
131
+ }
132
+ }
133
+ /**
134
+ * Rotate log files when size limit is reached
135
+ */
136
+ rotateIfNeeded() {
137
+ if (this.currentFileSize < this.config.maxFileSize) {
138
+ return;
139
+ }
140
+ // Close current stream
141
+ this.close();
142
+ try {
143
+ // Rotate existing files
144
+ for (let i = this.config.maxFiles - 1; i >= 1; i--) {
145
+ const oldPath = `${this.config.logPath}.${i}`;
146
+ const newPath = `${this.config.logPath}.${i + 1}`;
147
+ if (fs.existsSync(oldPath)) {
148
+ if (i === this.config.maxFiles - 1) {
149
+ fs.unlinkSync(oldPath); // Delete oldest
150
+ }
151
+ else {
152
+ fs.renameSync(oldPath, newPath);
153
+ }
154
+ }
155
+ }
156
+ // Rename current to .1
157
+ if (fs.existsSync(this.config.logPath)) {
158
+ fs.renameSync(this.config.logPath, `${this.config.logPath}.1`);
159
+ }
160
+ this.currentFileSize = 0;
161
+ }
162
+ catch (err) {
163
+ console.error('[ActivityLogger] Failed to rotate logs:', err);
164
+ }
165
+ }
166
+ /**
167
+ * Write a log entry
168
+ */
169
+ write(entry) {
170
+ if (this.config.logLevel === 'off') {
171
+ return;
172
+ }
173
+ const line = this.formatEntry(entry);
174
+ const bytes = Buffer.byteLength(line, 'utf-8');
175
+ // Check rotation
176
+ this.rotateIfNeeded();
177
+ // Write to file
178
+ const stream = this.ensureStream();
179
+ if (stream) {
180
+ stream.write(line);
181
+ this.currentFileSize += bytes;
182
+ }
183
+ // Optional console output
184
+ if (this.config.consoleOutput) {
185
+ console.log(line.trim());
186
+ }
187
+ }
188
+ /**
189
+ * Format a log entry as a single line
190
+ */
191
+ formatEntry(entry) {
192
+ const parts = [
193
+ entry.timestamp,
194
+ `[${entry.level}]`,
195
+ `[${entry.category}]`,
196
+ ];
197
+ if (entry.sessionId) {
198
+ parts.push(`[session:${entry.sessionId.substring(0, 8)}]`);
199
+ }
200
+ parts.push(entry.message);
201
+ if (entry.durationMs !== undefined) {
202
+ parts.push(`(${entry.durationMs}ms)`);
203
+ }
204
+ let line = parts.join(' ');
205
+ // Add data in rich mode
206
+ if (entry.data && this.config.logLevel === 'rich') {
207
+ line += '\n ' + JSON.stringify(entry.data, null, 2).replace(/\n/g, '\n ');
208
+ }
209
+ return line + '\n';
210
+ }
211
+ /**
212
+ * Get current timestamp
213
+ */
214
+ now() {
215
+ return new Date().toISOString();
216
+ }
217
+ /**
218
+ * Truncate text for basic logging
219
+ */
220
+ truncate(text, maxLen = 100) {
221
+ if (!text || text.length <= maxLen)
222
+ return text;
223
+ return text.substring(0, maxLen) + '...';
224
+ }
225
+ /**
226
+ * Close the log file
227
+ */
228
+ close() {
229
+ if (this.writeStream) {
230
+ this.writeStream.end();
231
+ this.writeStream = null;
232
+ }
233
+ }
234
+ // =========================================================================
235
+ // Logging Methods
236
+ // =========================================================================
237
+ info(category, message, data, sessionId) {
238
+ this.write({
239
+ timestamp: this.now(),
240
+ level: 'INFO',
241
+ category,
242
+ sessionId,
243
+ message,
244
+ data: this.config.logLevel === 'rich' ? data : undefined,
245
+ });
246
+ }
247
+ debug(category, message, data, sessionId) {
248
+ if (this.config.logLevel !== 'rich')
249
+ return;
250
+ this.write({
251
+ timestamp: this.now(),
252
+ level: 'DEBUG',
253
+ category,
254
+ sessionId,
255
+ message,
256
+ data,
257
+ });
258
+ }
259
+ warn(category, message, data, sessionId) {
260
+ this.write({
261
+ timestamp: this.now(),
262
+ level: 'WARN',
263
+ category,
264
+ sessionId,
265
+ message,
266
+ data: this.config.logLevel === 'rich' ? data : undefined,
267
+ });
268
+ }
269
+ error(category, message, error, sessionId) {
270
+ this.write({
271
+ timestamp: this.now(),
272
+ level: 'ERROR',
273
+ category,
274
+ sessionId,
275
+ message,
276
+ data: error ? { error: error.message || String(error), stack: error.stack } : undefined,
277
+ });
278
+ }
279
+ // =========================================================================
280
+ // Session Lifecycle
281
+ // =========================================================================
282
+ sessionCreated(sessionId, data) {
283
+ this.sessionTimers.set(sessionId, Date.now());
284
+ this.info('session', `Session created: ${data.provider}`, {
285
+ projectPath: data.projectPath,
286
+ model: data.model,
287
+ dtachSocket: data.dtachSocket,
288
+ }, sessionId);
289
+ }
290
+ sessionEnded(sessionId, data) {
291
+ const startTime = this.sessionTimers.get(sessionId);
292
+ const durationMs = startTime ? Date.now() - startTime : undefined;
293
+ this.sessionTimers.delete(sessionId);
294
+ this.write({
295
+ timestamp: this.now(),
296
+ level: 'INFO',
297
+ category: 'session',
298
+ sessionId,
299
+ message: `Session ended${data?.reason ? `: ${data.reason}` : ''}`,
300
+ data: this.config.logLevel === 'rich' ? {
301
+ messageCount: data?.messageCount,
302
+ totalTokens: data?.totalTokens,
303
+ costCents: data?.costCents,
304
+ } : undefined,
305
+ durationMs,
306
+ });
307
+ }
308
+ sessionStateChanged(sessionId, oldState, newState, toolName) {
309
+ const message = toolName
310
+ ? `State: ${oldState || 'null'} → ${newState} (tool: ${toolName})`
311
+ : `State: ${oldState || 'null'} → ${newState}`;
312
+ this.info('state', message, { oldState, newState, toolName }, sessionId);
313
+ }
314
+ /**
315
+ * Log when a turn is completed (Stop hook fired, Claude ready for new input)
316
+ */
317
+ turnCompleted(sessionId, data) {
318
+ this.info('turn', `Turn completed - ready for input`, {
319
+ messageCount: data?.messageCount,
320
+ toolUseCount: data?.toolUseCount,
321
+ }, sessionId);
322
+ }
323
+ /**
324
+ * Log when terminal output detects a state change
325
+ * This is the DEFINITIVE source for idle state detection
326
+ */
327
+ terminalStateDetected(sessionId, terminalState, mappedState) {
328
+ this.info('terminal', `Terminal state: ${terminalState} → session state: ${mappedState}`, {
329
+ terminalState,
330
+ mappedState,
331
+ source: 'terminal_output',
332
+ }, sessionId);
333
+ }
334
+ // =========================================================================
335
+ // Prompts and Responses
336
+ // =========================================================================
337
+ promptReceived(sessionId, prompt, source) {
338
+ const displayPrompt = this.config.logLevel === 'rich'
339
+ ? prompt
340
+ : this.truncate(prompt, 150);
341
+ this.info('prompt', `Prompt received (${source}): ${this.truncate(prompt, 80)}`, {
342
+ prompt: displayPrompt,
343
+ source,
344
+ length: prompt.length,
345
+ }, sessionId);
346
+ }
347
+ promptSent(sessionId, prompt, success) {
348
+ const displayPrompt = this.config.logLevel === 'rich'
349
+ ? prompt
350
+ : this.truncate(prompt, 150);
351
+ if (success) {
352
+ this.info('prompt', `Prompt sent to Claude: ${this.truncate(prompt, 80)}`, {
353
+ prompt: displayPrompt,
354
+ length: prompt.length,
355
+ }, sessionId);
356
+ }
357
+ else {
358
+ this.error('prompt', `Failed to send prompt: ${this.truncate(prompt, 80)}`, undefined, sessionId);
359
+ }
360
+ }
361
+ responseReceived(sessionId, data) {
362
+ const message = data.role === 'assistant'
363
+ ? `Response received (${data.outputTokens || 0} tokens${data.hasToolUse ? ', has tool_use' : ''})`
364
+ : `User message logged`;
365
+ this.info('message', message, {
366
+ role: data.role,
367
+ inputTokens: data.inputTokens,
368
+ outputTokens: data.outputTokens,
369
+ costCents: data.costCents,
370
+ hasToolUse: data.hasToolUse,
371
+ contentPreview: this.config.logLevel === 'rich' ? data.contentPreview : undefined,
372
+ }, sessionId);
373
+ }
374
+ // =========================================================================
375
+ // Tool Execution
376
+ // =========================================================================
377
+ toolStarted(sessionId, toolName, input) {
378
+ this.info('tool', `Tool started: ${toolName}`, {
379
+ toolName,
380
+ input: this.config.logLevel === 'rich' ? input : undefined,
381
+ }, sessionId);
382
+ }
383
+ toolCompleted(sessionId, toolName, data) {
384
+ const status = data?.success !== false ? 'completed' : 'failed';
385
+ this.write({
386
+ timestamp: this.now(),
387
+ level: data?.success !== false ? 'INFO' : 'WARN',
388
+ category: 'tool',
389
+ sessionId,
390
+ message: `Tool ${status}: ${toolName}${data?.error ? ` - ${data.error}` : ''}`,
391
+ data: this.config.logLevel === 'rich' ? {
392
+ toolName,
393
+ success: data?.success,
394
+ output: data?.output,
395
+ error: data?.error,
396
+ } : undefined,
397
+ durationMs: data?.durationMs,
398
+ });
399
+ }
400
+ // =========================================================================
401
+ // Subagent (Task) Tracking
402
+ // =========================================================================
403
+ subagentStarted(sessionId, agentId, description) {
404
+ this.info('subagent', `Subagent started: ${agentId}`, {
405
+ agentId,
406
+ description,
407
+ }, sessionId);
408
+ }
409
+ subagentCompleted(sessionId, agentId, durationMs) {
410
+ this.write({
411
+ timestamp: this.now(),
412
+ level: 'INFO',
413
+ category: 'subagent',
414
+ sessionId,
415
+ message: `Subagent completed: ${agentId}`,
416
+ data: { agentId },
417
+ durationMs,
418
+ });
419
+ }
420
+ // =========================================================================
421
+ // JSONL Sync
422
+ // =========================================================================
423
+ jsonlSyncStarted(sessionId, filePath) {
424
+ this.debug('sync', `JSONL sync started`, { filePath }, sessionId);
425
+ }
426
+ jsonlSyncCompleted(sessionId, data) {
427
+ if (data.messagesAdded > 0) {
428
+ this.write({
429
+ timestamp: this.now(),
430
+ level: 'INFO',
431
+ category: 'sync',
432
+ sessionId,
433
+ message: `JSONL sync: ${data.messagesAdded} messages added`,
434
+ data: this.config.logLevel === 'rich' ? data : undefined,
435
+ durationMs: data.durationMs,
436
+ });
437
+ }
438
+ }
439
+ // =========================================================================
440
+ // Hook Events
441
+ // =========================================================================
442
+ hookEventReceived(sessionId, eventType, data) {
443
+ this.info('hook', `Hook event: ${eventType}`, {
444
+ eventType,
445
+ ...(this.config.logLevel === 'rich' ? { data } : {}),
446
+ }, sessionId);
447
+ }
448
+ // =========================================================================
449
+ // Connection Events
450
+ // =========================================================================
451
+ daemonStarted(genboxId, mode) {
452
+ this.info('daemon', `Daemon started in ${mode} mode`, { genboxId, mode });
453
+ }
454
+ daemonStopped() {
455
+ this.info('daemon', 'Daemon stopped');
456
+ this.close();
457
+ }
458
+ serverStarted(port) {
459
+ this.info('server', `Server started on port ${port}`, { port });
460
+ }
461
+ clientConnected(clientId) {
462
+ this.debug('connection', `Client connected: ${clientId}`, { clientId });
463
+ }
464
+ clientDisconnected(clientId) {
465
+ this.debug('connection', `Client disconnected: ${clientId}`, { clientId });
466
+ }
467
+ // =========================================================================
468
+ // Error Tracking
469
+ // =========================================================================
470
+ syncError(sessionId, error, context) {
471
+ this.error('sync', `Sync error${context ? ` (${context})` : ''}`, typeof error === 'string' ? { message: error } : error, sessionId);
472
+ }
473
+ hookError(sessionId, error, hookType) {
474
+ this.error('hook', `Hook error${hookType ? ` (${hookType})` : ''}`, typeof error === 'string' ? { message: error } : error, sessionId);
475
+ }
476
+ }
477
+ exports.ActivityLogger = ActivityLogger;
478
+ // =========================================================================
479
+ // Singleton Instance
480
+ // =========================================================================
481
+ let loggerInstance = null;
482
+ /**
483
+ * Get the activity logger singleton
484
+ */
485
+ function getActivityLogger(config) {
486
+ if (!loggerInstance) {
487
+ loggerInstance = new ActivityLogger(config);
488
+ }
489
+ return loggerInstance;
490
+ }
491
+ /**
492
+ * Update log level at runtime (called when user changes settings)
493
+ */
494
+ function setActivityLogLevel(level) {
495
+ const logger = getActivityLogger();
496
+ logger.setLogLevel(level);
497
+ }
498
+ /**
499
+ * Get current log level
500
+ */
501
+ function getActivityLogLevel() {
502
+ return getActivityLogger().getLogLevel();
503
+ }
504
+ /**
505
+ * Close the activity logger (on shutdown)
506
+ */
507
+ function closeActivityLogger() {
508
+ if (loggerInstance) {
509
+ loggerInstance.close();
510
+ loggerInstance = null;
511
+ }
512
+ }
513
+ //# sourceMappingURL=activity-logger.js.map