import { mkdir, writeFile } from "node:fs/promises";
import { createServer } from "node:http";
import { dirname } from "node:path";
export class A2AAgent {
    static agent;
    static auth = publicAuth();
    static skills = [];
    static capabilities = {};
    static inputModes = ["application/json"];
    static outputModes = ["application/json"];
    static requiredSecrets = [];
    static requiredEnv = [];
    static consumerSetup = { fields: [] };
    static runtime = {};
    static workspaceAccess = { enabled: false };
    static configSchema = null;
    static stateSchema = null;
    static templateLineage = null;
    static metaAgentManifest = null;
    async dispatch(request) {
        const handler = this[request.handler];
        if (typeof handler !== "function") {
            throw new Error(`agent does not implement handler method: ${request.handler}`);
        }
        const context = new RunContext(request);
        const legacyRequest = { ...request, context };
        const raw = handler.length >= 2
            ? await handler.call(this, context, request.arguments)
            : await handler.call(this, legacyRequest);
        return context.finalizeResponse(normalizeWorkerResponse(raw));
    }
}
export class WorkspaceDenied extends Error {
    constructor(message) {
        super(message);
        this.name = "WorkspaceDenied";
    }
}
export class SandboxUnavailable extends Error {
    constructor(message = "no sandbox runtime attached to this context") {
        super(message);
        this.name = "SandboxUnavailable";
    }
}
export class SandboxRuntimeError extends Error {
    statusCode;
    responseBody;
    constructor(message, options = {}) {
        super(message);
        this.name = "SandboxRuntimeError";
        this.statusCode = options.statusCode;
        this.responseBody = options.responseBody;
    }
}
export class HttpSandboxHandle {
    baseUrl;
    name;
    timeoutSeconds;
    authToken;
    grantToken;
    constructor(options) {
        this.baseUrl = options.baseUrl.replace(/\/+$/, "");
        this.name = options.name;
        this.timeoutSeconds = options.timeoutSeconds ?? 1200;
        this.authToken = options.authToken ?? undefined;
        this.grantToken = options.grantToken ?? undefined;
    }
    async exec(cmd, args = [], options = {}) {
        return this.postExec({
            cmd,
            args,
            timeout_seconds: options.timeout ?? this.timeoutSeconds
        });
    }
    async shell(script, options = {}) {
        return this.postExec({
            script,
            timeout_seconds: options.timeout ?? this.timeoutSeconds
        });
    }
    async stop() {
        await this.kill();
    }
    async kill() {
        await sandboxFetch(`${this.baseUrl}/v1/sandboxes/${encodeURIComponent(this.name)}`, {
            method: "DELETE",
            headers: sandboxHeaders(this.authToken, this.grantToken),
            timeoutSeconds: 10
        });
    }
    async logs(_options = {}) {
        return "";
    }
    async postExec(body) {
        const timeoutSeconds = Number(body.timeout_seconds ?? this.timeoutSeconds) + 30;
        const response = await sandboxFetch(`${this.baseUrl}/v1/sandboxes/${encodeURIComponent(this.name)}/exec`, {
            method: "POST",
            headers: { ...sandboxHeaders(this.authToken, this.grantToken), "content-type": "application/json" },
            body: JSON.stringify(body),
            timeoutSeconds
        });
        return normalizeExecResult(await response.json());
    }
}
export class HttpSandboxClient {
    baseUrl;
    defaultWorkspace;
    timeoutSeconds;
    authToken;
    grantToken;
    constructor(baseUrl, options = {}) {
        this.baseUrl = baseUrl.replace(/\/+$/, "");
        this.defaultWorkspace = options.defaultWorkspace ?? undefined;
        this.timeoutSeconds = options.timeoutSeconds ?? 1200;
        this.authToken = options.authToken ?? undefined;
        this.grantToken = options.grantToken ?? undefined;
    }
    async create(spec) {
        const body = {
            name: spec.name,
            bucket: spec.workspace ?? this.defaultWorkspace ?? `agent-${spec.name}`,
            image: spec.image ?? "python:3.11-slim",
            memory_mib: spec.memory_mib ?? 512,
            cpus: spec.cpus ?? 1,
            labels: spec.labels ?? {}
        };
        const response = await sandboxFetch(`${this.baseUrl}/v1/sandboxes`, {
            method: "POST",
            headers: { ...sandboxHeaders(this.authToken, this.grantToken), "content-type": "application/json" },
            body: JSON.stringify(body),
            timeoutSeconds: this.timeoutSeconds + 30
        });
        const data = await response.json();
        const name = isObject(data) && typeof data.name === "string" ? data.name : spec.name;
        return this.get(name);
    }
    async get(name) {
        return new HttpSandboxHandle({
            baseUrl: this.baseUrl,
            name,
            timeoutSeconds: this.timeoutSeconds,
            authToken: this.authToken,
            grantToken: this.grantToken
        });
    }
    async list() {
        const response = await sandboxFetch(`${this.baseUrl}/v1/sandboxes`, {
            headers: sandboxHeaders(this.authToken, this.grantToken),
            timeoutSeconds: 10
        });
        const data = await response.json();
        return Array.isArray(data) ? data.filter((item) => typeof item === "string") : [];
    }
    async remove(name) {
        await sandboxFetch(`${this.baseUrl}/v1/sandboxes/${encodeURIComponent(name)}`, {
            method: "DELETE",
            headers: sandboxHeaders(this.authToken, this.grantToken),
            timeoutSeconds: 10
        });
    }
    async runPython(code, options = {}) {
        return this.runOneShot("/v1/run_python", {
            code,
            image: options.image ?? "python:3.11-slim",
            ...options
        });
    }
    async run_python(code, options = {}) {
        return this.runPython(code, options);
    }
    async runShell(script, options = {}) {
        return this.runOneShot("/v1/run_shell", {
            script,
            image: options.image ?? "python:3.11-slim",
            ...options
        });
    }
    async run_shell(script, options = {}) {
        return this.runShell(script, options);
    }
    async runOneShot(path, body) {
        const payload = { ...body };
        const workspace = payload.workspace;
        delete payload.workspace;
        payload.bucket ??= workspace ?? this.defaultWorkspace ?? "agent-workspace";
        payload.timeout_seconds ??= this.timeoutSeconds;
        const response = await sandboxFetch(`${this.baseUrl}${path}`, {
            method: "POST",
            headers: { ...sandboxHeaders(this.authToken, this.grantToken), "content-type": "application/json" },
            body: JSON.stringify(payload),
            timeoutSeconds: Number(payload.timeout_seconds) + 30
        });
        return normalizeExecResult(await response.json());
    }
}
export class WorkspaceClient {
    grantToken;
    grant;
    baseUrl;
    constructor(options) {
        this.baseUrl = options.cpUrl.replace(/\/+$/, "");
        this.grantToken = options.grantToken;
        this.grant = options.grant ?? decodeGrantPayload(options.grantToken);
    }
    get outputsPrefix() {
        return this.grant?.outputs_prefix ?? null;
    }
    async exists(path) {
        const response = await fetch(this.url(`files/${path}`), {
            method: "HEAD",
            headers: this.headers()
        });
        if (response.status === 404)
            return false;
        if (response.status >= 400)
            throw new WorkspaceDenied(`workspace stat failed: ${response.status}`);
        return true;
    }
    async readBytes(path) {
        const response = await fetch(this.url(`files/${path}`), { headers: this.headers() });
        if (response.status === 404)
            throw new Error(`workspace file not found: ${path}`);
        if (response.status >= 400)
            throw new WorkspaceDenied(`workspace read failed: ${response.status}`);
        return new Uint8Array(await response.arrayBuffer());
    }
    async readText(path) {
        return new TextDecoder().decode(await this.readBytes(path));
    }
    async writeBytes(path, content, contentType = "application/octet-stream") {
        const response = await fetch(this.url(`files/${path}`), {
            method: "PUT",
            headers: { ...this.headers(), "content-type": contentType },
            body: content
        });
        if (response.status >= 400)
            throw new WorkspaceDenied(`workspace write failed: ${response.status}`);
    }
    async writeText(path, content, contentType = "text/plain; charset=utf-8") {
        await this.writeBytes(path, Buffer.from(content, "utf8"), contentType);
    }
    async delete(path) {
        const response = await fetch(this.url(`files/${path}`), {
            method: "DELETE",
            headers: this.headers()
        });
        if (![204, 404].includes(response.status) && response.status >= 400) {
            throw new WorkspaceDenied(`workspace delete failed: ${response.status}`);
        }
    }
    async list() {
        const response = await fetch(this.url("files"), { headers: this.headers() });
        if (response.status >= 400)
            throw new WorkspaceDenied(`workspace list failed: ${response.status}`);
        const data = await response.json();
        return Array.isArray(data) ? data.filter(isObject).map((item) => ({
            path: String(item.path ?? ""),
            size_bytes: typeof item.size_bytes === "number" ? item.size_bytes : undefined,
            file_type: typeof item.file_type === "string" ? item.file_type : undefined
        })).filter((item) => item.path) : [];
    }
    headers() {
        return { "x-a2a-grant": this.grantToken };
    }
    url(path) {
        const suffix = path.split("/").map(encodeURIComponent).join("/");
        return `${this.baseUrl}/v1/workspace-grants/${suffix}`;
    }
}
export class MissingScopes extends Error {
    missing;
    constructor(missing) {
        super(`missing scopes: ${missing.sort().join(", ")}`);
        this.name = "MissingScopes";
        this.missing = [...missing].sort();
    }
}
export class RunContext {
    request;
    agent;
    skill;
    handler;
    arguments;
    auth;
    events = [];
    artifacts = [];
    workspaceClient;
    sandboxClient;
    constructor(request) {
        this.request = request;
        this.agent = request.agent;
        this.skill = request.skill;
        this.handler = request.handler;
        this.arguments = request.arguments;
        this.auth = request.auth ?? null;
    }
    get emittedEvents() {
        return [...this.events];
    }
    get emittedArtifacts() {
        return [...this.artifacts];
    }
    get taskId() {
        if (this.request.task_id)
            return this.request.task_id;
        const runId = this.request.composition?.run_id;
        if (typeof runId === "string" && runId)
            return runId;
        const taskId = this.request.composition?.task_id;
        if (typeof taskId === "string" && taskId)
            return taskId;
        return "local";
    }
    get grant() {
        return this.request.grant ? decodeGrantPayload(this.request.grant) : null;
    }
    get workspace() {
        if (!this.request.grant) {
            throw new Error("missing workspace grant");
        }
        const cpUrl = this.cpUrl();
        if (!cpUrl) {
            throw new Error("missing control plane URL for workspace grant");
        }
        this.workspaceClient ??= new WorkspaceClient({
            cpUrl,
            grantToken: this.request.grant,
            grant: this.grant
        });
        return this.workspaceClient;
    }
    get sandbox() {
        const baseUrl = process.env.A2A_SANDBOX_URL;
        if (!baseUrl)
            throw new SandboxUnavailable();
        this.sandboxClient ??= new HttpSandboxClient(baseUrl, {
            defaultWorkspace: this.grant?.bucket,
            timeoutSeconds: Number(process.env.A2A_SANDBOX_TIMEOUT_S || "1200"),
            authToken: process.env.A2A_SANDBOX_TOKEN,
            grantToken: this.request.grant
        });
        return this.sandboxClient;
    }
    async emitEvent(event) {
        const normalized = normalizeEvent(event);
        this.events.push(normalized);
        await this.request.emit?.(normalized);
    }
    async emitProgress(message, payload = {}) {
        await this.emitEvent({ kind: "progress", payload: { message, ...payload } });
    }
    async emitTextDelta(text) {
        await this.emitEvent({ kind: "text_delta", payload: { text } });
    }
    async emitError(message, options = {}) {
        await this.emitEvent({ kind: "error", payload: { message, ...options } });
    }
    async emitArtifact(ref) {
        const artifact = { ...ref };
        this.artifacts.push(artifact);
        await this.emitEvent({ kind: "artifact", payload: artifact });
    }
    async writeArtifact(name, data, contentType = "application/octet-stream", metadata = {}) {
        const bytes = bytesFromArtifactData(data);
        const path = this.artifactPath(name);
        let ref;
        if (this.request.grant && this.cpUrl()) {
            await this.workspace.writeBytes(path, bytes, contentType);
            ref = {
                name,
                path,
                uri: this.workspace.grant?.bucket ? `s3://${this.workspace.grant.bucket}/${path}` : `workspace://${path}`,
                mime_type: contentType,
                content_type: contentType,
                bytes: bytes.byteLength,
                metadata
            };
        }
        else {
            ref = {
                name,
                path,
                uri: `memory://${this.taskId}/${safeArtifactName(name)}`,
                mime_type: contentType,
                content_type: contentType,
                bytes: bytes.byteLength,
                metadata
            };
        }
        await this.emitArtifact(ref);
        return ref;
    }
    secret(name) {
        const value = process.env[name];
        if (value == null || value === "") {
            throw new Error(`missing secret: ${name}`);
        }
        return value;
    }
    consumerConfig(name, defaultValue) {
        const value = this.request.consumer_config?.[name];
        if (value === undefined)
            return defaultValue;
        return value;
    }
    consumerSecret(name) {
        const value = this.request.consumer_secrets?.[name];
        if (value == null || value === "") {
            throw new Error(`missing consumer secret: ${name}`);
        }
        return value;
    }
    llm() {
        if (!this.request.llm_creds) {
            throw new Error("missing LLM credentials");
        }
        return this.request.llm_creds;
    }
    cpJwt() {
        return this.request.cp_jwt ?? null;
    }
    cpUrl() {
        return this.request.cp_url ?? process.env.A2A_CP_URL ?? null;
    }
    requireScopes(required) {
        const present = scopesFromAuth(this.auth);
        const missing = required.filter((scope) => !present.has(scope));
        if (missing.length > 0)
            throw new MissingScopes(missing);
    }
    async checkCancelled() {
        if (this.request.cancelled) {
            throw new Error("operation cancelled");
        }
    }
    finalizeResponse(response) {
        const finalized = { ...response };
        if (finalized.events === undefined && this.events.length > 0) {
            finalized.events = this.emittedEvents;
        }
        if (finalized.artifacts === undefined && this.artifacts.length > 0) {
            finalized.artifacts = this.emittedArtifacts;
        }
        return finalized;
    }
    artifactPath(name) {
        const safeName = safeArtifactName(name);
        const prefix = this.workspaceClient?.outputsPrefix ?? this.grant?.outputs_prefix ?? "outputs/";
        const cleanPrefix = prefix ? `${prefix.replace(/^\/+/, "").replace(/\/+$/, "")}/` : "";
        return `${cleanPrefix}${safeArtifactName(this.taskId)}/${safeName}`;
    }
}
export function publicAuth() {
    return {
        model: "NoAuth",
        strategy: "public",
        principal_schema: { title: "NoAuth", type: "object", properties: {}, additionalProperties: false },
        required: false
    };
}
export function skill(declaration) {
    validateSkill(declaration);
    return declaration;
}
export function compileAgent(agentClass, options = {}) {
    const identity = agentClass.agent;
    if (!identity?.name)
        throw new Error("agent.agent.name is required");
    const skills = agentClass.skills.map(normalizeSkill);
    if (skills.length === 0)
        throw new Error("agent must declare at least one skill");
    const names = new Set();
    for (const item of skills) {
        if (names.has(item.name))
            throw new Error(`duplicate skill: ${item.name}`);
        names.add(item.name);
    }
    return {
        schema_version: "2026-06-04",
        language: options.language ?? "typescript",
        name: identity.name,
        description: identity.description ?? "",
        version: identity.version ?? "0.1.0",
        entrypoint: options.entrypoint ?? {},
        skills,
        capabilities: agentClass.capabilities,
        input_modes: agentClass.inputModes,
        output_modes: agentClass.outputModes,
        required_secrets: agentClass.requiredSecrets,
        required_env: agentClass.requiredEnv,
        consumer_setup: agentClass.consumerSetup,
        runtime: { sandbox: "microsandbox", ...agentClass.runtime },
        template_lineage: agentClass.templateLineage,
        meta_agent_manifest: agentClass.metaAgentManifest,
        state_schema: agentClass.stateSchema,
        workspace_access: agentClass.workspaceAccess,
        config_schema: agentClass.configSchema,
        auth: agentClass.auth,
        metadata: options.metadata ?? {}
    };
}
export async function writeAgentDsl(agentClass, path = ".a2a/agent.dsl.json", options = {}) {
    const dsl = compileAgent(agentClass, options);
    await mkdir(dirname(path), { recursive: true });
    await writeFile(path, `${JSON.stringify(dsl, null, 2)}\n`, "utf8");
    return dsl;
}
export function serveWorker(agentClass, handlers, options = {}) {
    const dsl = compileAgent(agentClass);
    const handlerNames = new Set(dsl.skills.map((item) => item.handler));
    const server = createServer(async (req, res) => {
        try {
            if (req.method === "POST" && req.url?.startsWith("/_a2a/invoke-stream/")) {
                await handleStreamingWorkerInvoke(req, res, handlerNames, handlers);
                return;
            }
            if (req.method !== "POST" || !req.url?.startsWith("/_a2a/invoke/")) {
                writeJson(res, 404, { error: "not found" });
                return;
            }
            const handlerName = decodeURIComponent(req.url.slice("/_a2a/invoke/".length));
            if (!handlerNames.has(handlerName) || typeof handlers[handlerName] !== "function") {
                writeJson(res, 404, { error: `unknown handler: ${handlerName}` });
                return;
            }
            const body = await readJson(req);
            const request = body;
            const raw = await handlers[handlerName](request);
            const response = normalizeWorkerResponse(raw);
            writeJson(res, 200, response);
        }
        catch (error) {
            writeJson(res, 500, { error: error instanceof Error ? error.message : String(error) });
        }
    });
    disableLongRunningWorkerTimeouts(server);
    server.listen(options.port ?? 9001, options.host ?? "127.0.0.1");
    return server;
}
export function serveAgent(agentClass, options = {}) {
    const dsl = compileAgent(agentClass);
    const agent = new agentClass();
    const handlerNames = new Set(dsl.skills.map((item) => item.handler));
    const server = createServer(async (req, res) => {
        try {
            if (req.method === "POST" && req.url?.startsWith("/_a2a/invoke-stream/")) {
                await handleStreamingAgentInvoke(req, res, handlerNames, agent);
                return;
            }
            if (req.method !== "POST" || !req.url?.startsWith("/_a2a/invoke/")) {
                writeJson(res, 404, { error: "not found" });
                return;
            }
            const handlerName = decodeURIComponent(req.url.slice("/_a2a/invoke/".length));
            if (!handlerNames.has(handlerName)) {
                writeJson(res, 404, { error: `unknown handler: ${handlerName}` });
                return;
            }
            const body = await readJson(req);
            const request = { ...body, handler: handlerName };
            const response = await agent.dispatch(request);
            writeJson(res, 200, response);
        }
        catch (error) {
            writeJson(res, 500, { error: error instanceof Error ? error.message : String(error) });
        }
    });
    disableLongRunningWorkerTimeouts(server);
    server.listen(options.port ?? 9001, options.host ?? "127.0.0.1");
    return server;
}
async function handleStreamingWorkerInvoke(req, res, handlerNames, handlers) {
    const handlerName = decodeURIComponent(req.url.slice("/_a2a/invoke-stream/".length));
    if (!handlerNames.has(handlerName) || typeof handlers[handlerName] !== "function") {
        writeSseError(res, 404, `unknown handler: ${handlerName}`);
        return;
    }
    await streamDispatch(res, async (emit) => {
        const body = await readJson(req);
        const request = { ...body, handler: handlerName, emit };
        return normalizeWorkerResponse(await handlers[handlerName](request));
    });
}
async function handleStreamingAgentInvoke(req, res, handlerNames, agent) {
    const handlerName = decodeURIComponent(req.url.slice("/_a2a/invoke-stream/".length));
    if (!handlerNames.has(handlerName)) {
        writeSseError(res, 404, `unknown handler: ${handlerName}`);
        return;
    }
    await streamDispatch(res, async (emit) => {
        const body = await readJson(req);
        const request = { ...body, handler: handlerName, emit };
        return agent.dispatch(request);
    });
}
async function streamDispatch(res, dispatch) {
    const emittedEvents = [];
    writeSseHead(res);
    writeSse(res, { type: "started" });
    try {
        const response = await dispatch((event) => {
            emittedEvents.push(event);
            writeSse(res, toEventFrame(event));
        });
        writeSse(res, {
            type: "result",
            result: response.result,
            events: response.events ?? emittedEvents,
            artifacts: response.artifacts ?? []
        });
    }
    catch (error) {
        writeSse(res, {
            type: "error",
            status: 500,
            detail: error instanceof Error ? error.message : String(error)
        });
    }
    finally {
        res.write("data: [DONE]\n\n");
        res.end();
    }
}
function toEventFrame(event) {
    const kind = typeof event.kind === "string"
        ? event.kind
        : typeof event.type === "string"
            ? event.type
            : "progress";
    const { kind: _kind, type: _type, payload: rawPayload, ...rest } = event;
    const payload = isObject(rawPayload) ? rawPayload : rest;
    return { type: "event", kind, payload };
}
function disableLongRunningWorkerTimeouts(server) {
    server.timeout = 0;
    server.requestTimeout = 0;
    server.headersTimeout = 0;
    server.keepAliveTimeout = 0;
}
function normalizeSkill(declaration) {
    validateSkill(declaration);
    return {
        name: declaration.name,
        description: declaration.description ?? "",
        handler: declaration.handler ?? declaration.name,
        tags: declaration.tags ?? [],
        scopes: declaration.scopes ?? [],
        stream: declaration.stream ?? false,
        policy: {
            timeout_seconds: declaration.policy?.timeout_seconds ?? null,
            idempotent: declaration.policy?.idempotent ?? false,
            max_retries: declaration.policy?.max_retries ?? 0,
            cost_class: declaration.policy?.cost_class ?? null,
            allow_scope_expansion: declaration.policy?.allow_scope_expansion ?? false,
            grant_mode: declaration.policy?.grant_mode ?? null,
            grant_allow_patterns: declaration.policy?.grant_allow_patterns ?? [],
            grant_deny_patterns: declaration.policy?.grant_deny_patterns ?? [],
            grant_outputs_prefix: declaration.policy?.grant_outputs_prefix ?? null,
            grant_write_prefixes: declaration.policy?.grant_write_prefixes ?? [],
            grant_ttl_seconds: declaration.policy?.grant_ttl_seconds ?? null,
            grant_run_timeout_seconds: declaration.policy?.grant_run_timeout_seconds ?? null,
            grant_approval_timeout_seconds: declaration.policy?.grant_approval_timeout_seconds ?? null,
            grant_scope_approval_timeout_seconds: declaration.policy?.grant_scope_approval_timeout_seconds ?? null
        },
        input_schema: declaration.input_schema,
        output_schema: declaration.output_schema
    };
}
function validateSkill(declaration) {
    if (!declaration.name)
        throw new Error("skill.name is required");
    if (declaration.input_schema?.type !== "object") {
        throw new Error(`skill ${declaration.name}: input_schema must be an object schema`);
    }
    if (typeof declaration.input_schema.properties !== "object" || declaration.input_schema.properties === null) {
        throw new Error(`skill ${declaration.name}: input_schema.properties is required`);
    }
    if (!Array.isArray(declaration.input_schema.required)) {
        throw new Error(`skill ${declaration.name}: input_schema.required must be an array`);
    }
    for (const key of declaration.input_schema.required) {
        if (typeof key !== "string")
            throw new Error(`skill ${declaration.name}: required values must be strings`);
        if (!(key in declaration.input_schema.properties)) {
            throw new Error(`skill ${declaration.name}: required field ${key} missing from properties`);
        }
    }
    if (!declaration.output_schema || Object.keys(declaration.output_schema).length === 0) {
        throw new Error(`skill ${declaration.name}: output_schema is required`);
    }
}
function normalizeWorkerResponse(value) {
    if (isObject(value) && "result" in value) {
        return value;
    }
    return { result: value };
}
function isObject(value) {
    return typeof value === "object" && value !== null && !Array.isArray(value);
}
function normalizeEvent(event) {
    const raw = event;
    if (typeof raw.kind === "string") {
        return {
            kind: raw.kind,
            payload: isObject(raw.payload) ? raw.payload : {}
        };
    }
    if (typeof raw.type === "string") {
        const { type, payload, ...rest } = raw;
        return {
            kind: type,
            payload: isObject(payload) ? payload : rest
        };
    }
    return { kind: "event", payload: raw };
}
function decodeGrantPayload(token) {
    const rawPayload = token.split(".", 1)[0];
    if (!rawPayload)
        return null;
    try {
        const padded = rawPayload.replace(/-/g, "+").replace(/_/g, "/").padEnd(Math.ceil(rawPayload.length / 4) * 4, "=");
        const parsed = JSON.parse(Buffer.from(padded, "base64").toString("utf8"));
        if (!isObject(parsed))
            return null;
        return parsed;
    }
    catch {
        return null;
    }
}
function bytesFromArtifactData(data) {
    if (typeof data === "string")
        return Buffer.from(data, "utf8");
    if (Buffer.isBuffer(data))
        return data;
    return data;
}
function safeArtifactName(name) {
    const clean = name.replace(/\\/g, "/").split("/").filter(Boolean).join("/");
    return clean.replace(/[^A-Za-z0-9._/-]/g, "_").replace(/\.\.(\/|$)/g, "");
}
function sandboxHeaders(authToken, grantToken) {
    const headers = {};
    if (authToken)
        headers.authorization = `Bearer ${authToken}`;
    if (grantToken)
        headers["x-a2a-grant"] = grantToken;
    return headers;
}
async function sandboxFetch(url, options) {
    const { timeoutSeconds, ...request } = options;
    const response = await fetch(url, {
        ...request,
        signal: AbortSignal.timeout(Math.max(1, timeoutSeconds) * 1000)
    });
    if (response.status >= 400) {
        const body = await response.text().catch(() => "");
        throw new SandboxRuntimeError(`sandbox request failed: ${request.method ?? "GET"} ${url} status=${response.status}`, {
            statusCode: response.status,
            responseBody: body || undefined
        });
    }
    return response;
}
function normalizeExecResult(value) {
    const data = isObject(value) ? value : {};
    return {
        stdout: typeof data.stdout === "string" ? data.stdout : "",
        stderr: typeof data.stderr === "string" ? data.stderr : "",
        exit_code: typeof data.exit_code === "number" ? data.exit_code : 0,
        truncated: typeof data.truncated === "boolean" ? data.truncated : false,
        files: Array.isArray(data.files)
            ? data.files.filter(isObject).map((item) => ({ ...item }))
            : []
    };
}
function scopesFromAuth(auth) {
    if (auth === null)
        return new Set();
    const scopes = new Set();
    const list = auth.scopes;
    if (Array.isArray(list)) {
        for (const item of list) {
            if (typeof item === "string")
                scopes.add(item);
        }
    }
    const scope = auth.scope;
    if (typeof scope === "string") {
        for (const item of scope.split(/\s+/)) {
            if (item)
                scopes.add(item);
        }
    }
    return scopes;
}
async function readJson(req) {
    const chunks = [];
    for await (const chunk of req)
        chunks.push(Buffer.from(chunk));
    const raw = Buffer.concat(chunks).toString("utf8");
    return raw ? JSON.parse(raw) : {};
}
function writeJson(res, status, body) {
    res.statusCode = status;
    res.setHeader("content-type", "application/json");
    res.end(JSON.stringify(body));
}
function writeSseHead(res) {
    if (res.headersSent)
        return;
    res.statusCode = 200;
    res.setHeader("content-type", "text/event-stream");
    res.setHeader("cache-control", "no-cache");
    res.setHeader("connection", "keep-alive");
    res.setHeader("x-accel-buffering", "no");
}
function writeSse(res, body) {
    writeSseHead(res);
    res.write(`data: ${JSON.stringify(body)}\n\n`);
}
function writeSseError(res, status, detail) {
    writeSse(res, { type: "error", status, detail });
    res.write("data: [DONE]\n\n");
    res.end();
}
//# sourceMappingURL=index.js.map