muuuuse 1.3.2 → 1.4.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.
- package/README.md +42 -62
- package/package.json +2 -3
- package/src/cli.js +17 -135
- package/src/runtime.js +208 -419
- package/src/util.js +28 -127
- package/src/agents.js +0 -539
- package/src/tmux.js +0 -170
package/README.md
CHANGED
|
@@ -1,105 +1,85 @@
|
|
|
1
1
|
# 🔌Muuuuse
|
|
2
2
|
|
|
3
|
-
`
|
|
3
|
+
`🔌Muuuuse` is a dead-simple terminal relay.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
It does one thing:
|
|
6
|
+
- arm two raw terminals
|
|
7
|
+
- watch for the final BEL-marked message from whatever program is running inside them
|
|
8
|
+
- inject that final message into the other armed terminal
|
|
9
|
+
- keep bouncing forever until you stop it
|
|
6
10
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
## What It Is Now
|
|
10
|
-
|
|
11
|
-
`🔌Muuuuse` no longer expects you to arm a terminal first and launch something later.
|
|
12
|
-
|
|
13
|
-
The main flow is:
|
|
11
|
+
There are only three commands:
|
|
14
12
|
|
|
15
13
|
```bash
|
|
16
|
-
muuuuse 1
|
|
17
|
-
muuuuse 2
|
|
14
|
+
muuuuse 1
|
|
15
|
+
muuuuse 2
|
|
18
16
|
muuuuse stop
|
|
19
17
|
```
|
|
20
18
|
|
|
21
|
-
|
|
19
|
+
No tmux.
|
|
20
|
+
No program arguments.
|
|
21
|
+
No status command.
|
|
22
|
+
No doctor command.
|
|
23
|
+
No preset logic.
|
|
22
24
|
|
|
23
|
-
|
|
25
|
+
## Flow
|
|
24
26
|
|
|
25
|
-
|
|
27
|
+
Shell 1:
|
|
26
28
|
|
|
27
29
|
```bash
|
|
28
|
-
|
|
30
|
+
muuuuse 1
|
|
29
31
|
```
|
|
30
32
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
Terminal 1:
|
|
33
|
+
Shell 2:
|
|
34
34
|
|
|
35
35
|
```bash
|
|
36
|
-
muuuuse
|
|
36
|
+
muuuuse 2
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
Now both shells are armed. Use them normally.
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
muuuuse 2 gemini
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
Terminal 3:
|
|
41
|
+
If you want Codex in one and Gemini in the other, start them inside the armed shells:
|
|
46
42
|
|
|
47
43
|
```bash
|
|
48
|
-
|
|
44
|
+
codex
|
|
49
45
|
```
|
|
50
46
|
|
|
51
|
-
Known presets expand to recommended flags automatically:
|
|
52
|
-
|
|
53
|
-
- `codex`
|
|
54
|
-
- `claude`
|
|
55
|
-
- `gemini`
|
|
56
|
-
|
|
57
|
-
So `muuuuse 1 codex` launches the fuller Codex command, not just bare `codex`.
|
|
58
|
-
|
|
59
|
-
## Generic Program Flow
|
|
60
|
-
|
|
61
|
-
This is not AI-only. Any local program can be wrapped directly.
|
|
62
|
-
|
|
63
|
-
Example:
|
|
64
|
-
|
|
65
47
|
```bash
|
|
66
|
-
|
|
67
|
-
muuuuse 2 bash -lc 'while read line; do printf "right: %s\n\n" "$line"; done'
|
|
48
|
+
gemini
|
|
68
49
|
```
|
|
69
50
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
For Codex, Claude, and Gemini, `🔌Muuuuse` waits for their structured final-answer logs instead of relaying transient screen chatter. For anything else, it first looks for an explicit `(answer)` block and otherwise falls back to the last stable output block after a turn goes idle.
|
|
73
|
-
|
|
74
|
-
## Sessions
|
|
51
|
+
Or run any other program. `🔌Muuuuse` is program-agnostic.
|
|
75
52
|
|
|
76
|
-
|
|
53
|
+
When the running program rings the terminal bell, `🔌Muuuuse` takes the final output block for that turn and injects it into the partner seat.
|
|
77
54
|
|
|
78
|
-
|
|
55
|
+
Stop the whole loop from any other shell:
|
|
79
56
|
|
|
80
57
|
```bash
|
|
81
|
-
muuuuse
|
|
82
|
-
muuuuse 2 --session demo gemini
|
|
83
|
-
muuuuse stop --session demo
|
|
58
|
+
muuuuse stop
|
|
84
59
|
```
|
|
85
60
|
|
|
86
|
-
|
|
61
|
+
## Install
|
|
87
62
|
|
|
88
63
|
```bash
|
|
89
|
-
muuuuse
|
|
64
|
+
npm install -g muuuuse
|
|
90
65
|
```
|
|
91
66
|
|
|
92
|
-
##
|
|
67
|
+
## What Counts As A Relay
|
|
93
68
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
69
|
+
`🔌Muuuuse` watches the armed terminal output for BEL (`\u0007`).
|
|
70
|
+
|
|
71
|
+
That BEL marks the end of a turn.
|
|
97
72
|
|
|
98
|
-
|
|
73
|
+
When it sees BEL, it:
|
|
74
|
+
1. grabs the final output block since the last submitted input
|
|
75
|
+
2. cleans the block
|
|
76
|
+
3. appends it to the seat event log
|
|
77
|
+
4. injects it into the other armed terminal followed by Enter
|
|
99
78
|
|
|
100
79
|
## Notes
|
|
101
80
|
|
|
102
81
|
- local only
|
|
103
|
-
-
|
|
104
|
-
-
|
|
105
|
-
-
|
|
82
|
+
- seat pairing defaults by current working directory
|
|
83
|
+
- state lives under `~/.muuuuse`
|
|
84
|
+
- `codeman` remains the richer transport layer
|
|
85
|
+
- `🔌Muuuuse` is the tiny relay protocol
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "muuuuse",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "🔌Muuuuse
|
|
3
|
+
"version": "1.4.0",
|
|
4
|
+
"description": "🔌Muuuuse arms two raw terminals and bounces BEL-marked final output between them.",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"bin": {
|
|
7
7
|
"muuuuse": "bin/muuse.js"
|
|
@@ -34,7 +34,6 @@
|
|
|
34
34
|
"relay",
|
|
35
35
|
"local",
|
|
36
36
|
"automation",
|
|
37
|
-
"script",
|
|
38
37
|
"codex",
|
|
39
38
|
"claude",
|
|
40
39
|
"gemini"
|
package/src/cli.js
CHANGED
|
@@ -1,18 +1,5 @@
|
|
|
1
|
-
const {
|
|
2
|
-
|
|
3
|
-
commandExists,
|
|
4
|
-
parseFlags,
|
|
5
|
-
readCommandVersion,
|
|
6
|
-
usage,
|
|
7
|
-
} = require("./util");
|
|
8
|
-
const {
|
|
9
|
-
SeatProcess,
|
|
10
|
-
readAllSessionStatuses,
|
|
11
|
-
readSessionStatus,
|
|
12
|
-
resolveProgramTokens,
|
|
13
|
-
resolveSessionName,
|
|
14
|
-
stopSessions,
|
|
15
|
-
} = require("./runtime");
|
|
1
|
+
const { BRAND, usage } = require("./util");
|
|
2
|
+
const { ArmedSeat, stopAllSessions } = require("./runtime");
|
|
16
3
|
|
|
17
4
|
async function main(argv = process.argv.slice(2)) {
|
|
18
5
|
if (argv.length === 0 || argv.includes("--help") || argv.includes("-h")) {
|
|
@@ -20,154 +7,49 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
20
7
|
return;
|
|
21
8
|
}
|
|
22
9
|
|
|
23
|
-
const command = argv[0];
|
|
24
|
-
|
|
25
|
-
if (command === "doctor") {
|
|
26
|
-
runDoctor();
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
10
|
+
const command = String(argv[0] || "").trim().toLowerCase();
|
|
29
11
|
|
|
30
12
|
if (command === "stop") {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
if (result.sessions.length === 0) {
|
|
34
|
-
process.stdout.write(`${BRAND} no live sessions found.\n`);
|
|
35
|
-
return;
|
|
13
|
+
if (argv.length > 1) {
|
|
14
|
+
throw new Error("`muuuuse stop` takes no extra arguments.");
|
|
36
15
|
}
|
|
37
16
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
17
|
+
const result = stopAllSessions();
|
|
18
|
+
if (result.sessions.length === 0) {
|
|
19
|
+
process.stdout.write(`${BRAND} no armed seats found.\n`);
|
|
20
|
+
return;
|
|
42
21
|
}
|
|
43
22
|
|
|
23
|
+
process.stdout.write(`${BRAND} stop requested.\n`);
|
|
44
24
|
for (const session of result.sessions) {
|
|
45
25
|
process.stdout.write(`${session.sessionName}\n`);
|
|
46
26
|
for (const seat of session.seats) {
|
|
47
|
-
process.stdout.write(
|
|
48
|
-
`seat ${seat.seatId}: wrapper ${describeStopResult(seat.wrapperStopped, seat.wrapperForced)}`
|
|
49
|
-
+ `, child ${describeStopResult(seat.childStopped, seat.childForced)}\n`
|
|
50
|
-
);
|
|
27
|
+
process.stdout.write(`seat ${seat.seatId}: wrapper ${describeStopResult(seat.wrapperStopped)} · child ${describeStopResult(seat.childStopped)}\n`);
|
|
51
28
|
}
|
|
52
29
|
}
|
|
53
30
|
return;
|
|
54
31
|
}
|
|
55
32
|
|
|
56
|
-
if (command === "
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
printSessionStatus(readSessionStatus(flags.session));
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const sessions = readAllSessionStatuses();
|
|
64
|
-
if (sessions.length === 0) {
|
|
65
|
-
process.stdout.write(`${BRAND} no tracked sessions.\n`);
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
for (const session of sessions) {
|
|
70
|
-
printSessionStatus(session);
|
|
33
|
+
if (command === "1" || command === "2") {
|
|
34
|
+
if (argv.length > 1) {
|
|
35
|
+
throw new Error(`\`muuuuse ${command}\` no longer takes a program. It arms this terminal raw.`);
|
|
71
36
|
}
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
37
|
|
|
75
|
-
|
|
76
|
-
const { positionals, flags } = parseFlags(argv.slice(1));
|
|
77
|
-
const sessionName = resolveSessionName(flags.session, process.cwd());
|
|
78
|
-
const commandTokens = resolveProgramTokens(positionals, !flags.noPreset);
|
|
79
|
-
const seat = new SeatProcess({
|
|
80
|
-
commandTokens,
|
|
38
|
+
const seat = new ArmedSeat({
|
|
81
39
|
cwd: process.cwd(),
|
|
82
|
-
maxRelays: flags.maxRelays,
|
|
83
40
|
seatId: Number(command),
|
|
84
|
-
sessionName,
|
|
85
41
|
});
|
|
86
42
|
const code = await seat.run();
|
|
87
43
|
process.exit(code);
|
|
88
44
|
}
|
|
89
45
|
|
|
90
|
-
if (command === "3") {
|
|
91
|
-
const { positionals, flags } = parseFlags(argv.slice(1));
|
|
92
|
-
const action = String(positionals[0] || "status").toLowerCase();
|
|
93
|
-
|
|
94
|
-
if (action === "stop") {
|
|
95
|
-
const forwarded = ["stop", ...argv.slice(1).filter((token) => token !== "stop")];
|
|
96
|
-
await main(forwarded);
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (action === "status") {
|
|
101
|
-
const forwarded = ["status", ...argv.slice(1).filter((token) => token !== "status")];
|
|
102
|
-
await main(forwarded);
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
throw new Error(`Unknown seat 3 action '${action}'. Try \`muuuuse stop\` or \`muuuuse status\`.`);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
46
|
throw new Error(`Unknown command '${command}'.`);
|
|
110
47
|
}
|
|
111
48
|
|
|
112
|
-
function
|
|
113
|
-
|
|
114
|
-
checkBinary("node", ["--version"], true),
|
|
115
|
-
checkBinary("npm", ["--version"], true),
|
|
116
|
-
checkBinary("codex", ["--version"], false),
|
|
117
|
-
checkBinary("claude", ["--version"], false),
|
|
118
|
-
checkBinary("gemini", ["--version"], false),
|
|
119
|
-
];
|
|
120
|
-
|
|
121
|
-
process.stdout.write(`${BRAND} doctor\n\n`);
|
|
122
|
-
for (const item of checks) {
|
|
123
|
-
process.stdout.write(`${item.ok ? "OK " : "MISS"} ${item.label}${item.detail ? `: ${item.detail}` : ""}\n`);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
process.stdout.write("\nKnown presets\n");
|
|
127
|
-
process.stdout.write("- codex\n");
|
|
128
|
-
process.stdout.write("- claude\n");
|
|
129
|
-
process.stdout.write("- gemini\n");
|
|
130
|
-
process.stdout.write("\nAny other local program can be wrapped directly with `muuuuse 1 <program...>` or `muuuuse 2 <program...>`.\n");
|
|
131
|
-
|
|
132
|
-
const missingRequired = checks.some((item) => item.required && !item.ok);
|
|
133
|
-
if (missingRequired) {
|
|
134
|
-
process.exitCode = 1;
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
function checkBinary(command, versionArgs, required) {
|
|
139
|
-
if (!commandExists(command)) {
|
|
140
|
-
return { label: command, ok: false, detail: "not installed", required };
|
|
141
|
-
}
|
|
142
|
-
const version = readCommandVersion(command, versionArgs) || "installed";
|
|
143
|
-
return { label: command, ok: true, detail: version, required };
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
function describeStopResult(signaled, forced) {
|
|
147
|
-
if (forced) {
|
|
148
|
-
return "killed";
|
|
149
|
-
}
|
|
150
|
-
if (signaled) {
|
|
151
|
-
return "signaled";
|
|
152
|
-
}
|
|
153
|
-
return "idle";
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
function printSessionStatus(status) {
|
|
157
|
-
process.stdout.write(`${BRAND} session ${status.sessionName}\n`);
|
|
158
|
-
for (const seat of status.seats) {
|
|
159
|
-
if (!seat.status) {
|
|
160
|
-
process.stdout.write(`seat ${seat.seatId}: idle\n`);
|
|
161
|
-
continue;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
const state = seat.status.state || "unknown";
|
|
165
|
-
const program = Array.isArray(seat.status.command) ? seat.status.command.join(" ") : "";
|
|
166
|
-
process.stdout.write(`seat ${seat.seatId}: ${state}${program ? ` (${program})` : ""}\n`);
|
|
167
|
-
}
|
|
49
|
+
function describeStopResult(signaled) {
|
|
50
|
+
return signaled ? "signaled" : "idle";
|
|
168
51
|
}
|
|
169
52
|
|
|
170
53
|
module.exports = {
|
|
171
54
|
main,
|
|
172
|
-
runDoctor,
|
|
173
55
|
};
|