Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/__tests__/attachments.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,12 @@ test('downloadAttachments saves files with UUID-prefixed names', async () => {
assert.equal(downloaded.length, 1);
assert.deepEqual(failed, []);
assert.equal(downloaded[0].originalName, 'photo.png');
assert.ok(downloaded[0].savedPath.includes(DEFAULT_FILES_SUBDIR));
// `DEFAULT_FILES_SUBDIR` is the literal string '.maestro/discord-files',
// but the joined `savedPath` uses `path.sep`. Normalize to the platform
// separator before checking containment so the test passes on Windows
// (where path.join produces backslashes) and Unix (forward slashes).
const expectedSubdir = DEFAULT_FILES_SUBDIR.split('/').join(path.sep);
assert.ok(downloaded[0].savedPath.includes(expectedSubdir));

const basename = path.basename(downloaded[0].savedPath);
assert.match(basename, /^[0-9a-f-]{36}-photo\.png$/);
Expand Down
36 changes: 26 additions & 10 deletions src/__tests__/auto-run-command.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ test('auto-run start rejects channels not connected to an agent', async () => {
assert.ok(reply.content.includes('not connected to an agent'));
});

// OS-agnostic relative path for the mocked Auto Run folder. Avoids the
// Windows pitfall where `path.isAbsolute('/agents/...')` is true and
// `path.join('/...', x)` prepends `C:\` instead of producing a
// relative join.
const MOCK_AUTO_RUN_FOLDER = path.join('agents', 'auto-run-docs');

test('auto-run start resolves a bare filename against the agent Auto Run folder', async () => {
const { channelDb } = await import('../providers/discord/channelsDb');
mock.method(channelDb, 'get', () => ({
Expand All @@ -64,7 +70,7 @@ test('auto-run start resolves a bare filename against the agent Auto Run folder'
name: 'TestBot',
toolType: 'claude',
cwd: '/proj',
autoRunFolderPath: '/agents/auto-run-docs',
autoRunFolderPath: MOCK_AUTO_RUN_FOLDER,
}));

const startMock = mock.method(maestro, 'startAutoRun', async () => '');
Expand All @@ -74,7 +80,10 @@ test('auto-run start resolves a bare filename against the agent Auto Run folder'

assert.equal(startMock.mock.callCount(), 1);
const opts = startMock.mock.calls[0].arguments[0] as { docs: string[] };
assert.deepEqual(opts.docs, [path.join('/agents/auto-run-docs', 'plan.md')]);
// Compute the expected value via the same OS-agnostic helper the
// production code uses internally — guarantees the assertion holds
// regardless of which platform's `path.resolve` semantics apply.
assert.deepEqual(opts.docs, [resolveContainedDocPath(MOCK_AUTO_RUN_FOLDER, 'plan.md')]);
});

test('auto-run start resolves a relative subpath against the agent Auto Run folder', async () => {
Expand All @@ -91,7 +100,7 @@ test('auto-run start resolves a relative subpath against the agent Auto Run fold
name: 'TestBot',
toolType: 'claude',
cwd: '/proj',
autoRunFolderPath: '/agents/auto-run-docs',
autoRunFolderPath: MOCK_AUTO_RUN_FOLDER,
}));

const startMock = mock.method(maestro, 'startAutoRun', async () => '');
Expand All @@ -101,7 +110,7 @@ test('auto-run start resolves a relative subpath against the agent Auto Run fold

assert.equal(startMock.mock.callCount(), 1);
const opts = startMock.mock.calls[0].arguments[0] as { docs: string[] };
assert.deepEqual(opts.docs, [path.join('/agents/auto-run-docs', 'subdir/doc.md')]);
assert.deepEqual(opts.docs, [resolveContainedDocPath(MOCK_AUTO_RUN_FOLDER, 'subdir/doc.md')]);
});

test('auto-run start accepts an absolute path that lives inside the agent folder', async () => {
Expand All @@ -118,11 +127,14 @@ test('auto-run start accepts an absolute path that lives inside the agent folder
name: 'TestBot',
toolType: 'claude',
cwd: '/proj',
autoRunFolderPath: '/agents/auto-run-docs',
autoRunFolderPath: MOCK_AUTO_RUN_FOLDER,
}));
const startMock = mock.method(maestro, 'startAutoRun', async () => '');

const inside = '/agents/auto-run-docs/subdir/doc.md';
// Build the absolute doc path the same way production does — via
// `path.resolve` against the (relative) folder — so the input
// round-trips identically on Linux and Windows.
const inside = path.join(path.resolve(MOCK_AUTO_RUN_FOLDER), 'subdir', 'doc.md');
const i = makeInteraction({ doc: inside });
await execute(i as unknown as Parameters<typeof execute>[0]);

Expand All @@ -145,11 +157,15 @@ test('auto-run start rejects an absolute path outside the agent folder', async (
name: 'TestBot',
toolType: 'claude',
cwd: '/proj',
autoRunFolderPath: '/agents/auto-run-docs',
autoRunFolderPath: MOCK_AUTO_RUN_FOLDER,
}));
const startMock = mock.method(maestro, 'startAutoRun', async () => '');

const i = makeInteraction({ doc: '/etc/passwd' });
// Build an absolute path that's guaranteed not to live under the
// resolved mock folder on any platform. `os.tmpdir()` is portable
// and resolvable via path.resolve on both OSes.
const outside = path.resolve(os.tmpdir(), 'evil.txt');
const i = makeInteraction({ doc: outside });
await execute(i as unknown as Parameters<typeof execute>[0]);

assert.equal(startMock.mock.callCount(), 0);
Expand All @@ -172,7 +188,7 @@ test('auto-run start rejects relative paths that escape the folder via traversal
name: 'TestBot',
toolType: 'claude',
cwd: '/proj',
autoRunFolderPath: '/agents/auto-run-docs',
autoRunFolderPath: MOCK_AUTO_RUN_FOLDER,
}));
const startMock = mock.method(maestro, 'startAutoRun', async () => '');

Expand Down Expand Up @@ -284,7 +300,7 @@ test('auto-run start surfaces errors from startAutoRun', async () => {
name: 'TestBot',
toolType: 'claude',
cwd: '/proj',
autoRunFolderPath: '/agents/auto-run-docs',
autoRunFolderPath: MOCK_AUTO_RUN_FOLDER,
}));
mock.method(maestro, 'startAutoRun', async () => {
throw new Error('boom');
Expand Down