muuuuse 2.3.4 → 2.3.5

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 CHANGED
@@ -15,16 +15,13 @@ It does one job:
15
15
  The whole surface is:
16
16
 
17
17
  ```bash
18
- muuuuse
19
18
  muuuuse 1
20
19
  muuuuse 1 flow on
21
20
  muuuuse 1 flow off
22
21
  muuuuse 1 flow off continue 5
23
- muuuuse 1 flow on continue 3 5 6
24
22
  muuuuse 2
25
23
  muuuuse 2 flow off
26
24
  muuuuse 2 flow on continue 3
27
- muuuuse 2 flow on continue 3 5 6
28
25
  muuuuse 3
29
26
  muuuuse 3 flow on
30
27
  muuuuse 4
@@ -51,7 +48,7 @@ Now both shells are armed. `muuuuse 1` generates the session key, `muuuuse 2` si
51
48
 
52
49
  `flow on` means that seat relays commentary and final answers. `flow off` means that seat relays and accepts final answers only. Mixed calibration is allowed per seat.
53
50
 
54
- `continue <seat> [<seat> ...]` forwards that seat's relayed output into one or more additional armed seats without changing the signed odd/even pair law. This lets you build local loops like `1 -> 2 -> 3 -> 4 -> 1`, split chains like `2 -> 3` and `2 -> 5`, or wider local meshes while every adjacent pair still keeps its own session keypair.
51
+ `continue <seat>` forwards that seat's relayed output into another armed seat without changing the signed odd/even pair law. This lets you build local loops like `1 -> 2 -> 3 -> 4 -> 1` while every adjacent pair still keeps its own session keypair.
55
52
 
56
53
  If you want Codex in one and Gemini in the other, start them inside the armed shells:
57
54
 
@@ -81,7 +78,7 @@ muuuuse stop
81
78
 
82
79
  - state lives under `~/.muuuuse`
83
80
  - only the signed armed pair can exchange relay events
84
- - `continue <seat> [<seat> ...]` is a separate local forwarding lane and can target any armed seat numbers
81
+ - `continue <seat>` is a separate local forwarding lane and can target any armed seat number
85
82
  - supported relay detection is built for Codex, Claude, and Gemini
86
83
 
87
84
  ## Install
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "muuuuse",
3
- "version": "2.3.4",
3
+ "version": "2.3.5",
4
4
  "description": "🔌Muuuuse arms regular terminals in isolated pairs and can continue relay output into any other armed seat.",
5
5
  "type": "commonjs",
6
6
  "bin": {
package/src/cli.js CHANGED
@@ -1,4 +1,4 @@
1
- const { BRAND, normalizeSeatId, usage } = require("./util");
1
+ const { BRAND, getPartnerSeatId, normalizeSeatId, usage } = require("./util");
2
2
  const { ArmedSeat, getStatusReport, stopAllSessions } = require("./runtime");
3
3
 
4
4
  async function main(argv = process.argv.slice(2)) {
@@ -56,10 +56,10 @@ async function main(argv = process.argv.slice(2)) {
56
56
 
57
57
  const seatId = normalizeSeatId(command);
58
58
  if (seatId) {
59
- const { flowMode, continueSeatId, continueSeatIds } = parseSeatOptions(command, argv.slice(1));
59
+ const { flowMode, continueSeatId, continueTargets } = parseSeatOptions(command, argv.slice(1));
60
60
  const seat = new ArmedSeat({
61
61
  cwd: process.cwd(),
62
- continueSeatIds,
62
+ continueTargets,
63
63
  continueSeatId,
64
64
  flowMode,
65
65
  seatId,
@@ -84,11 +84,9 @@ function renderSeatStatus(seat) {
84
84
  if (seat.partnerLive) {
85
85
  bits.push("peer live");
86
86
  }
87
- const continueSeatIds = Array.isArray(seat.continueSeatIds)
88
- ? seat.continueSeatIds
89
- : (seat.continueSeatId ? [seat.continueSeatId] : []);
90
- if (continueSeatIds.length > 0) {
91
- bits.push(`continue ${continueSeatIds.join(",")}`);
87
+ const renderedLinks = renderLinkTargets(seat);
88
+ if (renderedLinks) {
89
+ bits.push(`link ${renderedLinks}`);
92
90
  }
93
91
  if (seat.trust) {
94
92
  bits.push(`trust ${seat.trust}`);
@@ -107,16 +105,34 @@ function renderSeatStatus(seat) {
107
105
  return output;
108
106
  }
109
107
 
108
+ function renderLinkTargets(seat) {
109
+ const targets = [];
110
+ if (seat.partnerSeatId) {
111
+ targets.push({
112
+ targetSeatId: seat.partnerSeatId,
113
+ flowMode: seat.flowMode || "off",
114
+ });
115
+ }
116
+ for (const target of Array.isArray(seat.continueTargets) ? seat.continueTargets : []) {
117
+ targets.push(target);
118
+ }
119
+
120
+ return targets
121
+ .map((target) => `${target.targetSeatId}:${target.flowMode}`)
122
+ .join(", ");
123
+ }
124
+
110
125
  function parseSeatOptions(command, args) {
126
+ const seatId = normalizeSeatId(command);
111
127
  let flowMode = "off";
112
- const continueSeatIds = [];
113
- let sawContinue = false;
128
+ let continueSeatId = null;
129
+ let continueTargets = [];
114
130
  let index = 0;
115
131
 
116
132
  while (index < args.length) {
117
133
  const token = String(args[index] || "").trim().toLowerCase();
118
134
 
119
- if (token === "flow" && !sawContinue) {
135
+ if (token === "flow") {
120
136
  const flowToken = String(args[index + 1] || "").trim().toLowerCase();
121
137
  if (flowToken === "on" || flowToken === "off") {
122
138
  flowMode = flowToken;
@@ -127,22 +143,23 @@ function parseSeatOptions(command, args) {
127
143
  }
128
144
 
129
145
  if (token === "continue") {
130
- sawContinue = true;
131
- let consumedTargets = 0;
132
- index += 1;
133
-
134
- while (index < args.length) {
135
- const targetSeatId = normalizeSeatId(args[index]);
136
- if (!targetSeatId) {
137
- break;
138
- }
139
-
140
- continueSeatIds.push(targetSeatId);
141
- consumedTargets += 1;
142
- index += 1;
146
+ const parsedTargets = parseContinueTargets(args.slice(index + 1), flowMode);
147
+ if (parsedTargets.targets.length > 0) {
148
+ continueTargets = mergeTargets(continueTargets, parsedTargets.targets);
149
+ continueSeatId = continueTargets[0].targetSeatId;
150
+ index += 1 + parsedTargets.consumed;
151
+ continue;
143
152
  }
153
+ break;
154
+ }
144
155
 
145
- if (consumedTargets > 0) {
156
+ if (token === "link") {
157
+ const parsedLinks = parseLinkTargets(args.slice(index + 1), seatId, flowMode);
158
+ if (parsedLinks.consumed > 0) {
159
+ flowMode = parsedLinks.flowMode;
160
+ continueTargets = mergeTargets(continueTargets, parsedLinks.continueTargets);
161
+ continueSeatId = continueTargets[0]?.targetSeatId || null;
162
+ index += 1 + parsedLinks.consumed;
146
163
  continue;
147
164
  }
148
165
  break;
@@ -152,18 +169,98 @@ function parseSeatOptions(command, args) {
152
169
  }
153
170
 
154
171
  if (index === args.length) {
155
- return {
156
- flowMode,
157
- continueSeatId: continueSeatIds[0] || null,
158
- continueSeatIds,
159
- };
172
+ return { flowMode, continueSeatId, continueTargets };
160
173
  }
161
174
 
162
175
  throw new Error(
163
- `\`muuuuse ${command}\` accepts no extra arguments, \`flow on\` / \`flow off\`, optional \`continue <seat> [<seat> ...]\`, or both in sequence. Run it directly in the terminal you want to arm.`
176
+ `\`muuuuse ${command}\` accepts no extra arguments, \`flow on\` / \`flow off\`, optional \`continue <seat>\`, or \`link <seat> flow on [<seat> flow off ...]\`. Run it directly in the terminal you want to arm.`
164
177
  );
165
178
  }
166
179
 
180
+ function mergeTargets(existingTargets, nextTargets) {
181
+ const merged = [];
182
+ for (const target of Array.isArray(existingTargets) ? existingTargets : []) {
183
+ upsertTarget(merged, target);
184
+ }
185
+ for (const target of Array.isArray(nextTargets) ? nextTargets : []) {
186
+ upsertTarget(merged, target);
187
+ }
188
+
189
+ return merged;
190
+ }
191
+
192
+ function parseContinueTargets(args, defaultFlowMode) {
193
+ const targets = [];
194
+ let consumed = 0;
195
+
196
+ while (consumed < args.length) {
197
+ const targetSeatId = normalizeSeatId(args[consumed]);
198
+ if (!targetSeatId) {
199
+ break;
200
+ }
201
+
202
+ const nextFlowMode = parseFlowModeToken(args[consumed + 1], args[consumed + 2]);
203
+ const target = {
204
+ targetSeatId,
205
+ flowMode: nextFlowMode || defaultFlowMode,
206
+ };
207
+ upsertTarget(targets, target);
208
+ consumed += nextFlowMode ? 3 : 1;
209
+ }
210
+
211
+ return { consumed, targets };
212
+ }
213
+
214
+ function parseLinkTargets(args, seatId, defaultFlowMode) {
215
+ const partnerSeatId = seatId ? getPartnerSeatId(seatId) : null;
216
+ const continueTargets = [];
217
+ let flowMode = defaultFlowMode;
218
+ let consumed = 0;
219
+
220
+ while (consumed < args.length) {
221
+ const targetSeatId = normalizeSeatId(args[consumed]);
222
+ if (!targetSeatId) {
223
+ break;
224
+ }
225
+
226
+ const targetFlowMode = parseFlowModeToken(args[consumed + 1], args[consumed + 2]);
227
+ if (!targetFlowMode) {
228
+ break;
229
+ }
230
+
231
+ if (targetSeatId === partnerSeatId) {
232
+ flowMode = targetFlowMode;
233
+ } else {
234
+ upsertTarget(continueTargets, {
235
+ targetSeatId,
236
+ flowMode: targetFlowMode,
237
+ });
238
+ }
239
+
240
+ consumed += 3;
241
+ }
242
+
243
+ return { consumed, continueTargets, flowMode };
244
+ }
245
+
246
+ function parseFlowModeToken(flowToken, modeToken) {
247
+ const normalizedFlowToken = String(flowToken || "").trim().toLowerCase();
248
+ const normalizedModeToken = String(modeToken || "").trim().toLowerCase();
249
+ if (normalizedFlowToken === "flow" && (normalizedModeToken === "on" || normalizedModeToken === "off")) {
250
+ return normalizedModeToken;
251
+ }
252
+ return null;
253
+ }
254
+
255
+ function upsertTarget(targets, nextTarget) {
256
+ const existingIndex = targets.findIndex((entry) => entry.targetSeatId === nextTarget.targetSeatId);
257
+ if (existingIndex >= 0) {
258
+ targets[existingIndex] = nextTarget;
259
+ return;
260
+ }
261
+ targets.push(nextTarget);
262
+ }
263
+
167
264
  module.exports = {
168
265
  main,
169
266
  };
package/src/runtime.js CHANGED
@@ -91,34 +91,24 @@ function normalizeContinueSeatId(value) {
91
91
  return seatId || null;
92
92
  }
93
93
 
94
- function normalizeContinueSeatIds(value) {
95
- const values = Array.isArray(value) ? value : [value];
94
+ function normalizeContinueTargets(targets, defaultFlowMode = "off") {
95
+ const normalized = [];
96
96
  const seen = new Set();
97
- const seatIds = [];
98
97
 
99
- for (const entry of values) {
100
- const seatId = normalizeContinueSeatId(entry);
101
- if (!seatId || seen.has(seatId)) {
98
+ for (const entry of Array.isArray(targets) ? targets : []) {
99
+ const targetSeatId = normalizeSeatId(entry?.targetSeatId ?? entry?.seatId ?? entry);
100
+ if (!targetSeatId || seen.has(targetSeatId)) {
102
101
  continue;
103
102
  }
104
103
 
105
- seen.add(seatId);
106
- seatIds.push(seatId);
107
- }
108
-
109
- return seatIds;
110
- }
111
-
112
- function resolveContinueSeatConfig(continueSeatIds, continueSeatId) {
113
- if (Array.isArray(continueSeatIds) && continueSeatIds.length > 0) {
114
- return continueSeatIds;
115
- }
116
-
117
- if (continueSeatIds !== undefined && continueSeatIds !== null && !Array.isArray(continueSeatIds)) {
118
- return continueSeatIds;
104
+ seen.add(targetSeatId);
105
+ normalized.push({
106
+ targetSeatId,
107
+ flowMode: normalizeFlowMode(entry?.flowMode ?? entry?.flow ?? defaultFlowMode),
108
+ });
119
109
  }
120
110
 
121
- return continueSeatId;
111
+ return normalized;
122
112
  }
123
113
 
124
114
  function resolveShell() {
@@ -501,6 +491,7 @@ function buildAnswerSignaturePayload(sessionName, challenge, entry) {
501
491
  seatId: entry.seatId,
502
492
  origin: entry.origin,
503
493
  phase: entry.phase || "final_answer",
494
+ flowMode: entry.flowMode || "off",
504
495
  createdAt: entry.createdAt,
505
496
  text: entry.text,
506
497
  });
@@ -520,6 +511,7 @@ function buildContinuationEntry(sourceSessionName, targetSeatId, entry) {
520
511
  chainId: entry.chainId,
521
512
  hop: entry.hop,
522
513
  sourceAnswerId: entry.id,
514
+ flowMode: entry.flowMode || null,
523
515
  publicKey: entry.publicKey || null,
524
516
  signature: entry.signature || null,
525
517
  };
@@ -643,12 +635,15 @@ class ArmedSeat {
643
635
  this.partnerSeatId = getPartnerSeatId(options.seatId);
644
636
  this.anchorSeatId = isAnchorSeat(options.seatId) ? options.seatId : this.partnerSeatId;
645
637
  this.flowMode = normalizeFlowMode(options.flowMode);
646
- this.continueSeatIds = normalizeContinueSeatIds(
647
- resolveContinueSeatConfig(options.continueSeatIds, options.continueSeatId)
638
+ this.continueTargets = normalizeContinueTargets(
639
+ options.continueTargets || (
640
+ options.continueSeatId ? [{ targetSeatId: options.continueSeatId, flowMode: options.flowMode }] : []
641
+ ),
642
+ this.flowMode
648
643
  );
649
- this.continueSeatId = this.continueSeatIds[0] || null;
644
+ this.continueSeatId = this.continueTargets[0]?.targetSeatId || normalizeContinueSeatId(options.continueSeatId);
650
645
  this.cwd = normalizeWorkingPath(options.cwd);
651
- if (this.continueSeatIds.includes(this.seatId)) {
646
+ if (this.continueTargets.some((target) => target.targetSeatId === this.seatId)) {
652
647
  throw new Error(`\`muuuuse ${this.seatId}\` cannot continue to itself.`);
653
648
  }
654
649
  this.sessionName = resolveSessionName(this.cwd, this.seatId);
@@ -724,8 +719,8 @@ class ArmedSeat {
724
719
  partnerSeatId: this.partnerSeatId,
725
720
  sessionName: this.sessionName,
726
721
  flowMode: this.flowMode,
727
- continueSeatIds: this.continueSeatIds,
728
722
  continueSeatId: this.continueSeatId,
723
+ continueTargets: this.continueTargets,
729
724
  cwd: this.cwd,
730
725
  pid: process.pid,
731
726
  childPid: this.childPid,
@@ -741,8 +736,8 @@ class ArmedSeat {
741
736
  partnerSeatId: this.partnerSeatId,
742
737
  sessionName: this.sessionName,
743
738
  flowMode: this.flowMode,
744
- continueSeatIds: this.continueSeatIds,
745
739
  continueSeatId: this.continueSeatId,
740
+ continueTargets: this.continueTargets,
746
741
  cwd: this.cwd,
747
742
  pid: process.pid,
748
743
  childPid: this.childPid,
@@ -1088,8 +1083,12 @@ class ArmedSeat {
1088
1083
  return Number.isFinite(requestedAtMs) && requestedAtMs > this.startedAtMs;
1089
1084
  }
1090
1085
 
1086
+ shouldCaptureCommentary() {
1087
+ return this.flowMode === "on" || this.continueTargets.some((target) => target.flowMode === "on");
1088
+ }
1089
+
1091
1090
  findContinuationTarget(targetSeatId) {
1092
- const normalizedTargetSeatId = normalizeContinueSeatId(targetSeatId);
1091
+ const normalizedTargetSeatId = normalizeSeatId(targetSeatId);
1093
1092
  if (!normalizedTargetSeatId) {
1094
1093
  return null;
1095
1094
  }
@@ -1141,7 +1140,8 @@ class ArmedSeat {
1141
1140
  return;
1142
1141
  }
1143
1142
 
1144
- if (!shouldAcceptInboundEntry(this.flowMode, entry)) {
1143
+ const inboundFlowMode = normalizeFlowMode(entry.flowMode || this.flowMode);
1144
+ if (!shouldAcceptInboundEntry(inboundFlowMode, entry)) {
1145
1145
  continue;
1146
1146
  }
1147
1147
 
@@ -1153,6 +1153,7 @@ class ArmedSeat {
1153
1153
  seatId: entry.seatId,
1154
1154
  origin: entry.origin || "unknown",
1155
1155
  phase: getRelayPhase(entry),
1156
+ flowMode: inboundFlowMode,
1156
1157
  createdAt: entry.createdAt,
1157
1158
  text: payload,
1158
1159
  });
@@ -1208,7 +1209,8 @@ class ArmedSeat {
1208
1209
  return;
1209
1210
  }
1210
1211
 
1211
- if (!shouldAcceptInboundEntry(this.flowMode, entry)) {
1212
+ const continueFlowMode = normalizeFlowMode(entry.flowMode || this.flowMode);
1213
+ if (!shouldAcceptInboundEntry(continueFlowMode, entry)) {
1212
1214
  continue;
1213
1215
  }
1214
1216
 
@@ -1420,12 +1422,13 @@ class ArmedSeat {
1420
1422
  }
1421
1423
 
1422
1424
  const answers = [];
1425
+ const captureCommentary = this.shouldCaptureCommentary();
1423
1426
  if (detectedAgent.type === "codex") {
1424
1427
  const result = readCodexAnswers(
1425
1428
  this.liveState.sessionFile,
1426
1429
  this.liveState.offset,
1427
1430
  this.liveState.captureSinceMs,
1428
- { flowMode: this.flowMode === "on" }
1431
+ { flowMode: captureCommentary }
1429
1432
  );
1430
1433
  this.liveState.offset = result.nextOffset;
1431
1434
  answers.push(...result.answers);
@@ -1434,7 +1437,7 @@ class ArmedSeat {
1434
1437
  this.liveState.sessionFile,
1435
1438
  this.liveState.offset,
1436
1439
  this.liveState.captureSinceMs,
1437
- { flowMode: this.flowMode === "on" }
1440
+ { flowMode: captureCommentary }
1438
1441
  );
1439
1442
  this.liveState.offset = result.nextOffset;
1440
1443
  answers.push(...result.answers);
@@ -1443,7 +1446,7 @@ class ArmedSeat {
1443
1446
  this.liveState.sessionFile,
1444
1447
  this.liveState.lastMessageId,
1445
1448
  this.liveState.captureSinceMs,
1446
- { flowMode: this.flowMode === "on" }
1449
+ { flowMode: captureCommentary }
1447
1450
  );
1448
1451
  this.liveState.lastMessageId = result.lastMessageId;
1449
1452
  this.liveState.offset = result.fileSize;
@@ -1501,6 +1504,7 @@ class ArmedSeat {
1501
1504
  seatId: this.seatId,
1502
1505
  origin: entry.origin || "unknown",
1503
1506
  phase: entry.phase || "final_answer",
1507
+ flowMode: this.flowMode,
1504
1508
  text: payload,
1505
1509
  createdAt: entry.createdAt || new Date().toISOString(),
1506
1510
  chainId: pendingInboundContext?.chainId || entry.chainId || entryId,
@@ -1520,20 +1524,23 @@ class ArmedSeat {
1520
1524
  }
1521
1525
 
1522
1526
  forwardContinuation(signedEntry) {
1523
- if (this.continueSeatIds.length === 0) {
1527
+ if (this.continueTargets.length === 0) {
1524
1528
  return;
1525
1529
  }
1526
1530
 
1527
- for (const continueSeatId of this.continueSeatIds) {
1528
- const target = this.findContinuationTarget(continueSeatId);
1531
+ for (const targetEntry of this.continueTargets) {
1532
+ const target = this.findContinuationTarget(targetEntry.targetSeatId);
1529
1533
  if (!target) {
1530
- this.log(`[${this.seatId}] continue ${continueSeatId} unavailable`);
1534
+ this.log(`[${this.seatId}] continue ${targetEntry.targetSeatId} unavailable`);
1531
1535
  continue;
1532
1536
  }
1533
1537
 
1534
- const continuationEntry = buildContinuationEntry(this.sessionName, target.seatId, signedEntry);
1538
+ const continuationEntry = buildContinuationEntry(this.sessionName, target.seatId, {
1539
+ ...signedEntry,
1540
+ flowMode: targetEntry.flowMode,
1541
+ });
1535
1542
  appendJsonl(target.paths.continuePath, continuationEntry);
1536
- this.log(`[${this.seatId} => ${target.seatId}] ${previewText(continuationEntry.text)}`);
1543
+ this.log(`[${this.seatId} => ${target.seatId} ${targetEntry.flowMode}] ${previewText(continuationEntry.text)}`);
1537
1544
  }
1538
1545
  }
1539
1546
 
@@ -1583,9 +1590,10 @@ class ArmedSeat {
1583
1590
  this.log(`${BRAND} seat ${this.seatId} armed for ${this.sessionName}.`);
1584
1591
  this.log("Use this shell normally. Codex, Claude, and Gemini relay automatically from their local session logs.");
1585
1592
  this.log(`Seat ${this.seatId} relay mode is flow ${this.flowMode}.`);
1586
- if (this.continueSeatIds.length > 0) {
1587
- const targetLabel = this.continueSeatIds.length === 1 ? "seat" : "seats";
1588
- this.log(`Seat ${this.seatId} continues to ${targetLabel} ${this.continueSeatIds.join(", ")}.`);
1593
+ if (this.continueTargets.length > 0) {
1594
+ this.log(
1595
+ `Seat ${this.seatId} continues to ${this.continueTargets.map((target) => `seat ${target.targetSeatId} (${target.flowMode})`).join(", ")}.`
1596
+ );
1589
1597
  }
1590
1598
  if (isAnchorSeat(this.seatId)) {
1591
1599
  this.log(`Seat ${this.seatId} generated the session key and is waiting for seat ${this.partnerSeatId} to sign it.`);
@@ -1684,19 +1692,20 @@ function buildSeatReport(sessionName, seatId) {
1684
1692
  return null;
1685
1693
  }
1686
1694
 
1687
- const continueSeatIds = normalizeContinueSeatIds(
1688
- resolveContinueSeatConfig(
1689
- status?.continueSeatIds ?? meta?.continueSeatIds,
1690
- status?.continueSeatId ?? meta?.continueSeatId
1691
- )
1692
- );
1693
-
1694
1695
  return {
1695
1696
  seatId,
1697
+ partnerSeatId: status?.partnerSeatId || meta?.partnerSeatId || getPartnerSeatId(seatId),
1696
1698
  state: wrapperLive ? status?.state || "running" : "orphaned_child",
1697
1699
  flowMode: status?.flowMode || meta?.flowMode || "off",
1698
- continueSeatId: continueSeatIds[0] || null,
1699
- continueSeatIds,
1700
+ continueSeatId: status?.continueSeatId || meta?.continueSeatId || null,
1701
+ continueTargets: normalizeContinueTargets(
1702
+ status?.continueTargets || meta?.continueTargets || (
1703
+ (status?.continueSeatId || meta?.continueSeatId)
1704
+ ? [{ targetSeatId: status?.continueSeatId || meta?.continueSeatId, flowMode: status?.flowMode || meta?.flowMode || "off" }]
1705
+ : []
1706
+ ),
1707
+ status?.flowMode || meta?.flowMode || "off"
1708
+ ),
1700
1709
  wrapperPid,
1701
1710
  childPid,
1702
1711
  wrapperLive,
package/src/util.js CHANGED
@@ -284,36 +284,27 @@ function usage() {
284
284
  return [
285
285
  `${BRAND} arms regular terminals in isolated odd/even pairs and relays assistant output between each pair.`,
286
286
  "",
287
- "Command List:",
287
+ "Usage:",
288
288
  " muuuuse",
289
- " Show this command list.",
290
- "",
291
- " muuuuse <seat>",
292
- " Arm a seat and keep its normal odd/even partner relay behavior.",
293
- "",
294
- " muuuuse <seat> flow on",
295
- " Relay commentary and final answers into that armed shell.",
296
- "",
297
- " muuuuse <seat> flow off",
298
- " Relay final answers only into that armed shell.",
299
- "",
300
- " muuuuse <seat> flow on continue <seat> [<seat> ...]",
301
- " Fan that seat's relayed output into one or more additional armed seats.",
302
- "",
303
- " muuuuse status",
304
- " Show all armed seats, flow mode, pair trust, and continuation targets.",
305
- "",
289
+ " muuuuse 1",
290
+ " muuuuse 1 link 2 flow on",
291
+ " muuuuse 1 link 2 flow on 3 flow off",
292
+ " muuuuse 2",
293
+ " muuuuse 2 link 1 flow on",
294
+ " muuuuse 3",
295
+ " muuuuse 4",
296
+ " muuuuse 4 link 3 flow off 1 flow on",
306
297
  " muuuuse stop",
307
- " Stop every armed seat in the current cwd.",
298
+ " muuuuse status",
308
299
  "",
309
300
  "Flow:",
310
301
  " 1. Run `muuuuse 1` in terminal one.",
311
302
  " 2. Run `muuuuse 2` in terminal two.",
312
303
  " 3. The odd seat generates the session key and the matching even seat signs it automatically.",
313
304
  " 4. Additional pairs work the same way: `3/4`, `5/6`, `7/8`...",
314
- " 5. Optional: arm each seat with `flow on` or `flow off`.",
315
- " 6. Optional: add `continue <seat> [<seat> ...]` to forward that seat's relayed output into more armed seats.",
316
- " 7. Use those armed shells normally.",
305
+ " 5. Use `link <seat> flow on [<seat> flow off ...]` to set each outbound path.",
306
+ " 6. Linking the odd/even partner sets the normal pair flow. Extra linked seats become continuations.",
307
+ " 7. Legacy `flow on` / `flow off` and `continue` still parse, but `link` is the main command shape.",
317
308
  " 8. `flow off` sends final answers only. `flow on` keeps assistant commentary bouncing.",
318
309
  " 9. Run `muuuuse status` or `muuuuse stop` from any shell.",
319
310
  "",