fix: use stable yaml parser for aipod specs
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
"dependencies": {
|
||||
"@openai/codex": "0.133.0",
|
||||
"pg": "^8.13.1",
|
||||
"yaml": "^2.8.0",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.10.0",
|
||||
@@ -124,5 +125,7 @@
|
||||
"undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
|
||||
|
||||
"xtend": ["xtend@4.0.2", "", {}, "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="],
|
||||
|
||||
"yaml": ["yaml@2.9.0", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA=="],
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -11,7 +11,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@openai/codex": "0.133.0",
|
||||
"pg": "^8.13.1"
|
||||
"pg": "^8.13.1",
|
||||
"yaml": "^2.8.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/pg": "^8.11.10",
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { mkdir, readdir, readFile, rm, stat, writeFile } from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
||||
import { AgentRunError } from "./errors.js";
|
||||
import type { AipodSpec, AipodSpecRecord, BackendProfile, CreateQueueTaskInput, ExecutionPolicy, JsonRecord, JsonValue, RenderAipodInput, RenderedAipodQueueTask, ResourceBundleRef, SessionRef, WorkspaceRef } from "./types.js";
|
||||
import { backendProfileSpec, isBackendProfile } from "./backend-profiles.js";
|
||||
import { asRecord, stableHash, validateCreateQueueTask, validateExecutionPolicy, validateResourceBundleRef, validateSessionRef } from "./validation.js";
|
||||
|
||||
declare const Bun: { YAML: { parse(text: string): unknown; stringify(value: unknown): string } };
|
||||
|
||||
const aipodApiVersion = "agentrun.pikastech.local/v0.1";
|
||||
const aipodKind = "AipodSpec";
|
||||
|
||||
@@ -39,7 +38,7 @@ export async function applyAipodSpec(input: unknown, dir = aipodSpecDirectory())
|
||||
const spec = aipodSpecFromInput(input, "api");
|
||||
await mkdir(dir, { recursive: true });
|
||||
const file = path.join(dir, `${fileSafeAipodName(spec.metadata.name)}.yaml`);
|
||||
await writeFile(file, Bun.YAML.stringify(spec), "utf8");
|
||||
await writeFile(file, stringifyYaml(spec), "utf8");
|
||||
const record = await loadAipodSpecFile(file);
|
||||
return { action: "aipod-spec-apply", mutation: true, item: summarizeAipodSpecRecord(record), valuesPrinted: false };
|
||||
}
|
||||
@@ -53,7 +52,7 @@ export async function deleteAipodSpec(name: string, dir = aipodSpecDirectory()):
|
||||
export function parseAipodSpecYaml(text: string, source = "stdin"): AipodSpec {
|
||||
let parsed: unknown;
|
||||
try {
|
||||
parsed = Bun.YAML.parse(text);
|
||||
parsed = parseYaml(text);
|
||||
} catch (error) {
|
||||
throw new AgentRunError("schema-invalid", `aipod-spec YAML parse failed: ${error instanceof Error ? error.message : String(error)}`, { httpStatus: 400, details: { source, valuesPrinted: false } });
|
||||
}
|
||||
|
||||
@@ -12,6 +12,10 @@ const selfTest: SelfTestCase = async (context) => {
|
||||
const server = await startManagerServer({ port: 0, host: "127.0.0.1", sourceCommit: "self-test", store: new MemoryAgentRunStore(), aipodSpecDir: path.join(context.root, "config", "aipods") });
|
||||
try {
|
||||
const client = new ManagerClient(server.baseUrl);
|
||||
const parsedWithoutBunGlobal = await runNodeParserCompat(context);
|
||||
assert.equal(parsedWithoutBunGlobal.name, "Artificer");
|
||||
assert.equal(parsedWithoutBunGlobal.hasBunGlobal, false);
|
||||
|
||||
const listed = await client.get("/api/v1/aipod-specs") as JsonRecord;
|
||||
assert.equal(listed.action, "aipod-spec-list");
|
||||
assert.equal((listed.items as JsonRecord[]).some((item) => item.name === "Artificer"), true);
|
||||
@@ -68,7 +72,7 @@ const selfTest: SelfTestCase = async (context) => {
|
||||
assert.equal(commands.some((item) => item.includes("aipod-specs render <name>")), true);
|
||||
assert.equal(commands.some((item) => item.includes("queue submit --aipod <name>")), true);
|
||||
assertNoSecretLeak(submitPlan);
|
||||
return { name: "aipod-spec", tests: ["aipod-spec-artificer-yaml-render", "aipod-spec-git-mirror-url", "queue-submit-aipod-dry-run", "aipod-cli-help"] };
|
||||
return { name: "aipod-spec", tests: ["aipod-spec-yaml-parser-runtime-compatible", "aipod-spec-artificer-yaml-render", "aipod-spec-git-mirror-url", "queue-submit-aipod-dry-run", "aipod-cli-help"] };
|
||||
} finally {
|
||||
await new Promise<void>((resolve) => server.server.close(() => resolve()));
|
||||
}
|
||||
@@ -76,6 +80,17 @@ const selfTest: SelfTestCase = async (context) => {
|
||||
|
||||
export default selfTest;
|
||||
|
||||
async function runNodeParserCompat(context: { root: string }): Promise<JsonRecord> {
|
||||
const script = `import { readFileSync } from "node:fs";
|
||||
import { parseAipodSpecYaml } from "./src/common/aipod-specs.ts";
|
||||
const spec = parseAipodSpecYaml(readFileSync("config/aipods/artificer.yaml", "utf8"), "selftest-no-bun-yaml");
|
||||
console.log(JSON.stringify({ name: spec.metadata.name, hasBunGlobal: typeof globalThis.Bun !== "undefined" }));`;
|
||||
const proc = spawn("node", ["--import", "tsx", "--eval", script], { cwd: context.root, stdio: ["ignore", "pipe", "pipe"] });
|
||||
const [stdout, stderr, code] = await Promise.all([readStream(proc.stdout), readStream(proc.stderr), new Promise<number | null>((resolve) => proc.on("close", resolve))]);
|
||||
assert.equal(code, 0, stderr || stdout);
|
||||
return JSON.parse(stdout) as JsonRecord;
|
||||
}
|
||||
|
||||
async function runCliJson(context: { root: string }, managerUrl: string, args: string[]): Promise<JsonRecord> {
|
||||
const proc = spawn(process.execPath, [`${context.root}/scripts/agentrun-cli.ts`, "--manager-url", managerUrl, ...args], { stdio: ["ignore", "pipe", "pipe"] });
|
||||
const [stdout, stderr, code] = await Promise.all([readStream(proc.stdout), readStream(proc.stderr), new Promise<number | null>((resolve) => proc.on("close", resolve))]);
|
||||
|
||||
Regular → Executable
Reference in New Issue
Block a user