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/src/util.js
CHANGED
|
@@ -2,25 +2,11 @@ const { createHash, randomBytes } = require("node:crypto");
|
|
|
2
2
|
const fs = require("node:fs");
|
|
3
3
|
const os = require("node:os");
|
|
4
4
|
const path = require("node:path");
|
|
5
|
-
const { spawnSync } = require("node:child_process");
|
|
6
5
|
|
|
7
6
|
const BRAND = "🔌Muuuuse";
|
|
8
|
-
const POLL_MS =
|
|
9
|
-
const SESSION_MATCH_WINDOW_MS = 5 * 60 * 1000;
|
|
7
|
+
const POLL_MS = 220;
|
|
10
8
|
const MAX_RELAY_CHARS = 4000;
|
|
11
9
|
|
|
12
|
-
const FLAG_ALIASES = new Map([
|
|
13
|
-
["--max-relays", "maxRelays"],
|
|
14
|
-
["--no-preset", "noPreset"],
|
|
15
|
-
["--session", "session"],
|
|
16
|
-
]);
|
|
17
|
-
|
|
18
|
-
const BOOLEAN_FLAGS = new Set(["noPreset"]);
|
|
19
|
-
|
|
20
|
-
function shellEscape(value) {
|
|
21
|
-
return `'${String(value).replace(/'/g, `'\\''`)}'`;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
10
|
function createId(length = 10) {
|
|
25
11
|
return randomBytes(Math.ceil(length / 2)).toString("hex").slice(0, length);
|
|
26
12
|
}
|
|
@@ -34,12 +20,6 @@ function ensureDir(dirPath) {
|
|
|
34
20
|
return dirPath;
|
|
35
21
|
}
|
|
36
22
|
|
|
37
|
-
function resetDir(dirPath) {
|
|
38
|
-
fs.rmSync(dirPath, { recursive: true, force: true });
|
|
39
|
-
fs.mkdirSync(dirPath, { recursive: true });
|
|
40
|
-
return dirPath;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
23
|
function writeJson(filePath, value) {
|
|
44
24
|
ensureDir(path.dirname(filePath));
|
|
45
25
|
const tempPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
|
|
@@ -50,7 +30,7 @@ function writeJson(filePath, value) {
|
|
|
50
30
|
function readJson(filePath, fallback = null) {
|
|
51
31
|
try {
|
|
52
32
|
return JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
53
|
-
} catch
|
|
33
|
+
} catch {
|
|
54
34
|
return fallback;
|
|
55
35
|
}
|
|
56
36
|
}
|
|
@@ -65,10 +45,7 @@ function readAppendedText(filePath, previousOffset = 0) {
|
|
|
65
45
|
const stats = fs.statSync(filePath);
|
|
66
46
|
const startOffset = stats.size < previousOffset ? 0 : previousOffset;
|
|
67
47
|
if (stats.size === startOffset) {
|
|
68
|
-
return {
|
|
69
|
-
nextOffset: startOffset,
|
|
70
|
-
text: "",
|
|
71
|
-
};
|
|
48
|
+
return { nextOffset: startOffset, text: "" };
|
|
72
49
|
}
|
|
73
50
|
|
|
74
51
|
const fd = fs.openSync(filePath, "r");
|
|
@@ -85,10 +62,7 @@ function readAppendedText(filePath, previousOffset = 0) {
|
|
|
85
62
|
}
|
|
86
63
|
} catch (error) {
|
|
87
64
|
if (error && error.code === "ENOENT") {
|
|
88
|
-
return {
|
|
89
|
-
nextOffset: 0,
|
|
90
|
-
text: "",
|
|
91
|
-
};
|
|
65
|
+
return { nextOffset: 0, text: "" };
|
|
92
66
|
}
|
|
93
67
|
throw error;
|
|
94
68
|
}
|
|
@@ -97,29 +71,11 @@ function readAppendedText(filePath, previousOffset = 0) {
|
|
|
97
71
|
function getFileSize(filePath) {
|
|
98
72
|
try {
|
|
99
73
|
return fs.statSync(filePath).size;
|
|
100
|
-
} catch
|
|
74
|
+
} catch {
|
|
101
75
|
return 0;
|
|
102
76
|
}
|
|
103
77
|
}
|
|
104
78
|
|
|
105
|
-
function commandExists(command) {
|
|
106
|
-
const result = spawnSync("bash", ["-lc", `command -v ${shellEscape(command)} >/dev/null 2>&1`], {
|
|
107
|
-
encoding: "utf8",
|
|
108
|
-
});
|
|
109
|
-
return result.status === 0;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
function readCommandVersion(command, args = ["--version"]) {
|
|
113
|
-
const result = spawnSync(command, args, {
|
|
114
|
-
encoding: "utf8",
|
|
115
|
-
timeout: 4000,
|
|
116
|
-
});
|
|
117
|
-
if (result.status !== 0) {
|
|
118
|
-
return null;
|
|
119
|
-
}
|
|
120
|
-
return (result.stdout || result.stderr || "").trim().split("\n")[0] || null;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
79
|
function stripAnsi(text) {
|
|
124
80
|
return String(text || "").replace(
|
|
125
81
|
// eslint-disable-next-line no-control-regex
|
|
@@ -132,6 +88,7 @@ function sanitizeRelayText(input, maxChars = MAX_RELAY_CHARS) {
|
|
|
132
88
|
const normalized = stripAnsi(input)
|
|
133
89
|
.replace(/\r/g, "")
|
|
134
90
|
.replace(/\u0000/g, "")
|
|
91
|
+
.replace(/\u0007/g, "")
|
|
135
92
|
.replace(/\n{3,}/g, "\n\n")
|
|
136
93
|
.trim();
|
|
137
94
|
|
|
@@ -142,11 +99,6 @@ function sanitizeRelayText(input, maxChars = MAX_RELAY_CHARS) {
|
|
|
142
99
|
return `${normalized.slice(0, maxChars - 3).trimEnd()}...`;
|
|
143
100
|
}
|
|
144
101
|
|
|
145
|
-
function toInt(value, fallback) {
|
|
146
|
-
const parsed = Number.parseInt(String(value), 10);
|
|
147
|
-
return Number.isFinite(parsed) ? parsed : fallback;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
102
|
function isPidAlive(pid) {
|
|
151
103
|
if (!Number.isInteger(pid) || pid <= 0) {
|
|
152
104
|
return false;
|
|
@@ -155,7 +107,7 @@ function isPidAlive(pid) {
|
|
|
155
107
|
try {
|
|
156
108
|
process.kill(pid, 0);
|
|
157
109
|
return true;
|
|
158
|
-
} catch
|
|
110
|
+
} catch {
|
|
159
111
|
return false;
|
|
160
112
|
}
|
|
161
113
|
}
|
|
@@ -179,7 +131,7 @@ function getDefaultSessionName(currentPath = process.cwd()) {
|
|
|
179
131
|
const resolvedPath = (() => {
|
|
180
132
|
try {
|
|
181
133
|
return fs.realpathSync(currentPath);
|
|
182
|
-
} catch
|
|
134
|
+
} catch {
|
|
183
135
|
return path.resolve(currentPath);
|
|
184
136
|
}
|
|
185
137
|
})();
|
|
@@ -202,109 +154,58 @@ function getSeatPaths(sessionName, seatId) {
|
|
|
202
154
|
dir,
|
|
203
155
|
eventsPath: path.join(dir, "events.jsonl"),
|
|
204
156
|
metaPath: path.join(dir, "meta.json"),
|
|
157
|
+
pipePath: path.join(dir, "pipe.log"),
|
|
205
158
|
statusPath: path.join(dir, "status.json"),
|
|
206
159
|
};
|
|
207
160
|
}
|
|
208
161
|
|
|
209
|
-
function
|
|
210
|
-
const
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
const token = argv[index];
|
|
219
|
-
if (!token.startsWith("--")) {
|
|
220
|
-
positionals.push(token);
|
|
221
|
-
continue;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
const [rawFlag, inlineValue] = token.split("=", 2);
|
|
225
|
-
const key = FLAG_ALIASES.get(rawFlag);
|
|
226
|
-
if (!key) {
|
|
227
|
-
throw new Error(`Unknown flag: ${rawFlag}`);
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
if (BOOLEAN_FLAGS.has(key)) {
|
|
231
|
-
flags[key] = true;
|
|
232
|
-
continue;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
const next = inlineValue !== undefined ? inlineValue : argv[index + 1];
|
|
236
|
-
if (inlineValue === undefined) {
|
|
237
|
-
index += 1;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
if (next === undefined) {
|
|
241
|
-
throw new Error(`Missing value for ${rawFlag}`);
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
flags[key] = next;
|
|
162
|
+
function listSessionNames() {
|
|
163
|
+
const sessionsRoot = path.join(getStateRoot(), "sessions");
|
|
164
|
+
try {
|
|
165
|
+
return fs.readdirSync(sessionsRoot, { withFileTypes: true })
|
|
166
|
+
.filter((entry) => entry.isDirectory())
|
|
167
|
+
.map((entry) => entry.name)
|
|
168
|
+
.sort();
|
|
169
|
+
} catch {
|
|
170
|
+
return [];
|
|
245
171
|
}
|
|
246
|
-
|
|
247
|
-
flags.maxRelays = flags.maxRelays === Number.POSITIVE_INFINITY
|
|
248
|
-
? Number.POSITIVE_INFINITY
|
|
249
|
-
: toInt(flags.maxRelays, Number.POSITIVE_INFINITY);
|
|
250
|
-
|
|
251
|
-
return {
|
|
252
|
-
positionals,
|
|
253
|
-
flags,
|
|
254
|
-
};
|
|
255
172
|
}
|
|
256
173
|
|
|
257
174
|
function usage() {
|
|
258
175
|
return [
|
|
259
|
-
`${BRAND}
|
|
176
|
+
`${BRAND} arms two raw terminals and bounces BEL-marked final output between them.`,
|
|
260
177
|
"",
|
|
261
178
|
"Usage:",
|
|
262
|
-
" muuuuse 1
|
|
263
|
-
" muuuuse 2
|
|
264
|
-
" muuuuse stop",
|
|
265
|
-
" muuuuse status",
|
|
266
|
-
" muuuuse doctor",
|
|
267
|
-
"",
|
|
268
|
-
"Examples:",
|
|
269
|
-
" muuuuse 1 codex",
|
|
270
|
-
" muuuuse 2 gemini",
|
|
179
|
+
" muuuuse 1",
|
|
180
|
+
" muuuuse 2",
|
|
271
181
|
" muuuuse stop",
|
|
272
|
-
" muuuuse 1 bash -lc 'while read line; do printf \"script one: %s\\n\\n\" \"$line\"; done'",
|
|
273
182
|
"",
|
|
274
|
-
"
|
|
275
|
-
"
|
|
276
|
-
"
|
|
277
|
-
"
|
|
278
|
-
"
|
|
183
|
+
"Flow:",
|
|
184
|
+
" 1. Run `muuuuse 1` in terminal one.",
|
|
185
|
+
" 2. Run `muuuuse 2` in terminal two.",
|
|
186
|
+
" 3. Use those armed shells normally.",
|
|
187
|
+
" 4. When a program rings the terminal bell, that final block relays to the other seat.",
|
|
188
|
+
" 5. Run `muuuuse stop` from any other shell to stop every armed seat.",
|
|
279
189
|
].join("\n");
|
|
280
190
|
}
|
|
281
191
|
|
|
282
192
|
module.exports = {
|
|
283
193
|
BRAND,
|
|
284
|
-
MAX_RELAY_CHARS,
|
|
285
194
|
POLL_MS,
|
|
286
|
-
SESSION_MATCH_WINDOW_MS,
|
|
287
195
|
appendJsonl,
|
|
288
|
-
commandExists,
|
|
289
196
|
createId,
|
|
290
197
|
ensureDir,
|
|
291
198
|
getDefaultSessionName,
|
|
292
199
|
getFileSize,
|
|
293
|
-
getSeatDir,
|
|
294
200
|
getSeatPaths,
|
|
295
|
-
getSessionDir,
|
|
296
201
|
getStateRoot,
|
|
297
202
|
hashText,
|
|
298
203
|
isPidAlive,
|
|
299
|
-
|
|
204
|
+
listSessionNames,
|
|
300
205
|
readAppendedText,
|
|
301
|
-
readCommandVersion,
|
|
302
206
|
readJson,
|
|
303
|
-
resetDir,
|
|
304
207
|
sanitizeRelayText,
|
|
305
|
-
shellEscape,
|
|
306
208
|
sleep,
|
|
307
|
-
toInt,
|
|
308
209
|
usage,
|
|
309
210
|
writeJson,
|
|
310
211
|
};
|