@standardagents/cli 0.10.1-dev.d2d335e → 0.10.1-next.9e1860c

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
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { Command } from 'commander';
3
- import fs, { readFileSync } from 'fs';
4
- import path, { dirname, resolve } from 'path';
3
+ import fs3, { readFileSync } from 'fs';
4
+ import path3, { dirname, resolve } from 'path';
5
5
  import { fileURLToPath } from 'url';
6
6
  import crypto from 'crypto';
7
7
  import readline from 'readline';
@@ -10,6 +10,7 @@ import chalk from 'chalk';
10
10
  import { parse, modify, applyEdits } from 'jsonc-parser';
11
11
  import { loadFile, writeFile, generateCode } from 'magicast';
12
12
  import { addVitePlugin } from 'magicast/helpers';
13
+ import net from 'net';
13
14
 
14
15
  var logger = {
15
16
  success: (message) => {
@@ -115,30 +116,32 @@ agents/
115
116
 
116
117
  Files are **auto-discovered** at runtime. No manual registration needed.
117
118
 
118
- ## FlowState
119
+ ## ThreadState
119
120
 
120
- \`FlowState\` is the central state object available in tools and hooks:
121
+ \`ThreadState\` is the state object available in tools and hooks:
121
122
 
122
123
  \`\`\`typescript
123
- interface FlowState {
124
- thread: {
125
- id: string; // Thread identifier
126
- instance: DurableThread; // Durable Object instance
127
- };
128
- agent: AgentConfig; // Current agent configuration
129
- prompt: PromptConfig; // Current prompt configuration
130
- model: ModelConfig; // Current model configuration
131
- messages: Message[]; // Conversation history
132
- env: Env; // Cloudflare Worker environment
133
- rootState: FlowState; // Parent state (for sub-prompts)
124
+ interface ThreadState {
125
+ // Identity (readonly)
126
+ threadId: string; // Thread identifier
127
+ agentId: string; // Agent identifier
128
+ userId: string | null; // User identifier (if set)
129
+ createdAt: number; // Creation timestamp
130
+
131
+ // Methods
132
+ getMessages(options?): Promise<MessagesResult>; // Get conversation history
133
+ injectMessage(input): Promise<Message>; // Add message to thread
134
+ loadModel(name): Promise<ModelConfig>; // Load model definition
135
+ loadPrompt(name): Promise<PromptConfig>; // Load prompt definition
136
+ loadAgent(name): Promise<AgentConfig>; // Load agent definition
134
137
  }
135
138
  \`\`\`
136
139
 
137
140
  Access in tools:
138
141
  \`\`\`typescript
139
142
  export default defineTool('...', schema, async (flow, args) => {
140
- const threadId = flow.thread.id;
141
- const messages = flow.messages;
143
+ const threadId = flow.threadId;
144
+ const { messages } = await flow.getMessages();
142
145
  // ...
143
146
  });
144
147
  \`\`\`
@@ -282,15 +285,12 @@ Prompts define system instructions, model selection, and available tools for LLM
282
285
  | \`toolDescription\` | \`string\` | Yes | Description shown when used as a tool |
283
286
  | \`prompt\` | \`string \\| StructuredPrompt\` | Yes | System instructions |
284
287
  | \`model\` | \`string\` | Yes | Model name to use (references \`agents/models/\`) |
285
- | \`tools\` | \`(string \\| ToolConfig)[]\` | No | Available tools for LLM |
286
- | \`handoffAgents\` | \`string[]\` | No | Agents this prompt can hand off to |
288
+ | \`tools\` | \`(string \\| ToolConfig)[]\` | No | Available tools (include ai_human agent names for handoffs) |
287
289
  | \`includeChat\` | \`boolean\` | No | Include full conversation history |
288
290
  | \`includePastTools\` | \`boolean\` | No | Include previous tool results |
289
291
  | \`parallelToolCalls\` | \`boolean\` | No | Allow multiple concurrent tool calls |
290
292
  | \`toolChoice\` | \`'auto' \\| 'none' \\| 'required'\` | No | Tool calling strategy |
291
293
  | \`requiredSchema\` | \`z.ZodObject\` | No | Input validation when called as tool |
292
- | \`beforeTool\` | \`string\` | No | Tool to run before LLM request |
293
- | \`afterTool\` | \`string\` | No | Tool to run after LLM response |
294
294
  | \`reasoning\` | \`ReasoningConfig\` | No | Extended thinking configuration |
295
295
 
296
296
  ## Basic Example
@@ -490,7 +490,7 @@ export default defineAgent({
490
490
  });
491
491
  \`\`\`
492
492
 
493
- Other prompts can then include it in their \`handoffAgents\` array.
493
+ Other prompts can then include the agent name in their \`tools\` array to enable handoffs.
494
494
 
495
495
  ## Stop Conditions (Priority Order)
496
496
 
@@ -565,28 +565,27 @@ export default defineTool(
565
565
  | \`result\` | \`string\` | Tool output (required for success) |
566
566
  | \`error\` | \`string\` | Error message (for error status) |
567
567
 
568
- ## FlowState Access
568
+ ## ThreadState Access
569
569
 
570
- The \`flow\` parameter provides access to:
570
+ The \`flow\` parameter (a \`ThreadState\` object) provides access to:
571
571
 
572
572
  \`\`\`typescript
573
573
  async (flow, args) => {
574
- // Thread information
575
- const threadId = flow.thread.id;
576
- const thread = flow.thread.instance;
577
-
578
- // Configuration
579
- const agentName = flow.agent.name;
580
- const modelName = flow.model.name;
574
+ // Thread identity (readonly)
575
+ const threadId = flow.threadId;
576
+ const agentId = flow.agentId;
577
+ const userId = flow.userId; // string | null
581
578
 
582
579
  // Message history
583
- const messages = flow.messages;
580
+ const { messages } = await flow.getMessages();
581
+ const { messages: recent } = await flow.getMessages({ limit: 10, order: 'desc' });
584
582
 
585
- // Environment bindings
586
- const env = flow.env;
583
+ // Resource loading
584
+ const model = await flow.loadModel('gpt-4o');
585
+ const prompt = await flow.loadPrompt('support-prompt');
587
586
 
588
- // Parent state (for sub-prompts)
589
- const root = flow.rootState;
587
+ // Inject messages
588
+ await flow.injectMessage({ role: 'system', content: 'Note: ...' });
590
589
  }
591
590
  \`\`\`
592
591
 
@@ -635,14 +634,14 @@ import { queueTool } from '@standardagents/builder';
635
634
 
636
635
  export default defineTool(
637
636
  'Create order and send confirmation',
638
- z.object({ items: z.array(z.string()) }),
637
+ z.object({ items: z.array(z.string()), email: z.string() }),
639
638
  async (flow, args) => {
640
639
  const order = await createOrder(args.items);
641
640
 
642
641
  // Queue email tool to run next
643
642
  queueTool(flow, 'send_confirmation_email', {
644
643
  orderId: order.id,
645
- email: flow.thread.metadata.userEmail,
644
+ email: args.email,
646
645
  });
647
646
 
648
647
  return { status: 'success', result: JSON.stringify(order) };
@@ -981,17 +980,19 @@ Full reference: https://docs.standardagentbuilder.com/core-concepts/api
981
980
  `;
982
981
 
983
982
  // src/commands/scaffold.ts
984
- var WRANGLER_TEMPLATE = (name) => `{
983
+ var WRANGLER_TEMPLATE = (name) => {
984
+ const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
985
+ return `{
985
986
  "$schema": "node_modules/wrangler/config-schema.json",
986
987
  "name": "${name}",
987
988
  "main": "worker/index.ts",
988
- "compatibility_date": "2025-01-01",
989
+ "compatibility_date": "${today}",
989
990
  "compatibility_flags": ["nodejs_compat"],
990
991
  "observability": {
991
992
  "enabled": true
992
993
  },
993
994
  "assets": {
994
- "directory": "dist",
995
+ "directory": "dist/client",
995
996
  "not_found_handling": "single-page-application",
996
997
  "binding": "ASSETS",
997
998
  "run_worker_first": ["/**"]
@@ -1020,6 +1021,7 @@ var WRANGLER_TEMPLATE = (name) => `{
1020
1021
  ]
1021
1022
  }
1022
1023
  `;
1024
+ };
1023
1025
  var THREAD_TS = `import { DurableThread } from 'virtual:@standardagents/builder'
1024
1026
 
1025
1027
  export default class Thread extends DurableThread {}
@@ -1042,23 +1044,23 @@ export default {
1042
1044
  export { DurableThread, DurableAgentBuilder }
1043
1045
  `;
1044
1046
  function getProjectName(cwd) {
1045
- const packageJsonPath = path.join(cwd, "package.json");
1046
- if (fs.existsSync(packageJsonPath)) {
1047
+ const packageJsonPath = path3.join(cwd, "package.json");
1048
+ if (fs3.existsSync(packageJsonPath)) {
1047
1049
  try {
1048
- const pkg2 = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
1050
+ const pkg2 = JSON.parse(fs3.readFileSync(packageJsonPath, "utf-8"));
1049
1051
  if (pkg2.name) {
1050
1052
  return pkg2.name.replace(/^@[^/]+\//, "");
1051
1053
  }
1052
1054
  } catch {
1053
1055
  }
1054
1056
  }
1055
- return path.basename(cwd);
1057
+ return path3.basename(cwd);
1056
1058
  }
1057
1059
  function findViteConfig(cwd) {
1058
1060
  const candidates = ["vite.config.ts", "vite.config.js", "vite.config.mts", "vite.config.mjs"];
1059
1061
  for (const candidate of candidates) {
1060
- const configPath = path.join(cwd, candidate);
1061
- if (fs.existsSync(configPath)) {
1062
+ const configPath = path3.join(cwd, candidate);
1063
+ if (fs3.existsSync(configPath)) {
1062
1064
  return configPath;
1063
1065
  }
1064
1066
  }
@@ -1067,8 +1069,8 @@ function findViteConfig(cwd) {
1067
1069
  function findWranglerConfig(cwd) {
1068
1070
  const candidates = ["wrangler.jsonc", "wrangler.json"];
1069
1071
  for (const candidate of candidates) {
1070
- const configPath = path.join(cwd, candidate);
1071
- if (fs.existsSync(configPath)) {
1072
+ const configPath = path3.join(cwd, candidate);
1073
+ if (fs3.existsSync(configPath)) {
1072
1074
  return configPath;
1073
1075
  }
1074
1076
  }
@@ -1077,21 +1079,13 @@ function findWranglerConfig(cwd) {
1077
1079
  async function modifyViteConfig(configPath, force) {
1078
1080
  try {
1079
1081
  const mod = await loadFile(configPath);
1080
- const code = fs.readFileSync(configPath, "utf-8");
1082
+ const code = fs3.readFileSync(configPath, "utf-8");
1081
1083
  const hasCloudflare = code.includes("@cloudflare/vite-plugin") || code.includes("cloudflare()");
1082
1084
  const hasAgentBuilder = code.includes("@standardagents/builder") || code.includes("agentbuilder()");
1083
1085
  if (hasCloudflare && hasAgentBuilder && !force) {
1084
1086
  logger.info("Vite config already includes Standard Agents plugins");
1085
1087
  return true;
1086
1088
  }
1087
- if (!hasCloudflare || force) {
1088
- addVitePlugin(mod, {
1089
- from: "@cloudflare/vite-plugin",
1090
- imported: "cloudflare",
1091
- constructor: "cloudflare"
1092
- });
1093
- logger.success("Added cloudflare plugin to vite.config");
1094
- }
1095
1089
  if (!hasAgentBuilder || force) {
1096
1090
  addVitePlugin(mod, {
1097
1091
  from: "@standardagents/builder",
@@ -1101,6 +1095,14 @@ async function modifyViteConfig(configPath, force) {
1101
1095
  });
1102
1096
  logger.success("Added agentbuilder plugin to vite.config");
1103
1097
  }
1098
+ if (!hasCloudflare || force) {
1099
+ addVitePlugin(mod, {
1100
+ from: "@cloudflare/vite-plugin",
1101
+ imported: "cloudflare",
1102
+ constructor: "cloudflare"
1103
+ });
1104
+ logger.success("Added cloudflare plugin to vite.config");
1105
+ }
1104
1106
  await writeFile(mod, configPath);
1105
1107
  return true;
1106
1108
  } catch (error) {
@@ -1108,10 +1110,10 @@ async function modifyViteConfig(configPath, force) {
1108
1110
  logger.log("");
1109
1111
  logger.log("Please manually add the following to your vite.config.ts:");
1110
1112
  logger.log("");
1111
- logger.log(` import { cloudflare } from '@cloudflare/vite-plugin'`);
1112
1113
  logger.log(` import { agentbuilder } from '@standardagents/builder'`);
1114
+ logger.log(` import { cloudflare } from '@cloudflare/vite-plugin'`);
1113
1115
  logger.log("");
1114
- logger.log(` plugins: [cloudflare(), agentbuilder({ mountPoint: '/' })]`);
1116
+ logger.log(` plugins: [agentbuilder({ mountPoint: '/' }), cloudflare()]`);
1115
1117
  logger.log("");
1116
1118
  return false;
1117
1119
  }
@@ -1120,7 +1122,7 @@ function createOrUpdateWranglerConfig(cwd, projectName, force) {
1120
1122
  const existingConfig = findWranglerConfig(cwd);
1121
1123
  if (existingConfig && !force) {
1122
1124
  try {
1123
- const text = fs.readFileSync(existingConfig, "utf-8");
1125
+ const text = fs3.readFileSync(existingConfig, "utf-8");
1124
1126
  const config = parse(text);
1125
1127
  const hasBindings = config.durable_objects?.bindings?.some(
1126
1128
  (b) => b.name === "AGENT_BUILDER_THREAD" || b.name === "AGENT_BUILDER"
@@ -1160,14 +1162,14 @@ function createOrUpdateWranglerConfig(cwd, projectName, force) {
1160
1162
  }
1161
1163
  if (!config.assets) {
1162
1164
  const edits = modify(result, ["assets"], {
1163
- directory: "dist",
1165
+ directory: "dist/client",
1164
1166
  not_found_handling: "single-page-application",
1165
1167
  binding: "ASSETS",
1166
1168
  run_worker_first: ["/**"]
1167
1169
  }, {});
1168
1170
  result = applyEdits(result, edits);
1169
1171
  }
1170
- fs.writeFileSync(existingConfig, result, "utf-8");
1172
+ fs3.writeFileSync(existingConfig, result, "utf-8");
1171
1173
  logger.success("Updated wrangler.jsonc with Standard Agents configuration");
1172
1174
  return true;
1173
1175
  } catch (error) {
@@ -1175,9 +1177,9 @@ function createOrUpdateWranglerConfig(cwd, projectName, force) {
1175
1177
  return false;
1176
1178
  }
1177
1179
  }
1178
- const wranglerPath = path.join(cwd, "wrangler.jsonc");
1180
+ const wranglerPath = path3.join(cwd, "wrangler.jsonc");
1179
1181
  const sanitizedName = projectName.toLowerCase().replace(/[^a-z0-9-]/g, "-");
1180
- fs.writeFileSync(wranglerPath, WRANGLER_TEMPLATE(sanitizedName), "utf-8");
1182
+ fs3.writeFileSync(wranglerPath, WRANGLER_TEMPLATE(sanitizedName), "utf-8");
1181
1183
  logger.success("Created wrangler.jsonc");
1182
1184
  return true;
1183
1185
  }
@@ -1185,33 +1187,33 @@ function getWorkerEntryPoint(cwd) {
1185
1187
  const wranglerConfig = findWranglerConfig(cwd);
1186
1188
  if (wranglerConfig) {
1187
1189
  try {
1188
- const text = fs.readFileSync(wranglerConfig, "utf-8");
1190
+ const text = fs3.readFileSync(wranglerConfig, "utf-8");
1189
1191
  const config = parse(text);
1190
1192
  if (config.main) {
1191
- return path.join(cwd, config.main);
1193
+ return path3.join(cwd, config.main);
1192
1194
  }
1193
1195
  } catch {
1194
1196
  }
1195
1197
  }
1196
- return path.join(cwd, "worker", "index.ts");
1198
+ return path3.join(cwd, "worker", "index.ts");
1197
1199
  }
1198
1200
  async function createOrUpdateWorkerEntry(cwd, force) {
1199
1201
  const entryPath = getWorkerEntryPoint(cwd);
1200
- const entryDir = path.dirname(entryPath);
1201
- if (!fs.existsSync(entryDir)) {
1202
- fs.mkdirSync(entryDir, { recursive: true });
1203
- logger.success(`Created ${path.relative(cwd, entryDir)} directory`);
1204
- }
1205
- if (!fs.existsSync(entryPath)) {
1206
- fs.writeFileSync(entryPath, WORKER_INDEX, "utf-8");
1207
- logger.success(`Created ${path.relative(cwd, entryPath)}`);
1202
+ const entryDir = path3.dirname(entryPath);
1203
+ if (!fs3.existsSync(entryDir)) {
1204
+ fs3.mkdirSync(entryDir, { recursive: true });
1205
+ logger.success(`Created ${path3.relative(cwd, entryDir)} directory`);
1206
+ }
1207
+ if (!fs3.existsSync(entryPath)) {
1208
+ fs3.writeFileSync(entryPath, WORKER_INDEX, "utf-8");
1209
+ logger.success(`Created ${path3.relative(cwd, entryPath)}`);
1208
1210
  return true;
1209
1211
  }
1210
- const content = fs.readFileSync(entryPath, "utf-8");
1212
+ const content = fs3.readFileSync(entryPath, "utf-8");
1211
1213
  const hasRouter = content.includes("virtual:@standardagents/builder") && content.includes("router");
1212
1214
  const hasDurableExports = content.includes("DurableThread") && content.includes("DurableAgentBuilder");
1213
1215
  if (hasRouter && hasDurableExports && !force) {
1214
- logger.info(`${path.relative(cwd, entryPath)} already configured`);
1216
+ logger.info(`${path3.relative(cwd, entryPath)} already configured`);
1215
1217
  return true;
1216
1218
  }
1217
1219
  try {
@@ -1239,17 +1241,17 @@ async function createOrUpdateWorkerEntry(cwd, force) {
1239
1241
  }
1240
1242
  const { code } = generateCode(mod);
1241
1243
  if (force || !hasRouter) {
1242
- fs.writeFileSync(entryPath, WORKER_INDEX, "utf-8");
1243
- logger.success(`Updated ${path.relative(cwd, entryPath)} with Standard Agents router`);
1244
+ fs3.writeFileSync(entryPath, WORKER_INDEX, "utf-8");
1245
+ logger.success(`Updated ${path3.relative(cwd, entryPath)} with Standard Agents router`);
1244
1246
  }
1245
1247
  return true;
1246
1248
  } catch (error) {
1247
1249
  if (force) {
1248
- fs.writeFileSync(entryPath, WORKER_INDEX, "utf-8");
1249
- logger.success(`Created ${path.relative(cwd, entryPath)}`);
1250
+ fs3.writeFileSync(entryPath, WORKER_INDEX, "utf-8");
1251
+ logger.success(`Created ${path3.relative(cwd, entryPath)}`);
1250
1252
  return true;
1251
1253
  }
1252
- logger.warning(`Could not automatically modify ${path.relative(cwd, entryPath)}`);
1254
+ logger.warning(`Could not automatically modify ${path3.relative(cwd, entryPath)}`);
1253
1255
  logger.log("");
1254
1256
  logger.log("Please ensure your worker entry point includes:");
1255
1257
  logger.log("");
@@ -1268,30 +1270,30 @@ async function createOrUpdateWorkerEntry(cwd, force) {
1268
1270
  }
1269
1271
  }
1270
1272
  function createDurableObjects(cwd) {
1271
- const agentsDir = path.join(cwd, "agents");
1272
- if (!fs.existsSync(agentsDir)) {
1273
- fs.mkdirSync(agentsDir, { recursive: true });
1273
+ const agentsDir = path3.join(cwd, "agents");
1274
+ if (!fs3.existsSync(agentsDir)) {
1275
+ fs3.mkdirSync(agentsDir, { recursive: true });
1274
1276
  }
1275
- const threadPath = path.join(agentsDir, "Thread.ts");
1276
- if (!fs.existsSync(threadPath)) {
1277
- fs.writeFileSync(threadPath, THREAD_TS, "utf-8");
1277
+ const threadPath = path3.join(agentsDir, "Thread.ts");
1278
+ if (!fs3.existsSync(threadPath)) {
1279
+ fs3.writeFileSync(threadPath, THREAD_TS, "utf-8");
1278
1280
  logger.success("Created agents/Thread.ts");
1279
1281
  } else {
1280
1282
  logger.info("agents/Thread.ts already exists");
1281
1283
  }
1282
- const agentBuilderPath = path.join(agentsDir, "AgentBuilder.ts");
1283
- if (!fs.existsSync(agentBuilderPath)) {
1284
- fs.writeFileSync(agentBuilderPath, AGENT_BUILDER_TS, "utf-8");
1284
+ const agentBuilderPath = path3.join(agentsDir, "AgentBuilder.ts");
1285
+ if (!fs3.existsSync(agentBuilderPath)) {
1286
+ fs3.writeFileSync(agentBuilderPath, AGENT_BUILDER_TS, "utf-8");
1285
1287
  logger.success("Created agents/AgentBuilder.ts");
1286
1288
  } else {
1287
1289
  logger.info("agents/AgentBuilder.ts already exists");
1288
1290
  }
1289
1291
  }
1290
1292
  function createDirectoriesAndDocs(cwd) {
1291
- path.join(cwd, "agents");
1292
- const rootDocPath = path.join(cwd, "CLAUDE.md");
1293
- if (!fs.existsSync(rootDocPath)) {
1294
- fs.writeFileSync(rootDocPath, ROOT_CLAUDE_MD, "utf-8");
1293
+ path3.join(cwd, "agents");
1294
+ const rootDocPath = path3.join(cwd, "CLAUDE.md");
1295
+ if (!fs3.existsSync(rootDocPath)) {
1296
+ fs3.writeFileSync(rootDocPath, ROOT_CLAUDE_MD, "utf-8");
1295
1297
  logger.success("Created CLAUDE.md");
1296
1298
  }
1297
1299
  const directories = [
@@ -1303,26 +1305,26 @@ function createDirectoriesAndDocs(cwd) {
1303
1305
  { path: "agents/api", doc: API_CLAUDE_MD }
1304
1306
  ];
1305
1307
  for (const dir of directories) {
1306
- const dirPath = path.join(cwd, dir.path);
1307
- const docPath = path.join(dirPath, "CLAUDE.md");
1308
- if (!fs.existsSync(dirPath)) {
1309
- fs.mkdirSync(dirPath, { recursive: true });
1308
+ const dirPath = path3.join(cwd, dir.path);
1309
+ const docPath = path3.join(dirPath, "CLAUDE.md");
1310
+ if (!fs3.existsSync(dirPath)) {
1311
+ fs3.mkdirSync(dirPath, { recursive: true });
1310
1312
  logger.success(`Created ${dir.path}`);
1311
1313
  }
1312
- if (!fs.existsSync(docPath)) {
1313
- fs.writeFileSync(docPath, dir.doc, "utf-8");
1314
+ if (!fs3.existsSync(docPath)) {
1315
+ fs3.writeFileSync(docPath, dir.doc, "utf-8");
1314
1316
  logger.success(`Created ${dir.path}/CLAUDE.md`);
1315
1317
  }
1316
1318
  }
1317
1319
  }
1318
1320
  function updateTsConfig(cwd) {
1319
- const tsconfigPath = path.join(cwd, "tsconfig.json");
1320
- if (!fs.existsSync(tsconfigPath)) {
1321
+ const tsconfigPath = path3.join(cwd, "tsconfig.json");
1322
+ if (!fs3.existsSync(tsconfigPath)) {
1321
1323
  logger.info("No tsconfig.json found, skipping TypeScript configuration");
1322
1324
  return;
1323
1325
  }
1324
1326
  try {
1325
- const text = fs.readFileSync(tsconfigPath, "utf-8");
1327
+ const text = fs3.readFileSync(tsconfigPath, "utf-8");
1326
1328
  const config = parse(text);
1327
1329
  let result = text;
1328
1330
  const types = config.compilerOptions?.types || [];
@@ -1344,7 +1346,7 @@ function updateTsConfig(cwd) {
1344
1346
  result = applyEdits(result, edits);
1345
1347
  }
1346
1348
  if (newTypes.length > 0 || newIncludes.length > 0) {
1347
- fs.writeFileSync(tsconfigPath, result, "utf-8");
1349
+ fs3.writeFileSync(tsconfigPath, result, "utf-8");
1348
1350
  logger.success("Updated tsconfig.json with Standard Agents types");
1349
1351
  } else {
1350
1352
  logger.info("tsconfig.json already configured");
@@ -1365,21 +1367,21 @@ function cleanupViteDefaults(cwd) {
1365
1367
  ];
1366
1368
  const dirsToRemove = ["src", "public"];
1367
1369
  for (const file of filesToRemove) {
1368
- const filePath = path.join(cwd, file);
1369
- if (fs.existsSync(filePath)) {
1370
+ const filePath = path3.join(cwd, file);
1371
+ if (fs3.existsSync(filePath)) {
1370
1372
  try {
1371
- fs.unlinkSync(filePath);
1373
+ fs3.unlinkSync(filePath);
1372
1374
  } catch {
1373
1375
  }
1374
1376
  }
1375
1377
  }
1376
1378
  for (const dir of dirsToRemove) {
1377
- const dirPath = path.join(cwd, dir);
1378
- if (fs.existsSync(dirPath)) {
1379
+ const dirPath = path3.join(cwd, dir);
1380
+ if (fs3.existsSync(dirPath)) {
1379
1381
  try {
1380
- const files = fs.readdirSync(dirPath);
1382
+ const files = fs3.readdirSync(dirPath);
1381
1383
  if (files.length === 0) {
1382
- fs.rmdirSync(dirPath);
1384
+ fs3.rmdirSync(dirPath);
1383
1385
  }
1384
1386
  } catch {
1385
1387
  }
@@ -1513,12 +1515,27 @@ function detectPackageManager() {
1513
1515
  if (userAgent.includes("yarn")) return "yarn";
1514
1516
  if (userAgent.includes("bun")) return "bun";
1515
1517
  }
1516
- if (fs.existsSync("pnpm-lock.yaml")) return "pnpm";
1517
- if (fs.existsSync("yarn.lock")) return "yarn";
1518
- if (fs.existsSync("bun.lockb")) return "bun";
1519
- if (fs.existsSync("package-lock.json")) return "npm";
1518
+ if (fs3.existsSync("pnpm-lock.yaml")) return "pnpm";
1519
+ if (fs3.existsSync("yarn.lock")) return "yarn";
1520
+ if (fs3.existsSync("bun.lockb")) return "bun";
1521
+ if (fs3.existsSync("package-lock.json")) return "npm";
1520
1522
  return "npm";
1521
1523
  }
1524
+ function getBuilderPackageVersion() {
1525
+ try {
1526
+ const __dirname2 = path3.dirname(fileURLToPath(import.meta.url));
1527
+ const pkgPath = path3.resolve(__dirname2, "../../package.json");
1528
+ const pkg2 = JSON.parse(fs3.readFileSync(pkgPath, "utf-8"));
1529
+ const version = pkg2.version;
1530
+ const prereleaseMatch = version.match(/-([a-z]+)\./i);
1531
+ if (prereleaseMatch) {
1532
+ return `@${prereleaseMatch[1]}`;
1533
+ }
1534
+ return `@^${version}`;
1535
+ } catch {
1536
+ return "";
1537
+ }
1538
+ }
1522
1539
  async function selectPackageManager(detected) {
1523
1540
  const options = ["npm", "pnpm", "yarn", "bun"];
1524
1541
  const detectedIndex = options.indexOf(detected);
@@ -1600,8 +1617,8 @@ async function init(projectNameArg, options = {}) {
1600
1617
  logger.error("Project name is required");
1601
1618
  process.exit(1);
1602
1619
  }
1603
- const projectPath = path.join(cwd, projectName);
1604
- if (fs.existsSync(projectPath)) {
1620
+ const projectPath = path3.join(cwd, projectName);
1621
+ if (fs3.existsSync(projectPath)) {
1605
1622
  logger.error(`Directory "${projectName}" already exists`);
1606
1623
  process.exit(1);
1607
1624
  }
@@ -1633,24 +1650,24 @@ async function init(projectNameArg, options = {}) {
1633
1650
  logger.error("Failed to create Vite project");
1634
1651
  process.exit(1);
1635
1652
  }
1636
- const viteConfigPath = path.join(projectPath, "vite.config.ts");
1637
- if (!fs.existsSync(viteConfigPath)) {
1653
+ const viteConfigPath = path3.join(projectPath, "vite.config.ts");
1654
+ if (!fs3.existsSync(viteConfigPath)) {
1638
1655
  const viteConfigContent = `import { defineConfig } from 'vite'
1639
1656
 
1640
1657
  export default defineConfig({
1641
1658
  plugins: [],
1642
1659
  })
1643
1660
  `;
1644
- fs.writeFileSync(viteConfigPath, viteConfigContent, "utf-8");
1661
+ fs3.writeFileSync(viteConfigPath, viteConfigContent, "utf-8");
1645
1662
  logger.success("Created vite.config.ts");
1646
1663
  }
1647
- const packageJsonPath = path.join(projectPath, "package.json");
1648
- if (fs.existsSync(packageJsonPath)) {
1649
- const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
1664
+ const packageJsonPath = path3.join(projectPath, "package.json");
1665
+ if (fs3.existsSync(packageJsonPath)) {
1666
+ const packageJson = JSON.parse(fs3.readFileSync(packageJsonPath, "utf-8"));
1650
1667
  const kebabName = toKebabCase(projectName);
1651
1668
  if (packageJson.name !== kebabName) {
1652
1669
  packageJson.name = kebabName;
1653
- fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + "\n", "utf-8");
1670
+ fs3.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + "\n", "utf-8");
1654
1671
  }
1655
1672
  }
1656
1673
  logger.log("");
@@ -1659,12 +1676,16 @@ export default defineConfig({
1659
1676
  try {
1660
1677
  const installCmd = pm === "npm" ? "install" : "add";
1661
1678
  const devFlag = pm === "npm" ? "--save-dev" : "-D";
1679
+ const builderVersion = getBuilderPackageVersion();
1662
1680
  await runCommand(pm, [
1663
1681
  installCmd,
1664
1682
  devFlag,
1665
1683
  "@cloudflare/vite-plugin",
1666
- "@standardagents/builder",
1667
- "wrangler",
1684
+ "wrangler"
1685
+ ], projectPath);
1686
+ await runCommand(pm, [
1687
+ installCmd,
1688
+ `@standardagents/builder${builderVersion}`,
1668
1689
  "zod"
1669
1690
  ], projectPath);
1670
1691
  } catch (error) {
@@ -1737,14 +1758,14 @@ export default defineConfig({
1737
1758
  devVarsLines.push("# OPENAI_API_KEY=your-openai-key");
1738
1759
  }
1739
1760
  devVarsLines.push("");
1740
- const devVarsPath = path.join(projectPath, ".dev.vars");
1741
- fs.writeFileSync(devVarsPath, devVarsLines.join("\n"), "utf-8");
1761
+ const devVarsPath = path3.join(projectPath, ".dev.vars");
1762
+ fs3.writeFileSync(devVarsPath, devVarsLines.join("\n"), "utf-8");
1742
1763
  logger.success("Created .dev.vars with encryption key");
1743
- const gitignorePath = path.join(projectPath, ".gitignore");
1744
- if (fs.existsSync(gitignorePath)) {
1745
- const gitignoreContent = fs.readFileSync(gitignorePath, "utf-8");
1764
+ const gitignorePath = path3.join(projectPath, ".gitignore");
1765
+ if (fs3.existsSync(gitignorePath)) {
1766
+ const gitignoreContent = fs3.readFileSync(gitignorePath, "utf-8");
1746
1767
  if (!gitignoreContent.includes(".dev.vars")) {
1747
- fs.appendFileSync(gitignorePath, "\n# Local environment variables\n.dev.vars\n");
1768
+ fs3.appendFileSync(gitignorePath, "\n# Local environment variables\n.dev.vars\n");
1748
1769
  logger.success("Added .dev.vars to .gitignore");
1749
1770
  }
1750
1771
  }
@@ -1766,6 +1787,535 @@ export default defineConfig({
1766
1787
  logger.log("");
1767
1788
  logger.log("For more information, visit: https://standardagents.ai/docs");
1768
1789
  }
1790
+ function getReactPackageVersion() {
1791
+ try {
1792
+ const __dirname2 = path3.dirname(fileURLToPath(import.meta.url));
1793
+ const pkgPath = path3.resolve(__dirname2, "../package.json");
1794
+ const pkg2 = JSON.parse(fs3.readFileSync(pkgPath, "utf-8"));
1795
+ const version = pkg2.version;
1796
+ const prereleaseMatch = version.match(/-([a-z]+)\./i);
1797
+ if (prereleaseMatch) {
1798
+ return prereleaseMatch[1];
1799
+ }
1800
+ return `^${version}`;
1801
+ } catch {
1802
+ return "latest";
1803
+ }
1804
+ }
1805
+ function getChatSourceDir() {
1806
+ const __dirname2 = path3.dirname(fileURLToPath(import.meta.url));
1807
+ return path3.resolve(__dirname2, "../chat");
1808
+ }
1809
+ async function prompt2(question) {
1810
+ const rl = readline.createInterface({
1811
+ input: process.stdin,
1812
+ output: process.stdout
1813
+ });
1814
+ return new Promise((resolve2) => {
1815
+ rl.question(question, (answer) => {
1816
+ rl.close();
1817
+ resolve2(answer.trim());
1818
+ });
1819
+ });
1820
+ }
1821
+ function runCommand2(command, args, cwd) {
1822
+ return new Promise((resolve2, reject) => {
1823
+ const child = spawn(command, args, {
1824
+ cwd,
1825
+ stdio: "inherit",
1826
+ shell: false
1827
+ });
1828
+ child.on("close", (code) => {
1829
+ if (code === 0) {
1830
+ resolve2();
1831
+ } else {
1832
+ reject(new Error(`Command failed with exit code ${code}`));
1833
+ }
1834
+ });
1835
+ child.on("error", reject);
1836
+ });
1837
+ }
1838
+ function detectPackageManager2() {
1839
+ const userAgent = process.env.npm_config_user_agent;
1840
+ if (userAgent) {
1841
+ if (userAgent.includes("pnpm")) return "pnpm";
1842
+ if (userAgent.includes("yarn")) return "yarn";
1843
+ if (userAgent.includes("bun")) return "bun";
1844
+ }
1845
+ if (fs3.existsSync("pnpm-lock.yaml")) return "pnpm";
1846
+ if (fs3.existsSync("yarn.lock")) return "yarn";
1847
+ if (fs3.existsSync("bun.lockb")) return "bun";
1848
+ if (fs3.existsSync("package-lock.json")) return "npm";
1849
+ return "npm";
1850
+ }
1851
+ async function selectPackageManager2(detected) {
1852
+ const options = ["npm", "pnpm", "yarn", "bun"];
1853
+ const detectedIndex = options.indexOf(detected);
1854
+ return new Promise((resolve2) => {
1855
+ const stdin = process.stdin;
1856
+ const stdout = process.stdout;
1857
+ let selectedIndex = detectedIndex;
1858
+ const renderOptions = () => {
1859
+ stdout.write("\x1B[?25l");
1860
+ stdout.write(`\x1B[${options.length + 1}A`);
1861
+ stdout.write("\x1B[0J");
1862
+ stdout.write("Select a package manager:\n");
1863
+ options.forEach((opt, i) => {
1864
+ const marker = i === detectedIndex ? " (detected)" : "";
1865
+ const prefix = i === selectedIndex ? "\x1B[36m\u276F\x1B[0m" : " ";
1866
+ const highlight = i === selectedIndex ? "\x1B[36m" : "\x1B[90m";
1867
+ stdout.write(`${prefix} ${highlight}${opt}${marker}\x1B[0m
1868
+ `);
1869
+ });
1870
+ };
1871
+ stdout.write("Select a package manager:\n");
1872
+ options.forEach((opt, i) => {
1873
+ const marker = i === detectedIndex ? " (detected)" : "";
1874
+ const prefix = i === selectedIndex ? "\x1B[36m\u276F\x1B[0m" : " ";
1875
+ const highlight = i === selectedIndex ? "\x1B[36m" : "\x1B[90m";
1876
+ stdout.write(`${prefix} ${highlight}${opt}${marker}\x1B[0m
1877
+ `);
1878
+ });
1879
+ const wasRaw = stdin.isRaw;
1880
+ if (stdin.isTTY) {
1881
+ stdin.setRawMode(true);
1882
+ }
1883
+ stdin.resume();
1884
+ stdin.setEncoding("utf8");
1885
+ const cleanup = () => {
1886
+ stdin.setRawMode(wasRaw ?? false);
1887
+ stdin.pause();
1888
+ stdin.removeListener("data", onData);
1889
+ stdout.write("\x1B[?25h");
1890
+ };
1891
+ const onData = (key) => {
1892
+ if (key === "\x1B[A" || key === "k") {
1893
+ selectedIndex = (selectedIndex - 1 + options.length) % options.length;
1894
+ renderOptions();
1895
+ } else if (key === "\x1B[B" || key === "j") {
1896
+ selectedIndex = (selectedIndex + 1) % options.length;
1897
+ renderOptions();
1898
+ } else if (key === "\r" || key === "\n") {
1899
+ cleanup();
1900
+ resolve2(options[selectedIndex]);
1901
+ } else if (key === "") {
1902
+ cleanup();
1903
+ stdout.write("\n");
1904
+ process.exit(1);
1905
+ }
1906
+ };
1907
+ stdin.on("data", onData);
1908
+ });
1909
+ }
1910
+ async function selectFramework() {
1911
+ const options = [
1912
+ { value: "vite", label: "Vite (React + TypeScript)" },
1913
+ { value: "nextjs", label: "Next.js (App Router)" }
1914
+ ];
1915
+ return new Promise((resolve2) => {
1916
+ const stdin = process.stdin;
1917
+ const stdout = process.stdout;
1918
+ let selectedIndex = 0;
1919
+ const renderOptions = () => {
1920
+ stdout.write("\x1B[?25l");
1921
+ stdout.write(`\x1B[${options.length + 1}A`);
1922
+ stdout.write("\x1B[0J");
1923
+ stdout.write("Select a framework:\n");
1924
+ options.forEach((opt, i) => {
1925
+ const prefix = i === selectedIndex ? "\x1B[36m\u276F\x1B[0m" : " ";
1926
+ const highlight = i === selectedIndex ? "\x1B[36m" : "\x1B[90m";
1927
+ stdout.write(`${prefix} ${highlight}${opt.label}\x1B[0m
1928
+ `);
1929
+ });
1930
+ };
1931
+ stdout.write("Select a framework:\n");
1932
+ options.forEach((opt, i) => {
1933
+ const prefix = i === selectedIndex ? "\x1B[36m\u276F\x1B[0m" : " ";
1934
+ const highlight = i === selectedIndex ? "\x1B[36m" : "\x1B[90m";
1935
+ stdout.write(`${prefix} ${highlight}${opt.label}\x1B[0m
1936
+ `);
1937
+ });
1938
+ const wasRaw = stdin.isRaw;
1939
+ if (stdin.isTTY) {
1940
+ stdin.setRawMode(true);
1941
+ }
1942
+ stdin.resume();
1943
+ stdin.setEncoding("utf8");
1944
+ const cleanup = () => {
1945
+ stdin.setRawMode(wasRaw ?? false);
1946
+ stdin.pause();
1947
+ stdin.removeListener("data", onData);
1948
+ stdout.write("\x1B[?25h");
1949
+ };
1950
+ const onData = (key) => {
1951
+ if (key === "\x1B[A" || key === "k") {
1952
+ selectedIndex = (selectedIndex - 1 + options.length) % options.length;
1953
+ renderOptions();
1954
+ } else if (key === "\x1B[B" || key === "j") {
1955
+ selectedIndex = (selectedIndex + 1) % options.length;
1956
+ renderOptions();
1957
+ } else if (key === "\r" || key === "\n") {
1958
+ cleanup();
1959
+ resolve2(options[selectedIndex].value);
1960
+ } else if (key === "") {
1961
+ cleanup();
1962
+ stdout.write("\n");
1963
+ process.exit(1);
1964
+ }
1965
+ };
1966
+ stdin.on("data", onData);
1967
+ });
1968
+ }
1969
+ function isValidUrl(url) {
1970
+ try {
1971
+ new URL(url);
1972
+ return true;
1973
+ } catch {
1974
+ return false;
1975
+ }
1976
+ }
1977
+ async function isPortOpen(port) {
1978
+ const tryConnect = (host) => {
1979
+ return new Promise((resolve2) => {
1980
+ const socket = new net.Socket();
1981
+ socket.setTimeout(200);
1982
+ socket.on("connect", () => {
1983
+ socket.destroy();
1984
+ resolve2(true);
1985
+ });
1986
+ socket.on("timeout", () => {
1987
+ socket.destroy();
1988
+ resolve2(false);
1989
+ });
1990
+ socket.on("error", () => {
1991
+ socket.destroy();
1992
+ resolve2(false);
1993
+ });
1994
+ socket.connect(port, host);
1995
+ });
1996
+ };
1997
+ if (await tryConnect("127.0.0.1")) return true;
1998
+ if (await tryConnect("::1")) return true;
1999
+ return false;
2000
+ }
2001
+ async function isAgentbuilderInstance(url) {
2002
+ try {
2003
+ const controller = new AbortController();
2004
+ const timeout = setTimeout(() => controller.abort(), 1e3);
2005
+ const response = await fetch(`${url}/api/agents`, {
2006
+ signal: controller.signal,
2007
+ headers: { "Accept": "application/json" }
2008
+ });
2009
+ clearTimeout(timeout);
2010
+ if (response.status === 401) {
2011
+ return true;
2012
+ }
2013
+ if (response.ok) {
2014
+ const data = await response.json();
2015
+ return Array.isArray(data.agents);
2016
+ }
2017
+ return false;
2018
+ } catch {
2019
+ return false;
2020
+ }
2021
+ }
2022
+ async function detectAgentbuilderInstance() {
2023
+ const portsToScan = [
2024
+ 5173,
2025
+ 5174,
2026
+ 5175,
2027
+ 5176,
2028
+ 5177,
2029
+ 5178,
2030
+ 5179,
2031
+ 5180,
2032
+ 3e3,
2033
+ 3001,
2034
+ 3002,
2035
+ 3003,
2036
+ 8080,
2037
+ 8e3,
2038
+ 4e3
2039
+ ];
2040
+ logger.log("\x1B[90mScanning for running agentbuilder instance...\x1B[0m");
2041
+ const openPorts = [];
2042
+ await Promise.all(
2043
+ portsToScan.map(async (port) => {
2044
+ if (await isPortOpen(port)) {
2045
+ openPorts.push(port);
2046
+ }
2047
+ })
2048
+ );
2049
+ for (const port of openPorts.sort((a, b) => a - b)) {
2050
+ const url = `http://localhost:${port}`;
2051
+ if (await isAgentbuilderInstance(url)) {
2052
+ return url;
2053
+ }
2054
+ }
2055
+ return null;
2056
+ }
2057
+ function copyDir(src, dest, skip = []) {
2058
+ if (!fs3.existsSync(dest)) {
2059
+ fs3.mkdirSync(dest, { recursive: true });
2060
+ }
2061
+ const entries = fs3.readdirSync(src, { withFileTypes: true });
2062
+ for (const entry of entries) {
2063
+ if (skip.includes(entry.name)) continue;
2064
+ const srcPath = path3.join(src, entry.name);
2065
+ const destPath = path3.join(dest, entry.name);
2066
+ if (entry.isDirectory()) {
2067
+ copyDir(srcPath, destPath, skip);
2068
+ } else {
2069
+ fs3.copyFileSync(srcPath, destPath);
2070
+ }
2071
+ }
2072
+ }
2073
+ async function initChat(projectNameArg, options = {}) {
2074
+ const cwd = process.cwd();
2075
+ const chatSourceDir = getChatSourceDir();
2076
+ if (!fs3.existsSync(chatSourceDir)) {
2077
+ logger.error("Chat source files not found. This CLI installation may be corrupted.");
2078
+ process.exit(1);
2079
+ }
2080
+ logger.log("");
2081
+ logger.info("Scaffolding a frontend chat application...");
2082
+ logger.log("");
2083
+ let projectName = projectNameArg;
2084
+ if (!projectName && !options.yes) {
2085
+ projectName = await prompt2("Project name: ");
2086
+ }
2087
+ if (!projectName) {
2088
+ logger.error("Project name is required");
2089
+ process.exit(1);
2090
+ }
2091
+ const projectPath = path3.join(cwd, projectName);
2092
+ if (fs3.existsSync(projectPath)) {
2093
+ logger.error(`Directory "${projectName}" already exists`);
2094
+ process.exit(1);
2095
+ }
2096
+ let framework;
2097
+ if (options.framework) {
2098
+ framework = options.framework;
2099
+ } else if (options.yes) {
2100
+ framework = "vite";
2101
+ } else {
2102
+ framework = await selectFramework();
2103
+ logger.log("");
2104
+ }
2105
+ let serverUrl;
2106
+ if (options.yes) {
2107
+ serverUrl = "http://localhost:5173";
2108
+ } else {
2109
+ const detectedUrl = await detectAgentbuilderInstance();
2110
+ if (detectedUrl) {
2111
+ logger.success(`Found agentbuilder at ${detectedUrl}`);
2112
+ const urlInput = await prompt2(`Agentbuilder dev server URL [${detectedUrl}]: `);
2113
+ serverUrl = urlInput || detectedUrl;
2114
+ } else {
2115
+ logger.log("\x1B[90mNo running agentbuilder instance found\x1B[0m");
2116
+ const urlInput = await prompt2("Agentbuilder dev server URL [http://localhost:5173]: ");
2117
+ serverUrl = urlInput || "http://localhost:5173";
2118
+ }
2119
+ if (!isValidUrl(serverUrl)) {
2120
+ logger.error("Invalid URL format");
2121
+ process.exit(1);
2122
+ }
2123
+ }
2124
+ const detectedPm = detectPackageManager2();
2125
+ let pm;
2126
+ if (options.yes) {
2127
+ pm = detectedPm;
2128
+ } else {
2129
+ pm = await selectPackageManager2(detectedPm);
2130
+ logger.log("");
2131
+ }
2132
+ logger.log("");
2133
+ logger.info(`Creating ${framework === "vite" ? "Vite" : "Next.js"} project...`);
2134
+ logger.log("");
2135
+ fs3.mkdirSync(projectPath, { recursive: true });
2136
+ const reactVersion = getReactPackageVersion();
2137
+ if (framework === "vite") {
2138
+ await scaffoldVite(projectPath, chatSourceDir, projectName, serverUrl, reactVersion);
2139
+ } else {
2140
+ await scaffoldNextjs(projectPath, chatSourceDir, projectName, serverUrl, reactVersion);
2141
+ }
2142
+ logger.log("");
2143
+ logger.info("Installing dependencies...");
2144
+ logger.log("");
2145
+ try {
2146
+ await runCommand2(pm, pm === "npm" ? ["install"] : ["install"], projectPath);
2147
+ } catch (error) {
2148
+ logger.error("Failed to install dependencies");
2149
+ process.exit(1);
2150
+ }
2151
+ logger.log("");
2152
+ logger.success("Chat UI scaffolded successfully!");
2153
+ logger.log("");
2154
+ logger.info("Starting development server...");
2155
+ logger.log("");
2156
+ const devArgs = pm === "npm" ? ["run", "dev"] : ["dev"];
2157
+ const devProcess = spawn(pm, devArgs, {
2158
+ cwd: projectPath,
2159
+ stdio: ["inherit", "pipe", "pipe"],
2160
+ shell: false
2161
+ });
2162
+ let browserOpened = false;
2163
+ const openBrowser = (url) => {
2164
+ if (browserOpened) return;
2165
+ browserOpened = true;
2166
+ const openCmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
2167
+ spawn(openCmd, [url], { stdio: "ignore", detached: true }).unref();
2168
+ };
2169
+ devProcess.stdout?.on("data", (data) => {
2170
+ const text = data.toString();
2171
+ process.stdout.write(data);
2172
+ const urlMatch = text.match(/Local:\s+(https?:\/\/localhost:\d+\/?)/);
2173
+ if (urlMatch && !browserOpened) {
2174
+ openBrowser(urlMatch[1]);
2175
+ }
2176
+ });
2177
+ devProcess.stderr?.on("data", (data) => {
2178
+ process.stderr.write(data);
2179
+ });
2180
+ devProcess.on("error", (error) => {
2181
+ logger.error(`Failed to start dev server: ${error.message}`);
2182
+ process.exit(1);
2183
+ });
2184
+ }
2185
+ async function scaffoldVite(projectPath, chatSourceDir, projectName, serverUrl, reactVersion) {
2186
+ copyDir(path3.join(chatSourceDir, "src"), path3.join(projectPath, "src"), []);
2187
+ logger.success("Copied src/");
2188
+ const viteDir = path3.join(chatSourceDir, "vite");
2189
+ let indexHtml = fs3.readFileSync(path3.join(viteDir, "index.html"), "utf-8");
2190
+ indexHtml = indexHtml.replace('src="/main.tsx"', 'src="/src/main.tsx"');
2191
+ fs3.writeFileSync(path3.join(projectPath, "index.html"), indexHtml, "utf-8");
2192
+ logger.success("Created index.html");
2193
+ fs3.copyFileSync(path3.join(viteDir, "main.tsx"), path3.join(projectPath, "src", "main.tsx"));
2194
+ logger.success("Created src/main.tsx");
2195
+ let viteConfig = fs3.readFileSync(path3.join(viteDir, "vite.config.ts"), "utf-8");
2196
+ viteConfig = `import { defineConfig } from 'vite'
2197
+ import react from '@vitejs/plugin-react'
2198
+ import tailwindcss from '@tailwindcss/vite'
2199
+
2200
+ export default defineConfig({
2201
+ plugins: [
2202
+ react(),
2203
+ tailwindcss(),
2204
+ ],
2205
+ })
2206
+ `;
2207
+ fs3.writeFileSync(path3.join(projectPath, "vite.config.ts"), viteConfig, "utf-8");
2208
+ logger.success("Created vite.config.ts");
2209
+ fs3.copyFileSync(path3.join(chatSourceDir, "tsconfig.json"), path3.join(projectPath, "tsconfig.json"));
2210
+ const tsconfig = JSON.parse(fs3.readFileSync(path3.join(projectPath, "tsconfig.json"), "utf-8"));
2211
+ tsconfig.include = ["src"];
2212
+ delete tsconfig.compilerOptions?.paths;
2213
+ fs3.writeFileSync(path3.join(projectPath, "tsconfig.json"), JSON.stringify(tsconfig, null, 2) + "\n", "utf-8");
2214
+ logger.success("Created tsconfig.json");
2215
+ fs3.copyFileSync(path3.join(chatSourceDir, "package.json"), path3.join(projectPath, "package.json"));
2216
+ const pkg2 = JSON.parse(fs3.readFileSync(path3.join(projectPath, "package.json"), "utf-8"));
2217
+ pkg2.name = projectName;
2218
+ pkg2.scripts = {
2219
+ dev: "vite",
2220
+ build: "vite build",
2221
+ preview: "vite preview"
2222
+ };
2223
+ delete pkg2.private;
2224
+ if (pkg2.dependencies?.["@standardagents/react"]) {
2225
+ pkg2.dependencies["@standardagents/react"] = reactVersion;
2226
+ }
2227
+ delete pkg2.dependencies?.["next"];
2228
+ delete pkg2.devDependencies?.["@tailwindcss/postcss"];
2229
+ delete pkg2.devDependencies?.["postcss"];
2230
+ fs3.writeFileSync(path3.join(projectPath, "package.json"), JSON.stringify(pkg2, null, 2) + "\n", "utf-8");
2231
+ logger.success("Created package.json");
2232
+ const envContent = `# Agentbuilder connection
2233
+ VITE_AGENTBUILDER_URL=${serverUrl}
2234
+ `;
2235
+ fs3.writeFileSync(path3.join(projectPath, ".env"), envContent, "utf-8");
2236
+ logger.success("Created .env");
2237
+ fs3.writeFileSync(path3.join(projectPath, ".gitignore"), `node_modules
2238
+ dist
2239
+ .env
2240
+ `, "utf-8");
2241
+ logger.success("Created .gitignore");
2242
+ let mainTsx = fs3.readFileSync(path3.join(projectPath, "src", "main.tsx"), "utf-8");
2243
+ mainTsx = mainTsx.replace(/from '\.\.\/src\//g, "from './").replace(/import '\.\.\/src\//g, "import './");
2244
+ fs3.writeFileSync(path3.join(projectPath, "src", "main.tsx"), mainTsx, "utf-8");
2245
+ if (fs3.existsSync(path3.join(viteDir, "favicon.svg"))) {
2246
+ fs3.copyFileSync(path3.join(viteDir, "favicon.svg"), path3.join(projectPath, "favicon.svg"));
2247
+ logger.success("Created favicon.svg");
2248
+ }
2249
+ }
2250
+ async function scaffoldNextjs(projectPath, chatSourceDir, projectName, serverUrl, reactVersion) {
2251
+ copyDir(path3.join(chatSourceDir, "src"), path3.join(projectPath, "src"), []);
2252
+ logger.success("Copied src/");
2253
+ const nextDir = path3.join(chatSourceDir, "next");
2254
+ copyDir(path3.join(nextDir, "app"), path3.join(projectPath, "app"), []);
2255
+ logger.success("Copied app/");
2256
+ fs3.copyFileSync(path3.join(nextDir, "next.config.ts"), path3.join(projectPath, "next.config.ts"));
2257
+ logger.success("Created next.config.ts");
2258
+ fs3.copyFileSync(path3.join(nextDir, "postcss.config.mjs"), path3.join(projectPath, "postcss.config.mjs"));
2259
+ logger.success("Created postcss.config.mjs");
2260
+ const tsconfig = {
2261
+ compilerOptions: {
2262
+ target: "ES2017",
2263
+ lib: ["dom", "dom.iterable", "esnext"],
2264
+ allowJs: true,
2265
+ skipLibCheck: true,
2266
+ strict: true,
2267
+ noEmit: true,
2268
+ esModuleInterop: true,
2269
+ module: "esnext",
2270
+ moduleResolution: "bundler",
2271
+ resolveJsonModule: true,
2272
+ isolatedModules: true,
2273
+ jsx: "preserve",
2274
+ incremental: true,
2275
+ plugins: [{ name: "next" }],
2276
+ paths: {
2277
+ "@/*": ["./src/*"]
2278
+ }
2279
+ },
2280
+ include: ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
2281
+ exclude: ["node_modules"]
2282
+ };
2283
+ fs3.writeFileSync(path3.join(projectPath, "tsconfig.json"), JSON.stringify(tsconfig, null, 2) + "\n", "utf-8");
2284
+ logger.success("Created tsconfig.json");
2285
+ const pkg2 = JSON.parse(fs3.readFileSync(path3.join(chatSourceDir, "package.json"), "utf-8"));
2286
+ pkg2.name = projectName;
2287
+ pkg2.scripts = {
2288
+ dev: "next dev",
2289
+ build: "next build",
2290
+ start: "next start"
2291
+ };
2292
+ delete pkg2.private;
2293
+ if (pkg2.dependencies?.["@standardagents/react"]) {
2294
+ pkg2.dependencies["@standardagents/react"] = reactVersion;
2295
+ }
2296
+ delete pkg2.devDependencies?.["@tailwindcss/vite"];
2297
+ delete pkg2.devDependencies?.["@vitejs/plugin-react"];
2298
+ delete pkg2.devDependencies?.["vite"];
2299
+ fs3.writeFileSync(path3.join(projectPath, "package.json"), JSON.stringify(pkg2, null, 2) + "\n", "utf-8");
2300
+ logger.success("Created package.json");
2301
+ const envContent = `# Agentbuilder connection
2302
+ NEXT_PUBLIC_AGENTBUILDER_URL=${serverUrl}
2303
+ `;
2304
+ fs3.writeFileSync(path3.join(projectPath, ".env.local"), envContent, "utf-8");
2305
+ logger.success("Created .env.local");
2306
+ fs3.writeFileSync(path3.join(projectPath, ".gitignore"), `node_modules
2307
+ .next
2308
+ out
2309
+ .env.local
2310
+ `, "utf-8");
2311
+ logger.success("Created .gitignore");
2312
+ let layoutTsx = fs3.readFileSync(path3.join(projectPath, "app", "layout.tsx"), "utf-8");
2313
+ layoutTsx = layoutTsx.replace(/from '\.\.\/\.\.\/src\//g, "from '../src/");
2314
+ fs3.writeFileSync(path3.join(projectPath, "app", "layout.tsx"), layoutTsx, "utf-8");
2315
+ let pageTsx = fs3.readFileSync(path3.join(projectPath, "app", "page.tsx"), "utf-8");
2316
+ pageTsx = pageTsx.replace(/from '\.\.\/\.\.\/src\//g, "from '../src/");
2317
+ fs3.writeFileSync(path3.join(projectPath, "app", "page.tsx"), pageTsx, "utf-8");
2318
+ }
1769
2319
 
1770
2320
  // src/index.ts
1771
2321
  var __dirname$1 = dirname(fileURLToPath(import.meta.url));
@@ -1774,6 +2324,7 @@ var program = new Command();
1774
2324
  program.name("agents").description("CLI tool for Standard Agents / AgentBuilder").version(pkg.version);
1775
2325
  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);
1776
2326
  program.command("scaffold").description("Add Standard Agents to an existing Vite project").option("--force", "Overwrite existing configuration").action(scaffold);
2327
+ 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);
1777
2328
  program.parse();
1778
2329
  //# sourceMappingURL=index.js.map
1779
2330
  //# sourceMappingURL=index.js.map