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