-
Notifications
You must be signed in to change notification settings - Fork 23
Expand file tree
/
Copy pathgenerate.js
More file actions
153 lines (130 loc) · 4.54 KB
/
generate.js
File metadata and controls
153 lines (130 loc) · 4.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#!/usr/bin/env node
import { createClient, defineConfig } from "@hey-api/openapi-ts";
import * as fs from "fs/promises";
import { dirname } from "path";
import * as prettier from "prettier";
const CURRENT_SCHEMA_RELEASE = "v0.11.4";
await main();
async function main() {
if (!process.argv.includes("--skip-download")) {
await downloadSchemas(CURRENT_SCHEMA_RELEASE);
}
const metadata = JSON.parse(await fs.readFile("./schema/meta.json", "utf8"));
const schemaSrc = await fs.readFile("./schema/schema.json", "utf8");
const jsonSchema = JSON.parse(
schemaSrc.replaceAll("#/$defs/", "#/components/schemas/"),
);
await createClient({
input: {
openapi: "3.1.0",
info: {
title: "Agent Client Protocol",
version: "1.0.0",
},
components: {
schemas: jsonSchema.$defs,
},
},
output: {
path: "./src/schema",
postProcess: ["prettier"],
},
plugins: [
"zod",
{ bigInt: false, name: "@hey-api/transformers" },
"@hey-api/typescript",
],
});
const zodPath = "./src/schema/zod.gen.ts";
const zodSrc = await fs.readFile(zodPath, "utf8");
const zod = await prettier.format(
updateDocs(
zodSrc
.replace(`from "zod"`, `from "zod/v4"`)
.replaceAll(/z\.object\(/g, "z.looseObject(")
// Weird type issue
.replaceAll(
/z\.record\((?!z\.string\(\),\s*)([^)]+)\)/g,
"z.record(z.string(), $1)",
)
.replaceAll(
/z\.coerce\s*\.bigint\(\)\s*\.min\(BigInt\("-9223372036854775808"\),\s*\{\s*message:\s*"Invalid value: Expected int64 to be >= -9223372036854775808",\s*\}\s*\)\s*\.max\(BigInt\("9223372036854775807"\),\s*\{\s*message:\s*"Invalid value: Expected int64 to be <= 9223372036854775807",\s*\}\s*\)/gm,
"z.number()",
)
.replaceAll(
/z\.coerce\s*\.bigint\(\)\s*\.gte\(BigInt\(0\)\)\s*\.max\(BigInt\("18446744073709551615"\),\s*\{\s*message:\s*"Invalid value: Expected uint64 to be <= 18446744073709551615",\s*\}\s*\)/gm,
"z.number()",
),
),
{ parser: "typescript" },
);
await fs.writeFile(zodPath, zod);
const tsPath = "./src/schema/types.gen.ts";
const tsSrc = await fs.readFile(tsPath, "utf8");
const ts = await prettier.format(
updateDocs(
tsSrc.replace(
`export type ClientOptions`,
`// eslint-disable-next-line @typescript-eslint/no-unused-vars\ntype ClientOptions`,
),
),
{ parser: "typescript" },
);
await fs.writeFile(tsPath, ts);
const meta = await prettier.format(
`export const AGENT_METHODS = ${JSON.stringify(metadata.agentMethods, null, 2)} as const;
export const CLIENT_METHODS = ${JSON.stringify(metadata.clientMethods, null, 2)} as const;
export const PROTOCOL_VERSION = ${metadata.version};
`,
{ parser: "typescript" },
);
const indexPath = "./src/schema/index.ts";
const indexSrc = await fs.readFile(indexPath, "utf8");
await fs.writeFile(
indexPath,
`${indexSrc.replace(/\s*ClientOptions,/, "")}\n${meta}`,
);
}
/**
* Downloads a file from a URL to a local path
* @param {string} url - The URL to download from
* @param {string} outputPath - The local path to save the file
*/
async function downloadFile(url, outputPath) {
await fs.mkdir(dirname(outputPath), { recursive: true });
const response = await fetch(url);
if (response.status === 302 || response.status === 301) {
// Follow redirects
await downloadFile(response.headers.location, outputPath);
return;
}
if (response.status !== 200) {
throw new Error(`Failed to download ${url}: ${response.status}`);
}
await fs.writeFile(outputPath, response.body);
}
/**
* Downloads schema files from a GitHub release
* @param {string} tag - The GitHub release tag (e.g., "v0.5.0")
*/
async function downloadSchemas(tag) {
const baseUrl = `https://github.com/agentclientprotocol/agent-client-protocol/releases/download/${tag}`;
const files = [
{ url: `${baseUrl}/schema.unstable.json`, path: "./schema/schema.json" },
{ url: `${baseUrl}/meta.unstable.json`, path: "./schema/meta.json" },
];
console.log(`Downloading schemas from release ${tag}...`);
for (const file of files) {
await downloadFile(file.url, file.path);
}
console.log("Schema files downloaded successfully\n");
}
function updateDocs(src) {
let result = src;
// Replace UNSTABLE comments with @experimental at the end of the comment block
result = result.replace(
/(\/\*\*[\s\S]*?\*\*UNSTABLE\*\*[\s\S]*?)(\n\s*)\*\//g,
"$1$2*$2* @experimental$2*/",
);
return result;
}