@zergai/ztc 0.3.0-beta.1 → 0.4.0-beta.1
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/zmux-darwin-arm64 +0 -0
- package/bin/ztc-tui-darwin-arm64 +0 -0
- package/bin/zterm-darwin-arm64 +0 -0
- package/dist/App.js +16 -2
- package/dist/agent/agent.d.ts +20 -8
- package/dist/agent/agent.js +92 -40
- package/dist/agent/backends/gemini.js +1 -1
- package/dist/agent/backends/openai_format.js +2 -2
- package/dist/agent/backends/openai_responses.js +1 -1
- package/dist/agent/backends/types.d.ts +1 -0
- package/dist/agent/commands/config.js +15 -1
- package/dist/agent/commands/settings.js +23 -0
- package/dist/agent/commands/status.js +3 -0
- package/dist/agent/commands/types.d.ts +2 -0
- package/dist/agent/completion_state.js +2 -2
- package/dist/agent/factory.js +7 -1
- package/dist/agent/request_encoder.js +3 -0
- package/dist/agent/runtime/command_jobs.d.ts +47 -0
- package/dist/agent/runtime/command_jobs.js +268 -0
- package/dist/agent/runtime/execution_context.d.ts +16 -0
- package/dist/agent/runtime/execution_context.js +20 -0
- package/dist/agent/runtime/recovery.d.ts +9 -0
- package/dist/agent/runtime/recovery.js +71 -0
- package/dist/agent/runtime/tool_runtime.js +3 -1
- package/dist/agent/runtime/tool_scheduler.d.ts +6 -0
- package/dist/agent/runtime/tool_scheduler.js +57 -0
- package/dist/agent/subagent.js +30 -12
- package/dist/agent/tool_response_store.d.ts +2 -0
- package/dist/agent/tool_response_store.js +1 -0
- package/dist/agent/tools/deferred.js +2 -0
- package/dist/agent/tools/file.js +2 -0
- package/dist/agent/tools/pane.js +139 -42
- package/dist/agent/tools/recall_tool_response.js +1 -0
- package/dist/agent/tools/registry.js +3 -1
- package/dist/agent/tools/search.js +1 -0
- package/dist/agent/tools/shell.d.ts +2 -0
- package/dist/agent/tools/shell.js +57 -2
- package/dist/agent/tools/types.d.ts +4 -0
- package/dist/app/agent_runner.js +1 -1
- package/dist/app/ordered_transcript.d.ts +13 -0
- package/dist/app/ordered_transcript.js +55 -0
- package/dist/cli_ratatui.d.ts +2 -7
- package/dist/cli_ratatui.js +53 -34
- package/dist/config/execution.d.ts +12 -0
- package/dist/config/execution.js +13 -0
- package/dist/config/types.d.ts +1 -0
- package/dist/config.d.ts +1 -0
- package/dist/config.js +5 -0
- package/dist/emulation/tool_adapters.js +5 -2
- package/dist/headless.d.ts +1 -18
- package/dist/headless.js +15 -0
- package/dist/plugin/runtime.d.ts +1 -1
- package/dist/types.d.ts +3 -0
- package/dist/ui/ratatui/headless_pane_manager.d.ts +2 -19
- package/dist/ui/ratatui/headless_pane_manager.js +41 -34
- package/dist/ui/ratatui/pane_input.d.ts +4 -0
- package/dist/ui/ratatui/pane_input.js +15 -0
- package/dist/ui/ratatui/pane_relay.d.ts +3 -0
- package/dist/ui/ratatui/pane_relay.js +20 -2
- package/dist/ui/ratatui/protocol.d.ts +17 -0
- package/dist/ui/ratatui/protocol.js +1 -0
- package/dist/utils/shell.d.ts +2 -0
- package/dist/utils/shell.js +54 -11
- package/dist/web/mirror_stream.d.ts +2 -1
- package/dist/web/mirror_stream.js +7 -0
- package/dist/web/pane_registry.js +8 -2
- package/dist/web/view_plugin.d.ts +1 -0
- package/dist/zlm-embed.mjs +384 -118
- package/package.json +2 -2
|
@@ -28,6 +28,7 @@ export interface TranscriptAnchor {
|
|
|
28
28
|
line_offset: number;
|
|
29
29
|
}
|
|
30
30
|
/** Capability strings advertised by zmux/ztc-tui on the `Ready` event. */
|
|
31
|
+
export declare const CAPABILITY_PANE_DELIVERY_ACK = "pane_delivery_ack_v1";
|
|
31
32
|
export declare const CAPABILITY_SCROLLBACK_ANCHOR = "scrollback_anchor";
|
|
32
33
|
export declare const CAPABILITY_DESKTOP_UPDATE_RESTART = "desktop_update_restart_v1";
|
|
33
34
|
export declare const CAPABILITY_CLIPBOARD_IMAGE = "clipboard_image";
|
|
@@ -158,12 +159,14 @@ export type RustCommand = {
|
|
|
158
159
|
target?: number;
|
|
159
160
|
} | {
|
|
160
161
|
type: 'read_pane';
|
|
162
|
+
request_id?: string;
|
|
161
163
|
pane_id: number;
|
|
162
164
|
lines?: number;
|
|
163
165
|
viewport?: boolean;
|
|
164
166
|
ansi?: boolean;
|
|
165
167
|
} | {
|
|
166
168
|
type: 'write_pane';
|
|
169
|
+
request_id?: string;
|
|
167
170
|
pane_id: number;
|
|
168
171
|
input: string;
|
|
169
172
|
submit?: boolean;
|
|
@@ -356,8 +359,22 @@ export type RustEvent = {
|
|
|
356
359
|
type: 'session_restored';
|
|
357
360
|
restored_panes: number;
|
|
358
361
|
skipped_panes: number;
|
|
362
|
+
} | {
|
|
363
|
+
type: 'pane_write_result';
|
|
364
|
+
request_id?: string;
|
|
365
|
+
pane_id: number;
|
|
366
|
+
delivered: boolean;
|
|
367
|
+
queued?: boolean;
|
|
368
|
+
encoding_pending?: boolean;
|
|
369
|
+
delivered_bytes?: number;
|
|
370
|
+
total_bytes?: number;
|
|
371
|
+
partial?: boolean;
|
|
372
|
+
cancelled?: boolean;
|
|
373
|
+
error?: string;
|
|
359
374
|
} | {
|
|
360
375
|
type: 'pane_read';
|
|
376
|
+
request_id?: string;
|
|
377
|
+
error?: string;
|
|
361
378
|
pane_id: number;
|
|
362
379
|
content: string;
|
|
363
380
|
viewport?: boolean;
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* Shared by both ztc-tui (inline viewport) and zmux (fullscreen multiplexer).
|
|
6
6
|
*/
|
|
7
7
|
/** Capability strings advertised by zmux/ztc-tui on the `Ready` event. */
|
|
8
|
+
export const CAPABILITY_PANE_DELIVERY_ACK = 'pane_delivery_ack_v1';
|
|
8
9
|
export const CAPABILITY_SCROLLBACK_ANCHOR = 'scrollback_anchor';
|
|
9
10
|
export const CAPABILITY_DESKTOP_UPDATE_RESTART = 'desktop_update_restart_v1';
|
|
10
11
|
export const CAPABILITY_CLIPBOARD_IMAGE = 'clipboard_image';
|
package/dist/utils/shell.d.ts
CHANGED
|
@@ -18,6 +18,8 @@ export type RunShellCommandOptions = SandboxCommandOptions & {
|
|
|
18
18
|
temporaryWriteRoot?: string;
|
|
19
19
|
/** Text written verbatim to the command's stdin (avoids shell quoting). */
|
|
20
20
|
stdin?: string;
|
|
21
|
+
noTimeout?: boolean;
|
|
22
|
+
onOutput?: (stream: 'stdout' | 'stderr', chunk: string) => void;
|
|
21
23
|
};
|
|
22
24
|
/**
|
|
23
25
|
* Terminate every live shell-tool child group with `signal` and return the pids
|
package/dist/utils/shell.js
CHANGED
|
@@ -157,7 +157,7 @@ export async function runShellCommand(command, cwd, signal, timeoutMs, sandboxOp
|
|
|
157
157
|
throw new Error(`Command rejected for safety reasons: ${describeSafetyRule(verdict.rule)} (target: ${verdict.token}). `
|
|
158
158
|
+ `[safety rule=${verdict.rule} token=${verdict.token}]`);
|
|
159
159
|
}
|
|
160
|
-
const { env, temporaryWriteRoot, stdin, ...sandboxCommandOptions } = sandboxOptions ?? {};
|
|
160
|
+
const { env, temporaryWriteRoot, stdin, noTimeout, onOutput, ...sandboxCommandOptions } = sandboxOptions ?? {};
|
|
161
161
|
const subprocessEnv = env
|
|
162
162
|
?? (temporaryWriteRoot === undefined
|
|
163
163
|
? buildUserSubprocessEnv()
|
|
@@ -201,7 +201,15 @@ export async function runShellCommand(command, cwd, signal, timeoutMs, sandboxOp
|
|
|
201
201
|
let stderrOverflow = false;
|
|
202
202
|
let timedOut = false;
|
|
203
203
|
let cancelled = false;
|
|
204
|
+
let outputError;
|
|
204
205
|
child.stdout?.on('data', (chunk) => {
|
|
206
|
+
try {
|
|
207
|
+
onOutput?.('stdout', chunk);
|
|
208
|
+
}
|
|
209
|
+
catch (error) {
|
|
210
|
+
outputError = error;
|
|
211
|
+
onAbort();
|
|
212
|
+
}
|
|
205
213
|
if (stdout.length >= MAX_OUTPUT) {
|
|
206
214
|
stdoutOverflow = true;
|
|
207
215
|
return;
|
|
@@ -213,6 +221,13 @@ export async function runShellCommand(command, cwd, signal, timeoutMs, sandboxOp
|
|
|
213
221
|
}
|
|
214
222
|
});
|
|
215
223
|
child.stderr?.on('data', (chunk) => {
|
|
224
|
+
try {
|
|
225
|
+
onOutput?.('stderr', chunk);
|
|
226
|
+
}
|
|
227
|
+
catch (error) {
|
|
228
|
+
outputError = error;
|
|
229
|
+
onAbort();
|
|
230
|
+
}
|
|
216
231
|
if (stderr.length >= MAX_OUTPUT) {
|
|
217
232
|
stderrOverflow = true;
|
|
218
233
|
return;
|
|
@@ -224,16 +239,32 @@ export async function runShellCommand(command, cwd, signal, timeoutMs, sandboxOp
|
|
|
224
239
|
}
|
|
225
240
|
});
|
|
226
241
|
let killTimer = null;
|
|
242
|
+
let termination;
|
|
227
243
|
const escalateKill = () => {
|
|
228
|
-
if (
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
if (child.pid
|
|
232
|
-
killGroup(child.pid, '
|
|
233
|
-
|
|
234
|
-
|
|
244
|
+
if (termination)
|
|
245
|
+
return;
|
|
246
|
+
termination = new Promise(resolve => {
|
|
247
|
+
if (child.pid)
|
|
248
|
+
killGroup(child.pid, 'SIGTERM');
|
|
249
|
+
killTimer = setTimeout(() => {
|
|
250
|
+
if (child.pid) {
|
|
251
|
+
// The leader may already have exited while descendants still own
|
|
252
|
+
// the group. Never fall back to a potentially recycled leader PID.
|
|
253
|
+
if (process.platform !== 'win32') {
|
|
254
|
+
try {
|
|
255
|
+
process.kill(-child.pid, 'SIGKILL');
|
|
256
|
+
}
|
|
257
|
+
catch { /* group already exited */ }
|
|
258
|
+
}
|
|
259
|
+
else if (child.exitCode === null && child.signalCode === null) {
|
|
260
|
+
killGroup(child.pid, 'SIGKILL');
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
resolve();
|
|
264
|
+
}, 250);
|
|
265
|
+
});
|
|
235
266
|
};
|
|
236
|
-
const timeoutHandle = setTimeout(() => { timedOut = true; escalateKill(); }, timeout);
|
|
267
|
+
const timeoutHandle = noTimeout ? undefined : setTimeout(() => { timedOut = true; escalateKill(); }, timeout);
|
|
237
268
|
const onAbort = () => { cancelled = true; escalateKill(); };
|
|
238
269
|
if (signal)
|
|
239
270
|
signal.addEventListener('abort', onAbort, { once: true });
|
|
@@ -261,7 +292,13 @@ export async function runShellCommand(command, cwd, signal, timeoutMs, sandboxOp
|
|
|
261
292
|
cleanup();
|
|
262
293
|
rejectResult(e);
|
|
263
294
|
};
|
|
264
|
-
child.on('error', (err) => {
|
|
295
|
+
child.on('error', async (err) => {
|
|
296
|
+
if (termination)
|
|
297
|
+
await termination;
|
|
298
|
+
if (outputError) {
|
|
299
|
+
settleReject(outputError);
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
265
302
|
if (cancelled) {
|
|
266
303
|
settleReject(new Error('Command cancelled'));
|
|
267
304
|
return;
|
|
@@ -275,7 +312,13 @@ export async function runShellCommand(command, cwd, signal, timeoutMs, sandboxOp
|
|
|
275
312
|
truncated: stdoutOverflow || stderrOverflow,
|
|
276
313
|
});
|
|
277
314
|
});
|
|
278
|
-
child.on('close', (code, sig) => {
|
|
315
|
+
child.on('close', async (code, sig) => {
|
|
316
|
+
if (termination)
|
|
317
|
+
await termination;
|
|
318
|
+
if (outputError) {
|
|
319
|
+
settleReject(outputError);
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
279
322
|
if (cancelled) {
|
|
280
323
|
settleReject(new Error('Command cancelled'));
|
|
281
324
|
return;
|
|
@@ -18,7 +18,7 @@ import type { SlashCommandUsage } from '../agent/commands/index.js';
|
|
|
18
18
|
import type { MessageAttachment, MessageInput } from '../types.js';
|
|
19
19
|
import type { HostedSessionSettings } from '../hosted/session_settings.js';
|
|
20
20
|
import { type PaneStateUpdate } from './pane_registry.js';
|
|
21
|
-
export type MirrorEventType = 'message' | 'stream_start' | 'reasoning_delta' | 'stream_delta' | 'stream_end' | 'tool_call' | 'tool_result' | 'status' | 'token_usage' | 'error' | 'cancel' | 'mode_change' | 'pane_info' | 'pane_output' | 'zde_lite_state' | 'session_end' | 'reload' | 'clear' | 'todo_list' | 'prompt_entry' | 'ask_user' | 'queue_state' | 'accounts' | 'open_accounts' | 'hook_approval_request' | 'widget_prompt' | 'widget_select' | 'widget_questionnaire' | 'widget_dismiss' | 'widget_settings' | 'context_progress_bar_config' | 'zlicky_cursor' | 'zlicky_highlight' | 'zlicky_clear' | 'zlicky_status' | 'zlicky_capture_request' | 'cv_run_start' | 'cv_run_tick' | 'cv_run_end' | 'cv_diagnose_start' | 'cv_diagnose_classification' | 'cv_diagnose_proposal' | 'cv_diagnose_pr_opened' | 'cv_diagnose_end' | (string & {});
|
|
21
|
+
export type MirrorEventType = 'message' | 'stream_start' | 'reasoning_delta' | 'stream_delta' | 'stream_end' | 'tool_call' | 'tool_result' | 'status' | 'token_usage' | 'error' | 'cancel' | 'mode_change' | 'pane_info' | 'pane_output' | 'zde_lite_state' | 'session_end' | 'reload' | 'clear' | 'todo_list' | 'prompt_entry' | 'ask_user' | 'queue_state' | 'command_jobs' | 'accounts' | 'open_accounts' | 'hook_approval_request' | 'widget_prompt' | 'widget_select' | 'widget_questionnaire' | 'widget_dismiss' | 'widget_settings' | 'context_progress_bar_config' | 'zlicky_cursor' | 'zlicky_highlight' | 'zlicky_clear' | 'zlicky_status' | 'zlicky_capture_request' | 'cv_run_start' | 'cv_run_tick' | 'cv_run_end' | 'cv_diagnose_start' | 'cv_diagnose_classification' | 'cv_diagnose_proposal' | 'cv_diagnose_pr_opened' | 'cv_diagnose_end' | (string & {});
|
|
22
22
|
export interface MirrorEvent {
|
|
23
23
|
type: MirrorEventType;
|
|
24
24
|
timestamp: string;
|
|
@@ -199,6 +199,7 @@ export interface MirrorPaneViewportResult {
|
|
|
199
199
|
error?: string;
|
|
200
200
|
}
|
|
201
201
|
export interface MirrorPaneRecord {
|
|
202
|
+
commandJobs?: import('../agent/runtime/command_jobs.js').CommandReceipt[];
|
|
202
203
|
title?: string;
|
|
203
204
|
paneType?: string;
|
|
204
205
|
provider?: string;
|
|
@@ -2826,6 +2826,13 @@ export class MirrorStreamServer {
|
|
|
2826
2826
|
// Replay cached pane content that may have been evicted from event history,
|
|
2827
2827
|
// so new clients always see it regardless of history depth.
|
|
2828
2828
|
for (const [pid, info] of this.panes.entries()) {
|
|
2829
|
+
if (info.commandJobs) {
|
|
2830
|
+
res.write(`data: ${JSON.stringify({
|
|
2831
|
+
type: 'command_jobs',
|
|
2832
|
+
timestamp: new Date().toISOString(),
|
|
2833
|
+
data: { pane_id: pid, jobs: info.commandJobs },
|
|
2834
|
+
})}\n\n`);
|
|
2835
|
+
}
|
|
2829
2836
|
if ((info.paneType === 'doc' || info.paneType === 'feed') && info.docContent) {
|
|
2830
2837
|
res.write(`data: ${JSON.stringify({
|
|
2831
2838
|
type: 'pane_output',
|
|
@@ -95,6 +95,7 @@ export class PaneRegistry {
|
|
|
95
95
|
provider: prev?.provider,
|
|
96
96
|
model: prev?.model,
|
|
97
97
|
status: prev?.status,
|
|
98
|
+
commandJobs: prev?.commandJobs,
|
|
98
99
|
// Preserve cached content across a relayout — SSE reconnect replay
|
|
99
100
|
// (publishPaneInfo → doc/terminal snapshots) depends on it; a bare
|
|
100
101
|
// relayout must not blank a pane until its next output event.
|
|
@@ -114,19 +115,24 @@ export class PaneRegistry {
|
|
|
114
115
|
});
|
|
115
116
|
}
|
|
116
117
|
if (!next.has(0)) {
|
|
117
|
-
next.set(0, { title: 'Overseer', paneType: 'ztc', isVisible: true });
|
|
118
|
+
next.set(0, { ...this.panes.get(0), title: 'Overseer', paneType: 'ztc', isVisible: true });
|
|
118
119
|
}
|
|
119
120
|
this.panes = next;
|
|
120
121
|
}
|
|
121
122
|
/** Derive runtime status + cache pane content from a published event. */
|
|
122
123
|
applyEvent(event) {
|
|
123
|
-
const paneId = typeof event.data.pane_id === 'number' ? event.data.pane_id : undefined;
|
|
124
|
+
const paneId = typeof event.data.pane_id === 'number' ? event.data.pane_id : event.type === 'command_jobs' ? 0 : undefined;
|
|
124
125
|
if (paneId === undefined)
|
|
125
126
|
return;
|
|
127
|
+
if (paneId === 0 && event.type === 'command_jobs')
|
|
128
|
+
this.ensureOverseer();
|
|
126
129
|
const pane = this.panes.get(paneId);
|
|
127
130
|
if (!pane)
|
|
128
131
|
return;
|
|
129
132
|
switch (event.type) {
|
|
133
|
+
case 'command_jobs':
|
|
134
|
+
pane.commandJobs = Array.isArray(event.data.jobs) ? event.data.jobs.slice(0, 60) : [];
|
|
135
|
+
break;
|
|
130
136
|
case 'stream_start':
|
|
131
137
|
pane.status = 'streaming';
|
|
132
138
|
break;
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* Domain modules (Colony, monitoring dashboards, etc.) extend it
|
|
6
6
|
* by implementing this interface and registering via registerViewPlugin().
|
|
7
7
|
*/
|
|
8
|
+
export type { CommandReceipt as CommandJobView } from '../agent/runtime/command_jobs.js';
|
|
8
9
|
import type { IncomingMessage, ServerResponse } from 'http';
|
|
9
10
|
import type { MirrorEvent, MirrorPaneRecord } from './mirror_stream.js';
|
|
10
11
|
/**
|