@runtypelabs/cli 2.14.0 → 2.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +702 -55
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -35408,15 +35408,17 @@ var FlowInputSchema = external_exports.object({
|
|
|
35408
35408
|
id: external_exports.string().min(1).optional(),
|
|
35409
35409
|
name: external_exports.string().min(1).optional(),
|
|
35410
35410
|
description: external_exports.string().optional(),
|
|
35411
|
-
steps: external_exports.array(external_exports.any()).optional()
|
|
35411
|
+
steps: external_exports.array(external_exports.any()).optional(),
|
|
35412
|
+
contentHash: external_exports.string().length(64).optional()
|
|
35412
35413
|
}).refine(
|
|
35413
35414
|
(data) => {
|
|
35414
35415
|
const hasFlowId = !!data.id;
|
|
35415
35416
|
const hasSteps = !!(data.name && data.steps && data.steps.length > 0);
|
|
35416
|
-
|
|
35417
|
+
const hasPersistedFlow = !!(data.name && data.contentHash);
|
|
35418
|
+
return hasFlowId || hasSteps || hasPersistedFlow;
|
|
35417
35419
|
},
|
|
35418
35420
|
{
|
|
35419
|
-
message: "Either 'id'
|
|
35421
|
+
message: "Either 'id', flow definition with 'name' and 'steps', or persisted flow with 'name' and 'contentHash' must be provided."
|
|
35420
35422
|
}
|
|
35421
35423
|
);
|
|
35422
35424
|
var AgentLoopConfigSchema = external_exports.object({
|
|
@@ -53970,6 +53972,612 @@ gcloud run deploy runtype-deploy \\
|
|
|
53970
53972
|
\`GET /health\` returns \`{"status":"ok","agents":[...]}\`.
|
|
53971
53973
|
`;
|
|
53972
53974
|
}
|
|
53975
|
+
function workerIndexTs(agentSlugs) {
|
|
53976
|
+
const imports = agentSlugs.map((slug, i) => `import agent${i}Json from '../agents/${slug}.json'`).join("\n");
|
|
53977
|
+
const agentFiles = agentSlugs.map((slug, i) => ` ['${slug}.json', agent${i}Json],`).join("\n");
|
|
53978
|
+
return `/**
|
|
53979
|
+
* Generated by \`runtype deploy --target cloudflare\`.
|
|
53980
|
+
*
|
|
53981
|
+
* Routes:
|
|
53982
|
+
* GET /health \u2014 liveness probe (lists registered agent names)
|
|
53983
|
+
* POST /agent/:name \u2014 SSE stream of the agent event schema
|
|
53984
|
+
*
|
|
53985
|
+
* Agent definitions are statically imported so Wrangler bundles them.
|
|
53986
|
+
* To add a new agent:
|
|
53987
|
+
* 1. Export it with \`runtype deploy --agent <id> --target cloudflare\`
|
|
53988
|
+
* 2. Or drop a JSON file under agents/ and add an import + entry below
|
|
53989
|
+
* 3. Run \`wrangler deploy\`
|
|
53990
|
+
*/
|
|
53991
|
+
import {
|
|
53992
|
+
CloudflareAdapter,
|
|
53993
|
+
createRuntime,
|
|
53994
|
+
exportedAgentSchema,
|
|
53995
|
+
type ExportedAgent,
|
|
53996
|
+
} from '@runtypelabs/runtime'
|
|
53997
|
+
|
|
53998
|
+
// ---------------------------------------------------------------------------
|
|
53999
|
+
// Agent registry \u2014 static imports bundled by Wrangler at deploy time
|
|
54000
|
+
// ---------------------------------------------------------------------------
|
|
54001
|
+
|
|
54002
|
+
${imports}
|
|
54003
|
+
|
|
54004
|
+
function parseAgent(json: unknown, filename: string): ExportedAgent {
|
|
54005
|
+
try {
|
|
54006
|
+
return exportedAgentSchema.parse(json)
|
|
54007
|
+
} catch (err) {
|
|
54008
|
+
throw new Error(
|
|
54009
|
+
\`[runtype] invalid agent JSON in \${filename}: \${
|
|
54010
|
+
err instanceof Error ? err.message : String(err)
|
|
54011
|
+
}\`
|
|
54012
|
+
)
|
|
54013
|
+
}
|
|
54014
|
+
}
|
|
54015
|
+
|
|
54016
|
+
const agentFiles: Array<[string, unknown]> = [
|
|
54017
|
+
${agentFiles}
|
|
54018
|
+
]
|
|
54019
|
+
|
|
54020
|
+
const agentRegistry: Record<string, ExportedAgent> = {}
|
|
54021
|
+
for (const [filename, json] of agentFiles) {
|
|
54022
|
+
const agent = parseAgent(json, filename)
|
|
54023
|
+
if (agentRegistry[agent.name]) {
|
|
54024
|
+
throw new Error(\`[runtype] duplicate agent name "\${agent.name}" in \${filename}\`)
|
|
54025
|
+
}
|
|
54026
|
+
agentRegistry[agent.name] = agent
|
|
54027
|
+
}
|
|
54028
|
+
|
|
54029
|
+
// ---------------------------------------------------------------------------
|
|
54030
|
+
// Env \u2014 Wrangler injects secrets + bindings here
|
|
54031
|
+
// ---------------------------------------------------------------------------
|
|
54032
|
+
|
|
54033
|
+
export interface Env {
|
|
54034
|
+
// Secrets \u2014 set via \`wrangler secret put <NAME>\`
|
|
54035
|
+
ANTHROPIC_API_KEY?: string
|
|
54036
|
+
OPENAI_API_KEY?: string
|
|
54037
|
+
GOOGLE_API_KEY?: string
|
|
54038
|
+
MIXLAYER_API_KEY?: string
|
|
54039
|
+
// Optional: narrow CORS from * to specific origins (comma-separated)
|
|
54040
|
+
ALLOWED_ORIGINS?: string
|
|
54041
|
+
// Optional: KV namespace binding for durable cross-request caching
|
|
54042
|
+
CACHE_KV?: KVNamespace
|
|
54043
|
+
}
|
|
54044
|
+
|
|
54045
|
+
// ---------------------------------------------------------------------------
|
|
54046
|
+
// Worker
|
|
54047
|
+
// ---------------------------------------------------------------------------
|
|
54048
|
+
|
|
54049
|
+
export default {
|
|
54050
|
+
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
|
|
54051
|
+
const url = new URL(request.url)
|
|
54052
|
+
const cors = corsHeaders(request, env.ALLOWED_ORIGINS)
|
|
54053
|
+
|
|
54054
|
+
if (request.method === 'OPTIONS') {
|
|
54055
|
+
return new Response(null, { status: 204, headers: cors })
|
|
54056
|
+
}
|
|
54057
|
+
|
|
54058
|
+
if (request.method === 'GET' && url.pathname === '/health') {
|
|
54059
|
+
return json({ status: 'ok', agents: Object.keys(agentRegistry) }, 200, cors)
|
|
54060
|
+
}
|
|
54061
|
+
|
|
54062
|
+
const agentMatch = url.pathname.match(/^\\/agent\\/([^/]+)$/)
|
|
54063
|
+
if (request.method === 'POST' && agentMatch) {
|
|
54064
|
+
const name = decodeURIComponent(agentMatch[1])
|
|
54065
|
+
if (!agentRegistry[name]) {
|
|
54066
|
+
return json({ error: \`unknown agent: \${name}\` }, 404, cors)
|
|
54067
|
+
}
|
|
54068
|
+
|
|
54069
|
+
const runtime = createRuntime({
|
|
54070
|
+
agents: agentRegistry,
|
|
54071
|
+
keys: { mode: 'own' },
|
|
54072
|
+
adapter: new CloudflareAdapter(env, {
|
|
54073
|
+
kvNamespace: env.CACHE_KV,
|
|
54074
|
+
waitUntil: ctx.waitUntil.bind(ctx),
|
|
54075
|
+
}),
|
|
54076
|
+
})
|
|
54077
|
+
|
|
54078
|
+
let body: { messages?: Array<{ role: string; content: string }> } = {}
|
|
54079
|
+
try {
|
|
54080
|
+
body = (await request.json()) as typeof body
|
|
54081
|
+
} catch {
|
|
54082
|
+
return json({ error: 'request body must be JSON' }, 400, cors)
|
|
54083
|
+
}
|
|
54084
|
+
const messages = Array.isArray(body.messages) ? body.messages : []
|
|
54085
|
+
|
|
54086
|
+
try {
|
|
54087
|
+
const response = await runtime.executeAgent(name, {
|
|
54088
|
+
messages: messages as Array<{
|
|
54089
|
+
role: 'system' | 'user' | 'assistant'
|
|
54090
|
+
content: string
|
|
54091
|
+
}>,
|
|
54092
|
+
signal: request.signal,
|
|
54093
|
+
})
|
|
54094
|
+
const headers = new Headers(response.headers)
|
|
54095
|
+
for (const [k, v] of Object.entries(cors)) headers.set(k, v)
|
|
54096
|
+
return new Response(response.body, { status: response.status, headers })
|
|
54097
|
+
} catch (err) {
|
|
54098
|
+
return json({ error: err instanceof Error ? err.message : 'unknown error' }, 500, cors)
|
|
54099
|
+
}
|
|
54100
|
+
}
|
|
54101
|
+
|
|
54102
|
+
return json({ error: 'not found' }, 404, cors)
|
|
54103
|
+
},
|
|
54104
|
+
}
|
|
54105
|
+
|
|
54106
|
+
// ---------------------------------------------------------------------------
|
|
54107
|
+
// Helpers
|
|
54108
|
+
// ---------------------------------------------------------------------------
|
|
54109
|
+
|
|
54110
|
+
function json(body: unknown, status: number, extra: Record<string, string>): Response {
|
|
54111
|
+
return new Response(JSON.stringify(body), {
|
|
54112
|
+
status,
|
|
54113
|
+
headers: { 'Content-Type': 'application/json', ...extra },
|
|
54114
|
+
})
|
|
54115
|
+
}
|
|
54116
|
+
|
|
54117
|
+
function corsHeaders(request: Request, allowedOriginsEnv?: string): Record<string, string> {
|
|
54118
|
+
const origin = request.headers.get('Origin') ?? ''
|
|
54119
|
+
let allow = '*'
|
|
54120
|
+
if (allowedOriginsEnv) {
|
|
54121
|
+
const list = allowedOriginsEnv.split(',').map((o) => o.trim()).filter(Boolean)
|
|
54122
|
+
allow = list.includes(origin) ? origin : (list[0] ?? '*')
|
|
54123
|
+
}
|
|
54124
|
+
const headers: Record<string, string> = {
|
|
54125
|
+
'Access-Control-Allow-Origin': allow,
|
|
54126
|
+
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
|
|
54127
|
+
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
|
|
54128
|
+
'Access-Control-Max-Age': '86400',
|
|
54129
|
+
}
|
|
54130
|
+
if (allow !== '*') headers['Vary'] = 'Origin'
|
|
54131
|
+
return headers
|
|
54132
|
+
}
|
|
54133
|
+
`;
|
|
54134
|
+
}
|
|
54135
|
+
function wranglerToml(projectName) {
|
|
54136
|
+
return `name = "${projectName}"
|
|
54137
|
+
main = "src/index.ts"
|
|
54138
|
+
compatibility_date = "2025-01-01"
|
|
54139
|
+
|
|
54140
|
+
# Secrets \u2014 set via \`wrangler secret put <NAME>\`
|
|
54141
|
+
# Run this for each API key your agents need:
|
|
54142
|
+
# wrangler secret put ANTHROPIC_API_KEY
|
|
54143
|
+
# wrangler secret put OPENAI_API_KEY
|
|
54144
|
+
# wrangler secret put GOOGLE_API_KEY
|
|
54145
|
+
# wrangler secret put MIXLAYER_API_KEY
|
|
54146
|
+
|
|
54147
|
+
# Optional: KV namespace for durable cross-request caching.
|
|
54148
|
+
# Without this the adapter uses a per-isolate in-memory Map (ephemeral).
|
|
54149
|
+
# To enable:
|
|
54150
|
+
# 1. wrangler kv namespace create CACHE_KV
|
|
54151
|
+
# 2. Uncomment the block below and paste the generated id.
|
|
54152
|
+
# [[kv_namespaces]]
|
|
54153
|
+
# binding = "CACHE_KV"
|
|
54154
|
+
# id = "<paste your KV namespace id here>"
|
|
54155
|
+
|
|
54156
|
+
# Optional: Workers AI binding (for @cf/* and workers-ai/* model ids).
|
|
54157
|
+
# [ai]
|
|
54158
|
+
# binding = "AI"
|
|
54159
|
+
|
|
54160
|
+
# CORS: narrow from * to specific origins via ALLOWED_ORIGINS env var.
|
|
54161
|
+
# [vars]
|
|
54162
|
+
# ALLOWED_ORIGINS = "https://yourapp.com,https://persona-chat.dev"
|
|
54163
|
+
`;
|
|
54164
|
+
}
|
|
54165
|
+
function workerPackageJson(name, runtimeDep) {
|
|
54166
|
+
return JSON.stringify(
|
|
54167
|
+
{
|
|
54168
|
+
name,
|
|
54169
|
+
version: "0.0.0",
|
|
54170
|
+
private: true,
|
|
54171
|
+
scripts: {
|
|
54172
|
+
dev: "wrangler dev",
|
|
54173
|
+
deploy: "wrangler deploy",
|
|
54174
|
+
typecheck: "tsc --noEmit"
|
|
54175
|
+
},
|
|
54176
|
+
dependencies: {
|
|
54177
|
+
"@runtypelabs/runtime": runtimeDep
|
|
54178
|
+
},
|
|
54179
|
+
devDependencies: {
|
|
54180
|
+
"@cloudflare/workers-types": "^4.0.0",
|
|
54181
|
+
typescript: "^5.3.3",
|
|
54182
|
+
wrangler: "^4.0.0"
|
|
54183
|
+
}
|
|
54184
|
+
},
|
|
54185
|
+
null,
|
|
54186
|
+
2
|
|
54187
|
+
);
|
|
54188
|
+
}
|
|
54189
|
+
function workerTsconfigJson() {
|
|
54190
|
+
return JSON.stringify(
|
|
54191
|
+
{
|
|
54192
|
+
compilerOptions: {
|
|
54193
|
+
target: "ES2022",
|
|
54194
|
+
module: "ES2022",
|
|
54195
|
+
moduleResolution: "bundler",
|
|
54196
|
+
strict: true,
|
|
54197
|
+
resolveJsonModule: true,
|
|
54198
|
+
types: ["@cloudflare/workers-types"]
|
|
54199
|
+
},
|
|
54200
|
+
include: ["src"]
|
|
54201
|
+
},
|
|
54202
|
+
null,
|
|
54203
|
+
2
|
|
54204
|
+
);
|
|
54205
|
+
}
|
|
54206
|
+
function workerSetupSh(monorepoRoot) {
|
|
54207
|
+
return `#!/usr/bin/env bash
|
|
54208
|
+
# Generated by \`runtype deploy --target cloudflare\`.
|
|
54209
|
+
#
|
|
54210
|
+
# Builds and packs @runtypelabs/runtime from your local monorepo, then
|
|
54211
|
+
# installs all dependencies so you can run \`wrangler dev\` or deploy with
|
|
54212
|
+
# \`wrangler deploy\`.
|
|
54213
|
+
#
|
|
54214
|
+
# Usage (from this directory):
|
|
54215
|
+
# ./setup.sh
|
|
54216
|
+
|
|
54217
|
+
set -euo pipefail
|
|
54218
|
+
|
|
54219
|
+
DEPLOY_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")" && pwd)"
|
|
54220
|
+
MONOREPO_ROOT=${bashSingleQuote(monorepoRoot)}
|
|
54221
|
+
TARBALL_DIR="\${DEPLOY_DIR}/packages"
|
|
54222
|
+
|
|
54223
|
+
echo "[setup] building @runtypelabs/runtime..."
|
|
54224
|
+
pnpm --dir "\${MONOREPO_ROOT}" --filter @runtypelabs/runtime build
|
|
54225
|
+
|
|
54226
|
+
mkdir -p "\${TARBALL_DIR}"
|
|
54227
|
+
|
|
54228
|
+
echo "[setup] packing @runtypelabs/runtime tarball..."
|
|
54229
|
+
pnpm --dir "\${MONOREPO_ROOT}/packages/runtime" pack \\
|
|
54230
|
+
--pack-destination "\${TARBALL_DIR}"
|
|
54231
|
+
|
|
54232
|
+
RUNTIME_TGZ="$(ls "\${TARBALL_DIR}"/runtypelabs-runtime-*.tgz | head -n 1)"
|
|
54233
|
+
if [ -z "\${RUNTIME_TGZ}" ]; then
|
|
54234
|
+
echo "[setup] error: no tarball produced by pnpm pack" >&2
|
|
54235
|
+
exit 1
|
|
54236
|
+
fi
|
|
54237
|
+
RUNTIME_TGZ_NAME="$(basename "\${RUNTIME_TGZ}")"
|
|
54238
|
+
|
|
54239
|
+
echo "[setup] updating package.json with file: dependency..."
|
|
54240
|
+
node -e "
|
|
54241
|
+
const fs = require('fs');
|
|
54242
|
+
const pkg = JSON.parse(fs.readFileSync('\${DEPLOY_DIR}/package.json', 'utf8'));
|
|
54243
|
+
pkg.dependencies['@runtypelabs/runtime'] = 'file:./packages/\${RUNTIME_TGZ_NAME}';
|
|
54244
|
+
fs.writeFileSync('\${DEPLOY_DIR}/package.json', JSON.stringify(pkg, null, 2) + '\\\\n');
|
|
54245
|
+
"
|
|
54246
|
+
|
|
54247
|
+
echo "[setup] installing dependencies..."
|
|
54248
|
+
npm install --no-audit --no-fund
|
|
54249
|
+
|
|
54250
|
+
echo ""
|
|
54251
|
+
echo "[setup] Done! Next steps:"
|
|
54252
|
+
echo " wrangler dev \u2014 preview locally"
|
|
54253
|
+
echo " wrangler deploy \u2014 deploy to Cloudflare Workers"
|
|
54254
|
+
`;
|
|
54255
|
+
}
|
|
54256
|
+
function workerReadme(agentNames, secretNames) {
|
|
54257
|
+
const agentList = agentNames.map((n) => ` - ${n}`).join("\n");
|
|
54258
|
+
const secretList = secretNames.length > 0 ? secretNames.map((s) => ` wrangler secret put ${s}`).join("\n") : " (none detected)";
|
|
54259
|
+
return `# Runtype Cloudflare Workers Deployment
|
|
54260
|
+
|
|
54261
|
+
Generated by \`runtype deploy --target cloudflare\`. Contains the following agents:
|
|
54262
|
+
|
|
54263
|
+
${agentList}
|
|
54264
|
+
|
|
54265
|
+
## Setup
|
|
54266
|
+
|
|
54267
|
+
\`\`\`bash
|
|
54268
|
+
chmod +x setup.sh && ./setup.sh # build runtime + install deps
|
|
54269
|
+
\`\`\`
|
|
54270
|
+
|
|
54271
|
+
## Secrets
|
|
54272
|
+
|
|
54273
|
+
Set each API key your agents use:
|
|
54274
|
+
|
|
54275
|
+
\`\`\`bash
|
|
54276
|
+
${secretList}
|
|
54277
|
+
\`\`\`
|
|
54278
|
+
|
|
54279
|
+
## Run locally
|
|
54280
|
+
|
|
54281
|
+
\`\`\`bash
|
|
54282
|
+
wrangler dev
|
|
54283
|
+
\`\`\`
|
|
54284
|
+
|
|
54285
|
+
## Deploy
|
|
54286
|
+
|
|
54287
|
+
\`\`\`bash
|
|
54288
|
+
wrangler deploy
|
|
54289
|
+
\`\`\`
|
|
54290
|
+
|
|
54291
|
+
## Health check
|
|
54292
|
+
|
|
54293
|
+
\`GET /health\` returns \`{"status":"ok","agents":[...]}\`.
|
|
54294
|
+
|
|
54295
|
+
## Call an agent
|
|
54296
|
+
|
|
54297
|
+
\`\`\`bash
|
|
54298
|
+
curl https://<worker-subdomain>.workers.dev/agent/<name> \\
|
|
54299
|
+
-H 'Content-Type: application/json' \\
|
|
54300
|
+
-d '{"messages":[{"role":"user","content":"Hello"}]}'
|
|
54301
|
+
\`\`\`
|
|
54302
|
+
`;
|
|
54303
|
+
}
|
|
54304
|
+
function vercelRouteTs(agentSlugs) {
|
|
54305
|
+
const imports = agentSlugs.map((slug, i) => `import agent${i}Json from '../agents/${slug}.json'`).join("\n");
|
|
54306
|
+
const agentFiles = agentSlugs.map((slug, i) => ` ['${slug}.json', agent${i}Json],`).join("\n");
|
|
54307
|
+
return `/**
|
|
54308
|
+
* Generated by \`runtype deploy --target vercel\`.
|
|
54309
|
+
*
|
|
54310
|
+
* Catch-all Vercel Function. All traffic is rewritten here by vercel.json.
|
|
54311
|
+
* Routes:
|
|
54312
|
+
* GET /health \u2014 liveness probe (lists registered agent names)
|
|
54313
|
+
* POST /agent/:name \u2014 SSE stream of the agent event schema
|
|
54314
|
+
*
|
|
54315
|
+
* Agent definitions are statically imported and bundled by Vercel.
|
|
54316
|
+
* To add a new agent:
|
|
54317
|
+
* 1. Export it with \`runtype deploy --agent <id> --target vercel\`
|
|
54318
|
+
* 2. Or drop a JSON file under agents/ and add an import + entry below
|
|
54319
|
+
* 3. Run \`vercel deploy\`
|
|
54320
|
+
*/
|
|
54321
|
+
import { Hono } from 'hono'
|
|
54322
|
+
import { handle } from 'hono/vercel'
|
|
54323
|
+
import { cors } from 'hono/cors'
|
|
54324
|
+
import {
|
|
54325
|
+
VercelAdapter,
|
|
54326
|
+
createRuntime,
|
|
54327
|
+
exportedAgentSchema,
|
|
54328
|
+
type ExportedAgent,
|
|
54329
|
+
} from '@runtypelabs/runtime'
|
|
54330
|
+
|
|
54331
|
+
// ---------------------------------------------------------------------------
|
|
54332
|
+
// Agent registry \u2014 built at module load, cached across warm invocations
|
|
54333
|
+
// ---------------------------------------------------------------------------
|
|
54334
|
+
|
|
54335
|
+
${imports}
|
|
54336
|
+
|
|
54337
|
+
function parseAgent(json: unknown, filename: string): ExportedAgent {
|
|
54338
|
+
try {
|
|
54339
|
+
return exportedAgentSchema.parse(json)
|
|
54340
|
+
} catch (err) {
|
|
54341
|
+
throw new Error(
|
|
54342
|
+
\`[runtype] invalid agent JSON in \${filename}: \${
|
|
54343
|
+
err instanceof Error ? err.message : String(err)
|
|
54344
|
+
}\`
|
|
54345
|
+
)
|
|
54346
|
+
}
|
|
54347
|
+
}
|
|
54348
|
+
|
|
54349
|
+
const agentFiles: Array<[string, unknown]> = [
|
|
54350
|
+
${agentFiles}
|
|
54351
|
+
]
|
|
54352
|
+
|
|
54353
|
+
const agentRegistry: Record<string, ExportedAgent> = {}
|
|
54354
|
+
for (const [filename, json] of agentFiles) {
|
|
54355
|
+
const agent = parseAgent(json, filename)
|
|
54356
|
+
if (agentRegistry[agent.name]) {
|
|
54357
|
+
throw new Error(\`[runtype] duplicate agent name "\${agent.name}" in \${filename}\`)
|
|
54358
|
+
}
|
|
54359
|
+
agentRegistry[agent.name] = agent
|
|
54360
|
+
}
|
|
54361
|
+
|
|
54362
|
+
// ---------------------------------------------------------------------------
|
|
54363
|
+
// Runtime \u2014 constructed at module scope (warm across invocations)
|
|
54364
|
+
// ---------------------------------------------------------------------------
|
|
54365
|
+
|
|
54366
|
+
const runtime = createRuntime({
|
|
54367
|
+
agents: agentRegistry,
|
|
54368
|
+
keys: { mode: 'own' },
|
|
54369
|
+
adapter: new VercelAdapter(),
|
|
54370
|
+
})
|
|
54371
|
+
|
|
54372
|
+
// ---------------------------------------------------------------------------
|
|
54373
|
+
// Hono app
|
|
54374
|
+
// ---------------------------------------------------------------------------
|
|
54375
|
+
|
|
54376
|
+
const app = new Hono()
|
|
54377
|
+
|
|
54378
|
+
const allowedOriginsEnv = process.env.ALLOWED_ORIGINS?.trim()
|
|
54379
|
+
const allowedOrigins = allowedOriginsEnv
|
|
54380
|
+
? allowedOriginsEnv.split(',').map((o) => o.trim()).filter(Boolean)
|
|
54381
|
+
: '*'
|
|
54382
|
+
|
|
54383
|
+
app.use(
|
|
54384
|
+
'*',
|
|
54385
|
+
cors({
|
|
54386
|
+
origin: allowedOrigins,
|
|
54387
|
+
allowMethods: ['GET', 'POST', 'OPTIONS'],
|
|
54388
|
+
allowHeaders: ['Content-Type', 'Authorization'],
|
|
54389
|
+
maxAge: 86400,
|
|
54390
|
+
})
|
|
54391
|
+
)
|
|
54392
|
+
|
|
54393
|
+
app.get('/health', (c) => c.json({ status: 'ok', agents: Object.keys(agentRegistry) }))
|
|
54394
|
+
|
|
54395
|
+
app.post('/agent/:name', async (c) => {
|
|
54396
|
+
const name = c.req.param('name')
|
|
54397
|
+
if (!runtime.getAgent(name)) {
|
|
54398
|
+
return c.json({ error: \`unknown agent: \${name}\` }, 404)
|
|
54399
|
+
}
|
|
54400
|
+
|
|
54401
|
+
let body: { messages?: Array<{ role: string; content: string }> } = {}
|
|
54402
|
+
try {
|
|
54403
|
+
body = (await c.req.json()) as typeof body
|
|
54404
|
+
} catch {
|
|
54405
|
+
return c.json({ error: 'request body must be JSON' }, 400)
|
|
54406
|
+
}
|
|
54407
|
+
const messages = Array.isArray(body.messages) ? body.messages : []
|
|
54408
|
+
|
|
54409
|
+
try {
|
|
54410
|
+
const response = await runtime.executeAgent(name, {
|
|
54411
|
+
messages: messages as Array<{
|
|
54412
|
+
role: 'system' | 'user' | 'assistant'
|
|
54413
|
+
content: string
|
|
54414
|
+
}>,
|
|
54415
|
+
signal: c.req.raw.signal,
|
|
54416
|
+
})
|
|
54417
|
+
return response
|
|
54418
|
+
} catch (err) {
|
|
54419
|
+
return c.json({ error: err instanceof Error ? err.message : 'unknown error' }, 500)
|
|
54420
|
+
}
|
|
54421
|
+
})
|
|
54422
|
+
|
|
54423
|
+
export const GET = handle(app)
|
|
54424
|
+
export const POST = handle(app)
|
|
54425
|
+
`;
|
|
54426
|
+
}
|
|
54427
|
+
function vercelJson() {
|
|
54428
|
+
return JSON.stringify(
|
|
54429
|
+
{
|
|
54430
|
+
rewrites: [{ source: "/(.*)", destination: "/api/[[...route]]" }],
|
|
54431
|
+
functions: {
|
|
54432
|
+
"api/[[...route]].ts": { maxDuration: 60 }
|
|
54433
|
+
}
|
|
54434
|
+
},
|
|
54435
|
+
null,
|
|
54436
|
+
2
|
|
54437
|
+
);
|
|
54438
|
+
}
|
|
54439
|
+
function vercelPackageJson(name, runtimeDep) {
|
|
54440
|
+
return JSON.stringify(
|
|
54441
|
+
{
|
|
54442
|
+
name,
|
|
54443
|
+
version: "0.0.0",
|
|
54444
|
+
private: true,
|
|
54445
|
+
scripts: {
|
|
54446
|
+
dev: "vercel dev",
|
|
54447
|
+
deploy: "vercel deploy",
|
|
54448
|
+
typecheck: "tsc --noEmit"
|
|
54449
|
+
},
|
|
54450
|
+
dependencies: {
|
|
54451
|
+
"@runtypelabs/runtime": runtimeDep,
|
|
54452
|
+
hono: "^4.12.16"
|
|
54453
|
+
},
|
|
54454
|
+
devDependencies: {
|
|
54455
|
+
"@types/node": "^22.0.0",
|
|
54456
|
+
"@vercel/node": "^5.0.0",
|
|
54457
|
+
typescript: "^5.3.3",
|
|
54458
|
+
vercel: "^44.0.0"
|
|
54459
|
+
}
|
|
54460
|
+
},
|
|
54461
|
+
null,
|
|
54462
|
+
2
|
|
54463
|
+
);
|
|
54464
|
+
}
|
|
54465
|
+
function vercelTsconfigJson() {
|
|
54466
|
+
return JSON.stringify(
|
|
54467
|
+
{
|
|
54468
|
+
compilerOptions: {
|
|
54469
|
+
target: "ES2022",
|
|
54470
|
+
module: "ESNext",
|
|
54471
|
+
moduleResolution: "bundler",
|
|
54472
|
+
strict: true,
|
|
54473
|
+
resolveJsonModule: true,
|
|
54474
|
+
esModuleInterop: true,
|
|
54475
|
+
skipLibCheck: true
|
|
54476
|
+
},
|
|
54477
|
+
include: ["api"]
|
|
54478
|
+
},
|
|
54479
|
+
null,
|
|
54480
|
+
2
|
|
54481
|
+
);
|
|
54482
|
+
}
|
|
54483
|
+
function vercelSetupSh(monorepoRoot) {
|
|
54484
|
+
return `#!/usr/bin/env bash
|
|
54485
|
+
# Generated by \`runtype deploy --target vercel\`.
|
|
54486
|
+
#
|
|
54487
|
+
# Builds and packs @runtypelabs/runtime from your local monorepo, then
|
|
54488
|
+
# installs all dependencies so you can run \`vercel dev\` or deploy with
|
|
54489
|
+
# \`vercel deploy\`.
|
|
54490
|
+
#
|
|
54491
|
+
# Usage (from this directory):
|
|
54492
|
+
# ./setup.sh
|
|
54493
|
+
|
|
54494
|
+
set -euo pipefail
|
|
54495
|
+
|
|
54496
|
+
DEPLOY_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")" && pwd)"
|
|
54497
|
+
MONOREPO_ROOT=${bashSingleQuote(monorepoRoot)}
|
|
54498
|
+
TARBALL_DIR="\${DEPLOY_DIR}/packages"
|
|
54499
|
+
|
|
54500
|
+
echo "[setup] building @runtypelabs/runtime..."
|
|
54501
|
+
pnpm --dir "\${MONOREPO_ROOT}" --filter @runtypelabs/runtime build
|
|
54502
|
+
|
|
54503
|
+
mkdir -p "\${TARBALL_DIR}"
|
|
54504
|
+
|
|
54505
|
+
echo "[setup] packing @runtypelabs/runtime tarball..."
|
|
54506
|
+
pnpm --dir "\${MONOREPO_ROOT}/packages/runtime" pack \\
|
|
54507
|
+
--pack-destination "\${TARBALL_DIR}"
|
|
54508
|
+
|
|
54509
|
+
RUNTIME_TGZ="$(ls "\${TARBALL_DIR}"/runtypelabs-runtime-*.tgz | head -n 1)"
|
|
54510
|
+
if [ -z "\${RUNTIME_TGZ}" ]; then
|
|
54511
|
+
echo "[setup] error: no tarball produced by pnpm pack" >&2
|
|
54512
|
+
exit 1
|
|
54513
|
+
fi
|
|
54514
|
+
RUNTIME_TGZ_NAME="$(basename "\${RUNTIME_TGZ}")"
|
|
54515
|
+
|
|
54516
|
+
echo "[setup] updating package.json with file: dependency..."
|
|
54517
|
+
node -e "
|
|
54518
|
+
const fs = require('fs');
|
|
54519
|
+
const pkg = JSON.parse(fs.readFileSync('\${DEPLOY_DIR}/package.json', 'utf8'));
|
|
54520
|
+
pkg.dependencies['@runtypelabs/runtime'] = 'file:./packages/\${RUNTIME_TGZ_NAME}';
|
|
54521
|
+
fs.writeFileSync('\${DEPLOY_DIR}/package.json', JSON.stringify(pkg, null, 2) + '\\\\n');
|
|
54522
|
+
"
|
|
54523
|
+
|
|
54524
|
+
echo "[setup] installing dependencies..."
|
|
54525
|
+
npm install --no-audit --no-fund
|
|
54526
|
+
|
|
54527
|
+
echo ""
|
|
54528
|
+
echo "[setup] Done! Next steps:"
|
|
54529
|
+
echo " vercel dev \u2014 preview locally"
|
|
54530
|
+
echo " vercel deploy \u2014 deploy to Vercel Functions"
|
|
54531
|
+
`;
|
|
54532
|
+
}
|
|
54533
|
+
function vercelReadme(agentNames, secretNames) {
|
|
54534
|
+
const agentList = agentNames.map((n) => ` - ${n}`).join("\n");
|
|
54535
|
+
const secretList = secretNames.length > 0 ? secretNames.map((s) => ` vercel env add ${s}`).join("\n") : " (none detected)";
|
|
54536
|
+
return `# Runtype Vercel Functions Deployment
|
|
54537
|
+
|
|
54538
|
+
Generated by \`runtype deploy --target vercel\`. Contains the following agents:
|
|
54539
|
+
|
|
54540
|
+
${agentList}
|
|
54541
|
+
|
|
54542
|
+
## Setup
|
|
54543
|
+
|
|
54544
|
+
\`\`\`bash
|
|
54545
|
+
chmod +x setup.sh && ./setup.sh # build runtime + install deps
|
|
54546
|
+
\`\`\`
|
|
54547
|
+
|
|
54548
|
+
## Secrets
|
|
54549
|
+
|
|
54550
|
+
Set each API key your agents use via the Vercel dashboard or CLI:
|
|
54551
|
+
|
|
54552
|
+
\`\`\`bash
|
|
54553
|
+
${secretList}
|
|
54554
|
+
\`\`\`
|
|
54555
|
+
|
|
54556
|
+
## Run locally
|
|
54557
|
+
|
|
54558
|
+
\`\`\`bash
|
|
54559
|
+
vercel dev
|
|
54560
|
+
\`\`\`
|
|
54561
|
+
|
|
54562
|
+
## Deploy
|
|
54563
|
+
|
|
54564
|
+
\`\`\`bash
|
|
54565
|
+
vercel deploy
|
|
54566
|
+
\`\`\`
|
|
54567
|
+
|
|
54568
|
+
## Health check
|
|
54569
|
+
|
|
54570
|
+
\`GET /health\` returns \`{"status":"ok","agents":[...]}\`.
|
|
54571
|
+
|
|
54572
|
+
## Call an agent
|
|
54573
|
+
|
|
54574
|
+
\`\`\`bash
|
|
54575
|
+
curl https://<your-project>.vercel.app/agent/<name> \\
|
|
54576
|
+
-H 'Content-Type: application/json' \\
|
|
54577
|
+
-d '{"messages":[{"role":"user","content":"Hello"}]}'
|
|
54578
|
+
\`\`\`
|
|
54579
|
+
`;
|
|
54580
|
+
}
|
|
53973
54581
|
function collectSecretNames(agentDef) {
|
|
53974
54582
|
const names = /* @__PURE__ */ new Set();
|
|
53975
54583
|
const model = agentDef.config?.model?.toLowerCase();
|
|
@@ -53992,13 +54600,13 @@ function collectSecretNames(agentDef) {
|
|
|
53992
54600
|
function slugify2(s) {
|
|
53993
54601
|
return s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 63);
|
|
53994
54602
|
}
|
|
53995
|
-
var deployCommand = new Command24("deploy").description("Export an agent or flow and scaffold a
|
|
54603
|
+
var deployCommand = new Command24("deploy").description("Export an agent or flow and scaffold a deployment (cloud-run, cloudflare, or vercel)").option("--agent <id>", "Agent ID to export (may be repeated)", (v, acc) => {
|
|
53996
54604
|
acc.push(v);
|
|
53997
54605
|
return acc;
|
|
53998
54606
|
}, []).option("--flow <id>", "Flow ID to export (may be repeated)", (v, acc) => {
|
|
53999
54607
|
acc.push(v);
|
|
54000
54608
|
return acc;
|
|
54001
|
-
}, []).option("--output <dir>", "Output directory for the scaffold (default: ./runtype-deploy)", "./runtype-deploy").option("--name <name>", "Project name used in package.json (default: derived from output dir)").action(
|
|
54609
|
+
}, []).option("--output <dir>", "Output directory for the scaffold (default: ./runtype-deploy)", "./runtype-deploy").option("--name <name>", "Project name used in package.json (default: derived from output dir)").option("--target <target>", "Deployment target: cloud-run, cloudflare, or vercel (default: cloud-run)", "cloud-run").action(
|
|
54002
54610
|
async (options) => {
|
|
54003
54611
|
const agentIds = options.agent;
|
|
54004
54612
|
const flowIds = options.flow;
|
|
@@ -54006,13 +54614,18 @@ var deployCommand = new Command24("deploy").description("Export an agent or flow
|
|
|
54006
54614
|
console.error(chalk30.red("Error: provide at least one --agent <id> or --flow <id>"));
|
|
54007
54615
|
process.exit(1);
|
|
54008
54616
|
}
|
|
54617
|
+
const target = options.target;
|
|
54618
|
+
if (target !== "cloud-run" && target !== "cloudflare" && target !== "vercel") {
|
|
54619
|
+
console.error(chalk30.red(`Error: unknown --target "${target}". Must be one of: cloud-run, cloudflare, vercel`));
|
|
54620
|
+
process.exit(1);
|
|
54621
|
+
}
|
|
54009
54622
|
const apiKey = await ensureAuth();
|
|
54010
54623
|
if (!apiKey) return;
|
|
54011
54624
|
const client = new ApiClient(apiKey);
|
|
54012
54625
|
const outDir = path14.resolve(options.output);
|
|
54013
54626
|
const projectName = options.name ?? slugify2(path14.basename(outDir));
|
|
54014
54627
|
console.log(chalk30.cyan(`
|
|
54015
|
-
Scaffolding deployment to ${outDir}
|
|
54628
|
+
Scaffolding ${target} deployment to ${outDir}
|
|
54016
54629
|
`));
|
|
54017
54630
|
const agentDefs = [];
|
|
54018
54631
|
for (const id of agentIds) {
|
|
@@ -54063,36 +54676,26 @@ Scaffolding deployment to ${outDir}
|
|
|
54063
54676
|
process.exit(1);
|
|
54064
54677
|
}
|
|
54065
54678
|
}
|
|
54679
|
+
const agentSlugs = agentDefs.map(({ name }) => slugify2(name));
|
|
54680
|
+
const slugSet = /* @__PURE__ */ new Set();
|
|
54681
|
+
for (let i = 0; i < agentSlugs.length; i++) {
|
|
54682
|
+
const slug = agentSlugs[i];
|
|
54683
|
+
if (slugSet.has(slug)) {
|
|
54684
|
+
const colliders = agentDefs.filter(({ name }) => slugify2(name) === slug).map(({ name }) => `"${name}"`).join(" and ");
|
|
54685
|
+
console.error(chalk30.red(`Error: agents ${colliders} produce the same slug "${slug}".`));
|
|
54686
|
+
console.error(chalk30.yellow(" Rename one of them in the Runtype dashboard to make slugs unique."));
|
|
54687
|
+
process.exit(1);
|
|
54688
|
+
}
|
|
54689
|
+
slugSet.add(slug);
|
|
54690
|
+
}
|
|
54066
54691
|
fs14.mkdirSync(path14.join(outDir, "agents"), { recursive: true });
|
|
54067
54692
|
fs14.mkdirSync(path14.join(outDir, "packages"), { recursive: true });
|
|
54068
54693
|
for (const { name, def } of agentDefs) {
|
|
54069
54694
|
const filename = `${slugify2(name)}.json`;
|
|
54070
|
-
fs14.writeFileSync(
|
|
54071
|
-
path14.join(outDir, "agents", filename),
|
|
54072
|
-
JSON.stringify(def, null, 2)
|
|
54073
|
-
);
|
|
54695
|
+
fs14.writeFileSync(path14.join(outDir, "agents", filename), JSON.stringify(def, null, 2));
|
|
54074
54696
|
console.log(` Wrote agents/${filename}`);
|
|
54075
54697
|
}
|
|
54076
|
-
|
|
54077
|
-
path14.join(outDir, "server.ts"),
|
|
54078
|
-
serverTs()
|
|
54079
|
-
);
|
|
54080
|
-
fs14.writeFileSync(
|
|
54081
|
-
path14.join(outDir, "Dockerfile"),
|
|
54082
|
-
dockerfile()
|
|
54083
|
-
);
|
|
54084
|
-
fs14.writeFileSync(
|
|
54085
|
-
path14.join(outDir, ".dockerignore"),
|
|
54086
|
-
dockerignore()
|
|
54087
|
-
);
|
|
54088
|
-
fs14.writeFileSync(
|
|
54089
|
-
path14.join(outDir, "tsconfig.json"),
|
|
54090
|
-
tsconfigJson()
|
|
54091
|
-
);
|
|
54092
|
-
fs14.writeFileSync(
|
|
54093
|
-
path14.join(outDir, "package.json"),
|
|
54094
|
-
packageJson(projectName, "workspace:*")
|
|
54095
|
-
);
|
|
54698
|
+
const agentNames = agentDefs.map((a) => a.name);
|
|
54096
54699
|
let monorepoRoot = process.cwd();
|
|
54097
54700
|
for (let i = 0; i < 8; i++) {
|
|
54098
54701
|
if (fs14.existsSync(path14.join(monorepoRoot, "pnpm-workspace.yaml"))) break;
|
|
@@ -54100,46 +54703,90 @@ Scaffolding deployment to ${outDir}
|
|
|
54100
54703
|
if (parent === monorepoRoot) break;
|
|
54101
54704
|
monorepoRoot = parent;
|
|
54102
54705
|
}
|
|
54103
|
-
const setupScript = setupSh(monorepoRoot);
|
|
54104
|
-
const setupPath = path14.join(outDir, "setup.sh");
|
|
54105
|
-
fs14.writeFileSync(setupPath, setupScript);
|
|
54106
|
-
fs14.chmodSync(setupPath, 493);
|
|
54107
54706
|
const allSecrets = /* @__PURE__ */ new Set();
|
|
54108
54707
|
for (const { def } of agentDefs) {
|
|
54109
54708
|
for (const s of collectSecretNames(def)) allSecrets.add(s);
|
|
54110
54709
|
}
|
|
54111
54710
|
const secretNames = Array.from(allSecrets);
|
|
54112
|
-
|
|
54113
|
-
path14.join(outDir, "
|
|
54114
|
-
|
|
54115
|
-
|
|
54116
|
-
|
|
54117
|
-
)
|
|
54118
|
-
|
|
54711
|
+
if (target === "cloudflare") {
|
|
54712
|
+
fs14.mkdirSync(path14.join(outDir, "src"), { recursive: true });
|
|
54713
|
+
fs14.writeFileSync(path14.join(outDir, "src", "index.ts"), workerIndexTs(agentSlugs));
|
|
54714
|
+
fs14.writeFileSync(path14.join(outDir, "wrangler.toml"), wranglerToml(projectName));
|
|
54715
|
+
fs14.writeFileSync(path14.join(outDir, "package.json"), workerPackageJson(projectName, "workspace:*"));
|
|
54716
|
+
fs14.writeFileSync(path14.join(outDir, "tsconfig.json"), workerTsconfigJson());
|
|
54717
|
+
const setupPath = path14.join(outDir, "setup.sh");
|
|
54718
|
+
fs14.writeFileSync(setupPath, workerSetupSh(monorepoRoot));
|
|
54719
|
+
fs14.chmodSync(setupPath, 493);
|
|
54720
|
+
fs14.writeFileSync(path14.join(outDir, "README.md"), workerReadme(agentNames, secretNames));
|
|
54721
|
+
} else if (target === "vercel") {
|
|
54722
|
+
fs14.mkdirSync(path14.join(outDir, "api"), { recursive: true });
|
|
54723
|
+
fs14.writeFileSync(path14.join(outDir, "api", "[[...route]].ts"), vercelRouteTs(agentSlugs));
|
|
54724
|
+
fs14.writeFileSync(path14.join(outDir, "vercel.json"), vercelJson());
|
|
54725
|
+
fs14.writeFileSync(path14.join(outDir, "package.json"), vercelPackageJson(projectName, "workspace:*"));
|
|
54726
|
+
fs14.writeFileSync(path14.join(outDir, "tsconfig.json"), vercelTsconfigJson());
|
|
54727
|
+
const setupPath = path14.join(outDir, "setup.sh");
|
|
54728
|
+
fs14.writeFileSync(setupPath, vercelSetupSh(monorepoRoot));
|
|
54729
|
+
fs14.chmodSync(setupPath, 493);
|
|
54730
|
+
fs14.writeFileSync(path14.join(outDir, "README.md"), vercelReadme(agentNames, secretNames));
|
|
54731
|
+
} else {
|
|
54732
|
+
fs14.writeFileSync(path14.join(outDir, "server.ts"), serverTs());
|
|
54733
|
+
fs14.writeFileSync(path14.join(outDir, "Dockerfile"), dockerfile());
|
|
54734
|
+
fs14.writeFileSync(path14.join(outDir, ".dockerignore"), dockerignore());
|
|
54735
|
+
fs14.writeFileSync(path14.join(outDir, "tsconfig.json"), tsconfigJson());
|
|
54736
|
+
fs14.writeFileSync(path14.join(outDir, "package.json"), packageJson(projectName, "workspace:*"));
|
|
54737
|
+
const setupPath = path14.join(outDir, "setup.sh");
|
|
54738
|
+
fs14.writeFileSync(setupPath, setupSh(monorepoRoot));
|
|
54739
|
+
fs14.chmodSync(setupPath, 493);
|
|
54740
|
+
fs14.writeFileSync(path14.join(outDir, "README.md"), readme(agentNames, secretNames));
|
|
54741
|
+
}
|
|
54119
54742
|
console.log("");
|
|
54120
54743
|
console.log(chalk30.green(`\u2713 Scaffold written to ${outDir}`));
|
|
54121
54744
|
console.log("");
|
|
54122
54745
|
console.log(chalk30.bold("Next steps:"));
|
|
54123
54746
|
console.log(` cd ${options.output}`);
|
|
54124
54747
|
console.log(" chmod +x setup.sh && ./setup.sh # pack runtime + install deps");
|
|
54125
|
-
|
|
54126
|
-
|
|
54127
|
-
|
|
54128
|
-
|
|
54129
|
-
|
|
54130
|
-
|
|
54748
|
+
if (target === "cloudflare") {
|
|
54749
|
+
console.log(" wrangler dev # test locally");
|
|
54750
|
+
console.log("");
|
|
54751
|
+
if (secretNames.length > 0) {
|
|
54752
|
+
console.log(chalk30.yellow("Required secrets (set via wrangler):"));
|
|
54753
|
+
for (const s of secretNames) {
|
|
54754
|
+
console.log(` wrangler secret put ${chalk30.cyan(s)}`);
|
|
54755
|
+
}
|
|
54756
|
+
console.log("");
|
|
54131
54757
|
}
|
|
54758
|
+
console.log("Deploy to Cloudflare Workers:");
|
|
54759
|
+
console.log(" wrangler deploy");
|
|
54760
|
+
} else if (target === "vercel") {
|
|
54761
|
+
console.log(" vercel dev # test locally");
|
|
54132
54762
|
console.log("");
|
|
54133
|
-
|
|
54134
|
-
|
|
54763
|
+
if (secretNames.length > 0) {
|
|
54764
|
+
console.log(chalk30.yellow("Required secrets (set via Vercel):"));
|
|
54765
|
+
for (const s of secretNames) {
|
|
54766
|
+
console.log(` vercel env add ${chalk30.cyan(s)}`);
|
|
54767
|
+
}
|
|
54768
|
+
console.log("");
|
|
54769
|
+
}
|
|
54770
|
+
console.log("Deploy to Vercel Functions:");
|
|
54771
|
+
console.log(" vercel deploy");
|
|
54772
|
+
} else {
|
|
54773
|
+
console.log(" npm run dev # test locally");
|
|
54135
54774
|
console.log("");
|
|
54775
|
+
if (secretNames.length > 0) {
|
|
54776
|
+
console.log(chalk30.yellow("Required secrets (set before deploying):"));
|
|
54777
|
+
for (const s of secretNames) {
|
|
54778
|
+
console.log(` ${chalk30.cyan(s)}`);
|
|
54779
|
+
}
|
|
54780
|
+
console.log("");
|
|
54781
|
+
console.log(" Set via Cloud Run: gcloud run deploy \u2026 --set-secrets KEY=NAME:latest");
|
|
54782
|
+
console.log(" Or export locally: export KEY=<value>");
|
|
54783
|
+
console.log("");
|
|
54784
|
+
}
|
|
54785
|
+
console.log("Deploy to Cloud Run:");
|
|
54786
|
+
console.log(` gcloud run deploy ${projectName} --source ${options.output} \\`);
|
|
54787
|
+
console.log(" --region us-central1 --platform managed \\");
|
|
54788
|
+
console.log(" --allow-unauthenticated --port 8080");
|
|
54136
54789
|
}
|
|
54137
|
-
console.log("Deploy to Cloud Run:");
|
|
54138
|
-
console.log(
|
|
54139
|
-
` gcloud run deploy ${projectName} --source ${options.output} \\`
|
|
54140
|
-
);
|
|
54141
|
-
console.log(" --region us-central1 --platform managed \\");
|
|
54142
|
-
console.log(" --allow-unauthenticated --port 8080");
|
|
54143
54790
|
}
|
|
54144
54791
|
);
|
|
54145
54792
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@runtypelabs/cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.15.0",
|
|
4
4
|
"description": "Command-line interface for Runtype AI platform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"micromatch": "^4.0.8",
|
|
22
22
|
"yaml": "^2.8.3",
|
|
23
23
|
"@runtypelabs/ink-components": "0.3.1",
|
|
24
|
-
"@runtypelabs/sdk": "1.
|
|
24
|
+
"@runtypelabs/sdk": "1.24.0",
|
|
25
25
|
"@runtypelabs/terminal-animations": "0.2.0"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|