zerg-ztc 0.1.11 → 0.1.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/ztc-audio-darwin-arm64 +0 -0
- package/dist/utils/dictation_native.d.ts.map +1 -1
- package/dist/utils/dictation_native.js +43 -23
- package/dist/utils/dictation_native.js.map +1 -1
- package/package.json +5 -4
- package/packages/ztc-dictation/Cargo.toml +0 -43
- package/packages/ztc-dictation/README.md +0 -65
- package/packages/ztc-dictation/index.d.ts +0 -16
- package/packages/ztc-dictation/index.js +0 -74
- package/packages/ztc-dictation/package.json +0 -41
- package/packages/ztc-dictation/src/main.rs +0 -430
- package/src/App.tsx +0 -910
- package/src/agent/agent.ts +0 -534
- package/src/agent/backends/anthropic.ts +0 -86
- package/src/agent/backends/gemini.ts +0 -119
- package/src/agent/backends/inception.ts +0 -23
- package/src/agent/backends/index.ts +0 -17
- package/src/agent/backends/openai.ts +0 -23
- package/src/agent/backends/openai_compatible.ts +0 -143
- package/src/agent/backends/types.ts +0 -83
- package/src/agent/commands/clipboard.ts +0 -77
- package/src/agent/commands/config.ts +0 -204
- package/src/agent/commands/debug.ts +0 -23
- package/src/agent/commands/dictation.ts +0 -11
- package/src/agent/commands/emulation.ts +0 -80
- package/src/agent/commands/execution.ts +0 -9
- package/src/agent/commands/help.ts +0 -20
- package/src/agent/commands/history.ts +0 -13
- package/src/agent/commands/index.ts +0 -48
- package/src/agent/commands/input_mode.ts +0 -22
- package/src/agent/commands/keybindings.ts +0 -40
- package/src/agent/commands/model.ts +0 -11
- package/src/agent/commands/models.ts +0 -116
- package/src/agent/commands/permissions.ts +0 -64
- package/src/agent/commands/retry.ts +0 -9
- package/src/agent/commands/shell.ts +0 -68
- package/src/agent/commands/skills.ts +0 -54
- package/src/agent/commands/status.ts +0 -19
- package/src/agent/commands/types.ts +0 -88
- package/src/agent/commands/update.ts +0 -32
- package/src/agent/factory.ts +0 -60
- package/src/agent/index.ts +0 -20
- package/src/agent/runtime/capabilities.ts +0 -7
- package/src/agent/runtime/memory.ts +0 -23
- package/src/agent/runtime/policy.ts +0 -48
- package/src/agent/runtime/session.ts +0 -18
- package/src/agent/runtime/tracing.ts +0 -23
- package/src/agent/tools/file.ts +0 -178
- package/src/agent/tools/index.ts +0 -52
- package/src/agent/tools/screenshot.ts +0 -821
- package/src/agent/tools/search.ts +0 -138
- package/src/agent/tools/shell.ts +0 -69
- package/src/agent/tools/skills.ts +0 -28
- package/src/agent/tools/types.ts +0 -14
- package/src/agent/tools/zerg.ts +0 -50
- package/src/cli.tsx +0 -163
- package/src/components/ActivityLine.tsx +0 -23
- package/src/components/FullScreen.tsx +0 -79
- package/src/components/Header.tsx +0 -27
- package/src/components/InputArea.tsx +0 -1660
- package/src/components/MessageList.tsx +0 -71
- package/src/components/SingleMessage.tsx +0 -298
- package/src/components/StatusBar.tsx +0 -55
- package/src/components/index.tsx +0 -8
- package/src/config/types.ts +0 -19
- package/src/config.ts +0 -186
- package/src/debug/logger.ts +0 -14
- package/src/emulation/README.md +0 -24
- package/src/emulation/catalog.ts +0 -82
- package/src/emulation/trace_style.ts +0 -8
- package/src/emulation/types.ts +0 -7
- package/src/skills/index.ts +0 -36
- package/src/skills/loader.ts +0 -135
- package/src/skills/registry.ts +0 -6
- package/src/skills/types.ts +0 -10
- package/src/types.ts +0 -84
- package/src/ui/README.md +0 -44
- package/src/ui/core/factory.ts +0 -9
- package/src/ui/core/index.ts +0 -4
- package/src/ui/core/input.ts +0 -38
- package/src/ui/core/input_segments.ts +0 -410
- package/src/ui/core/input_state.ts +0 -17
- package/src/ui/core/layout_yoga.ts +0 -122
- package/src/ui/core/style.ts +0 -38
- package/src/ui/core/types.ts +0 -54
- package/src/ui/ink/index.tsx +0 -1
- package/src/ui/ink/render.tsx +0 -60
- package/src/ui/views/activity_line.ts +0 -33
- package/src/ui/views/app.ts +0 -111
- package/src/ui/views/header.ts +0 -44
- package/src/ui/views/input_area.ts +0 -255
- package/src/ui/views/message_list.ts +0 -443
- package/src/ui/views/status_bar.ts +0 -114
- package/src/ui/vue/index.ts +0 -53
- package/src/ui/web/frame_render.tsx +0 -148
- package/src/ui/web/index.tsx +0 -1
- package/src/ui/web/render.tsx +0 -41
- package/src/utils/clipboard.ts +0 -39
- package/src/utils/clipboard_image.ts +0 -40
- package/src/utils/dictation.ts +0 -467
- package/src/utils/dictation_native.ts +0 -258
- package/src/utils/diff.ts +0 -52
- package/src/utils/image_preview.ts +0 -36
- package/src/utils/models.ts +0 -98
- package/src/utils/path_complete.ts +0 -173
- package/src/utils/path_format.ts +0 -99
- package/src/utils/shell.ts +0 -72
- package/src/utils/spinner_frames.ts +0 -1
- package/src/utils/spinner_verbs.ts +0 -23
- package/src/utils/table.ts +0 -171
- package/src/utils/tool_summary.ts +0 -56
- package/src/utils/tool_trace.ts +0 -346
- package/src/utils/update.ts +0 -44
- package/src/utils/version.ts +0 -15
- package/src/web/index.html +0 -352
- package/src/web/mirror-favicon.svg +0 -4
- package/src/web/mirror.html +0 -641
- package/src/web/mirror_hook.ts +0 -25
- package/src/web/mirror_server.ts +0 -204
- package/tsconfig.json +0 -22
- package/vite.config.ts +0 -363
- /package/{packages/ztc-dictation/bin → bin}/.gitkeep +0 -0
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
import { spawn } from 'child_process';
|
|
2
|
-
import { resolve } from 'path';
|
|
3
|
-
import { Tool, ToolContext } from './types.js';
|
|
4
|
-
import { ToolCapability } from '../runtime/capabilities.js';
|
|
5
|
-
|
|
6
|
-
interface RunResult {
|
|
7
|
-
stdout: string;
|
|
8
|
-
stderr: string;
|
|
9
|
-
code: number;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
function runCommand(command: string, args: string[], cwd: string): Promise<RunResult> {
|
|
13
|
-
return new Promise((resolveResult, reject) => {
|
|
14
|
-
const child = spawn(command, args, { cwd });
|
|
15
|
-
let stdout = '';
|
|
16
|
-
let stderr = '';
|
|
17
|
-
child.stdout.on('data', chunk => { stdout += chunk.toString(); });
|
|
18
|
-
child.stderr.on('data', chunk => { stderr += chunk.toString(); });
|
|
19
|
-
child.on('error', reject);
|
|
20
|
-
child.on('close', (code) => {
|
|
21
|
-
resolveResult({ stdout, stderr, code: code ?? 1 });
|
|
22
|
-
});
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// --- Search Tool ---
|
|
27
|
-
|
|
28
|
-
export const searchTool: Tool = {
|
|
29
|
-
capabilities: [ToolCapability.FILE_READ],
|
|
30
|
-
definition: {
|
|
31
|
-
name: 'search',
|
|
32
|
-
description: 'Search for a pattern in files (ripgrep preferred)',
|
|
33
|
-
parameters: {
|
|
34
|
-
type: 'object',
|
|
35
|
-
properties: {
|
|
36
|
-
pattern: {
|
|
37
|
-
type: 'string',
|
|
38
|
-
description: 'Regex pattern to search for'
|
|
39
|
-
},
|
|
40
|
-
path: {
|
|
41
|
-
type: 'string',
|
|
42
|
-
description: 'Path to search within (default: .)'
|
|
43
|
-
},
|
|
44
|
-
glob: {
|
|
45
|
-
type: 'string',
|
|
46
|
-
description: 'Optional glob filter (e.g., "*.ts")'
|
|
47
|
-
},
|
|
48
|
-
output_mode: {
|
|
49
|
-
type: 'string',
|
|
50
|
-
description: 'Output mode: content or files',
|
|
51
|
-
enum: ['content', 'files']
|
|
52
|
-
},
|
|
53
|
-
max_results: {
|
|
54
|
-
type: 'string',
|
|
55
|
-
description: 'Maximum number of results (default: 20)'
|
|
56
|
-
}
|
|
57
|
-
},
|
|
58
|
-
required: ['pattern']
|
|
59
|
-
}
|
|
60
|
-
},
|
|
61
|
-
execute: async (args, context) => {
|
|
62
|
-
const baseCwd = context?.cwd || process.cwd();
|
|
63
|
-
const pattern = String(args.pattern || '');
|
|
64
|
-
const path = resolve(baseCwd, String(args.path || '.'));
|
|
65
|
-
const glob = args.glob ? String(args.glob) : undefined;
|
|
66
|
-
const outputMode = args.output_mode === 'files' ? 'files' : 'content';
|
|
67
|
-
const maxResults = Math.max(1, Math.min(200, parseInt(String(args.max_results || '20'), 10)));
|
|
68
|
-
|
|
69
|
-
if (!pattern) {
|
|
70
|
-
throw new Error('Search pattern is required');
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const rgArgs: string[] = [];
|
|
74
|
-
if (outputMode === 'files') {
|
|
75
|
-
rgArgs.push('-l', '--max-count', String(maxResults));
|
|
76
|
-
} else {
|
|
77
|
-
rgArgs.push('--line-number', '--column', '--with-filename', '--no-heading', '--max-count', String(maxResults));
|
|
78
|
-
}
|
|
79
|
-
if (glob) {
|
|
80
|
-
rgArgs.push('-g', glob);
|
|
81
|
-
}
|
|
82
|
-
rgArgs.push(pattern, path);
|
|
83
|
-
|
|
84
|
-
let result: RunResult | null = null;
|
|
85
|
-
try {
|
|
86
|
-
result = await runCommand('rg', rgArgs, baseCwd);
|
|
87
|
-
} catch {
|
|
88
|
-
result = null;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if (!result || (result.code !== 0 && result.code !== 1)) {
|
|
92
|
-
const grepArgs = ['-R', '-n', pattern, path];
|
|
93
|
-
const fallback = await runCommand('grep', grepArgs, baseCwd);
|
|
94
|
-
if (fallback.code !== 0 && fallback.code !== 1) {
|
|
95
|
-
throw new Error(fallback.stderr || 'Search failed');
|
|
96
|
-
}
|
|
97
|
-
result = fallback;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
const stdout = result.stdout.trim();
|
|
101
|
-
if (!stdout) {
|
|
102
|
-
return JSON.stringify({ pattern, path, matches: [], count: 0, truncated: false });
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
if (outputMode === 'files') {
|
|
106
|
-
const files = stdout.split('\n').slice(0, maxResults);
|
|
107
|
-
return JSON.stringify({
|
|
108
|
-
pattern,
|
|
109
|
-
path,
|
|
110
|
-
files,
|
|
111
|
-
count: files.length,
|
|
112
|
-
truncated: files.length >= maxResults
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const lines = stdout.split('\n');
|
|
117
|
-
const matches = [];
|
|
118
|
-
for (const line of lines) {
|
|
119
|
-
const match = line.match(/^(.+?):(\d+):(\d+):(.*)$/);
|
|
120
|
-
if (!match) continue;
|
|
121
|
-
matches.push({
|
|
122
|
-
path: match[1],
|
|
123
|
-
line: Number(match[2]),
|
|
124
|
-
column: Number(match[3]),
|
|
125
|
-
text: match[4]
|
|
126
|
-
});
|
|
127
|
-
if (matches.length >= maxResults) break;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
return JSON.stringify({
|
|
131
|
-
pattern,
|
|
132
|
-
path,
|
|
133
|
-
matches,
|
|
134
|
-
count: matches.length,
|
|
135
|
-
truncated: matches.length >= maxResults
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
};
|
package/src/agent/tools/shell.ts
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import { exec } from 'child_process';
|
|
2
|
-
import { promisify } from 'util';
|
|
3
|
-
import { resolve } from 'path';
|
|
4
|
-
import { Tool, ToolContext } from './types.js';
|
|
5
|
-
import { ToolCapability } from '../runtime/capabilities.js';
|
|
6
|
-
|
|
7
|
-
const execAsync = promisify(exec);
|
|
8
|
-
|
|
9
|
-
// --- Shell Tool ---
|
|
10
|
-
|
|
11
|
-
export const runCommandTool: Tool = {
|
|
12
|
-
capabilities: [ToolCapability.SHELL_EXEC],
|
|
13
|
-
definition: {
|
|
14
|
-
name: 'run_command',
|
|
15
|
-
description: 'Execute a shell command and return output',
|
|
16
|
-
parameters: {
|
|
17
|
-
type: 'object',
|
|
18
|
-
properties: {
|
|
19
|
-
command: {
|
|
20
|
-
type: 'string',
|
|
21
|
-
description: 'Shell command to execute'
|
|
22
|
-
},
|
|
23
|
-
cwd: {
|
|
24
|
-
type: 'string',
|
|
25
|
-
description: 'Working directory for the command'
|
|
26
|
-
},
|
|
27
|
-
timeout: {
|
|
28
|
-
type: 'string',
|
|
29
|
-
description: 'Timeout in milliseconds (default: 30000)'
|
|
30
|
-
}
|
|
31
|
-
},
|
|
32
|
-
required: ['command']
|
|
33
|
-
}
|
|
34
|
-
},
|
|
35
|
-
execute: async (args, context) => {
|
|
36
|
-
const command = String(args.command);
|
|
37
|
-
const baseCwd = context?.cwd || process.cwd();
|
|
38
|
-
const cwd = args.cwd ? resolve(baseCwd, String(args.cwd)) : baseCwd;
|
|
39
|
-
const timeout = parseInt(String(args.timeout || '30000'), 10);
|
|
40
|
-
|
|
41
|
-
// Basic safety checks
|
|
42
|
-
const dangerous = ['rm -rf /', 'mkfs', ':(){:|:&};:'];
|
|
43
|
-
if (dangerous.some(d => command.includes(d))) {
|
|
44
|
-
throw new Error('Command rejected for safety reasons');
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
try {
|
|
48
|
-
const { stdout, stderr } = await execAsync(command, {
|
|
49
|
-
cwd,
|
|
50
|
-
timeout,
|
|
51
|
-
maxBuffer: 1024 * 1024 // 1MB
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
return JSON.stringify({
|
|
55
|
-
command,
|
|
56
|
-
cwd,
|
|
57
|
-
stdout: stdout.slice(0, 10000),
|
|
58
|
-
stderr: stderr.slice(0, 10000),
|
|
59
|
-
truncated: stdout.length > 10000 || stderr.length > 10000
|
|
60
|
-
});
|
|
61
|
-
} catch (err) {
|
|
62
|
-
const e = err as Error & { stdout?: string; stderr?: string; code?: number };
|
|
63
|
-
// Include both stdout and stderr in error - many tools output errors to stdout
|
|
64
|
-
const output = [e.stdout, e.stderr].filter(Boolean).join('\n').trim();
|
|
65
|
-
const outputSnippet = output.slice(0, 2000) || '(no output)';
|
|
66
|
-
throw new Error(`Command failed (exit ${e.code || '?'}):\n${outputSnippet}`);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
};
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { Tool } from './types.js';
|
|
2
|
-
import { ToolCapability } from '../runtime/capabilities.js';
|
|
3
|
-
import { loadSkills } from '../../skills/loader.js';
|
|
4
|
-
|
|
5
|
-
export const listSkillsTool: Tool = {
|
|
6
|
-
capabilities: [ToolCapability.FILE_READ],
|
|
7
|
-
definition: {
|
|
8
|
-
name: 'list_skills',
|
|
9
|
-
description: 'List available skills',
|
|
10
|
-
parameters: {
|
|
11
|
-
type: 'object',
|
|
12
|
-
properties: {},
|
|
13
|
-
required: []
|
|
14
|
-
}
|
|
15
|
-
},
|
|
16
|
-
execute: async () => {
|
|
17
|
-
const skills = await loadSkills();
|
|
18
|
-
return JSON.stringify({
|
|
19
|
-
count: skills.length,
|
|
20
|
-
skills: skills.map(skill => ({
|
|
21
|
-
id: skill.id,
|
|
22
|
-
name: skill.name,
|
|
23
|
-
description: skill.description,
|
|
24
|
-
sourceRoot: skill.sourceRoot
|
|
25
|
-
}))
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
};
|
package/src/agent/tools/types.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { ToolDefinition } from '../../types.js';
|
|
2
|
-
import { ToolCapability } from '../runtime/capabilities.js';
|
|
3
|
-
|
|
4
|
-
// --- Tool Interface ---
|
|
5
|
-
|
|
6
|
-
export interface ToolContext {
|
|
7
|
-
cwd: string; // Working directory for path resolution
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export interface Tool {
|
|
11
|
-
definition: ToolDefinition;
|
|
12
|
-
capabilities?: ToolCapability[];
|
|
13
|
-
execute: (args: Record<string, unknown>, context?: ToolContext) => Promise<string>;
|
|
14
|
-
}
|
package/src/agent/tools/zerg.ts
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { Tool } from './types.js';
|
|
2
|
-
import { ToolCapability } from '../runtime/capabilities.js';
|
|
3
|
-
|
|
4
|
-
// --- Zerg Integration Tool ---
|
|
5
|
-
|
|
6
|
-
export const zergQueryTool: Tool = {
|
|
7
|
-
capabilities: [ToolCapability.NETWORK],
|
|
8
|
-
definition: {
|
|
9
|
-
name: 'zerg_query',
|
|
10
|
-
description: 'Send a query to the Zerg continual AI system',
|
|
11
|
-
parameters: {
|
|
12
|
-
type: 'object',
|
|
13
|
-
properties: {
|
|
14
|
-
query: {
|
|
15
|
-
type: 'string',
|
|
16
|
-
description: 'Query or instruction for Zerg'
|
|
17
|
-
},
|
|
18
|
-
context: {
|
|
19
|
-
type: 'string',
|
|
20
|
-
description: 'Additional context for the query'
|
|
21
|
-
},
|
|
22
|
-
project: {
|
|
23
|
-
type: 'string',
|
|
24
|
-
description: 'Project identifier within Zerg'
|
|
25
|
-
},
|
|
26
|
-
wait: {
|
|
27
|
-
type: 'string',
|
|
28
|
-
description: 'If "true", wait for completion; otherwise return task ID'
|
|
29
|
-
}
|
|
30
|
-
},
|
|
31
|
-
required: ['query']
|
|
32
|
-
}
|
|
33
|
-
},
|
|
34
|
-
execute: async (args) => {
|
|
35
|
-
// Placeholder - implement actual Zerg API integration
|
|
36
|
-
const query = String(args.query);
|
|
37
|
-
const context = args.context ? String(args.context) : undefined;
|
|
38
|
-
const project = args.project ? String(args.project) : 'default';
|
|
39
|
-
|
|
40
|
-
// TODO: Replace with actual Zerg API call
|
|
41
|
-
return JSON.stringify({
|
|
42
|
-
status: 'placeholder',
|
|
43
|
-
message: 'Zerg integration not yet implemented',
|
|
44
|
-
query,
|
|
45
|
-
context,
|
|
46
|
-
project,
|
|
47
|
-
taskId: `zerg_${Date.now()}`
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
};
|
package/src/cli.tsx
DELETED
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import React from 'react';
|
|
3
|
-
import { render } from 'ink';
|
|
4
|
-
import { resolve } from 'path';
|
|
5
|
-
import { statSync } from 'fs';
|
|
6
|
-
import { App } from './App.js';
|
|
7
|
-
import { configStore } from './config.js';
|
|
8
|
-
import { getVersion } from './utils/version.js';
|
|
9
|
-
|
|
10
|
-
// --- CLI Entry Point ---
|
|
11
|
-
|
|
12
|
-
// Parse command line args
|
|
13
|
-
const args = process.argv.slice(2);
|
|
14
|
-
|
|
15
|
-
if (args.includes('--help') || args.includes('-h')) {
|
|
16
|
-
const version = getVersion();
|
|
17
|
-
console.log(`
|
|
18
|
-
ZTC - Zerg Terminal Client v${version}
|
|
19
|
-
|
|
20
|
-
Usage: ztc [options]
|
|
21
|
-
|
|
22
|
-
Options:
|
|
23
|
-
-h, --help Show this help message
|
|
24
|
-
-v, --version Show version number
|
|
25
|
-
--cwd <path> Start in a specific working directory
|
|
26
|
-
|
|
27
|
-
Environment Variables:
|
|
28
|
-
ANTHROPIC_API_KEY API key for Claude (optional, can be set in-app)
|
|
29
|
-
|
|
30
|
-
In-App Commands:
|
|
31
|
-
/help Show available commands
|
|
32
|
-
/config key <key> Set API key
|
|
33
|
-
/config show Show current configuration
|
|
34
|
-
/clear Clear message history
|
|
35
|
-
/status Show current status
|
|
36
|
-
/exit Exit ZTC
|
|
37
|
-
|
|
38
|
-
Keyboard Shortcuts:
|
|
39
|
-
Ctrl+C Exit
|
|
40
|
-
Ctrl+L Clear screen
|
|
41
|
-
Up/Down Navigate command history
|
|
42
|
-
Ctrl+U Clear input line
|
|
43
|
-
Ctrl+W Delete word
|
|
44
|
-
Ctrl+A Move to start of line
|
|
45
|
-
Ctrl+E Move to end of line
|
|
46
|
-
`);
|
|
47
|
-
process.exit(0);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
if (args.includes('--version') || args.includes('-v')) {
|
|
51
|
-
console.log(`ztc v${getVersion()}`);
|
|
52
|
-
process.exit(0);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const cwdIndex = args.indexOf('--cwd');
|
|
56
|
-
if (cwdIndex >= 0) {
|
|
57
|
-
const target = args[cwdIndex + 1];
|
|
58
|
-
if (!target) {
|
|
59
|
-
console.error('Error: --cwd requires a path');
|
|
60
|
-
process.exit(1);
|
|
61
|
-
}
|
|
62
|
-
const resolved = resolve(target);
|
|
63
|
-
try {
|
|
64
|
-
const info = statSync(resolved);
|
|
65
|
-
if (!info.isDirectory()) {
|
|
66
|
-
throw new Error('Not a directory');
|
|
67
|
-
}
|
|
68
|
-
process.chdir(resolved);
|
|
69
|
-
} catch {
|
|
70
|
-
console.error(`Error: invalid --cwd path (${resolved})`);
|
|
71
|
-
process.exit(1);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
async function main(): Promise<void> {
|
|
76
|
-
await configStore.load(true);
|
|
77
|
-
|
|
78
|
-
const isTty = Boolean(process.stdout.isTTY);
|
|
79
|
-
const useAltScreen = isTty
|
|
80
|
-
&& process.env.ZTC_ALT_SCREEN === '1'
|
|
81
|
-
&& process.env.ZTC_NO_ALT_SCREEN !== '1'
|
|
82
|
-
&& process.env.ZTC_SCROLLBACK !== '1';
|
|
83
|
-
|
|
84
|
-
if (useAltScreen) {
|
|
85
|
-
process.stdout.write('\x1b[?1049h');
|
|
86
|
-
process.stdout.write('\x1b[?25l');
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (isTty) {
|
|
90
|
-
// Clear screen and move cursor home for a clean start
|
|
91
|
-
process.stdout.write('\x1b[2J');
|
|
92
|
-
process.stdout.write('\x1b[H');
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// In scrollback mode, print a static header once at startup
|
|
96
|
-
const scrollback = !useAltScreen;
|
|
97
|
-
if (scrollback && isTty) {
|
|
98
|
-
const version = getVersion();
|
|
99
|
-
const dateLabel = new Date().toLocaleDateString('en-US', {
|
|
100
|
-
month: 'short',
|
|
101
|
-
day: '2-digit',
|
|
102
|
-
year: 'numeric'
|
|
103
|
-
});
|
|
104
|
-
const cols = process.stdout.columns || 80;
|
|
105
|
-
const title = 'Zerg Terminal Client';
|
|
106
|
-
const right = `${dateLabel} • v${version} • Ctrl+C exit • /help`;
|
|
107
|
-
const padding = Math.max(0, cols - title.length - right.length - 4);
|
|
108
|
-
const borderLine = '─'.repeat(cols - 2);
|
|
109
|
-
|
|
110
|
-
console.log(`┌${borderLine}┐`);
|
|
111
|
-
console.log(`│ ${title}${' '.repeat(padding)}${right} │`);
|
|
112
|
-
console.log(`└${borderLine}┘`);
|
|
113
|
-
console.log(''); // Extra line after header
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// Enable bracketed paste mode so we can detect paste boundaries
|
|
117
|
-
process.stdout.write('\x1b[?2004h');
|
|
118
|
-
|
|
119
|
-
// Enable Kitty keyboard protocol (progressive enhancement)
|
|
120
|
-
// This allows detection of Cmd+V and other modifier combinations
|
|
121
|
-
// Flags: 1 = disambiguate escape codes, 2 = report event types, 4 = report alternate keys, 8 = report all keys
|
|
122
|
-
// Using flags=1 for basic disambiguation which reports Cmd+V as CSI sequence
|
|
123
|
-
process.stdout.write('\x1b[>1u');
|
|
124
|
-
|
|
125
|
-
if (useAltScreen) {
|
|
126
|
-
// Wrap stdout.write to use synchronized output (reduces flicker)
|
|
127
|
-
// DECSM/DECRM 2026 tells terminal to batch updates
|
|
128
|
-
const originalWrite = process.stdout.write.bind(process.stdout);
|
|
129
|
-
let syncPending = false;
|
|
130
|
-
process.stdout.write = function(chunk: any, encoding?: any, callback?: any): boolean {
|
|
131
|
-
if (!syncPending) {
|
|
132
|
-
syncPending = true;
|
|
133
|
-
originalWrite('\x1b[?2026h'); // Begin synchronized update
|
|
134
|
-
setImmediate(() => {
|
|
135
|
-
originalWrite('\x1b[?2026l'); // End synchronized update
|
|
136
|
-
syncPending = false;
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
return originalWrite(chunk, encoding, callback);
|
|
140
|
-
} as typeof process.stdout.write;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
// Render the app
|
|
144
|
-
const { waitUntilExit } = render(<App />);
|
|
145
|
-
|
|
146
|
-
// Handle clean exit
|
|
147
|
-
waitUntilExit().then(() => {
|
|
148
|
-
// Disable Kitty keyboard protocol
|
|
149
|
-
process.stdout.write('\x1b[<u');
|
|
150
|
-
// Disable bracketed paste mode
|
|
151
|
-
process.stdout.write('\x1b[?2004l');
|
|
152
|
-
if (useAltScreen) {
|
|
153
|
-
process.stdout.write('\x1b[?25h');
|
|
154
|
-
process.stdout.write('\x1b[?1049l');
|
|
155
|
-
}
|
|
156
|
-
console.log('Goodbye from ZTC! 👋');
|
|
157
|
-
process.exit(0);
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
void main();
|
|
162
|
-
|
|
163
|
-
// getVersion moved to utils/version.ts
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { AgentState } from '../types.js';
|
|
3
|
-
import { InkNode } from '../ui/ink/index.js';
|
|
4
|
-
import { buildActivityLineView } from '../ui/views/activity_line.js';
|
|
5
|
-
|
|
6
|
-
interface ActivityLineProps {
|
|
7
|
-
state: AgentState;
|
|
8
|
-
spinnerLabel?: string | null;
|
|
9
|
-
spinnerFrame?: string | null;
|
|
10
|
-
inputMode?: 'queue' | 'interrupt';
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export const ActivityLine: React.FC<ActivityLineProps> = ({
|
|
14
|
-
state,
|
|
15
|
-
spinnerLabel,
|
|
16
|
-
spinnerFrame,
|
|
17
|
-
inputMode
|
|
18
|
-
}) => {
|
|
19
|
-
const node = buildActivityLineView({ state, spinnerLabel, spinnerFrame, inputMode });
|
|
20
|
-
return <InkNode node={node} />;
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
export default ActivityLine;
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import React, { PropsWithChildren, useState, useEffect } from 'react';
|
|
2
|
-
import { Box } from 'ink';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* FullScreen component that uses the alternate screen buffer.
|
|
6
|
-
*
|
|
7
|
-
* This prevents flickering by:
|
|
8
|
-
* 1. Switching to the alternate screen buffer (like vim, htop, less do)
|
|
9
|
-
* 2. Tracking terminal resize events
|
|
10
|
-
* 3. Restoring the original terminal state on exit
|
|
11
|
-
*
|
|
12
|
-
* ANSI escape codes:
|
|
13
|
-
* - \x1b[?1049h - Enter alternate screen buffer
|
|
14
|
-
* - \x1b[?1049l - Exit alternate screen buffer
|
|
15
|
-
* - \x1b[?25l - Hide cursor
|
|
16
|
-
* - \x1b[?25h - Show cursor
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
interface FullScreenProps extends PropsWithChildren {
|
|
20
|
-
debug?: boolean;
|
|
21
|
-
scrollback?: boolean;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function getTerminalSize() {
|
|
25
|
-
return {
|
|
26
|
-
columns: process.stdout.columns || 80,
|
|
27
|
-
rows: process.stdout.rows || 24,
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export const FullScreen: React.FC<FullScreenProps> = ({ children, debug = false, scrollback = false }) => {
|
|
32
|
-
const { rows, columns } = useScreenSize();
|
|
33
|
-
|
|
34
|
-
return (
|
|
35
|
-
<Box
|
|
36
|
-
flexDirection="column"
|
|
37
|
-
width={columns}
|
|
38
|
-
height={scrollback ? undefined : rows}
|
|
39
|
-
overflow={scrollback ? undefined : 'hidden'}
|
|
40
|
-
borderStyle={debug ? 'single' : undefined}
|
|
41
|
-
borderColor={debug ? 'red' : undefined}
|
|
42
|
-
>
|
|
43
|
-
{children}
|
|
44
|
-
</Box>
|
|
45
|
-
);
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Hook to get current screen size with resize tracking
|
|
50
|
-
*/
|
|
51
|
-
export function useScreenSize() {
|
|
52
|
-
const [size, setSize] = useState(getTerminalSize);
|
|
53
|
-
|
|
54
|
-
useEffect(() => {
|
|
55
|
-
const updateSize = () => {
|
|
56
|
-
const current = getTerminalSize();
|
|
57
|
-
setSize(prev => {
|
|
58
|
-
if (prev.rows !== current.rows || prev.columns !== current.columns) {
|
|
59
|
-
return current;
|
|
60
|
-
}
|
|
61
|
-
return prev;
|
|
62
|
-
});
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
process.stdout.on('resize', updateSize);
|
|
66
|
-
|
|
67
|
-
// Also check on an interval as a fallback for some terminals
|
|
68
|
-
const interval = setInterval(updateSize, 1000);
|
|
69
|
-
|
|
70
|
-
return () => {
|
|
71
|
-
process.stdout.off('resize', updateSize);
|
|
72
|
-
clearInterval(interval);
|
|
73
|
-
};
|
|
74
|
-
}, []);
|
|
75
|
-
|
|
76
|
-
return size;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
export default FullScreen;
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { InkNode } from '../ui/ink/index.js';
|
|
3
|
-
import { buildHeaderView } from '../ui/views/header.js';
|
|
4
|
-
|
|
5
|
-
interface HeaderProps {
|
|
6
|
-
title?: string;
|
|
7
|
-
version?: string;
|
|
8
|
-
showHelp?: boolean;
|
|
9
|
-
debug?: boolean;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export const Header: React.FC<HeaderProps> = ({
|
|
13
|
-
title = 'Zerg Terminal Client',
|
|
14
|
-
version = '0.1.0',
|
|
15
|
-
showHelp = true,
|
|
16
|
-
debug = false
|
|
17
|
-
}) => {
|
|
18
|
-
const dateLabel = new Date().toLocaleDateString('en-US', {
|
|
19
|
-
month: 'short',
|
|
20
|
-
day: '2-digit',
|
|
21
|
-
year: 'numeric'
|
|
22
|
-
});
|
|
23
|
-
const node = buildHeaderView({ title, version, dateLabel, showHelp, debug });
|
|
24
|
-
return <InkNode node={node} />;
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
export default Header;
|