blob: 19f172ec27910cf25ddbbc6d84a6967550586009 [file]
import type { SessionEvent } from '@maka/core';
import { createWorkspaceWritePermissionProfile } from '@maka/core';
import type { SessionSummary } from '@maka/core';
import {
runMakaTextCliCore,
type MakaRunContext,
type MakaRunContextInput,
type MakaRunOutcome,
type MakaRunRuntime,
} from '../run-command-core.js';
const scenario = process.env.MAKA_RUN_FIXTURE_SCENARIO ?? 'completed';
let observer: MakaRunContextInput['runOutcomeObserver'];
let permissionDenied = false;
let releaseStop: (() => void) | undefined;
let releaseGraphWait: (() => void) | undefined;
let graphActivityReleased = false;
const target = {
connection: {
slug: 'fixture',
name: 'Fixture',
providerType: 'ollama',
enabled: true,
defaultModel: 'fixture-model',
},
apiKey: '',
model: 'fixture-model',
};
const summary = {
id: 'session-fixture',
cwd: process.cwd(),
name: 'fixture',
isFlagged: false,
isArchived: false,
labels: [],
hasUnread: false,
status: 'active',
backend: 'ai-sdk',
llmConnectionSlug: 'fixture',
connectionLocked: false,
model: 'fixture-model',
permissionMode: 'explore',
} satisfies SessionSummary;
const runtime: MakaRunRuntime = {
async createSession(input) {
if (process.env.MAKA_RUN_EXPECT_NO_CREATE === '1') {
throw new Error('unexpected createSession call');
}
if (
process.env.MAKA_RUN_EXPECT_PERMISSION_MODE &&
input.permissionMode !== process.env.MAKA_RUN_EXPECT_PERMISSION_MODE
) {
throw new Error(`unexpected permissionMode ${input.permissionMode}`);
}
if (
process.env.MAKA_RUN_EXPECT_SESSION_NAME &&
input.name !== process.env.MAKA_RUN_EXPECT_SESSION_NAME
) {
throw new Error(`unexpected Session name ${JSON.stringify(input.name)}`);
}
return summary;
},
async readExecutionBoundary() {
const kind = process.env.MAKA_RUN_BOUNDARY_KIND ?? 'managed';
return kind === 'managed'
? {
kind,
profile: createWorkspaceWritePermissionProfile(),
revision: 0,
}
: { kind: kind as 'bypass' | 'external', revision: 0 };
},
async setExecutionBoundaryKind(_sessionId, kind) {
if (
process.env.MAKA_RUN_EXPECT_BOUNDARY_KIND &&
kind !== process.env.MAKA_RUN_EXPECT_BOUNDARY_KIND
) {
throw new Error(`unexpected boundary kind ${kind}`);
}
},
async *sendMessage(sessionId, input): AsyncIterable<SessionEvent> {
if (process.env.MAKA_RUN_EXPECT_NO_SEND === '1') {
throw new Error('unexpected sendMessage call');
}
if (
process.env.MAKA_RUN_EXPECT_SESSION_ID &&
sessionId !== process.env.MAKA_RUN_EXPECT_SESSION_ID
) {
throw new Error(`unexpected sessionId ${sessionId}`);
}
if (scenario === 'runtime-error') throw new Error('provider failed after startup');
if (scenario === 'graph-runtime-error') {
if (input.turnOrchestration?.mode !== 'graph') {
throw new Error('expected graph orchestration');
}
await notify(failedResult('provider_unavailable', 'provider failed before graph creation'));
return;
}
if (scenario === 'graph-wait') {
if (input.turnOrchestration?.mode !== 'graph') {
throw new Error('expected graph orchestration');
}
await notify(completedResult('initial graph supervisor output'));
return;
}
if (process.env.MAKA_RUN_EXPECT_GRAPH === '1') {
if (
input.turnOrchestration?.mode !== 'graph' ||
input.turnOrchestration.source !== 'host_api'
) {
throw new Error(
`unexpected graph orchestration ${JSON.stringify(input.turnOrchestration)}`,
);
}
await notify(completedResult('initial graph supervisor output'));
return;
}
if (scenario === 'sandbox-boundary') {
yield {
type: 'sandbox_boundary_request',
id: 'event-boundary',
turnId: input.turnId,
ts: 1,
requestId: 'boundary-1',
toolUseId: 'tool-boundary',
justification: 'Read an external file.',
expansion: {
filesystem: {
entries: [{ path: '/outside/file.txt', access: 'read', scope: 'exact' }],
},
},
};
if (!permissionDenied) throw new Error('sandbox boundary request was not denied');
return;
}
if (scenario === 'sandbox-boundary-tool-result') {
yield {
type: 'tool_result',
id: 'event-boundary-result',
turnId: input.turnId,
ts: 1,
toolUseId: 'tool-boundary',
isError: true,
content: {
kind: 'text',
text: 'Bash requires an approved session sandbox boundary expansion.',
sandboxFailure: {
reason: 'sandbox_boundary_required',
requiredExpansion: { network: { enabled: true } },
},
},
} as unknown as SessionEvent;
await notify(completedResult('should not be emitted'));
return;
}
if (scenario === 'sandbox-boundary-recovered') {
yield {
type: 'tool_result',
id: 'event-boundary-result',
turnId: input.turnId,
ts: 1,
toolUseId: 'tool-boundary',
isError: true,
content: {
kind: 'text',
text: 'Bash requires an approved session sandbox boundary expansion.',
sandboxFailure: {
reason: 'sandbox_boundary_required',
requiredExpansion: { network: { enabled: true } },
},
},
} as unknown as SessionEvent;
yield {
type: 'tool_result',
id: 'event-safe-result',
turnId: input.turnId,
ts: 2,
toolUseId: 'tool-safe',
isError: false,
content: { kind: 'text', text: 'completed within the current boundary' },
};
await notify({ ...completedResult('recovered safely'), sandboxBoundary: 'recovered' });
return;
}
if (scenario === 'slow') {
process.stderr.write('fixture-ready\n');
const keepAlive = setInterval(() => {}, 1_000);
await new Promise<void>((resolve) => {
releaseStop = resolve;
});
clearInterval(keepAlive);
await notify(failedResult('aborted', 'fixture stopped'));
return;
}
if (scenario === 'missing-output') {
await notify(
failedResult('missing_final_output', 'completed invocation produced no final output'),
);
return;
}
if (scenario === 'step-limit') {
await notify(
failedResult('step_limit', 'explicit tool-step limit reached; send continue to resume'),
);
return;
}
const maxSteps = process.env.MAKA_RUN_EXPECT_MAX_STEPS;
const output = maxSteps ? `maxSteps=${maxSteps};prompt=${input.text}` : `prompt=${input.text}`;
await notify(completedResult(output));
},
async respondToSandboxBoundary(_sessionId, response) {
permissionDenied = response.decision === 'deny' && response.requestId === 'boundary-1';
},
async stopSession() {
releaseStop?.();
},
};
async function createContext(input: MakaRunContextInput): Promise<MakaRunContext> {
if (scenario === 'config-error') throw new Error('unknown connection fixture-missing');
if (
process.env.MAKA_RUN_EXPECT_MAX_STEPS &&
input.maxSteps !== Number(process.env.MAKA_RUN_EXPECT_MAX_STEPS)
) {
throw new Error(`unexpected maxSteps ${String(input.maxSteps)}`);
}
if (
process.env.MAKA_RUN_EXPECT_CONTEXT_CWD &&
input.cwd !== process.env.MAKA_RUN_EXPECT_CONTEXT_CWD
) {
throw new Error(`unexpected context cwd ${input.cwd}`);
}
if (
process.env.MAKA_RUN_EXPECT_CONTEXT_CONNECTION &&
input.requestedConnectionSlug !== process.env.MAKA_RUN_EXPECT_CONTEXT_CONNECTION
) {
throw new Error(`unexpected context connection ${String(input.requestedConnectionSlug)}`);
}
if (
process.env.MAKA_RUN_EXPECT_CONTEXT_MODEL &&
input.requestedModel !== process.env.MAKA_RUN_EXPECT_CONTEXT_MODEL
) {
throw new Error(`unexpected context model ${String(input.requestedModel)}`);
}
if (process.env.MAKA_RUN_EXPECT_CWD_OVERRIDE) {
const actual = JSON.stringify(input.sessionCwdOverride);
if (actual !== process.env.MAKA_RUN_EXPECT_CWD_OVERRIDE) {
throw new Error(`unexpected sessionCwdOverride ${actual}`);
}
}
observer = input.runOutcomeObserver;
if (
process.env.MAKA_RUN_EXPECT_GRAPH === '1' ||
scenario === 'graph-runtime-error' ||
scenario === 'graph-wait'
) {
if (!input.enableAgentGraph) throw new Error('Graph host was not enabled');
return {
runtime,
target,
agentGraph: {
reserveActivity: () => ({
release: () => {
graphActivityReleased = true;
},
}),
waitForCompletion: async () => {
if (!graphActivityReleased) throw new Error('Graph activity was not released');
if (scenario === 'graph-runtime-error') {
process.stderr.write('graph-wait-called\n');
throw new Error('unexpected graph wait after failed invocation');
}
if (scenario === 'graph-wait') {
process.stderr.write('fixture-ready\n');
const keepAlive = setInterval(() => {}, 1_000);
await new Promise<void>((resolve) => {
releaseGraphWait = resolve;
});
clearInterval(keepAlive);
return;
}
if (process.env.MAKA_RUN_GRAPH_BOUNDARY_FAILURE === '1') {
await notify({
...completedResult('child could not complete'),
outcomeId: 'run-child',
sandboxBoundary: 'unresolved',
});
}
await notify(completedResult('graph completed'));
},
},
close: async () => {
releaseGraphWait?.();
},
};
}
return { runtime, target, close: async () => {} };
}
async function listSessions(): Promise<SessionSummary[]> {
return JSON.parse(process.env.MAKA_RUN_FIXTURE_SESSIONS ?? '[]') as SessionSummary[];
}
function completedResult(finalOutput: string): MakaRunOutcome {
return {
outcomeId: 'run-fixture',
status: 'completed',
finalOutput,
sandboxBoundary: 'none',
};
}
function failedResult(failureClass: string, message: string): MakaRunOutcome {
return {
outcomeId: 'run-fixture',
status: 'failed',
failure: { class: failureClass, message },
sandboxBoundary: 'none',
};
}
async function notify(result: MakaRunOutcome): Promise<void> {
await observer?.(result);
}
runMakaTextCliCore(process.argv.slice(2), { createContext, listSessions }).then(
(code) => {
process.exitCode = code;
},
(error) => {
process.stderr.write(`${error instanceof Error ? error.stack : String(error)}\n`);
process.exitCode = 1;
},
);