mirror of
https://github.com/anomalyco/opencode.git
synced 2026-07-10 00:28:29 +00:00
chore: generate
This commit is contained in:
parent
a8983bd2c7
commit
1b9b260458
8 changed files with 1120 additions and 4357 deletions
|
|
@ -165,9 +165,7 @@ const api = OpenAPI.fromSpec({
|
|||
spec: await Bun.file("openapi.json").json(), // parsed document (no YAML)
|
||||
auth: {
|
||||
resolve: ({ name, scopes, operation }) =>
|
||||
name === "BearerAuth"
|
||||
? Effect.succeed({ type: "bearer", token })
|
||||
: Effect.succeed(undefined),
|
||||
name === "BearerAuth" ? Effect.succeed({ type: "bearer", token }) : Effect.succeed(undefined),
|
||||
},
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -46,9 +46,7 @@ export const invoke = (plan: Plan, input: unknown): Effect.Effect<unknown, unkno
|
|||
)
|
||||
}
|
||||
if (json && Option.isNone(decoded)) {
|
||||
return yield* Effect.fail(
|
||||
toolError(`${plan.operation.method} ${plan.operation.path} returned malformed JSON.`),
|
||||
)
|
||||
return yield* Effect.fail(toolError(`${plan.operation.method} ${plan.operation.path} returned malformed JSON.`))
|
||||
}
|
||||
return parsed
|
||||
})
|
||||
|
|
@ -208,8 +206,9 @@ const buildUrl = (plan: Plan, input: Readonly<Record<string, unknown>>): string
|
|||
return toolError(`Missing required path parameter '${field.inputName}'.`)
|
||||
}
|
||||
const fieldValue = serializeSimple(field, item, (value) =>
|
||||
encodeURIComponent(value).replace(/[!'()*]/g, (character) =>
|
||||
`%${character.charCodeAt(0).toString(16).toUpperCase()}`,
|
||||
encodeURIComponent(value).replace(
|
||||
/[!'()*]/g,
|
||||
(character) => `%${character.charCodeAt(0).toString(16).toUpperCase()}`,
|
||||
),
|
||||
)
|
||||
if (fieldValue instanceof ToolError) return fieldValue
|
||||
|
|
@ -271,10 +270,7 @@ const serializeQuery = (
|
|||
if (value.some((item) => item === undefined || (item !== null && typeof item === "object"))) {
|
||||
return toolError(`Query parameter '${field.inputName}' contains an unsupported nested value.`)
|
||||
}
|
||||
return value.reduce(
|
||||
(current, item) => HttpClientRequest.appendUrlParam(current, field.name, String(item)),
|
||||
request,
|
||||
)
|
||||
return value.reduce((current, item) => HttpClientRequest.appendUrlParam(current, field.name, String(item)), request)
|
||||
}
|
||||
if (isRecord(value) && field.explode) {
|
||||
return Object.entries(value).reduce<HttpClientRequest.HttpClientRequest | ToolError>((current, [name, item]) => {
|
||||
|
|
@ -289,11 +285,15 @@ const serializeQuery = (
|
|||
return rendered instanceof ToolError ? rendered : HttpClientRequest.appendUrlParam(request, field.name, rendered)
|
||||
}
|
||||
|
||||
const readResponseBody = (response: HttpClientResponse.HttpClientResponse, plan: Plan): Effect.Effect<string, ToolError> =>
|
||||
const readResponseBody = (
|
||||
response: HttpClientResponse.HttpClientResponse,
|
||||
plan: Plan,
|
||||
): Effect.Effect<string, ToolError> =>
|
||||
Effect.gen(function* () {
|
||||
const contentLength = response.headers["content-length"]
|
||||
const parsedSize = contentLength === undefined ? undefined : Number.parseInt(contentLength, 10)
|
||||
const declaredSize = parsedSize !== undefined && Number.isSafeInteger(parsedSize) && parsedSize >= 0 ? parsedSize : undefined
|
||||
const declaredSize =
|
||||
parsedSize !== undefined && Number.isSafeInteger(parsedSize) && parsedSize >= 0 ? parsedSize : undefined
|
||||
if (declaredSize !== undefined && declaredSize > maxResponseBodyBytes) {
|
||||
return yield* Effect.fail(toolError(`${plan.operation.method} ${plan.operation.path} response exceeds 50 MiB.`))
|
||||
}
|
||||
|
|
@ -304,7 +304,9 @@ const readResponseBody = (response: HttpClientResponse.HttpClientResponse, plan:
|
|||
return Effect.fail(toolError(`${plan.operation.method} ${plan.operation.path} response exceeds 50 MiB.`))
|
||||
}
|
||||
if (size + chunk.byteLength > body.byteLength) {
|
||||
const grown = Buffer.allocUnsafe(Math.min(maxResponseBodyBytes, Math.max(size + chunk.byteLength, body.byteLength * 2)))
|
||||
const grown = Buffer.allocUnsafe(
|
||||
Math.min(maxResponseBodyBytes, Math.max(size + chunk.byteLength, body.byteLength * 2)),
|
||||
)
|
||||
body.copy(grown, 0, 0, size)
|
||||
body = grown
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,7 +78,9 @@ const isBinaryMediaType = (document: Document, mediaType: string, value: unknown
|
|||
return isRecord(schema) && schema.format === "binary"
|
||||
}
|
||||
|
||||
const jsonContent = (content: Record<string, unknown>): { readonly mediaType: string; readonly schema: unknown } | undefined => {
|
||||
const jsonContent = (
|
||||
content: Record<string, unknown>,
|
||||
): { readonly mediaType: string; readonly schema: unknown } | undefined => {
|
||||
const entry = Object.entries(content).find(([mediaType]) => isJsonMediaType(mediaType))
|
||||
return entry !== undefined && isRecord(entry[1]) ? { mediaType: entry[0], schema: entry[1].schema } : undefined
|
||||
}
|
||||
|
|
@ -344,7 +346,7 @@ export const operationOutput = (
|
|||
if (outcomes.length === 0) return { ok: true, value: undefined }
|
||||
return {
|
||||
ok: true,
|
||||
value: withDefinitions(outcomes.length === 1 ? outcomes[0] ?? {} : { anyOf: outcomes }, definitions),
|
||||
value: withDefinitions(outcomes.length === 1 ? (outcomes[0] ?? {}) : { anyOf: outcomes }, definitions),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -380,7 +382,9 @@ export const operationPath = (
|
|||
namespaces: ReadonlySet<string>,
|
||||
): ReadonlyArray<string> => {
|
||||
const raw = nonEmptyString(operation.operationId)
|
||||
const segments = (raw === undefined ? [fallbackOperationId(method, path)] : raw.split(".")).map(sanitizeOperationSegment)
|
||||
const segments = (raw === undefined ? [fallbackOperationId(method, path)] : raw.split(".")).map(
|
||||
sanitizeOperationSegment,
|
||||
)
|
||||
if (isOperationPathAvailable(segments, used, namespaces)) return segments
|
||||
const conflict = segments.slice(0, -1).findIndex((_, index) => used.has(segments.slice(0, index + 1).join(".")))
|
||||
if (conflict >= 0 && conflict + 1 < segments.length) {
|
||||
|
|
|
|||
|
|
@ -93,16 +93,10 @@
|
|||
},
|
||||
"role": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"admin",
|
||||
"member"
|
||||
]
|
||||
"enum": ["admin", "member"]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name",
|
||||
"email"
|
||||
],
|
||||
"required": ["name", "email"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
|
|
@ -143,9 +137,7 @@
|
|||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"query"
|
||||
],
|
||||
"required": ["query"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
|
|
@ -216,17 +208,10 @@
|
|||
},
|
||||
"role": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"admin",
|
||||
"member"
|
||||
]
|
||||
"enum": ["admin", "member"]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"name",
|
||||
"email"
|
||||
],
|
||||
"required": ["id", "name", "email"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
|
|
|
|||
5356
packages/codemode/test/fixtures/opencode-v2-openapi.json
vendored
5356
packages/codemode/test/fixtures/opencode-v2-openapi.json
vendored
File diff suppressed because it is too large
Load diff
|
|
@ -54,7 +54,9 @@ const json = (value: unknown, status = 200) =>
|
|||
|
||||
const singleOperation = (operation: Record<string, unknown>, method = "get"): Document => ({
|
||||
openapi: "3.1.0",
|
||||
paths: { "/test": { [method]: { operationId: "test", responses: { 200: { description: "Success" } }, ...operation } } },
|
||||
paths: {
|
||||
"/test": { [method]: { operationId: "test", responses: { 200: { description: "Success" } }, ...operation } },
|
||||
},
|
||||
})
|
||||
|
||||
describe("OpenAPI.fromSpec", () => {
|
||||
|
|
@ -94,7 +96,12 @@ describe("OpenAPI.fromSpec", () => {
|
|||
const remove = toolAt(api.tools, "users.remove")
|
||||
|
||||
expect(api.skipped).toEqual([])
|
||||
if (!Tool.isDefinition(get) || !Tool.isDefinition(create) || !Tool.isDefinition(search) || !Tool.isDefinition(remove)) {
|
||||
if (
|
||||
!Tool.isDefinition(get) ||
|
||||
!Tool.isDefinition(create) ||
|
||||
!Tool.isDefinition(search) ||
|
||||
!Tool.isDefinition(remove)
|
||||
) {
|
||||
throw new Error("happy-path fixture did not generate every operation")
|
||||
}
|
||||
expect(inputTypeScript(get)).toBe(
|
||||
|
|
@ -110,7 +117,8 @@ describe("OpenAPI.fromSpec", () => {
|
|||
|
||||
const result = await Effect.runPromise(
|
||||
CodeMode.make({ tools: { api: api.tools } })
|
||||
.execute(`
|
||||
.execute(
|
||||
`
|
||||
const user = await tools.api.users.get({
|
||||
userId: "user-1",
|
||||
include: ["profile", "permissions"],
|
||||
|
|
@ -128,7 +136,8 @@ describe("OpenAPI.fromSpec", () => {
|
|||
})
|
||||
const removed = await tools.api.users.remove({ userId: "user-1" })
|
||||
return { user, created, summary, removed }
|
||||
`)
|
||||
`,
|
||||
)
|
||||
.pipe(Effect.provide(client.layer)),
|
||||
)
|
||||
|
||||
|
|
@ -482,9 +491,9 @@ describe("OpenAPI.fromSpec", () => {
|
|||
expect(url.searchParams.get("nullable")).toBe("null")
|
||||
expect(url.searchParams.get("constructor")).toBe("safe")
|
||||
expect(client.requests[0]!.headers.meta).toBe("a=b,c=d")
|
||||
await expect(
|
||||
Effect.runPromise(tool.run({ keys: [undefined] }).pipe(Effect.provide(client.layer))),
|
||||
).rejects.toThrow("unsupported nested value")
|
||||
await expect(Effect.runPromise(tool.run({ keys: [undefined] }).pipe(Effect.provide(client.layer)))).rejects.toThrow(
|
||||
"unsupported nested value",
|
||||
)
|
||||
})
|
||||
|
||||
test("skips unsupported parameter encodings and malformed security", () => {
|
||||
|
|
@ -586,7 +595,10 @@ describe("OpenAPI.fromSpec", () => {
|
|||
|
||||
test("applies authentication carriers without prototype or collision loss", async () => {
|
||||
const client = recordingClient(() => json({ ok: true }))
|
||||
const authenticated = (security: ReadonlyArray<Record<string, ReadonlyArray<string>>>, schemes: Record<string, unknown>) =>
|
||||
const authenticated = (
|
||||
security: ReadonlyArray<Record<string, ReadonlyArray<string>>>,
|
||||
schemes: Record<string, unknown>,
|
||||
) =>
|
||||
OpenAPI.fromSpec({
|
||||
baseUrl,
|
||||
spec: { ...singleOperation({}), security, components: { securitySchemes: schemes } },
|
||||
|
|
@ -602,13 +614,10 @@ describe("OpenAPI.fromSpec", () => {
|
|||
expect(new URL(client.requests[0]!.url).searchParams.get("__proto__")).toBe("secret")
|
||||
|
||||
const duplicate = toolAt(
|
||||
authenticated(
|
||||
[{ first: [], second: [] }],
|
||||
{
|
||||
first: { type: "apiKey", in: "header", name: "x-key" },
|
||||
second: { type: "apiKey", in: "header", name: "x-key" },
|
||||
},
|
||||
).tools,
|
||||
authenticated([{ first: [], second: [] }], {
|
||||
first: { type: "apiKey", in: "header", name: "x-key" },
|
||||
second: { type: "apiKey", in: "header", name: "x-key" },
|
||||
}).tools,
|
||||
"test",
|
||||
)
|
||||
if (!Tool.isDefinition(duplicate)) throw new Error("duplicate auth tool was not generated")
|
||||
|
|
@ -633,8 +642,7 @@ describe("OpenAPI.fromSpec", () => {
|
|||
},
|
||||
},
|
||||
auth: {
|
||||
resolve: ({ name }) =>
|
||||
Effect.succeed(name === "bearer" ? { type: "bearer", token: "secret" } : undefined),
|
||||
resolve: ({ name }) => Effect.succeed(name === "bearer" ? { type: "bearer", token: "secret" } : undefined),
|
||||
},
|
||||
})
|
||||
const alternativeTool = toolAt(alternative.tools, "test")
|
||||
|
|
@ -766,9 +774,7 @@ describe("OpenAPI.fromSpec", () => {
|
|||
const oversized = recordingClient(
|
||||
() => new Response(null, { headers: { "content-length": String(50 * 1024 * 1024 + 1) } }),
|
||||
)
|
||||
const malformed = recordingClient(
|
||||
() => new Response("{", { headers: { "content-type": "application/json" } }),
|
||||
)
|
||||
const malformed = recordingClient(() => new Response("{", { headers: { "content-type": "application/json" } }))
|
||||
const chunked = recordingClient(() => new Response(new Uint8Array(50 * 1024 * 1024 + 1)))
|
||||
|
||||
await expect(Effect.runPromise(tool.run({}).pipe(Effect.provide(oversized.layer)))).rejects.toThrow(
|
||||
|
|
|
|||
|
|
@ -308,10 +308,7 @@ describe("union schemas render every alternative", () => {
|
|||
|
||||
test("allOf renders intersections with parenthesized union members", () => {
|
||||
const schema = {
|
||||
allOf: [
|
||||
{ type: "object", properties: { id: { type: "string" } } },
|
||||
{ type: ["string", "null"] },
|
||||
],
|
||||
allOf: [{ type: "object", properties: { id: { type: "string" } } }, { type: ["string", "null"] }],
|
||||
} as const
|
||||
expect(jsonSchemaToTypeScript(schema)).toBe("{ id?: string } & (string | null)")
|
||||
})
|
||||
|
|
@ -321,7 +318,9 @@ describe("union schemas render every alternative", () => {
|
|||
"unknown",
|
||||
)
|
||||
expect(
|
||||
jsonSchemaToTypeScript({ allOf: [{ type: "string" }, { allOf: [{ $ref: "https://example.com/external.json" }] }] }),
|
||||
jsonSchemaToTypeScript({
|
||||
allOf: [{ type: "string" }, { allOf: [{ $ref: "https://example.com/external.json" }] }],
|
||||
}),
|
||||
).toBe("unknown")
|
||||
expect(
|
||||
jsonSchemaToTypeScript({
|
||||
|
|
|
|||
|
|
@ -14507,6 +14507,7 @@
|
|||
},
|
||||
"description": "Establish a WebSocket connection streaming PTY output and accepting terminal input.",
|
||||
"summary": "Connect to PTY session",
|
||||
"x-websocket": true,
|
||||
"x-codeSamples": [
|
||||
{
|
||||
"lang": "js",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue