seatmesh 0.1.0

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.
Files changed (60) hide show
  1. package/dist/chat-cli.d.ts +4 -0
  2. package/dist/chat-cli.d.ts.map +1 -0
  3. package/dist/chat-cli.js +162 -0
  4. package/dist/chat-cli.js.map +1 -0
  5. package/dist/checkback-cli.d.ts +4 -0
  6. package/dist/checkback-cli.d.ts.map +1 -0
  7. package/dist/checkback-cli.js +103 -0
  8. package/dist/checkback-cli.js.map +1 -0
  9. package/dist/contract-lock-cli.d.ts +4 -0
  10. package/dist/contract-lock-cli.d.ts.map +1 -0
  11. package/dist/contract-lock-cli.js +180 -0
  12. package/dist/contract-lock-cli.js.map +1 -0
  13. package/dist/init.d.ts +19 -0
  14. package/dist/init.d.ts.map +1 -0
  15. package/dist/init.js +63 -0
  16. package/dist/init.js.map +1 -0
  17. package/dist/init.test.d.ts +2 -0
  18. package/dist/init.test.d.ts.map +1 -0
  19. package/dist/init.test.js +37 -0
  20. package/dist/init.test.js.map +1 -0
  21. package/dist/main.d.ts +3 -0
  22. package/dist/main.d.ts.map +1 -0
  23. package/dist/main.js +868 -0
  24. package/dist/main.js.map +1 -0
  25. package/dist/migrate-runtime.d.ts +15 -0
  26. package/dist/migrate-runtime.d.ts.map +1 -0
  27. package/dist/migrate-runtime.js +67 -0
  28. package/dist/migrate-runtime.js.map +1 -0
  29. package/dist/room-cli.d.ts +5 -0
  30. package/dist/room-cli.d.ts.map +1 -0
  31. package/dist/room-cli.js +301 -0
  32. package/dist/room-cli.js.map +1 -0
  33. package/dist/room.d.ts +4 -0
  34. package/dist/room.d.ts.map +1 -0
  35. package/dist/room.js +149 -0
  36. package/dist/room.js.map +1 -0
  37. package/dist/status-report.d.ts +20 -0
  38. package/dist/status-report.d.ts.map +1 -0
  39. package/dist/status-report.js +218 -0
  40. package/dist/status-report.js.map +1 -0
  41. package/dist/update.d.ts +15 -0
  42. package/dist/update.d.ts.map +1 -0
  43. package/dist/update.js +89 -0
  44. package/dist/update.js.map +1 -0
  45. package/dist/watch-daemon.d.ts +2 -0
  46. package/dist/watch-daemon.d.ts.map +1 -0
  47. package/dist/watch-daemon.js +41 -0
  48. package/dist/watch-daemon.js.map +1 -0
  49. package/dist/work-daemon.d.ts +2 -0
  50. package/dist/work-daemon.d.ts.map +1 -0
  51. package/dist/work-daemon.js +42 -0
  52. package/dist/work-daemon.js.map +1 -0
  53. package/package.json +29 -0
  54. package/templates/init/README.md +20 -0
  55. package/templates/init/mesh-agents.json +16 -0
  56. package/templates/init/mesh.config.yaml +94 -0
  57. package/templates/init/roles/common.yaml +5 -0
  58. package/templates/init/roles/master.yaml +5 -0
  59. package/templates/init/roles/secretary.yaml +2 -0
  60. package/templates/init/roles/worker.yaml +2 -0
package/dist/main.js ADDED
@@ -0,0 +1,868 @@
1
+ #!/usr/bin/env node
2
+ import { loadProfile, profilePaths, loadRoleIndex, renderRoleIndex, validateRoleIndex, runStackPassthrough, } from "seat-mesh-core";
3
+ import { snapshotConnectivity, formatStatus } from "seat-mesh-connectivity";
4
+ import { createRegistryForProfile } from "seat-mesh-providers";
5
+ import { printWhoami, printAgentCard, runWhoami, capturePaneSnapshot, listSessionPanes, sessionAttach, sessionUp, sessionStatus, relayoutMeshSession, reloadMesh, ensureMeshInbox, startMeshInbox, stopMeshInbox, restartMeshInbox, printMeshInboxStatus, sendToMaster, secretaryLaunch, secretaryRestart, secretaryDispatch, secretaryCollect, secretaryMeshWatch, secretarySupervise, secretaryStatus, printMiniList, miniSpawn, miniPrompt, miniDone, miniSpawnAll, runMeshSmoke, printSmokeResults, launchSession, printLaunchResults, enqueuePrompt, runRemind, printRemindResults, verifyMeshSession, printVerify, labelMeshSession, liveMeshSession, ensureBaseLayout, applyMeshSessionBorders, runFlush, printFlushResults, runSwitch, setPaneTitle, setPaneStatus, printSeatContexts, runPeek, runPpa, runToSlot, runToMini, applyMeshState, saveMeshSession, submitPaneOp, clearPaneOpsQueue, printPaneOpsList, printRelayoutPlan, assertRelayoutSafe, buildFullColdStartBrief, enqueueColdStart, runSeatInit, } from "seat-mesh-tmux";
6
+ import { buildChatCommands } from "./chat-cli.js";
7
+ import { buildCheckbackCommands } from "./checkback-cli.js";
8
+ import { buildContractLockCommands } from "./contract-lock-cli.js";
9
+ import { buildRoomCommands } from "./room-cli.js";
10
+ import { runInit } from "./init.js";
11
+ function parseArgs(argv) {
12
+ const profileFlag = [];
13
+ const rest = [];
14
+ for (let i = 0; i < argv.length; i++) {
15
+ const a = argv[i];
16
+ if (a === "--profile" || a === "-p") {
17
+ const v = argv[++i];
18
+ if (!v)
19
+ throw new Error("--profile requires a path");
20
+ profileFlag.push(v);
21
+ continue;
22
+ }
23
+ rest.push(a);
24
+ }
25
+ return { profile: profileFlag[0], rest };
26
+ }
27
+ /** Profile yaml + mesh-agents.json layout overrides (yaml is fallback only). */
28
+ function meshLoaded(profileArg) {
29
+ return applyMeshState(loadProfile(profileArg));
30
+ }
31
+ function usage(loaded) {
32
+ const prof = loaded ? `profile=${loaded.profile.name}` : "";
33
+ console.log(`seat-mesh${prof ? ` (${prof})` : ""} — profile-driven tmux multi-agent CLI
34
+
35
+ Docs: README.md + docs/ONE-PATH.md + docs/QUICKSTART.md
36
+ Cold start: bin/seat-mesh auto-runs npm install + build when dist is stale
37
+
38
+ init [--force] [--seats-root PATH] [--name NAME] create .sm/ dotdir
39
+ update [--dry-run] [--migrate] refresh _vendor templates + paths.json
40
+ report [--json] full stack report (same as bare npx seat-mesh)
41
+ session attach|up|status
42
+ verify layout + labels health
43
+ reload [--layout] rebuild engine + labels (no session kill; --layout re-grids)
44
+ layout [--no-leads] [--dry-run] [--yes] workers + minis grid (queued)
45
+ ops list|clear pane-op queue (serial)
46
+ save|auto scrape session -> mesh-agents.json (daemon also auto-scrapes every 10m)
47
+ labels re-apply @mesh_* + border strip
48
+ inbox [--json] | inbox stop|restart
49
+ peer <target> <msg...> manager -> any pane (one path; alias: prompt -m)
50
+ to-master | to-slot | to-mini <msg...> enqueue (daemon injects)
51
+ secretary start|dispatch|collect|status|watch …
52
+ mini list|spawn|prompt|done|dispatch-all
53
+ checkback start|list|cancel|cancel-all (alias: patience)
54
+ test smoke: layout, providers, inbox, proxy
55
+ launch [--now] [targets…]
56
+ prompt | remind | flush
57
+ contexts [--json] | peek | ppa
58
+ switch | handoff | title | status
59
+ agent [target] scoped can/cannot for this pane (profile role)
60
+ whoami [target] | cold-start [--inject] | seat init
61
+ room | chat | index | proxy | providers | manager | stack | profile show
62
+
63
+ --profile <dir|yaml> override config (default: .sm/ walk-up or bundled profile)
64
+ `);
65
+ }
66
+ async function main() {
67
+ const { profile: profileArg, rest } = parseArgs(process.argv.slice(2));
68
+ const [cmd, sub, ...tail] = rest;
69
+ if (!cmd) {
70
+ const loaded = meshLoaded(profileArg);
71
+ const { printStatusReport } = await import("./status-report.js");
72
+ const report = await printStatusReport(loaded, { json: rest.includes("--json") });
73
+ process.exit(report.ok ? 0 : 1);
74
+ }
75
+ if (cmd === "-h" || cmd === "--help" || cmd === "help") {
76
+ usage(meshLoaded(profileArg));
77
+ return;
78
+ }
79
+ if (cmd === "update") {
80
+ const { runUpdate } = await import("./update.js");
81
+ const dryRun = rest.includes("--dry-run");
82
+ const migrate = rest.includes("--migrate");
83
+ const r = runUpdate({ profileArg, dryRun, migrate });
84
+ console.log(`OK: update dryRun=${dryRun} migrate=${migrate}`);
85
+ console.log(` paths: ${r.pathsManifest}`);
86
+ for (const line of r.refreshed)
87
+ console.log(` refreshed: ${line}`);
88
+ for (const line of r.skipped)
89
+ console.log(` skipped (exists): ${line}`);
90
+ if (r.migrate) {
91
+ for (const line of r.migrate.copied)
92
+ console.log(` migrate copied: ${line}`);
93
+ for (const line of r.migrate.skipped)
94
+ console.log(` migrate skipped: ${line}`);
95
+ }
96
+ return;
97
+ }
98
+ if (cmd === "migrate-runtime") {
99
+ const { runMigrateRuntime } = await import("./migrate-runtime.js");
100
+ const dryRun = rest.includes("--dry-run");
101
+ const noSeats = rest.includes("--no-seats");
102
+ const r = runMigrateRuntime({ profileArg, dryRun, seats: !noSeats });
103
+ console.log(`OK: migrate-runtime dryRun=${dryRun}`);
104
+ for (const line of r.copied)
105
+ console.log(` copied: ${line}`);
106
+ for (const line of r.skipped)
107
+ console.log(` skipped: ${line}`);
108
+ for (const line of r.notes)
109
+ console.log(` note: ${line}`);
110
+ return;
111
+ }
112
+ if (cmd === "init") {
113
+ const force = rest.includes("--force");
114
+ const seatsIdx = rest.indexOf("--seats-root");
115
+ const seatsRoot = seatsIdx >= 0 && rest[seatsIdx + 1] ? rest[seatsIdx + 1] : undefined;
116
+ const nameIdx = rest.indexOf("--name");
117
+ const name = nameIdx >= 0 && rest[nameIdx + 1] ? rest[nameIdx + 1] : undefined;
118
+ const r = runInit({ force, seatsRoot, name });
119
+ console.log(`OK: init ${r.smDir}`);
120
+ console.log(` config: ${r.configPath}`);
121
+ console.log(` created: ${r.created.length} file(s)`);
122
+ if (r.skipped.length)
123
+ console.log(` skipped (exists): ${r.skipped.length}`);
124
+ console.log(" next: npx seat-mesh session up (or ./sm.sh if wired)");
125
+ return;
126
+ }
127
+ if (cmd === "profile" && sub === "show") {
128
+ const loaded = meshLoaded(profileArg);
129
+ const paths = profilePaths(loaded);
130
+ console.log(`name=${loaded.profile.name}`);
131
+ console.log(`path=${loaded.profilePath}`);
132
+ console.log(`workspace=${loaded.workspace}`);
133
+ console.log(`workspace_id=${loaded.workspaceId}`);
134
+ console.log(`session_name=${loaded.sessionName}`);
135
+ console.log(`daemon_port=${paths.daemonPort}`);
136
+ console.log(`data_root=${paths.dataRoot}`);
137
+ console.log(`daemon_dir=${paths.daemonDir}`);
138
+ console.log(`seats_root=${paths.seatsRoot}`);
139
+ console.log(`roles_dir=${paths.rolesDir}`);
140
+ return;
141
+ }
142
+ if (cmd === "session") {
143
+ const loaded = meshLoaded(profileArg);
144
+ if (sub === "up") {
145
+ sessionUp(loaded);
146
+ console.log(`OK: session '${loaded.sessionName}' created`);
147
+ printMeshInboxStatus(loaded);
148
+ return;
149
+ }
150
+ if (sub === "attach" || !sub) {
151
+ sessionAttach(loaded);
152
+ return;
153
+ }
154
+ if (sub === "status") {
155
+ sessionStatus(loaded);
156
+ return;
157
+ }
158
+ console.error("usage: session attach|up|status");
159
+ process.exit(2);
160
+ }
161
+ if (cmd === "verify") {
162
+ const loaded = meshLoaded(profileArg);
163
+ ensureMeshInbox(loaded, { quiet: true });
164
+ const layoutOk = printVerify(verifyMeshSession(loaded));
165
+ const inboxOk = printMeshInboxStatus(loaded);
166
+ process.exit(layoutOk && inboxOk ? 0 : 1);
167
+ }
168
+ if (cmd === "reload") {
169
+ const loaded = meshLoaded(profileArg);
170
+ const layout = rest.includes("--layout");
171
+ reloadMesh(loaded, { layout });
172
+ console.log(layout
173
+ ? `OK: reload + relayout session ${loaded.sessionName}`
174
+ : `OK: reload (build + labels) session ${loaded.sessionName}`);
175
+ printMeshInboxStatus(loaded);
176
+ return;
177
+ }
178
+ if (cmd === "layout") {
179
+ const loaded = meshLoaded(profileArg);
180
+ const skipLeads = rest.includes("--no-leads");
181
+ const force = rest.includes("--yes");
182
+ const dryRun = rest.includes("--dry-run");
183
+ const m = loaded.profile.layout?.minis;
184
+ if (dryRun) {
185
+ printRelayoutPlan(loaded);
186
+ return;
187
+ }
188
+ submitPaneOp(loaded, "relayout", { skipMinisLeads: skipLeads, force }, `layout ${m?.grid ?? "grid"}`, () => {
189
+ assertRelayoutSafe(loaded, force);
190
+ relayoutMeshSession(loaded, { skipMinisLeads: skipLeads, force });
191
+ const reg = createRegistryForProfile(loaded.profile);
192
+ const saved = saveMeshSession(loaded, reg);
193
+ const grid = m?.grid ?? "4x2";
194
+ const leadNote = skipLeads || !m
195
+ ? ""
196
+ : ` leads=[${Array.isArray(m.leads) ? m.leads.join(",") : "1,2"}]`;
197
+ console.log(`OK: relayout ${loaded.sessionName} (workers 3x2, minis ${grid}${leadNote})`);
198
+ console.log(`OK: layout saved ${saved}`);
199
+ });
200
+ return;
201
+ }
202
+ if (cmd === "ops") {
203
+ const loaded = meshLoaded(profileArg);
204
+ if (sub === "list" || !sub) {
205
+ printPaneOpsList(loaded);
206
+ return;
207
+ }
208
+ if (sub === "clear") {
209
+ const n = clearPaneOpsQueue(loaded);
210
+ if (n < 0) {
211
+ console.error("pane-ops clear: inbox unavailable");
212
+ process.exit(1);
213
+ }
214
+ console.log(`OK: pane-ops cleared ${n} open`);
215
+ return;
216
+ }
217
+ console.error("usage: ops list|clear");
218
+ process.exit(2);
219
+ }
220
+ if (cmd === "inbox") {
221
+ const loaded = meshLoaded(profileArg);
222
+ const json = rest.includes("--json");
223
+ if (sub === "stop") {
224
+ stopMeshInbox(loaded);
225
+ return;
226
+ }
227
+ if (sub === "restart") {
228
+ restartMeshInbox(loaded);
229
+ return;
230
+ }
231
+ if (sub === "start") {
232
+ startMeshInbox(loaded);
233
+ return;
234
+ }
235
+ // status (default): engine auto-starts, then one-line status
236
+ ensureMeshInbox(loaded, { quiet: true });
237
+ const ok = printMeshInboxStatus(loaded, { json });
238
+ process.exit(ok ? 0 : 1);
239
+ }
240
+ if (cmd === "to-master") {
241
+ const loaded = meshLoaded(profileArg);
242
+ let from;
243
+ let slot;
244
+ const parts = [];
245
+ const args = [sub, ...tail].filter((a) => a != null && a !== "");
246
+ for (let i = 0; i < args.length; i++) {
247
+ const a = args[i];
248
+ if (a === "--from" && args[i + 1])
249
+ from = args[++i];
250
+ else if (a === "--slot" && args[i + 1])
251
+ slot = args[++i];
252
+ else
253
+ parts.push(a);
254
+ }
255
+ const msg = parts.join(" ").trim();
256
+ if (!msg) {
257
+ console.error("usage: to-master [--from <who>] [--slot <N|label>] <msg...>");
258
+ process.exit(2);
259
+ }
260
+ const entry = sendToMaster(loaded, msg, { from, slot });
261
+ if (!entry || entry.ok !== true) {
262
+ console.error("FAIL: to-master enqueue (inbox down?) — run: ./sm.sh inbox");
263
+ process.exit(1);
264
+ }
265
+ console.log(JSON.stringify(entry, null, 2));
266
+ return;
267
+ }
268
+ if (cmd === "to-slot") {
269
+ const loaded = meshLoaded(profileArg);
270
+ const dest = sub;
271
+ const msg = tail.join(" ").trim();
272
+ try {
273
+ runToSlot(loaded, dest ?? "", msg);
274
+ }
275
+ catch (e) {
276
+ console.error(e.message);
277
+ process.exit(1);
278
+ }
279
+ return;
280
+ }
281
+ if (cmd === "to-mini") {
282
+ const loaded = meshLoaded(profileArg);
283
+ const mid = sub;
284
+ const msg = tail.join(" ").trim();
285
+ try {
286
+ runToMini(loaded, mid ?? "", msg);
287
+ }
288
+ catch (e) {
289
+ console.error(e.message);
290
+ process.exit(1);
291
+ }
292
+ return;
293
+ }
294
+ if (cmd === "peer") {
295
+ const loaded = meshLoaded(profileArg);
296
+ const target = sub;
297
+ const msg = tail.join(" ").trim();
298
+ if (!target || !msg) {
299
+ console.error("usage: peer <manager|secretary|slot-N|mini-N|pane> <msg...>");
300
+ process.exit(2);
301
+ }
302
+ try {
303
+ const { paneId, targetLabel } = enqueuePrompt(loaded, target, msg, { manager: true });
304
+ console.log(`OK: peer -> ${targetLabel} pane=${paneId} (daemon inject when idle)`);
305
+ }
306
+ catch (e) {
307
+ console.error(e.message);
308
+ process.exit(1);
309
+ }
310
+ return;
311
+ }
312
+ if (cmd === "mini") {
313
+ const loaded = meshLoaded(profileArg);
314
+ const reg = createRegistryForProfile(loaded.profile);
315
+ if (sub === "list" || !sub) {
316
+ printMiniList(loaded);
317
+ return;
318
+ }
319
+ if (sub === "dispatch-all") {
320
+ miniSpawnAll(loaded, reg);
321
+ return;
322
+ }
323
+ if (sub === "spawn") {
324
+ const args = tail.filter((a) => a !== "--");
325
+ let role = "helper";
326
+ const ids = [];
327
+ const taskParts = [];
328
+ for (let i = 0; i < args.length; i++) {
329
+ const a = args[i];
330
+ if (a === "--role" && args[i + 1]) {
331
+ role = args[++i];
332
+ continue;
333
+ }
334
+ if (a === "all") {
335
+ for (let n = 1; n <= loaded.profile.session.miniMax; n++)
336
+ ids.push(n);
337
+ continue;
338
+ }
339
+ const m = a.match(/^mini-?(\d+)$/);
340
+ if (m) {
341
+ ids.push(Number(m[1]));
342
+ continue;
343
+ }
344
+ if (/^\d+$/.test(a)) {
345
+ ids.push(Number(a));
346
+ continue;
347
+ }
348
+ taskParts.push(a);
349
+ }
350
+ const task = taskParts.join(" ").trim();
351
+ if (!ids.length || !task) {
352
+ console.error("usage: mini spawn <1-8|all|mini-N> [--role helper] <task...>");
353
+ process.exit(2);
354
+ }
355
+ for (const n of ids) {
356
+ submitPaneOp(loaded, "mini-spawn", { n, role, task, viaSecretary: false }, `mini spawn ${n} role=${role}`, () => miniSpawn(loaded, reg, n, role, task, { viaSecretary: false }));
357
+ }
358
+ return;
359
+ }
360
+ if (sub === "prompt") {
361
+ const n = Number(tail[0]);
362
+ const text = tail.slice(1).join(" ");
363
+ if (!n || !text) {
364
+ console.error("usage: mini prompt <N> <text...>");
365
+ process.exit(2);
366
+ }
367
+ miniPrompt(loaded, reg, n, text);
368
+ return;
369
+ }
370
+ if (sub === "done") {
371
+ const n = Number(tail[0]);
372
+ const report = tail.slice(1).join(" ");
373
+ if (!n || !report) {
374
+ console.error("usage: mini done <N> PASS|FAIL: <evidence>");
375
+ process.exit(2);
376
+ }
377
+ miniDone(loaded, n, report);
378
+ return;
379
+ }
380
+ console.error("usage: mini list|spawn|prompt|done|dispatch-all");
381
+ process.exit(2);
382
+ }
383
+ if (cmd === "secretary") {
384
+ const loaded = meshLoaded(profileArg);
385
+ if (sub === "start") {
386
+ secretaryLaunch(loaded);
387
+ return;
388
+ }
389
+ if (sub === "restart") {
390
+ const reg = createRegistryForProfile(loaded.profile);
391
+ secretaryRestart(loaded, reg);
392
+ saveMeshSession(loaded, reg);
393
+ return;
394
+ }
395
+ if (sub === "dispatch") {
396
+ const reg = createRegistryForProfile(loaded.profile);
397
+ secretaryDispatch(loaded, reg);
398
+ return;
399
+ }
400
+ if (sub === "collect") {
401
+ const reg = createRegistryForProfile(loaded.profile);
402
+ const send = rest.includes("--send");
403
+ const nudge = rest.includes("--nudge");
404
+ const digest = secretaryCollect(loaded, reg, { sendManager: send, nudgeOpen: nudge });
405
+ process.exit(digest.allDone ? 0 : 1);
406
+ }
407
+ if (sub === "status" || !sub) {
408
+ secretaryStatus(loaded);
409
+ return;
410
+ }
411
+ if (sub === "watch") {
412
+ const action = (tail[0] ?? "status").toLowerCase();
413
+ if (action === "on") {
414
+ secretaryMeshWatch(loaded, "on", tail[1] ?? "5m");
415
+ return;
416
+ }
417
+ if (action === "off") {
418
+ secretaryMeshWatch(loaded, "off");
419
+ return;
420
+ }
421
+ secretaryMeshWatch(loaded, "status");
422
+ return;
423
+ }
424
+ if (sub === "supervise") {
425
+ const reg = createRegistryForProfile(loaded.profile);
426
+ const action = (tail[0] ?? "status").toLowerCase();
427
+ if (action === "on") {
428
+ secretarySupervise(loaded, reg, "on", tail[1] ?? "5m");
429
+ return;
430
+ }
431
+ if (action === "off") {
432
+ secretarySupervise(loaded, reg, "off");
433
+ return;
434
+ }
435
+ secretarySupervise(loaded, reg, "status");
436
+ return;
437
+ }
438
+ console.error("usage: secretary start|restart|status|supervise on [5m]|supervise off|watch on [5m]|watch off");
439
+ process.exit(2);
440
+ }
441
+ if (cmd === "peek") {
442
+ const loaded = meshLoaded(profileArg);
443
+ const reg = createRegistryForProfile(loaded.profile);
444
+ const target = sub ?? "here";
445
+ const modeRaw = (tail[0] ?? "status").toLowerCase();
446
+ const mode = modeRaw === "full" ? "full" : "status";
447
+ try {
448
+ runPeek(loaded, reg, target, mode);
449
+ }
450
+ catch (e) {
451
+ console.error(e.message);
452
+ process.exit(1);
453
+ }
454
+ return;
455
+ }
456
+ if (cmd === "ppa") {
457
+ const loaded = meshLoaded(profileArg);
458
+ const reg = createRegistryForProfile(loaded.profile);
459
+ const ppaSub = sub ?? "perf-index";
460
+ if (ppaSub !== "perf-index" && ppaSub !== "index") {
461
+ console.error("usage: ppa [perf-index]");
462
+ process.exit(2);
463
+ }
464
+ try {
465
+ runPpa(loaded, reg);
466
+ }
467
+ catch (e) {
468
+ console.error(e.message);
469
+ process.exit(1);
470
+ }
471
+ return;
472
+ }
473
+ if (cmd === "contexts" || cmd === "seats") {
474
+ const loaded = meshLoaded(profileArg);
475
+ printSeatContexts(loaded, rest.includes("--json"));
476
+ return;
477
+ }
478
+ if (cmd === "cold-start" || cmd === "coldstart") {
479
+ const loaded = meshLoaded(profileArg);
480
+ const inject = rest.includes("--inject");
481
+ const force = rest.includes("--force");
482
+ const targetArg = sub && sub !== "--inject" ? sub : undefined;
483
+ const w = runWhoami(loaded, targetArg);
484
+ const miniMatch = targetArg?.match(/^mini-(\d+)$/);
485
+ const mini = miniMatch?.[1] ?? (w.role === "manager-mini" ? targetArg : undefined);
486
+ const target = targetArg ?? "here";
487
+ if (inject) {
488
+ const r = enqueueColdStart(loaded, target, {
489
+ mini: mini ?? null,
490
+ force,
491
+ });
492
+ console.log(r.skipped
493
+ ? `OK: cold-start skipped (idempotent fingerprint=${r.fingerprint}) -> ${target}`
494
+ : `OK: cold-start enqueued fingerprint=${r.fingerprint} -> ${target}`);
495
+ return;
496
+ }
497
+ console.log(buildFullColdStartBrief(loaded, w, { mini: mini ?? null }));
498
+ return;
499
+ }
500
+ if (cmd === "seat" && sub === "init") {
501
+ const loaded = meshLoaded(profileArg);
502
+ const { created, ensured } = runSeatInit(loaded);
503
+ console.log(`OK: seat init (ensured=${ensured.length} created=${created.length} — idempotent, never overwrites FOCUS/TASKS)`);
504
+ for (const p of created.slice(0, 12))
505
+ console.log(` + ${p}`);
506
+ if (created.length > 12)
507
+ console.log(` ... +${created.length - 12} more`);
508
+ return;
509
+ }
510
+ if (cmd === "test") {
511
+ const loaded = meshLoaded(profileArg);
512
+ ensureMeshInbox(loaded, { quiet: true });
513
+ const results = await runMeshSmoke(loaded);
514
+ const ok = printSmokeResults(results);
515
+ process.exit(ok ? 0 : 1);
516
+ }
517
+ if (cmd === "labels") {
518
+ const loaded = meshLoaded(profileArg);
519
+ const session = liveMeshSession(loaded);
520
+ const layout = loaded.profile.layout;
521
+ if (!layout) {
522
+ console.error("profile missing layout");
523
+ process.exit(1);
524
+ }
525
+ labelMeshSession(loaded, session);
526
+ applyMeshSessionBorders(session, [
527
+ layout.nvim.window,
528
+ layout.base.window,
529
+ layout.workers.window,
530
+ layout.minis.window,
531
+ ]);
532
+ console.log(`OK: labels + borders on session ${session}`);
533
+ return;
534
+ }
535
+ if (cmd === "launch") {
536
+ const loaded = meshLoaded(profileArg);
537
+ const rawArgs = [sub, ...tail].filter((a) => Boolean(a) && a !== "--");
538
+ const launchNow = rawArgs.includes("--now");
539
+ const targets = rawArgs.filter((a) => a !== "--now");
540
+ const label = targets.length ? targets.join(",") : "all";
541
+ const runLaunch = () => {
542
+ const results = launchSession(loaded, {
543
+ targets: targets.length ? targets : undefined,
544
+ });
545
+ printLaunchResults(results);
546
+ if (results.some((r) => r.status === "failed"))
547
+ process.exit(1);
548
+ };
549
+ if (launchNow) {
550
+ runLaunch();
551
+ return;
552
+ }
553
+ submitPaneOp(loaded, "launch", { targets: targets.length ? targets : undefined }, `launch ${label}`, runLaunch);
554
+ return;
555
+ }
556
+ if (cmd === "prompt") {
557
+ const loaded = meshLoaded(profileArg);
558
+ let manager = false;
559
+ const args = [];
560
+ for (const a of [sub, ...tail].filter((x) => x != null && x !== "")) {
561
+ if (a === "--manager" || a === "-m")
562
+ manager = true;
563
+ else
564
+ args.push(a);
565
+ }
566
+ const [target, ...textParts] = args;
567
+ if (!target || !textParts.length) {
568
+ console.error("usage: prompt [--manager] <target> <text...>");
569
+ process.exit(2);
570
+ }
571
+ const text = textParts.join(" ");
572
+ const { paneId, targetLabel } = enqueuePrompt(loaded, target, text, { manager });
573
+ console.log(`OK: queued -> ${targetLabel} pane=${paneId} (daemon inject when idle)`);
574
+ return;
575
+ }
576
+ if (cmd === "remind") {
577
+ const loaded = meshLoaded(profileArg);
578
+ const workerCount = loaded.profile.session.workerCount;
579
+ const [target, ...noteParts] = [sub, ...tail].filter(Boolean);
580
+ if (!target) {
581
+ console.error(`usage: remind <slot|all> [note...] (manager-only, workers 1-${workerCount})`);
582
+ process.exit(2);
583
+ }
584
+ const parsed = /^(?:slot-)?(\d+)$/.exec(target);
585
+ if (target !== "all" && !parsed) {
586
+ console.error(`usage: remind <slot|all> [note...] (manager-only, workers 1-${workerCount})`);
587
+ process.exit(2);
588
+ }
589
+ if (parsed) {
590
+ const n = Number(parsed[1]);
591
+ if (n < 1 || n > workerCount) {
592
+ console.error(`refused: remind targets worker slots 1-${workerCount} only (got ${n})`);
593
+ process.exit(2);
594
+ }
595
+ }
596
+ const results = runRemind(loaded, target, {
597
+ note: noteParts.length ? noteParts.join(" ") : undefined,
598
+ });
599
+ printRemindResults(results);
600
+ return;
601
+ }
602
+ if (cmd === "flush") {
603
+ const loaded = meshLoaded(profileArg);
604
+ const reg = createRegistryForProfile(loaded.profile);
605
+ const target = sub ?? "all";
606
+ if (!sub) {
607
+ console.error("usage: flush <slot|all|manager|mini-N>");
608
+ process.exit(2);
609
+ }
610
+ const results = runFlush(loaded, reg, target);
611
+ printFlushResults(results);
612
+ return;
613
+ }
614
+ if (cmd === "switch" || cmd === "handoff") {
615
+ const loaded = meshLoaded(profileArg);
616
+ const reg = createRegistryForProfile(loaded.profile);
617
+ const args = [sub, ...tail].filter(Boolean);
618
+ if (args.length < 2) {
619
+ console.error("usage: switch <target> <agent|kiro|claude|opencode|empty> [--fresh|--resume ID] [reason...]");
620
+ process.exit(2);
621
+ }
622
+ const target = args[0];
623
+ const newType = args[1];
624
+ let fresh = false;
625
+ let resumeId;
626
+ const reasonParts = [];
627
+ for (let i = 2; i < args.length; i++) {
628
+ const a = args[i];
629
+ if (a === "--fresh")
630
+ fresh = true;
631
+ else if (a === "--resume" && args[i + 1])
632
+ resumeId = args[++i];
633
+ else if (a.startsWith("--resume="))
634
+ resumeId = a.slice("--resume=".length);
635
+ else
636
+ reasonParts.push(a);
637
+ }
638
+ const reason = reasonParts.join(" ") || undefined;
639
+ submitPaneOp(loaded, "switch", { target, newType, fresh, resumeId, reason }, `switch ${target} -> ${newType}`, () => runSwitch(loaded, reg, target, newType, {
640
+ fresh,
641
+ resumeId,
642
+ reason,
643
+ }));
644
+ return;
645
+ }
646
+ if (cmd === "report") {
647
+ const loaded = meshLoaded(profileArg);
648
+ const { printStatusReport } = await import("./status-report.js");
649
+ const report = await printStatusReport(loaded, { json: rest.includes("--json") });
650
+ process.exit(report.ok ? 0 : 1);
651
+ }
652
+ if (cmd === "title") {
653
+ const loaded = meshLoaded(profileArg);
654
+ const [target, ...parts] = [sub, ...tail].filter(Boolean);
655
+ if (!target || !parts.length) {
656
+ console.error("usage: title <target> <text...>");
657
+ process.exit(2);
658
+ }
659
+ setPaneTitle(loaded, target, parts.join(" "));
660
+ console.log(`OK: title ${target}`);
661
+ return;
662
+ }
663
+ if (cmd === "status") {
664
+ const loaded = meshLoaded(profileArg);
665
+ const [target, ...parts] = [sub, ...tail].filter(Boolean);
666
+ if (!target || !parts.length) {
667
+ console.error("usage: status <target> <text...>");
668
+ process.exit(2);
669
+ }
670
+ setPaneStatus(loaded, target, parts.join(" "));
671
+ console.log(`OK: status ${target}`);
672
+ return;
673
+ }
674
+ if (cmd === "agent") {
675
+ const loaded = meshLoaded(profileArg);
676
+ const w = runWhoami(loaded, sub || tail[0]);
677
+ printAgentCard(w);
678
+ return;
679
+ }
680
+ if (cmd === "whoami" || cmd === "where") {
681
+ if (cmd === "where") {
682
+ console.error("note: where is deprecated — use ./sm.sh whoami");
683
+ }
684
+ const loaded = meshLoaded(profileArg);
685
+ printWhoami(loaded, sub || tail[0]);
686
+ return;
687
+ }
688
+ if (cmd === "index") {
689
+ const loaded = meshLoaded(profileArg);
690
+ const paths = profilePaths(loaded);
691
+ if (sub === "show") {
692
+ let role = "worker";
693
+ for (let i = 0; i < tail.length; i++) {
694
+ if (tail[i] === "--role" && tail[i + 1])
695
+ role = tail[++i];
696
+ }
697
+ const index = loadRoleIndex(paths.rolesDir, role);
698
+ if (tail.includes("--json")) {
699
+ console.log(JSON.stringify(index, null, 2));
700
+ }
701
+ else {
702
+ console.log(renderRoleIndex(index));
703
+ }
704
+ return;
705
+ }
706
+ if (sub === "validate") {
707
+ let role = "worker";
708
+ for (let i = 0; i < tail.length; i++) {
709
+ if (tail[i] === "--role" && tail[i + 1])
710
+ role = tail[++i];
711
+ }
712
+ const index = loadRoleIndex(paths.rolesDir, role);
713
+ const result = validateRoleIndex(index, loaded.workspace);
714
+ if (!result.ok) {
715
+ console.error(`FAIL: missing paths:\n${result.missing.map((m) => ` - ${m}`).join("\n")}`);
716
+ process.exit(1);
717
+ }
718
+ console.log(`OK: role=${role} paths exist under ${loaded.workspace}`);
719
+ return;
720
+ }
721
+ console.error("usage: index show|validate");
722
+ process.exit(2);
723
+ }
724
+ if (cmd === "proxy") {
725
+ const loaded = meshLoaded(profileArg);
726
+ const snap = await snapshotConnectivity(loaded.profile);
727
+ if (sub === "status" || sub === "check" || !sub) {
728
+ console.log(formatStatus(snap));
729
+ if (sub === "check" && snap.pendingTriggers.length)
730
+ process.exit(1);
731
+ return;
732
+ }
733
+ if (sub === "reset") {
734
+ const { spawnSync } = await import("node:child_process");
735
+ const path = await import("node:path");
736
+ const script = path.join(loaded.workspace, "scripts/oc-proxy-reset.sh");
737
+ const r = spawnSync("bash", [script], {
738
+ cwd: loaded.workspace,
739
+ encoding: "utf8",
740
+ stdio: "inherit",
741
+ });
742
+ process.exit(r.status ?? 1);
743
+ }
744
+ console.error("usage: proxy status|check|reset");
745
+ process.exit(2);
746
+ }
747
+ if (cmd === "providers") {
748
+ const loaded = meshLoaded(profileArg);
749
+ const reg = createRegistryForProfile(loaded.profile);
750
+ if (sub === "list") {
751
+ for (const p of reg.all())
752
+ console.log(p.id);
753
+ return;
754
+ }
755
+ if (sub === "scan") {
756
+ const session = tail[0] ?? liveMeshSession(loaded);
757
+ const panes = listSessionPanes(session);
758
+ if (!panes.length) {
759
+ console.error(`no panes in session ${session} (tmux running?)`);
760
+ process.exit(1);
761
+ }
762
+ for (const paneId of panes) {
763
+ const snap = capturePaneSnapshot(paneId);
764
+ if (!snap)
765
+ continue;
766
+ const prov = reg.detect(snap);
767
+ const det = prov?.detect(snap);
768
+ const state = prov?.composerState(snap) ?? { phase: "plain_shell" };
769
+ const slot = snap.options.mesh_slot || "-";
770
+ const ports = snap.options.mesh_ports || "-";
771
+ console.log(`${paneId}\t${prov?.id ?? "?"}\t${det?.resumeId ?? "-"}\t${state.phase}${state.limitKind ? `:${state.limitKind}` : ""}\tslot=${slot}\tports=${ports}\t${snap.windowName}`);
772
+ }
773
+ return;
774
+ }
775
+ console.error("usage: providers list|scan [session]");
776
+ process.exit(2);
777
+ }
778
+ if (cmd === "manager") {
779
+ const loaded = meshLoaded(profileArg);
780
+ const w = runWhoami(loaded);
781
+ const isManager = w.role === "manager" || w.role === "manager-2";
782
+ const label = w.role === "manager-2"
783
+ ? "yes: manager-2"
784
+ : isManager
785
+ ? "yes: manager"
786
+ : `no: role=${w.role}`;
787
+ console.log(label);
788
+ process.exit(isManager ? 0 : 1);
789
+ }
790
+ if (cmd === "base") {
791
+ const loaded = meshLoaded(profileArg);
792
+ if (sub === "ensure") {
793
+ const session = liveMeshSession(loaded);
794
+ const panes = ensureBaseLayout(loaded, session);
795
+ labelMeshSession(loaded, session);
796
+ console.log(`OK: base panes=${panes.length} columns=${loaded.profile.layout?.base.columns?.join("|") ?? "?"}`);
797
+ return;
798
+ }
799
+ console.error("usage: base ensure");
800
+ process.exit(2);
801
+ }
802
+ if (cmd === "stack" || cmd === "dc") {
803
+ const loaded = meshLoaded(profileArg);
804
+ const args = [sub, ...tail].filter((a) => a != null && a !== "");
805
+ process.exit(runStackPassthrough(loaded, args));
806
+ }
807
+ if (cmd === "room" || cmd === "contract" || cmd === "chat") {
808
+ const loaded = meshLoaded(profileArg);
809
+ const getLoaded = () => loaded;
810
+ const branch = cmd === "room"
811
+ ? buildRoomCommands(getLoaded)
812
+ : cmd === "contract"
813
+ ? buildContractLockCommands(getLoaded)
814
+ : buildChatCommands(getLoaded);
815
+ if (!sub) {
816
+ branch.outputHelp();
817
+ return;
818
+ }
819
+ try {
820
+ await branch.parseAsync([sub, ...tail], { from: "user" });
821
+ }
822
+ catch (e) {
823
+ const err = e;
824
+ if (err.code === "commander.helpDisplayed" || err.code === "commander.version")
825
+ return;
826
+ throw e;
827
+ }
828
+ return;
829
+ }
830
+ if (cmd === "save" || cmd === "auto") {
831
+ const loaded = meshLoaded(profileArg);
832
+ const reg = createRegistryForProfile(loaded.profile);
833
+ const file = saveMeshSession(loaded, reg);
834
+ const m = loaded.profile.layout?.minis;
835
+ const layoutNote = m
836
+ ? ` minis=${m.grid} max=${m.max} leads=[${Array.isArray(m.leads) ? m.leads.join(",") : "?"}]`
837
+ : "";
838
+ console.log(`OK: saved ${file}${layoutNote}`);
839
+ return;
840
+ }
841
+ if (cmd === "checkback" || cmd === "patience") {
842
+ const loaded = meshLoaded(profileArg);
843
+ const getLoaded = () => loaded;
844
+ const branch = buildCheckbackCommands(getLoaded);
845
+ if (!sub) {
846
+ branch.outputHelp();
847
+ return;
848
+ }
849
+ try {
850
+ await branch.parseAsync([sub, ...tail], { from: "user" });
851
+ }
852
+ catch (e) {
853
+ const err = e;
854
+ if (err.code === "commander.helpDisplayed" || err.code === "commander.version")
855
+ return;
856
+ throw e;
857
+ }
858
+ return;
859
+ }
860
+ console.error(`unknown command: ${cmd}`);
861
+ usage();
862
+ process.exit(2);
863
+ }
864
+ main().catch((e) => {
865
+ console.error(e.message);
866
+ process.exit(1);
867
+ });
868
+ //# sourceMappingURL=main.js.map