repositories
loading repo index
repositories
loading repo index
repository
loading code, commits, and activity
public Clawd ADK gateway launch mirror
stars
latest
clone command
git clone gitlawb://did:key:z6Mkq5mY...iFZ5/my-project-publ...git clone gitlawb://did:key:z6Mkq5mY.../my-project-publ...2fa351d6docs: add automaton and perps launch sources16d ago| #1 | /** |
| #2 | * CLAWD API Client |
| #3 | * |
| #4 | * Communicates with CLAWD Runtime's control plane for sandbox management, |
| #5 | * credits, and infrastructure operations. |
| #6 | * Adapted from @aiws/sdk patterns. |
| #7 | */ |
| #8 | export function createClawdRuntimeClient(options) { |
| #9 | const { apiUrl, apiKey, sandboxId } = options; |
| #10 | async function request(method, path, body) { |
| #11 | const resp = await fetch(`${apiUrl}${path}`, { |
| #12 | method, |
| #13 | headers: { |
| #14 | "Content-Type": "application/json", |
| #15 | Authorization: apiKey, |
| #16 | }, |
| #17 | body: body ? JSON.stringify(body) : undefined, |
| #18 | }); |
| #19 | if (!resp.ok) { |
| #20 | const text = await resp.text(); |
| #21 | throw new Error(`CLAWD Runtime API error: ${method} ${path} -> ${resp.status}: ${text}`); |
| #22 | } |
| #23 | const contentType = resp.headers.get("content-type"); |
| #24 | if (contentType?.includes("application/json")) { |
| #25 | return resp.json(); |
| #26 | } |
| #27 | return resp.text(); |
| #28 | } |
| #29 | // ─── Sandbox Operations (own sandbox) ──────────────────────── |
| #30 | const exec = async (command, timeout) => { |
| #31 | const result = await request("POST", `/v1/sandboxes/${sandboxId}/exec`, { command, timeout }); |
| #32 | return { |
| #33 | stdout: result.stdout || "", |
| #34 | stderr: result.stderr || "", |
| #35 | exitCode: result.exit_code ?? result.exitCode ?? 0, |
| #36 | }; |
| #37 | }; |
| #38 | const writeFile = async (path, content) => { |
| #39 | await request("POST", `/v1/sandboxes/${sandboxId}/files/upload/json`, { path, content }); |
| #40 | }; |
| #41 | const readFile = async (filePath) => { |
| #42 | const result = await request("GET", `/v1/sandboxes/${sandboxId}/files/read?path=${encodeURIComponent(filePath)}`); |
| #43 | return typeof result === "string" ? result : result.content || ""; |
| #44 | }; |
| #45 | const exposePort = async (port) => { |
| #46 | const result = await request("POST", `/v1/sandboxes/${sandboxId}/ports/expose`, { port }); |
| #47 | return { |
| #48 | port: result.port, |
| #49 | publicUrl: result.public_url || result.publicUrl || result.url, |
| #50 | sandboxId, |
| #51 | }; |
| #52 | }; |
| #53 | const removePort = async (port) => { |
| #54 | await request("DELETE", `/v1/sandboxes/${sandboxId}/ports/${port}`); |
| #55 | }; |
| #56 | // ─── Sandbox Management (other sandboxes) ──────────────────── |
| #57 | const createSandbox = async (options) => { |
| #58 | const result = await request("POST", "/v1/sandboxes", { |
| #59 | name: options.name, |
| #60 | vcpu: options.vcpu || 1, |
| #61 | memory_mb: options.memoryMb || 512, |
| #62 | disk_gb: options.diskGb || 5, |
| #63 | region: options.region, |
| #64 | }); |
| #65 | return { |
| #66 | id: result.id || result.sandbox_id, |
| #67 | status: result.status || "running", |
| #68 | region: result.region || "", |
| #69 | vcpu: result.vcpu || options.vcpu || 1, |
| #70 | memoryMb: result.memory_mb || options.memoryMb || 512, |
| #71 | diskGb: result.disk_gb || options.diskGb || 5, |
| #72 | terminalUrl: result.terminal_url, |
| #73 | createdAt: result.created_at || new Date().toISOString(), |
| #74 | }; |
| #75 | }; |
| #76 | const deleteSandbox = async (targetId) => { |
| #77 | await request("DELETE", `/v1/sandboxes/${targetId}`); |
| #78 | }; |
| #79 | const listSandboxes = async () => { |
| #80 | const result = await request("GET", "/v1/sandboxes"); |
| #81 | const sandboxes = Array.isArray(result) |
| #82 | ? result |
| #83 | : result.sandboxes || []; |
| #84 | return sandboxes.map((s) => ({ |
| #85 | id: s.id || s.sandbox_id, |
| #86 | status: s.status || "unknown", |
| #87 | region: s.region || "", |
| #88 | vcpu: s.vcpu || 0, |
| #89 | memoryMb: s.memory_mb || 0, |
| #90 | diskGb: s.disk_gb || 0, |
| #91 | terminalUrl: s.terminal_url, |
| #92 | createdAt: s.created_at || "", |
| #93 | })); |
| #94 | }; |
| #95 | // ─── Credits ───────────────────────────────────────────────── |
| #96 | const getCreditsBalance = async () => { |
| #97 | const result = await request("GET", "/v1/credits/balance"); |
| #98 | return result.balance_cents ?? result.credits_cents ?? 0; |
| #99 | }; |
| #100 | const getCreditsPricing = async () => { |
| #101 | const result = await request("GET", "/v1/credits/pricing"); |
| #102 | const tiers = result.tiers || result.pricing || []; |
| #103 | return tiers.map((t) => ({ |
| #104 | name: t.name || "", |
| #105 | vcpu: t.vcpu || 0, |
| #106 | memoryMb: t.memory_mb || 0, |
| #107 | diskGb: t.disk_gb || 0, |
| #108 | monthlyCents: t.monthly_cents || 0, |
| #109 | })); |
| #110 | }; |
| #111 | const transferCredits = async (toAddress, amountCents, note) => { |
| #112 | const payload = { |
| #113 | to_address: toAddress, |
| #114 | amount_cents: amountCents, |
| #115 | note, |
| #116 | }; |
| #117 | const paths = [ |
| #118 | "/v1/credits/transfer", |
| #119 | "/v1/credits/transfers", |
| #120 | ]; |
| #121 | let lastError = "Unknown transfer error"; |
| #122 | for (const path of paths) { |
| #123 | const resp = await fetch(`${apiUrl}${path}`, { |
| #124 | method: "POST", |
| #125 | headers: { |
| #126 | "Content-Type": "application/json", |
| #127 | Authorization: apiKey, |
| #128 | }, |
| #129 | body: JSON.stringify(payload), |
| #130 | }); |
| #131 | if (!resp.ok) { |
| #132 | const text = await resp.text(); |
| #133 | lastError = `${resp.status}: ${text}`; |
| #134 | // Try next known endpoint shape before failing. |
| #135 | if (resp.status === 404) |
| #136 | continue; |
| #137 | throw new Error(`CLAWD Runtime API error: POST ${path} -> ${lastError}`); |
| #138 | } |
| #139 | const data = await resp.json().catch(() => ({})); |
| #140 | return { |
| #141 | transferId: data.transfer_id || data.id || "", |
| #142 | status: data.status || "submitted", |
| #143 | toAddress: data.to_address || toAddress, |
| #144 | amountCents: data.amount_cents ?? amountCents, |
| #145 | balanceAfterCents: data.balance_after_cents ?? data.new_balance_cents ?? undefined, |
| #146 | }; |
| #147 | } |
| #148 | throw new Error(`CLAWD Runtime API error: POST /v1/credits/transfer -> ${lastError}`); |
| #149 | }; |
| #150 | // ─── Domains ────────────────────────────────────────────────── |
| #151 | const searchDomains = async (query, tlds) => { |
| #152 | const params = new URLSearchParams({ query }); |
| #153 | if (tlds) |
| #154 | params.set("tlds", tlds); |
| #155 | const result = await request("GET", `/v1/domains/search?${params}`); |
| #156 | const results = result.results || result.domains || []; |
| #157 | return results.map((d) => ({ |
| #158 | domain: d.domain, |
| #159 | available: d.available ?? d.purchasable ?? false, |
| #160 | registrationPrice: d.registration_price ?? d.purchase_price, |
| #161 | renewalPrice: d.renewal_price, |
| #162 | currency: d.currency || "USD", |
| #163 | })); |
| #164 | }; |
| #165 | const registerDomain = async (domain, years = 1) => { |
| #166 | const result = await request("POST", "/v1/domains/register", { |
| #167 | domain, |
| #168 | years, |
| #169 | }); |
| #170 | return { |
| #171 | domain: result.domain || domain, |
| #172 | status: result.status || "registered", |
| #173 | expiresAt: result.expires_at || result.expiry, |
| #174 | transactionId: result.transaction_id || result.id, |
| #175 | }; |
| #176 | }; |
| #177 | const listDnsRecords = async (domain) => { |
| #178 | const result = await request("GET", `/v1/domains/${encodeURIComponent(domain)}/dns`); |
| #179 | const records = result.records || result || []; |
| #180 | return (Array.isArray(records) ? records : []).map((r) => ({ |
| #181 | id: r.id || r.record_id || "", |
| #182 | type: r.type || "", |
| #183 | host: r.host || r.name || "", |
| #184 | value: r.value || r.answer || "", |
| #185 | ttl: r.ttl, |
| #186 | distance: r.distance ?? r.priority, |
| #187 | })); |
| #188 | }; |
| #189 | const addDnsRecord = async (domain, type, host, value, ttl) => { |
| #190 | const result = await request("POST", `/v1/domains/${encodeURIComponent(domain)}/dns`, { type, host, value, ttl: ttl || 3600 }); |
| #191 | return { |
| #192 | id: result.id || result.record_id || "", |
| #193 | type: result.type || type, |
| #194 | host: result.host || host, |
| #195 | value: result.value || value, |
| #196 | ttl: result.ttl || ttl || 3600, |
| #197 | }; |
| #198 | }; |
| #199 | const deleteDnsRecord = async (domain, recordId) => { |
| #200 | await request("DELETE", `/v1/domains/${encodeURIComponent(domain)}/dns/${encodeURIComponent(recordId)}`); |
| #201 | }; |
| #202 | // ─── Model Discovery ─────────────────────────────────────────── |
| #203 | const listModels = async () => { |
| #204 | // Try inference.x402.wtf first (has availability info), fall back to control plane |
| #205 | const urls = ["https://inference.x402.wtf/v1/models", `${apiUrl}/v1/models`]; |
| #206 | for (const url of urls) { |
| #207 | try { |
| #208 | const resp = await fetch(url, { |
| #209 | headers: { Authorization: apiKey }, |
| #210 | }); |
| #211 | if (!resp.ok) |
| #212 | continue; |
| #213 | const result = await resp.json(); |
| #214 | const raw = result.data || result.models || []; |
| #215 | return raw |
| #216 | .filter((m) => m.available !== false) |
| #217 | .map((m) => ({ |
| #218 | id: m.id, |
| #219 | provider: m.provider || m.owned_by || "unknown", |
| #220 | pricing: { |
| #221 | inputPerMillion: m.pricing?.input_per_million ?? m.pricing?.input_per_1m_tokens_usd ?? 0, |
| #222 | outputPerMillion: m.pricing?.output_per_million ?? m.pricing?.output_per_1m_tokens_usd ?? 0, |
| #223 | }, |
| #224 | })); |
| #225 | } |
| #226 | catch { |
| #227 | continue; |
| #228 | } |
| #229 | } |
| #230 | return []; |
| #231 | }; |
| #232 | const client = { |
| #233 | exec, |
| #234 | writeFile, |
| #235 | readFile, |
| #236 | exposePort, |
| #237 | removePort, |
| #238 | createSandbox, |
| #239 | deleteSandbox, |
| #240 | listSandboxes, |
| #241 | getCreditsBalance, |
| #242 | getCreditsPricing, |
| #243 | transferCredits, |
| #244 | searchDomains, |
| #245 | registerDomain, |
| #246 | listDnsRecords, |
| #247 | addDnsRecord, |
| #248 | deleteDnsRecord, |
| #249 | listModels, |
| #250 | }; |
| #251 | // Expose for child sandbox operations in replication module |
| #252 | client.__apiUrl = apiUrl; |
| #253 | client.__apiKey = apiKey; |
| #254 | return client; |
| #255 | } |
| #256 | //# sourceMappingURL=client.js.map |