muuuuse 4.0.0 → 5.0.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/package.json +2 -2
- package/src/agents.js +38 -0
- package/src/cli.js +7 -22
- package/src/runtime.js +18 -11
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "muuuuse",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "🔌Muuuuse arms
|
|
3
|
+
"version": "5.0.0",
|
|
4
|
+
"description": "🔌Muuuuse arms terminals with flexible routing to any targets - pure message relay graph.",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"bin": {
|
|
7
7
|
"muuuuse": "bin/muuse.js"
|
package/src/agents.js
CHANGED
|
@@ -69,6 +69,44 @@ function detectAgent(processes) {
|
|
|
69
69
|
return buildDetectedAgent("gemini", process);
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
|
+
|
|
73
|
+
// Fallback: if no agent process found, check for Claude Code running in a separate terminal
|
|
74
|
+
// (Claude Code's session updates even if it's not a child process of this shell)
|
|
75
|
+
if (processes.length > 0) {
|
|
76
|
+
// Use the bash/shell process as reference for timing
|
|
77
|
+
const shellProcess = processes[0];
|
|
78
|
+
const now = Date.now();
|
|
79
|
+
const recentThreshold = now - 2 * 60 * 1000; // Last 2 minutes
|
|
80
|
+
|
|
81
|
+
const CLAUDE_ROOT = path.join(os.homedir(), ".claude", "projects");
|
|
82
|
+
if (fs.existsSync(CLAUDE_ROOT)) {
|
|
83
|
+
try {
|
|
84
|
+
const sessionFiles = walkFiles(CLAUDE_ROOT, (f) => f.endsWith(".jsonl"))
|
|
85
|
+
.map(filePath => {
|
|
86
|
+
try {
|
|
87
|
+
const stat = fs.statSync(filePath);
|
|
88
|
+
return { filePath, mtimeMs: stat.mtimeMs };
|
|
89
|
+
} catch {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
})
|
|
93
|
+
.filter(e => e && e.mtimeMs > recentThreshold)
|
|
94
|
+
.sort((a, b) => b.mtimeMs - a.mtimeMs)[0];
|
|
95
|
+
|
|
96
|
+
if (sessionFiles) {
|
|
97
|
+
return {
|
|
98
|
+
type: "claude",
|
|
99
|
+
pid: process.pid || shellProcess.pid,
|
|
100
|
+
args: "claude-code-terminal-session",
|
|
101
|
+
cwd: shellProcess.cwd || null,
|
|
102
|
+
elapsedSeconds: Math.round((Date.now() - shellProcess.startedAtMs) / 1000),
|
|
103
|
+
processStartedAtMs: Date.now() - (shellProcess.elapsedSeconds ?? 0) * 1000,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
} catch {}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
72
110
|
return null;
|
|
73
111
|
}
|
|
74
112
|
|
package/src/cli.js
CHANGED
|
@@ -105,16 +105,7 @@ function renderSeatStatus(seat) {
|
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
function renderLinkTargets(seat) {
|
|
108
|
-
const targets = [];
|
|
109
|
-
if (seat.partnerSeatId) {
|
|
110
|
-
targets.push({
|
|
111
|
-
targetSeatId: seat.partnerSeatId,
|
|
112
|
-
flowMode: seat.flowMode || "off",
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
for (const target of Array.isArray(seat.continueTargets) ? seat.continueTargets : []) {
|
|
116
|
-
targets.push(target);
|
|
117
|
-
}
|
|
108
|
+
const targets = Array.isArray(seat.continueTargets) ? seat.continueTargets : [];
|
|
118
109
|
if (targets.length === 0) {
|
|
119
110
|
return "";
|
|
120
111
|
}
|
|
@@ -165,9 +156,7 @@ function parseSeatOptions(command, args) {
|
|
|
165
156
|
}
|
|
166
157
|
|
|
167
158
|
function parseLinkTargets(args, seatId, defaultFlowMode) {
|
|
168
|
-
const
|
|
169
|
-
const continueTargets = [];
|
|
170
|
-
let flowMode = defaultFlowMode;
|
|
159
|
+
const targets = [];
|
|
171
160
|
let consumed = 0;
|
|
172
161
|
|
|
173
162
|
while (consumed < args.length) {
|
|
@@ -181,19 +170,15 @@ function parseLinkTargets(args, seatId, defaultFlowMode) {
|
|
|
181
170
|
break;
|
|
182
171
|
}
|
|
183
172
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
targetSeatId,
|
|
189
|
-
flowMode: targetFlowMode,
|
|
190
|
-
});
|
|
191
|
-
}
|
|
173
|
+
upsertTarget(targets, {
|
|
174
|
+
targetSeatId,
|
|
175
|
+
flowMode: targetFlowMode,
|
|
176
|
+
});
|
|
192
177
|
|
|
193
178
|
consumed += 3;
|
|
194
179
|
}
|
|
195
180
|
|
|
196
|
-
return { consumed, continueTargets, flowMode };
|
|
181
|
+
return { consumed, continueTargets: targets, flowMode: defaultFlowMode };
|
|
197
182
|
}
|
|
198
183
|
|
|
199
184
|
function parseFlowModeToken(flowToken, modeToken) {
|
package/src/runtime.js
CHANGED
|
@@ -222,7 +222,12 @@ function findJoinableSessionName(currentPath = process.cwd(), seatId = 2) {
|
|
|
222
222
|
const stopRequestedAtMs = Date.parse(stopRequest?.requestedAt || "");
|
|
223
223
|
const createdAtMs = Date.parse(controller?.createdAt || anchorMeta?.startedAt || anchorStatus?.updatedAt || "");
|
|
224
224
|
|
|
225
|
-
if (
|
|
225
|
+
// Accept session if: controller exists AND (anchor is live OR anchor has written meta/status files).
|
|
226
|
+
// This handles the startup race: anchor might not have a live PID yet, but if it wrote files, it's initialized.
|
|
227
|
+
const controllerExists = controller !== null;
|
|
228
|
+
const anchorInitialized = anchorMeta !== null || anchorStatus !== null;
|
|
229
|
+
const anchorReady = anchorLive || anchorInitialized;
|
|
230
|
+
if (!controllerExists || !anchorReady || seatLive) {
|
|
226
231
|
return null;
|
|
227
232
|
}
|
|
228
233
|
|
|
@@ -1523,18 +1528,13 @@ class ArmedSeat {
|
|
|
1523
1528
|
this.identity.privateKey
|
|
1524
1529
|
);
|
|
1525
1530
|
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
if (shouldAcceptInboundEntry(this.flowMode, signedEntry)) {
|
|
1529
|
-
appendJsonl(this.paths.eventsPath, signedEntry);
|
|
1530
|
-
this.log(`[${this.seatId}] ${previewText(payload)}`);
|
|
1531
|
-
}
|
|
1532
|
-
|
|
1533
|
-
this.forwardContinuation(signedEntry);
|
|
1531
|
+
appendJsonl(this.paths.eventsPath, signedEntry);
|
|
1532
|
+
this.routeToTargets(signedEntry);
|
|
1534
1533
|
this.rememberEmittedAnswer(answerKey);
|
|
1534
|
+
this.log(`[${this.seatId}] ${previewText(payload)}`);
|
|
1535
1535
|
}
|
|
1536
1536
|
|
|
1537
|
-
|
|
1537
|
+
routeToTargets(signedEntry) {
|
|
1538
1538
|
if (this.continueTargets.length === 0) {
|
|
1539
1539
|
return;
|
|
1540
1540
|
}
|
|
@@ -1546,7 +1546,7 @@ class ArmedSeat {
|
|
|
1546
1546
|
|
|
1547
1547
|
const target = this.findContinuationTarget(targetEntry.targetSeatId);
|
|
1548
1548
|
if (!target) {
|
|
1549
|
-
this.log(`[${this.seatId}]
|
|
1549
|
+
this.log(`[${this.seatId}] target ${targetEntry.targetSeatId} unavailable`);
|
|
1550
1550
|
continue;
|
|
1551
1551
|
}
|
|
1552
1552
|
|
|
@@ -1795,6 +1795,13 @@ function stopAllSessions() {
|
|
|
1795
1795
|
signalPid(seat.wrapperPid, "SIGTERM");
|
|
1796
1796
|
}
|
|
1797
1797
|
}
|
|
1798
|
+
|
|
1799
|
+
// Clean up session directory so stale data doesn't bleed into next session.
|
|
1800
|
+
try {
|
|
1801
|
+
fs.rmSync(sessionPaths.dir, { recursive: true, force: true });
|
|
1802
|
+
} catch {
|
|
1803
|
+
// Best-effort cleanup.
|
|
1804
|
+
}
|
|
1798
1805
|
}
|
|
1799
1806
|
|
|
1800
1807
|
return {
|