@townco/ui 0.1.33 → 0.1.35

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 (48) hide show
  1. package/dist/core/hooks/use-chat-session.d.ts +1 -1
  2. package/dist/core/schemas/chat.d.ts +1 -1
  3. package/dist/gui/components/Button.js +1 -1
  4. package/dist/gui/components/ChatEmptyState.js +1 -1
  5. package/dist/gui/components/ChatHeader.js +2 -2
  6. package/dist/gui/components/ChatInput.js +1 -1
  7. package/dist/gui/components/ChatInputCommandMenu.js +1 -1
  8. package/dist/gui/components/ChatLayout.js +1 -1
  9. package/dist/gui/components/ChatPanelTabContent.d.ts +3 -0
  10. package/dist/gui/components/ChatPanelTabContent.js +24 -5
  11. package/dist/gui/components/ChatSecondaryPanel.js +3 -3
  12. package/dist/gui/components/ChatView.js +28 -9
  13. package/dist/gui/components/Dialog.js +2 -2
  14. package/dist/gui/components/DropdownMenu.js +7 -7
  15. package/dist/gui/components/FileSystemItem.d.ts +17 -0
  16. package/dist/gui/components/FileSystemItem.js +81 -0
  17. package/dist/gui/components/FileSystemView.d.ts +14 -0
  18. package/dist/gui/components/FileSystemView.js +46 -0
  19. package/dist/gui/components/Input.js +1 -1
  20. package/dist/gui/components/Label.js +1 -1
  21. package/dist/gui/components/MarkdownRenderer.js +5 -5
  22. package/dist/gui/components/Message.d.ts +1 -1
  23. package/dist/gui/components/MessageContent.js +8 -8
  24. package/dist/gui/components/PanelTabsHeader.js +1 -1
  25. package/dist/gui/components/Reasoning.js +2 -2
  26. package/dist/gui/components/Response.js +13 -11
  27. package/dist/gui/components/Select.js +3 -3
  28. package/dist/gui/components/SourceListItem.js +1 -1
  29. package/dist/gui/components/Tabs.js +1 -1
  30. package/dist/gui/components/Task.js +2 -2
  31. package/dist/gui/components/Textarea.js +1 -1
  32. package/dist/gui/components/ThinkingBlock.js +2 -2
  33. package/dist/gui/components/TodoList.js +1 -1
  34. package/dist/gui/components/ToolCall.js +67 -70
  35. package/dist/gui/components/ToolCallList.js +1 -1
  36. package/dist/gui/components/index.d.ts +4 -0
  37. package/dist/gui/components/index.js +4 -0
  38. package/dist/gui/data/mockFileSystemData.d.ts +21 -0
  39. package/dist/gui/data/mockFileSystemData.js +127 -0
  40. package/dist/gui/types/filesystem.d.ts +27 -0
  41. package/dist/gui/types/filesystem.js +5 -0
  42. package/dist/sdk/schemas/session.d.ts +12 -12
  43. package/package.json +3 -3
  44. package/src/styles/global.css +108 -0
  45. package/dist/core/lib/logger.d.ts +0 -59
  46. package/dist/core/lib/logger.js +0 -191
  47. package/dist/tui/components/LogsPanel.d.ts +0 -5
  48. package/dist/tui/components/LogsPanel.js +0 -29
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Mock filesystem data - stub implementation
3
+ * Replace this with a real FileSystemProvider implementation later
4
+ */
5
+ /**
6
+ * Stub filesystem data matching the Figma design
7
+ * This data can be easily replaced with real filesystem queries
8
+ */
9
+ export const mockFileSystemData = [
10
+ {
11
+ id: "folder-1",
12
+ name: "Item 1",
13
+ type: "folder",
14
+ children: [
15
+ {
16
+ id: "file-1-1",
17
+ name: "Item 2",
18
+ type: "file",
19
+ extension: "tsx",
20
+ },
21
+ {
22
+ id: "file-1-2",
23
+ name: "Item 3",
24
+ type: "file",
25
+ extension: "ts",
26
+ },
27
+ {
28
+ id: "file-1-3",
29
+ name: "Item 4",
30
+ type: "file",
31
+ extension: "json",
32
+ },
33
+ {
34
+ id: "file-1-4",
35
+ name: "Item 5",
36
+ type: "file",
37
+ extension: "md",
38
+ },
39
+ ],
40
+ },
41
+ {
42
+ id: "folder-2",
43
+ name: "Description 1",
44
+ type: "folder",
45
+ children: [
46
+ {
47
+ id: "file-2-1",
48
+ name: "Description 2",
49
+ type: "file",
50
+ extension: "tsx",
51
+ },
52
+ {
53
+ id: "file-2-2",
54
+ name: "Description 3",
55
+ type: "file",
56
+ extension: "ts",
57
+ },
58
+ {
59
+ id: "file-2-3",
60
+ name: "Description 4",
61
+ type: "file",
62
+ extension: "json",
63
+ },
64
+ {
65
+ id: "file-2-4",
66
+ name: "Description 5",
67
+ type: "file",
68
+ extension: "md",
69
+ },
70
+ ],
71
+ },
72
+ {
73
+ id: "folder-3",
74
+ name: "financial-docs",
75
+ type: "folder",
76
+ children: [],
77
+ },
78
+ ];
79
+ /**
80
+ * Mock FileSystemProvider implementation
81
+ * Replace this class with a real implementation that fetches from an actual filesystem
82
+ */
83
+ export class MockFileSystemProvider {
84
+ data;
85
+ constructor(data = mockFileSystemData) {
86
+ this.data = data;
87
+ }
88
+ async getRootItems() {
89
+ // Simulate async operation
90
+ return Promise.resolve(this.data);
91
+ }
92
+ async getItemChildren(itemId) {
93
+ const findItem = (items) => {
94
+ for (const item of items) {
95
+ if (item.id === itemId)
96
+ return item;
97
+ if (item.children) {
98
+ const found = findItem(item.children);
99
+ if (found)
100
+ return found;
101
+ }
102
+ }
103
+ return undefined;
104
+ };
105
+ const item = findItem(this.data);
106
+ return Promise.resolve(item?.children || []);
107
+ }
108
+ async getItemDetails(itemId) {
109
+ const findItem = (items) => {
110
+ for (const item of items) {
111
+ if (item.id === itemId)
112
+ return item;
113
+ if (item.children) {
114
+ const found = findItem(item.children);
115
+ if (found)
116
+ return found;
117
+ }
118
+ }
119
+ return undefined;
120
+ };
121
+ const item = findItem(this.data);
122
+ if (!item) {
123
+ throw new Error(`Item with id ${itemId} not found`);
124
+ }
125
+ return Promise.resolve(item);
126
+ }
127
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Filesystem types for the file manager view
3
+ * This stub system can be easily replaced with real filesystem data later
4
+ */
5
+ export type FileSystemItemType = "file" | "folder";
6
+ export interface FileSystemItem {
7
+ id: string;
8
+ name: string;
9
+ type: FileSystemItemType;
10
+ children?: FileSystemItem[];
11
+ size?: number;
12
+ lastModified?: Date;
13
+ path?: string;
14
+ extension?: string;
15
+ }
16
+ export interface FileSystemData {
17
+ items: FileSystemItem[];
18
+ }
19
+ /**
20
+ * Interface for filesystem data providers
21
+ * Implement this to replace the stub with real data
22
+ */
23
+ export interface FileSystemProvider {
24
+ getRootItems(): Promise<FileSystemItem[]>;
25
+ getItemChildren(itemId: string): Promise<FileSystemItem[]>;
26
+ getItemDetails(itemId: string): Promise<FileSystemItem>;
27
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Filesystem types for the file manager view
3
+ * This stub system can be easily replaced with real filesystem data later
4
+ */
5
+ export {};
@@ -4,12 +4,12 @@ import { z } from "zod";
4
4
  */
5
5
  export declare const SessionStatus: z.ZodEnum<{
6
6
  error: "error";
7
- disconnected: "disconnected";
7
+ idle: "idle";
8
8
  connecting: "connecting";
9
9
  connected: "connected";
10
- idle: "idle";
11
10
  active: "active";
12
11
  streaming: "streaming";
12
+ disconnected: "disconnected";
13
13
  }>;
14
14
  export type SessionStatus = z.infer<typeof SessionStatus>;
15
15
  /**
@@ -41,12 +41,12 @@ export declare const Session: z.ZodObject<{
41
41
  id: z.ZodString;
42
42
  status: z.ZodEnum<{
43
43
  error: "error";
44
- disconnected: "disconnected";
44
+ idle: "idle";
45
45
  connecting: "connecting";
46
46
  connected: "connected";
47
- idle: "idle";
48
47
  active: "active";
49
48
  streaming: "streaming";
49
+ disconnected: "disconnected";
50
50
  }>;
51
51
  config: z.ZodObject<{
52
52
  agentPath: z.ZodString;
@@ -109,12 +109,12 @@ export declare const SessionUpdate: z.ZodUnion<readonly [z.ZodObject<{
109
109
  sessionId: z.ZodString;
110
110
  status: z.ZodOptional<z.ZodEnum<{
111
111
  error: "error";
112
- disconnected: "disconnected";
112
+ idle: "idle";
113
113
  connecting: "connecting";
114
114
  connected: "connected";
115
- idle: "idle";
116
115
  active: "active";
117
116
  streaming: "streaming";
117
+ disconnected: "disconnected";
118
118
  }>>;
119
119
  message: z.ZodOptional<z.ZodObject<{
120
120
  id: z.ZodString;
@@ -216,12 +216,12 @@ export declare const SessionUpdate: z.ZodUnion<readonly [z.ZodObject<{
216
216
  sessionId: z.ZodString;
217
217
  status: z.ZodOptional<z.ZodEnum<{
218
218
  error: "error";
219
- disconnected: "disconnected";
219
+ idle: "idle";
220
220
  connecting: "connecting";
221
221
  connected: "connected";
222
- idle: "idle";
223
222
  active: "active";
224
223
  streaming: "streaming";
224
+ disconnected: "disconnected";
225
225
  }>>;
226
226
  message: z.ZodOptional<z.ZodObject<{
227
227
  id: z.ZodString;
@@ -307,12 +307,12 @@ export declare const SessionUpdate: z.ZodUnion<readonly [z.ZodObject<{
307
307
  sessionId: z.ZodString;
308
308
  status: z.ZodOptional<z.ZodEnum<{
309
309
  error: "error";
310
- disconnected: "disconnected";
310
+ idle: "idle";
311
311
  connecting: "connecting";
312
312
  connected: "connected";
313
- idle: "idle";
314
313
  active: "active";
315
314
  streaming: "streaming";
315
+ disconnected: "disconnected";
316
316
  }>>;
317
317
  message: z.ZodOptional<z.ZodObject<{
318
318
  id: z.ZodString;
@@ -363,12 +363,12 @@ export declare const SessionUpdate: z.ZodUnion<readonly [z.ZodObject<{
363
363
  sessionId: z.ZodString;
364
364
  status: z.ZodOptional<z.ZodEnum<{
365
365
  error: "error";
366
- disconnected: "disconnected";
366
+ idle: "idle";
367
367
  connecting: "connecting";
368
368
  connected: "connected";
369
- idle: "idle";
370
369
  active: "active";
371
370
  streaming: "streaming";
371
+ disconnected: "disconnected";
372
372
  }>>;
373
373
  message: z.ZodOptional<z.ZodObject<{
374
374
  id: z.ZodString;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@townco/ui",
3
- "version": "0.1.33",
3
+ "version": "0.1.35",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -40,7 +40,7 @@
40
40
  },
41
41
  "dependencies": {
42
42
  "@agentclientprotocol/sdk": "^0.5.1",
43
- "@townco/core": "0.0.11",
43
+ "@townco/core": "0.0.13",
44
44
  "@radix-ui/react-dialog": "^1.1.15",
45
45
  "@radix-ui/react-dropdown-menu": "^2.1.16",
46
46
  "@radix-ui/react-label": "^2.1.8",
@@ -62,7 +62,7 @@
62
62
  },
63
63
  "devDependencies": {
64
64
  "@tailwindcss/postcss": "^4.1.17",
65
- "@townco/tsconfig": "0.1.30",
65
+ "@townco/tsconfig": "0.1.32",
66
66
  "@types/node": "^24.10.0",
67
67
  "@types/react": "^19.2.2",
68
68
  "ink": "^6.4.0",
@@ -52,11 +52,24 @@
52
52
 
53
53
  /* Typography - Letter spacing */
54
54
  --letter-spacing-tight: -0.48px;
55
+ --letter-spacing-heading: -0.4px;
55
56
  --letter-spacing-uppercase: 1.12px;
56
57
 
57
58
  /* Typography - Font sizes with line heights */
59
+ --font-size-heading-1: 3rem; /* 48px */
60
+ --line-height-heading-1: 1; /* 100% */
61
+
62
+ --font-size-heading-2: 1.875rem; /* 30px */
63
+ --line-height-heading-2: 1; /* 100% */
64
+
58
65
  --font-size-heading-3: 1.5rem; /* 24px */
59
66
  --line-height-heading-3: 1.2; /* 120% */
67
+
68
+ --font-size-heading-4: 1.25rem; /* 20px */
69
+ --line-height-heading-4: 1.2; /* 120% */
70
+
71
+ --font-size-heading-5: 1rem; /* 16px */
72
+ --line-height-heading-5: 1.2; /* 120% */
60
73
 
61
74
  --font-size-subheading: 1.25rem; /* 20px */
62
75
  --line-height-subheading: 1.5; /* 150% */
@@ -64,6 +77,24 @@
64
77
  --font-size-label: 0.875rem; /* 14px */
65
78
  --line-height-label: 1.5; /* 150% */
66
79
 
80
+
81
+ --font-size-paragraph: 1rem; /* 16px */
82
+ --line-height-paragraph: 1.5; /* 150% */
83
+
84
+ --font-size-paragraph-sm: 0.875rem; /* 14px */
85
+ --line-height-paragraph-sm: 1.5; /* 150% */
86
+
87
+ --font-size-paragraph-mini: 0.75rem; /* 12px */
88
+ --line-height-paragraph-mini: 1.5; /* 150% */
89
+
90
+ --font-size-caption: 0.75rem; /* 12px */
91
+ --line-height-caption: 1.5; /* 150% */
92
+
93
+ --font-size-code: 0.875rem; /* 14px */
94
+ --line-height-code: 1.5; /* 150% */
95
+
96
+ --letter-spacing-wide: 0.07em;
97
+
67
98
  /* Shadows */
68
99
  --shadow-sm: 0 8px 24px -16px rgba(0, 0, 0, 0.04), 0 4px 16px 0 rgba(0, 0, 0, 0.04);
69
100
  --shadow-md: 0 8px 24px -16px rgba(0, 0, 0, 0.04), 0 4px 16px 0 rgba(0, 0, 0, 0.04);
@@ -177,12 +208,40 @@
177
208
 
178
209
  @layer utilities {
179
210
  /* Typography utilities following design system */
211
+ .text-heading-1 {
212
+ font-size: var(--font-size-heading-1);
213
+ line-height: var(--line-height-heading-1);
214
+ font-weight: 600;
215
+ letter-spacing: var(--letter-spacing-tight);
216
+ }
217
+
218
+ .text-heading-2 {
219
+ font-size: var(--font-size-heading-2);
220
+ line-height: var(--line-height-heading-2);
221
+ font-weight: 600;
222
+ letter-spacing: var(--letter-spacing-tight);
223
+ }
224
+
180
225
  .text-heading-3 {
181
226
  font-size: var(--font-size-heading-3);
182
227
  line-height: var(--line-height-heading-3);
183
228
  font-weight: 600;
184
229
  letter-spacing: var(--letter-spacing-tight);
185
230
  }
231
+
232
+ .text-heading-4 {
233
+ font-size: var(--font-size-heading-4);
234
+ line-height: var(--line-height-heading-4);
235
+ font-weight: 600;
236
+ letter-spacing: var(--letter-spacing-heading);
237
+ }
238
+
239
+ .text-heading-5 {
240
+ font-size: var(--font-size-heading-5);
241
+ line-height: var(--line-height-heading-5);
242
+ font-weight: 600;
243
+ letter-spacing: var(--letter-spacing-heading);
244
+ }
186
245
 
187
246
  .text-subheading {
188
247
  font-size: var(--font-size-subheading);
@@ -197,6 +256,55 @@
197
256
  letter-spacing: var(--letter-spacing-uppercase);
198
257
  text-transform: uppercase;
199
258
  }
259
+
260
+ .text-paragraph {
261
+ font-size: var(--font-size-paragraph);
262
+ line-height: var(--line-height-paragraph);
263
+ font-weight: 400;
264
+ }
265
+
266
+ .text-paragraph-medium {
267
+ font-size: var(--font-size-paragraph);
268
+ line-height: var(--line-height-paragraph);
269
+ font-weight: 500;
270
+ }
271
+
272
+ .text-paragraph-sm {
273
+ font-size: var(--font-size-paragraph-sm);
274
+ line-height: var(--line-height-paragraph-sm);
275
+ font-weight: 400;
276
+ }
277
+
278
+ .text-paragraph-sm-medium {
279
+ font-size: var(--font-size-paragraph-sm);
280
+ line-height: var(--line-height-paragraph-sm);
281
+ font-weight: 500;
282
+ letter-spacing: var(--letter-spacing-wide);
283
+ }
284
+
285
+ .text-paragraph-mini {
286
+ font-size: var(--font-size-paragraph-mini);
287
+ line-height: var(--line-height-paragraph-mini);
288
+ font-weight: 400;
289
+ }
290
+
291
+ .text-paragraph-mini-medium {
292
+ font-size: var(--font-size-paragraph-mini);
293
+ line-height: var(--line-height-paragraph-mini);
294
+ font-weight: 500;
295
+ }
296
+
297
+ .text-caption {
298
+ font-size: var(--font-size-caption);
299
+ line-height: var(--line-height-caption);
300
+ font-weight: 400;
301
+ }
302
+
303
+ .text-code {
304
+ font-size: var(--font-size-code);
305
+ line-height: var(--line-height-code);
306
+ font-family: monospace;
307
+ }
200
308
  }
201
309
 
202
310
  @keyframes spin {
@@ -1,59 +0,0 @@
1
- /**
2
- * Browser-compatible logger
3
- * Outputs structured JSON logs to console with color-coding
4
- * Also captures logs to a global store for in-app viewing
5
- * In Node.js environment with logsDir option, also writes to .logs/ directory
6
- */
7
- export type LogLevel = "trace" | "debug" | "info" | "warn" | "error" | "fatal";
8
- export interface LogEntry {
9
- id: string;
10
- timestamp: string;
11
- level: LogLevel;
12
- service: string;
13
- message: string;
14
- metadata?: Record<string, unknown>;
15
- }
16
- /**
17
- * Get all captured logs
18
- */
19
- export declare function getCapturedLogs(): LogEntry[];
20
- /**
21
- * Clear all captured logs
22
- */
23
- export declare function clearCapturedLogs(): void;
24
- /**
25
- * Subscribe to log updates
26
- */
27
- type LogSubscriber = (entry: LogEntry) => void;
28
- export declare function subscribeToLogs(callback: LogSubscriber): () => void;
29
- /**
30
- * Configure global logs directory for file writing
31
- * Must be called before creating any loggers (typically at TUI startup)
32
- */
33
- export declare function configureLogsDir(logsDir: string): void;
34
- export declare class Logger {
35
- private service;
36
- private minLevel;
37
- private logFilePath?;
38
- private logsDir?;
39
- private writeQueue;
40
- private isWriting;
41
- constructor(service: string, minLevel?: LogLevel);
42
- private setupFileLogging;
43
- private writeToFile;
44
- private shouldLog;
45
- private log;
46
- trace(message: string, metadata?: Record<string, unknown>): void;
47
- debug(message: string, metadata?: Record<string, unknown>): void;
48
- info(message: string, metadata?: Record<string, unknown>): void;
49
- warn(message: string, metadata?: Record<string, unknown>): void;
50
- error(message: string, metadata?: Record<string, unknown>): void;
51
- fatal(message: string, metadata?: Record<string, unknown>): void;
52
- }
53
- /**
54
- * Create a logger instance for a service
55
- * @param service - Service name (e.g., "gui", "http-agent", "tui")
56
- * @param minLevel - Minimum log level to display (default: "debug")
57
- */
58
- export declare function createLogger(service: string, minLevel?: LogLevel): Logger;
59
- export {};
@@ -1,191 +0,0 @@
1
- /**
2
- * Browser-compatible logger
3
- * Outputs structured JSON logs to console with color-coding
4
- * Also captures logs to a global store for in-app viewing
5
- * In Node.js environment with logsDir option, also writes to .logs/ directory
6
- */
7
- // Check if running in Node.js
8
- const isNode = typeof process !== "undefined" && process.versions?.node;
9
- // Global logs directory configuration (set once at app startup for TUI)
10
- let globalLogsDir;
11
- // Global log store
12
- const globalLogStore = [];
13
- let logIdCounter = 0;
14
- /**
15
- * Get all captured logs
16
- */
17
- export function getCapturedLogs() {
18
- return [...globalLogStore];
19
- }
20
- /**
21
- * Clear all captured logs
22
- */
23
- export function clearCapturedLogs() {
24
- globalLogStore.length = 0;
25
- }
26
- const logSubscribers = new Set();
27
- export function subscribeToLogs(callback) {
28
- logSubscribers.add(callback);
29
- return () => logSubscribers.delete(callback);
30
- }
31
- function notifyLogSubscribers(entry) {
32
- for (const callback of logSubscribers) {
33
- callback(entry);
34
- }
35
- }
36
- /**
37
- * Configure global logs directory for file writing
38
- * Must be called before creating any loggers (typically at TUI startup)
39
- */
40
- export function configureLogsDir(logsDir) {
41
- globalLogsDir = logsDir;
42
- }
43
- const LOG_LEVELS = {
44
- trace: 0,
45
- debug: 1,
46
- info: 2,
47
- warn: 3,
48
- error: 4,
49
- fatal: 5,
50
- };
51
- const _LOG_COLORS = {
52
- trace: "#6B7280", // gray
53
- debug: "#3B82F6", // blue
54
- info: "#10B981", // green
55
- warn: "#F59E0B", // orange
56
- error: "#EF4444", // red
57
- fatal: "#DC2626", // dark red
58
- };
59
- const _LOG_STYLES = {
60
- trace: "color: #6B7280",
61
- debug: "color: #3B82F6; font-weight: bold",
62
- info: "color: #10B981; font-weight: bold",
63
- warn: "color: #F59E0B; font-weight: bold",
64
- error: "color: #EF4444; font-weight: bold",
65
- fatal: "color: #DC2626; font-weight: bold; background: #FEE2E2",
66
- };
67
- export class Logger {
68
- service;
69
- minLevel;
70
- logFilePath;
71
- logsDir;
72
- writeQueue = [];
73
- isWriting = false;
74
- constructor(service, minLevel = "debug") {
75
- this.service = service;
76
- this.minLevel = minLevel;
77
- // In production, suppress trace and debug logs
78
- if (typeof process !== "undefined" &&
79
- process.env?.NODE_ENV === "production") {
80
- this.minLevel = "info";
81
- }
82
- // Note: File logging setup is done lazily in log() method
83
- // This allows loggers created before configureLogsDir() to still write to files
84
- }
85
- setupFileLogging() {
86
- if (!isNode || !globalLogsDir)
87
- return;
88
- try {
89
- // Dynamic import for Node.js modules
90
- const path = require("node:path");
91
- const fs = require("node:fs");
92
- this.logsDir = globalLogsDir;
93
- this.logFilePath = path.join(this.logsDir, `${this.service}.log`);
94
- // Create logs directory if it doesn't exist
95
- if (!fs.existsSync(this.logsDir)) {
96
- fs.mkdirSync(this.logsDir, { recursive: true });
97
- }
98
- }
99
- catch (_error) {
100
- // Silently fail if we can't set up file logging
101
- }
102
- }
103
- async writeToFile(content) {
104
- if (!this.logFilePath || !isNode)
105
- return;
106
- this.writeQueue.push(content);
107
- if (this.isWriting) {
108
- return;
109
- }
110
- this.isWriting = true;
111
- while (this.writeQueue.length > 0) {
112
- const batch = this.writeQueue.splice(0, this.writeQueue.length);
113
- const data = `${batch.join("\n")}\n`;
114
- try {
115
- // Dynamic import for Node.js modules
116
- const fs = require("node:fs");
117
- await fs.promises.appendFile(this.logFilePath, data, "utf-8");
118
- }
119
- catch (_error) {
120
- // Silently fail
121
- }
122
- }
123
- this.isWriting = false;
124
- }
125
- shouldLog(level) {
126
- return LOG_LEVELS[level] >= LOG_LEVELS[this.minLevel];
127
- }
128
- log(level, message, metadata) {
129
- if (!this.shouldLog(level)) {
130
- return;
131
- }
132
- const entry = {
133
- id: `log_${++logIdCounter}`,
134
- timestamp: new Date().toISOString(),
135
- level,
136
- service: this.service,
137
- message,
138
- ...(metadata && { metadata }),
139
- };
140
- // Store in global log store
141
- globalLogStore.push(entry);
142
- // Notify subscribers
143
- notifyLogSubscribers(entry);
144
- // Write to file in Node.js (for logs tab to read)
145
- // Lazily set up file logging if globalLogsDir was configured after this logger was created
146
- if (isNode && !this.logFilePath && globalLogsDir) {
147
- this.setupFileLogging();
148
- }
149
- if (isNode && this.logFilePath) {
150
- // Write as JSON without the id field (to match expected format)
151
- const fileEntry = {
152
- timestamp: entry.timestamp,
153
- level: entry.level,
154
- service: entry.service,
155
- message: entry.message,
156
- ...(entry.metadata && { metadata: entry.metadata }),
157
- };
158
- this.writeToFile(JSON.stringify(fileEntry)).catch(() => {
159
- // Silently fail
160
- });
161
- }
162
- // No console output - logs are only captured and displayed in UI
163
- // This prevents logs from polluting stdout/stderr in TUI mode
164
- }
165
- trace(message, metadata) {
166
- this.log("trace", message, metadata);
167
- }
168
- debug(message, metadata) {
169
- this.log("debug", message, metadata);
170
- }
171
- info(message, metadata) {
172
- this.log("info", message, metadata);
173
- }
174
- warn(message, metadata) {
175
- this.log("warn", message, metadata);
176
- }
177
- error(message, metadata) {
178
- this.log("error", message, metadata);
179
- }
180
- fatal(message, metadata) {
181
- this.log("fatal", message, metadata);
182
- }
183
- }
184
- /**
185
- * Create a logger instance for a service
186
- * @param service - Service name (e.g., "gui", "http-agent", "tui")
187
- * @param minLevel - Minimum log level to display (default: "debug")
188
- */
189
- export function createLogger(service, minLevel = "debug") {
190
- return new Logger(service, minLevel);
191
- }
@@ -1,5 +0,0 @@
1
- import type { LogEntry } from "../../core/lib/logger.js";
2
- export interface LogsPanelProps {
3
- logs: LogEntry[];
4
- }
5
- export declare function LogsPanel({ logs: initialLogs }: LogsPanelProps): import("react/jsx-runtime").JSX.Element;