40 lines
1.9 KiB
TypeScript
40 lines
1.9 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import test from "node:test";
|
|
import { callExecLua, formatFailure, startBridge, startCraftos, waitForComputers } from "./harness.js";
|
|
|
|
test("exec-lua runs code through the real TrapOS mcp-computer program", async () => {
|
|
const bridge = await startBridge();
|
|
const craftos = startCraftos("/programs/mcp-computer.lua", {
|
|
mountRepo: true,
|
|
shellArgs: [bridge.linkUrl],
|
|
timeoutMs: 15_000,
|
|
});
|
|
try {
|
|
await waitForComputers(bridge.registry, 1, 12_000);
|
|
const text = await callExecLua(bridge.mcpUrl, 0, "print('hello from exec'); return 2 + 3");
|
|
assert.match(text, /^computer: 0 \(Label: null\)\nok: true\nreturns: \[\{.*\}\]\noutput:\nhello from exec$/);
|
|
assert.match(text, /"type":"number"/);
|
|
assert.match(text, /"value":5/);
|
|
|
|
const runtimeError = await callExecLua(bridge.mcpUrl, 0, "print('before runtime error'); error('boom', 0)");
|
|
assert.equal(runtimeError, "computer: 0 (Label: null)\nok: false\nerror: boom\noutput:\nbefore runtime error");
|
|
|
|
const syntaxError = await callExecLua(bridge.mcpUrl, 0, "print('unterminated'\nreturn 1");
|
|
assert.match(syntaxError, /^computer: 0 \(Label: null\)\nok: false\nerror: .+\noutput:$/);
|
|
assert.match(syntaxError, /near|expected|unexpected/);
|
|
|
|
const visibleWrite = await callExecLua(bridge.mcpUrl, 0, "term.clear(); term.setCursorPos(1, 1); term.write('visible'); return 'done'");
|
|
assert.match(visibleWrite, /^computer: 0 \(Label: null\)\nok: true\nreturns: \[\{.*\}\]\noutput:$/);
|
|
assert.match(visibleWrite, /"type":"string"/);
|
|
assert.match(visibleWrite, /"value":"done"/);
|
|
} catch (error) {
|
|
craftos.abort();
|
|
const result = await craftos.done;
|
|
throw new Error(formatFailure(error instanceof Error ? error.message : String(error), result.output), { cause: error });
|
|
} finally {
|
|
craftos.abort();
|
|
await craftos.done;
|
|
await bridge.close();
|
|
}
|
|
});
|