@standardagents/cli 0.10.1-next.bbd142a → 0.11.0-next.99fb790

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) => {
@@ -205,15 +206,24 @@ Models define which LLM provider and model to use for prompts.
205
206
  import { defineModel } from '@standardagents/builder';
206
207
 
207
208
  export default defineModel({
208
- name: 'gpt-4o',
209
- provider: 'openai',
210
- model: 'gpt-4o',
211
- fallbacks: ['gpt-4-turbo', 'gpt-3.5-turbo'],
212
- inputPrice: 2.5,
213
- outputPrice: 10,
209
+ name: 'default',
210
+ provider: 'openrouter',
211
+ model: 'google/gemini-3-flash-preview',
212
+ fallbacks: ['fast', 'cheap-heavy'],
214
213
  });
215
214
  \`\`\`
216
215
 
216
+ ## Recommended Models (OpenRouter)
217
+
218
+ | Use Case | Model ID | Description |
219
+ |----------|----------|-------------|
220
+ | Fast/Cheap | \`z-ai/glm-4.5-air\` | Quick responses, low cost |
221
+ | Mid-tier | \`google/gemini-3-flash-preview\` | Good balance of speed and quality |
222
+ | Cheap Heavy | \`z-ai/glm-4.7\` | More capable, still affordable |
223
+ | Heavy | \`google/gemini-3-pro-preview\` | Most capable, for complex tasks |
224
+
225
+ **\u26A0\uFE0F Google Models**: When using Google models (\`google/gemini-*\`), you must enable \`reasoning\` in your prompt configuration or tool calls will fail. See the prompts CLAUDE.md for details.
226
+
217
227
  ## Provider API Keys
218
228
 
219
229
  Set these environment variables in \`.dev.vars\` (local) or Cloudflare secrets (production):
@@ -241,16 +251,16 @@ For OpenRouter, use the full model path:
241
251
 
242
252
  \`\`\`typescript
243
253
  export default defineModel({
244
- name: 'claude-3-opus',
254
+ name: 'heavy',
245
255
  provider: 'openrouter',
246
- model: 'anthropic/claude-3-opus',
247
- includedProviders: ['anthropic'], // Prefer Anthropic's servers
256
+ model: 'google/gemini-3-pro-preview',
257
+ includedProviders: ['google'], // Prefer Google's servers
248
258
  });
249
259
  \`\`\`
250
260
 
251
261
  ## Best Practices
252
262
 
253
- - **Name by use case**, not model ID (e.g., \`fast_reasoning\` not \`gpt-4o-mini\`)
263
+ - **Name by use case**, not model ID (e.g., \`fast\`, \`default\`, \`heavy\`)
254
264
  - **Configure fallbacks** for production reliability
255
265
  - **Set pricing** for cost tracking in logs
256
266
  - **Use environment variables** for API keys, never hardcode
@@ -273,15 +283,12 @@ Prompts define system instructions, model selection, and available tools for LLM
273
283
  | \`toolDescription\` | \`string\` | Yes | Description shown when used as a tool |
274
284
  | \`prompt\` | \`string \\| StructuredPrompt\` | Yes | System instructions |
275
285
  | \`model\` | \`string\` | Yes | Model name to use (references \`agents/models/\`) |
276
- | \`tools\` | \`(string \\| ToolConfig)[]\` | No | Available tools for LLM |
277
- | \`handoffAgents\` | \`string[]\` | No | Agents this prompt can hand off to |
286
+ | \`tools\` | \`(string \\| ToolConfig)[]\` | No | Available tools (include ai_human agent names for handoffs) |
278
287
  | \`includeChat\` | \`boolean\` | No | Include full conversation history |
279
288
  | \`includePastTools\` | \`boolean\` | No | Include previous tool results |
280
289
  | \`parallelToolCalls\` | \`boolean\` | No | Allow multiple concurrent tool calls |
281
290
  | \`toolChoice\` | \`'auto' \\| 'none' \\| 'required'\` | No | Tool calling strategy |
282
291
  | \`requiredSchema\` | \`z.ZodObject\` | No | Input validation when called as tool |
283
- | \`beforeTool\` | \`string\` | No | Tool to run before LLM request |
284
- | \`afterTool\` | \`string\` | No | Tool to run after LLM response |
285
292
  | \`reasoning\` | \`ReasoningConfig\` | No | Extended thinking configuration |
286
293
 
287
294
  ## Basic Example
@@ -292,7 +299,7 @@ import { definePrompt } from '@standardagents/builder';
292
299
  export default definePrompt({
293
300
  name: 'customer_support',
294
301
  toolDescription: 'Handle customer support inquiries',
295
- model: 'gpt-4o',
302
+ model: 'default',
296
303
  prompt: \`You are a helpful customer support agent.
297
304
  Always be polite and professional.
298
305
  If you cannot help, escalate to a human.\`,
@@ -309,7 +316,7 @@ Include other prompts for reusable instruction blocks:
309
316
  export default definePrompt({
310
317
  name: 'main_assistant',
311
318
  toolDescription: 'Primary assistant',
312
- model: 'gpt-4o',
319
+ model: 'default',
313
320
  prompt: [
314
321
  { type: 'text', content: 'You are a helpful assistant.\\n\\n' },
315
322
  { type: 'include', prompt: 'common_rules' }, // Includes another prompt
@@ -345,7 +352,7 @@ import { z } from 'zod';
345
352
  export default definePrompt({
346
353
  name: 'data_extractor',
347
354
  toolDescription: 'Extract structured data from text',
348
- model: 'gpt-4o',
355
+ model: 'default',
349
356
  prompt: 'Extract the requested data from the input.',
350
357
  requiredSchema: z.object({
351
358
  text: z.string().describe('Text to extract from'),
@@ -362,7 +369,7 @@ Enable for complex reasoning tasks:
362
369
  export default definePrompt({
363
370
  name: 'code_reviewer',
364
371
  toolDescription: 'Review code for issues',
365
- model: 'claude-3-opus',
372
+ model: 'heavy',
366
373
  prompt: 'Review the code thoroughly...',
367
374
  reasoning: {
368
375
  effort: 'high', // 'low' | 'medium' | 'high'
@@ -372,6 +379,14 @@ export default definePrompt({
372
379
  });
373
380
  \`\`\`
374
381
 
382
+ **\u26A0\uFE0F Google Models Require Reasoning**: When using Google models (\`google/gemini-*\`) via OpenRouter, you **must** include \`reasoning\` configuration or tool calls will fail. At minimum:
383
+
384
+ \`\`\`typescript
385
+ reasoning: {
386
+ effort: 'low', // Can be 'low', 'medium', or 'high'
387
+ },
388
+ \`\`\`
389
+
375
390
  ## Best Practices
376
391
 
377
392
  - **Write clear instructions** - Structure with headers and bullet points
@@ -473,7 +488,7 @@ export default defineAgent({
473
488
  });
474
489
  \`\`\`
475
490
 
476
- Other prompts can then include it in their \`handoffAgents\` array.
491
+ Other prompts can then include the agent name in their \`tools\` array to enable handoffs.
477
492
 
478
493
  ## Stop Conditions (Priority Order)
479
494
 
@@ -483,9 +498,15 @@ Other prompts can then include it in their \`handoffAgents\` array.
483
498
  4. **stopOnResponse** - Ends turn when LLM returns text
484
499
  5. **maxSessionTurns** - Ends conversation (hard limit: 250)
485
500
 
501
+ ## Naming Convention
502
+
503
+ Agent names **must** end with the \`_agent\` suffix (e.g., \`support_agent\`, \`research_agent\`).
504
+ This convention is enforced by the builder UI and makes agents easily identifiable in logs and code.
505
+
486
506
  ## Best Practices
487
507
 
488
508
  - **Use descriptive names** (\`customer_support_agent\` not \`agent1\`)
509
+ - **Always use the _agent suffix** - names like \`support_agent\`, \`research_agent\`
489
510
  - **Always set maxTurns** as a safety limit
490
511
  - **Match stop conditions to use case** - chat apps use stopOnResponse, workflows use stopTool
491
512
  - **Use labels** for clarity in logs and UI
@@ -1019,23 +1040,23 @@ export default {
1019
1040
  export { DurableThread, DurableAgentBuilder }
1020
1041
  `;
1021
1042
  function getProjectName(cwd) {
1022
- const packageJsonPath = path.join(cwd, "package.json");
1023
- if (fs.existsSync(packageJsonPath)) {
1043
+ const packageJsonPath = path3.join(cwd, "package.json");
1044
+ if (fs3.existsSync(packageJsonPath)) {
1024
1045
  try {
1025
- const pkg2 = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
1046
+ const pkg2 = JSON.parse(fs3.readFileSync(packageJsonPath, "utf-8"));
1026
1047
  if (pkg2.name) {
1027
1048
  return pkg2.name.replace(/^@[^/]+\//, "");
1028
1049
  }
1029
1050
  } catch {
1030
1051
  }
1031
1052
  }
1032
- return path.basename(cwd);
1053
+ return path3.basename(cwd);
1033
1054
  }
1034
1055
  function findViteConfig(cwd) {
1035
1056
  const candidates = ["vite.config.ts", "vite.config.js", "vite.config.mts", "vite.config.mjs"];
1036
1057
  for (const candidate of candidates) {
1037
- const configPath = path.join(cwd, candidate);
1038
- if (fs.existsSync(configPath)) {
1058
+ const configPath = path3.join(cwd, candidate);
1059
+ if (fs3.existsSync(configPath)) {
1039
1060
  return configPath;
1040
1061
  }
1041
1062
  }
@@ -1044,8 +1065,8 @@ function findViteConfig(cwd) {
1044
1065
  function findWranglerConfig(cwd) {
1045
1066
  const candidates = ["wrangler.jsonc", "wrangler.json"];
1046
1067
  for (const candidate of candidates) {
1047
- const configPath = path.join(cwd, candidate);
1048
- if (fs.existsSync(configPath)) {
1068
+ const configPath = path3.join(cwd, candidate);
1069
+ if (fs3.existsSync(configPath)) {
1049
1070
  return configPath;
1050
1071
  }
1051
1072
  }
@@ -1054,7 +1075,7 @@ function findWranglerConfig(cwd) {
1054
1075
  async function modifyViteConfig(configPath, force) {
1055
1076
  try {
1056
1077
  const mod = await loadFile(configPath);
1057
- const code = fs.readFileSync(configPath, "utf-8");
1078
+ const code = fs3.readFileSync(configPath, "utf-8");
1058
1079
  const hasCloudflare = code.includes("@cloudflare/vite-plugin") || code.includes("cloudflare()");
1059
1080
  const hasAgentBuilder = code.includes("@standardagents/builder") || code.includes("agentbuilder()");
1060
1081
  if (hasCloudflare && hasAgentBuilder && !force) {
@@ -1097,7 +1118,7 @@ function createOrUpdateWranglerConfig(cwd, projectName, force) {
1097
1118
  const existingConfig = findWranglerConfig(cwd);
1098
1119
  if (existingConfig && !force) {
1099
1120
  try {
1100
- const text = fs.readFileSync(existingConfig, "utf-8");
1121
+ const text = fs3.readFileSync(existingConfig, "utf-8");
1101
1122
  const config = parse(text);
1102
1123
  const hasBindings = config.durable_objects?.bindings?.some(
1103
1124
  (b) => b.name === "AGENT_BUILDER_THREAD" || b.name === "AGENT_BUILDER"
@@ -1144,7 +1165,7 @@ function createOrUpdateWranglerConfig(cwd, projectName, force) {
1144
1165
  }, {});
1145
1166
  result = applyEdits(result, edits);
1146
1167
  }
1147
- fs.writeFileSync(existingConfig, result, "utf-8");
1168
+ fs3.writeFileSync(existingConfig, result, "utf-8");
1148
1169
  logger.success("Updated wrangler.jsonc with Standard Agents configuration");
1149
1170
  return true;
1150
1171
  } catch (error) {
@@ -1152,9 +1173,9 @@ function createOrUpdateWranglerConfig(cwd, projectName, force) {
1152
1173
  return false;
1153
1174
  }
1154
1175
  }
1155
- const wranglerPath = path.join(cwd, "wrangler.jsonc");
1176
+ const wranglerPath = path3.join(cwd, "wrangler.jsonc");
1156
1177
  const sanitizedName = projectName.toLowerCase().replace(/[^a-z0-9-]/g, "-");
1157
- fs.writeFileSync(wranglerPath, WRANGLER_TEMPLATE(sanitizedName), "utf-8");
1178
+ fs3.writeFileSync(wranglerPath, WRANGLER_TEMPLATE(sanitizedName), "utf-8");
1158
1179
  logger.success("Created wrangler.jsonc");
1159
1180
  return true;
1160
1181
  }
@@ -1162,33 +1183,33 @@ function getWorkerEntryPoint(cwd) {
1162
1183
  const wranglerConfig = findWranglerConfig(cwd);
1163
1184
  if (wranglerConfig) {
1164
1185
  try {
1165
- const text = fs.readFileSync(wranglerConfig, "utf-8");
1186
+ const text = fs3.readFileSync(wranglerConfig, "utf-8");
1166
1187
  const config = parse(text);
1167
1188
  if (config.main) {
1168
- return path.join(cwd, config.main);
1189
+ return path3.join(cwd, config.main);
1169
1190
  }
1170
1191
  } catch {
1171
1192
  }
1172
1193
  }
1173
- return path.join(cwd, "worker", "index.ts");
1194
+ return path3.join(cwd, "worker", "index.ts");
1174
1195
  }
1175
1196
  async function createOrUpdateWorkerEntry(cwd, force) {
1176
1197
  const entryPath = getWorkerEntryPoint(cwd);
1177
- const entryDir = path.dirname(entryPath);
1178
- if (!fs.existsSync(entryDir)) {
1179
- fs.mkdirSync(entryDir, { recursive: true });
1180
- logger.success(`Created ${path.relative(cwd, entryDir)} directory`);
1181
- }
1182
- if (!fs.existsSync(entryPath)) {
1183
- fs.writeFileSync(entryPath, WORKER_INDEX, "utf-8");
1184
- logger.success(`Created ${path.relative(cwd, entryPath)}`);
1198
+ const entryDir = path3.dirname(entryPath);
1199
+ if (!fs3.existsSync(entryDir)) {
1200
+ fs3.mkdirSync(entryDir, { recursive: true });
1201
+ logger.success(`Created ${path3.relative(cwd, entryDir)} directory`);
1202
+ }
1203
+ if (!fs3.existsSync(entryPath)) {
1204
+ fs3.writeFileSync(entryPath, WORKER_INDEX, "utf-8");
1205
+ logger.success(`Created ${path3.relative(cwd, entryPath)}`);
1185
1206
  return true;
1186
1207
  }
1187
- const content = fs.readFileSync(entryPath, "utf-8");
1208
+ const content = fs3.readFileSync(entryPath, "utf-8");
1188
1209
  const hasRouter = content.includes("virtual:@standardagents/builder") && content.includes("router");
1189
1210
  const hasDurableExports = content.includes("DurableThread") && content.includes("DurableAgentBuilder");
1190
1211
  if (hasRouter && hasDurableExports && !force) {
1191
- logger.info(`${path.relative(cwd, entryPath)} already configured`);
1212
+ logger.info(`${path3.relative(cwd, entryPath)} already configured`);
1192
1213
  return true;
1193
1214
  }
1194
1215
  try {
@@ -1216,17 +1237,17 @@ async function createOrUpdateWorkerEntry(cwd, force) {
1216
1237
  }
1217
1238
  const { code } = generateCode(mod);
1218
1239
  if (force || !hasRouter) {
1219
- fs.writeFileSync(entryPath, WORKER_INDEX, "utf-8");
1220
- logger.success(`Updated ${path.relative(cwd, entryPath)} with Standard Agents router`);
1240
+ fs3.writeFileSync(entryPath, WORKER_INDEX, "utf-8");
1241
+ logger.success(`Updated ${path3.relative(cwd, entryPath)} with Standard Agents router`);
1221
1242
  }
1222
1243
  return true;
1223
1244
  } catch (error) {
1224
1245
  if (force) {
1225
- fs.writeFileSync(entryPath, WORKER_INDEX, "utf-8");
1226
- logger.success(`Created ${path.relative(cwd, entryPath)}`);
1246
+ fs3.writeFileSync(entryPath, WORKER_INDEX, "utf-8");
1247
+ logger.success(`Created ${path3.relative(cwd, entryPath)}`);
1227
1248
  return true;
1228
1249
  }
1229
- logger.warning(`Could not automatically modify ${path.relative(cwd, entryPath)}`);
1250
+ logger.warning(`Could not automatically modify ${path3.relative(cwd, entryPath)}`);
1230
1251
  logger.log("");
1231
1252
  logger.log("Please ensure your worker entry point includes:");
1232
1253
  logger.log("");
@@ -1245,31 +1266,31 @@ async function createOrUpdateWorkerEntry(cwd, force) {
1245
1266
  }
1246
1267
  }
1247
1268
  function createDurableObjects(cwd) {
1248
- const agentsDir = path.join(cwd, "agents");
1249
- if (!fs.existsSync(agentsDir)) {
1250
- fs.mkdirSync(agentsDir, { recursive: true });
1269
+ const agentsDir = path3.join(cwd, "agents");
1270
+ if (!fs3.existsSync(agentsDir)) {
1271
+ fs3.mkdirSync(agentsDir, { recursive: true });
1251
1272
  }
1252
- const threadPath = path.join(agentsDir, "Thread.ts");
1253
- if (!fs.existsSync(threadPath)) {
1254
- fs.writeFileSync(threadPath, THREAD_TS, "utf-8");
1273
+ const threadPath = path3.join(agentsDir, "Thread.ts");
1274
+ if (!fs3.existsSync(threadPath)) {
1275
+ fs3.writeFileSync(threadPath, THREAD_TS, "utf-8");
1255
1276
  logger.success("Created agents/Thread.ts");
1256
1277
  } else {
1257
1278
  logger.info("agents/Thread.ts already exists");
1258
1279
  }
1259
- const agentBuilderPath = path.join(agentsDir, "AgentBuilder.ts");
1260
- if (!fs.existsSync(agentBuilderPath)) {
1261
- fs.writeFileSync(agentBuilderPath, AGENT_BUILDER_TS, "utf-8");
1280
+ const agentBuilderPath = path3.join(agentsDir, "AgentBuilder.ts");
1281
+ if (!fs3.existsSync(agentBuilderPath)) {
1282
+ fs3.writeFileSync(agentBuilderPath, AGENT_BUILDER_TS, "utf-8");
1262
1283
  logger.success("Created agents/AgentBuilder.ts");
1263
1284
  } else {
1264
1285
  logger.info("agents/AgentBuilder.ts already exists");
1265
1286
  }
1266
1287
  }
1267
1288
  function createDirectoriesAndDocs(cwd) {
1268
- const agentsDir = path.join(cwd, "agents");
1269
- const rootDocPath = path.join(agentsDir, "CLAUDE.md");
1270
- if (!fs.existsSync(rootDocPath)) {
1271
- fs.writeFileSync(rootDocPath, ROOT_CLAUDE_MD, "utf-8");
1272
- logger.success("Created agents/CLAUDE.md");
1289
+ path3.join(cwd, "agents");
1290
+ const rootDocPath = path3.join(cwd, "CLAUDE.md");
1291
+ if (!fs3.existsSync(rootDocPath)) {
1292
+ fs3.writeFileSync(rootDocPath, ROOT_CLAUDE_MD, "utf-8");
1293
+ logger.success("Created CLAUDE.md");
1273
1294
  }
1274
1295
  const directories = [
1275
1296
  { path: "agents/agents", doc: AGENTS_CLAUDE_MD },
@@ -1280,26 +1301,26 @@ function createDirectoriesAndDocs(cwd) {
1280
1301
  { path: "agents/api", doc: API_CLAUDE_MD }
1281
1302
  ];
1282
1303
  for (const dir of directories) {
1283
- const dirPath = path.join(cwd, dir.path);
1284
- const docPath = path.join(dirPath, "CLAUDE.md");
1285
- if (!fs.existsSync(dirPath)) {
1286
- fs.mkdirSync(dirPath, { recursive: true });
1304
+ const dirPath = path3.join(cwd, dir.path);
1305
+ const docPath = path3.join(dirPath, "CLAUDE.md");
1306
+ if (!fs3.existsSync(dirPath)) {
1307
+ fs3.mkdirSync(dirPath, { recursive: true });
1287
1308
  logger.success(`Created ${dir.path}`);
1288
1309
  }
1289
- if (!fs.existsSync(docPath)) {
1290
- fs.writeFileSync(docPath, dir.doc, "utf-8");
1310
+ if (!fs3.existsSync(docPath)) {
1311
+ fs3.writeFileSync(docPath, dir.doc, "utf-8");
1291
1312
  logger.success(`Created ${dir.path}/CLAUDE.md`);
1292
1313
  }
1293
1314
  }
1294
1315
  }
1295
1316
  function updateTsConfig(cwd) {
1296
- const tsconfigPath = path.join(cwd, "tsconfig.json");
1297
- if (!fs.existsSync(tsconfigPath)) {
1317
+ const tsconfigPath = path3.join(cwd, "tsconfig.json");
1318
+ if (!fs3.existsSync(tsconfigPath)) {
1298
1319
  logger.info("No tsconfig.json found, skipping TypeScript configuration");
1299
1320
  return;
1300
1321
  }
1301
1322
  try {
1302
- const text = fs.readFileSync(tsconfigPath, "utf-8");
1323
+ const text = fs3.readFileSync(tsconfigPath, "utf-8");
1303
1324
  const config = parse(text);
1304
1325
  let result = text;
1305
1326
  const types = config.compilerOptions?.types || [];
@@ -1321,7 +1342,7 @@ function updateTsConfig(cwd) {
1321
1342
  result = applyEdits(result, edits);
1322
1343
  }
1323
1344
  if (newTypes.length > 0 || newIncludes.length > 0) {
1324
- fs.writeFileSync(tsconfigPath, result, "utf-8");
1345
+ fs3.writeFileSync(tsconfigPath, result, "utf-8");
1325
1346
  logger.success("Updated tsconfig.json with Standard Agents types");
1326
1347
  } else {
1327
1348
  logger.info("tsconfig.json already configured");
@@ -1342,21 +1363,21 @@ function cleanupViteDefaults(cwd) {
1342
1363
  ];
1343
1364
  const dirsToRemove = ["src", "public"];
1344
1365
  for (const file of filesToRemove) {
1345
- const filePath = path.join(cwd, file);
1346
- if (fs.existsSync(filePath)) {
1366
+ const filePath = path3.join(cwd, file);
1367
+ if (fs3.existsSync(filePath)) {
1347
1368
  try {
1348
- fs.unlinkSync(filePath);
1369
+ fs3.unlinkSync(filePath);
1349
1370
  } catch {
1350
1371
  }
1351
1372
  }
1352
1373
  }
1353
1374
  for (const dir of dirsToRemove) {
1354
- const dirPath = path.join(cwd, dir);
1355
- if (fs.existsSync(dirPath)) {
1375
+ const dirPath = path3.join(cwd, dir);
1376
+ if (fs3.existsSync(dirPath)) {
1356
1377
  try {
1357
- const files = fs.readdirSync(dirPath);
1378
+ const files = fs3.readdirSync(dirPath);
1358
1379
  if (files.length === 0) {
1359
- fs.rmdirSync(dirPath);
1380
+ fs3.rmdirSync(dirPath);
1360
1381
  }
1361
1382
  } catch {
1362
1383
  }
@@ -1388,8 +1409,8 @@ async function scaffold(options = {}) {
1388
1409
  logger.log("");
1389
1410
  logger.log("Your project structure:");
1390
1411
  logger.log("");
1412
+ logger.log(" CLAUDE.md # Architecture documentation");
1391
1413
  logger.log(" agents/");
1392
- logger.log(" \u251C\u2500\u2500 CLAUDE.md # Architecture documentation");
1393
1414
  logger.log(" \u251C\u2500\u2500 Thread.ts # Durable Object for threads");
1394
1415
  logger.log(" \u251C\u2500\u2500 AgentBuilder.ts # Durable Object for agent state");
1395
1416
  logger.log(" \u251C\u2500\u2500 agents/ # Agent definitions");
@@ -1490,12 +1511,27 @@ function detectPackageManager() {
1490
1511
  if (userAgent.includes("yarn")) return "yarn";
1491
1512
  if (userAgent.includes("bun")) return "bun";
1492
1513
  }
1493
- if (fs.existsSync("pnpm-lock.yaml")) return "pnpm";
1494
- if (fs.existsSync("yarn.lock")) return "yarn";
1495
- if (fs.existsSync("bun.lockb")) return "bun";
1496
- if (fs.existsSync("package-lock.json")) return "npm";
1514
+ if (fs3.existsSync("pnpm-lock.yaml")) return "pnpm";
1515
+ if (fs3.existsSync("yarn.lock")) return "yarn";
1516
+ if (fs3.existsSync("bun.lockb")) return "bun";
1517
+ if (fs3.existsSync("package-lock.json")) return "npm";
1497
1518
  return "npm";
1498
1519
  }
1520
+ function getBuilderPackageVersion() {
1521
+ try {
1522
+ const __dirname2 = path3.dirname(fileURLToPath(import.meta.url));
1523
+ const pkgPath = path3.resolve(__dirname2, "../../package.json");
1524
+ const pkg2 = JSON.parse(fs3.readFileSync(pkgPath, "utf-8"));
1525
+ const version = pkg2.version;
1526
+ const prereleaseMatch = version.match(/-([a-z]+)\./i);
1527
+ if (prereleaseMatch) {
1528
+ return `@${prereleaseMatch[1]}`;
1529
+ }
1530
+ return `@^${version}`;
1531
+ } catch {
1532
+ return "";
1533
+ }
1534
+ }
1499
1535
  async function selectPackageManager(detected) {
1500
1536
  const options = ["npm", "pnpm", "yarn", "bun"];
1501
1537
  const detectedIndex = options.indexOf(detected);
@@ -1577,8 +1613,8 @@ async function init(projectNameArg, options = {}) {
1577
1613
  logger.error("Project name is required");
1578
1614
  process.exit(1);
1579
1615
  }
1580
- const projectPath = path.join(cwd, projectName);
1581
- if (fs.existsSync(projectPath)) {
1616
+ const projectPath = path3.join(cwd, projectName);
1617
+ if (fs3.existsSync(projectPath)) {
1582
1618
  logger.error(`Directory "${projectName}" already exists`);
1583
1619
  process.exit(1);
1584
1620
  }
@@ -1610,24 +1646,24 @@ async function init(projectNameArg, options = {}) {
1610
1646
  logger.error("Failed to create Vite project");
1611
1647
  process.exit(1);
1612
1648
  }
1613
- const viteConfigPath = path.join(projectPath, "vite.config.ts");
1614
- if (!fs.existsSync(viteConfigPath)) {
1649
+ const viteConfigPath = path3.join(projectPath, "vite.config.ts");
1650
+ if (!fs3.existsSync(viteConfigPath)) {
1615
1651
  const viteConfigContent = `import { defineConfig } from 'vite'
1616
1652
 
1617
1653
  export default defineConfig({
1618
1654
  plugins: [],
1619
1655
  })
1620
1656
  `;
1621
- fs.writeFileSync(viteConfigPath, viteConfigContent, "utf-8");
1657
+ fs3.writeFileSync(viteConfigPath, viteConfigContent, "utf-8");
1622
1658
  logger.success("Created vite.config.ts");
1623
1659
  }
1624
- const packageJsonPath = path.join(projectPath, "package.json");
1625
- if (fs.existsSync(packageJsonPath)) {
1626
- const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
1660
+ const packageJsonPath = path3.join(projectPath, "package.json");
1661
+ if (fs3.existsSync(packageJsonPath)) {
1662
+ const packageJson = JSON.parse(fs3.readFileSync(packageJsonPath, "utf-8"));
1627
1663
  const kebabName = toKebabCase(projectName);
1628
1664
  if (packageJson.name !== kebabName) {
1629
1665
  packageJson.name = kebabName;
1630
- fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + "\n", "utf-8");
1666
+ fs3.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + "\n", "utf-8");
1631
1667
  }
1632
1668
  }
1633
1669
  logger.log("");
@@ -1636,11 +1672,12 @@ export default defineConfig({
1636
1672
  try {
1637
1673
  const installCmd = pm === "npm" ? "install" : "add";
1638
1674
  const devFlag = pm === "npm" ? "--save-dev" : "-D";
1675
+ const builderVersion = getBuilderPackageVersion();
1639
1676
  await runCommand(pm, [
1640
1677
  installCmd,
1641
1678
  devFlag,
1642
1679
  "@cloudflare/vite-plugin",
1643
- "@standardagents/builder",
1680
+ `@standardagents/builder${builderVersion}`,
1644
1681
  "wrangler",
1645
1682
  "zod"
1646
1683
  ], projectPath);
@@ -1714,14 +1751,14 @@ export default defineConfig({
1714
1751
  devVarsLines.push("# OPENAI_API_KEY=your-openai-key");
1715
1752
  }
1716
1753
  devVarsLines.push("");
1717
- const devVarsPath = path.join(projectPath, ".dev.vars");
1718
- fs.writeFileSync(devVarsPath, devVarsLines.join("\n"), "utf-8");
1754
+ const devVarsPath = path3.join(projectPath, ".dev.vars");
1755
+ fs3.writeFileSync(devVarsPath, devVarsLines.join("\n"), "utf-8");
1719
1756
  logger.success("Created .dev.vars with encryption key");
1720
- const gitignorePath = path.join(projectPath, ".gitignore");
1721
- if (fs.existsSync(gitignorePath)) {
1722
- const gitignoreContent = fs.readFileSync(gitignorePath, "utf-8");
1757
+ const gitignorePath = path3.join(projectPath, ".gitignore");
1758
+ if (fs3.existsSync(gitignorePath)) {
1759
+ const gitignoreContent = fs3.readFileSync(gitignorePath, "utf-8");
1723
1760
  if (!gitignoreContent.includes(".dev.vars")) {
1724
- fs.appendFileSync(gitignorePath, "\n# Local environment variables\n.dev.vars\n");
1761
+ fs3.appendFileSync(gitignorePath, "\n# Local environment variables\n.dev.vars\n");
1725
1762
  logger.success("Added .dev.vars to .gitignore");
1726
1763
  }
1727
1764
  }
@@ -1743,6 +1780,535 @@ export default defineConfig({
1743
1780
  logger.log("");
1744
1781
  logger.log("For more information, visit: https://standardagents.ai/docs");
1745
1782
  }
1783
+ function getReactPackageVersion() {
1784
+ try {
1785
+ const __dirname2 = path3.dirname(fileURLToPath(import.meta.url));
1786
+ const pkgPath = path3.resolve(__dirname2, "../package.json");
1787
+ const pkg2 = JSON.parse(fs3.readFileSync(pkgPath, "utf-8"));
1788
+ const version = pkg2.version;
1789
+ const prereleaseMatch = version.match(/-([a-z]+)\./i);
1790
+ if (prereleaseMatch) {
1791
+ return prereleaseMatch[1];
1792
+ }
1793
+ return `^${version}`;
1794
+ } catch {
1795
+ return "latest";
1796
+ }
1797
+ }
1798
+ function getChatSourceDir() {
1799
+ const __dirname2 = path3.dirname(fileURLToPath(import.meta.url));
1800
+ return path3.resolve(__dirname2, "../chat");
1801
+ }
1802
+ async function prompt2(question) {
1803
+ const rl = readline.createInterface({
1804
+ input: process.stdin,
1805
+ output: process.stdout
1806
+ });
1807
+ return new Promise((resolve2) => {
1808
+ rl.question(question, (answer) => {
1809
+ rl.close();
1810
+ resolve2(answer.trim());
1811
+ });
1812
+ });
1813
+ }
1814
+ function runCommand2(command, args, cwd) {
1815
+ return new Promise((resolve2, reject) => {
1816
+ const child = spawn(command, args, {
1817
+ cwd,
1818
+ stdio: "inherit",
1819
+ shell: false
1820
+ });
1821
+ child.on("close", (code) => {
1822
+ if (code === 0) {
1823
+ resolve2();
1824
+ } else {
1825
+ reject(new Error(`Command failed with exit code ${code}`));
1826
+ }
1827
+ });
1828
+ child.on("error", reject);
1829
+ });
1830
+ }
1831
+ function detectPackageManager2() {
1832
+ const userAgent = process.env.npm_config_user_agent;
1833
+ if (userAgent) {
1834
+ if (userAgent.includes("pnpm")) return "pnpm";
1835
+ if (userAgent.includes("yarn")) return "yarn";
1836
+ if (userAgent.includes("bun")) return "bun";
1837
+ }
1838
+ if (fs3.existsSync("pnpm-lock.yaml")) return "pnpm";
1839
+ if (fs3.existsSync("yarn.lock")) return "yarn";
1840
+ if (fs3.existsSync("bun.lockb")) return "bun";
1841
+ if (fs3.existsSync("package-lock.json")) return "npm";
1842
+ return "npm";
1843
+ }
1844
+ async function selectPackageManager2(detected) {
1845
+ const options = ["npm", "pnpm", "yarn", "bun"];
1846
+ const detectedIndex = options.indexOf(detected);
1847
+ return new Promise((resolve2) => {
1848
+ const stdin = process.stdin;
1849
+ const stdout = process.stdout;
1850
+ let selectedIndex = detectedIndex;
1851
+ const renderOptions = () => {
1852
+ stdout.write("\x1B[?25l");
1853
+ stdout.write(`\x1B[${options.length + 1}A`);
1854
+ stdout.write("\x1B[0J");
1855
+ stdout.write("Select a package manager:\n");
1856
+ options.forEach((opt, i) => {
1857
+ const marker = i === detectedIndex ? " (detected)" : "";
1858
+ const prefix = i === selectedIndex ? "\x1B[36m\u276F\x1B[0m" : " ";
1859
+ const highlight = i === selectedIndex ? "\x1B[36m" : "\x1B[90m";
1860
+ stdout.write(`${prefix} ${highlight}${opt}${marker}\x1B[0m
1861
+ `);
1862
+ });
1863
+ };
1864
+ stdout.write("Select a package manager:\n");
1865
+ options.forEach((opt, i) => {
1866
+ const marker = i === detectedIndex ? " (detected)" : "";
1867
+ const prefix = i === selectedIndex ? "\x1B[36m\u276F\x1B[0m" : " ";
1868
+ const highlight = i === selectedIndex ? "\x1B[36m" : "\x1B[90m";
1869
+ stdout.write(`${prefix} ${highlight}${opt}${marker}\x1B[0m
1870
+ `);
1871
+ });
1872
+ const wasRaw = stdin.isRaw;
1873
+ if (stdin.isTTY) {
1874
+ stdin.setRawMode(true);
1875
+ }
1876
+ stdin.resume();
1877
+ stdin.setEncoding("utf8");
1878
+ const cleanup = () => {
1879
+ stdin.setRawMode(wasRaw ?? false);
1880
+ stdin.pause();
1881
+ stdin.removeListener("data", onData);
1882
+ stdout.write("\x1B[?25h");
1883
+ };
1884
+ const onData = (key) => {
1885
+ if (key === "\x1B[A" || key === "k") {
1886
+ selectedIndex = (selectedIndex - 1 + options.length) % options.length;
1887
+ renderOptions();
1888
+ } else if (key === "\x1B[B" || key === "j") {
1889
+ selectedIndex = (selectedIndex + 1) % options.length;
1890
+ renderOptions();
1891
+ } else if (key === "\r" || key === "\n") {
1892
+ cleanup();
1893
+ resolve2(options[selectedIndex]);
1894
+ } else if (key === "") {
1895
+ cleanup();
1896
+ stdout.write("\n");
1897
+ process.exit(1);
1898
+ }
1899
+ };
1900
+ stdin.on("data", onData);
1901
+ });
1902
+ }
1903
+ async function selectFramework() {
1904
+ const options = [
1905
+ { value: "vite", label: "Vite (React + TypeScript)" },
1906
+ { value: "nextjs", label: "Next.js (App Router)" }
1907
+ ];
1908
+ return new Promise((resolve2) => {
1909
+ const stdin = process.stdin;
1910
+ const stdout = process.stdout;
1911
+ let selectedIndex = 0;
1912
+ const renderOptions = () => {
1913
+ stdout.write("\x1B[?25l");
1914
+ stdout.write(`\x1B[${options.length + 1}A`);
1915
+ stdout.write("\x1B[0J");
1916
+ stdout.write("Select a framework:\n");
1917
+ options.forEach((opt, i) => {
1918
+ const prefix = i === selectedIndex ? "\x1B[36m\u276F\x1B[0m" : " ";
1919
+ const highlight = i === selectedIndex ? "\x1B[36m" : "\x1B[90m";
1920
+ stdout.write(`${prefix} ${highlight}${opt.label}\x1B[0m
1921
+ `);
1922
+ });
1923
+ };
1924
+ stdout.write("Select a framework:\n");
1925
+ options.forEach((opt, i) => {
1926
+ const prefix = i === selectedIndex ? "\x1B[36m\u276F\x1B[0m" : " ";
1927
+ const highlight = i === selectedIndex ? "\x1B[36m" : "\x1B[90m";
1928
+ stdout.write(`${prefix} ${highlight}${opt.label}\x1B[0m
1929
+ `);
1930
+ });
1931
+ const wasRaw = stdin.isRaw;
1932
+ if (stdin.isTTY) {
1933
+ stdin.setRawMode(true);
1934
+ }
1935
+ stdin.resume();
1936
+ stdin.setEncoding("utf8");
1937
+ const cleanup = () => {
1938
+ stdin.setRawMode(wasRaw ?? false);
1939
+ stdin.pause();
1940
+ stdin.removeListener("data", onData);
1941
+ stdout.write("\x1B[?25h");
1942
+ };
1943
+ const onData = (key) => {
1944
+ if (key === "\x1B[A" || key === "k") {
1945
+ selectedIndex = (selectedIndex - 1 + options.length) % options.length;
1946
+ renderOptions();
1947
+ } else if (key === "\x1B[B" || key === "j") {
1948
+ selectedIndex = (selectedIndex + 1) % options.length;
1949
+ renderOptions();
1950
+ } else if (key === "\r" || key === "\n") {
1951
+ cleanup();
1952
+ resolve2(options[selectedIndex].value);
1953
+ } else if (key === "") {
1954
+ cleanup();
1955
+ stdout.write("\n");
1956
+ process.exit(1);
1957
+ }
1958
+ };
1959
+ stdin.on("data", onData);
1960
+ });
1961
+ }
1962
+ function isValidUrl(url) {
1963
+ try {
1964
+ new URL(url);
1965
+ return true;
1966
+ } catch {
1967
+ return false;
1968
+ }
1969
+ }
1970
+ async function isPortOpen(port) {
1971
+ const tryConnect = (host) => {
1972
+ return new Promise((resolve2) => {
1973
+ const socket = new net.Socket();
1974
+ socket.setTimeout(200);
1975
+ socket.on("connect", () => {
1976
+ socket.destroy();
1977
+ resolve2(true);
1978
+ });
1979
+ socket.on("timeout", () => {
1980
+ socket.destroy();
1981
+ resolve2(false);
1982
+ });
1983
+ socket.on("error", () => {
1984
+ socket.destroy();
1985
+ resolve2(false);
1986
+ });
1987
+ socket.connect(port, host);
1988
+ });
1989
+ };
1990
+ if (await tryConnect("127.0.0.1")) return true;
1991
+ if (await tryConnect("::1")) return true;
1992
+ return false;
1993
+ }
1994
+ async function isAgentbuilderInstance(url) {
1995
+ try {
1996
+ const controller = new AbortController();
1997
+ const timeout = setTimeout(() => controller.abort(), 1e3);
1998
+ const response = await fetch(`${url}/api/agents`, {
1999
+ signal: controller.signal,
2000
+ headers: { "Accept": "application/json" }
2001
+ });
2002
+ clearTimeout(timeout);
2003
+ if (response.status === 401) {
2004
+ return true;
2005
+ }
2006
+ if (response.ok) {
2007
+ const data = await response.json();
2008
+ return Array.isArray(data.agents);
2009
+ }
2010
+ return false;
2011
+ } catch {
2012
+ return false;
2013
+ }
2014
+ }
2015
+ async function detectAgentbuilderInstance() {
2016
+ const portsToScan = [
2017
+ 5173,
2018
+ 5174,
2019
+ 5175,
2020
+ 5176,
2021
+ 5177,
2022
+ 5178,
2023
+ 5179,
2024
+ 5180,
2025
+ 3e3,
2026
+ 3001,
2027
+ 3002,
2028
+ 3003,
2029
+ 8080,
2030
+ 8e3,
2031
+ 4e3
2032
+ ];
2033
+ logger.log("\x1B[90mScanning for running agentbuilder instance...\x1B[0m");
2034
+ const openPorts = [];
2035
+ await Promise.all(
2036
+ portsToScan.map(async (port) => {
2037
+ if (await isPortOpen(port)) {
2038
+ openPorts.push(port);
2039
+ }
2040
+ })
2041
+ );
2042
+ for (const port of openPorts.sort((a, b) => a - b)) {
2043
+ const url = `http://localhost:${port}`;
2044
+ if (await isAgentbuilderInstance(url)) {
2045
+ return url;
2046
+ }
2047
+ }
2048
+ return null;
2049
+ }
2050
+ function copyDir(src, dest, skip = []) {
2051
+ if (!fs3.existsSync(dest)) {
2052
+ fs3.mkdirSync(dest, { recursive: true });
2053
+ }
2054
+ const entries = fs3.readdirSync(src, { withFileTypes: true });
2055
+ for (const entry of entries) {
2056
+ if (skip.includes(entry.name)) continue;
2057
+ const srcPath = path3.join(src, entry.name);
2058
+ const destPath = path3.join(dest, entry.name);
2059
+ if (entry.isDirectory()) {
2060
+ copyDir(srcPath, destPath, skip);
2061
+ } else {
2062
+ fs3.copyFileSync(srcPath, destPath);
2063
+ }
2064
+ }
2065
+ }
2066
+ async function initChat(projectNameArg, options = {}) {
2067
+ const cwd = process.cwd();
2068
+ const chatSourceDir = getChatSourceDir();
2069
+ if (!fs3.existsSync(chatSourceDir)) {
2070
+ logger.error("Chat source files not found. This CLI installation may be corrupted.");
2071
+ process.exit(1);
2072
+ }
2073
+ logger.log("");
2074
+ logger.info("Scaffolding a frontend chat application...");
2075
+ logger.log("");
2076
+ let projectName = projectNameArg;
2077
+ if (!projectName && !options.yes) {
2078
+ projectName = await prompt2("Project name: ");
2079
+ }
2080
+ if (!projectName) {
2081
+ logger.error("Project name is required");
2082
+ process.exit(1);
2083
+ }
2084
+ const projectPath = path3.join(cwd, projectName);
2085
+ if (fs3.existsSync(projectPath)) {
2086
+ logger.error(`Directory "${projectName}" already exists`);
2087
+ process.exit(1);
2088
+ }
2089
+ let framework;
2090
+ if (options.framework) {
2091
+ framework = options.framework;
2092
+ } else if (options.yes) {
2093
+ framework = "vite";
2094
+ } else {
2095
+ framework = await selectFramework();
2096
+ logger.log("");
2097
+ }
2098
+ let serverUrl;
2099
+ if (options.yes) {
2100
+ serverUrl = "http://localhost:5173";
2101
+ } else {
2102
+ const detectedUrl = await detectAgentbuilderInstance();
2103
+ if (detectedUrl) {
2104
+ logger.success(`Found agentbuilder at ${detectedUrl}`);
2105
+ const urlInput = await prompt2(`Agentbuilder dev server URL [${detectedUrl}]: `);
2106
+ serverUrl = urlInput || detectedUrl;
2107
+ } else {
2108
+ logger.log("\x1B[90mNo running agentbuilder instance found\x1B[0m");
2109
+ const urlInput = await prompt2("Agentbuilder dev server URL [http://localhost:5173]: ");
2110
+ serverUrl = urlInput || "http://localhost:5173";
2111
+ }
2112
+ if (!isValidUrl(serverUrl)) {
2113
+ logger.error("Invalid URL format");
2114
+ process.exit(1);
2115
+ }
2116
+ }
2117
+ const detectedPm = detectPackageManager2();
2118
+ let pm;
2119
+ if (options.yes) {
2120
+ pm = detectedPm;
2121
+ } else {
2122
+ pm = await selectPackageManager2(detectedPm);
2123
+ logger.log("");
2124
+ }
2125
+ logger.log("");
2126
+ logger.info(`Creating ${framework === "vite" ? "Vite" : "Next.js"} project...`);
2127
+ logger.log("");
2128
+ fs3.mkdirSync(projectPath, { recursive: true });
2129
+ const reactVersion = getReactPackageVersion();
2130
+ if (framework === "vite") {
2131
+ await scaffoldVite(projectPath, chatSourceDir, projectName, serverUrl, reactVersion);
2132
+ } else {
2133
+ await scaffoldNextjs(projectPath, chatSourceDir, projectName, serverUrl, reactVersion);
2134
+ }
2135
+ logger.log("");
2136
+ logger.info("Installing dependencies...");
2137
+ logger.log("");
2138
+ try {
2139
+ await runCommand2(pm, pm === "npm" ? ["install"] : ["install"], projectPath);
2140
+ } catch (error) {
2141
+ logger.error("Failed to install dependencies");
2142
+ process.exit(1);
2143
+ }
2144
+ logger.log("");
2145
+ logger.success("Chat UI scaffolded successfully!");
2146
+ logger.log("");
2147
+ logger.info("Starting development server...");
2148
+ logger.log("");
2149
+ const devArgs = pm === "npm" ? ["run", "dev"] : ["dev"];
2150
+ const devProcess = spawn(pm, devArgs, {
2151
+ cwd: projectPath,
2152
+ stdio: ["inherit", "pipe", "pipe"],
2153
+ shell: false
2154
+ });
2155
+ let browserOpened = false;
2156
+ const openBrowser = (url) => {
2157
+ if (browserOpened) return;
2158
+ browserOpened = true;
2159
+ const openCmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
2160
+ spawn(openCmd, [url], { stdio: "ignore", detached: true }).unref();
2161
+ };
2162
+ devProcess.stdout?.on("data", (data) => {
2163
+ const text = data.toString();
2164
+ process.stdout.write(data);
2165
+ const urlMatch = text.match(/Local:\s+(https?:\/\/localhost:\d+\/?)/);
2166
+ if (urlMatch && !browserOpened) {
2167
+ openBrowser(urlMatch[1]);
2168
+ }
2169
+ });
2170
+ devProcess.stderr?.on("data", (data) => {
2171
+ process.stderr.write(data);
2172
+ });
2173
+ devProcess.on("error", (error) => {
2174
+ logger.error(`Failed to start dev server: ${error.message}`);
2175
+ process.exit(1);
2176
+ });
2177
+ }
2178
+ async function scaffoldVite(projectPath, chatSourceDir, projectName, serverUrl, reactVersion) {
2179
+ copyDir(path3.join(chatSourceDir, "src"), path3.join(projectPath, "src"), []);
2180
+ logger.success("Copied src/");
2181
+ const viteDir = path3.join(chatSourceDir, "vite");
2182
+ let indexHtml = fs3.readFileSync(path3.join(viteDir, "index.html"), "utf-8");
2183
+ indexHtml = indexHtml.replace('src="/main.tsx"', 'src="/src/main.tsx"');
2184
+ fs3.writeFileSync(path3.join(projectPath, "index.html"), indexHtml, "utf-8");
2185
+ logger.success("Created index.html");
2186
+ fs3.copyFileSync(path3.join(viteDir, "main.tsx"), path3.join(projectPath, "src", "main.tsx"));
2187
+ logger.success("Created src/main.tsx");
2188
+ let viteConfig = fs3.readFileSync(path3.join(viteDir, "vite.config.ts"), "utf-8");
2189
+ viteConfig = `import { defineConfig } from 'vite'
2190
+ import react from '@vitejs/plugin-react'
2191
+ import tailwindcss from '@tailwindcss/vite'
2192
+
2193
+ export default defineConfig({
2194
+ plugins: [
2195
+ react(),
2196
+ tailwindcss(),
2197
+ ],
2198
+ })
2199
+ `;
2200
+ fs3.writeFileSync(path3.join(projectPath, "vite.config.ts"), viteConfig, "utf-8");
2201
+ logger.success("Created vite.config.ts");
2202
+ fs3.copyFileSync(path3.join(chatSourceDir, "tsconfig.json"), path3.join(projectPath, "tsconfig.json"));
2203
+ const tsconfig = JSON.parse(fs3.readFileSync(path3.join(projectPath, "tsconfig.json"), "utf-8"));
2204
+ tsconfig.include = ["src"];
2205
+ delete tsconfig.compilerOptions?.paths;
2206
+ fs3.writeFileSync(path3.join(projectPath, "tsconfig.json"), JSON.stringify(tsconfig, null, 2) + "\n", "utf-8");
2207
+ logger.success("Created tsconfig.json");
2208
+ fs3.copyFileSync(path3.join(chatSourceDir, "package.json"), path3.join(projectPath, "package.json"));
2209
+ const pkg2 = JSON.parse(fs3.readFileSync(path3.join(projectPath, "package.json"), "utf-8"));
2210
+ pkg2.name = projectName;
2211
+ pkg2.scripts = {
2212
+ dev: "vite",
2213
+ build: "vite build",
2214
+ preview: "vite preview"
2215
+ };
2216
+ delete pkg2.private;
2217
+ if (pkg2.dependencies?.["@standardagents/react"]) {
2218
+ pkg2.dependencies["@standardagents/react"] = reactVersion;
2219
+ }
2220
+ delete pkg2.dependencies?.["next"];
2221
+ delete pkg2.devDependencies?.["@tailwindcss/postcss"];
2222
+ delete pkg2.devDependencies?.["postcss"];
2223
+ fs3.writeFileSync(path3.join(projectPath, "package.json"), JSON.stringify(pkg2, null, 2) + "\n", "utf-8");
2224
+ logger.success("Created package.json");
2225
+ const envContent = `# Agentbuilder connection
2226
+ VITE_AGENTBUILDER_URL=${serverUrl}
2227
+ `;
2228
+ fs3.writeFileSync(path3.join(projectPath, ".env"), envContent, "utf-8");
2229
+ logger.success("Created .env");
2230
+ fs3.writeFileSync(path3.join(projectPath, ".gitignore"), `node_modules
2231
+ dist
2232
+ .env
2233
+ `, "utf-8");
2234
+ logger.success("Created .gitignore");
2235
+ let mainTsx = fs3.readFileSync(path3.join(projectPath, "src", "main.tsx"), "utf-8");
2236
+ mainTsx = mainTsx.replace(/from '\.\.\/src\//g, "from './").replace(/import '\.\.\/src\//g, "import './");
2237
+ fs3.writeFileSync(path3.join(projectPath, "src", "main.tsx"), mainTsx, "utf-8");
2238
+ if (fs3.existsSync(path3.join(viteDir, "favicon.svg"))) {
2239
+ fs3.copyFileSync(path3.join(viteDir, "favicon.svg"), path3.join(projectPath, "favicon.svg"));
2240
+ logger.success("Created favicon.svg");
2241
+ }
2242
+ }
2243
+ async function scaffoldNextjs(projectPath, chatSourceDir, projectName, serverUrl, reactVersion) {
2244
+ copyDir(path3.join(chatSourceDir, "src"), path3.join(projectPath, "src"), []);
2245
+ logger.success("Copied src/");
2246
+ const nextDir = path3.join(chatSourceDir, "next");
2247
+ copyDir(path3.join(nextDir, "app"), path3.join(projectPath, "app"), []);
2248
+ logger.success("Copied app/");
2249
+ fs3.copyFileSync(path3.join(nextDir, "next.config.ts"), path3.join(projectPath, "next.config.ts"));
2250
+ logger.success("Created next.config.ts");
2251
+ fs3.copyFileSync(path3.join(nextDir, "postcss.config.mjs"), path3.join(projectPath, "postcss.config.mjs"));
2252
+ logger.success("Created postcss.config.mjs");
2253
+ const tsconfig = {
2254
+ compilerOptions: {
2255
+ target: "ES2017",
2256
+ lib: ["dom", "dom.iterable", "esnext"],
2257
+ allowJs: true,
2258
+ skipLibCheck: true,
2259
+ strict: true,
2260
+ noEmit: true,
2261
+ esModuleInterop: true,
2262
+ module: "esnext",
2263
+ moduleResolution: "bundler",
2264
+ resolveJsonModule: true,
2265
+ isolatedModules: true,
2266
+ jsx: "preserve",
2267
+ incremental: true,
2268
+ plugins: [{ name: "next" }],
2269
+ paths: {
2270
+ "@/*": ["./src/*"]
2271
+ }
2272
+ },
2273
+ include: ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
2274
+ exclude: ["node_modules"]
2275
+ };
2276
+ fs3.writeFileSync(path3.join(projectPath, "tsconfig.json"), JSON.stringify(tsconfig, null, 2) + "\n", "utf-8");
2277
+ logger.success("Created tsconfig.json");
2278
+ const pkg2 = JSON.parse(fs3.readFileSync(path3.join(chatSourceDir, "package.json"), "utf-8"));
2279
+ pkg2.name = projectName;
2280
+ pkg2.scripts = {
2281
+ dev: "next dev",
2282
+ build: "next build",
2283
+ start: "next start"
2284
+ };
2285
+ delete pkg2.private;
2286
+ if (pkg2.dependencies?.["@standardagents/react"]) {
2287
+ pkg2.dependencies["@standardagents/react"] = reactVersion;
2288
+ }
2289
+ delete pkg2.devDependencies?.["@tailwindcss/vite"];
2290
+ delete pkg2.devDependencies?.["@vitejs/plugin-react"];
2291
+ delete pkg2.devDependencies?.["vite"];
2292
+ fs3.writeFileSync(path3.join(projectPath, "package.json"), JSON.stringify(pkg2, null, 2) + "\n", "utf-8");
2293
+ logger.success("Created package.json");
2294
+ const envContent = `# Agentbuilder connection
2295
+ NEXT_PUBLIC_AGENTBUILDER_URL=${serverUrl}
2296
+ `;
2297
+ fs3.writeFileSync(path3.join(projectPath, ".env.local"), envContent, "utf-8");
2298
+ logger.success("Created .env.local");
2299
+ fs3.writeFileSync(path3.join(projectPath, ".gitignore"), `node_modules
2300
+ .next
2301
+ out
2302
+ .env.local
2303
+ `, "utf-8");
2304
+ logger.success("Created .gitignore");
2305
+ let layoutTsx = fs3.readFileSync(path3.join(projectPath, "app", "layout.tsx"), "utf-8");
2306
+ layoutTsx = layoutTsx.replace(/from '\.\.\/\.\.\/src\//g, "from '../src/");
2307
+ fs3.writeFileSync(path3.join(projectPath, "app", "layout.tsx"), layoutTsx, "utf-8");
2308
+ let pageTsx = fs3.readFileSync(path3.join(projectPath, "app", "page.tsx"), "utf-8");
2309
+ pageTsx = pageTsx.replace(/from '\.\.\/\.\.\/src\//g, "from '../src/");
2310
+ fs3.writeFileSync(path3.join(projectPath, "app", "page.tsx"), pageTsx, "utf-8");
2311
+ }
1746
2312
 
1747
2313
  // src/index.ts
1748
2314
  var __dirname$1 = dirname(fileURLToPath(import.meta.url));
@@ -1751,6 +2317,7 @@ var program = new Command();
1751
2317
  program.name("agents").description("CLI tool for Standard Agents / AgentBuilder").version(pkg.version);
1752
2318
  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);
1753
2319
  program.command("scaffold").description("Add Standard Agents to an existing Vite project").option("--force", "Overwrite existing configuration").action(scaffold);
2320
+ 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);
1754
2321
  program.parse();
1755
2322
  //# sourceMappingURL=index.js.map
1756
2323
  //# sourceMappingURL=index.js.map