@zswarm/core 0.1.4 → 0.1.6
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/README.md +4 -1
- package/dist/exec.d.ts +14 -1
- package/dist/exec.js +107 -14
- package/dist/harness.js +12 -7
- package/dist/index.d.ts +11 -10
- package/dist/index.js +8 -8
- package/dist/ops/bus.d.ts +16 -10
- package/dist/ops/bus.js +164 -98
- package/dist/ops/delivery.d.ts +3 -3
- package/dist/ops/delivery.js +4 -7
- package/dist/ops/dispatch.d.ts +7 -1
- package/dist/ops/dispatch.js +208 -68
- package/dist/ops/guards.d.ts +2 -0
- package/dist/ops/guards.js +11 -1
- package/dist/ops/observation.d.ts +8 -0
- package/dist/ops/observation.js +26 -0
- package/dist/ops/routing.d.ts +13 -0
- package/dist/ops/routing.js +21 -0
- package/dist/ops/serve.d.ts +1 -0
- package/dist/ops/serve.js +7 -1
- package/dist/ops/spawn.d.ts +3 -3
- package/dist/ops/spawn.js +130 -64
- package/dist/ops/status.d.ts +30 -5
- package/dist/ops/status.js +231 -91
- package/dist/ops/types.d.ts +7 -1
- package/dist/ops/util.d.ts +4 -0
- package/dist/ops/util.js +7 -1
- package/dist/ops/wait.d.ts +8 -1
- package/dist/ops/wait.js +7 -3
- package/dist/schema.d.ts +2 -0
- package/dist/schema.js +50 -8
- package/dist/state.d.ts +7 -6
- package/dist/state.js +77 -17
- package/dist/zellij/args.d.ts +4 -0
- package/dist/zellij/args.js +1 -0
- package/dist/zellij/binary.d.ts +34 -0
- package/dist/zellij/binary.js +169 -8
- package/dist/zellij/bus.d.ts +11 -0
- package/dist/zellij/bus.js +22 -1
- package/dist/zellij/client.d.ts +23 -5
- package/dist/zellij/client.js +99 -33
- package/dist/zellij/panes.js +3 -0
- package/dist/zellij/session.d.ts +19 -3
- package/dist/zellij/session.js +39 -9
- package/package.json +3 -3
package/dist/ops/bus.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
2
|
import { ZellijError } from "../errors.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { loadPolicy } from "../policy.js";
|
|
4
|
+
import { DEFAULT_BUS_KEY, DEFAULT_BUS_TIMEOUT_MS, busPluginUrl, isBusPluginPane, parseBusReply, parseChangedReply, parseScrollbackReply, parseWaitReply, resolveBusPlugin, scrollbackToScreen, } from "../zellij/bus.js";
|
|
5
|
+
import { DEFAULT_TIMEOUT_MS } from "../zellij/binary.js";
|
|
6
|
+
import { isTrue, throwIfAborted } from "./util.js";
|
|
5
7
|
/**
|
|
6
8
|
* Whether to ask the event-bus plugin, and what to do when it does not answer.
|
|
7
9
|
*
|
|
@@ -9,10 +11,14 @@ import { isTrue } from "./util.js";
|
|
|
9
11
|
* prompt, because a pipe to a plugin that was never approved costs a process
|
|
10
12
|
* and a timeout on every call and then falls back anyway.
|
|
11
13
|
*/
|
|
12
|
-
/** Config keys to try before giving up; each one is a fresh pipe destination. */
|
|
13
|
-
const MAX_KEY_ATTEMPTS = 3;
|
|
14
14
|
/** A just-launched instance answers before Zellij has pushed it anything. */
|
|
15
15
|
const COLD_RETRY_MS = 200;
|
|
16
|
+
/**
|
|
17
|
+
* A marker written this recently with no live pane is an in-flight install,
|
|
18
|
+
* not a closed pane. Relaunching it is how concurrent agents used to stack
|
|
19
|
+
* copies.
|
|
20
|
+
*/
|
|
21
|
+
const INSTALL_IN_FLIGHT_MS = 10_000;
|
|
16
22
|
/** Set once a pipe has failed, so one dead plugin costs one timeout, not many. */
|
|
17
23
|
let processDisabled = null;
|
|
18
24
|
/** The key that actually answered, per session, for the life of this process. */
|
|
@@ -30,8 +36,8 @@ function negative(raw) {
|
|
|
30
36
|
const v = (raw ?? "").trim().toLowerCase();
|
|
31
37
|
return v === "0" || v === "false" || v === "no" || v === "off";
|
|
32
38
|
}
|
|
33
|
-
export function planBus(client, state, env = process.env) {
|
|
34
|
-
const marker = state.readBus();
|
|
39
|
+
export function planBus(client, state, env = process.env, session = "") {
|
|
40
|
+
const marker = session ? state.readBus(session) : null;
|
|
35
41
|
// A marker can outlive the wasm it names — an upgrade renames the artifact,
|
|
36
42
|
// so a remembered path that no longer exists must not shadow the current one.
|
|
37
43
|
const remembered = marker && existsSync(marker.plugin) ? marker : null;
|
|
@@ -65,8 +71,10 @@ export function planBus(client, state, env = process.env) {
|
|
|
65
71
|
return { ...base, enabled: true, reason: "installed" };
|
|
66
72
|
return { ...base, reason: 'not installed; run zswarm({op:"bus", install:true})' };
|
|
67
73
|
}
|
|
68
|
-
async function askOnce(client, session, url, configKey, payload) {
|
|
69
|
-
const result = await client.pipePlugin({
|
|
74
|
+
async function askOnce(client, session, url, configKey, payload, timeoutMs) {
|
|
75
|
+
const result = await client.pipePlugin({
|
|
76
|
+
session, url, configKey, payload, timeoutMs,
|
|
77
|
+
});
|
|
70
78
|
return parseBusReply(result.stdout);
|
|
71
79
|
}
|
|
72
80
|
/**
|
|
@@ -75,62 +83,80 @@ async function askOnce(client, session, url, configKey, payload) {
|
|
|
75
83
|
* blind (ready:false, paneUpdates:0) until something moves. Renaming a pane
|
|
76
84
|
* to the title it already has is an invisible change that forces the push.
|
|
77
85
|
*/
|
|
78
|
-
async function nudgeManifest(client, session) {
|
|
79
|
-
|
|
86
|
+
async function nudgeManifest(client, session, env, remaining) {
|
|
87
|
+
if (loadPolicy(env).readOnly)
|
|
88
|
+
return;
|
|
89
|
+
const listBudget = Math.min(DEFAULT_TIMEOUT_MS, remaining());
|
|
90
|
+
if (listBudget <= 0)
|
|
91
|
+
return;
|
|
92
|
+
const panes = await client.listPanes(session, listBudget);
|
|
80
93
|
const pane = panes.find((p) => !p.isPlugin && !p.exited && p.title.trim());
|
|
81
94
|
if (!pane)
|
|
82
95
|
return;
|
|
83
|
-
|
|
96
|
+
const renameBudget = Math.min(DEFAULT_TIMEOUT_MS, remaining());
|
|
97
|
+
if (renameBudget <= 0)
|
|
98
|
+
return;
|
|
99
|
+
await client.renamePane({
|
|
100
|
+
session,
|
|
101
|
+
paneId: pane.id,
|
|
102
|
+
name: pane.title,
|
|
103
|
+
timeoutMs: renameBudget,
|
|
104
|
+
});
|
|
84
105
|
}
|
|
85
106
|
/**
|
|
86
107
|
* One pipe, one answer — or null, and the caller polls instead.
|
|
87
108
|
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
109
|
+
* A freshly launched instance replies before Zellij has pushed it a manifest,
|
|
110
|
+
* so a not-ready answer is retried once rather than reported as an empty
|
|
111
|
+
* session. If it is still cold after that, one same-title rename nudges Zellij
|
|
112
|
+
* to push. A silent pipe used to rotate `instance=` keys, and `zellij pipe
|
|
113
|
+
* --plugin` loads a new copy for each key — that is how a dead bus became
|
|
114
|
+
* dozens of WASM panes. One remembered key, then polling.
|
|
93
115
|
*/
|
|
94
|
-
export async function busSnapshot(client, state, session, clock, env = process.env, payload = "status") {
|
|
95
|
-
const
|
|
116
|
+
export async function busSnapshot(client, state, session, clock, env = process.env, payload = "status", opts = {}) {
|
|
117
|
+
const remaining = () => {
|
|
118
|
+
throwIfAborted(opts.signal);
|
|
119
|
+
return opts.deadlineAt === undefined
|
|
120
|
+
? Infinity
|
|
121
|
+
: Math.max(0, opts.deadlineAt - clock.now());
|
|
122
|
+
};
|
|
123
|
+
if (remaining() <= 0)
|
|
124
|
+
return null;
|
|
125
|
+
const plan = planBus(client, state, env, session);
|
|
96
126
|
const pluginPath = plan.plugin;
|
|
97
|
-
|
|
127
|
+
const url = plan.url;
|
|
128
|
+
if (!plan.enabled || !url || !pluginPath)
|
|
98
129
|
return null;
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
catch {
|
|
118
|
-
// A failed nudge must not fail the op — the caller polls instead.
|
|
119
|
-
}
|
|
130
|
+
const configKey = answeredWith.get(session) ?? plan.configKey;
|
|
131
|
+
const ask = async () => {
|
|
132
|
+
const budget = Math.min(DEFAULT_BUS_TIMEOUT_MS, remaining());
|
|
133
|
+
if (budget <= 0)
|
|
134
|
+
return null;
|
|
135
|
+
const snapshot = await askOnce(client, session, url, configKey, payload, budget);
|
|
136
|
+
throwIfAborted(opts.signal);
|
|
137
|
+
return snapshot;
|
|
138
|
+
};
|
|
139
|
+
let snapshot = await ask();
|
|
140
|
+
if (snapshot && !snapshot.ready && remaining() > 0) {
|
|
141
|
+
await clock.sleep(Math.min(COLD_RETRY_MS, remaining()));
|
|
142
|
+
snapshot = (await ask()) ?? snapshot;
|
|
143
|
+
}
|
|
144
|
+
if (snapshot && !snapshot.ready && remaining() > 0) {
|
|
145
|
+
try {
|
|
146
|
+
await nudgeManifest(client, session, env, remaining);
|
|
147
|
+
snapshot = (await ask()) ?? snapshot;
|
|
120
148
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
// Remember the rotation, so the next process starts on a live key.
|
|
125
|
-
state.writeBus({
|
|
126
|
-
plugin: pluginPath,
|
|
127
|
-
configKey,
|
|
128
|
-
installedAt: clock.now(),
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
return { snapshot, configKey };
|
|
149
|
+
catch {
|
|
150
|
+
throwIfAborted(opts.signal);
|
|
151
|
+
// A failed nudge must not fail the op — the caller polls instead.
|
|
132
152
|
}
|
|
133
|
-
|
|
153
|
+
}
|
|
154
|
+
// An expired request says nothing about bus health or an empty cold manifest.
|
|
155
|
+
if (remaining() <= 0 && !snapshot?.ready)
|
|
156
|
+
return null;
|
|
157
|
+
if (snapshot) {
|
|
158
|
+
answeredWith.set(session, configKey);
|
|
159
|
+
return { snapshot, configKey };
|
|
134
160
|
}
|
|
135
161
|
processDisabled = "plugin did not answer; using zellij polling for this run";
|
|
136
162
|
return null;
|
|
@@ -146,10 +172,10 @@ export async function busSnapshot(client, state, session, clock, env = process.e
|
|
|
146
172
|
* `dump-screen` returns them ragged. `normalizeScreen` erases exactly that
|
|
147
173
|
* difference, and every caller here already normalizes before comparing.
|
|
148
174
|
*/
|
|
149
|
-
export async function busScreens(client, state, session, paneIds, clock, env = process.env) {
|
|
175
|
+
export async function busScreens(client, state, session, paneIds, clock, env = process.env, timeoutMs) {
|
|
150
176
|
if (paneIds.length < 2)
|
|
151
177
|
return null;
|
|
152
|
-
const plan = planBus(client, state, env);
|
|
178
|
+
const plan = planBus(client, state, env, session);
|
|
153
179
|
if (!plan.enabled || !plan.url)
|
|
154
180
|
return null;
|
|
155
181
|
const configKey = answeredWith.get(session) ?? plan.configKey;
|
|
@@ -158,6 +184,7 @@ export async function busScreens(client, state, session, paneIds, clock, env = p
|
|
|
158
184
|
url: plan.url,
|
|
159
185
|
configKey,
|
|
160
186
|
panes: paneIds,
|
|
187
|
+
timeoutMs,
|
|
161
188
|
});
|
|
162
189
|
const parsed = parseScrollbackReply(reply.stdout);
|
|
163
190
|
if (!parsed || !parsed.ready)
|
|
@@ -179,7 +206,7 @@ export async function busScreens(client, state, session, paneIds, clock, env = p
|
|
|
179
206
|
* instance, no reply — and the caller runs its own loop.
|
|
180
207
|
*/
|
|
181
208
|
export async function busWait(client, state, session, request, env = process.env) {
|
|
182
|
-
const plan = planBus(client, state, env);
|
|
209
|
+
const plan = planBus(client, state, env, session);
|
|
183
210
|
if (!plan.enabled || !plan.url)
|
|
184
211
|
return null;
|
|
185
212
|
const configKey = answeredWith.get(session) ?? plan.configKey;
|
|
@@ -199,10 +226,10 @@ export async function busWait(client, state, session, request, env = process.env
|
|
|
199
226
|
* `status` answers by sampling twice, without the gap between samples — but
|
|
200
227
|
* relative to the previous call rather than a fixed window.
|
|
201
228
|
*/
|
|
202
|
-
export async function busChanged(client, state, session, paneIds, env = process.env) {
|
|
229
|
+
export async function busChanged(client, state, session, paneIds, env = process.env, timeoutMs) {
|
|
203
230
|
if (paneIds.length === 0)
|
|
204
231
|
return null;
|
|
205
|
-
const plan = planBus(client, state, env);
|
|
232
|
+
const plan = planBus(client, state, env, session);
|
|
206
233
|
if (!plan.enabled || !plan.url)
|
|
207
234
|
return null;
|
|
208
235
|
const configKey = answeredWith.get(session) ?? plan.configKey;
|
|
@@ -211,20 +238,70 @@ export async function busChanged(client, state, session, paneIds, env = process.
|
|
|
211
238
|
url: plan.url,
|
|
212
239
|
configKey,
|
|
213
240
|
panes: paneIds,
|
|
241
|
+
timeoutMs,
|
|
214
242
|
});
|
|
215
243
|
const parsed = parseChangedReply(reply.stdout);
|
|
216
244
|
if (!parsed || !parsed.ready)
|
|
217
245
|
return null;
|
|
218
246
|
return parsed.panes.length === paneIds.length ? parsed : null;
|
|
219
247
|
}
|
|
248
|
+
function installedReply(session, plugin, configKey, ready, panes, extra = {}) {
|
|
249
|
+
return {
|
|
250
|
+
ok: true,
|
|
251
|
+
data: {
|
|
252
|
+
session,
|
|
253
|
+
installed: true,
|
|
254
|
+
plugin,
|
|
255
|
+
url: busPluginUrl(plugin),
|
|
256
|
+
configKey,
|
|
257
|
+
ready,
|
|
258
|
+
panes,
|
|
259
|
+
...extra,
|
|
260
|
+
},
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
async function listBusPluginPanes(client, session, pluginPath) {
|
|
264
|
+
const panes = await client.listPanes(session);
|
|
265
|
+
return panes.filter((pane) => isBusPluginPane(pane, pluginPath));
|
|
266
|
+
}
|
|
267
|
+
/** Close every zswarm-bus plugin pane in this session. Best-effort per pane. */
|
|
268
|
+
export async function closeBusPluginPanes(client, session, pluginPath) {
|
|
269
|
+
const closed = [];
|
|
270
|
+
const panes = await listBusPluginPanes(client, session, pluginPath);
|
|
271
|
+
for (const pane of panes) {
|
|
272
|
+
try {
|
|
273
|
+
await client.closePane({ session, paneId: pane.id });
|
|
274
|
+
closed.push(pane.id);
|
|
275
|
+
}
|
|
276
|
+
catch {
|
|
277
|
+
// A pane that vanished between list and close is the desired end state.
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return closed;
|
|
281
|
+
}
|
|
220
282
|
/** Report on the bus, install it, or forget it. */
|
|
221
283
|
export async function busOp(client, state, args, clock, env = process.env, policy) {
|
|
284
|
+
const sessionArg = typeof args.session === "string" ? args.session : undefined;
|
|
222
285
|
if (isTrue(args.clear)) {
|
|
223
|
-
|
|
286
|
+
let session = null;
|
|
287
|
+
let closed = [];
|
|
288
|
+
try {
|
|
289
|
+
session = (await client.resolveSession(sessionArg)).session;
|
|
290
|
+
}
|
|
291
|
+
catch {
|
|
292
|
+
session = sessionArg?.trim() || null;
|
|
293
|
+
}
|
|
294
|
+
if (session) {
|
|
295
|
+
closed = await closeBusPluginPanes(client, session, resolveBusPlugin(env) ?? state.readBus(session)?.plugin ?? null);
|
|
296
|
+
state.clearBus(session);
|
|
297
|
+
}
|
|
298
|
+
else {
|
|
299
|
+
state.clearBus();
|
|
300
|
+
}
|
|
224
301
|
resetBusCache();
|
|
225
|
-
return { ok: true, data: { installed: false, cleared: true } };
|
|
302
|
+
return { ok: true, data: { installed: false, cleared: true, closed } };
|
|
226
303
|
}
|
|
227
|
-
const { session } = await client.resolveSession(
|
|
304
|
+
const { session } = await client.resolveSession(sessionArg);
|
|
228
305
|
if (isTrue(args.install)) {
|
|
229
306
|
// Installing opens a pane, which a read-only crew is not allowed to do.
|
|
230
307
|
if (policy?.readOnly) {
|
|
@@ -234,32 +311,31 @@ export async function busOp(client, state, args, clock, env = process.env, polic
|
|
|
234
311
|
if (!plugin) {
|
|
235
312
|
throw new ZellijError("bus_missing", "no plugin wasm found; run pnpm build:plugin or set ZSWARM_BUS_PLUGIN");
|
|
236
313
|
}
|
|
237
|
-
const previous = state.readBus();
|
|
314
|
+
const previous = state.readBus(session);
|
|
238
315
|
const force = isTrue(args.force);
|
|
239
|
-
// Launching again would add a second instance, so an install that is
|
|
240
|
-
// already answering is a no-op unless the caller asked for a fresh one.
|
|
241
316
|
if (previous && !force) {
|
|
242
317
|
const live = await busSnapshot(client, state, session, clock, env);
|
|
243
318
|
if (live?.snapshot.ready) {
|
|
244
|
-
return {
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
};
|
|
319
|
+
return installedReply(session, previous.plugin, live.configKey, true, live.snapshot.panes.length, { note: "already installed" });
|
|
320
|
+
}
|
|
321
|
+
const existing = await listBusPluginPanes(client, session, plugin);
|
|
322
|
+
if (existing.length > 0) {
|
|
323
|
+
return installedReply(session, previous.plugin, previous.configKey, false, null, {
|
|
324
|
+
pane: existing[0]?.id ?? null,
|
|
325
|
+
note: "already installed but not answering; approve the permission prompt in the existing pane — do not --force unless you intend to replace it",
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
if (clock.now() - previous.installedAt < INSTALL_IN_FLIGHT_MS) {
|
|
329
|
+
return installedReply(session, previous.plugin, previous.configKey, false, null, {
|
|
330
|
+
note: "install already in flight; wait for the permission prompt rather than launching another pane",
|
|
331
|
+
});
|
|
257
332
|
}
|
|
258
333
|
}
|
|
259
|
-
//
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
334
|
+
// Marker first so a concurrent install sees an in-flight write and
|
|
335
|
+
// stops. Then reap orphans so a reload cannot stack on the old copies.
|
|
336
|
+
const configKey = previous?.configKey ?? DEFAULT_BUS_KEY;
|
|
337
|
+
state.writeBus(session, { plugin, configKey, installedAt: clock.now() });
|
|
338
|
+
const closed = await closeBusPluginPanes(client, session, plugin);
|
|
263
339
|
const url = busPluginUrl(plugin);
|
|
264
340
|
const launched = await client.launchPlugin({
|
|
265
341
|
session,
|
|
@@ -268,27 +344,17 @@ export async function busOp(client, state, args, clock, env = process.env, polic
|
|
|
268
344
|
floating: true,
|
|
269
345
|
skipCache: force,
|
|
270
346
|
});
|
|
271
|
-
state.writeBus({ plugin, configKey, installedAt: clock.now() });
|
|
272
347
|
resetBusCache();
|
|
273
348
|
const probe = await busSnapshot(client, state, session, clock, env);
|
|
274
|
-
return {
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
plugin,
|
|
280
|
-
|
|
281
|
-
configKey,
|
|
282
|
-
pane: launched.paneId,
|
|
283
|
-
ready: probe?.snapshot.ready ?? false,
|
|
284
|
-
panes: probe?.snapshot.panes.length ?? null,
|
|
285
|
-
note: probe
|
|
286
|
-
? "bus answering; list and status use it now, and this pane can be closed"
|
|
287
|
-
: "approve the plugin's permission prompt in the new pane, then re-run",
|
|
288
|
-
},
|
|
289
|
-
};
|
|
349
|
+
return installedReply(session, plugin, configKey, probe?.snapshot.ready ?? false, probe?.snapshot.panes.length ?? null, {
|
|
350
|
+
pane: launched.paneId,
|
|
351
|
+
closed,
|
|
352
|
+
note: probe
|
|
353
|
+
? "bus answering; keep this floating pane open — closing it unloads the bus"
|
|
354
|
+
: "approve the plugin's permission prompt in the new pane, then re-run without --install",
|
|
355
|
+
});
|
|
290
356
|
}
|
|
291
|
-
const plan = planBus(client, state, env);
|
|
357
|
+
const plan = planBus(client, state, env, session);
|
|
292
358
|
const probe = plan.enabled
|
|
293
359
|
? await busSnapshot(client, state, session, clock, env)
|
|
294
360
|
: null;
|
package/dist/ops/delivery.d.ts
CHANGED
|
@@ -40,9 +40,9 @@ export declare function withSenderLabel(args: Record<string, unknown>, opts?: {
|
|
|
40
40
|
selfTitle?: string | null;
|
|
41
41
|
}): Record<string, unknown>;
|
|
42
42
|
/**
|
|
43
|
-
* Before forwarding over `ZSWARM_SERVE`,
|
|
44
|
-
*
|
|
45
|
-
*
|
|
43
|
+
* Before forwarding over `ZSWARM_SERVE`, stamp a caller-chosen label. Leaving
|
|
44
|
+
* `from` unset used to let the Zellij-side process fill in its pane title —
|
|
45
|
+
* which is the serve daemon when it runs in a pane, not the remote sender.
|
|
46
46
|
*/
|
|
47
47
|
export declare function attachKnownSender(args: Record<string, unknown>, env: NodeJS.ProcessEnv): Record<string, unknown>;
|
|
48
48
|
export declare function bodyText(client: ZellijClient, args: Record<string, unknown>, body: string): string;
|
package/dist/ops/delivery.js
CHANGED
|
@@ -45,19 +45,16 @@ export function withSenderLabel(args, opts = {}) {
|
|
|
45
45
|
return { ...args, from: senderLabel(args, opts) };
|
|
46
46
|
}
|
|
47
47
|
/**
|
|
48
|
-
* Before forwarding over `ZSWARM_SERVE`,
|
|
49
|
-
*
|
|
50
|
-
*
|
|
48
|
+
* Before forwarding over `ZSWARM_SERVE`, stamp a caller-chosen label. Leaving
|
|
49
|
+
* `from` unset used to let the Zellij-side process fill in its pane title —
|
|
50
|
+
* which is the serve daemon when it runs in a pane, not the remote sender.
|
|
51
51
|
*/
|
|
52
52
|
export function attachKnownSender(args, env) {
|
|
53
53
|
const op = String(args.op ?? "");
|
|
54
54
|
if (op !== "send" && op !== "broadcast")
|
|
55
55
|
return args;
|
|
56
56
|
const sender = resolveSender(args, { env });
|
|
57
|
-
|
|
58
|
-
return { ...args, from: sender.label };
|
|
59
|
-
}
|
|
60
|
-
return args;
|
|
57
|
+
return { ...args, from: sender.label };
|
|
61
58
|
}
|
|
62
59
|
export function bodyText(client, args, body) {
|
|
63
60
|
return isTrue(args.raw) ? body : client.formatPeerMessage(senderLabel(args), body);
|
package/dist/ops/dispatch.d.ts
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import { type ZellijClient } from "../zellij/client.js";
|
|
2
2
|
import type { DispatchDeps, OpsResult } from "./types.js";
|
|
3
|
-
/**
|
|
3
|
+
/**
|
|
4
|
+
* Per-invocation routing from `--local` / `--ssh`. `--local` clears both SSH
|
|
5
|
+
* and serve (and remote IPC). `--ssh` sets the destination for this call and
|
|
6
|
+
* clears serve so the flag wins over a sticky ZSWARM_SERVE.
|
|
7
|
+
*/
|
|
8
|
+
export declare function resolveInvocationEnv(args: Record<string, unknown>, base: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
|
|
9
|
+
/** Shared MCP/CLI dispatch, with invocation routing on successes and failures. */
|
|
4
10
|
export declare function dispatchZswarm(args: Record<string, unknown>, injected?: ZellijClient, deps?: DispatchDeps): Promise<OpsResult>;
|