@memnexus-ai/mx-agent-cli 0.1.156 → 0.1.158
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/dist/__tests__/leader-lock.test.d.ts +12 -0
- package/dist/__tests__/leader-lock.test.d.ts.map +1 -0
- package/dist/__tests__/leader-lock.test.js +293 -0
- package/dist/__tests__/leader-lock.test.js.map +1 -0
- package/dist/__tests__/team-name-propagation.test.d.ts +3 -0
- package/dist/__tests__/team-name-propagation.test.d.ts.map +1 -1
- package/dist/__tests__/team-name-propagation.test.js +73 -15
- package/dist/__tests__/team-name-propagation.test.js.map +1 -1
- package/dist/__tests__/unlock.test.d.ts +11 -0
- package/dist/__tests__/unlock.test.d.ts.map +1 -0
- package/dist/__tests__/unlock.test.js +100 -0
- package/dist/__tests__/unlock.test.js.map +1 -0
- package/dist/commands/start.d.ts.map +1 -1
- package/dist/commands/start.js +143 -1
- package/dist/commands/start.js.map +1 -1
- package/dist/commands/unlock.d.ts +19 -0
- package/dist/commands/unlock.d.ts.map +1 -0
- package/dist/commands/unlock.js +114 -0
- package/dist/commands/unlock.js.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/claude.d.ts +22 -3
- package/dist/lib/claude.d.ts.map +1 -1
- package/dist/lib/claude.js +81 -17
- package/dist/lib/claude.js.map +1 -1
- package/dist/lib/leader-lock.d.ts +144 -0
- package/dist/lib/leader-lock.d.ts.map +1 -0
- package/dist/lib/leader-lock.js +278 -0
- package/dist/lib/leader-lock.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* leader-lock.ts — leader-session start-time mutual exclusion (Platform v2.30, #3946).
|
|
3
|
+
*
|
|
4
|
+
* ── SCOPE STATEMENT (explicit) ────────────────────────────────────────────
|
|
5
|
+
* This module implements leader-session START-TIME mutual exclusion ONLY: it
|
|
6
|
+
* refuses to launch a second `mx-agent start` leader in a worktree that already
|
|
7
|
+
* has a live leader. It is a file-based advisory lock in the worktree root.
|
|
8
|
+
*
|
|
9
|
+
* It does NOT address the concurrent named-memory WRITE-RACE class — that is a
|
|
10
|
+
* separate, already-shipped fix (#3697 / #3713, compare-and-set on named-memory
|
|
11
|
+
* writes). Do not conflate the two: this lock guards process launch, CAS guards
|
|
12
|
+
* memory content. Sub-agent teammates are spawned via the Task tool INSIDE a
|
|
13
|
+
* leader session, never via `mx-agent start`, so they never touch this lock
|
|
14
|
+
* (asserted in leader-lock.test.ts).
|
|
15
|
+
*
|
|
16
|
+
* ── Liveness discriminator ─────────────────────────────────────────────────
|
|
17
|
+
* A recorded PID is a live match for THIS worktree iff `/proc/<pid>` exists AND
|
|
18
|
+
* either `/proc/<pid>/cwd` resolves to this worktree's realpath (worktree-unique)
|
|
19
|
+
* OR `/proc/<pid>/environ` contains `CLAUDE_WORKTREE_PATH=<this worktree>`. We do
|
|
20
|
+
* NOT use cmdline (identical across teams) or tty (headless sessions have none).
|
|
21
|
+
*
|
|
22
|
+
* ── Fail-open contract ─────────────────────────────────────────────────────
|
|
23
|
+
* Any ambiguity (no /proc, permission errors, malformed lock) resolves to
|
|
24
|
+
* FAIL OPEN with a loud warning — never brick a legitimate start.
|
|
25
|
+
*/
|
|
26
|
+
import { existsSync, readFileSync, realpathSync, statSync, unlinkSync, writeFileSync } from 'fs';
|
|
27
|
+
import { join } from 'path';
|
|
28
|
+
export const LOCK_FILENAME = '.mx-leader.lock';
|
|
29
|
+
export function lockPath(worktreePath) {
|
|
30
|
+
return join(worktreePath, LOCK_FILENAME);
|
|
31
|
+
}
|
|
32
|
+
/** Hard cap on lock file size. A well-formed lock is a few hundred bytes; a
|
|
33
|
+
* multi-megabyte file is either corruption or a crafted resource-exhaustion
|
|
34
|
+
* attempt. Oversize → treated as malformed (fail open), never read into memory. */
|
|
35
|
+
export const MAX_LOCK_BYTES = 64 * 1024;
|
|
36
|
+
export function readLock(worktreePath) {
|
|
37
|
+
const p = lockPath(worktreePath);
|
|
38
|
+
if (!existsSync(p))
|
|
39
|
+
return { present: false, lock: null };
|
|
40
|
+
// Size guard BEFORE reading — bound the bytes we ever pull into memory.
|
|
41
|
+
try {
|
|
42
|
+
const size = statSync(p).size;
|
|
43
|
+
if (size > MAX_LOCK_BYTES) {
|
|
44
|
+
return { present: true, lock: null, parseError: `lock file too large (${size} > ${MAX_LOCK_BYTES} bytes)` };
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
return { present: true, lock: null, parseError: err instanceof Error ? err.message : String(err) };
|
|
49
|
+
}
|
|
50
|
+
let raw;
|
|
51
|
+
try {
|
|
52
|
+
raw = readFileSync(p, 'utf-8');
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
return { present: true, lock: null, parseError: err instanceof Error ? err.message : String(err) };
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
const obj = JSON.parse(raw);
|
|
59
|
+
if (typeof obj.team !== 'string' ||
|
|
60
|
+
typeof obj.worktreePath !== 'string' ||
|
|
61
|
+
typeof obj.wrapperPid !== 'number' ||
|
|
62
|
+
typeof obj.startedAt !== 'string' ||
|
|
63
|
+
typeof obj.version !== 'string' ||
|
|
64
|
+
(obj.childPid !== null && typeof obj.childPid !== 'number')) {
|
|
65
|
+
return { present: true, lock: null, parseError: 'lock missing required fields' };
|
|
66
|
+
}
|
|
67
|
+
return { present: true, lock: obj };
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
return { present: true, lock: null, parseError: err instanceof Error ? err.message : String(err) };
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function serializeLock(lock) {
|
|
74
|
+
return JSON.stringify(lock, null, 2) + '\n';
|
|
75
|
+
}
|
|
76
|
+
/** Force-write (overwrite) the lock. Used to patch childPid into a lock we
|
|
77
|
+
* already own, and as the final fail-open path. For the mutual-exclusion
|
|
78
|
+
* decision use {@link claimLock}, not this. */
|
|
79
|
+
export function writeLock(worktreePath, lock) {
|
|
80
|
+
writeFileSync(lockPath(worktreePath), serializeLock(lock), 'utf-8');
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Atomically claim the lock via an exclusive create (`O_CREAT | O_EXCL`, i.e.
|
|
84
|
+
* `writeFileSync(..., { flag: 'wx' })`). This single filesystem operation IS the
|
|
85
|
+
* mutual-exclusion decision: if two `mx-agent start` invocations race, exactly
|
|
86
|
+
* one exclusive-create succeeds and the other gets EEXIST. No check-then-write
|
|
87
|
+
* TOCTOU window (that was the pre-fix bug: liveness check and lock write were
|
|
88
|
+
* separated by the whole fetch/rebase sequence, so both racers passed).
|
|
89
|
+
*
|
|
90
|
+
* NOTE: scope is single-host. `O_EXCL` on a POSIX filesystem is atomic locally;
|
|
91
|
+
* it is NOT guaranteed atomic over some network filesystems (older NFS). Agents
|
|
92
|
+
* run one host per worktree, so this holds. The named-memory write-race across
|
|
93
|
+
* hosts is a separate, shipped concern (#3697/#3713 CAS).
|
|
94
|
+
*/
|
|
95
|
+
export function claimLock(worktreePath, lock) {
|
|
96
|
+
try {
|
|
97
|
+
writeFileSync(lockPath(worktreePath), serializeLock(lock), { encoding: 'utf-8', flag: 'wx' });
|
|
98
|
+
return { ok: true };
|
|
99
|
+
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
const code = err.code;
|
|
102
|
+
if (code === 'EEXIST')
|
|
103
|
+
return { ok: false, reason: 'exists' };
|
|
104
|
+
return { ok: false, reason: 'error', error: err instanceof Error ? err.message : String(err) };
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/** Read-modify-write to record the child PID once the child has spawned. */
|
|
108
|
+
export function updateChildPid(worktreePath, childPid) {
|
|
109
|
+
const { lock } = readLock(worktreePath);
|
|
110
|
+
if (!lock)
|
|
111
|
+
return; // lock vanished/corrupt — nothing to update; launch proceeds.
|
|
112
|
+
writeLock(worktreePath, { ...lock, childPid });
|
|
113
|
+
}
|
|
114
|
+
export function removeLock(worktreePath) {
|
|
115
|
+
try {
|
|
116
|
+
unlinkSync(lockPath(worktreePath));
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
// Already gone — fine.
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
function normalizeRealpath(p) {
|
|
123
|
+
try {
|
|
124
|
+
return realpathSync(p);
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
return p;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Probe a single PID against a worktree. See module header for the discriminator.
|
|
132
|
+
*
|
|
133
|
+
* Errors are classified: a missing `/proc/<pid>` (or ENOENT mid-read) means the
|
|
134
|
+
* process is gone → `dead`. A permission error (EACCES/EPERM) reading cwd/environ
|
|
135
|
+
* means we cannot verify → `indeterminate` (fail open). A live process whose
|
|
136
|
+
* cwd/environ point elsewhere → `dead` (not our leader).
|
|
137
|
+
*/
|
|
138
|
+
export function probePid(pid, worktreeReal) {
|
|
139
|
+
if (!Number.isInteger(pid) || pid <= 0) {
|
|
140
|
+
return { pid, state: 'dead', reason: 'invalid pid' };
|
|
141
|
+
}
|
|
142
|
+
if (!existsSync('/proc')) {
|
|
143
|
+
return { pid, state: 'indeterminate', reason: '/proc not available' };
|
|
144
|
+
}
|
|
145
|
+
const procDir = `/proc/${pid}`;
|
|
146
|
+
if (!existsSync(procDir)) {
|
|
147
|
+
return { pid, state: 'dead', reason: 'no such process' };
|
|
148
|
+
}
|
|
149
|
+
let permissionBlocked = false;
|
|
150
|
+
// 1. cwd — the strongest signal (worktree-unique symlink).
|
|
151
|
+
let cwdReal;
|
|
152
|
+
try {
|
|
153
|
+
cwdReal = realpathSync(`${procDir}/cwd`);
|
|
154
|
+
if (cwdReal === worktreeReal) {
|
|
155
|
+
return { pid, state: 'live', matchedBy: 'cwd', cwd: cwdReal };
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
catch (err) {
|
|
159
|
+
const code = err.code;
|
|
160
|
+
if (code === 'ENOENT') {
|
|
161
|
+
return { pid, state: 'dead', reason: 'process exited during probe' };
|
|
162
|
+
}
|
|
163
|
+
if (code === 'EACCES' || code === 'EPERM') {
|
|
164
|
+
permissionBlocked = true;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
// 2. environ — covers cases where cwd changed but the launch env is intact.
|
|
168
|
+
try {
|
|
169
|
+
const environ = readFileSync(`${procDir}/environ`, 'utf-8');
|
|
170
|
+
for (const entry of environ.split('\0')) {
|
|
171
|
+
const eq = entry.indexOf('=');
|
|
172
|
+
if (eq === -1)
|
|
173
|
+
continue;
|
|
174
|
+
if (entry.slice(0, eq) !== 'CLAUDE_WORKTREE_PATH')
|
|
175
|
+
continue;
|
|
176
|
+
const val = entry.slice(eq + 1);
|
|
177
|
+
if (val === worktreeReal || normalizeRealpath(val) === worktreeReal) {
|
|
178
|
+
return { pid, state: 'live', matchedBy: 'environ', cwd: cwdReal };
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
catch (err) {
|
|
183
|
+
const code = err.code;
|
|
184
|
+
if (code === 'EACCES' || code === 'EPERM') {
|
|
185
|
+
permissionBlocked = true;
|
|
186
|
+
}
|
|
187
|
+
// ENOENT here just means the process exited between the two reads; the cwd
|
|
188
|
+
// path already handled a clean exit, so fall through.
|
|
189
|
+
}
|
|
190
|
+
// Process is alive but we found no positive match. If reads were blocked by
|
|
191
|
+
// permissions we cannot conclude it's a different worktree → indeterminate.
|
|
192
|
+
if (permissionBlocked) {
|
|
193
|
+
return { pid, state: 'indeterminate', reason: 'process alive but /proc unreadable (permission)' };
|
|
194
|
+
}
|
|
195
|
+
return { pid, state: 'dead', reason: 'alive but different worktree', cwd: cwdReal };
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Heartbeat freshness window. The child refreshes the lock mtime on every Bash
|
|
199
|
+
* PostToolUse (see deploy-verification-reminder.sh). A lock touched within this
|
|
200
|
+
* window is evidence a child was recently alive; we use it only to STRENGTHEN
|
|
201
|
+
* the stale-lock warning, never to force a refusal (clock skew / idle sessions
|
|
202
|
+
* must not brick a start). Primary detection is always the both-PID probe.
|
|
203
|
+
*/
|
|
204
|
+
export const HEARTBEAT_FRESH_SECONDS = 300;
|
|
205
|
+
/**
|
|
206
|
+
* Evaluate a lock's liveness by probing BOTH recorded PIDs (wrapper + child).
|
|
207
|
+
*
|
|
208
|
+
* - Any PID a live match for this worktree → `live` (refuse).
|
|
209
|
+
* - No live match, but at least one indeterminate probe → `indeterminate` (fail open).
|
|
210
|
+
* - All PIDs dead/mismatched → `stale` (replace).
|
|
211
|
+
*/
|
|
212
|
+
export function checkLiveness(lock, worktreePath) {
|
|
213
|
+
const worktreeReal = normalizeRealpath(worktreePath);
|
|
214
|
+
const pids = [lock.wrapperPid, lock.childPid].filter((p) => typeof p === 'number' && Number.isInteger(p) && p > 0);
|
|
215
|
+
const probes = pids.map(pid => probePid(pid, worktreeReal));
|
|
216
|
+
let lockAgeSeconds = null;
|
|
217
|
+
try {
|
|
218
|
+
const mtimeMs = statSync(lockPath(worktreePath)).mtimeMs;
|
|
219
|
+
lockAgeSeconds = Math.max(0, Math.round((Date.now() - mtimeMs) / 1000));
|
|
220
|
+
}
|
|
221
|
+
catch {
|
|
222
|
+
lockAgeSeconds = null;
|
|
223
|
+
}
|
|
224
|
+
const livePids = probes.filter(p => p.state === 'live').map(p => p.pid);
|
|
225
|
+
let state;
|
|
226
|
+
if (livePids.length > 0)
|
|
227
|
+
state = 'live';
|
|
228
|
+
else if (probes.some(p => p.state === 'indeterminate'))
|
|
229
|
+
state = 'indeterminate';
|
|
230
|
+
else
|
|
231
|
+
state = 'stale';
|
|
232
|
+
return { state, probes, livePids, lockAgeSeconds };
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Sanitize a lock-derived string before printing it to a terminal.
|
|
236
|
+
*
|
|
237
|
+
* The lock file is attacker-influenceable (any process that can write the
|
|
238
|
+
* worktree can craft it). Its string fields (team, worktreePath, startedAt,
|
|
239
|
+
* version, and probe cwd) are echoed into the refusal/unlock evidence, which
|
|
240
|
+
* prints to a TTY. Without sanitization a crafted `team` could embed OSC/CSI
|
|
241
|
+
* escape sequences (erase-line, cursor moves, tab-title rewrite) — the reviewer
|
|
242
|
+
* demonstrated this. Strip C0 (0x00–0x1F) and DEL+C1 (0x7F–0x9F) control chars
|
|
243
|
+
* and cap the printed length.
|
|
244
|
+
*/
|
|
245
|
+
export const MAX_EVIDENCE_FIELD_CHARS = 256;
|
|
246
|
+
export function sanitizeField(value, maxLen = MAX_EVIDENCE_FIELD_CHARS) {
|
|
247
|
+
// Strip C0 (0x00-0x1F), DEL (0x7F) and C1 (0x80-0x9F) — built from escape
|
|
248
|
+
// sequences so this source file itself carries no raw control bytes.
|
|
249
|
+
const CONTROL_CHARS = new RegExp("[\\u0000-\\u001F\\u007F-\\u009F]", "g");
|
|
250
|
+
const stripped = String(value).replace(CONTROL_CHARS, "");
|
|
251
|
+
return stripped.length > maxLen ? `${stripped.slice(0, maxLen)}…(truncated)` : stripped;
|
|
252
|
+
}
|
|
253
|
+
/** Human-readable evidence block shared by the refusal message and `mx-agent unlock`. */
|
|
254
|
+
export function formatLockEvidence(lock, result) {
|
|
255
|
+
const lines = [];
|
|
256
|
+
lines.push(` team: ${sanitizeField(lock.team)}`);
|
|
257
|
+
lines.push(` worktree: ${sanitizeField(lock.worktreePath)}`);
|
|
258
|
+
lines.push(` wrapper pid: ${lock.wrapperPid}`); // numeric — safe
|
|
259
|
+
lines.push(` child pid: ${lock.childPid ?? '(not yet spawned)'}`); // numeric | null — safe
|
|
260
|
+
lines.push(` started at: ${sanitizeField(lock.startedAt)}`);
|
|
261
|
+
lines.push(` version: ${sanitizeField(lock.version)}`);
|
|
262
|
+
if (result) {
|
|
263
|
+
if (result.livePids.length > 0) {
|
|
264
|
+
lines.push(` live pids: ${result.livePids.join(', ')}`); // numeric — safe
|
|
265
|
+
}
|
|
266
|
+
for (const probe of result.probes) {
|
|
267
|
+
const detail = probe.matchedBy
|
|
268
|
+
? `matched by ${probe.matchedBy}${probe.cwd ? ` (cwd=${sanitizeField(probe.cwd)})` : ''}`
|
|
269
|
+
: probe.reason ?? '';
|
|
270
|
+
lines.push(` pid ${probe.pid}: ${probe.state}${detail ? ` — ${detail}` : ''}`);
|
|
271
|
+
}
|
|
272
|
+
if (result.lockAgeSeconds !== null) {
|
|
273
|
+
lines.push(` lock age: ${result.lockAgeSeconds}s (mtime heartbeat)`);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
return lines.join('\n');
|
|
277
|
+
}
|
|
278
|
+
//# sourceMappingURL=leader-lock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"leader-lock.js","sourceRoot":"","sources":["../../src/lib/leader-lock.ts"],"names":[],"mappings":"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"}
|