297 lines
14 KiB
JavaScript
297 lines
14 KiB
JavaScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { chmod, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
|
import os from "node:os";
|
|
import path from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
import { spawnSync } from "node:child_process";
|
|
|
|
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
|
|
test("codex app-server protocol snapshot script records schema, help and method inventory", async () => {
|
|
const runtimeRoot = await mkdtemp(path.join(os.tmpdir(), "boss-codex-protocol-snapshot-"));
|
|
const fakeBin = path.join(runtimeRoot, "codex");
|
|
const outDir = path.join(runtimeRoot, "snapshot");
|
|
await writeFile(
|
|
fakeBin,
|
|
`#!/usr/bin/env node
|
|
const fs = require("node:fs");
|
|
const path = require("node:path");
|
|
const args = process.argv.slice(2);
|
|
function writeGenerated(out, name, content) {
|
|
fs.mkdirSync(out, { recursive: true });
|
|
fs.writeFileSync(path.join(out, name), content);
|
|
}
|
|
if (args.includes("--version")) {
|
|
console.log("codex-cli 0.135.0-alpha.1");
|
|
process.exit(0);
|
|
}
|
|
if (args[0] === "app-server" && args.includes("--help")) {
|
|
console.log("Usage: codex app-server [OPTIONS]");
|
|
console.log("--listen <URL> stdio:// unix:// ws://IP:PORT off");
|
|
process.exit(0);
|
|
}
|
|
if (args[0] === "app-server" && args[1] === "generate-json-schema") {
|
|
const out = args[args.indexOf("--out") + 1];
|
|
writeGenerated(out, "codex_app_server_protocol.schemas.json", JSON.stringify({
|
|
anyOf: [
|
|
{ properties: { method: { const: "thread/start" } } },
|
|
{ properties: { method: { const: "thread/inject_items" } } },
|
|
{ properties: { method: { const: "thread/archive" } } },
|
|
{ properties: { method: { const: "thread/archived" } } },
|
|
{ properties: { method: { const: "thread/unarchive" } } },
|
|
{ properties: { method: { const: "thread/unarchived" } } },
|
|
{ properties: { method: { const: "thread/fork" } } },
|
|
{ properties: { method: { const: "thread/closed" } } },
|
|
{ properties: { method: { const: "thread/compact/start" } } },
|
|
{ properties: { method: { const: "thread/rollback" } } },
|
|
{ properties: { method: { const: "thread/name/set" } } },
|
|
{ properties: { method: { const: "thread/name/updated" } } },
|
|
{ properties: { method: { const: "thread/metadata/update" } } },
|
|
{ properties: { method: { const: "thread/shellCommand" } } },
|
|
{ properties: { method: { const: "thread/unsubscribe" } } },
|
|
{ properties: { method: { const: "thread/started" } } },
|
|
{ properties: { method: { const: "plugin/install" } } },
|
|
{ properties: { method: { const: "plugin/installed" } } },
|
|
{ properties: { method: { const: "plugin/uninstall" } } },
|
|
{ properties: { method: { const: "plugin/read" } } },
|
|
{ properties: { method: { const: "plugin/skill/read" } } },
|
|
{ properties: { method: { const: "plugin/share/save" } } },
|
|
{ properties: { method: { const: "plugin/share/checkout" } } },
|
|
{ properties: { method: { const: "plugin/share/delete" } } },
|
|
{ properties: { method: { const: "plugin/share/updateTargets" } } },
|
|
{ properties: { method: { const: "plugin/share/list" } } },
|
|
{ properties: { method: { const: "account/login/start" } } },
|
|
{ properties: { method: { const: "account/login/cancel" } } },
|
|
{ properties: { method: { const: "account/login/completed" } } },
|
|
{ properties: { method: { const: "account/logout" } } },
|
|
{ properties: { method: { const: "account/chatgptAuthTokens/refresh" } } },
|
|
{ properties: { method: { const: "account/sendAddCreditsNudgeEmail" } } },
|
|
{ properties: { method: { const: "config/value/write" } } },
|
|
{ properties: { method: { const: "config/batchWrite" } } },
|
|
{ properties: { method: { const: "config/mcpServer/reload" } } },
|
|
{ properties: { method: { const: "skills/config/write" } } },
|
|
{ properties: { method: { const: "command/exec" } } },
|
|
{ properties: { method: { const: "command/exec/write" } } },
|
|
{ properties: { method: { const: "command/exec/resize" } } },
|
|
{ properties: { method: { const: "command/exec/terminate" } } },
|
|
{ properties: { method: { const: "fs/readFile" } } },
|
|
{ properties: { method: { const: "fs/readDirectory" } } },
|
|
{ properties: { method: { const: "fs/getMetadata" } } },
|
|
{ properties: { method: { const: "fs/writeFile" } } },
|
|
{ properties: { method: { const: "fs/createDirectory" } } },
|
|
{ properties: { method: { const: "fs/remove" } } },
|
|
{ properties: { method: { const: "fs/copy" } } },
|
|
{ properties: { method: { const: "fs/watch" } } },
|
|
{ properties: { method: { const: "fs/unwatch" } } },
|
|
{ properties: { method: { const: "externalAgentConfig/detect" } } },
|
|
{ properties: { method: { const: "externalAgentConfig/import" } } },
|
|
{ properties: { method: { const: "externalAgentConfig/import/completed" } } },
|
|
{ properties: { method: { const: "marketplace/add" } } },
|
|
{ properties: { method: { const: "marketplace/remove" } } },
|
|
{ properties: { method: { const: "marketplace/upgrade" } } },
|
|
{ properties: { method: { const: "experimentalFeature/list" } } },
|
|
{ properties: { method: { const: "experimentalFeature/enablement/set" } } },
|
|
{ properties: { method: { const: "review/start" } } },
|
|
{ properties: { method: { const: "windowsSandbox/readiness" } } },
|
|
{ properties: { method: { const: "windowsSandbox/setupStart" } } },
|
|
{ properties: { method: { const: "windowsSandbox/setupCompleted" } } },
|
|
{ properties: { method: { const: "fuzzyFileSearch/sessionUpdated" } } },
|
|
{ properties: { method: { const: "fuzzyFileSearch/sessionCompleted" } } },
|
|
{ properties: { method: { const: "mcpServer/oauth/login" } } },
|
|
{ properties: { method: { const: "mcpServer/oauthLogin/completed" } } },
|
|
{ properties: { method: { const: "mcpServer/resource/read" } } },
|
|
{ properties: { method: { const: "mcpServer/tool/call" } } },
|
|
{ properties: { method: { const: "mcpServer/elicitation/request" } } },
|
|
{ properties: { method: { const: "item/tool/requestUserInput" } } },
|
|
{ properties: { method: { const: "item/permissions/requestApproval" } } },
|
|
{ properties: { method: { const: "process/outputDelta" } } },
|
|
{ properties: { method: { const: "process/exited" } } },
|
|
{ properties: { method: { const: "rawResponseItem/completed" } } },
|
|
{ properties: { method: { const: "thread/approveGuardianDeniedAction" } } },
|
|
{ properties: { method: { const: "skills/changed" } } },
|
|
{ properties: { method: { const: "skills/extraRoots/set" } } },
|
|
{ properties: { method: { const: "hooks/list" } } },
|
|
{ properties: { method: { const: "turn/interrupt" } } },
|
|
{ properties: { method: { const: "turn/start" } } }
|
|
]
|
|
}, null, 2));
|
|
process.exit(0);
|
|
}
|
|
if (args[0] === "app-server" && args[1] === "generate-ts") {
|
|
const out = args[args.indexOf("--out") + 1];
|
|
writeGenerated(out, "ClientRequest.ts", 'export type ClientRequest = { "method": "thread/start" } | { "method": "skills/extraRoots/set" } | { "method": "hooks/list" } | { "method": "turn/start" };\\n');
|
|
process.exit(0);
|
|
}
|
|
console.error("unexpected args " + args.join(" "));
|
|
process.exit(2);
|
|
`,
|
|
"utf8",
|
|
);
|
|
await chmod(fakeBin, 0o755);
|
|
|
|
try {
|
|
const result = spawnSync(
|
|
process.execPath,
|
|
[
|
|
"scripts/codex-app-server-protocol-snapshot.mjs",
|
|
"--codex-bin",
|
|
fakeBin,
|
|
"--out-dir",
|
|
outDir,
|
|
],
|
|
{
|
|
cwd: repoRoot,
|
|
encoding: "utf8",
|
|
},
|
|
);
|
|
|
|
assert.equal(result.status, 0, result.stderr);
|
|
const manifest = JSON.parse(await readFile(path.join(outDir, "0.135.0-alpha.1", "manifest.json"), "utf8"));
|
|
assert.equal(manifest.codexVersion, "0.135.0-alpha.1");
|
|
assert.equal(manifest.supports.wsTransport, true);
|
|
assert.equal(manifest.supports.unixTransport, true);
|
|
assert.equal(manifest.supports.threadInjectItems, true);
|
|
assert.equal(manifest.supports.skillsExtraRoots, true);
|
|
assert.equal(manifest.supports.hooksList, true);
|
|
assert.equal(manifest.supports.threadArchive, true);
|
|
assert.equal(manifest.supports.threadUnarchive, true);
|
|
assert.equal(manifest.supports.threadFork, true);
|
|
assert.equal(manifest.supports.threadCompactStart, true);
|
|
assert.equal(manifest.supports.threadRollback, true);
|
|
assert.equal(manifest.supports.threadNameSet, true);
|
|
assert.equal(manifest.supports.threadMetadataUpdate, true);
|
|
assert.equal(manifest.supports.threadShellCommand, true);
|
|
assert.equal(manifest.supports.threadUnsubscribe, true);
|
|
assert.equal(manifest.supports.turnInterrupt, true);
|
|
assert.equal(manifest.supports.pluginInstall, true);
|
|
assert.equal(manifest.supports.pluginUninstall, true);
|
|
assert.equal(manifest.supports.pluginRead, true);
|
|
assert.equal(manifest.supports.pluginSkillRead, true);
|
|
assert.equal(manifest.supports.pluginShare, true);
|
|
assert.equal(manifest.supports.accountLogin, true);
|
|
assert.equal(manifest.supports.accountLogout, true);
|
|
assert.equal(manifest.supports.accountTokenRefresh, true);
|
|
assert.equal(manifest.supports.accountAddCreditsNudge, true);
|
|
assert.equal(manifest.supports.configValueWrite, true);
|
|
assert.equal(manifest.supports.configBatchWrite, true);
|
|
assert.equal(manifest.supports.configMcpServerReload, true);
|
|
assert.equal(manifest.supports.skillsConfigWrite, true);
|
|
assert.equal(manifest.supports.commandExec, true);
|
|
assert.equal(manifest.supports.commandExecWrite, true);
|
|
assert.equal(manifest.supports.commandExecResize, true);
|
|
assert.equal(manifest.supports.commandExecTerminate, true);
|
|
assert.equal(manifest.supports.fsRead, true);
|
|
assert.equal(manifest.supports.fsWrite, true);
|
|
assert.equal(manifest.supports.fsWatch, true);
|
|
assert.equal(manifest.supports.externalAgentImport, true);
|
|
assert.equal(manifest.supports.marketplaceAdd, true);
|
|
assert.equal(manifest.supports.marketplaceRemove, true);
|
|
assert.equal(manifest.supports.marketplaceUpgrade, true);
|
|
assert.equal(manifest.supports.experimentalFeatureEnablementSet, true);
|
|
assert.equal(manifest.supports.reviewStart, true);
|
|
assert.equal(manifest.supports.windowsSandboxReadiness, true);
|
|
assert.equal(manifest.supports.windowsSandboxSetupStart, true);
|
|
assert.equal(manifest.supports.fuzzyFileSearchEvents, true);
|
|
assert.equal(manifest.supports.mcpOAuthLogin, true);
|
|
assert.equal(manifest.supports.mcpResourceRead, true);
|
|
assert.equal(manifest.supports.mcpToolCall, true);
|
|
assert.equal(manifest.supports.mcpElicitation, true);
|
|
assert.equal(manifest.supports.toolRequestUserInput, true);
|
|
assert.equal(manifest.supports.permissionRequestApproval, true);
|
|
assert.equal(manifest.supports.guardianDeniedActionApproval, true);
|
|
assert.equal(manifest.supports.processEvents, true);
|
|
assert.equal(manifest.supports.rawResponseCompleted, true);
|
|
assert.equal(manifest.supports.skillsChanged, true);
|
|
assert.equal(manifest.supports.pluginInstalledNotification, true);
|
|
assert.equal(manifest.supports.threadLifecycleEvents, true);
|
|
assert.deepEqual(manifest.methods, [
|
|
"account/chatgptAuthTokens/refresh",
|
|
"account/login/cancel",
|
|
"account/login/completed",
|
|
"account/login/start",
|
|
"account/logout",
|
|
"account/sendAddCreditsNudgeEmail",
|
|
"command/exec",
|
|
"command/exec/resize",
|
|
"command/exec/terminate",
|
|
"command/exec/write",
|
|
"config/batchWrite",
|
|
"config/mcpServer/reload",
|
|
"config/value/write",
|
|
"experimentalFeature/enablement/set",
|
|
"experimentalFeature/list",
|
|
"externalAgentConfig/detect",
|
|
"externalAgentConfig/import",
|
|
"externalAgentConfig/import/completed",
|
|
"fs/copy",
|
|
"fs/createDirectory",
|
|
"fs/getMetadata",
|
|
"fs/readDirectory",
|
|
"fs/readFile",
|
|
"fs/remove",
|
|
"fs/unwatch",
|
|
"fs/watch",
|
|
"fs/writeFile",
|
|
"fuzzyFileSearch/sessionCompleted",
|
|
"fuzzyFileSearch/sessionUpdated",
|
|
"hooks/list",
|
|
"item/permissions/requestApproval",
|
|
"item/tool/requestUserInput",
|
|
"marketplace/add",
|
|
"marketplace/remove",
|
|
"marketplace/upgrade",
|
|
"mcpServer/elicitation/request",
|
|
"mcpServer/oauth/login",
|
|
"mcpServer/oauthLogin/completed",
|
|
"mcpServer/resource/read",
|
|
"mcpServer/tool/call",
|
|
"plugin/install",
|
|
"plugin/installed",
|
|
"plugin/read",
|
|
"plugin/share/checkout",
|
|
"plugin/share/delete",
|
|
"plugin/share/list",
|
|
"plugin/share/save",
|
|
"plugin/share/updateTargets",
|
|
"plugin/skill/read",
|
|
"plugin/uninstall",
|
|
"process/exited",
|
|
"process/outputDelta",
|
|
"rawResponseItem/completed",
|
|
"review/start",
|
|
"skills/changed",
|
|
"skills/config/write",
|
|
"skills/extraRoots/set",
|
|
"thread/approveGuardianDeniedAction",
|
|
"thread/archive",
|
|
"thread/archived",
|
|
"thread/closed",
|
|
"thread/compact/start",
|
|
"thread/fork",
|
|
"thread/inject_items",
|
|
"thread/metadata/update",
|
|
"thread/name/set",
|
|
"thread/name/updated",
|
|
"thread/rollback",
|
|
"thread/shellCommand",
|
|
"thread/start",
|
|
"thread/started",
|
|
"thread/unarchive",
|
|
"thread/unarchived",
|
|
"thread/unsubscribe",
|
|
"turn/interrupt",
|
|
"turn/start",
|
|
"windowsSandbox/readiness",
|
|
"windowsSandbox/setupCompleted",
|
|
"windowsSandbox/setupStart",
|
|
]);
|
|
assert.match(
|
|
await readFile(path.join(outDir, "0.135.0-alpha.1", "app-server-help.txt"), "utf8"),
|
|
/ws:\/\/IP:PORT/,
|
|
);
|
|
} finally {
|
|
await rm(runtimeRoot, { recursive: true, force: true });
|
|
}
|
|
});
|