blob: 101b01a599a594978ee5d09beef6f7532a80911e [file]
import assert from 'node:assert/strict';
import { describe, test } from 'node:test';
import type { SessionSummary } from '@maka/core';
import { selectMakaRunSession } from '../run-session-selection.js';
describe('maka run session selection', () => {
test('new runs canonicalize the explicit cwd or process cwd', async () => {
const deps = canonicalizer({ '/link': '/repo', '/process': '/process-real' });
assert.deepEqual(
await selectMakaRunSession(
{
sessions: [],
continueLatest: false,
explicitCwd: '/link',
processCwd: '/process',
thinkingSpecified: false,
},
deps,
),
{ kind: 'new', cwd: '/repo' },
);
assert.deepEqual(
await selectMakaRunSession(
{
sessions: [],
continueLatest: false,
processCwd: '/process',
thinkingSpecified: false,
},
deps,
),
{ kind: 'new', cwd: '/process-real' },
);
});
test('resume uses the stored canonical cwd and ignores implicit process cwd', async () => {
const stored = session({ id: 'resume-me', cwd: '/stored-link' });
const selected = await selectMakaRunSession(
{
sessions: [stored],
resumeId: stored.id,
continueLatest: false,
processCwd: '/unrelated-process-cwd',
thinkingSpecified: false,
},
canonicalizer({ '/stored-link': '/repo' }),
);
assert.equal(selected.kind, 'existing');
assert.equal(selected.cwd, '/repo');
assert.equal(selected.kind === 'existing' ? selected.session : undefined, stored);
assert.equal(stored.cwd, '/stored-link');
});
test('resume accepts a canonically equal explicit cwd and rejects a conflict', async () => {
const stored = session({ id: 'resume-me', cwd: '/stored-link' });
const deps = canonicalizer({
'/stored-link': '/repo',
'/explicit-link': '/repo',
'/other': '/other',
});
const selected = await selectMakaRunSession(
{
sessions: [stored],
resumeId: stored.id,
continueLatest: false,
explicitCwd: '/explicit-link',
processCwd: '/ignored',
thinkingSpecified: false,
},
deps,
);
assert.equal(selected.cwd, '/repo');
await assert.rejects(
selectMakaRunSession(
{
sessions: [stored],
resumeId: stored.id,
continueLatest: false,
explicitCwd: '/other',
processCwd: '/ignored',
thinkingSpecified: false,
},
deps,
),
/--cwd conflicts/,
);
});
test('resume accepts Auto sessions and rejects missing cwd, unsupported backend, and explicit config conflicts', async () => {
const deps = canonicalizer({ '/repo': '/repo' });
const base = session({ id: 'resume-me', cwd: '/repo', thinkingLevel: 'high' });
await assert.rejects(
selectMakaRunSession(
{
sessions: [session({ id: 'resume-me', cwd: undefined })],
resumeId: 'resume-me',
continueLatest: false,
processCwd: '/ignored',
thinkingSpecified: false,
},
deps,
),
/has no stored cwd/,
);
const auto = session({ id: 'resume-me', permissionMode: 'ask' });
const resumedAuto = await selectMakaRunSession(
{
sessions: [auto],
resumeId: 'resume-me',
continueLatest: false,
processCwd: '/ignored',
thinkingSpecified: false,
},
deps,
);
assert.equal(resumedAuto.kind === 'existing' ? resumedAuto.session : undefined, auto);
await assert.rejects(
selectMakaRunSession(
{
sessions: [session({ id: 'resume-me', backend: 'pi-agent' })],
resumeId: 'resume-me',
continueLatest: false,
processCwd: '/ignored',
thinkingSpecified: false,
},
deps,
),
/unsupported backend/,
);
for (const conflict of [
{ explicitConnection: 'other' },
{ explicitModel: 'other' },
{ thinkingSpecified: true, explicitThinking: undefined },
{ explicitPermissionMode: 'bypass' as const },
]) {
await assert.rejects(
selectMakaRunSession(
{
sessions: [base],
resumeId: base.id,
continueLatest: false,
processCwd: '/ignored',
thinkingSpecified: false,
...conflict,
},
deps,
),
/conflicts with resumed session/,
);
}
});
test('continue selects by lastMessageAt descending then id ascending after cwd filtering', async () => {
const selected = await selectMakaRunSession(
{
sessions: [
session({ id: 'archived', lastMessageAt: 500, isArchived: true }),
session({ id: 'done', lastMessageAt: 500, status: 'done' }),
session({ id: 'ask', lastMessageAt: 500, permissionMode: 'ask' }),
session({ id: 'missing-time', lastMessageAt: undefined }),
session({ id: 'inaccessible', cwd: '/missing', lastMessageAt: 400 }),
session({ id: 'b', cwd: '/repo-link', lastMessageAt: 300 }),
session({ id: 'a', cwd: '/repo', lastMessageAt: 300, status: 'aborted' }),
session({ id: 'older', cwd: '/repo', lastMessageAt: 200 }),
],
continueLatest: true,
processCwd: '/process-link',
thinkingSpecified: false,
},
canonicalizer({
'/process-link': '/repo',
'/repo-link': '/repo',
'/repo': '/repo',
}),
);
assert.equal(selected.kind, 'existing');
assert.equal(selected.kind === 'existing' ? selected.session.id : undefined, 'ask');
assert.equal(selected.cwd, '/repo');
});
test('continue skips linked child sessions while explicit resume still accepts them', async () => {
const child = session({
id: 'child',
lastMessageAt: 500,
subagentParent: {
kind: 'subagent',
parentSessionId: 'parent',
spawnedBy: {
parentRunId: 'parent-run',
parentTurnId: 'parent-turn',
toolCallId: 'tool-call',
},
lifecycle: 'foreground',
},
});
const parent = session({ id: 'parent', lastMessageAt: 100 });
const deps = canonicalizer({ '/repo': '/repo' });
const continued = await selectMakaRunSession(
{
sessions: [child, parent],
continueLatest: true,
processCwd: '/repo',
thinkingSpecified: false,
},
deps,
);
assert.equal(continued.kind === 'existing' ? continued.session.id : undefined, parent.id);
const resumed = await selectMakaRunSession(
{
sessions: [child, parent],
resumeId: child.id,
continueLatest: false,
processCwd: '/repo',
thinkingSpecified: false,
},
deps,
);
assert.equal(resumed.kind === 'existing' ? resumed.session.id : undefined, child.id);
});
test('continue returns a preflight failure when no cwd-compatible session exists', async () => {
await assert.rejects(
selectMakaRunSession(
{
sessions: [session({ id: 'other', cwd: '/other', lastMessageAt: 10 })],
continueLatest: true,
processCwd: '/repo',
thinkingSpecified: false,
},
canonicalizer({ '/repo': '/repo', '/other': '/other' }),
),
/no compatible session found/,
);
});
});
function session(overrides: Partial<SessionSummary> = {}): SessionSummary {
return {
id: 'session-1',
cwd: '/repo',
name: 'Session',
isFlagged: false,
isArchived: false,
labels: [],
hasUnread: false,
lastMessageAt: 100,
status: 'active',
backend: 'ai-sdk',
llmConnectionSlug: 'fixture',
connectionLocked: false,
model: 'fixture-model',
permissionMode: 'explore',
...overrides,
};
}
function canonicalizer(paths: Record<string, string>) {
return {
async canonicalizeDirectory(path: string): Promise<string> {
const canonical = paths[path];
if (!canonical) throw new Error(`missing path: ${path}`);
return canonical;
},
};
}