zerg-ztc 0.1.11 → 0.1.13

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 (122) hide show
  1. package/bin/ztc-audio-darwin-arm64 +0 -0
  2. package/dist/utils/dictation_native.d.ts.map +1 -1
  3. package/dist/utils/dictation_native.js +43 -23
  4. package/dist/utils/dictation_native.js.map +1 -1
  5. package/package.json +5 -4
  6. package/packages/ztc-dictation/Cargo.toml +0 -43
  7. package/packages/ztc-dictation/README.md +0 -65
  8. package/packages/ztc-dictation/index.d.ts +0 -16
  9. package/packages/ztc-dictation/index.js +0 -74
  10. package/packages/ztc-dictation/package.json +0 -41
  11. package/packages/ztc-dictation/src/main.rs +0 -430
  12. package/src/App.tsx +0 -910
  13. package/src/agent/agent.ts +0 -534
  14. package/src/agent/backends/anthropic.ts +0 -86
  15. package/src/agent/backends/gemini.ts +0 -119
  16. package/src/agent/backends/inception.ts +0 -23
  17. package/src/agent/backends/index.ts +0 -17
  18. package/src/agent/backends/openai.ts +0 -23
  19. package/src/agent/backends/openai_compatible.ts +0 -143
  20. package/src/agent/backends/types.ts +0 -83
  21. package/src/agent/commands/clipboard.ts +0 -77
  22. package/src/agent/commands/config.ts +0 -204
  23. package/src/agent/commands/debug.ts +0 -23
  24. package/src/agent/commands/dictation.ts +0 -11
  25. package/src/agent/commands/emulation.ts +0 -80
  26. package/src/agent/commands/execution.ts +0 -9
  27. package/src/agent/commands/help.ts +0 -20
  28. package/src/agent/commands/history.ts +0 -13
  29. package/src/agent/commands/index.ts +0 -48
  30. package/src/agent/commands/input_mode.ts +0 -22
  31. package/src/agent/commands/keybindings.ts +0 -40
  32. package/src/agent/commands/model.ts +0 -11
  33. package/src/agent/commands/models.ts +0 -116
  34. package/src/agent/commands/permissions.ts +0 -64
  35. package/src/agent/commands/retry.ts +0 -9
  36. package/src/agent/commands/shell.ts +0 -68
  37. package/src/agent/commands/skills.ts +0 -54
  38. package/src/agent/commands/status.ts +0 -19
  39. package/src/agent/commands/types.ts +0 -88
  40. package/src/agent/commands/update.ts +0 -32
  41. package/src/agent/factory.ts +0 -60
  42. package/src/agent/index.ts +0 -20
  43. package/src/agent/runtime/capabilities.ts +0 -7
  44. package/src/agent/runtime/memory.ts +0 -23
  45. package/src/agent/runtime/policy.ts +0 -48
  46. package/src/agent/runtime/session.ts +0 -18
  47. package/src/agent/runtime/tracing.ts +0 -23
  48. package/src/agent/tools/file.ts +0 -178
  49. package/src/agent/tools/index.ts +0 -52
  50. package/src/agent/tools/screenshot.ts +0 -821
  51. package/src/agent/tools/search.ts +0 -138
  52. package/src/agent/tools/shell.ts +0 -69
  53. package/src/agent/tools/skills.ts +0 -28
  54. package/src/agent/tools/types.ts +0 -14
  55. package/src/agent/tools/zerg.ts +0 -50
  56. package/src/cli.tsx +0 -163
  57. package/src/components/ActivityLine.tsx +0 -23
  58. package/src/components/FullScreen.tsx +0 -79
  59. package/src/components/Header.tsx +0 -27
  60. package/src/components/InputArea.tsx +0 -1660
  61. package/src/components/MessageList.tsx +0 -71
  62. package/src/components/SingleMessage.tsx +0 -298
  63. package/src/components/StatusBar.tsx +0 -55
  64. package/src/components/index.tsx +0 -8
  65. package/src/config/types.ts +0 -19
  66. package/src/config.ts +0 -186
  67. package/src/debug/logger.ts +0 -14
  68. package/src/emulation/README.md +0 -24
  69. package/src/emulation/catalog.ts +0 -82
  70. package/src/emulation/trace_style.ts +0 -8
  71. package/src/emulation/types.ts +0 -7
  72. package/src/skills/index.ts +0 -36
  73. package/src/skills/loader.ts +0 -135
  74. package/src/skills/registry.ts +0 -6
  75. package/src/skills/types.ts +0 -10
  76. package/src/types.ts +0 -84
  77. package/src/ui/README.md +0 -44
  78. package/src/ui/core/factory.ts +0 -9
  79. package/src/ui/core/index.ts +0 -4
  80. package/src/ui/core/input.ts +0 -38
  81. package/src/ui/core/input_segments.ts +0 -410
  82. package/src/ui/core/input_state.ts +0 -17
  83. package/src/ui/core/layout_yoga.ts +0 -122
  84. package/src/ui/core/style.ts +0 -38
  85. package/src/ui/core/types.ts +0 -54
  86. package/src/ui/ink/index.tsx +0 -1
  87. package/src/ui/ink/render.tsx +0 -60
  88. package/src/ui/views/activity_line.ts +0 -33
  89. package/src/ui/views/app.ts +0 -111
  90. package/src/ui/views/header.ts +0 -44
  91. package/src/ui/views/input_area.ts +0 -255
  92. package/src/ui/views/message_list.ts +0 -443
  93. package/src/ui/views/status_bar.ts +0 -114
  94. package/src/ui/vue/index.ts +0 -53
  95. package/src/ui/web/frame_render.tsx +0 -148
  96. package/src/ui/web/index.tsx +0 -1
  97. package/src/ui/web/render.tsx +0 -41
  98. package/src/utils/clipboard.ts +0 -39
  99. package/src/utils/clipboard_image.ts +0 -40
  100. package/src/utils/dictation.ts +0 -467
  101. package/src/utils/dictation_native.ts +0 -258
  102. package/src/utils/diff.ts +0 -52
  103. package/src/utils/image_preview.ts +0 -36
  104. package/src/utils/models.ts +0 -98
  105. package/src/utils/path_complete.ts +0 -173
  106. package/src/utils/path_format.ts +0 -99
  107. package/src/utils/shell.ts +0 -72
  108. package/src/utils/spinner_frames.ts +0 -1
  109. package/src/utils/spinner_verbs.ts +0 -23
  110. package/src/utils/table.ts +0 -171
  111. package/src/utils/tool_summary.ts +0 -56
  112. package/src/utils/tool_trace.ts +0 -346
  113. package/src/utils/update.ts +0 -44
  114. package/src/utils/version.ts +0 -15
  115. package/src/web/index.html +0 -352
  116. package/src/web/mirror-favicon.svg +0 -4
  117. package/src/web/mirror.html +0 -641
  118. package/src/web/mirror_hook.ts +0 -25
  119. package/src/web/mirror_server.ts +0 -204
  120. package/tsconfig.json +0 -22
  121. package/vite.config.ts +0 -363
  122. /package/{packages/ztc-dictation/bin → bin}/.gitkeep +0 -0
@@ -1,171 +0,0 @@
1
- /**
2
- * Box-drawing table utilities
3
- * Uses Unicode box-drawing characters for clean terminal tables
4
- */
5
-
6
- // Box-drawing characters
7
- const BOX = {
8
- topLeft: '┌',
9
- topRight: '┐',
10
- bottomLeft: '└',
11
- bottomRight: '┘',
12
- horizontal: '─',
13
- vertical: '│',
14
- leftT: '├',
15
- rightT: '┤',
16
- topT: '┬',
17
- bottomT: '┴',
18
- cross: '┼'
19
- };
20
-
21
- // Light box (for subtler tables)
22
- const BOX_LIGHT = {
23
- topLeft: '╭',
24
- topRight: '╮',
25
- bottomLeft: '╰',
26
- bottomRight: '╯',
27
- horizontal: '─',
28
- vertical: '│',
29
- leftT: '├',
30
- rightT: '┤',
31
- topT: '┬',
32
- bottomT: '┴',
33
- cross: '┼'
34
- };
35
-
36
- export interface TableColumn {
37
- header: string;
38
- key: string;
39
- width?: number;
40
- align?: 'left' | 'right' | 'center';
41
- }
42
-
43
- export interface TableOptions {
44
- rounded?: boolean;
45
- headerSeparator?: boolean;
46
- compact?: boolean;
47
- }
48
-
49
- function padString(str: string, width: number, align: 'left' | 'right' | 'center' = 'left'): string {
50
- const visibleLength = str.replace(/\x1b\[[0-9;]*m/g, '').length;
51
- const padding = Math.max(0, width - visibleLength);
52
-
53
- if (align === 'right') {
54
- return ' '.repeat(padding) + str;
55
- }
56
- if (align === 'center') {
57
- const left = Math.floor(padding / 2);
58
- const right = padding - left;
59
- return ' '.repeat(left) + str + ' '.repeat(right);
60
- }
61
- return str + ' '.repeat(padding);
62
- }
63
-
64
- function getColumnWidths(columns: TableColumn[], rows: Record<string, unknown>[]): number[] {
65
- return columns.map(col => {
66
- const headerWidth = col.header.length;
67
- const dataWidth = rows.reduce((max, row) => {
68
- const value = String(row[col.key] || '');
69
- const visibleLength = value.replace(/\x1b\[[0-9;]*m/g, '').length;
70
- return Math.max(max, visibleLength);
71
- }, 0);
72
- return col.width || Math.max(headerWidth, dataWidth);
73
- });
74
- }
75
-
76
- /**
77
- * Format data as a box-drawing table
78
- */
79
- export function formatTable(
80
- columns: TableColumn[],
81
- rows: Record<string, unknown>[],
82
- options: TableOptions = {}
83
- ): string {
84
- const { rounded = false, headerSeparator = true, compact = false } = options;
85
- const box = rounded ? BOX_LIGHT : BOX;
86
- const widths = getColumnWidths(columns, rows);
87
- const lines: string[] = [];
88
-
89
- // Top border
90
- const topBorder = box.topLeft +
91
- widths.map(w => box.horizontal.repeat(w + 2)).join(box.topT) +
92
- box.topRight;
93
- lines.push(topBorder);
94
-
95
- // Header row
96
- const headerRow = box.vertical +
97
- columns.map((col, i) => ' ' + padString(col.header, widths[i], 'center') + ' ').join(box.vertical) +
98
- box.vertical;
99
- lines.push(headerRow);
100
-
101
- // Header separator
102
- if (headerSeparator) {
103
- const separator = box.leftT +
104
- widths.map(w => box.horizontal.repeat(w + 2)).join(box.cross) +
105
- box.rightT;
106
- lines.push(separator);
107
- }
108
-
109
- // Data rows
110
- for (const row of rows) {
111
- const dataRow = box.vertical +
112
- columns.map((col, i) => {
113
- const value = String(row[col.key] || '');
114
- return ' ' + padString(value, widths[i], col.align) + ' ';
115
- }).join(box.vertical) +
116
- box.vertical;
117
- lines.push(dataRow);
118
-
119
- // Row separator (if not compact)
120
- if (!compact && rows.indexOf(row) < rows.length - 1) {
121
- const rowSep = box.leftT +
122
- widths.map(w => box.horizontal.repeat(w + 2)).join(box.cross) +
123
- box.rightT;
124
- lines.push(rowSep);
125
- }
126
- }
127
-
128
- // Bottom border
129
- const bottomBorder = box.bottomLeft +
130
- widths.map(w => box.horizontal.repeat(w + 2)).join(box.bottomT) +
131
- box.bottomRight;
132
- lines.push(bottomBorder);
133
-
134
- return lines.join('\n');
135
- }
136
-
137
- /**
138
- * Simple two-column table (key-value style)
139
- */
140
- export function formatKeyValueTable(
141
- data: Array<{ label: string; value: string }>,
142
- options: TableOptions = {}
143
- ): string {
144
- const columns: TableColumn[] = [
145
- { header: 'Key', key: 'label', align: 'left' },
146
- { header: 'Value', key: 'value', align: 'left' }
147
- ];
148
- const rows = data.map(d => ({ label: d.label, value: d.value }));
149
- return formatTable(columns, rows, { ...options, headerSeparator: false });
150
- }
151
-
152
- /**
153
- * Format a schedule/calendar table
154
- */
155
- export function formatScheduleTable(
156
- events: Array<{ time: string; event: string }>,
157
- options: TableOptions = {}
158
- ): string {
159
- const columns: TableColumn[] = [
160
- { header: 'Time', key: 'time', align: 'left', width: 7 },
161
- { header: 'Event', key: 'event', align: 'left' }
162
- ];
163
- return formatTable(columns, events, { rounded: true, compact: true, ...options });
164
- }
165
-
166
- /**
167
- * Simple horizontal line/divider
168
- */
169
- export function formatDivider(width = 80, char = '─'): string {
170
- return char.repeat(width);
171
- }
@@ -1,56 +0,0 @@
1
- type ParsedResult = Record<string, unknown>;
2
-
3
- function parseResult(raw: string): ParsedResult | null {
4
- try {
5
- const data = JSON.parse(raw) as ParsedResult;
6
- if (data && typeof data === 'object') return data;
7
- } catch {
8
- return null;
9
- }
10
- return null;
11
- }
12
-
13
- export function summarizeToolResult(tool: string, raw: string): string {
14
- const parsed = parseResult(raw);
15
- if (!parsed) {
16
- const trimmed = raw.trim();
17
- return trimmed.length > 140 ? `${trimmed.slice(0, 140)}...` : trimmed || 'Done';
18
- }
19
-
20
- if (tool === 'read_file') {
21
- const path = String(parsed.path || '');
22
- const size = parsed.size ? ` (${parsed.size} bytes)` : '';
23
- return `Read ${path}${size}`;
24
- }
25
- if (tool === 'write_file') {
26
- const path = String(parsed.path || '');
27
- const action = String(parsed.action || 'written');
28
- return `Wrote ${path} (${action})`;
29
- }
30
- if (tool === 'list_directory') {
31
- const path = String(parsed.path || '');
32
- const entries = Array.isArray(parsed.entries) ? parsed.entries.length : 0;
33
- return `Listed ${path} (${entries} items)`;
34
- }
35
- if (tool === 'run_command') {
36
- const cwd = String(parsed.cwd || '');
37
- const cmd = String(parsed.command || '');
38
- return `Ran ${cmd}${cwd ? ` (cwd ${cwd})` : ''}`;
39
- }
40
- if (tool === 'search') {
41
- const count = parsed.count ? String(parsed.count) : '0';
42
- const path = String(parsed.path || '');
43
- return `Found ${count} matches${path ? ` in ${path}` : ''}`;
44
- }
45
-
46
- const fallback = raw.trim();
47
- return fallback.length > 140 ? `${fallback.slice(0, 140)}...` : fallback || 'Done';
48
- }
49
-
50
- export function summarizeToolArgs(args: Record<string, unknown>): string {
51
- const entries = Object.entries(args)
52
- .map(([key, value]) => `${key}=${String(value)}`)
53
- .slice(0, 3);
54
- if (entries.length === 0) return '';
55
- return `(${entries.join(', ')}${Object.keys(args).length > 3 ? ', ...' : ''})`;
56
- }
@@ -1,346 +0,0 @@
1
- import { getTraceStyle } from '../emulation/trace_style.js';
2
- import { formatTracePath, formatBytes, formatDuration } from './path_format.js';
3
-
4
- const toolLabels: Record<string, string> = {
5
- run_command: 'Bash',
6
- read_file: 'Read',
7
- write_file: 'Update',
8
- list_directory: 'List',
9
- search: 'Search',
10
- screenshot: 'Screenshot',
11
- list_windows: 'ListWindows',
12
- run_and_capture: 'RunCapture'
13
- };
14
-
15
- function formatArgs(tool: string, args: Record<string, unknown>): string {
16
- // Compact arg formatting - just show the key values
17
- if (tool === 'run_command') {
18
- const command = args.command ? String(args.command) : '';
19
- // Truncate long commands
20
- const truncated = command.length > 60 ? command.slice(0, 57) + '...' : command;
21
- return `(${truncated})`;
22
- }
23
-
24
- if (tool === 'search') {
25
- const pattern = args.pattern ? String(args.pattern) : '';
26
- const path = args.path ? formatTracePath(String(args.path)) : '';
27
- if (path) {
28
- return `(${pattern}, ${path})`;
29
- }
30
- return `(${pattern})`;
31
- }
32
-
33
- if (tool === 'read_file' || tool === 'write_file' || tool === 'list_directory') {
34
- const path = args.path ? formatTracePath(String(args.path)) : '';
35
- return `(${path})`;
36
- }
37
-
38
- if (tool === 'screenshot') {
39
- if (args.app) return `(app: "${args.app}")`;
40
- if (args.pid) return `(pid: ${args.pid})`;
41
- if (args.windowId) return `(windowId: ${args.windowId})`;
42
- return '';
43
- }
44
-
45
- if (tool === 'list_windows') {
46
- if (args.filter) return `(filter: "${args.filter}")`;
47
- return '';
48
- }
49
-
50
- // Generic: show first few args compactly
51
- const entries = Object.entries(args).slice(0, 3);
52
- if (entries.length === 0) return '';
53
-
54
- const parts = entries.map(([key, value]) => {
55
- if (typeof value === 'string') {
56
- const v = value.length > 30 ? value.slice(0, 27) + '...' : value;
57
- return `${key}: "${v}"`;
58
- }
59
- return `${key}: ${value}`;
60
- });
61
-
62
- return `(${parts.join(', ')})`;
63
- }
64
-
65
- function parseResult(raw: string): Record<string, unknown> | null {
66
- try {
67
- const data = JSON.parse(raw) as Record<string, unknown>;
68
- if (data && typeof data === 'object') return data;
69
- } catch {
70
- return null;
71
- }
72
- return null;
73
- }
74
-
75
- interface ParsedDiff {
76
- addedLines: number;
77
- removedLines: number;
78
- hunks: Array<{
79
- header: string;
80
- lines: Array<{ type: 'add' | 'remove' | 'context'; lineNum?: number; text: string }>;
81
- }>;
82
- }
83
-
84
- function parseDiff(diff: string): ParsedDiff | null {
85
- if (!diff || !diff.includes('@@')) return null;
86
-
87
- const lines = diff.split('\n');
88
- let addedLines = 0;
89
- let removedLines = 0;
90
- const hunks: ParsedDiff['hunks'] = [];
91
- let currentHunk: ParsedDiff['hunks'][0] | null = null;
92
-
93
- for (const line of lines) {
94
- if (line.startsWith('@@')) {
95
- if (currentHunk) hunks.push(currentHunk);
96
- currentHunk = { header: line, lines: [] };
97
- continue;
98
- }
99
-
100
- if (!currentHunk) continue;
101
-
102
- if (line.startsWith('+') && !line.startsWith('+++')) {
103
- addedLines++;
104
- currentHunk.lines.push({ type: 'add', text: line.slice(1) });
105
- } else if (line.startsWith('-') && !line.startsWith('---')) {
106
- removedLines++;
107
- currentHunk.lines.push({ type: 'remove', text: line.slice(1) });
108
- } else if (line.startsWith(' ')) {
109
- currentHunk.lines.push({ type: 'context', text: line.slice(1) });
110
- }
111
- }
112
-
113
- if (currentHunk) hunks.push(currentHunk);
114
-
115
- return { addedLines, removedLines, hunks };
116
- }
117
-
118
- function formatOutcome(tool: string, result: string, durationMs?: number): string {
119
- const parsed = parseResult(result);
120
- const duration = typeof durationMs === 'number' ? ` in ${formatDuration(durationMs)}` : '';
121
-
122
- if (parsed && tool === 'search') {
123
- const count = typeof parsed.count === 'number' ? parsed.count : 0;
124
- const label = count === 1 ? 'match' : 'matches';
125
- return `Found ${count} ${label}${duration}`;
126
- }
127
-
128
- if (parsed && tool === 'run_command') {
129
- const stdout = String(parsed.stdout || '');
130
- const stderr = String(parsed.stderr || '');
131
- const lines = (stdout || stderr).trim().split('\n').filter(Boolean).length;
132
- const label = lines === 1 ? 'line' : 'lines';
133
- return lines > 0 ? `Output ${lines} ${label}${duration}` : `Done${duration}`;
134
- }
135
-
136
- if (parsed && tool === 'read_file') {
137
- const path = formatTracePath(String(parsed.path || ''));
138
- const size = typeof parsed.size === 'number' ? formatBytes(parsed.size) : '';
139
- const truncated = parsed.truncated ? ' (truncated)' : '';
140
- return `${path} (${size})${duration}${truncated}`;
141
- }
142
-
143
- if (parsed && tool === 'write_file') {
144
- const path = formatTracePath(String(parsed.path || ''));
145
- const diff = parseDiff(String(parsed.diff || ''));
146
- if (diff) {
147
- const parts: string[] = [];
148
- if (diff.addedLines > 0) parts.push(`+${diff.addedLines}`);
149
- if (diff.removedLines > 0) parts.push(`-${diff.removedLines}`);
150
- const summary = parts.length > 0 ? ` (${parts.join(', ')} lines)` : '';
151
- return `${path}${summary}${duration}`;
152
- }
153
- return `${path}${duration}`;
154
- }
155
-
156
- if (parsed && tool === 'list_directory') {
157
- const path = formatTracePath(String(parsed.path || ''));
158
- const entries = Array.isArray(parsed.entries) ? parsed.entries.length : 0;
159
- return `${path} (${entries} items)${duration}`;
160
- }
161
-
162
- if (parsed && tool === 'screenshot') {
163
- const desc = String(parsed.description || 'Screenshot captured');
164
- return `${desc}${duration}`;
165
- }
166
-
167
- return `Done${duration}`;
168
- }
169
-
170
- function buildOutputLines(tool: string, result: string): { lines: string[]; truncated: boolean } {
171
- const parsed = parseResult(result);
172
- if (!parsed) {
173
- return { lines: [], truncated: false };
174
- }
175
-
176
- if (tool === 'run_command') {
177
- const stdout = String(parsed.stdout || '');
178
- const stderr = String(parsed.stderr || '');
179
- const combined = [stdout, stderr].filter(Boolean).join('\n');
180
- const lines = combined.split('\n').filter(Boolean);
181
- return { lines, truncated: Boolean(parsed.truncated) };
182
- }
183
-
184
- if (tool === 'search') {
185
- const matches = Array.isArray(parsed.matches) ? parsed.matches : [];
186
- const lines = matches.map((entry: unknown) => {
187
- if (!entry || typeof entry !== 'object') return '';
188
- const row = entry as Record<string, unknown>;
189
- const file = formatTracePath(String(row.path || ''));
190
- const line = row.line ? `:${row.line}` : '';
191
- const text = String(row.text || '');
192
- return `${file}${line} ${text}`.trim();
193
- }).filter(Boolean);
194
- return { lines, truncated: Boolean(parsed.truncated) };
195
- }
196
-
197
- if (tool === 'read_file') {
198
- const content = String(parsed.content || '');
199
- const lines = content.split('\n');
200
- return { lines, truncated: Boolean(parsed.truncated) };
201
- }
202
-
203
- if (tool === 'write_file') {
204
- // Return formatted diff lines
205
- const diff = parseDiff(String(parsed.diff || ''));
206
- if (diff && diff.hunks.length > 0) {
207
- const lines: string[] = [];
208
- for (const hunk of diff.hunks) {
209
- for (const line of hunk.lines) {
210
- if (line.type === 'add') {
211
- lines.push(`+ ${line.text}`);
212
- } else if (line.type === 'remove') {
213
- lines.push(`- ${line.text}`);
214
- } else {
215
- lines.push(` ${line.text}`);
216
- }
217
- }
218
- }
219
- return { lines, truncated: Boolean(parsed.truncated) };
220
- }
221
- return { lines: [], truncated: false };
222
- }
223
-
224
- return { lines: [], truncated: false };
225
- }
226
-
227
- export function formatToolStart(tool: string, args: Record<string, unknown>, emulationId?: string): string {
228
- const style = getTraceStyle(emulationId);
229
- const label = toolLabels[tool] || tool;
230
- const argsText = formatArgs(tool, args);
231
-
232
- if (style === 'claude_code') {
233
- return `⏺ ${label}${argsText}`;
234
- }
235
- if (style === 'codex') {
236
- if (tool === 'run_command') {
237
- const command = args.command ? String(args.command) : '';
238
- return `! ${command}`;
239
- }
240
- return `⏺ ${label}${argsText}`;
241
- }
242
- return `> ${label}${argsText}`;
243
- }
244
-
245
- export function formatToolEnd(tool: string, result: string, durationMs?: number, emulationId?: string): string {
246
- const style = getTraceStyle(emulationId);
247
- const summary = formatOutcome(tool, result, durationMs);
248
-
249
- if (style === 'claude_code') {
250
- return `⎿ ${summary}`;
251
- }
252
- if (style === 'codex') {
253
- if (tool === 'run_command') {
254
- const { lines } = buildOutputLines(tool, result);
255
- if (lines.length === 0) {
256
- return ` ⎿ (No content)`;
257
- }
258
- }
259
- return ` ⎿ ${summary}`;
260
- }
261
- return `< ${summary}`;
262
- }
263
-
264
- export function formatToolError(tool: string, error: string, emulationId?: string): string {
265
- const style = getTraceStyle(emulationId);
266
- const label = toolLabels[tool] || tool;
267
-
268
- // Provide helpful error messages
269
- let displayError = error;
270
- if (error.includes('Screen Recording permission')) {
271
- displayError = 'Screen Recording permission required (System Settings > Privacy & Security)';
272
- }
273
-
274
- if (style === 'claude_code') {
275
- return `⎿ ${label} failed: ${displayError}`;
276
- }
277
- if (style === 'codex') {
278
- return ` ${label} failed: ${displayError}`;
279
- }
280
- return `< ${label} failed: ${displayError}`;
281
- }
282
-
283
- export interface ToolOutputMessage {
284
- preview: string;
285
- full: string;
286
- truncated: boolean;
287
- diffLines?: Array<{ type: 'add' | 'remove' | 'context'; text: string }>;
288
- }
289
-
290
- export function buildToolOutputMessage(
291
- tool: string,
292
- result: string,
293
- durationMs?: number,
294
- emulationId?: string
295
- ): ToolOutputMessage {
296
- const { lines, truncated } = buildOutputLines(tool, result);
297
- const parsed = parseResult(result);
298
-
299
- // For write_file, extract diff info
300
- let diffLines: ToolOutputMessage['diffLines'];
301
- if (tool === 'write_file' && parsed) {
302
- const diff = parseDiff(String(parsed.diff || ''));
303
- if (diff && diff.hunks.length > 0) {
304
- diffLines = [];
305
- for (const hunk of diff.hunks) {
306
- for (const line of hunk.lines) {
307
- diffLines.push({ type: line.type, text: line.text });
308
- }
309
- }
310
- }
311
- }
312
-
313
- if (lines.length === 0 && !diffLines) {
314
- const summary = formatToolEnd(tool, result, durationMs, emulationId);
315
- return { preview: summary, full: summary, truncated: false };
316
- }
317
-
318
- const maxLines = 8;
319
- const previewLines = lines.slice(0, maxLines);
320
- const remaining = lines.length - previewLines.length;
321
- const expandHint = truncated || remaining > 0 ? ' (ctrl+o to expand)' : '';
322
-
323
- const summary = formatToolEnd(tool, result, durationMs, emulationId);
324
- const indent = ' ';
325
-
326
- const previewBlock = [summary];
327
- for (const line of previewLines) {
328
- previewBlock.push(`${indent}${line}`);
329
- }
330
- if (expandHint) {
331
- const extraLabel = remaining > 0 ? `… +${remaining} lines` : '…';
332
- previewBlock.push(`${indent}${extraLabel}${expandHint}`);
333
- }
334
-
335
- const fullBlock = [summary];
336
- for (const line of lines) {
337
- fullBlock.push(`${indent}${line}`);
338
- }
339
-
340
- return {
341
- preview: previewBlock.join('\n'),
342
- full: fullBlock.join('\n'),
343
- truncated: Boolean(expandHint),
344
- diffLines
345
- };
346
- }
@@ -1,44 +0,0 @@
1
- const PACKAGE_NAME = 'zerg-ztc';
2
-
3
- export interface UpdateCheck {
4
- current: string;
5
- latest: string;
6
- hasUpdate: boolean;
7
- }
8
-
9
- function parseVersion(value: string): number[] {
10
- return value.split('.').map(part => Number(part.replace(/[^0-9]/g, '')) || 0);
11
- }
12
-
13
- export function compareVersions(a: string, b: string): number {
14
- const pa = parseVersion(a);
15
- const pb = parseVersion(b);
16
- const len = Math.max(pa.length, pb.length);
17
- for (let i = 0; i < len; i += 1) {
18
- const av = pa[i] ?? 0;
19
- const bv = pb[i] ?? 0;
20
- if (av > bv) return 1;
21
- if (av < bv) return -1;
22
- }
23
- return 0;
24
- }
25
-
26
- export async function fetchLatestVersion(): Promise<string> {
27
- const res = await fetch(`https://registry.npmjs.org/${PACKAGE_NAME}/latest`, {
28
- headers: { 'Accept': 'application/json' }
29
- });
30
- if (!res.ok) {
31
- throw new Error(`Version check failed (${res.status})`);
32
- }
33
- const data = await res.json() as { version?: string };
34
- return data.version || '0.0.0';
35
- }
36
-
37
- export async function checkForUpdate(current: string): Promise<UpdateCheck> {
38
- const latest = await fetchLatestVersion();
39
- return {
40
- current,
41
- latest,
42
- hasUpdate: compareVersions(latest, current) > 0
43
- };
44
- }
@@ -1,15 +0,0 @@
1
- import { readFileSync } from 'fs';
2
- import { dirname, resolve } from 'path';
3
- import { fileURLToPath } from 'url';
4
-
5
- export function getVersion(): string {
6
- try {
7
- const here = dirname(fileURLToPath(import.meta.url));
8
- const pkgPath = resolve(here, '../../package.json');
9
- const raw = readFileSync(pkgPath, 'utf-8');
10
- const parsed = JSON.parse(raw) as { version?: string };
11
- return parsed.version || '0.0.0';
12
- } catch {
13
- return '0.0.0';
14
- }
15
- }