staff-mcp 1.0.27 → 1.0.29

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.
@@ -3,3 +3,26 @@ export declare const DEFAULT_TIMEOUT = 10000;
3
3
  export declare const SEARCH_MAX_COLUMNS = 200;
4
4
  export declare const SEARCH_MAX_MATCHES = 200;
5
5
  export declare const SEARCH_EXEC_MAX_BUFFER: number;
6
+ /** Maximum image file size (10MB). Base64 encoding adds ~33% overhead. */
7
+ export declare const IMAGE_SIZE_LIMIT: number;
8
+ /** Number of leading bytes to read for magic-byte sniffing and binary detection. */
9
+ export declare const FILE_SNIFF_SIZE = 4096;
10
+ /** MIME types that are returned as image content blocks (not including SVG). */
11
+ export declare const SUPPORTED_IMAGE_MIMES: Set<string>;
12
+ /** Fallback: extension → MIME type mapping (used when sniffing fails, e.g. for SVG). */
13
+ export declare const IMAGE_MIME_BY_EXTENSION: Record<string, string>;
14
+ /**
15
+ * Sniff the MIME type of a file from its leading bytes (magic bytes).
16
+ * Returns null if the bytes don't match any known image signature.
17
+ */
18
+ export declare function sniffImageMime(bytes: Uint8Array): string | null;
19
+ /**
20
+ * Determine whether a file is binary (should not be read as text).
21
+ * Uses content-based detection only (no extension reliance):
22
+ * 1. Contains a null byte (0x00) → true
23
+ * 2. Ratio of non-printable bytes > 30% → true
24
+ *
25
+ * @param filepath - File path (reserved for future use, not currently used)
26
+ * @param bytes - Leading bytes of the file (recommend 4096 bytes)
27
+ */
28
+ export declare function isBinaryFile(filepath: string, bytes: Uint8Array): boolean;
@@ -3,4 +3,79 @@ export const DEFAULT_TIMEOUT = 10000;
3
3
  export const SEARCH_MAX_COLUMNS = 200;
4
4
  export const SEARCH_MAX_MATCHES = 200;
5
5
  export const SEARCH_EXEC_MAX_BUFFER = 50 * 1024 * 1024; // 50MB
6
+ // --- Image reading support ---
7
+ /** Maximum image file size (10MB). Base64 encoding adds ~33% overhead. */
8
+ export const IMAGE_SIZE_LIMIT = 10 * 1024 * 1024;
9
+ /** Number of leading bytes to read for magic-byte sniffing and binary detection. */
10
+ export const FILE_SNIFF_SIZE = 4096;
11
+ /** MIME types that are returned as image content blocks (not including SVG). */
12
+ export const SUPPORTED_IMAGE_MIMES = new Set([
13
+ "image/jpeg",
14
+ "image/png",
15
+ "image/gif",
16
+ "image/webp",
17
+ ]);
18
+ /** Fallback: extension → MIME type mapping (used when sniffing fails, e.g. for SVG). */
19
+ export const IMAGE_MIME_BY_EXTENSION = {
20
+ ".png": "image/png",
21
+ ".jpg": "image/jpeg",
22
+ ".jpeg": "image/jpeg",
23
+ ".gif": "image/gif",
24
+ ".webp": "image/webp",
25
+ ".svg": "image/svg+xml",
26
+ ".bmp": "image/bmp",
27
+ ".tiff": "image/tiff",
28
+ ".ico": "image/x-icon",
29
+ };
30
+ /**
31
+ * Sniff the MIME type of a file from its leading bytes (magic bytes).
32
+ * Returns null if the bytes don't match any known image signature.
33
+ */
34
+ export function sniffImageMime(bytes) {
35
+ if (bytes.length >= 4 && bytes[0] === 0x89 && bytes[1] === 0x50 && bytes[2] === 0x4e && bytes[3] === 0x47) {
36
+ return "image/png";
37
+ }
38
+ if (bytes.length >= 3 && bytes[0] === 0xff && bytes[1] === 0xd8 && bytes[2] === 0xff) {
39
+ return "image/jpeg";
40
+ }
41
+ if (bytes.length >= 6 && bytes[0] === 0x47 && bytes[1] === 0x49 && bytes[2] === 0x46 && bytes[3] === 0x38) {
42
+ return "image/gif";
43
+ }
44
+ // WebP: RIFF....WEBP
45
+ if (bytes.length >= 12 &&
46
+ bytes[0] === 0x52 && bytes[1] === 0x49 && bytes[2] === 0x46 && bytes[3] === 0x46 &&
47
+ bytes[8] === 0x57 && bytes[9] === 0x45 && bytes[10] === 0x42 && bytes[11] === 0x50) {
48
+ return "image/webp";
49
+ }
50
+ return null;
51
+ }
52
+ // --- Binary file detection ---
53
+ /**
54
+ * Determine whether a file is binary (should not be read as text).
55
+ * Uses content-based detection only (no extension reliance):
56
+ * 1. Contains a null byte (0x00) → true
57
+ * 2. Ratio of non-printable bytes > 30% → true
58
+ *
59
+ * @param filepath - File path (reserved for future use, not currently used)
60
+ * @param bytes - Leading bytes of the file (recommend 4096 bytes)
61
+ */
62
+ export function isBinaryFile(filepath, bytes) {
63
+ if (bytes.length === 0) {
64
+ return false;
65
+ }
66
+ // 1. Null byte detection - text files almost never contain 0x00
67
+ let nonPrintableCount = 0;
68
+ for (let i = 0; i < bytes.length; i++) {
69
+ const b = bytes[i];
70
+ if (b === 0x00) {
71
+ return true;
72
+ }
73
+ // Count non-printable bytes (excluding common whitespace: \t=9, \n=10, \r=13)
74
+ if (b < 9 || (b > 13 && b < 32)) {
75
+ nonPrintableCount++;
76
+ }
77
+ }
78
+ // 2. Non-printable ratio threshold
79
+ return nonPrintableCount / bytes.length > 0.3;
80
+ }
6
81
  //# sourceMappingURL=constants.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAAG,MAAM,CAAC;AACtC,MAAM,CAAC,MAAM,eAAe,GAAG,KAAK,CAAC;AACrC,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAG,CAAC;AACtC,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAG,CAAC;AACtC,MAAM,CAAC,MAAM,sBAAsB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,OAAO"}
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ interface SignalSource {
2
+ on(event: NodeJS.Signals, listener: () => void): unknown;
3
+ removeListener(event: NodeJS.Signals, listener: () => void): unknown;
4
+ }
5
+ export interface DockerProxyOptions {
6
+ command?: string;
7
+ commandPrefixArgs?: readonly string[];
8
+ input?: NodeJS.ReadableStream;
9
+ signalSource?: SignalSource;
10
+ gracefulShutdownTimeoutMs?: number;
11
+ containerIdWaitTimeoutMs?: number;
12
+ containerCleanupTimeoutMs?: number;
13
+ forceKillTimeoutMs?: number;
14
+ }
15
+ /**
16
+ * Reject Docker options that would detach the CLI or disable the lifecycle
17
+ * guarantees managed by staff-mcp. This validator is intentionally applied to
18
+ * user-supplied Docker options only, because the command executed inside the
19
+ * container can legitimately contain similarly named flags.
20
+ */
21
+ export declare function validateAdditionalDockerArgs(args: readonly string[]): void;
22
+ /**
23
+ * Run the Docker-compatible CLI and keep its lifecycle tied to this process.
24
+ *
25
+ * For stdio transport, the caller's stdin remains the MCP data channel. For
26
+ * HTTP/reverse transports, child.stdin is intentionally kept open as a private
27
+ * lifecycle pipe instead of being connected to process.stdin. This allows the
28
+ * service to run under PM2/systemd/Supervisor even when fd 0 is /dev/null, while
29
+ * still making the container exit if the host proxy disappears unexpectedly.
30
+ */
31
+ export declare function runDockerProxy(dockerArgs: readonly string[], transport: string, options?: DockerProxyOptions): Promise<number>;
32
+ export {};
@@ -0,0 +1,492 @@
1
+ import { spawn } from "node:child_process";
2
+ import { randomUUID } from "node:crypto";
3
+ import * as fs from "node:fs";
4
+ import * as os from "node:os";
5
+ import * as path from "node:path";
6
+ const HANDLED_SIGNALS = ["SIGINT", "SIGTERM", "SIGHUP"];
7
+ const DEFAULT_GRACEFUL_SHUTDOWN_TIMEOUT_MS = 20_000;
8
+ const DEFAULT_CONTAINER_ID_WAIT_TIMEOUT_MS = 1_000;
9
+ const DEFAULT_CONTAINER_CLEANUP_TIMEOUT_MS = 20_000;
10
+ const DEFAULT_FORCE_KILL_TIMEOUT_MS = 5_000;
11
+ const CONTAINER_ID_POLL_INTERVAL_MS = 50;
12
+ function exitCodeFromSignal(signal) {
13
+ switch (signal) {
14
+ case "SIGHUP":
15
+ return 129;
16
+ case "SIGINT":
17
+ return 130;
18
+ case "SIGKILL":
19
+ return 137;
20
+ case "SIGTERM":
21
+ return 143;
22
+ default:
23
+ return 1;
24
+ }
25
+ }
26
+ function hasManagedIdentityArg(args) {
27
+ return args.some((arg) => arg === "--cidfile" ||
28
+ arg.startsWith("--cidfile=") ||
29
+ arg === "--name" ||
30
+ arg.startsWith("--name="));
31
+ }
32
+ function prepareContainerIdentity(dockerArgs) {
33
+ const args = [...dockerArgs];
34
+ if (hasManagedIdentityArg(args)) {
35
+ throw new Error("--cidfile and --name are managed internally by staff-mcp.");
36
+ }
37
+ const runIndex = args.indexOf("run");
38
+ if (runIndex < 0) {
39
+ throw new Error("Docker proxy arguments must contain the 'run' subcommand.");
40
+ }
41
+ const ownedDirectory = fs.mkdtempSync(path.join(os.tmpdir(), "staff-mcp-container-"));
42
+ const cidFilePath = path.join(ownedDirectory, "container.cid");
43
+ const containerName = `staff-mcp-${process.pid}-${randomUUID()}`;
44
+ args.splice(runIndex + 1, 0, "--cidfile", cidFilePath, "--name", containerName);
45
+ return { args, cidFilePath, containerName, ownedDirectory };
46
+ }
47
+ function readContainerId(cidFilePath) {
48
+ try {
49
+ const containerId = fs.readFileSync(cidFilePath, "utf8").trim();
50
+ return /^[a-f0-9]{64}$/i.test(containerId) ? containerId : undefined;
51
+ }
52
+ catch (error) {
53
+ const code = error.code;
54
+ if (code === "ENOENT") {
55
+ return undefined;
56
+ }
57
+ console.error(`[staff-mcp] Failed to read Docker cidfile '${cidFilePath}':`, error);
58
+ return undefined;
59
+ }
60
+ }
61
+ function delay(milliseconds) {
62
+ return new Promise((resolve) => setTimeout(resolve, milliseconds));
63
+ }
64
+ function isMissingContainerError(stderr) {
65
+ return /no such container|no container with (?:name or id|id|name).*found|container .* does not exist/i.test(stderr);
66
+ }
67
+ /**
68
+ * Reject Docker options that would detach the CLI or disable the lifecycle
69
+ * guarantees managed by staff-mcp. This validator is intentionally applied to
70
+ * user-supplied Docker options only, because the command executed inside the
71
+ * container can legitimately contain similarly named flags.
72
+ */
73
+ export function validateAdditionalDockerArgs(args) {
74
+ for (const arg of args) {
75
+ const normalized = arg.toLowerCase();
76
+ const isShortDetachOption = (/^-[^-][a-z]*$/i.test(arg) && arg.slice(1).includes("d")) || normalized.startsWith("-d=");
77
+ if (isShortDetachOption ||
78
+ normalized === "--detach" ||
79
+ (normalized.startsWith("--detach=") && normalized !== "--detach=false")) {
80
+ throw new Error("detached containers are not supported by the staff-mcp Docker proxy");
81
+ }
82
+ if (normalized.startsWith("--rm=") && !["--rm=true", "--rm=t", "--rm=1"].includes(normalized)) {
83
+ throw new Error("--rm cannot be disabled by the staff-mcp Docker proxy");
84
+ }
85
+ if (normalized.startsWith("--interactive=") &&
86
+ !["--interactive=true", "--interactive=t", "--interactive=1"].includes(normalized)) {
87
+ throw new Error("interactive stdin cannot be disabled by the staff-mcp Docker proxy");
88
+ }
89
+ if (/^-[^-]*i[^=]*=/.test(arg)) {
90
+ throw new Error("assigned -i values are not supported; use -i or --interactive=true");
91
+ }
92
+ if (normalized === "--cidfile" ||
93
+ normalized.startsWith("--cidfile=") ||
94
+ normalized === "--name" ||
95
+ normalized.startsWith("--name=")) {
96
+ throw new Error("--cidfile and --name are managed internally by staff-mcp");
97
+ }
98
+ }
99
+ }
100
+ /**
101
+ * Run the Docker-compatible CLI and keep its lifecycle tied to this process.
102
+ *
103
+ * For stdio transport, the caller's stdin remains the MCP data channel. For
104
+ * HTTP/reverse transports, child.stdin is intentionally kept open as a private
105
+ * lifecycle pipe instead of being connected to process.stdin. This allows the
106
+ * service to run under PM2/systemd/Supervisor even when fd 0 is /dev/null, while
107
+ * still making the container exit if the host proxy disappears unexpectedly.
108
+ */
109
+ export async function runDockerProxy(dockerArgs, transport, options = {}) {
110
+ const command = options.command ?? "docker";
111
+ const commandPrefixArgs = [...(options.commandPrefixArgs ?? [])];
112
+ const input = options.input ?? process.stdin;
113
+ const signalSource = options.signalSource ?? process;
114
+ const gracefulShutdownTimeoutMs = options.gracefulShutdownTimeoutMs ?? DEFAULT_GRACEFUL_SHUTDOWN_TIMEOUT_MS;
115
+ const containerIdWaitTimeoutMs = options.containerIdWaitTimeoutMs ?? DEFAULT_CONTAINER_ID_WAIT_TIMEOUT_MS;
116
+ const containerCleanupTimeoutMs = options.containerCleanupTimeoutMs ?? DEFAULT_CONTAINER_CLEANUP_TIMEOUT_MS;
117
+ const forceKillTimeoutMs = options.forceKillTimeoutMs ?? DEFAULT_FORCE_KILL_TIMEOUT_MS;
118
+ let containerIdentity;
119
+ try {
120
+ containerIdentity = prepareContainerIdentity(dockerArgs);
121
+ }
122
+ catch (error) {
123
+ const message = error instanceof Error ? error.message : String(error);
124
+ console.error(`[staff-mcp] Failed to prepare Docker proxy: ${message}`);
125
+ return 1;
126
+ }
127
+ return new Promise((resolve) => {
128
+ let child;
129
+ let cleanupChild;
130
+ let runExit;
131
+ let trackedContainerId;
132
+ let settled = false;
133
+ let shutdownStarted = false;
134
+ let shutdownActivated = false;
135
+ let cleanupInProgress = false;
136
+ let cleanupAttempted = false;
137
+ let containerCleanupConfirmed = false;
138
+ let cleanupFailed = false;
139
+ let escalationPromise;
140
+ let gracefulTimer;
141
+ let postCleanupTimer;
142
+ let postCleanupFinalTimer;
143
+ let cidPollTimer;
144
+ const signalHandlers = new Map();
145
+ const captureContainerId = () => {
146
+ if (!trackedContainerId) {
147
+ trackedContainerId = readContainerId(containerIdentity.cidFilePath);
148
+ }
149
+ return trackedContainerId;
150
+ };
151
+ const isChildRunning = () => child !== undefined && child.exitCode === null && child.signalCode === null;
152
+ const removeListeners = () => {
153
+ for (const [signal, handler] of signalHandlers) {
154
+ signalSource.removeListener(signal, handler);
155
+ }
156
+ signalHandlers.clear();
157
+ if (transport === "stdio" && child?.stdin) {
158
+ input.unpipe(child.stdin);
159
+ input.removeListener("end", handleInputEnd);
160
+ input.removeListener("error", handleInputError);
161
+ }
162
+ };
163
+ const finish = (exitCode) => {
164
+ if (settled) {
165
+ return;
166
+ }
167
+ settled = true;
168
+ if (gracefulTimer) {
169
+ clearTimeout(gracefulTimer);
170
+ }
171
+ if (postCleanupTimer) {
172
+ clearTimeout(postCleanupTimer);
173
+ }
174
+ if (postCleanupFinalTimer) {
175
+ clearTimeout(postCleanupFinalTimer);
176
+ }
177
+ if (cidPollTimer) {
178
+ clearInterval(cidPollTimer);
179
+ }
180
+ removeListeners();
181
+ try {
182
+ fs.rmSync(containerIdentity.ownedDirectory, { recursive: true, force: true });
183
+ }
184
+ catch (error) {
185
+ console.error(`[staff-mcp] Failed to remove temporary cidfile directory '${containerIdentity.ownedDirectory}':`, error);
186
+ }
187
+ resolve(exitCode);
188
+ };
189
+ const maybeFinish = () => {
190
+ if (!runExit || cleanupInProgress) {
191
+ return;
192
+ }
193
+ finish(cleanupFailed ? 1 : (runExit.code ?? exitCodeFromSignal(runExit.signal)));
194
+ };
195
+ const closeLifecyclePipe = () => {
196
+ if (!child?.stdin) {
197
+ return;
198
+ }
199
+ if (transport === "stdio") {
200
+ input.unpipe(child.stdin);
201
+ }
202
+ if (!child.stdin.destroyed && !child.stdin.writableEnded) {
203
+ child.stdin.end();
204
+ }
205
+ };
206
+ const waitForContainerId = async () => {
207
+ const deadline = Date.now() + containerIdWaitTimeoutMs;
208
+ let containerId = captureContainerId();
209
+ while (!containerId && isChildRunning() && Date.now() < deadline) {
210
+ await delay(Math.min(CONTAINER_ID_POLL_INTERVAL_MS, Math.max(1, deadline - Date.now())));
211
+ containerId = captureContainerId();
212
+ }
213
+ return containerId;
214
+ };
215
+ const forceRemoveContainer = (containerId) => new Promise((resolveCleanup) => {
216
+ let completed = false;
217
+ let cleanupSpawned = false;
218
+ let cleanupTimer;
219
+ let cleanupForceTimer;
220
+ let cleanupFinalTimer;
221
+ let stderr = "";
222
+ const complete = (success) => {
223
+ if (completed) {
224
+ return;
225
+ }
226
+ completed = true;
227
+ if (cleanupTimer) {
228
+ clearTimeout(cleanupTimer);
229
+ }
230
+ if (cleanupForceTimer) {
231
+ clearTimeout(cleanupForceTimer);
232
+ }
233
+ if (cleanupFinalTimer) {
234
+ clearTimeout(cleanupFinalTimer);
235
+ }
236
+ cleanupChild = undefined;
237
+ resolveCleanup(success);
238
+ };
239
+ try {
240
+ cleanupChild = spawn(command, [...commandPrefixArgs, "rm", "-f", containerId], {
241
+ stdio: ["ignore", "ignore", "pipe"],
242
+ });
243
+ }
244
+ catch (error) {
245
+ console.error(`[staff-mcp] Failed to start fallback container cleanup for ${containerId}:`, error);
246
+ complete(false);
247
+ return;
248
+ }
249
+ cleanupChild.once("spawn", () => {
250
+ cleanupSpawned = true;
251
+ });
252
+ cleanupChild.stderr?.on("data", (chunk) => {
253
+ if (stderr.length < 8_192) {
254
+ stderr += chunk.toString();
255
+ }
256
+ });
257
+ cleanupChild.once("error", (error) => {
258
+ console.error(`[staff-mcp] Failed to run fallback container cleanup for ${containerId}: ${error.message}`);
259
+ if (!cleanupSpawned && cleanupChild?.pid === undefined) {
260
+ complete(false);
261
+ }
262
+ });
263
+ cleanupChild.once("close", (code, signal) => {
264
+ if (completed) {
265
+ return;
266
+ }
267
+ const detail = stderr.trim();
268
+ if (code === 0 || isMissingContainerError(detail)) {
269
+ console.error(`[staff-mcp] Fallback container cleanup completed for ${containerId}.`);
270
+ complete(true);
271
+ return;
272
+ }
273
+ console.error(`[staff-mcp] Fallback container cleanup failed for ${containerId}: code ${code ?? "null"}` +
274
+ `${signal ? `, signal ${signal}` : ""}${detail ? `, ${detail}` : ""}`);
275
+ complete(false);
276
+ });
277
+ cleanupTimer = setTimeout(() => {
278
+ console.error(`[staff-mcp] Fallback container cleanup for ${containerId} exceeded ${containerCleanupTimeoutMs}ms; sending SIGTERM.`);
279
+ cleanupChild?.kill("SIGTERM");
280
+ cleanupForceTimer = setTimeout(() => {
281
+ if (!completed) {
282
+ console.error(`[staff-mcp] Fallback container cleanup for ${containerId} did not stop within an additional ${forceKillTimeoutMs}ms; sending SIGKILL.`);
283
+ cleanupChild?.kill("SIGKILL");
284
+ cleanupFinalTimer = setTimeout(() => {
285
+ if (!completed) {
286
+ console.error(`[staff-mcp] Fallback container cleanup for ${containerId} did not report completion after SIGKILL.`);
287
+ complete(false);
288
+ }
289
+ }, forceKillTimeoutMs);
290
+ }
291
+ }, forceKillTimeoutMs);
292
+ }, containerCleanupTimeoutMs);
293
+ });
294
+ const scheduleRunCliTermination = () => {
295
+ if (!isChildRunning() || postCleanupTimer) {
296
+ return;
297
+ }
298
+ child.kill("SIGTERM");
299
+ postCleanupTimer = setTimeout(() => {
300
+ if (!isChildRunning()) {
301
+ return;
302
+ }
303
+ console.error(`[staff-mcp] Docker CLI did not exit within ${forceKillTimeoutMs}ms; sending SIGKILL.`);
304
+ child.kill("SIGKILL");
305
+ postCleanupFinalTimer = setTimeout(() => {
306
+ if (!runExit && isChildRunning()) {
307
+ console.error("[staff-mcp] Docker CLI did not report completion after SIGKILL.");
308
+ cleanupFailed = true;
309
+ runExit = { code: 1, signal: null };
310
+ maybeFinish();
311
+ }
312
+ }, forceKillTimeoutMs);
313
+ }, forceKillTimeoutMs);
314
+ };
315
+ const escalateShutdown = () => {
316
+ if (escalationPromise) {
317
+ return escalationPromise;
318
+ }
319
+ escalationPromise = (async () => {
320
+ if (gracefulTimer) {
321
+ clearTimeout(gracefulTimer);
322
+ gracefulTimer = undefined;
323
+ }
324
+ if (!isChildRunning()) {
325
+ return;
326
+ }
327
+ if (containerCleanupConfirmed || cleanupAttempted) {
328
+ scheduleRunCliTermination();
329
+ return;
330
+ }
331
+ const containerId = await waitForContainerId();
332
+ if (!isChildRunning()) {
333
+ return;
334
+ }
335
+ if (!containerId) {
336
+ // Do not treat "no such container" as successful cleanup while the
337
+ // Docker CLI may still be pulling an image or creating the container.
338
+ // Stop the CLI first; its close handler will then remove the unique
339
+ // generated name after no further create request can be issued.
340
+ console.error(`[staff-mcp] Docker cidfile was unavailable; terminating the CLI before cleaning up '${containerIdentity.containerName}'.`);
341
+ scheduleRunCliTermination();
342
+ return;
343
+ }
344
+ cleanupInProgress = true;
345
+ cleanupAttempted = true;
346
+ const removed = await forceRemoveContainer(containerId);
347
+ cleanupInProgress = false;
348
+ if (removed) {
349
+ containerCleanupConfirmed = true;
350
+ cleanupFailed = false;
351
+ // Once the exact tracked container has been removed, it is safe to
352
+ // terminate a stuck CLI.
353
+ }
354
+ else {
355
+ cleanupFailed = true;
356
+ console.error(`[staff-mcp] Container ${containerId} could not be confirmed removed; terminating the stuck Docker CLI with an error status.`);
357
+ }
358
+ scheduleRunCliTermination();
359
+ maybeFinish();
360
+ })().finally(() => {
361
+ escalationPromise = undefined;
362
+ });
363
+ return escalationPromise;
364
+ };
365
+ const activateShutdown = () => {
366
+ if (!shutdownStarted || shutdownActivated || !child) {
367
+ return;
368
+ }
369
+ shutdownActivated = true;
370
+ closeLifecyclePipe();
371
+ gracefulTimer = setTimeout(() => {
372
+ if (!isChildRunning()) {
373
+ return;
374
+ }
375
+ console.error(`[staff-mcp] Docker proxy did not exit within ${gracefulShutdownTimeoutMs}ms; removing its tracked container.`);
376
+ void escalateShutdown();
377
+ }, gracefulShutdownTimeoutMs);
378
+ };
379
+ const requestShutdown = (reason, repeatedSignal = false) => {
380
+ if (settled) {
381
+ return;
382
+ }
383
+ if (!shutdownStarted) {
384
+ shutdownStarted = true;
385
+ console.error(`[staff-mcp] Docker proxy shutdown requested: ${reason}`);
386
+ activateShutdown();
387
+ return;
388
+ }
389
+ if (repeatedSignal) {
390
+ console.error(`[staff-mcp] Repeated shutdown signal received: ${reason}`);
391
+ void escalateShutdown();
392
+ }
393
+ };
394
+ function handleInputEnd() {
395
+ requestShutdown("stdio input closed");
396
+ }
397
+ function handleInputError(error) {
398
+ console.error(`[staff-mcp] Docker proxy input error: ${error.message}`);
399
+ requestShutdown("stdio input error");
400
+ }
401
+ for (const signal of HANDLED_SIGNALS) {
402
+ const handler = () => requestShutdown(`received ${signal}`, true);
403
+ signalHandlers.set(signal, handler);
404
+ signalSource.on(signal, handler);
405
+ }
406
+ try {
407
+ child = spawn(command, [...commandPrefixArgs, ...containerIdentity.args], {
408
+ stdio: ["pipe", "inherit", "inherit"],
409
+ });
410
+ }
411
+ catch (error) {
412
+ const message = error instanceof Error ? error.message : String(error);
413
+ console.error(`[staff-mcp] Failed to start docker proxy: ${message}`);
414
+ finish(1);
415
+ return;
416
+ }
417
+ if (!child.stdin) {
418
+ console.error("[staff-mcp] Failed to start docker proxy: child stdin is unavailable.");
419
+ child.kill("SIGKILL");
420
+ finish(1);
421
+ return;
422
+ }
423
+ child.stdin.on("error", (error) => {
424
+ if (!settled && error.code !== "EPIPE") {
425
+ console.error(`[staff-mcp] Docker proxy stdin error: ${error.message}`);
426
+ }
427
+ });
428
+ child.once("error", (error) => {
429
+ if (settled) {
430
+ return;
431
+ }
432
+ if (child?.pid === undefined) {
433
+ console.error(`[staff-mcp] Failed to start docker proxy: ${error.message}`);
434
+ finish(1);
435
+ return;
436
+ }
437
+ console.error(`[staff-mcp] Docker proxy process error: ${error.message}`);
438
+ cleanupFailed = true;
439
+ requestShutdown("Docker proxy process error", true);
440
+ });
441
+ child.once("close", (code, signal) => {
442
+ if (settled) {
443
+ return;
444
+ }
445
+ captureContainerId();
446
+ runExit = { code, signal };
447
+ if (gracefulTimer) {
448
+ clearTimeout(gracefulTimer);
449
+ }
450
+ if (postCleanupTimer) {
451
+ clearTimeout(postCleanupTimer);
452
+ }
453
+ if (postCleanupFinalTimer) {
454
+ clearTimeout(postCleanupFinalTimer);
455
+ }
456
+ console.error(`[staff-mcp] Docker proxy exited with code ${code ?? "null"}${signal ? ` (signal ${signal})` : ""}.`);
457
+ // If a supervisor killed the Docker CLI directly, --rm may not have
458
+ // completed. Clean up by exact ID when available, otherwise use the
459
+ // unique generated name that was part of the container-create request.
460
+ if (!cleanupInProgress &&
461
+ !cleanupAttempted &&
462
+ !containerCleanupConfirmed &&
463
+ (signal !== null || code !== 0)) {
464
+ const cleanupReference = trackedContainerId ?? containerIdentity.containerName;
465
+ cleanupInProgress = true;
466
+ cleanupAttempted = true;
467
+ void forceRemoveContainer(cleanupReference)
468
+ .then((removed) => {
469
+ containerCleanupConfirmed = removed;
470
+ cleanupFailed = !removed;
471
+ })
472
+ .finally(() => {
473
+ cleanupInProgress = false;
474
+ maybeFinish();
475
+ });
476
+ return;
477
+ }
478
+ maybeFinish();
479
+ });
480
+ cidPollTimer = setInterval(captureContainerId, CONTAINER_ID_POLL_INTERVAL_MS);
481
+ cidPollTimer.unref();
482
+ if (transport === "stdio") {
483
+ input.once("end", handleInputEnd);
484
+ input.once("error", handleInputError);
485
+ input.pipe(child.stdin);
486
+ }
487
+ // A signal source can synchronously request shutdown while handlers are
488
+ // being installed (and a real OS signal can arrive during startup).
489
+ activateShutdown();
490
+ });
491
+ }
492
+ //# sourceMappingURL=docker-proxy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docker-proxy.js","sourceRoot":"","sources":["../../src/docker-proxy.ts"],"names":[],"mappings":"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"}