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