zerg-ztc 0.1.0 → 0.1.2
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/dist/App.d.ts.map +1 -1
- package/dist/App.js +16 -0
- package/dist/App.js.map +1 -1
- package/dist/cli.js +13 -8
- package/dist/cli.js.map +1 -1
- package/dist/components/InputArea.d.ts.map +1 -1
- package/dist/components/InputArea.js +9 -1
- package/dist/components/InputArea.js.map +1 -1
- package/dist/ui/views/input_area.js +1 -1
- package/dist/ui/web/frame_render.d.ts +23 -0
- package/dist/ui/web/frame_render.d.ts.map +1 -0
- package/dist/ui/web/frame_render.js +73 -0
- package/dist/ui/web/frame_render.js.map +1 -0
- package/dist/ui/web/index.d.ts +2 -0
- package/dist/ui/web/index.d.ts.map +1 -0
- package/dist/ui/web/index.js +2 -0
- package/dist/ui/web/index.js.map +1 -0
- package/dist/ui/web/render.d.ts +6 -0
- package/dist/ui/web/render.d.ts.map +1 -0
- package/dist/ui/web/render.js +30 -0
- package/dist/ui/web/render.js.map +1 -0
- package/dist/web/mirror_hook.d.ts +4 -0
- package/dist/web/mirror_hook.d.ts.map +1 -0
- package/dist/web/mirror_hook.js +22 -0
- package/dist/web/mirror_hook.js.map +1 -0
- package/dist/web/mirror_server.d.ts +16 -0
- package/dist/web/mirror_server.d.ts.map +1 -0
- package/dist/web/mirror_server.js +177 -0
- package/dist/web/mirror_server.js.map +1 -0
- package/package.json +1 -1
- package/src/App.tsx +18 -0
- package/src/cli.tsx +15 -8
- package/src/components/InputArea.tsx +9 -1
- package/src/ui/views/input_area.ts +1 -1
- package/src/ui/web/frame_render.tsx +148 -0
- package/src/ui/web/index.tsx +1 -0
- package/src/ui/web/render.tsx +41 -0
- package/src/web/index.html +352 -0
- package/src/web/mirror-favicon.svg +4 -0
- package/src/web/mirror.html +641 -0
- package/src/web/mirror_hook.ts +25 -0
- package/src/web/mirror_server.ts +204 -0
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>ZTC - Zerg Terminal Client</title>
|
|
7
|
+
<style>
|
|
8
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
9
|
+
|
|
10
|
+
:root {
|
|
11
|
+
--bg: #0d1117;
|
|
12
|
+
--fg: #e6edf3;
|
|
13
|
+
--gray: #7d8590;
|
|
14
|
+
--blue: #58a6ff;
|
|
15
|
+
--magenta: #d2a8ff;
|
|
16
|
+
--green: #3fb950;
|
|
17
|
+
--yellow: #d29922;
|
|
18
|
+
--red: #f85149;
|
|
19
|
+
--cyan: #76e3ea;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
body {
|
|
23
|
+
font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace;
|
|
24
|
+
font-size: 14px;
|
|
25
|
+
background: var(--bg);
|
|
26
|
+
color: var(--fg);
|
|
27
|
+
height: 100vh;
|
|
28
|
+
display: flex;
|
|
29
|
+
flex-direction: column;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.header {
|
|
33
|
+
padding: 8px 16px;
|
|
34
|
+
display: flex;
|
|
35
|
+
justify-content: space-between;
|
|
36
|
+
border-bottom: 1px solid #30363d;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.header-title {
|
|
40
|
+
color: var(--magenta);
|
|
41
|
+
font-weight: bold;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.header-help {
|
|
45
|
+
color: var(--gray);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.messages {
|
|
49
|
+
flex: 1;
|
|
50
|
+
overflow-y: auto;
|
|
51
|
+
padding: 16px;
|
|
52
|
+
display: flex;
|
|
53
|
+
flex-direction: column;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.message {
|
|
57
|
+
margin-bottom: 16px;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.message-header {
|
|
61
|
+
display: flex;
|
|
62
|
+
align-items: center;
|
|
63
|
+
gap: 8px;
|
|
64
|
+
margin-bottom: 4px;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.message-role {
|
|
68
|
+
font-weight: bold;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.message-role.user { color: var(--blue); }
|
|
72
|
+
.message-role.assistant { color: var(--magenta); }
|
|
73
|
+
.message-role.system { color: var(--gray); }
|
|
74
|
+
.message-role.tool { color: var(--yellow); }
|
|
75
|
+
|
|
76
|
+
.message-time {
|
|
77
|
+
color: var(--gray);
|
|
78
|
+
font-size: 12px;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.message-content {
|
|
82
|
+
margin-left: 24px;
|
|
83
|
+
white-space: pre-wrap;
|
|
84
|
+
line-height: 1.5;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.tool-call {
|
|
88
|
+
margin-left: 24px;
|
|
89
|
+
margin-top: 8px;
|
|
90
|
+
padding: 8px;
|
|
91
|
+
background: #161b22;
|
|
92
|
+
border-radius: 4px;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.tool-name {
|
|
96
|
+
color: var(--cyan);
|
|
97
|
+
font-weight: bold;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.tool-status {
|
|
101
|
+
margin-left: 8px;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.tool-status.running { color: var(--yellow); }
|
|
105
|
+
.tool-status.complete { color: var(--green); }
|
|
106
|
+
.tool-status.error { color: var(--red); }
|
|
107
|
+
|
|
108
|
+
.input-area {
|
|
109
|
+
padding: 16px;
|
|
110
|
+
border-top: 1px solid #30363d;
|
|
111
|
+
display: flex;
|
|
112
|
+
align-items: center;
|
|
113
|
+
gap: 8px;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.input-prompt {
|
|
117
|
+
color: var(--blue);
|
|
118
|
+
font-weight: bold;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.input-field {
|
|
122
|
+
flex: 1;
|
|
123
|
+
background: transparent;
|
|
124
|
+
border: none;
|
|
125
|
+
color: var(--fg);
|
|
126
|
+
font-family: inherit;
|
|
127
|
+
font-size: inherit;
|
|
128
|
+
outline: none;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.input-field::placeholder {
|
|
132
|
+
color: var(--gray);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.input-field:disabled {
|
|
136
|
+
opacity: 0.5;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.status-bar {
|
|
140
|
+
padding: 8px 16px;
|
|
141
|
+
display: flex;
|
|
142
|
+
justify-content: space-between;
|
|
143
|
+
background: #161b22;
|
|
144
|
+
font-size: 12px;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.status-left {
|
|
148
|
+
display: flex;
|
|
149
|
+
align-items: center;
|
|
150
|
+
gap: 8px;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.status-indicator {
|
|
154
|
+
width: 8px;
|
|
155
|
+
height: 8px;
|
|
156
|
+
border-radius: 50%;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.status-indicator.idle { background: var(--green); }
|
|
160
|
+
.status-indicator.thinking { background: var(--yellow); animation: pulse 1s infinite; }
|
|
161
|
+
.status-indicator.error { background: var(--red); }
|
|
162
|
+
|
|
163
|
+
@keyframes pulse {
|
|
164
|
+
0%, 100% { opacity: 1; }
|
|
165
|
+
50% { opacity: 0.5; }
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.status-right {
|
|
169
|
+
color: var(--gray);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/* Debug mode */
|
|
173
|
+
.debug .header,
|
|
174
|
+
.debug .messages,
|
|
175
|
+
.debug .input-area,
|
|
176
|
+
.debug .status-bar {
|
|
177
|
+
border: 1px dashed var(--gray);
|
|
178
|
+
}
|
|
179
|
+
</style>
|
|
180
|
+
</head>
|
|
181
|
+
<body>
|
|
182
|
+
<div id="root"></div>
|
|
183
|
+
|
|
184
|
+
<script type="module">
|
|
185
|
+
// Simple state management
|
|
186
|
+
const state = {
|
|
187
|
+
messages: [],
|
|
188
|
+
agentState: { status: 'idle' },
|
|
189
|
+
debug: false
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
const generateId = () => Math.random().toString(36).slice(2, 11);
|
|
193
|
+
|
|
194
|
+
function formatTime(date) {
|
|
195
|
+
return date.toLocaleTimeString('en-US', {
|
|
196
|
+
hour: '2-digit',
|
|
197
|
+
minute: '2-digit',
|
|
198
|
+
hour12: false
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const roleIcons = {
|
|
203
|
+
user: '❯',
|
|
204
|
+
assistant: '◆',
|
|
205
|
+
system: '●',
|
|
206
|
+
tool: '⚙'
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
function render() {
|
|
210
|
+
const root = document.getElementById('root');
|
|
211
|
+
root.innerHTML = `
|
|
212
|
+
<div class="header">
|
|
213
|
+
<div>
|
|
214
|
+
<span class="header-title">◆ Zerg Terminal Client ◆</span>
|
|
215
|
+
<span style="color: var(--gray)"> v0.1.0</span>
|
|
216
|
+
</div>
|
|
217
|
+
<div class="header-help">Ctrl+Enter send • /help</div>
|
|
218
|
+
</div>
|
|
219
|
+
|
|
220
|
+
<div class="messages" id="messages">
|
|
221
|
+
${state.messages.map(msg => `
|
|
222
|
+
<div class="message">
|
|
223
|
+
<div class="message-header">
|
|
224
|
+
<span class="message-role ${msg.role}">${roleIcons[msg.role]} ${msg.role === 'user' ? 'You' : msg.role === 'assistant' ? 'Zerg' : msg.role.charAt(0).toUpperCase() + msg.role.slice(1)}</span>
|
|
225
|
+
<span class="message-time">• ${formatTime(msg.timestamp)}</span>
|
|
226
|
+
</div>
|
|
227
|
+
<div class="message-content">${escapeHtml(msg.content)}</div>
|
|
228
|
+
${msg.toolCalls ? msg.toolCalls.map(tool => `
|
|
229
|
+
<div class="tool-call">
|
|
230
|
+
<span class="tool-name">${tool.name}</span>
|
|
231
|
+
<span class="tool-status ${tool.status}">${tool.status}</span>
|
|
232
|
+
${tool.result ? `<div style="margin-top: 4px; color: var(--gray)">→ ${escapeHtml(tool.result.slice(0, 100))}</div>` : ''}
|
|
233
|
+
</div>
|
|
234
|
+
`).join('') : ''}
|
|
235
|
+
</div>
|
|
236
|
+
`).join('')}
|
|
237
|
+
</div>
|
|
238
|
+
|
|
239
|
+
<div class="input-area">
|
|
240
|
+
<span class="input-prompt">❯</span>
|
|
241
|
+
<input
|
|
242
|
+
type="text"
|
|
243
|
+
class="input-field"
|
|
244
|
+
id="input"
|
|
245
|
+
placeholder="${state.agentState.status !== 'idle' ? 'Processing...' : 'Type a message or /help for commands...'}"
|
|
246
|
+
${state.agentState.status !== 'idle' ? 'disabled' : ''}
|
|
247
|
+
/>
|
|
248
|
+
</div>
|
|
249
|
+
|
|
250
|
+
<div class="status-bar">
|
|
251
|
+
<div class="status-left">
|
|
252
|
+
<div class="status-indicator ${state.agentState.status}"></div>
|
|
253
|
+
<span>${state.agentState.status === 'idle' ? 'Ready' : state.agentState.status}</span>
|
|
254
|
+
</div>
|
|
255
|
+
<div class="status-right">ZTC v0.1.0 (Web)</div>
|
|
256
|
+
</div>
|
|
257
|
+
`;
|
|
258
|
+
|
|
259
|
+
// Scroll to bottom
|
|
260
|
+
const messages = document.getElementById('messages');
|
|
261
|
+
messages.scrollTop = messages.scrollHeight;
|
|
262
|
+
|
|
263
|
+
// Setup input handler
|
|
264
|
+
const input = document.getElementById('input');
|
|
265
|
+
input.focus();
|
|
266
|
+
input.addEventListener('keydown', handleInput);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function escapeHtml(text) {
|
|
270
|
+
const div = document.createElement('div');
|
|
271
|
+
div.textContent = text;
|
|
272
|
+
return div.innerHTML;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function addMessage(msg) {
|
|
276
|
+
state.messages.push({
|
|
277
|
+
...msg,
|
|
278
|
+
id: generateId(),
|
|
279
|
+
timestamp: new Date()
|
|
280
|
+
});
|
|
281
|
+
render();
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function handleInput(e) {
|
|
285
|
+
if (e.key === 'Enter' && !e.shiftKey) {
|
|
286
|
+
e.preventDefault();
|
|
287
|
+
const text = e.target.value.trim();
|
|
288
|
+
if (!text) return;
|
|
289
|
+
|
|
290
|
+
e.target.value = '';
|
|
291
|
+
|
|
292
|
+
if (text.startsWith('/')) {
|
|
293
|
+
handleCommand(text);
|
|
294
|
+
} else {
|
|
295
|
+
handleSubmit(text);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
function handleCommand(text) {
|
|
301
|
+
const [cmd, ...args] = text.slice(1).split(/\s+/);
|
|
302
|
+
|
|
303
|
+
switch (cmd) {
|
|
304
|
+
case 'help':
|
|
305
|
+
addMessage({
|
|
306
|
+
role: 'system',
|
|
307
|
+
content: `Available commands:
|
|
308
|
+
/help - Show this help
|
|
309
|
+
/clear - Clear messages
|
|
310
|
+
/debug - Toggle debug mode
|
|
311
|
+
/status - Show status`
|
|
312
|
+
});
|
|
313
|
+
break;
|
|
314
|
+
case 'clear':
|
|
315
|
+
state.messages = [];
|
|
316
|
+
addMessage({ role: 'system', content: 'Messages cleared.' });
|
|
317
|
+
break;
|
|
318
|
+
case 'debug':
|
|
319
|
+
state.debug = !state.debug;
|
|
320
|
+
document.body.classList.toggle('debug', state.debug);
|
|
321
|
+
addMessage({ role: 'system', content: `Debug mode ${state.debug ? 'enabled' : 'disabled'}` });
|
|
322
|
+
break;
|
|
323
|
+
default:
|
|
324
|
+
addMessage({ role: 'system', content: `Unknown command: /${cmd}` });
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
async function handleSubmit(text) {
|
|
329
|
+
addMessage({ role: 'user', content: text });
|
|
330
|
+
|
|
331
|
+
state.agentState = { status: 'thinking' };
|
|
332
|
+
render();
|
|
333
|
+
|
|
334
|
+
// Simulate response (replace with actual API call)
|
|
335
|
+
setTimeout(() => {
|
|
336
|
+
addMessage({
|
|
337
|
+
role: 'assistant',
|
|
338
|
+
content: `This is the web UI preview. Connect to the ZTC backend for real responses.\n\nYou said: "${text}"`
|
|
339
|
+
});
|
|
340
|
+
state.agentState = { status: 'idle' };
|
|
341
|
+
render();
|
|
342
|
+
}, 1000);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Initialize
|
|
346
|
+
addMessage({
|
|
347
|
+
role: 'system',
|
|
348
|
+
content: 'Welcome to ZTC Web Preview.\nThis is a browser-based UI for debugging. Type a message or /help for commands.'
|
|
349
|
+
});
|
|
350
|
+
</script>
|
|
351
|
+
</body>
|
|
352
|
+
</html>
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64">
|
|
2
|
+
<rect x="6" y="6" width="52" height="52" rx="10" ry="10" fill="#000" stroke="#fff" stroke-width="4" />
|
|
3
|
+
<text x="32" y="38" text-anchor="middle" font-family="Arial, Helvetica, sans-serif" font-size="20" fill="#fff">ZDE</text>
|
|
4
|
+
</svg>
|