源码快照 @ 2026-09-02 (source-only, 剔除非源码素材)
This commit is contained in:
@@ -0,0 +1,144 @@
|
||||
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();
|
||||
}
|
||||
Reference in New Issue
Block a user