Files

145 lines
4.5 KiB
JavaScript

import assert from "node:assert/strict";
import { findFreePort, makeClient, parseArgs, spawnOpencodeServe, waitForHealthy } from "./_util.mjs";
const args = parseArgs(process.argv.slice(2));
const directory = args.get("dir") ?? process.cwd();
const port = await findFreePort();
const server = await spawnOpencodeServe({ directory, port });
const results = {
ok: true,
baseUrl: server.baseUrl,
directory: server.cwd,
steps: [],
};
function formatError(e) {
if (e instanceof Error) return e.message;
try {
return JSON.stringify(e);
} catch {
return String(e);
}
}
function step(name, fn) {
results.steps.push({ name, status: "running" });
const idx = results.steps.length - 1;
return Promise.resolve()
.then(fn)
.then((data) => {
results.steps[idx] = { name, status: "ok", data };
})
.catch((e) => {
results.ok = false;
results.steps[idx] = { name, status: "error", error: formatError(e) };
throw e;
});
}
const targetPath = args.get("path") ?? "src/app/pages/session.tsx";
const absolutePath = (() => {
const trimmed = String(targetPath || "").trim();
if (!trimmed) return "";
if (trimmed.startsWith("/")) return trimmed;
if (/^[a-zA-Z]:\\/.test(trimmed)) return trimmed;
return (server.cwd + "/" + trimmed).replace("//", "/");
})();
const fileUrl = absolutePath ? `file://${absolutePath}` : "";
try {
const client = makeClient({ baseUrl: server.baseUrl, directory: server.cwd });
await step("health", async () => waitForHealthy(client));
let sessionId = "";
await step("session.create", async () => {
const session = await client.session.create({ title: "OpenWork mention-send" });
sessionId = session.id;
assert.ok(sessionId);
return { id: session.id };
});
async function messagesSummary(label) {
const msgs = await client.session.messages({ sessionID: sessionId, limit: 50 });
const roles = msgs.map((m) => m?.role ?? m?.info?.role ?? null);
const user = msgs.filter((m) => (m?.role ?? m?.info?.role ?? null) === "user");
const last = user[user.length - 1];
const lastParts = Array.isArray(last?.parts) ? last.parts : [];
return {
label,
total: msgs.length,
userCount: user.length,
roles: Array.from(new Set(roles)),
lastMessageRole: msgs.length ? (msgs[msgs.length - 1]?.role ?? msgs[msgs.length - 1]?.info?.role ?? null) : null,
sampleKeys: msgs.length ? Object.keys(msgs[0] ?? {}) : [],
sample: msgs.length
? {
role: msgs[0]?.role ?? msgs[0]?.info?.role ?? null,
parts: Array.isArray(msgs[0]?.parts) ? msgs[0].parts.map((p) => p.type) : [],
}
: null,
lastUserParts: lastParts.map((p) => p.type),
lastUserText: (lastParts.find((p) => p.type === "text")?.text ?? ""),
};
}
await step("messages.initial", async () => messagesSummary("initial"));
await step("prompt.invalidFilePart", async () => {
// Mirrors the bug in OpenWork: sending a file mention with only {path}.
try {
await client.session.prompt({
sessionID: sessionId,
noReply: true,
parts: [
{ type: "text", text: " " },
{ type: "file", path: targetPath },
],
});
throw new Error("expected prompt to fail validation, but it succeeded");
} catch (e) {
return { expectedFailure: true, error: formatError(e) };
}
});
await step("prompt.spaceTextWithValidFile", async () => {
assert.ok(fileUrl, "missing file url");
await client.session.prompt({
sessionID: sessionId,
noReply: true,
parts: [
{ type: "text", text: " " },
{ type: "file", mime: "text/plain", url: fileUrl, filename: "session.tsx" },
],
});
return messagesSummary("after-space-text");
});
await step("prompt.fixedPayload", async () => {
assert.ok(fileUrl, "missing file url");
await client.session.prompt({
sessionID: sessionId,
noReply: true,
parts: [
{ type: "text", text: `@${targetPath}` },
{ type: "file", mime: "text/plain", url: fileUrl, filename: "session.tsx" },
],
});
const summary = await messagesSummary("after-fixed");
assert.ok(summary.lastUserText.includes(targetPath), "expected last user text to include the mentioned path");
return summary;
});
console.log(JSON.stringify(results, null, 2));
} catch (e) {
results.ok = false;
results.error = formatError(e);
results.stderr = server.getStderr();
console.error(JSON.stringify(results, null, 2));
process.exitCode = 1;
} finally {
await server.close();
}