@zswarm/core 0.1.0 → 0.1.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/dist/ops/bus.d.ts CHANGED
@@ -23,6 +23,7 @@ export declare function planBus(client: ZellijClient, state: StateStore, env?: N
23
23
  * message and replies with nothing, so each attempt rotates to a new key. And a
24
24
  * freshly launched instance replies before Zellij has pushed it a manifest, so
25
25
  * a not-ready answer is retried once rather than reported as an empty session.
26
+ * If it is still cold after that, one same-title rename nudges Zellij to push.
26
27
  */
27
28
  export declare function busSnapshot(client: ZellijClient, state: StateStore, session: string, clock: Clock, env?: NodeJS.ProcessEnv, payload?: string): Promise<{
28
29
  snapshot: BusSnapshot;
package/dist/ops/bus.js CHANGED
@@ -53,7 +53,7 @@ export function planBus(client, state, env = process.env) {
53
53
  if (!plugin) {
54
54
  return {
55
55
  ...base,
56
- reason: "no plugin wasm found; build plugin/zswarm-events or set ZSWARM_BUS_PLUGIN",
56
+ reason: "no plugin wasm found; run pnpm build:plugin or set ZSWARM_BUS_PLUGIN",
57
57
  };
58
58
  }
59
59
  if (processDisabled)
@@ -69,6 +69,19 @@ async function askOnce(client, session, url, configKey, payload) {
69
69
  const result = await client.pipePlugin({ session, url, configKey, payload });
70
70
  return parseBusReply(result.stdout);
71
71
  }
72
+ /**
73
+ * Zellij pushes a pane manifest on change, never on subscribe — there is no
74
+ * get_pane_manifest(). A quiet session leaves a freshly launched instance
75
+ * blind (ready:false, paneUpdates:0) until something moves. Renaming a pane
76
+ * to the title it already has is an invisible change that forces the push.
77
+ */
78
+ async function nudgeManifest(client, session) {
79
+ const panes = await client.listPanes(session);
80
+ const pane = panes.find((p) => !p.isPlugin && !p.exited && p.title.trim());
81
+ if (!pane)
82
+ return;
83
+ await client.renamePane({ session, paneId: pane.id, name: pane.title });
84
+ }
72
85
  /**
73
86
  * One pipe, one answer — or null, and the caller polls instead.
74
87
  *
@@ -76,6 +89,7 @@ async function askOnce(client, session, url, configKey, payload) {
76
89
  * message and replies with nothing, so each attempt rotates to a new key. And a
77
90
  * freshly launched instance replies before Zellij has pushed it a manifest, so
78
91
  * a not-ready answer is retried once rather than reported as an empty session.
92
+ * If it is still cold after that, one same-title rename nudges Zellij to push.
79
93
  */
80
94
  export async function busSnapshot(client, state, session, clock, env = process.env, payload = "status") {
81
95
  const plan = planBus(client, state, env);
@@ -83,6 +97,7 @@ export async function busSnapshot(client, state, session, clock, env = process.e
83
97
  if (!plan.enabled || !plan.url || !pluginPath)
84
98
  return null;
85
99
  let configKey = answeredWith.get(session) ?? plan.configKey;
100
+ let nudged = false;
86
101
  for (let attempt = 0; attempt < MAX_KEY_ATTEMPTS; attempt++) {
87
102
  let snapshot = await askOnce(client, session, plan.url, configKey, payload);
88
103
  if (snapshot && !snapshot.ready) {
@@ -91,6 +106,18 @@ export async function busSnapshot(client, state, session, clock, env = process.e
91
106
  (await askOnce(client, session, plan.url, configKey, payload)) ??
92
107
  snapshot;
93
108
  }
109
+ if (snapshot && !snapshot.ready && !nudged) {
110
+ nudged = true;
111
+ try {
112
+ await nudgeManifest(client, session);
113
+ snapshot =
114
+ (await askOnce(client, session, plan.url, configKey, payload)) ??
115
+ snapshot;
116
+ }
117
+ catch {
118
+ // A failed nudge must not fail the op — the caller polls instead.
119
+ }
120
+ }
94
121
  if (snapshot) {
95
122
  answeredWith.set(session, configKey);
96
123
  if (plan.installed && configKey !== plan.configKey) {
@@ -205,7 +232,7 @@ export async function busOp(client, state, args, clock, env = process.env, polic
205
232
  }
206
233
  const plugin = resolveBusPlugin(env);
207
234
  if (!plugin) {
208
- throw new ZellijError("bus_missing", "no plugin wasm found; build plugin/zswarm-events or set ZSWARM_BUS_PLUGIN");
235
+ throw new ZellijError("bus_missing", "no plugin wasm found; run pnpm build:plugin or set ZSWARM_BUS_PLUGIN");
209
236
  }
210
237
  const previous = state.readBus();
211
238
  const force = isTrue(args.force);
package/dist/schema.d.ts CHANGED
@@ -22,5 +22,4 @@ export declare const PARAMS: readonly ParamSpec[];
22
22
  export declare function mcpInputSchema(): Record<string, unknown>;
23
23
  export declare const MCP_TOOL_DESCRIPTION: string;
24
24
  export declare function cliUsage(): string;
25
- /** Turn argv (without the op) into dispatch args, driven by PARAMS. */
26
25
  export declare function parseCliArgv(argv: string[]): Record<string, unknown>;
package/dist/schema.js CHANGED
@@ -443,8 +443,27 @@ export function cliUsage() {
443
443
  return lines.join("\n");
444
444
  }
445
445
  /** Turn argv (without the op) into dispatch args, driven by PARAMS. */
446
+ /**
447
+ * Pull the op out of argv, tolerating flags before it.
448
+ *
449
+ * The op normally comes first. When it does not — `zswarm --session crew list`
450
+ * — the first token is a flag, and taking argv[0] blindly reported the flag as
451
+ * an unknown op. Only positions that already errored are affected: if argv[0]
452
+ * is a real op it wins, so `send reviewer list` still sends the word "list".
453
+ */
454
+ function extractOp(argv) {
455
+ const first = argv[0];
456
+ if (first && !first.startsWith("-")) {
457
+ return { op: first, rest: argv.slice(1) };
458
+ }
459
+ const names = OP_NAMES;
460
+ const at = argv.findIndex((token) => names.includes(token));
461
+ if (at === -1)
462
+ return { op: first ?? "", rest: argv.slice(1) };
463
+ return { op: argv[at], rest: [...argv.slice(0, at), ...argv.slice(at + 1)] };
464
+ }
446
465
  export function parseCliArgv(argv) {
447
- const [op, ...rest] = argv;
466
+ const { op, rest } = extractOp(argv);
448
467
  if (!op)
449
468
  throw new ZellijError("usage", "no op given");
450
469
  const out = { op };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zswarm/core",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "type": "module",
5
5
  "description": "zSwarm Zellij client and shared ops dispatch",
6
6
  "exports": {
@@ -29,6 +29,6 @@
29
29
  },
30
30
  "scripts": {
31
31
  "build": "tsc -p tsconfig.json",
32
- "test": "pnpm run build && node --test tests/*.test.mjs"
32
+ "test": "pnpm run build && node --test"
33
33
  }
34
34
  }