muuuuse 2.3.4 → 2.3.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 +2 -5
- package/package.json +1 -1
- package/src/cli.js +25 -35
- package/src/runtime.js +19 -66
- package/src/util.js +14 -21
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
|
|
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
|
|
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
package/src/cli.js
CHANGED
|
@@ -56,10 +56,9 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
56
56
|
|
|
57
57
|
const seatId = normalizeSeatId(command);
|
|
58
58
|
if (seatId) {
|
|
59
|
-
const { flowMode, continueSeatId
|
|
59
|
+
const { flowMode, continueSeatId } = parseSeatOptions(command, argv.slice(1));
|
|
60
60
|
const seat = new ArmedSeat({
|
|
61
61
|
cwd: process.cwd(),
|
|
62
|
-
continueSeatIds,
|
|
63
62
|
continueSeatId,
|
|
64
63
|
flowMode,
|
|
65
64
|
seatId,
|
|
@@ -84,11 +83,8 @@ function renderSeatStatus(seat) {
|
|
|
84
83
|
if (seat.partnerLive) {
|
|
85
84
|
bits.push("peer live");
|
|
86
85
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
: (seat.continueSeatId ? [seat.continueSeatId] : []);
|
|
90
|
-
if (continueSeatIds.length > 0) {
|
|
91
|
-
bits.push(`continue ${continueSeatIds.join(",")}`);
|
|
86
|
+
if (seat.continueSeatId) {
|
|
87
|
+
bits.push(`continue ${seat.continueSeatId}`);
|
|
92
88
|
}
|
|
93
89
|
if (seat.trust) {
|
|
94
90
|
bits.push(`trust ${seat.trust}`);
|
|
@@ -109,14 +105,12 @@ function renderSeatStatus(seat) {
|
|
|
109
105
|
|
|
110
106
|
function parseSeatOptions(command, args) {
|
|
111
107
|
let flowMode = "off";
|
|
112
|
-
|
|
113
|
-
let sawContinue = false;
|
|
114
|
-
let index = 0;
|
|
108
|
+
let continueSeatId = null;
|
|
115
109
|
|
|
116
|
-
|
|
110
|
+
for (let index = 0; index < args.length;) {
|
|
117
111
|
const token = String(args[index] || "").trim().toLowerCase();
|
|
118
112
|
|
|
119
|
-
if (token === "flow"
|
|
113
|
+
if (token === "flow") {
|
|
120
114
|
const flowToken = String(args[index + 1] || "").trim().toLowerCase();
|
|
121
115
|
if (flowToken === "on" || flowToken === "off") {
|
|
122
116
|
flowMode = flowToken;
|
|
@@ -127,22 +121,10 @@ function parseSeatOptions(command, args) {
|
|
|
127
121
|
}
|
|
128
122
|
|
|
129
123
|
if (token === "continue") {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
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) {
|
|
124
|
+
const targetSeatId = normalizeSeatId(args[index + 1]);
|
|
125
|
+
if (targetSeatId) {
|
|
126
|
+
continueSeatId = targetSeatId;
|
|
127
|
+
index += 2;
|
|
146
128
|
continue;
|
|
147
129
|
}
|
|
148
130
|
break;
|
|
@@ -151,19 +133,27 @@ function parseSeatOptions(command, args) {
|
|
|
151
133
|
break;
|
|
152
134
|
}
|
|
153
135
|
|
|
154
|
-
if (
|
|
155
|
-
return {
|
|
156
|
-
flowMode,
|
|
157
|
-
continueSeatId: continueSeatIds[0] || null,
|
|
158
|
-
continueSeatIds,
|
|
159
|
-
};
|
|
136
|
+
if (args.length === 0 || (flowMode || continueSeatId !== null) && consumedAllArgs(args, flowMode, continueSeatId)) {
|
|
137
|
+
return { flowMode, continueSeatId };
|
|
160
138
|
}
|
|
161
139
|
|
|
162
140
|
throw new Error(
|
|
163
|
-
`\`muuuuse ${command}\` accepts no extra arguments, \`flow on\` / \`flow off\`, optional \`continue <seat
|
|
141
|
+
`\`muuuuse ${command}\` accepts no extra arguments, \`flow on\` / \`flow off\`, optional \`continue <seat>\`, or both in sequence. Run it directly in the terminal you want to arm.`
|
|
164
142
|
);
|
|
165
143
|
}
|
|
166
144
|
|
|
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
|
+
|
|
167
157
|
module.exports = {
|
|
168
158
|
main,
|
|
169
159
|
};
|
package/src/runtime.js
CHANGED
|
@@ -91,36 +91,6 @@ 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
|
-
|
|
124
94
|
function resolveShell() {
|
|
125
95
|
const shell = String(process.env.SHELL || "").trim();
|
|
126
96
|
return shell || "/bin/bash";
|
|
@@ -629,7 +599,7 @@ async function sendTextAndEnter(child, text, shouldAbort = () => false) {
|
|
|
629
599
|
}
|
|
630
600
|
|
|
631
601
|
try {
|
|
632
|
-
child.write("\
|
|
602
|
+
child.write("\n");
|
|
633
603
|
} catch {
|
|
634
604
|
return false;
|
|
635
605
|
}
|
|
@@ -643,12 +613,9 @@ class ArmedSeat {
|
|
|
643
613
|
this.partnerSeatId = getPartnerSeatId(options.seatId);
|
|
644
614
|
this.anchorSeatId = isAnchorSeat(options.seatId) ? options.seatId : this.partnerSeatId;
|
|
645
615
|
this.flowMode = normalizeFlowMode(options.flowMode);
|
|
646
|
-
this.
|
|
647
|
-
resolveContinueSeatConfig(options.continueSeatIds, options.continueSeatId)
|
|
648
|
-
);
|
|
649
|
-
this.continueSeatId = this.continueSeatIds[0] || null;
|
|
616
|
+
this.continueSeatId = normalizeContinueSeatId(options.continueSeatId);
|
|
650
617
|
this.cwd = normalizeWorkingPath(options.cwd);
|
|
651
|
-
if (this.
|
|
618
|
+
if (this.continueSeatId === this.seatId) {
|
|
652
619
|
throw new Error(`\`muuuuse ${this.seatId}\` cannot continue to itself.`);
|
|
653
620
|
}
|
|
654
621
|
this.sessionName = resolveSessionName(this.cwd, this.seatId);
|
|
@@ -724,7 +691,6 @@ class ArmedSeat {
|
|
|
724
691
|
partnerSeatId: this.partnerSeatId,
|
|
725
692
|
sessionName: this.sessionName,
|
|
726
693
|
flowMode: this.flowMode,
|
|
727
|
-
continueSeatIds: this.continueSeatIds,
|
|
728
694
|
continueSeatId: this.continueSeatId,
|
|
729
695
|
cwd: this.cwd,
|
|
730
696
|
pid: process.pid,
|
|
@@ -741,7 +707,6 @@ class ArmedSeat {
|
|
|
741
707
|
partnerSeatId: this.partnerSeatId,
|
|
742
708
|
sessionName: this.sessionName,
|
|
743
709
|
flowMode: this.flowMode,
|
|
744
|
-
continueSeatIds: this.continueSeatIds,
|
|
745
710
|
continueSeatId: this.continueSeatId,
|
|
746
711
|
cwd: this.cwd,
|
|
747
712
|
pid: process.pid,
|
|
@@ -1088,19 +1053,18 @@ class ArmedSeat {
|
|
|
1088
1053
|
return Number.isFinite(requestedAtMs) && requestedAtMs > this.startedAtMs;
|
|
1089
1054
|
}
|
|
1090
1055
|
|
|
1091
|
-
findContinuationTarget(
|
|
1092
|
-
|
|
1093
|
-
if (!normalizedTargetSeatId) {
|
|
1056
|
+
findContinuationTarget() {
|
|
1057
|
+
if (!this.continueSeatId) {
|
|
1094
1058
|
return null;
|
|
1095
1059
|
}
|
|
1096
1060
|
|
|
1097
1061
|
const candidates = listSessionNames()
|
|
1098
1062
|
.map((sessionName) => {
|
|
1099
|
-
if (!getSeatDirIfExists(sessionName,
|
|
1063
|
+
if (!getSeatDirIfExists(sessionName, this.continueSeatId)) {
|
|
1100
1064
|
return null;
|
|
1101
1065
|
}
|
|
1102
1066
|
|
|
1103
|
-
const seat = buildSeatReport(sessionName,
|
|
1067
|
+
const seat = buildSeatReport(sessionName, this.continueSeatId);
|
|
1104
1068
|
if (!seat || !matchesWorkingPath(seat.cwd, this.cwd)) {
|
|
1105
1069
|
return null;
|
|
1106
1070
|
}
|
|
@@ -1520,21 +1484,19 @@ class ArmedSeat {
|
|
|
1520
1484
|
}
|
|
1521
1485
|
|
|
1522
1486
|
forwardContinuation(signedEntry) {
|
|
1523
|
-
if (this.
|
|
1487
|
+
if (!this.continueSeatId) {
|
|
1524
1488
|
return;
|
|
1525
1489
|
}
|
|
1526
1490
|
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
continue;
|
|
1532
|
-
}
|
|
1533
|
-
|
|
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)}`);
|
|
1491
|
+
const target = this.findContinuationTarget();
|
|
1492
|
+
if (!target) {
|
|
1493
|
+
this.log(`[${this.seatId}] continue ${this.continueSeatId} unavailable`);
|
|
1494
|
+
return;
|
|
1537
1495
|
}
|
|
1496
|
+
|
|
1497
|
+
const continuationEntry = buildContinuationEntry(this.sessionName, target.seatId, signedEntry);
|
|
1498
|
+
appendJsonl(target.paths.continuePath, continuationEntry);
|
|
1499
|
+
this.log(`[${this.seatId} => ${target.seatId}] ${previewText(continuationEntry.text)}`);
|
|
1538
1500
|
}
|
|
1539
1501
|
|
|
1540
1502
|
async tick() {
|
|
@@ -1583,9 +1545,8 @@ class ArmedSeat {
|
|
|
1583
1545
|
this.log(`${BRAND} seat ${this.seatId} armed for ${this.sessionName}.`);
|
|
1584
1546
|
this.log("Use this shell normally. Codex, Claude, and Gemini relay automatically from their local session logs.");
|
|
1585
1547
|
this.log(`Seat ${this.seatId} relay mode is flow ${this.flowMode}.`);
|
|
1586
|
-
if (this.
|
|
1587
|
-
|
|
1588
|
-
this.log(`Seat ${this.seatId} continues to ${targetLabel} ${this.continueSeatIds.join(", ")}.`);
|
|
1548
|
+
if (this.continueSeatId) {
|
|
1549
|
+
this.log(`Seat ${this.seatId} continues to seat ${this.continueSeatId}.`);
|
|
1589
1550
|
}
|
|
1590
1551
|
if (isAnchorSeat(this.seatId)) {
|
|
1591
1552
|
this.log(`Seat ${this.seatId} generated the session key and is waiting for seat ${this.partnerSeatId} to sign it.`);
|
|
@@ -1684,19 +1645,11 @@ function buildSeatReport(sessionName, seatId) {
|
|
|
1684
1645
|
return null;
|
|
1685
1646
|
}
|
|
1686
1647
|
|
|
1687
|
-
const continueSeatIds = normalizeContinueSeatIds(
|
|
1688
|
-
resolveContinueSeatConfig(
|
|
1689
|
-
status?.continueSeatIds ?? meta?.continueSeatIds,
|
|
1690
|
-
status?.continueSeatId ?? meta?.continueSeatId
|
|
1691
|
-
)
|
|
1692
|
-
);
|
|
1693
|
-
|
|
1694
1648
|
return {
|
|
1695
1649
|
seatId,
|
|
1696
1650
|
state: wrapperLive ? status?.state || "running" : "orphaned_child",
|
|
1697
1651
|
flowMode: status?.flowMode || meta?.flowMode || "off",
|
|
1698
|
-
continueSeatId:
|
|
1699
|
-
continueSeatIds,
|
|
1652
|
+
continueSeatId: status?.continueSeatId || meta?.continueSeatId || null,
|
|
1700
1653
|
wrapperPid,
|
|
1701
1654
|
childPid,
|
|
1702
1655
|
wrapperLive,
|
package/src/util.js
CHANGED
|
@@ -284,27 +284,20 @@ 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
|
-
"",
|
|
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
|
-
"",
|
|
287
|
+
"Usage:",
|
|
288
|
+
" muuuuse 1",
|
|
289
|
+
" muuuuse 1 flow on",
|
|
290
|
+
" muuuuse 1 flow off",
|
|
291
|
+
" muuuuse 1 flow on continue 3",
|
|
292
|
+
" muuuuse 2",
|
|
293
|
+
" muuuuse 2 flow on",
|
|
294
|
+
" muuuuse 2 flow off",
|
|
295
|
+
" muuuuse 2 flow on continue 3",
|
|
296
|
+
" muuuuse 3",
|
|
297
|
+
" muuuuse 4",
|
|
298
|
+
" muuuuse 4 flow on continue 1",
|
|
306
299
|
" muuuuse stop",
|
|
307
|
-
"
|
|
300
|
+
" muuuuse status",
|
|
308
301
|
"",
|
|
309
302
|
"Flow:",
|
|
310
303
|
" 1. Run `muuuuse 1` in terminal one.",
|
|
@@ -312,7 +305,7 @@ function usage() {
|
|
|
312
305
|
" 3. The odd seat generates the session key and the matching even seat signs it automatically.",
|
|
313
306
|
" 4. Additional pairs work the same way: `3/4`, `5/6`, `7/8`...",
|
|
314
307
|
" 5. Optional: arm each seat with `flow on` or `flow off`.",
|
|
315
|
-
" 6. Optional: add `continue <seat
|
|
308
|
+
" 6. Optional: add `continue <seat>` to forward that seat's relayed output into another armed seat.",
|
|
316
309
|
" 7. Use those armed shells normally.",
|
|
317
310
|
" 8. `flow off` sends final answers only. `flow on` keeps assistant commentary bouncing.",
|
|
318
311
|
" 9. Run `muuuuse status` or `muuuuse stop` from any shell.",
|