@zergai/ztc 0.7.0-beta.1 → 0.8.1-dev.202611041708
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-audio-darwin-arm64 +0 -0
- package/bin/ztc-capture-darwin-arm64 +0 -0
- package/bin/ztc-computer-darwin-arm64 +0 -0
- package/bin/ztc-llm-darwin-arm64 +0 -0
- package/bin/ztc-tts-darwin-arm64 +0 -0
- package/bin/ztc-tui-darwin-arm64 +0 -0
- package/bin/zterm-darwin-arm64 +0 -0
- package/dist/agent/tools/bus_message.js +27 -12
- package/dist/agent/tools/pane.d.ts +5 -0
- package/dist/agent/tools/pane.js +34 -0
- package/dist/cli_ratatui.js +5 -2
- package/dist/emulation/ztc_mux_addendum.js +8 -0
- package/dist/panes/labels.d.ts +7 -0
- package/dist/panes/labels.js +9 -0
- package/dist/web/mirror_client.d.ts +2 -0
- package/dist/web/mirror_client.js +5 -0
- package/dist/zlm-embed.mjs +1 -1
- package/package.json +5 -5
package/bin/zmux-darwin-arm64
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/bin/ztc-llm-darwin-arm64
CHANGED
|
Binary file
|
package/bin/ztc-tts-darwin-arm64
CHANGED
|
Binary file
|
package/bin/ztc-tui-darwin-arm64
CHANGED
|
Binary file
|
package/bin/zterm-darwin-arm64
CHANGED
|
Binary file
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* from cli_ratatui.ts at startup.
|
|
6
6
|
*/
|
|
7
7
|
import { readPaneResponseSnapshot } from '../../utils/pane_response.js';
|
|
8
|
+
import { resolvePaneIdByName } from './pane.js';
|
|
8
9
|
// --- Setter-based transport access ---
|
|
9
10
|
let busTransportRef = null;
|
|
10
11
|
export function setBusTransport(transport) {
|
|
@@ -26,6 +27,13 @@ function parseBusRecipient(value) {
|
|
|
26
27
|
return parseInt(toRaw, 10);
|
|
27
28
|
return new Error(`Error: "to" must be a numeric pane id from [PEERS] or "all"; got "${toRaw}".`);
|
|
28
29
|
}
|
|
30
|
+
/** A pane number, "all", or (outside simulations) the name a person gave a pane. */
|
|
31
|
+
async function resolveBusRecipient(value) {
|
|
32
|
+
const parsed = parseBusRecipient(value);
|
|
33
|
+
if (!(parsed instanceof Error) || process.env.ZTC_SIM_FREE_MODE)
|
|
34
|
+
return parsed;
|
|
35
|
+
return resolvePaneIdByName(String(value).trim());
|
|
36
|
+
}
|
|
29
37
|
async function waitForNewPaneResponse(paneId, baseline, timeoutMs) {
|
|
30
38
|
const deadline = Date.now() + timeoutMs;
|
|
31
39
|
while (Date.now() < deadline) {
|
|
@@ -81,7 +89,7 @@ When the user asks you to ask/tell another pane and get a reply, answer, respons
|
|
|
81
89
|
|
|
82
90
|
Do not use send_message for non-roster parties; use contact_external(external_id=...) instead.
|
|
83
91
|
|
|
84
|
-
|
|
92
|
+
Panes are named: a ZTC pane renamed with /rename shows its session name. When the person mentions a name ("say hi to ben"), it usually means the pane with that name; pass the name as "to", or check list_terminal_panes first.`;
|
|
85
93
|
export const sendMessageTool = {
|
|
86
94
|
definition: {
|
|
87
95
|
name: 'send_message',
|
|
@@ -93,7 +101,7 @@ export const sendMessageTool = {
|
|
|
93
101
|
type: 'string',
|
|
94
102
|
description: process.env.ZTC_SIM_FREE_MODE
|
|
95
103
|
? 'Recipient pane number (look it up in [PEERS]) or "all" to broadcast.'
|
|
96
|
-
: 'Target
|
|
104
|
+
: 'Target pane: its ID, its name as list_terminal_panes shows it (a renamed ZTC pane is named after its session, e.g. "ben"), or "all" for broadcast.',
|
|
97
105
|
},
|
|
98
106
|
text: {
|
|
99
107
|
type: 'string',
|
|
@@ -142,10 +150,12 @@ export const sendMessageTool = {
|
|
|
142
150
|
busTransportRef.sendBusMessage(0, payload, 'ztc_message');
|
|
143
151
|
return `Message queued (${kind}) to ${externalIdRaw}: "${text.slice(0, 100)}${text.length > 100 ? '...' : ''}"`;
|
|
144
152
|
}
|
|
145
|
-
const to =
|
|
153
|
+
const to = await resolveBusRecipient(args.to);
|
|
146
154
|
if (to instanceof Error) {
|
|
147
155
|
return to.message;
|
|
148
156
|
}
|
|
157
|
+
const named = typeof to === 'number' && !/^\d+$/.test(String(args.to).trim()) ? String(args.to).trim() : null;
|
|
158
|
+
const recipient = named ? `${named} (ZTC ${to})` : `ZTC ${to}`;
|
|
149
159
|
// In sim free mode, route messages through the coordinator (pane 0) instead of
|
|
150
160
|
// sending directly to target panes. Direct delivery triggers runAgent() on the
|
|
151
161
|
// recipient, creating reactive chains. The coordinator records the message in
|
|
@@ -179,16 +189,16 @@ export const sendMessageTool = {
|
|
|
179
189
|
if (waitForResponse && baseline) {
|
|
180
190
|
try {
|
|
181
191
|
const response = await waitForNewPaneResponse(to, baseline, 90_000);
|
|
182
|
-
return `Response from
|
|
192
|
+
return `Response from ${recipient}:\n${response}`;
|
|
183
193
|
}
|
|
184
194
|
catch (err) {
|
|
185
|
-
return `Message sent to
|
|
195
|
+
return `Message sent to ${recipient}, but no completed response arrived within 90s: ${err.message}`;
|
|
186
196
|
}
|
|
187
197
|
}
|
|
188
198
|
if (to === 'all') {
|
|
189
199
|
return `Message broadcast to all ZTCs: "${text.slice(0, 100)}${text.length > 100 ? '...' : ''}"`;
|
|
190
200
|
}
|
|
191
|
-
return `Message sent to
|
|
201
|
+
return `Message sent to ${recipient}: "${text.slice(0, 100)}${text.length > 100 ? '...' : ''}"`;
|
|
192
202
|
},
|
|
193
203
|
};
|
|
194
204
|
export const contactExternalTool = {
|
|
@@ -259,8 +269,8 @@ export const askZtcPaneTool = {
|
|
|
259
269
|
type: 'object',
|
|
260
270
|
properties: {
|
|
261
271
|
pane_id: {
|
|
262
|
-
type: '
|
|
263
|
-
description: 'Target ZTC pane ID.',
|
|
272
|
+
type: 'string',
|
|
273
|
+
description: 'Target ZTC pane: its ID (e.g. "2") or its name as list_terminal_panes shows it (e.g. "ben").',
|
|
264
274
|
},
|
|
265
275
|
text: {
|
|
266
276
|
type: 'string',
|
|
@@ -280,11 +290,16 @@ export const askZtcPaneTool = {
|
|
|
280
290
|
}
|
|
281
291
|
// pane_id 0 (the coordinator) is valid — don't use `|| ''`, which coerces 0
|
|
282
292
|
// to falsy and then rejects it via the >= 0 guard below.
|
|
283
|
-
const
|
|
284
|
-
|
|
285
|
-
|
|
293
|
+
const rawTarget = args.pane_id === undefined || args.pane_id === null ? '' : String(args.pane_id).trim();
|
|
294
|
+
let paneId = rawTarget === '' ? NaN : Number(rawTarget);
|
|
295
|
+
if (rawTarget !== '' && Number.isNaN(paneId) && !process.env.ZTC_SIM_FREE_MODE) {
|
|
296
|
+
const resolved = await resolvePaneIdByName(rawTarget);
|
|
297
|
+
if (resolved instanceof Error)
|
|
298
|
+
return resolved.message;
|
|
299
|
+
paneId = resolved;
|
|
300
|
+
}
|
|
286
301
|
if (Number.isNaN(paneId) || paneId < 0) {
|
|
287
|
-
return 'Error: pane_id must be a non-negative integer.';
|
|
302
|
+
return 'Error: pane_id must be a non-negative integer or a pane name.';
|
|
288
303
|
}
|
|
289
304
|
const text = String(args.text || '').trim();
|
|
290
305
|
if (!text) {
|
|
@@ -32,6 +32,11 @@ export declare function publishMirrorZdeLiteState(paneId: number, state: Record<
|
|
|
32
32
|
export declare function clearPaneToolsTuiProcess(): void;
|
|
33
33
|
export declare function getMuxTransport(): PaneCommandTransport | null;
|
|
34
34
|
export declare function getPaneToolsTransport(): PaneCommandTransport | null;
|
|
35
|
+
/**
|
|
36
|
+
* Resolves "ben" to the one other pane named ben. People address panes by the
|
|
37
|
+
* names they gave them with /rename, not by pane number.
|
|
38
|
+
*/
|
|
39
|
+
export declare function resolvePaneIdByName(name: string): Promise<number | Error>;
|
|
35
40
|
export declare function waitForPaneCreatedOrError(tui: PaneCommandTransport, expected: {
|
|
36
41
|
paneType?: string;
|
|
37
42
|
title?: string;
|
package/dist/agent/tools/pane.js
CHANGED
|
@@ -269,6 +269,40 @@ function parseLinesInput(value) {
|
|
|
269
269
|
}
|
|
270
270
|
return text.split(/\r?\n/);
|
|
271
271
|
}
|
|
272
|
+
/** A pane's name is its displayed title: a renamed ZTC pane shows its session name. */
|
|
273
|
+
function paneName(title) {
|
|
274
|
+
return title.replace(/^\[[^\]]*\]\s*/, '').trim().toLowerCase();
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Resolves "ben" to the one other pane named ben. People address panes by the
|
|
278
|
+
* names they gave them with /rename, not by pane number.
|
|
279
|
+
*/
|
|
280
|
+
export async function resolvePaneIdByName(name) {
|
|
281
|
+
if (!tuiProcessRef || !tuiProcessRef.isMuxMode) {
|
|
282
|
+
return new Error('Error: Pane names are only available with panes (zmux or the desktop app).');
|
|
283
|
+
}
|
|
284
|
+
const transport = tuiProcessRef;
|
|
285
|
+
const listed = waitForEvent(transport, (event) => event.type === 'pane_list', 5000);
|
|
286
|
+
if (!transport.send({ type: 'list_panes' })) {
|
|
287
|
+
listed.catch(() => { });
|
|
288
|
+
return new Error('Error: Unable to list panes to find that name.');
|
|
289
|
+
}
|
|
290
|
+
const event = await listed.catch((error) => error);
|
|
291
|
+
if (event instanceof Error)
|
|
292
|
+
return new Error(`Error: ${event.message}`);
|
|
293
|
+
if (event.type !== 'pane_list')
|
|
294
|
+
return new Error('Error: Unexpected response while listing panes.');
|
|
295
|
+
const wanted = paneName(name);
|
|
296
|
+
const others = event.panes.filter((pane) => pane.id !== ownPaneId);
|
|
297
|
+
const matches = others.filter((pane) => paneName(pane.title) === wanted);
|
|
298
|
+
if (matches.length === 1)
|
|
299
|
+
return matches[0].id;
|
|
300
|
+
if (matches.length > 1) {
|
|
301
|
+
return new Error(`Error: ${matches.length} panes are named "${name}" (${matches.map((pane) => pane.id).join(', ')}); use a pane ID.`);
|
|
302
|
+
}
|
|
303
|
+
const names = others.map((pane) => `[${pane.id}] ${pane.title}`).join(', ');
|
|
304
|
+
return new Error(`Error: no pane is named "${name}". ${names ? `Panes: ${names}.` : 'There are no other panes.'}`);
|
|
305
|
+
}
|
|
272
306
|
export function waitForPaneCreatedOrError(tui, expected, timeoutMs = 15000) {
|
|
273
307
|
return waitForEvent(tui, (event) => event.type === 'error' || (event.type === 'pane_created'
|
|
274
308
|
&& (!expected.requestId || event.request_id === expected.requestId)
|
package/dist/cli_ratatui.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { environmentOperationInProgress } from './agent/commands/environment.js';
|
|
2
2
|
import { getEnvironment, openEnvironment, releaseEnvironment, describeEnvironmentForAgent, isEnvironmentWorkspacePath } from './environment/store.js';
|
|
3
|
-
import { readPaneLabels } from './panes/labels.js';
|
|
3
|
+
import { readPaneLabels, sessionNamePaneTitle } from './panes/labels.js';
|
|
4
4
|
import { reconcileOrderedTranscript } from './app/ordered_transcript.js';
|
|
5
5
|
import { listCommandJobs, shutdownCommandJobs, subscribeCommandJobs } from './agent/runtime/command_jobs.js';
|
|
6
6
|
import { CommandPaneManager, commandPaneText } from './agent/runtime/command_panes.js';
|
|
@@ -2525,7 +2525,7 @@ export class RatatuiApp {
|
|
|
2525
2525
|
if (!this.paneActivityTransport().hasCapability('pane_labels_v1'))
|
|
2526
2526
|
this.syncOwnPaneTitle();
|
|
2527
2527
|
else if (this.sessionName)
|
|
2528
|
-
this.paneActivityTransport().send(
|
|
2528
|
+
this.paneActivityTransport().send(sessionNamePaneTitle(paneId, this.sessionName));
|
|
2529
2529
|
else
|
|
2530
2530
|
void readPaneLabels(this.paneActivityTransport(), paneId).then(labels => {
|
|
2531
2531
|
delete labels.manual_title;
|
|
@@ -2533,6 +2533,7 @@ export class RatatuiApp {
|
|
|
2533
2533
|
}).catch(error => this.addSystemMessage(`Unable to clear pane name: ${error.message}`));
|
|
2534
2534
|
}
|
|
2535
2535
|
this.sessionLabels.manual_title = this.sessionName;
|
|
2536
|
+
this.mirrorClient?.setPaneName(this.sessionName);
|
|
2536
2537
|
this.render();
|
|
2537
2538
|
},
|
|
2538
2539
|
getPaneLabels: async (paneId) => {
|
|
@@ -2546,6 +2547,7 @@ export class RatatuiApp {
|
|
|
2546
2547
|
if (paneId === undefined) {
|
|
2547
2548
|
this.sessionLabels = { ...labels };
|
|
2548
2549
|
this.sessionName = labels.manual_title;
|
|
2550
|
+
this.mirrorClient?.setPaneName(this.sessionName);
|
|
2549
2551
|
}
|
|
2550
2552
|
else {
|
|
2551
2553
|
const pane = this.paneRegistry.get(paneId);
|
|
@@ -4263,6 +4265,7 @@ export class RatatuiApp {
|
|
|
4263
4265
|
return;
|
|
4264
4266
|
this.sessionLabels = { ...labels };
|
|
4265
4267
|
this.sessionName = labels.manual_title;
|
|
4268
|
+
this.mirrorClient?.setPaneName(this.sessionName);
|
|
4266
4269
|
this.render();
|
|
4267
4270
|
});
|
|
4268
4271
|
setPaneToolsTuiProcess(this.paneRelayClient);
|
|
@@ -20,6 +20,14 @@ must actually use the relevant pane or bus tools in that turn.
|
|
|
20
20
|
- Use \`write_terminal_pane\` only for non-ZTC panes such as shells, commands, or editors.
|
|
21
21
|
- Use \`list_terminal_panes\` and \`read_terminal_pane\` to confirm what happened before reporting results.
|
|
22
22
|
|
|
23
|
+
### Pane Names
|
|
24
|
+
|
|
25
|
+
Panes have names. A ZTC pane renamed with \`/rename\` shows its session name
|
|
26
|
+
(\`list_terminal_panes\` lists it, e.g. \`[1] ben\`). When the person mentions a
|
|
27
|
+
name ("say hi to ben", "ask matt"), assume they mean the pane with that name:
|
|
28
|
+
pass the name to \`send_message\` (\`to\`) or \`ask_ztc_pane\` (\`pane_id\`), or check
|
|
29
|
+
\`list_terminal_panes\` first. Ask only if no pane has that name.
|
|
30
|
+
|
|
23
31
|
### Per-Pane Model Selection
|
|
24
32
|
|
|
25
33
|
When creating ZTC panes with \`create_ztc_pane\`, you can specify different LLM models:
|
package/dist/panes/labels.d.ts
CHANGED
|
@@ -5,6 +5,13 @@ export declare function readPaneLabels(transport: {
|
|
|
5
5
|
on(handler: (event: RustEvent) => void): () => void;
|
|
6
6
|
hasCapability?(name: string): boolean;
|
|
7
7
|
}, paneId: number): Promise<PaneLabels>;
|
|
8
|
+
/**
|
|
9
|
+
* Names a pane after its session. Explicitly manual: the native renderers read
|
|
10
|
+
* a title without `source` as inferred, and the next activity title replaces
|
|
11
|
+
* an inferred title, so a /rename vanished from the pane, its pill and
|
|
12
|
+
* list_terminal_panes.
|
|
13
|
+
*/
|
|
14
|
+
export declare function sessionNamePaneTitle(paneId: number, name: string): RustCommand;
|
|
8
15
|
/** Mirror of the native PaneLabels projection; inferred state stays independent. */
|
|
9
16
|
export declare function displayPaneTitle(inferred: string, labels?: PaneLabels): string;
|
|
10
17
|
export declare function inferAgentPaneTitle(input: {
|
package/dist/panes/labels.js
CHANGED
|
@@ -29,6 +29,15 @@ export async function readPaneLabels(transport, paneId) {
|
|
|
29
29
|
}
|
|
30
30
|
});
|
|
31
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* Names a pane after its session. Explicitly manual: the native renderers read
|
|
34
|
+
* a title without `source` as inferred, and the next activity title replaces
|
|
35
|
+
* an inferred title, so a /rename vanished from the pane, its pill and
|
|
36
|
+
* list_terminal_panes.
|
|
37
|
+
*/
|
|
38
|
+
export function sessionNamePaneTitle(paneId, name) {
|
|
39
|
+
return { type: 'set_pane_title', pane_id: paneId, title: name, source: 'manual' };
|
|
40
|
+
}
|
|
32
41
|
/** Mirror of the native PaneLabels projection; inferred state stays independent. */
|
|
33
42
|
export function displayPaneTitle(inferred, labels = {}) {
|
|
34
43
|
const title = labels.manual_title || [labels.project, labels.task, inferred].filter(Boolean).join(' · ');
|
|
@@ -38,6 +38,8 @@ export declare class MirrorClient implements MirrorPublisher {
|
|
|
38
38
|
constructor(port: number, paneId: number, options?: MirrorClientOptions | string);
|
|
39
39
|
getPaneId(): number;
|
|
40
40
|
getPaneName(): string;
|
|
41
|
+
/** A renamed pane speaks under its session name; no name restores "ZTC <id>". */
|
|
42
|
+
setPaneName(name: string | undefined): void;
|
|
41
43
|
getBusMember(): BusMember;
|
|
42
44
|
publish(event: {
|
|
43
45
|
type: string;
|
|
@@ -56,6 +56,11 @@ export class MirrorClient {
|
|
|
56
56
|
getPaneName() {
|
|
57
57
|
return this.paneName;
|
|
58
58
|
}
|
|
59
|
+
/** A renamed pane speaks under its session name; no name restores "ZTC <id>". */
|
|
60
|
+
setPaneName(name) {
|
|
61
|
+
const trimmed = name?.trim();
|
|
62
|
+
this.paneName = trimmed ? trimmed : this.paneId > 0 ? `ZTC ${this.paneId}` : 'ZTC';
|
|
63
|
+
}
|
|
59
64
|
getBusMember() {
|
|
60
65
|
return { id: this.paneId, name: this.paneName };
|
|
61
66
|
}
|
package/dist/zlm-embed.mjs
CHANGED
|
@@ -78502,7 +78502,7 @@ var invokeSkillTool = makeInvokeSkillTool(resolveAmbientSkills);
|
|
|
78502
78502
|
// src/zlm.ts
|
|
78503
78503
|
var ZLM_EMBED_API_VERSION = "zerglang.ztc-embed/1";
|
|
78504
78504
|
var ZLM_STDIO_PROTOCOL = "zerglang.ztc-host/1";
|
|
78505
|
-
var ZLM_ZTC_VERSION = true ? "0.
|
|
78505
|
+
var ZLM_ZTC_VERSION = true ? "0.8.1-dev.202611041708" : "development";
|
|
78506
78506
|
var ZLM_MAX_HOST_TOOLS = 64;
|
|
78507
78507
|
var ZLM_MAX_SYSTEM_PROMPT_BYTES = 128 * 1024;
|
|
78508
78508
|
var ZLM_HOST_APPROVAL_CAPABILITIES = Object.freeze([
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zergai/ztc",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.1-dev.202611041708",
|
|
4
4
|
"description": "Zerg Terminal Client - CLI agent for continual AI systems",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
6
6
|
"homepage": "https://zergai.com/docs/ztc",
|
|
@@ -275,13 +275,13 @@
|
|
|
275
275
|
"node": "^20.19.0 || >=22.12.0"
|
|
276
276
|
},
|
|
277
277
|
"zergRelease": {
|
|
278
|
-
"branch": "
|
|
279
|
-
"channel": "
|
|
280
|
-
"sourceCommit": "
|
|
278
|
+
"branch": "development",
|
|
279
|
+
"channel": "dev",
|
|
280
|
+
"sourceCommit": "eac530d341d6b7057b5fcc242ce3d9c835ceeeb1",
|
|
281
281
|
"sourceVersion": "0.2.0-canary.2"
|
|
282
282
|
},
|
|
283
283
|
"publishConfig": {
|
|
284
|
-
"tag": "
|
|
284
|
+
"tag": "dev",
|
|
285
285
|
"access": "public"
|
|
286
286
|
}
|
|
287
287
|
}
|