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 CHANGED
@@ -1,105 +1,85 @@
1
1
  # 🔌Muuuuse
2
2
 
3
- `muuuuse` installs one CLI:
3
+ `🔌Muuuuse` is a dead-simple terminal relay.
4
4
 
5
- - `muuuuse`
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
- The public brand stays `🔌Muuuuse`. The terminal command stays `muuuuse`.
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 <program...>
17
- muuuuse 2 <program...>
14
+ muuuuse 1
15
+ muuuuse 2
18
16
  muuuuse stop
19
17
  ```
20
18
 
21
- Seat `1` and seat `2` each launch and own a real local program under a PTY wrapper. Once both seats are alive in the same lane, they automatically bounce final blocks between each other by typing the partner answer plus `Enter` into the wrapped program.
19
+ No tmux.
20
+ No program arguments.
21
+ No status command.
22
+ No doctor command.
23
+ No preset logic.
22
24
 
23
- `muuuuse stop` is the real cleanup command. With no flags it force-stops every tracked lane. Use `--session <name>` if you only want one explicit lane.
25
+ ## Flow
24
26
 
25
- ## Install
27
+ Shell 1:
26
28
 
27
29
  ```bash
28
- npm install -g muuuuse
30
+ muuuuse 1
29
31
  ```
30
32
 
31
- ## Fastest AI Flow
32
-
33
- Terminal 1:
33
+ Shell 2:
34
34
 
35
35
  ```bash
36
- muuuuse 1 codex
36
+ muuuuse 2
37
37
  ```
38
38
 
39
- Terminal 2:
39
+ Now both shells are armed. Use them normally.
40
40
 
41
- ```bash
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
- muuuuse stop
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
- muuuuse 1 bash -lc 'while read line; do printf "left: %s\n\n" "$line"; done'
67
- muuuuse 2 bash -lc 'while read line; do printf "right: %s\n\n" "$line"; done'
48
+ gemini
68
49
  ```
69
50
 
70
- Type into one seat and the other seat will receive the relayed block.
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
- Seats auto-pair by current working directory by default.
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
- If you want an explicit lane name, use:
55
+ Stop the whole loop from any other shell:
79
56
 
80
57
  ```bash
81
- muuuuse 1 --session demo codex
82
- muuuuse 2 --session demo gemini
83
- muuuuse stop --session demo
58
+ muuuuse stop
84
59
  ```
85
60
 
86
- You can also inspect the lane:
61
+ ## Install
87
62
 
88
63
  ```bash
89
- muuuuse status
64
+ npm install -g muuuuse
90
65
  ```
91
66
 
92
- ## Doctor
67
+ ## What Counts As A Relay
93
68
 
94
- ```bash
95
- muuuuse doctor
96
- ```
69
+ `🔌Muuuuse` watches the armed terminal output for BEL (`\u0007`).
70
+
71
+ That BEL marks the end of a turn.
97
72
 
98
- This checks the local runtime plus common agent binaries if you use them.
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
- - no tmux requirement for the main path
104
- - no remote control surface here; that belongs to `codeman`
105
- - best with programs that naturally produce turn-shaped output
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.3.2",
4
- "description": "🔌Muuuuse wraps two local programs and bounces final blocks between them from the terminal you launched.",
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
- BRAND,
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
- const { flags } = parseFlags(argv.slice(1));
32
- const result = await stopSessions(flags.session || null);
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
- if (flags.session) {
39
- process.stdout.write(`${BRAND} stop requested for session ${flags.session}.\n`);
40
- } else {
41
- process.stdout.write(`${BRAND} stop requested for all sessions.\n`);
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 === "status") {
57
- const { flags } = parseFlags(argv.slice(1));
58
- if (flags.session) {
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
- if (command === "1" || command === "2") {
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 runDoctor() {
113
- const checks = [
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
  };