zerg-ztc 0.1.7 → 0.1.11

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 (106) hide show
  1. package/dist/App.d.ts.map +1 -1
  2. package/dist/App.js +75 -8
  3. package/dist/App.js.map +1 -1
  4. package/dist/agent/agent.d.ts +2 -0
  5. package/dist/agent/agent.d.ts.map +1 -1
  6. package/dist/agent/agent.js +111 -10
  7. package/dist/agent/agent.js.map +1 -1
  8. package/dist/agent/backends/anthropic.d.ts.map +1 -1
  9. package/dist/agent/backends/anthropic.js +15 -3
  10. package/dist/agent/backends/anthropic.js.map +1 -1
  11. package/dist/agent/backends/gemini.d.ts.map +1 -1
  12. package/dist/agent/backends/gemini.js +12 -0
  13. package/dist/agent/backends/gemini.js.map +1 -1
  14. package/dist/agent/backends/index.d.ts +1 -1
  15. package/dist/agent/backends/index.d.ts.map +1 -1
  16. package/dist/agent/backends/openai_compatible.d.ts.map +1 -1
  17. package/dist/agent/backends/openai_compatible.js +12 -0
  18. package/dist/agent/backends/openai_compatible.js.map +1 -1
  19. package/dist/agent/backends/types.d.ts +21 -1
  20. package/dist/agent/backends/types.d.ts.map +1 -1
  21. package/dist/agent/commands/dictation.d.ts +3 -0
  22. package/dist/agent/commands/dictation.d.ts.map +1 -0
  23. package/dist/agent/commands/dictation.js +10 -0
  24. package/dist/agent/commands/dictation.js.map +1 -0
  25. package/dist/agent/commands/index.d.ts.map +1 -1
  26. package/dist/agent/commands/index.js +2 -1
  27. package/dist/agent/commands/index.js.map +1 -1
  28. package/dist/agent/commands/types.d.ts +7 -0
  29. package/dist/agent/commands/types.d.ts.map +1 -1
  30. package/dist/agent/runtime/capabilities.d.ts +2 -1
  31. package/dist/agent/runtime/capabilities.d.ts.map +1 -1
  32. package/dist/agent/runtime/capabilities.js +1 -0
  33. package/dist/agent/runtime/capabilities.js.map +1 -1
  34. package/dist/agent/tools/index.d.ts +1 -0
  35. package/dist/agent/tools/index.d.ts.map +1 -1
  36. package/dist/agent/tools/index.js +6 -1
  37. package/dist/agent/tools/index.js.map +1 -1
  38. package/dist/agent/tools/screenshot.d.ts +23 -0
  39. package/dist/agent/tools/screenshot.d.ts.map +1 -0
  40. package/dist/agent/tools/screenshot.js +735 -0
  41. package/dist/agent/tools/screenshot.js.map +1 -0
  42. package/dist/components/InputArea.d.ts +1 -0
  43. package/dist/components/InputArea.d.ts.map +1 -1
  44. package/dist/components/InputArea.js +591 -43
  45. package/dist/components/InputArea.js.map +1 -1
  46. package/dist/components/SingleMessage.d.ts.map +1 -1
  47. package/dist/components/SingleMessage.js +157 -7
  48. package/dist/components/SingleMessage.js.map +1 -1
  49. package/dist/config/types.d.ts +6 -0
  50. package/dist/config/types.d.ts.map +1 -1
  51. package/dist/ui/views/status_bar.js +2 -2
  52. package/dist/ui/views/status_bar.js.map +1 -1
  53. package/dist/utils/dictation.d.ts +46 -0
  54. package/dist/utils/dictation.d.ts.map +1 -0
  55. package/dist/utils/dictation.js +409 -0
  56. package/dist/utils/dictation.js.map +1 -0
  57. package/dist/utils/dictation_native.d.ts +51 -0
  58. package/dist/utils/dictation_native.d.ts.map +1 -0
  59. package/dist/utils/dictation_native.js +216 -0
  60. package/dist/utils/dictation_native.js.map +1 -0
  61. package/dist/utils/path_complete.d.ts.map +1 -1
  62. package/dist/utils/path_complete.js +31 -6
  63. package/dist/utils/path_complete.js.map +1 -1
  64. package/dist/utils/path_format.d.ts +20 -0
  65. package/dist/utils/path_format.d.ts.map +1 -0
  66. package/dist/utils/path_format.js +90 -0
  67. package/dist/utils/path_format.js.map +1 -0
  68. package/dist/utils/table.d.ts +38 -0
  69. package/dist/utils/table.d.ts.map +1 -0
  70. package/dist/utils/table.js +133 -0
  71. package/dist/utils/table.js.map +1 -0
  72. package/dist/utils/tool_trace.d.ts +7 -2
  73. package/dist/utils/tool_trace.d.ts.map +1 -1
  74. package/dist/utils/tool_trace.js +156 -51
  75. package/dist/utils/tool_trace.js.map +1 -1
  76. package/package.json +4 -1
  77. package/packages/ztc-dictation/Cargo.toml +43 -0
  78. package/packages/ztc-dictation/README.md +65 -0
  79. package/packages/ztc-dictation/bin/.gitkeep +0 -0
  80. package/packages/ztc-dictation/index.d.ts +16 -0
  81. package/packages/ztc-dictation/index.js +74 -0
  82. package/packages/ztc-dictation/package.json +41 -0
  83. package/packages/ztc-dictation/src/main.rs +430 -0
  84. package/src/App.tsx +110 -7
  85. package/src/agent/agent.ts +116 -11
  86. package/src/agent/backends/anthropic.ts +15 -5
  87. package/src/agent/backends/gemini.ts +12 -0
  88. package/src/agent/backends/index.ts +1 -0
  89. package/src/agent/backends/openai_compatible.ts +12 -0
  90. package/src/agent/backends/types.ts +25 -1
  91. package/src/agent/commands/dictation.ts +11 -0
  92. package/src/agent/commands/index.ts +2 -0
  93. package/src/agent/commands/types.ts +8 -0
  94. package/src/agent/runtime/capabilities.ts +2 -1
  95. package/src/agent/tools/index.ts +6 -1
  96. package/src/agent/tools/screenshot.ts +821 -0
  97. package/src/components/InputArea.tsx +606 -42
  98. package/src/components/SingleMessage.tsx +248 -9
  99. package/src/config/types.ts +7 -0
  100. package/src/ui/views/status_bar.ts +2 -2
  101. package/src/utils/dictation.ts +467 -0
  102. package/src/utils/dictation_native.ts +258 -0
  103. package/src/utils/path_complete.ts +30 -4
  104. package/src/utils/path_format.ts +99 -0
  105. package/src/utils/table.ts +171 -0
  106. package/src/utils/tool_trace.ts +184 -54
@@ -2,6 +2,111 @@ import React from 'react';
2
2
  import { Box, Text } from 'ink';
3
3
  import { Message } from '../types.js';
4
4
 
5
+ // Box-drawing characters for tables
6
+ const BOX = {
7
+ topLeft: '╭',
8
+ topRight: '╮',
9
+ bottomLeft: '╰',
10
+ bottomRight: '╯',
11
+ horizontal: '─',
12
+ vertical: '│',
13
+ leftT: '├',
14
+ rightT: '┤',
15
+ topT: '┬',
16
+ bottomT: '┴',
17
+ cross: '┼'
18
+ };
19
+
20
+ interface ParsedTable {
21
+ headers: string[];
22
+ rows: string[][];
23
+ }
24
+
25
+ function parseMarkdownTable(lines: string[]): ParsedTable | null {
26
+ // Need at least header row and separator row
27
+ if (lines.length < 2) return null;
28
+
29
+ const headerLine = lines[0];
30
+ const separatorLine = lines[1];
31
+
32
+ // Check if it looks like a markdown table
33
+ if (!headerLine.includes('|') || !separatorLine.match(/^\|?[\s\-:|]+\|?$/)) {
34
+ return null;
35
+ }
36
+
37
+ const parseRow = (line: string): string[] => {
38
+ return line
39
+ .split('|')
40
+ .map(cell => cell.trim())
41
+ .filter((_, i, arr) => i > 0 && i < arr.length - 1 || (arr.length === 2 && i === 0));
42
+ };
43
+
44
+ const headers = parseRow(headerLine);
45
+ if (headers.length === 0) return null;
46
+
47
+ const rows: string[][] = [];
48
+ for (let i = 2; i < lines.length; i++) {
49
+ if (!lines[i].includes('|')) break;
50
+ rows.push(parseRow(lines[i]));
51
+ }
52
+
53
+ return { headers, rows };
54
+ }
55
+
56
+ function renderBoxTable(table: ParsedTable): string[] {
57
+ const { headers, rows } = table;
58
+
59
+ // Calculate column widths
60
+ const widths = headers.map((h, i) => {
61
+ const dataMax = rows.reduce((max, row) => {
62
+ const cell = row[i] || '';
63
+ return Math.max(max, cell.length);
64
+ }, 0);
65
+ return Math.max(h.length, dataMax);
66
+ });
67
+
68
+ const output: string[] = [];
69
+
70
+ // Top border
71
+ output.push(
72
+ BOX.topLeft +
73
+ widths.map(w => BOX.horizontal.repeat(w + 2)).join(BOX.topT) +
74
+ BOX.topRight
75
+ );
76
+
77
+ // Header row
78
+ output.push(
79
+ BOX.vertical +
80
+ headers.map((h, i) => ' ' + h.padEnd(widths[i]) + ' ').join(BOX.vertical) +
81
+ BOX.vertical
82
+ );
83
+
84
+ // Header separator
85
+ output.push(
86
+ BOX.leftT +
87
+ widths.map(w => BOX.horizontal.repeat(w + 2)).join(BOX.cross) +
88
+ BOX.rightT
89
+ );
90
+
91
+ // Data rows
92
+ for (const row of rows) {
93
+ output.push(
94
+ BOX.vertical +
95
+ widths.map((w, i) => ' ' + (row[i] || '').padEnd(w) + ' ').join(BOX.vertical) +
96
+ BOX.vertical
97
+ );
98
+ }
99
+
100
+ // Bottom border
101
+ output.push(
102
+ BOX.bottomLeft +
103
+ widths.map(w => BOX.horizontal.repeat(w + 2)).join(BOX.bottomT) +
104
+ BOX.bottomRight
105
+ );
106
+
107
+ return output;
108
+ }
109
+
5
110
  interface SingleMessageProps {
6
111
  message: Message;
7
112
  expandToolOutputs?: boolean;
@@ -28,17 +133,149 @@ function formatTime(date: Date): string {
28
133
  });
29
134
  }
30
135
 
136
+ interface DiffLine {
137
+ type: 'add' | 'remove' | 'context';
138
+ text: string;
139
+ }
140
+
141
+ interface ToolOutput {
142
+ preview: string;
143
+ full: string;
144
+ truncated: boolean;
145
+ diffLines?: DiffLine[];
146
+ }
147
+
148
+ // Render a line with diff coloring
149
+ const DiffLineComponent: React.FC<{ line: DiffLine; lineNum?: number }> = ({ line, lineNum }) => {
150
+ const prefix = line.type === 'add' ? '+' : line.type === 'remove' ? '-' : ' ';
151
+ const color = line.type === 'add' ? 'green' : line.type === 'remove' ? 'red' : undefined;
152
+ const lineNumStr = lineNum !== undefined ? `${String(lineNum).padStart(4)} ` : '';
153
+
154
+ return (
155
+ <Text color={color}>
156
+ {' '}{lineNumStr}{prefix} {line.text}
157
+ </Text>
158
+ );
159
+ };
160
+
161
+ // Render content with diff awareness and markdown table support
162
+ const ContentRenderer: React.FC<{
163
+ content: string;
164
+ diffLines?: DiffLine[];
165
+ isToolTrace: boolean;
166
+ }> = ({ content, diffLines, isToolTrace }) => {
167
+ // If we have structured diff lines, render them with colors
168
+ if (diffLines && diffLines.length > 0 && isToolTrace) {
169
+ const lines = content.split('\n');
170
+ const summaryLine = lines[0] || '';
171
+
172
+ return (
173
+ <Box flexDirection="column">
174
+ <Text>{summaryLine}</Text>
175
+ {diffLines.map((line, i) => (
176
+ <DiffLineComponent key={i} line={line} />
177
+ ))}
178
+ </Box>
179
+ );
180
+ }
181
+
182
+ // Parse content into segments (text and tables)
183
+ const lines = content.split('\n');
184
+ const segments: Array<{ type: 'text' | 'table'; lines: string[] }> = [];
185
+ let i = 0;
186
+
187
+ while (i < lines.length) {
188
+ const line = lines[i];
189
+
190
+ // Check if this looks like the start of a markdown table
191
+ if (line.includes('|') && i + 1 < lines.length && lines[i + 1].match(/^\|?[\s\-:|]+\|?$/)) {
192
+ // Collect all table lines
193
+ const tableLines: string[] = [line];
194
+ let j = i + 1;
195
+ while (j < lines.length && lines[j].includes('|')) {
196
+ tableLines.push(lines[j]);
197
+ j++;
198
+ }
199
+
200
+ const parsed = parseMarkdownTable(tableLines);
201
+ if (parsed && parsed.rows.length > 0) {
202
+ const boxLines = renderBoxTable(parsed);
203
+ segments.push({ type: 'table', lines: boxLines });
204
+ i = j;
205
+ continue;
206
+ }
207
+ }
208
+
209
+ // Regular text line
210
+ if (segments.length === 0 || segments[segments.length - 1].type !== 'text') {
211
+ segments.push({ type: 'text', lines: [] });
212
+ }
213
+ segments[segments.length - 1].lines.push(line);
214
+ i++;
215
+ }
216
+
217
+ return (
218
+ <Box flexDirection="column">
219
+ {segments.map((segment, segIdx) => (
220
+ <Box key={segIdx} flexDirection="column">
221
+ {segment.lines.map((line, lineIdx) => {
222
+ // Color diff lines in output
223
+ if (isToolTrace) {
224
+ const trimmed = line.trimStart();
225
+ if (trimmed.startsWith('+ ') && !trimmed.startsWith('+ …')) {
226
+ return <Text key={lineIdx} color="green">{line}</Text>;
227
+ }
228
+ if (trimmed.startsWith('- ')) {
229
+ return <Text key={lineIdx} color="red">{line}</Text>;
230
+ }
231
+ }
232
+ // Table lines get a subtle color
233
+ if (segment.type === 'table') {
234
+ return <Text key={lineIdx} color="cyan">{line}</Text>;
235
+ }
236
+ return <Text key={lineIdx}>{line}</Text>;
237
+ })}
238
+ </Box>
239
+ ))}
240
+ </Box>
241
+ );
242
+ };
243
+
31
244
  export const SingleMessage: React.FC<SingleMessageProps> = ({
32
245
  message,
33
246
  expandToolOutputs = false
34
247
  }) => {
35
248
  const config = roleConfigs[message.role] || roleConfigs.system;
36
- const toolOutput = message.metadata && (message.metadata as Record<string, any>).toolOutput;
37
- const content = toolOutput && expandToolOutputs && toolOutput.full
38
- ? toolOutput.full
39
- : toolOutput && toolOutput.preview
40
- ? toolOutput.preview
41
- : message.content;
249
+ const metadata = message.metadata as Record<string, unknown> | undefined;
250
+ const toolOutput = metadata?.toolOutput as ToolOutput | undefined;
251
+
252
+ // Determine content to show
253
+ let content: string;
254
+ let diffLines: DiffLine[] | undefined;
255
+
256
+ if (toolOutput) {
257
+ content = expandToolOutputs && toolOutput.full ? toolOutput.full : toolOutput.preview;
258
+ diffLines = toolOutput.diffLines;
259
+ } else {
260
+ content = message.content;
261
+ }
262
+
263
+ const isToolTrace = message.role === 'tool';
264
+
265
+ // For tool traces, use more compact display
266
+ if (isToolTrace) {
267
+ return (
268
+ <Box flexDirection="column" marginY={0} paddingX={1}>
269
+ <Box flexDirection="column" marginLeft={1}>
270
+ <ContentRenderer
271
+ content={content}
272
+ diffLines={diffLines}
273
+ isToolTrace={true}
274
+ />
275
+ </Box>
276
+ </Box>
277
+ );
278
+ }
42
279
 
43
280
  return (
44
281
  <Box flexDirection="column" marginY={1} paddingX={1}>
@@ -48,9 +285,11 @@ export const SingleMessage: React.FC<SingleMessageProps> = ({
48
285
  {message.isStreaming && <Text color="yellow" bold> ▌</Text>}
49
286
  </Box>
50
287
  <Box flexDirection="column" marginLeft={2}>
51
- {content.split('\n').map((line: string, i: number) => (
52
- <Text key={i}>{line}</Text>
53
- ))}
288
+ <ContentRenderer
289
+ content={content}
290
+ diffLines={diffLines}
291
+ isToolTrace={false}
292
+ />
54
293
  </Box>
55
294
  </Box>
56
295
  );
@@ -1,3 +1,9 @@
1
+ export interface DictationSettings {
2
+ provider?: 'openai' | 'local' | 'macos';
3
+ language?: string; // e.g., 'en', 'es', 'fr'
4
+ whisperModel?: string; // For local whisper: 'tiny', 'base', 'small', 'medium', 'large'
5
+ }
6
+
1
7
  export interface ZTCConfig {
2
8
  apiKey?: string;
3
9
  apiKeys?: Record<string, string>;
@@ -9,4 +15,5 @@ export interface ZTCConfig {
9
15
  emulationId?: string;
10
16
  spinnerVerbs?: string[];
11
17
  toolPermissions?: Partial<Record<'file_read' | 'file_write' | 'shell_exec' | 'network', boolean>>;
18
+ dictation?: DictationSettings;
12
19
  }
@@ -67,8 +67,8 @@ export function buildStatusBarView({
67
67
 
68
68
  return box([
69
69
  box([
70
- text(isActive ? '⠋ ' : `${config.icon} `, { color: config.color }),
71
- text(label, { color: config.color }),
70
+ text(isActive ? '⠋' : config.icon, { color: config.color }),
71
+ text(` ${label}`, { color: config.color }),
72
72
  state.error ? text(` - ${state.error}`, { color: 'red' }) : text('', {}),
73
73
  toastLabel ? text(' • ', { color: 'gray', dimColor: true }) : text('', {}),
74
74
  toastLabel ? text(toastLabel, { color: 'yellow' }) : text('', {})