muuuuse 2.3.3 → 2.3.4
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 +5 -2
- package/package.json +1 -1
- package/src/cli.js +35 -25
- package/src/runtime.js +65 -18
- package/src/util.js +21 -14
package/README.md
CHANGED
|
@@ -15,13 +15,16 @@ It does one job:
|
|
|
15
15
|
The whole surface is:
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
|
+
muuuuse
|
|
18
19
|
muuuuse 1
|
|
19
20
|
muuuuse 1 flow on
|
|
20
21
|
muuuuse 1 flow off
|
|
21
22
|
muuuuse 1 flow off continue 5
|
|
23
|
+
muuuuse 1 flow on continue 3 5 6
|
|
22
24
|
muuuuse 2
|
|
23
25
|
muuuuse 2 flow off
|
|
24
26
|
muuuuse 2 flow on continue 3
|
|
27
|
+
muuuuse 2 flow on continue 3 5 6
|
|
25
28
|
muuuuse 3
|
|
26
29
|
muuuuse 3 flow on
|
|
27
30
|
muuuuse 4
|
|
@@ -48,7 +51,7 @@ Now both shells are armed. `muuuuse 1` generates the session key, `muuuuse 2` si
|
|
|
48
51
|
|
|
49
52
|
`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.
|
|
50
53
|
|
|
51
|
-
`continue <seat
|
|
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.
|
|
52
55
|
|
|
53
56
|
If you want Codex in one and Gemini in the other, start them inside the armed shells:
|
|
54
57
|
|
|
@@ -78,7 +81,7 @@ muuuuse stop
|
|
|
78
81
|
|
|
79
82
|
- state lives under `~/.muuuuse`
|
|
80
83
|
- only the signed armed pair can exchange relay events
|
|
81
|
-
- `continue <seat
|
|
84
|
+
- `continue <seat> [<seat> ...]` is a separate local forwarding lane and can target any armed seat numbers
|
|
82
85
|
- supported relay detection is built for Codex, Claude, and Gemini
|
|
83
86
|
|
|
84
87
|
## Install
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -56,9 +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 } = parseSeatOptions(command, argv.slice(1));
|
|
59
|
+
const { flowMode, continueSeatId, continueSeatIds } = parseSeatOptions(command, argv.slice(1));
|
|
60
60
|
const seat = new ArmedSeat({
|
|
61
61
|
cwd: process.cwd(),
|
|
62
|
+
continueSeatIds,
|
|
62
63
|
continueSeatId,
|
|
63
64
|
flowMode,
|
|
64
65
|
seatId,
|
|
@@ -83,8 +84,11 @@ function renderSeatStatus(seat) {
|
|
|
83
84
|
if (seat.partnerLive) {
|
|
84
85
|
bits.push("peer live");
|
|
85
86
|
}
|
|
86
|
-
|
|
87
|
-
|
|
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(",")}`);
|
|
88
92
|
}
|
|
89
93
|
if (seat.trust) {
|
|
90
94
|
bits.push(`trust ${seat.trust}`);
|
|
@@ -105,12 +109,14 @@ function renderSeatStatus(seat) {
|
|
|
105
109
|
|
|
106
110
|
function parseSeatOptions(command, args) {
|
|
107
111
|
let flowMode = "off";
|
|
108
|
-
|
|
112
|
+
const continueSeatIds = [];
|
|
113
|
+
let sawContinue = false;
|
|
114
|
+
let index = 0;
|
|
109
115
|
|
|
110
|
-
|
|
116
|
+
while (index < args.length) {
|
|
111
117
|
const token = String(args[index] || "").trim().toLowerCase();
|
|
112
118
|
|
|
113
|
-
if (token === "flow") {
|
|
119
|
+
if (token === "flow" && !sawContinue) {
|
|
114
120
|
const flowToken = String(args[index + 1] || "").trim().toLowerCase();
|
|
115
121
|
if (flowToken === "on" || flowToken === "off") {
|
|
116
122
|
flowMode = flowToken;
|
|
@@ -121,10 +127,22 @@ function parseSeatOptions(command, args) {
|
|
|
121
127
|
}
|
|
122
128
|
|
|
123
129
|
if (token === "continue") {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
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;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (consumedTargets > 0) {
|
|
128
146
|
continue;
|
|
129
147
|
}
|
|
130
148
|
break;
|
|
@@ -133,27 +151,19 @@ function parseSeatOptions(command, args) {
|
|
|
133
151
|
break;
|
|
134
152
|
}
|
|
135
153
|
|
|
136
|
-
if (
|
|
137
|
-
return {
|
|
154
|
+
if (index === args.length) {
|
|
155
|
+
return {
|
|
156
|
+
flowMode,
|
|
157
|
+
continueSeatId: continueSeatIds[0] || null,
|
|
158
|
+
continueSeatIds,
|
|
159
|
+
};
|
|
138
160
|
}
|
|
139
161
|
|
|
140
162
|
throw new Error(
|
|
141
|
-
`\`muuuuse ${command}\` accepts no extra arguments, \`flow on\` / \`flow off\`, optional \`continue <seat
|
|
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.`
|
|
142
164
|
);
|
|
143
165
|
}
|
|
144
166
|
|
|
145
|
-
function consumedAllArgs(args, flowMode, continueSeatId) {
|
|
146
|
-
const expected = [];
|
|
147
|
-
if (flowMode !== "off" || args.includes("flow")) {
|
|
148
|
-
expected.push("flow", flowMode);
|
|
149
|
-
}
|
|
150
|
-
if (continueSeatId !== null || args.includes("continue")) {
|
|
151
|
-
expected.push("continue", String(continueSeatId));
|
|
152
|
-
}
|
|
153
|
-
return expected.length === args.length &&
|
|
154
|
-
expected.every((value, index) => String(args[index]).trim().toLowerCase() === String(value).trim().toLowerCase());
|
|
155
|
-
}
|
|
156
|
-
|
|
157
167
|
module.exports = {
|
|
158
168
|
main,
|
|
159
169
|
};
|
package/src/runtime.js
CHANGED
|
@@ -91,6 +91,36 @@ function normalizeContinueSeatId(value) {
|
|
|
91
91
|
return seatId || null;
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
+
function normalizeContinueSeatIds(value) {
|
|
95
|
+
const values = Array.isArray(value) ? value : [value];
|
|
96
|
+
const seen = new Set();
|
|
97
|
+
const seatIds = [];
|
|
98
|
+
|
|
99
|
+
for (const entry of values) {
|
|
100
|
+
const seatId = normalizeContinueSeatId(entry);
|
|
101
|
+
if (!seatId || seen.has(seatId)) {
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
|
|
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;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return continueSeatId;
|
|
122
|
+
}
|
|
123
|
+
|
|
94
124
|
function resolveShell() {
|
|
95
125
|
const shell = String(process.env.SHELL || "").trim();
|
|
96
126
|
return shell || "/bin/bash";
|
|
@@ -613,9 +643,12 @@ class ArmedSeat {
|
|
|
613
643
|
this.partnerSeatId = getPartnerSeatId(options.seatId);
|
|
614
644
|
this.anchorSeatId = isAnchorSeat(options.seatId) ? options.seatId : this.partnerSeatId;
|
|
615
645
|
this.flowMode = normalizeFlowMode(options.flowMode);
|
|
616
|
-
this.
|
|
646
|
+
this.continueSeatIds = normalizeContinueSeatIds(
|
|
647
|
+
resolveContinueSeatConfig(options.continueSeatIds, options.continueSeatId)
|
|
648
|
+
);
|
|
649
|
+
this.continueSeatId = this.continueSeatIds[0] || null;
|
|
617
650
|
this.cwd = normalizeWorkingPath(options.cwd);
|
|
618
|
-
if (this.
|
|
651
|
+
if (this.continueSeatIds.includes(this.seatId)) {
|
|
619
652
|
throw new Error(`\`muuuuse ${this.seatId}\` cannot continue to itself.`);
|
|
620
653
|
}
|
|
621
654
|
this.sessionName = resolveSessionName(this.cwd, this.seatId);
|
|
@@ -691,6 +724,7 @@ class ArmedSeat {
|
|
|
691
724
|
partnerSeatId: this.partnerSeatId,
|
|
692
725
|
sessionName: this.sessionName,
|
|
693
726
|
flowMode: this.flowMode,
|
|
727
|
+
continueSeatIds: this.continueSeatIds,
|
|
694
728
|
continueSeatId: this.continueSeatId,
|
|
695
729
|
cwd: this.cwd,
|
|
696
730
|
pid: process.pid,
|
|
@@ -707,6 +741,7 @@ class ArmedSeat {
|
|
|
707
741
|
partnerSeatId: this.partnerSeatId,
|
|
708
742
|
sessionName: this.sessionName,
|
|
709
743
|
flowMode: this.flowMode,
|
|
744
|
+
continueSeatIds: this.continueSeatIds,
|
|
710
745
|
continueSeatId: this.continueSeatId,
|
|
711
746
|
cwd: this.cwd,
|
|
712
747
|
pid: process.pid,
|
|
@@ -1053,18 +1088,19 @@ class ArmedSeat {
|
|
|
1053
1088
|
return Number.isFinite(requestedAtMs) && requestedAtMs > this.startedAtMs;
|
|
1054
1089
|
}
|
|
1055
1090
|
|
|
1056
|
-
findContinuationTarget() {
|
|
1057
|
-
|
|
1091
|
+
findContinuationTarget(targetSeatId) {
|
|
1092
|
+
const normalizedTargetSeatId = normalizeContinueSeatId(targetSeatId);
|
|
1093
|
+
if (!normalizedTargetSeatId) {
|
|
1058
1094
|
return null;
|
|
1059
1095
|
}
|
|
1060
1096
|
|
|
1061
1097
|
const candidates = listSessionNames()
|
|
1062
1098
|
.map((sessionName) => {
|
|
1063
|
-
if (!getSeatDirIfExists(sessionName,
|
|
1099
|
+
if (!getSeatDirIfExists(sessionName, normalizedTargetSeatId)) {
|
|
1064
1100
|
return null;
|
|
1065
1101
|
}
|
|
1066
1102
|
|
|
1067
|
-
const seat = buildSeatReport(sessionName,
|
|
1103
|
+
const seat = buildSeatReport(sessionName, normalizedTargetSeatId);
|
|
1068
1104
|
if (!seat || !matchesWorkingPath(seat.cwd, this.cwd)) {
|
|
1069
1105
|
return null;
|
|
1070
1106
|
}
|
|
@@ -1484,19 +1520,21 @@ class ArmedSeat {
|
|
|
1484
1520
|
}
|
|
1485
1521
|
|
|
1486
1522
|
forwardContinuation(signedEntry) {
|
|
1487
|
-
if (
|
|
1523
|
+
if (this.continueSeatIds.length === 0) {
|
|
1488
1524
|
return;
|
|
1489
1525
|
}
|
|
1490
1526
|
|
|
1491
|
-
const
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1527
|
+
for (const continueSeatId of this.continueSeatIds) {
|
|
1528
|
+
const target = this.findContinuationTarget(continueSeatId);
|
|
1529
|
+
if (!target) {
|
|
1530
|
+
this.log(`[${this.seatId}] continue ${continueSeatId} unavailable`);
|
|
1531
|
+
continue;
|
|
1532
|
+
}
|
|
1496
1533
|
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1534
|
+
const continuationEntry = buildContinuationEntry(this.sessionName, target.seatId, signedEntry);
|
|
1535
|
+
appendJsonl(target.paths.continuePath, continuationEntry);
|
|
1536
|
+
this.log(`[${this.seatId} => ${target.seatId}] ${previewText(continuationEntry.text)}`);
|
|
1537
|
+
}
|
|
1500
1538
|
}
|
|
1501
1539
|
|
|
1502
1540
|
async tick() {
|
|
@@ -1545,8 +1583,9 @@ class ArmedSeat {
|
|
|
1545
1583
|
this.log(`${BRAND} seat ${this.seatId} armed for ${this.sessionName}.`);
|
|
1546
1584
|
this.log("Use this shell normally. Codex, Claude, and Gemini relay automatically from their local session logs.");
|
|
1547
1585
|
this.log(`Seat ${this.seatId} relay mode is flow ${this.flowMode}.`);
|
|
1548
|
-
if (this.
|
|
1549
|
-
|
|
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(", ")}.`);
|
|
1550
1589
|
}
|
|
1551
1590
|
if (isAnchorSeat(this.seatId)) {
|
|
1552
1591
|
this.log(`Seat ${this.seatId} generated the session key and is waiting for seat ${this.partnerSeatId} to sign it.`);
|
|
@@ -1645,11 +1684,19 @@ function buildSeatReport(sessionName, seatId) {
|
|
|
1645
1684
|
return null;
|
|
1646
1685
|
}
|
|
1647
1686
|
|
|
1687
|
+
const continueSeatIds = normalizeContinueSeatIds(
|
|
1688
|
+
resolveContinueSeatConfig(
|
|
1689
|
+
status?.continueSeatIds ?? meta?.continueSeatIds,
|
|
1690
|
+
status?.continueSeatId ?? meta?.continueSeatId
|
|
1691
|
+
)
|
|
1692
|
+
);
|
|
1693
|
+
|
|
1648
1694
|
return {
|
|
1649
1695
|
seatId,
|
|
1650
1696
|
state: wrapperLive ? status?.state || "running" : "orphaned_child",
|
|
1651
1697
|
flowMode: status?.flowMode || meta?.flowMode || "off",
|
|
1652
|
-
continueSeatId:
|
|
1698
|
+
continueSeatId: continueSeatIds[0] || null,
|
|
1699
|
+
continueSeatIds,
|
|
1653
1700
|
wrapperPid,
|
|
1654
1701
|
childPid,
|
|
1655
1702
|
wrapperLive,
|
package/src/util.js
CHANGED
|
@@ -284,20 +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
|
-
"
|
|
288
|
-
" muuuuse
|
|
289
|
-
"
|
|
290
|
-
"
|
|
291
|
-
" muuuuse
|
|
292
|
-
"
|
|
293
|
-
"
|
|
294
|
-
" muuuuse
|
|
295
|
-
"
|
|
296
|
-
"
|
|
297
|
-
" muuuuse
|
|
298
|
-
"
|
|
299
|
-
"
|
|
287
|
+
"Command List:",
|
|
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
|
+
"",
|
|
300
303
|
" muuuuse status",
|
|
304
|
+
" Show all armed seats, flow mode, pair trust, and continuation targets.",
|
|
305
|
+
"",
|
|
306
|
+
" muuuuse stop",
|
|
307
|
+
" Stop every armed seat in the current cwd.",
|
|
301
308
|
"",
|
|
302
309
|
"Flow:",
|
|
303
310
|
" 1. Run `muuuuse 1` in terminal one.",
|
|
@@ -305,7 +312,7 @@ function usage() {
|
|
|
305
312
|
" 3. The odd seat generates the session key and the matching even seat signs it automatically.",
|
|
306
313
|
" 4. Additional pairs work the same way: `3/4`, `5/6`, `7/8`...",
|
|
307
314
|
" 5. Optional: arm each seat with `flow on` or `flow off`.",
|
|
308
|
-
" 6. Optional: add `continue <seat
|
|
315
|
+
" 6. Optional: add `continue <seat> [<seat> ...]` to forward that seat's relayed output into more armed seats.",
|
|
309
316
|
" 7. Use those armed shells normally.",
|
|
310
317
|
" 8. `flow off` sends final answers only. `flow on` keeps assistant commentary bouncing.",
|
|
311
318
|
" 9. Run `muuuuse status` or `muuuuse stop` from any shell.",
|