From 02058c37fad5cccd15d13b461341d7e9bca63b0e Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 28 Mar 2026 20:58:47 +0000 Subject: [PATCH] fix: handle Bun daemon argv duplication (#112) (thanks @dedene) --- CHANGELOG.md | 1 + tests/daemon-launch.test.ts | 50 +++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 tests/daemon-launch.test.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d54e7f..843cfeb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## [Unreleased] ### CLI +- Skip Bun compiled `/$bunfs/...` argv entries when detached daemon restarts spawn child processes, so compiled binaries do not duplicate the virtual entry path and lose the `daemon` command. (PR #112, thanks @dedene) - Keep `mcporter call --output json` parseable by emitting valid JSON even when the command falls back to raw output. (PR #128, thanks @armanddp) - Ignore static `Authorization` headers once OAuth is active so imported editor configs cannot override fresh OAuth tokens. (PR #123, thanks @ahonn) - Preserve full JSON/error payloads when `data` is just one field instead of collapsing the response to `data` alone. (PR #106, thanks @AielloChan) diff --git a/tests/daemon-launch.test.ts b/tests/daemon-launch.test.ts new file mode 100644 index 0000000..5ce6bfa --- /dev/null +++ b/tests/daemon-launch.test.ts @@ -0,0 +1,50 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; + +const spawnMock = vi.fn(() => ({ unref: vi.fn() })); + +vi.mock('node:child_process', () => ({ + spawn: spawnMock, +})); + +const originalArgv = [...process.argv]; +const originalExecArgv = [...process.execArgv]; + +describe('launchDaemonDetached', () => { + beforeEach(() => { + spawnMock.mockClear(); + process.argv = ['/tmp/mcporter', '/$bunfs/root/mcporter.js']; + process.execArgv = ['--smol']; + }); + + afterEach(() => { + process.argv = [...originalArgv]; + process.execArgv = [...originalExecArgv]; + }); + + it('omits Bun virtual entry paths from detached child args', async () => { + const { launchDaemonDetached } = await import('../src/daemon/launch.js'); + + launchDaemonDetached({ + configPath: '/tmp/mcporter.json', + configExplicit: true, + rootDir: '/repo', + socketPath: '/tmp/mcporter.sock', + metadataPath: '/tmp/mcporter.meta.json', + extraArgs: ['--log'], + }); + + expect(spawnMock).toHaveBeenCalledWith( + process.execPath, + ['--smol', '--config', '/tmp/mcporter.json', '--root', '/repo', 'daemon', 'start', '--foreground', '--log'], + expect.objectContaining({ + detached: true, + stdio: 'ignore', + env: expect.objectContaining({ + MCPORTER_DAEMON_CHILD: '1', + MCPORTER_DAEMON_SOCKET: '/tmp/mcporter.sock', + MCPORTER_DAEMON_METADATA: '/tmp/mcporter.meta.json', + }), + }) + ); + }); +});