@standardagents/cli 0.12.9 → 0.13.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 CHANGED
@@ -4,7 +4,7 @@ import path3 from 'path';
4
4
  import fs3 from 'fs';
5
5
  import crypto from 'crypto';
6
6
  import readline from 'readline';
7
- import { spawn } from 'child_process';
7
+ import { spawn, execSync } from 'child_process';
8
8
  import chalk from 'chalk';
9
9
  import { parse, modify, applyEdits } from 'jsonc-parser';
10
10
  import { loadFile, writeFile, generateCode } from 'magicast';
@@ -127,16 +127,37 @@ interface ThreadState {
127
127
  agentId: string; // Agent identifier
128
128
  userId: string | null; // User identifier (if set)
129
129
  createdAt: number; // Creation timestamp
130
+ children: SubagentRegistryEntry[]; // Resumable child registry
131
+ terminated: number | null; // Soft-termination timestamp
130
132
 
131
133
  // Methods
132
134
  getMessages(options?): Promise<MessagesResult>; // Get conversation history
133
135
  injectMessage(input): Promise<Message>; // Add message to thread
136
+ queueMessage(input): Promise<void>; // Queue message for next step
134
137
  loadModel(name): Promise<ModelConfig>; // Load model definition
135
138
  loadPrompt(name): Promise<PromptConfig>; // Load prompt definition
136
139
  loadAgent(name): Promise<AgentConfig>; // Load agent definition
140
+ env(propertyName): Promise<string>; // Resolve env value for this thread
141
+ setEnv(propertyName, value): Promise<void>; // Set thread env + propagate to active descendants
142
+ notifyParent(content): Promise<void>; // Explicitly queue a silent message to the parent
143
+ setStatus(status): Promise<void>; // Update this child in the parent registry
144
+ getChildThread(referenceId): Promise<ThreadState | null>; // Resolve child thread
145
+ getParentThread(): Promise<ThreadState | null>; // Resolve parent thread
146
+ terminate(): Promise<void>; // Soft-terminate thread
137
147
  }
138
148
  \`\`\`
139
149
 
150
+ ## Subagents
151
+
152
+ \`dual_ai\` agents can be used as subagents from prompt tool configs:
153
+
154
+ - Each subagent runs in its own thread (\`DurableThread\`)
155
+ - Parent/child linkage is tracked in thread metadata
156
+ - Resumable children are visible in \`state.children\`
157
+ - Parent threads create/message resumable children via built-ins (\`subagent_create\`, \`subagent_message\`)
158
+ - Child completion results are queued back to the parent when \`parentCommunication\` is \`implicit\`
159
+ - Explicit relationships can stay idle until code calls \`state.notifyParent()\` or \`state.setStatus()\`
160
+
140
161
  Access in tools:
141
162
  \`\`\`typescript
142
163
  export default defineTool('...', schema, async (state, args) => {
@@ -297,12 +318,14 @@ Prompts define system instructions, model selection, and available tools for LLM
297
318
  | \`toolDescription\` | \`string\` | Yes | Description shown when used as a tool |
298
319
  | \`prompt\` | \`string \\| StructuredPrompt\` | Yes | System instructions |
299
320
  | \`model\` | \`string\` | Yes | Model name to use (references \`agents/models/\`) |
300
- | \`tools\` | \`(string \\| ToolConfig)[]\` | No | Available tools (include ai_human agent names for handoffs) |
321
+ | \`tools\` | \`(string \\| ToolConfig \\| SubagentToolConfig)[]\` | No | Available tools (include ai_human agent names for handoffs and dual_ai subagent configs) |
301
322
  | \`includeChat\` | \`boolean\` | No | Include full conversation history |
302
323
  | \`includePastTools\` | \`boolean\` | No | Include previous tool results |
303
324
  | \`parallelToolCalls\` | \`boolean\` | No | Allow multiple concurrent tool calls |
304
325
  | \`toolChoice\` | \`'auto' \\| 'none' \\| 'required'\` | No | Tool calling strategy |
305
326
  | \`requiredSchema\` | \`z.ZodObject\` | No | Input validation when called as tool |
327
+ | \`variables\` | \`VariableDefinition[]\` | No | Variable declarations (\`name\`, \`type\`, \`required\`, \`scoped\`, \`description\`) |
328
+ | \`env\` | \`Record<string, string>\` | No | Prompt-level default values for variables |
306
329
  | \`hooks\` | \`string[]\` | No | Hook IDs to run for this prompt (overrides agent hooks) |
307
330
  | \`reasoning\` | \`ReasoningConfig\` | No | Extended thinking configuration |
308
331
 
@@ -335,11 +358,14 @@ export default definePrompt({
335
358
  prompt: [
336
359
  { type: 'text', content: 'You are a helpful assistant.\\n\\n' },
337
360
  { type: 'include', prompt: 'common_rules' }, // Includes another prompt
361
+ { type: 'env', property: 'ASSISTANT_TONE' }, // Inject variable value
338
362
  { type: 'text', content: '\\n\\nBe concise.' },
339
363
  ],
340
364
  });
341
365
  \`\`\`
342
366
 
367
+ \`type: 'env'\` inserts a resolved thread variable value. Use this only for non-secret values that are safe to expose to the LLM.
368
+
343
369
  ## Tool Configuration
344
370
 
345
371
  Tools can be simple names or detailed configs:
@@ -357,6 +383,48 @@ tools: [
357
383
  ],
358
384
  \`\`\`
359
385
 
386
+ ### Subagent Tool Configuration
387
+
388
+ Use \`SubagentToolConfig\` when the tool is a \`dual_ai\` agent:
389
+
390
+ \`\`\`typescript
391
+ tools: [
392
+ // Blocking, non-resumable (default)
393
+ { name: 'data_processor_agent' },
394
+
395
+ // Non-blocking, resumable with a single instance
396
+ {
397
+ name: 'browser_agent',
398
+ blocking: false,
399
+ immediate: {
400
+ nameEnv: 'BROWSER_AGENT_NAME',
401
+ descriptionEnv: 'BROWSER_AGENT_DESCRIPTION',
402
+ scopedEnv: ['BROWSER_AGENT_API_KEY'],
403
+ },
404
+ optional: 'ENABLE_BROWSER_AGENT',
405
+ initAgentNameProperty: 'name',
406
+ resumable: {
407
+ receives_messages: 'side_a',
408
+ maxInstances: 1,
409
+ parentCommunication: 'explicit',
410
+ },
411
+ },
412
+ ]
413
+ \`\`\`
414
+
415
+ When prompt-configured resumable dual_ai subagents exist, the runtime auto-injects:
416
+ - \`subagent_create\` for spawning new child instances
417
+ - \`subagent_message\` for messaging active resumable instances
418
+
419
+ \`subagent_create\` supports optional \`name\` for human-friendly child thread labels.
420
+ Pair it with \`initAgentNameProperty\` to map that argument into a \`name:<value>\` thread tag.
421
+
422
+ Set \`immediate: true\` to run a tool automatically when the prompt activates.
423
+ Use \`immediate: { nameEnv, descriptionEnv, scopedEnv }\` when you want safe per-instance bootstrap hints while keeping copied scoped env runtime-only.
424
+ Set \`optional: 'ENV_NAME'\` to enable a subagent branch only when env resolves to \`true\`, \`1\`, or \`yes\`.
425
+ Set \`resumable.parentCommunication: 'explicit'\` when the child should stay quiet until its own tools or hooks call \`state.notifyParent()\` or \`state.setStatus()\`.
426
+ If required scoped vars are missing, the runtime returns \`error_code: "subagent_env_required"\` with a temporary \`GET/POST /api/threads/:id/variables/:requestId\` endpoint in \`error_data.endpoint\`.
427
+
360
428
  ## Input Validation
361
429
 
362
430
  Validate inputs when prompt is called as a tool:
@@ -447,6 +515,7 @@ Agents orchestrate conversations by defining prompts, stop conditions, and turn
447
515
  | \`maxSessionTurns\` | \`number\` | No | Max total turns across both sides |
448
516
  | \`exposeAsTool\` | \`boolean\` | No | Allow other prompts to hand off to this agent |
449
517
  | \`toolDescription\` | \`string\` | No | Description when used as tool (required if exposeAsTool) |
518
+ | \`env\` | \`Record<string, string>\` | No | Agent-level default variable values |
450
519
  | \`hooks\` | \`string[]\` | No | Hook IDs to run for this agent (fallback if prompt has no hooks) |
451
520
  | \`tags\` | \`string[]\` | No | Tags for categorization and filtering |
452
521
 
@@ -460,6 +529,8 @@ Agents orchestrate conversations by defining prompts, stop conditions, and turn
460
529
  | \`stopTool\` | \`string\` | No | Tool that stops this side's turn |
461
530
  | \`stopToolResponseProperty\` | \`string\` | No | Property to extract from stop tool result |
462
531
  | \`endConversationTool\` | \`string\` | No | Tool that ends the entire conversation |
532
+ | \`failSessionTool\` | \`string\` | No | Tool that fails and ends the entire conversation |
533
+ | \`statusTool\` | \`string\` | No | Tool that reports subagent status to a parent registry |
463
534
  | \`maxTurns\` | \`number\` | No | Maximum turns for this side |
464
535
  | \`manualStopCondition\` | \`boolean\` | No | Enable custom stop handling via hooks |
465
536
 
@@ -504,6 +575,34 @@ export default defineAgent({
504
575
  });
505
576
  \`\`\`
506
577
 
578
+ ## Dual-AI Subagent Pattern
579
+
580
+ When a \`dual_ai\` agent is used as a subagent tool, a common split is:
581
+ - **sideA**: performs work (tools, data gathering, execution)
582
+ - **sideB**: reflection, verification, and quality checks
583
+
584
+ \`\`\`typescript
585
+ export default defineAgent({
586
+ name: 'research_subagent',
587
+ type: 'dual_ai',
588
+ exposeAsTool: true,
589
+ toolDescription: 'Researches and validates findings autonomously',
590
+ maxSessionTurns: 16,
591
+ sideA: {
592
+ label: 'Worker',
593
+ prompt: 'research_worker',
594
+ statusTool: 'set_subagent_status',
595
+ failSessionTool: 'fail_research_subagent',
596
+ endConversationTool: 'finish_subagent',
597
+ },
598
+ sideB: {
599
+ label: 'Reviewer',
600
+ prompt: 'research_reviewer',
601
+ stopOnResponse: true,
602
+ },
603
+ });
604
+ \`\`\`
605
+
507
606
  ## Agent Handoffs
508
607
 
509
608
  Expose an agent for handoffs from other prompts:
@@ -524,11 +623,12 @@ Other prompts can then include the agent name in their \`tools\` array to enable
524
623
 
525
624
  ## Stop Conditions (Priority Order)
526
625
 
527
- 1. **endConversationTool** - Ends entire conversation (highest priority)
528
- 2. **stopTool** - Ends current side's turn
529
- 3. **maxTurns** - Ends side's participation when reached
530
- 4. **stopOnResponse** - Ends turn when LLM returns text
531
- 5. **maxSessionTurns** - Ends conversation (hard limit: 250)
626
+ 1. **failSessionTool** - Ends entire conversation with a terminal failure
627
+ 2. **endConversationTool** - Ends entire conversation successfully
628
+ 3. **stopTool** - Ends current side's turn
629
+ 4. **maxTurns** - Ends side's participation when reached
630
+ 5. **stopOnResponse** - Ends turn when LLM returns text
631
+ 6. **maxSessionTurns** - Ends conversation (hard limit: 250)
532
632
 
533
633
  ## Hooks
534
634
 
@@ -578,7 +678,7 @@ defineTool({
578
678
  description: string, // What the tool does (shown to LLM)
579
679
  args?: z.ZodObject, // Input validation schema (optional)
580
680
  execute: (state, args) => ToolResult, // Implementation
581
- tenvs?: z.ZodObject, // Thread environment variables (optional)
681
+ variables?: VariableDefinition[], // Declared variables (optional)
582
682
  })
583
683
  \`\`\`
584
684
 
@@ -611,6 +711,8 @@ export default defineTool({
611
711
  | \`status\` | \`'success' \\| 'error'\` | Whether the tool succeeded |
612
712
  | \`result\` | \`string\` | Tool output (required for success) |
613
713
  | \`error\` | \`string\` | Error message (for error status) |
714
+ | \`error_code\` | \`string\` | Machine-readable error code |
715
+ | \`error_data\` | \`Record<string, unknown>\` | Structured error payload |
614
716
  | \`attachments\` | \`ToolAttachment[]\` | Files to attach (images, etc.) |
615
717
 
616
718
  ## ThreadState Access
@@ -630,8 +732,9 @@ execute: async (state, args) => {
630
732
  // Message history
631
733
  const messages = state.messages;
632
734
 
633
- // Environment bindings
634
- const env = state.env;
735
+ // Thread variable resolution
736
+ const apiKey = await state.env('GOOGLE_API_KEY');
737
+ await state.setEnv('LAST_TOOL_RUN_AT', new Date().toISOString());
635
738
 
636
739
  // Parent state (for sub-prompts)
637
740
  const root = state.rootState;
@@ -718,25 +821,33 @@ export default defineTool({
718
821
  });
719
822
  \`\`\`
720
823
 
721
- ## Thread Environment Variables (tenvs)
824
+ ## Variables and Env
722
825
 
723
- Tools can declare required thread environment variables:
826
+ Tools can declare variable requirements with \`variables\`, including \`required\` and \`description\` metadata:
724
827
 
725
828
  \`\`\`typescript
726
829
  export default defineTool({
727
830
  description: 'Search uploaded documents',
728
831
  args: z.object({ query: z.string() }),
729
832
  execute: async (state, args) => {
730
- const vectorStoreId = state.tenvs.vectorStoreId;
833
+ const vectorStoreId = await state.env('VECTOR_STORE_ID');
731
834
  const results = await searchVectorStore(vectorStoreId, args.query);
732
835
  return { status: 'success', result: JSON.stringify(results) };
733
836
  },
734
- tenvs: z.object({
735
- vectorStoreId: z.string().describe('OpenAI Vector Store ID'),
736
- }),
837
+ variables: [
838
+ {
839
+ name: 'VECTOR_STORE_ID',
840
+ type: 'text',
841
+ required: true,
842
+ scoped: false,
843
+ description: 'OpenAI Vector Store ID',
844
+ },
845
+ ],
737
846
  });
738
847
  \`\`\`
739
848
 
849
+ Use \`scoped: true\` for per-instance values that should not inherit from parent thread env (for example per-account OAuth tokens on subagents).
850
+
740
851
  ## Returning Attachments
741
852
 
742
853
  Tools can return file attachments (e.g., generated images):
@@ -1056,6 +1167,10 @@ export default defineThreadEndpoint(async (req, state) => {
1056
1167
  order: 'desc',
1057
1168
  });
1058
1169
 
1170
+ // Thread env (thread scope + active descendants)
1171
+ const approvalGate = await state.env('TOPDOWN_APPROVAL_GATE');
1172
+ await state.setEnv('TOPDOWN_APPROVAL_GATE', approvalGate || 'open');
1173
+
1059
1174
  // File system operations
1060
1175
  const files = await state.findFiles('**/*.json');
1061
1176
  const data = await state.readFile('/data/config.json');
@@ -1702,7 +1817,7 @@ function getPackageVersion() {
1702
1817
  if (process.env.STANDARDAGENTS_WORKSPACE === "1") {
1703
1818
  return "workspace:*";
1704
1819
  }
1705
- return "0.12.9";
1820
+ return "0.13.0";
1706
1821
  }
1707
1822
  async function selectPackageManager(detected) {
1708
1823
  const options = ["npm", "pnpm", "yarn", "bun"];
@@ -1799,21 +1914,25 @@ async function init(projectNameArg, options = {}) {
1799
1914
  switch (pm) {
1800
1915
  case "pnpm":
1801
1916
  createCmd = "pnpm";
1802
- createArgs = ["create", "vite@latest", projectName, "--template", template, "--no-interactive"];
1917
+ createArgs = ["create", "vite@latest", projectName, "--template", template, "--yes"];
1803
1918
  break;
1804
1919
  case "yarn":
1805
1920
  createCmd = "yarn";
1806
- createArgs = ["create", "vite@latest", projectName, "--template", template, "--no-interactive"];
1921
+ createArgs = ["create", "vite@latest", projectName, "--template", template, "--yes"];
1807
1922
  break;
1808
1923
  case "bun":
1809
1924
  createCmd = "bun";
1810
- createArgs = ["create", "vite@latest", projectName, "--template", template, "--no-interactive"];
1925
+ createArgs = ["create", "vite@latest", projectName, "--template", template, "--yes"];
1811
1926
  break;
1812
1927
  default:
1813
1928
  createCmd = "npm";
1814
- createArgs = ["create", "vite@latest", projectName, "--", "--template", template, "--no-interactive"];
1929
+ createArgs = ["create", "vite@latest", projectName, "--", "--template", template, "--yes"];
1815
1930
  }
1816
1931
  await runCommand(createCmd, createArgs, cwd);
1932
+ const createdPackageJsonPath = path3.join(projectPath, "package.json");
1933
+ if (!fs3.existsSync(createdPackageJsonPath)) {
1934
+ throw new Error("Vite project scaffolding did not create package.json");
1935
+ }
1817
1936
  } catch (error) {
1818
1937
  logger.error("Failed to create Vite project");
1819
1938
  process.exit(1);
@@ -2916,16 +3035,307 @@ async function listPacked() {
2916
3035
  console.log("");
2917
3036
  }
2918
3037
  }
3038
+ var DEFAULT_ENDPOINT = "https://api.standardagents.ai";
3039
+ var FREE_TIER_BUNDLE_LIMIT = 5 * 1024 * 1024;
3040
+ function parseEnvFile(content) {
3041
+ const result = {};
3042
+ for (const line of content.split("\n")) {
3043
+ const trimmed = line.trim();
3044
+ if (!trimmed || trimmed.startsWith("#")) continue;
3045
+ const eqIndex = trimmed.indexOf("=");
3046
+ if (eqIndex === -1) continue;
3047
+ const key = trimmed.slice(0, eqIndex).trim();
3048
+ let value = trimmed.slice(eqIndex + 1).trim();
3049
+ if (value.startsWith('"') && value.endsWith('"')) {
3050
+ value = value.slice(1, -1).replace(/\\"/g, '"');
3051
+ } else if (value.startsWith("'") && value.endsWith("'")) {
3052
+ value = value.slice(1, -1);
3053
+ }
3054
+ result[key] = value;
3055
+ }
3056
+ return result;
3057
+ }
3058
+ function compareVersions(a, b) {
3059
+ const [coreA, preA] = a.replace(/^v/, "").split("-", 2);
3060
+ const [coreB, preB] = b.replace(/^v/, "").split("-", 2);
3061
+ const partsA = coreA.split(".").map(Number);
3062
+ const partsB = coreB.split(".").map(Number);
3063
+ for (let i = 0; i < 3; i++) {
3064
+ const va = partsA[i] ?? 0;
3065
+ const vb = partsB[i] ?? 0;
3066
+ if (va < vb) return -1;
3067
+ if (va > vb) return 1;
3068
+ }
3069
+ if (preA && !preB) return -1;
3070
+ if (!preA && preB) return 1;
3071
+ return 0;
3072
+ }
3073
+ function validateBundleSize(sizeBytes) {
3074
+ if (sizeBytes > FREE_TIER_BUNDLE_LIMIT) {
3075
+ return `Bundle size (${formatBytes(sizeBytes)}) exceeds the free tier limit (${formatBytes(FREE_TIER_BUNDLE_LIMIT)}). A paid plan may be required.`;
3076
+ }
3077
+ return null;
3078
+ }
3079
+ function createManifest(agents, builderVersion) {
3080
+ return {
3081
+ agents,
3082
+ builder_version: builderVersion
3083
+ };
3084
+ }
3085
+ function formatBytes(bytes) {
3086
+ if (bytes < 1024) return `${bytes} B`;
3087
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
3088
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
3089
+ }
3090
+ function formatDeployError(response) {
3091
+ if (response.error) {
3092
+ return `${response.error.code}: ${response.error.message}`;
3093
+ }
3094
+ if (response.errors && response.errors.length > 0) {
3095
+ return response.errors.join("\n");
3096
+ }
3097
+ return "Unknown error";
3098
+ }
3099
+ function detectProject() {
3100
+ const hasWranglerJsonc = fs3.existsSync("wrangler.jsonc") || fs3.existsSync("wrangler.json");
3101
+ const hasAgentsDir = fs3.existsSync("agents/agents");
3102
+ return hasWranglerJsonc || hasAgentsDir;
3103
+ }
3104
+ function loadConfig(options) {
3105
+ const envFileVars = fs3.existsSync(".env") ? parseEnvFile(fs3.readFileSync(".env", "utf-8")) : {};
3106
+ const apiKey = options.apiKey || process.env.PLATFORM_API_KEY || envFileVars.PLATFORM_API_KEY;
3107
+ if (!apiKey) {
3108
+ throw new Error(
3109
+ "No API key found. Provide one with --api-key, set PLATFORM_API_KEY env var, or add it to .env"
3110
+ );
3111
+ }
3112
+ const endpoint = options.endpoint || process.env.PLATFORM_ENDPOINT || envFileVars.PLATFORM_ENDPOINT || DEFAULT_ENDPOINT;
3113
+ return { apiKey, endpoint };
3114
+ }
3115
+ function discoverAgents() {
3116
+ const agentsDir = "agents/agents";
3117
+ if (!fs3.existsSync(agentsDir)) return [];
3118
+ const scriptExtensions = /* @__PURE__ */ new Set([".ts", ".js", ".mts", ".mjs"]);
3119
+ const files = fs3.readdirSync(agentsDir).filter((f) => scriptExtensions.has(path3.extname(f)));
3120
+ return files.map((file) => {
3121
+ const filePath = path3.join(agentsDir, file);
3122
+ const realPath = fs3.realpathSync(filePath);
3123
+ if (!realPath.startsWith(fs3.realpathSync("."))) {
3124
+ return path3.basename(file, path3.extname(file));
3125
+ }
3126
+ const content = fs3.readFileSync(filePath, "utf-8");
3127
+ const nameMatch = content.match(/defineAgent\s*\(\s*\{[\s\S]*?\bname\s*:\s*['"]([^'"]+)['"]/);
3128
+ return nameMatch ? nameMatch[1] : path3.basename(file, path3.extname(file));
3129
+ });
3130
+ }
3131
+ function getBuilderVersion() {
3132
+ const searchPaths = [
3133
+ "node_modules/@standardagents/builder/package.json",
3134
+ "../node_modules/@standardagents/builder/package.json"
3135
+ ];
3136
+ for (const p of searchPaths) {
3137
+ if (fs3.existsSync(p)) {
3138
+ const pkg = JSON.parse(fs3.readFileSync(p, "utf-8"));
3139
+ return pkg.version;
3140
+ }
3141
+ }
3142
+ throw new Error("Could not find @standardagents/builder. Is it installed?");
3143
+ }
3144
+ function detectPackageManager3() {
3145
+ const userAgent = process.env.npm_config_user_agent;
3146
+ if (userAgent) {
3147
+ if (userAgent.includes("pnpm")) return "pnpm";
3148
+ if (userAgent.includes("yarn")) return "yarn";
3149
+ if (userAgent.includes("bun")) return "bun";
3150
+ }
3151
+ if (fs3.existsSync("pnpm-lock.yaml")) return "pnpm";
3152
+ if (fs3.existsSync("yarn.lock")) return "yarn";
3153
+ if (fs3.existsSync("bun.lockb") || fs3.existsSync("bun.lock")) return "bun";
3154
+ return "npm";
3155
+ }
3156
+ function buildProject(endpoint) {
3157
+ const pm = detectPackageManager3();
3158
+ const buildCmd = pm === "npm" ? "npx vite build" : `${pm} exec vite build`;
3159
+ execSync(buildCmd, {
3160
+ stdio: "inherit",
3161
+ env: {
3162
+ ...process.env,
3163
+ PLATFORM_ENDPOINT: endpoint
3164
+ }
3165
+ });
3166
+ }
3167
+ function findWorkerBundle() {
3168
+ const searchDirs = [".wrangler/tmp", "dist"];
3169
+ for (const dir of searchDirs) {
3170
+ if (!fs3.existsSync(dir)) continue;
3171
+ const bundle = findBundleInDir(dir);
3172
+ if (bundle) return bundle;
3173
+ }
3174
+ throw new Error(
3175
+ "Could not find Worker bundle in build output.\nExpected build output in .wrangler/tmp/ or dist/.\nMake sure `vite build` completed successfully."
3176
+ );
3177
+ }
3178
+ function findBundleInDir(dir) {
3179
+ const entries = fs3.readdirSync(dir, { withFileTypes: true });
3180
+ const jsFiles = entries.filter((e) => e.isFile() && (e.name.endsWith(".js") || e.name.endsWith(".mjs")));
3181
+ jsFiles.sort((a, b) => {
3182
+ const aIsIndex = a.name === "index.js" || a.name === "index.mjs" ? 0 : 1;
3183
+ const bIsIndex = b.name === "index.js" || b.name === "index.mjs" ? 0 : 1;
3184
+ if (aIsIndex !== bIsIndex) return aIsIndex - bIsIndex;
3185
+ const aSize = fs3.statSync(path3.join(dir, a.name)).size;
3186
+ const bSize = fs3.statSync(path3.join(dir, b.name)).size;
3187
+ return bSize - aSize;
3188
+ });
3189
+ for (const entry of jsFiles) {
3190
+ const fullPath = path3.join(dir, entry.name);
3191
+ const content = fs3.readFileSync(fullPath);
3192
+ if (content.length > 0 && content.toString("utf-8", 0, 1e4).includes("export")) {
3193
+ return { bundlePath: fullPath, bundleContent: content };
3194
+ }
3195
+ }
3196
+ for (const entry of entries) {
3197
+ if (entry.isDirectory() && entry.name !== "client" && entry.name !== "node_modules") {
3198
+ const result = findBundleInDir(path3.join(dir, entry.name));
3199
+ if (result) return result;
3200
+ }
3201
+ }
3202
+ return null;
3203
+ }
3204
+ async function checkPlatformVersion(endpoint, builderVersion) {
3205
+ const res = await fetch(`${endpoint}/manifest`);
3206
+ if (!res.ok) {
3207
+ throw new Error(`Failed to check platform version: ${res.status} ${res.statusText}`);
3208
+ }
3209
+ const manifest = await res.json();
3210
+ if (compareVersions(builderVersion, manifest.minimum_builder_version) < 0) {
3211
+ throw new Error(
3212
+ `Builder version ${builderVersion} is below the platform minimum (${manifest.minimum_builder_version}).
3213
+ Please upgrade @standardagents/builder:
3214
+ npm install @standardagents/builder@latest`
3215
+ );
3216
+ }
3217
+ return manifest;
3218
+ }
3219
+ async function uploadDeploy(endpoint, apiKey, bundleContent, manifest, builderVersion) {
3220
+ const formData = new FormData();
3221
+ formData.append("bundle", new Blob([new Uint8Array(bundleContent)], { type: "application/javascript" }), "index.js");
3222
+ formData.append("manifest", new Blob([JSON.stringify(manifest)], { type: "application/json" }), "manifest.json");
3223
+ formData.append("builder_version", builderVersion);
3224
+ formData.append("agent_count", String(manifest.agents.length));
3225
+ const res = await fetch(`${endpoint}/deploys`, {
3226
+ method: "POST",
3227
+ headers: {
3228
+ "Authorization": `Bearer ${apiKey}`
3229
+ },
3230
+ body: formData
3231
+ });
3232
+ let body;
3233
+ try {
3234
+ body = await res.json();
3235
+ } catch {
3236
+ throw new Error(`Deploy failed (${res.status}): Invalid response from server`);
3237
+ }
3238
+ if (!res.ok) {
3239
+ const errorMsg = formatDeployError(body);
3240
+ throw new Error(`Deploy failed (${res.status}): ${errorMsg}`);
3241
+ }
3242
+ return body;
3243
+ }
3244
+ async function deploy(options) {
3245
+ console.log("");
3246
+ logger.info(`${chalk.bold("Standard Agents Deploy")}
3247
+ `);
3248
+ if (!detectProject()) {
3249
+ logger.error("This does not appear to be a Standard Agents project.");
3250
+ logger.info("Run this command from a directory with wrangler.jsonc and agents/agents/.");
3251
+ process.exit(1);
3252
+ }
3253
+ let apiKey;
3254
+ let endpoint;
3255
+ try {
3256
+ ({ apiKey, endpoint } = loadConfig(options));
3257
+ } catch (err) {
3258
+ logger.error(err.message);
3259
+ process.exit(1);
3260
+ }
3261
+ logger.success("Configuration loaded");
3262
+ const agents = discoverAgents();
3263
+ if (agents.length === 0) {
3264
+ logger.error("No agents found in agents/agents/.");
3265
+ logger.info("Create at least one agent with defineAgent() before deploying.");
3266
+ process.exit(1);
3267
+ }
3268
+ logger.success(`Found ${agents.length} agent${agents.length === 1 ? "" : "s"}: ${agents.join(", ")}`);
3269
+ let builderVersion;
3270
+ try {
3271
+ builderVersion = getBuilderVersion();
3272
+ } catch (err) {
3273
+ logger.error(err.message);
3274
+ process.exit(1);
3275
+ }
3276
+ logger.info(`Builder version: ${builderVersion}`);
3277
+ try {
3278
+ const platformManifest = await checkPlatformVersion(endpoint, builderVersion);
3279
+ if (compareVersions(builderVersion, platformManifest.latest_builder_version) < 0) {
3280
+ logger.warning(
3281
+ `A newer builder version is available (${platformManifest.latest_builder_version}). Consider upgrading.`
3282
+ );
3283
+ }
3284
+ } catch (err) {
3285
+ logger.error(err.message);
3286
+ process.exit(1);
3287
+ }
3288
+ logger.info("Building project...\n");
3289
+ try {
3290
+ buildProject(endpoint);
3291
+ } catch {
3292
+ console.log("");
3293
+ logger.error("Build failed. See output above for details.");
3294
+ process.exit(1);
3295
+ }
3296
+ console.log("");
3297
+ logger.success("Build complete");
3298
+ let bundlePath;
3299
+ let bundleContent;
3300
+ try {
3301
+ ({ bundlePath, bundleContent } = findWorkerBundle());
3302
+ } catch (err) {
3303
+ logger.error(err.message);
3304
+ process.exit(1);
3305
+ }
3306
+ const manifest = createManifest(agents, builderVersion);
3307
+ logger.success(`Bundle: ${bundlePath} (${formatBytes(bundleContent.length)})`);
3308
+ const sizeWarning = validateBundleSize(bundleContent.length);
3309
+ if (sizeWarning) {
3310
+ logger.warning(sizeWarning);
3311
+ }
3312
+ logger.info("Uploading...");
3313
+ try {
3314
+ const result = await uploadDeploy(endpoint, apiKey, bundleContent, manifest, builderVersion);
3315
+ console.log("");
3316
+ logger.success(chalk.bold("Deploy successful!"));
3317
+ console.log(` Deploy ID: ${result.deploy.id}`);
3318
+ console.log(` Status: ${result.deploy.status}`);
3319
+ if (result.deploy.account_id) {
3320
+ console.log(` URL: https://${result.deploy.account_id}.standardagents.ai`);
3321
+ }
3322
+ console.log("");
3323
+ } catch (err) {
3324
+ logger.error(err.message);
3325
+ process.exit(1);
3326
+ }
3327
+ }
2919
3328
 
2920
3329
  // src/index.ts
2921
3330
  var program = new Command();
2922
- program.name("agents").description("CLI tool for Standard Agents / AgentBuilder").version("0.12.9");
3331
+ program.name("agents").description("CLI tool for Standard Agents / AgentBuilder").version("0.13.0");
2923
3332
  program.command("init [project-name]").description("Create a new Standard Agents project (runs create vite, then scaffold)").option("-y, --yes", "Skip prompts and use defaults").option("--template <template>", "Vite template to use", "vanilla-ts").action(init);
2924
3333
  program.command("scaffold").description("Add Standard Agents to an existing Vite project").option("--force", "Overwrite existing configuration").action(scaffold);
2925
3334
  program.command("init-chat [project-name]").description("Scaffold a frontend chat application").option("-y, --yes", "Skip prompts and use defaults").option("--framework <framework>", "Framework to use (vite or nextjs)").action(initChat);
2926
3335
  program.command("pack [agent-name]").description("Pack an agent with all its dependencies").option("--output <dir>", "Output directory (default: agents/packed)").option("--npm", "Generate npm-ready package structure").option("--version <version>", "Package version (default: 1.0.0)").option("--no-remove", "Keep original files after packing").option("--no-interactive", "Skip interactive item mode selector").action(pack);
2927
3336
  program.command("unpack [package]").description("Unpack a packed agent to the local agents directory").option("--no-signatures", "Remove package signatures (fully editable)").action(unpack);
2928
3337
  program.command("list-packed").description("List all discovered packed agents").action(listPacked);
3338
+ program.command("deploy").description("Build and deploy your project to the Standard Agents platform").option("--api-key <key>", "Platform API key (overrides PLATFORM_API_KEY env var)").option("--endpoint <url>", "Platform API endpoint (default: https://api.standardagents.ai)").action(deploy);
2929
3339
  program.parse();
2930
3340
  //# sourceMappingURL=index.js.map
2931
3341
  //# sourceMappingURL=index.js.map