@standardagents/cli 0.15.3 → 0.17.0-next.a4b7340
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/README.md +38 -41
- package/dist/index.js +628 -762
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -6,12 +6,12 @@ import crypto from 'crypto';
|
|
|
6
6
|
import os3 from 'os';
|
|
7
7
|
import net from 'net';
|
|
8
8
|
import readline from 'readline';
|
|
9
|
-
import { spawn,
|
|
9
|
+
import { spawn, execFileSync, spawnSync } from 'child_process';
|
|
10
10
|
import { fileURLToPath, pathToFileURL } from 'url';
|
|
11
|
-
import { FIRST_PARTY_PROVIDER_PACKAGES,
|
|
11
|
+
import { FIRST_PARTY_PROVIDER_PACKAGES, AGENT_DEFINITIONS_AGENTS_MD, PROMPTS_AGENTS_MD, MODELS_AGENTS_MD, TOOLS_AGENTS_MD, HOOKS_AGENTS_MD, API_AGENTS_MD, renderAgentBuilderSupportFiles, ROOT_AGENTS_MD } from '@standardagents/agentbuilder-template';
|
|
12
12
|
import chalk from 'chalk';
|
|
13
13
|
import { parse, modify, applyEdits } from 'jsonc-parser';
|
|
14
|
-
import { loadFile, writeFile
|
|
14
|
+
import { loadFile, writeFile } from 'magicast';
|
|
15
15
|
import { addVitePlugin } from 'magicast/helpers';
|
|
16
16
|
import { useState, useMemo } from 'react';
|
|
17
17
|
import { render, renderToString, Box, Text, useApp, useInput } from 'ink';
|
|
@@ -235,30 +235,11 @@ function openBrowser(url) {
|
|
|
235
235
|
return false;
|
|
236
236
|
}
|
|
237
237
|
}
|
|
238
|
-
function getScaffoldCompatibilityDate() {
|
|
239
|
-
return "2025-08-13";
|
|
240
|
-
}
|
|
241
238
|
function getScaffoldStandardAgentsVersion() {
|
|
242
239
|
if (process.env.STANDARDAGENTS_WORKSPACE === "1") {
|
|
243
240
|
return "workspace:*";
|
|
244
241
|
}
|
|
245
|
-
return "0.
|
|
246
|
-
}
|
|
247
|
-
function getScaffoldCloudflareVitePluginVersion() {
|
|
248
|
-
return "^1.17.0";
|
|
249
|
-
}
|
|
250
|
-
function getProjectName(cwd) {
|
|
251
|
-
const packageJsonPath = path7.join(cwd, "package.json");
|
|
252
|
-
if (fs3.existsSync(packageJsonPath)) {
|
|
253
|
-
try {
|
|
254
|
-
const pkg = JSON.parse(fs3.readFileSync(packageJsonPath, "utf-8"));
|
|
255
|
-
if (pkg.name) {
|
|
256
|
-
return pkg.name.replace(/^@[^/]+\//, "");
|
|
257
|
-
}
|
|
258
|
-
} catch {
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
return path7.basename(cwd);
|
|
242
|
+
return "0.17.0-next.a4b7340";
|
|
262
243
|
}
|
|
263
244
|
function findViteConfig(cwd) {
|
|
264
245
|
const candidates = ["vite.config.ts", "vite.config.js", "vite.config.mts", "vite.config.mjs"];
|
|
@@ -270,16 +251,6 @@ function findViteConfig(cwd) {
|
|
|
270
251
|
}
|
|
271
252
|
return null;
|
|
272
253
|
}
|
|
273
|
-
function findWranglerConfig(cwd) {
|
|
274
|
-
const candidates = ["wrangler.jsonc", "wrangler.json"];
|
|
275
|
-
for (const candidate of candidates) {
|
|
276
|
-
const configPath = path7.join(cwd, candidate);
|
|
277
|
-
if (fs3.existsSync(configPath)) {
|
|
278
|
-
return configPath;
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
return null;
|
|
282
|
-
}
|
|
283
254
|
function dependencySectionFor(pkg, packageName, fallback) {
|
|
284
255
|
if (pkg.dependencies?.[packageName] !== void 0) return "dependencies";
|
|
285
256
|
if (pkg.devDependencies?.[packageName] !== void 0) return "devDependencies";
|
|
@@ -294,27 +265,20 @@ function setPackageDependency(packageJsonText, section, packageName, version) {
|
|
|
294
265
|
function updatePackageDependencies(cwd, versions = {}) {
|
|
295
266
|
const packageJsonPath = path7.join(cwd, "package.json");
|
|
296
267
|
if (!fs3.existsSync(packageJsonPath)) {
|
|
297
|
-
logger.warning("No package.json found. Install @standardagents/builder
|
|
268
|
+
logger.warning("No package.json found. Install @standardagents/builder manually.");
|
|
298
269
|
return false;
|
|
299
270
|
}
|
|
300
271
|
try {
|
|
301
272
|
const text = fs3.readFileSync(packageJsonPath, "utf-8");
|
|
302
273
|
const pkg = JSON.parse(text);
|
|
303
274
|
const desiredBuilderVersion = versions.standardAgents ?? getScaffoldStandardAgentsVersion();
|
|
304
|
-
const desiredCloudflareVersion = versions.cloudflareVitePlugin ?? getScaffoldCloudflareVitePluginVersion();
|
|
305
275
|
const builderSection = dependencySectionFor(pkg, "@standardagents/builder", "dependencies");
|
|
306
|
-
const cloudflareSection = dependencySectionFor(pkg, "@cloudflare/vite-plugin", "devDependencies");
|
|
307
276
|
let result = text;
|
|
308
277
|
let changed = false;
|
|
309
278
|
if (pkg[builderSection]?.["@standardagents/builder"] !== desiredBuilderVersion) {
|
|
310
279
|
result = setPackageDependency(result, builderSection, "@standardagents/builder", desiredBuilderVersion);
|
|
311
280
|
changed = true;
|
|
312
281
|
}
|
|
313
|
-
const currentAfterBuilder = JSON.parse(result);
|
|
314
|
-
if (currentAfterBuilder[cloudflareSection]?.["@cloudflare/vite-plugin"] !== desiredCloudflareVersion) {
|
|
315
|
-
result = setPackageDependency(result, cloudflareSection, "@cloudflare/vite-plugin", desiredCloudflareVersion);
|
|
316
|
-
changed = true;
|
|
317
|
-
}
|
|
318
282
|
if (!changed) {
|
|
319
283
|
logger.info("package.json already has current Standard Agents dependencies");
|
|
320
284
|
return true;
|
|
@@ -332,28 +296,18 @@ async function modifyViteConfig(configPath, force) {
|
|
|
332
296
|
try {
|
|
333
297
|
const mod = await loadFile(configPath);
|
|
334
298
|
const code = fs3.readFileSync(configPath, "utf-8");
|
|
335
|
-
const
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
logger.info("Vite config already includes Standard Agents plugins");
|
|
299
|
+
const hasAgentBuilder = code.includes("@standardagents/builder") || code.includes("builder()") || code.includes("agentbuilder()");
|
|
300
|
+
if (hasAgentBuilder && !force) {
|
|
301
|
+
logger.info("Vite config already includes builder plugin");
|
|
339
302
|
return true;
|
|
340
303
|
}
|
|
341
304
|
if (!hasAgentBuilder || force) {
|
|
342
305
|
addVitePlugin(mod, {
|
|
343
306
|
from: "@standardagents/builder",
|
|
344
|
-
imported: "
|
|
345
|
-
constructor: "
|
|
346
|
-
options: { mountPoint: "/" }
|
|
347
|
-
});
|
|
348
|
-
logger.success("Added agentbuilder plugin to vite.config");
|
|
349
|
-
}
|
|
350
|
-
if (!hasCloudflare || force) {
|
|
351
|
-
addVitePlugin(mod, {
|
|
352
|
-
from: "@cloudflare/vite-plugin",
|
|
353
|
-
imported: "cloudflare",
|
|
354
|
-
constructor: "cloudflare"
|
|
307
|
+
imported: "builder",
|
|
308
|
+
constructor: "builder"
|
|
355
309
|
});
|
|
356
|
-
logger.success("Added
|
|
310
|
+
logger.success("Added builder plugin to vite.config");
|
|
357
311
|
}
|
|
358
312
|
await writeFile(mod, configPath);
|
|
359
313
|
return true;
|
|
@@ -362,257 +316,42 @@ async function modifyViteConfig(configPath, force) {
|
|
|
362
316
|
logger.log("");
|
|
363
317
|
logger.log("Please manually add the following to your vite.config.ts:");
|
|
364
318
|
logger.log("");
|
|
365
|
-
logger.log(` import {
|
|
366
|
-
logger.log(` import { cloudflare } from '@cloudflare/vite-plugin'`);
|
|
319
|
+
logger.log(` import { builder } from '@standardagents/builder'`);
|
|
367
320
|
logger.log("");
|
|
368
|
-
logger.log(` plugins: [
|
|
321
|
+
logger.log(` plugins: [builder()]`);
|
|
369
322
|
logger.log("");
|
|
370
323
|
return false;
|
|
371
324
|
}
|
|
372
325
|
}
|
|
373
|
-
function
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
(b) => b.name === "AGENT_BUILDER_THREAD" || b.name === "AGENT_BUILDER"
|
|
381
|
-
);
|
|
382
|
-
const hasCodeLoader = config.worker_loaders?.some(
|
|
383
|
-
(loader) => loader.binding === "AGENT_BUILDER_CODE_LOADER"
|
|
384
|
-
);
|
|
385
|
-
const hasCodeCompatibilityDate = config.vars?.AGENT_BUILDER_CODE_COMPATIBILITY_DATE === getScaffoldCompatibilityDate();
|
|
386
|
-
const hasCtxExportsFlag = Array.isArray(config.compatibility_flags) ? config.compatibility_flags.includes("enable_ctx_exports") : false;
|
|
387
|
-
if (hasBindings && hasCodeLoader && hasCodeCompatibilityDate && hasCtxExportsFlag) {
|
|
388
|
-
logger.info("wrangler.jsonc already configured for Standard Agents");
|
|
389
|
-
return true;
|
|
390
|
-
}
|
|
391
|
-
let result = text;
|
|
392
|
-
if (!hasCodeLoader) {
|
|
393
|
-
const loaders = [...config.worker_loaders || [], { binding: "AGENT_BUILDER_CODE_LOADER" }];
|
|
394
|
-
const edits = modify(result, ["worker_loaders"], loaders, {});
|
|
395
|
-
result = applyEdits(result, edits);
|
|
396
|
-
}
|
|
397
|
-
if (!hasCodeCompatibilityDate) {
|
|
398
|
-
const vars = {
|
|
399
|
-
...config.vars || {},
|
|
400
|
-
AGENT_BUILDER_CODE_COMPATIBILITY_DATE: getScaffoldCompatibilityDate()
|
|
401
|
-
};
|
|
402
|
-
const edits = modify(result, ["vars"], vars, {});
|
|
403
|
-
result = applyEdits(result, edits);
|
|
404
|
-
}
|
|
405
|
-
if (!hasCtxExportsFlag) {
|
|
406
|
-
const flags = Array.isArray(config.compatibility_flags) ? [...config.compatibility_flags, "enable_ctx_exports"] : ["nodejs_compat", "enable_ctx_exports"];
|
|
407
|
-
const edits = modify(result, ["compatibility_flags"], flags, {});
|
|
408
|
-
result = applyEdits(result, edits);
|
|
409
|
-
}
|
|
410
|
-
if (!config.durable_objects) {
|
|
411
|
-
const edits = modify(result, ["durable_objects"], {
|
|
412
|
-
bindings: [
|
|
413
|
-
{ name: "AGENT_BUILDER_THREAD", class_name: "DurableThread" },
|
|
414
|
-
{ name: "AGENT_BUILDER", class_name: "DurableAgentBuilder" }
|
|
415
|
-
]
|
|
416
|
-
}, {});
|
|
417
|
-
result = applyEdits(result, edits);
|
|
418
|
-
} else {
|
|
419
|
-
const bindings = config.durable_objects.bindings || [];
|
|
420
|
-
if (!bindings.some((b) => b.name === "AGENT_BUILDER_THREAD")) {
|
|
421
|
-
bindings.push({ name: "AGENT_BUILDER_THREAD", class_name: "DurableThread" });
|
|
422
|
-
}
|
|
423
|
-
if (!bindings.some((b) => b.name === "AGENT_BUILDER")) {
|
|
424
|
-
bindings.push({ name: "AGENT_BUILDER", class_name: "DurableAgentBuilder" });
|
|
425
|
-
}
|
|
426
|
-
const edits = modify(result, ["durable_objects", "bindings"], bindings, {});
|
|
427
|
-
result = applyEdits(result, edits);
|
|
428
|
-
}
|
|
429
|
-
if (!config.migrations) {
|
|
430
|
-
const edits = modify(result, ["migrations"], [
|
|
431
|
-
{ tag: "v1", new_sqlite_classes: ["DurableThread"] },
|
|
432
|
-
{ tag: "v2", new_sqlite_classes: ["DurableAgentBuilder"] }
|
|
433
|
-
], {});
|
|
434
|
-
result = applyEdits(result, edits);
|
|
435
|
-
}
|
|
436
|
-
if (!config.main || !config.main.includes("worker")) {
|
|
437
|
-
const edits = modify(result, ["main"], "worker/index.ts", {});
|
|
438
|
-
result = applyEdits(result, edits);
|
|
439
|
-
}
|
|
440
|
-
if (!config.assets) {
|
|
441
|
-
const edits = modify(result, ["assets"], {
|
|
442
|
-
directory: "dist/client",
|
|
443
|
-
not_found_handling: "single-page-application",
|
|
444
|
-
binding: "ASSETS",
|
|
445
|
-
run_worker_first: ["/**"]
|
|
446
|
-
}, {});
|
|
447
|
-
result = applyEdits(result, edits);
|
|
448
|
-
}
|
|
449
|
-
fs3.writeFileSync(existingConfig, result, "utf-8");
|
|
450
|
-
logger.success("Updated wrangler.jsonc with Standard Agents configuration");
|
|
451
|
-
return true;
|
|
452
|
-
} catch (error) {
|
|
453
|
-
logger.warning(`Could not update wrangler config: ${error}`);
|
|
454
|
-
return false;
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
const wranglerPath = path7.join(cwd, "wrangler.jsonc");
|
|
458
|
-
const sanitizedName = projectName.toLowerCase().replace(/[^a-z0-9-]/g, "-");
|
|
459
|
-
fs3.writeFileSync(
|
|
460
|
-
wranglerPath,
|
|
461
|
-
renderWranglerJson({
|
|
462
|
-
projectName: sanitizedName,
|
|
463
|
-
compatibilityDate: getScaffoldCompatibilityDate()
|
|
464
|
-
}),
|
|
465
|
-
"utf-8"
|
|
466
|
-
);
|
|
467
|
-
logger.success("Created wrangler.jsonc");
|
|
468
|
-
return true;
|
|
469
|
-
}
|
|
470
|
-
function getWorkerEntryPoint(cwd) {
|
|
471
|
-
const wranglerConfig = findWranglerConfig(cwd);
|
|
472
|
-
if (wranglerConfig) {
|
|
473
|
-
try {
|
|
474
|
-
const text = fs3.readFileSync(wranglerConfig, "utf-8");
|
|
475
|
-
const config = parse(text);
|
|
476
|
-
if (config.main) {
|
|
477
|
-
return path7.join(cwd, config.main);
|
|
478
|
-
}
|
|
479
|
-
} catch {
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
return path7.join(cwd, "worker", "index.ts");
|
|
483
|
-
}
|
|
484
|
-
async function createOrUpdateWorkerEntry(cwd, force) {
|
|
485
|
-
const entryPath = getWorkerEntryPoint(cwd);
|
|
486
|
-
const entryDir = path7.dirname(entryPath);
|
|
487
|
-
if (!fs3.existsSync(entryDir)) {
|
|
488
|
-
fs3.mkdirSync(entryDir, { recursive: true });
|
|
489
|
-
logger.success(`Created ${path7.relative(cwd, entryDir)} directory`);
|
|
490
|
-
}
|
|
491
|
-
if (!fs3.existsSync(entryPath)) {
|
|
492
|
-
fs3.writeFileSync(entryPath, renderWorkerIndex(), "utf-8");
|
|
493
|
-
logger.success(`Created ${path7.relative(cwd, entryPath)}`);
|
|
494
|
-
return true;
|
|
495
|
-
}
|
|
496
|
-
const content = fs3.readFileSync(entryPath, "utf-8");
|
|
497
|
-
const hasRouter = content.includes("virtual:@standardagents/builder") && content.includes("router");
|
|
498
|
-
const hasDurableExports = content.includes("DurableThread") && content.includes("DurableAgentBuilder");
|
|
499
|
-
const hasCodeBridge = content.includes("CodeExecutionBridge");
|
|
500
|
-
if (hasRouter && hasDurableExports && hasCodeBridge && !force) {
|
|
501
|
-
logger.info(`${path7.relative(cwd, entryPath)} already configured`);
|
|
502
|
-
return true;
|
|
503
|
-
}
|
|
504
|
-
if (hasRouter && hasDurableExports && !hasCodeBridge && !force) {
|
|
505
|
-
fs3.writeFileSync(
|
|
506
|
-
entryPath,
|
|
507
|
-
`${content.trimEnd()}
|
|
508
|
-
|
|
509
|
-
export { CodeExecutionBridge } from "virtual:@standardagents/builder"
|
|
510
|
-
`,
|
|
511
|
-
"utf-8"
|
|
512
|
-
);
|
|
513
|
-
logger.success(`Updated ${path7.relative(cwd, entryPath)} with CodeExecutionBridge export`);
|
|
514
|
-
return true;
|
|
515
|
-
}
|
|
516
|
-
try {
|
|
517
|
-
const mod = await loadFile(entryPath);
|
|
518
|
-
if (!content.includes("virtual:@standardagents/builder") || force) {
|
|
519
|
-
mod.imports.$add({
|
|
520
|
-
from: "virtual:@standardagents/builder",
|
|
521
|
-
imported: "router",
|
|
522
|
-
local: "router"
|
|
523
|
-
});
|
|
524
|
-
}
|
|
525
|
-
if (!content.includes("'../agents/Thread'") || force) {
|
|
526
|
-
mod.imports.$add({
|
|
527
|
-
from: "../agents/Thread",
|
|
528
|
-
imported: "default",
|
|
529
|
-
local: "DurableThread"
|
|
530
|
-
});
|
|
531
|
-
}
|
|
532
|
-
if (!content.includes("'../agents/AgentBuilder'") || force) {
|
|
533
|
-
mod.imports.$add({
|
|
534
|
-
from: "../agents/AgentBuilder",
|
|
535
|
-
imported: "default",
|
|
536
|
-
local: "DurableAgentBuilder"
|
|
537
|
-
});
|
|
538
|
-
}
|
|
539
|
-
const { code } = generateCode(mod);
|
|
540
|
-
if (force || !hasRouter) {
|
|
541
|
-
fs3.writeFileSync(entryPath, renderWorkerIndex(), "utf-8");
|
|
542
|
-
logger.success(`Updated ${path7.relative(cwd, entryPath)} with Standard Agents router`);
|
|
326
|
+
function createDirectoriesAndDocs(cwd) {
|
|
327
|
+
function writeAgentsDocWithClaudeSymlink(dirPath, doc, label) {
|
|
328
|
+
const agentsDocPath = path7.join(dirPath, "AGENTS.md");
|
|
329
|
+
const claudeDocPath = path7.join(dirPath, "CLAUDE.md");
|
|
330
|
+
if (!fs3.existsSync(agentsDocPath)) {
|
|
331
|
+
fs3.writeFileSync(agentsDocPath, doc, "utf-8");
|
|
332
|
+
logger.success(`Created ${label}/AGENTS.md`);
|
|
543
333
|
}
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
fs3.writeFileSync(entryPath, renderWorkerIndex(), "utf-8");
|
|
548
|
-
logger.success(`Created ${path7.relative(cwd, entryPath)}`);
|
|
549
|
-
return true;
|
|
334
|
+
if (!fs3.existsSync(claudeDocPath)) {
|
|
335
|
+
fs3.symlinkSync("AGENTS.md", claudeDocPath);
|
|
336
|
+
logger.success(`Created ${label}/CLAUDE.md symlink`);
|
|
550
337
|
}
|
|
551
|
-
logger.warning(`Could not automatically modify ${path7.relative(cwd, entryPath)}`);
|
|
552
|
-
logger.log("");
|
|
553
|
-
logger.log("Please ensure your worker entry point includes:");
|
|
554
|
-
logger.log("");
|
|
555
|
-
logger.log(` import { router } from "virtual:@standardagents/builder"`);
|
|
556
|
-
logger.log(` import DurableThread from '../agents/Thread';`);
|
|
557
|
-
logger.log(` import DurableAgentBuilder from '../agents/AgentBuilder';`);
|
|
558
|
-
logger.log("");
|
|
559
|
-
logger.log(" // In your fetch handler:");
|
|
560
|
-
logger.log(" const res = router(request, env)");
|
|
561
|
-
logger.log(" if (res) return res");
|
|
562
|
-
logger.log("");
|
|
563
|
-
logger.log(" // Export Durable Objects:");
|
|
564
|
-
logger.log(" export { DurableThread, DurableAgentBuilder }");
|
|
565
|
-
logger.log(' export { CodeExecutionBridge } from "virtual:@standardagents/builder"');
|
|
566
|
-
logger.log("");
|
|
567
|
-
return false;
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
function createDurableObjects(cwd) {
|
|
571
|
-
const agentsDir = path7.join(cwd, "agents");
|
|
572
|
-
if (!fs3.existsSync(agentsDir)) {
|
|
573
|
-
fs3.mkdirSync(agentsDir, { recursive: true });
|
|
574
|
-
}
|
|
575
|
-
const threadPath = path7.join(agentsDir, "Thread.ts");
|
|
576
|
-
if (!fs3.existsSync(threadPath)) {
|
|
577
|
-
fs3.writeFileSync(threadPath, renderDurableThread(), "utf-8");
|
|
578
|
-
logger.success("Created agents/Thread.ts");
|
|
579
|
-
} else {
|
|
580
|
-
logger.info("agents/Thread.ts already exists");
|
|
581
|
-
}
|
|
582
|
-
const agentBuilderPath = path7.join(agentsDir, "AgentBuilder.ts");
|
|
583
|
-
if (!fs3.existsSync(agentBuilderPath)) {
|
|
584
|
-
fs3.writeFileSync(agentBuilderPath, renderDurableAgentBuilder(), "utf-8");
|
|
585
|
-
logger.success("Created agents/AgentBuilder.ts");
|
|
586
|
-
} else {
|
|
587
|
-
logger.info("agents/AgentBuilder.ts already exists");
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
function createDirectoriesAndDocs(cwd) {
|
|
591
|
-
path7.join(cwd, "agents");
|
|
592
|
-
const rootDocPath = path7.join(cwd, "CLAUDE.md");
|
|
593
|
-
if (!fs3.existsSync(rootDocPath)) {
|
|
594
|
-
fs3.writeFileSync(rootDocPath, ROOT_CLAUDE_MD, "utf-8");
|
|
595
|
-
logger.success("Created CLAUDE.md");
|
|
596
338
|
}
|
|
339
|
+
writeAgentsDocWithClaudeSymlink(cwd, ROOT_AGENTS_MD, ".");
|
|
597
340
|
const directories = [
|
|
598
|
-
{ path: "agents/agents", doc:
|
|
599
|
-
{ path: "agents/prompts", doc:
|
|
600
|
-
{ path: "agents/models", doc:
|
|
601
|
-
{ path: "agents/tools", doc:
|
|
602
|
-
{ path: "agents/hooks", doc:
|
|
603
|
-
{ path: "agents/api", doc:
|
|
341
|
+
{ path: "agents/agents", doc: AGENT_DEFINITIONS_AGENTS_MD },
|
|
342
|
+
{ path: "agents/prompts", doc: PROMPTS_AGENTS_MD },
|
|
343
|
+
{ path: "agents/models", doc: MODELS_AGENTS_MD },
|
|
344
|
+
{ path: "agents/tools", doc: TOOLS_AGENTS_MD },
|
|
345
|
+
{ path: "agents/hooks", doc: HOOKS_AGENTS_MD },
|
|
346
|
+
{ path: "agents/api", doc: API_AGENTS_MD }
|
|
604
347
|
];
|
|
605
348
|
for (const dir of directories) {
|
|
606
349
|
const dirPath = path7.join(cwd, dir.path);
|
|
607
|
-
const docPath = path7.join(dirPath, "CLAUDE.md");
|
|
608
350
|
if (!fs3.existsSync(dirPath)) {
|
|
609
351
|
fs3.mkdirSync(dirPath, { recursive: true });
|
|
610
352
|
logger.success(`Created ${dir.path}`);
|
|
611
353
|
}
|
|
612
|
-
|
|
613
|
-
fs3.writeFileSync(docPath, dir.doc, "utf-8");
|
|
614
|
-
logger.success(`Created ${dir.path}/CLAUDE.md`);
|
|
615
|
-
}
|
|
354
|
+
writeAgentsDocWithClaudeSymlink(dirPath, dir.doc, dir.path);
|
|
616
355
|
}
|
|
617
356
|
}
|
|
618
357
|
function updateTsConfig(cwd) {
|
|
@@ -627,7 +366,6 @@ function updateTsConfig(cwd) {
|
|
|
627
366
|
let result = text;
|
|
628
367
|
const types = config.compilerOptions?.types || [];
|
|
629
368
|
const newTypes = [
|
|
630
|
-
"./worker-configuration.d.ts",
|
|
631
369
|
"./.agents/types.d.ts",
|
|
632
370
|
"./.agents/virtual-module.d.ts"
|
|
633
371
|
].filter((t) => !types.includes(t));
|
|
@@ -637,7 +375,7 @@ function updateTsConfig(cwd) {
|
|
|
637
375
|
result = applyEdits(result, edits);
|
|
638
376
|
}
|
|
639
377
|
const include = config.include || [];
|
|
640
|
-
const newIncludes = ["
|
|
378
|
+
const newIncludes = ["agents", ".agents", "vite.config.ts"].filter((i) => !include.includes(i));
|
|
641
379
|
if (newIncludes.length > 0) {
|
|
642
380
|
const allIncludes = [...include, ...newIncludes];
|
|
643
381
|
const edits = modify(result, ["include"], allIncludes, {});
|
|
@@ -661,9 +399,14 @@ function cleanupViteDefaults(cwd) {
|
|
|
661
399
|
"src/typescript.svg",
|
|
662
400
|
"src/vite-env.d.ts",
|
|
663
401
|
"index.html",
|
|
664
|
-
"public/vite.svg"
|
|
402
|
+
"public/vite.svg",
|
|
403
|
+
"wrangler.jsonc",
|
|
404
|
+
"wrangler.json",
|
|
405
|
+
"worker/index.ts",
|
|
406
|
+
"agents/Thread.ts",
|
|
407
|
+
"agents/AgentBuilder.ts"
|
|
665
408
|
];
|
|
666
|
-
const dirsToRemove = ["src", "public"];
|
|
409
|
+
const dirsToRemove = ["src", "public", "worker"];
|
|
667
410
|
for (const file of filesToRemove) {
|
|
668
411
|
const filePath = path7.join(cwd, file);
|
|
669
412
|
if (fs3.existsSync(filePath)) {
|
|
@@ -688,7 +431,6 @@ function cleanupViteDefaults(cwd) {
|
|
|
688
431
|
}
|
|
689
432
|
async function scaffold(options = {}) {
|
|
690
433
|
const cwd = process.cwd();
|
|
691
|
-
const projectName = getProjectName(cwd);
|
|
692
434
|
const force = options.force || false;
|
|
693
435
|
logger.info("Scaffolding Standard Agents...");
|
|
694
436
|
logger.log("");
|
|
@@ -696,12 +438,9 @@ async function scaffold(options = {}) {
|
|
|
696
438
|
if (viteConfigPath) {
|
|
697
439
|
await modifyViteConfig(viteConfigPath, force);
|
|
698
440
|
} else {
|
|
699
|
-
logger.warning("No vite.config found. Please create one with
|
|
441
|
+
logger.warning("No vite.config found. Please create one with the agentbuilder plugin.");
|
|
700
442
|
}
|
|
701
443
|
updatePackageDependencies(cwd);
|
|
702
|
-
createOrUpdateWranglerConfig(cwd, projectName, force);
|
|
703
|
-
await createOrUpdateWorkerEntry(cwd, force);
|
|
704
|
-
createDurableObjects(cwd);
|
|
705
444
|
createDirectoriesAndDocs(cwd);
|
|
706
445
|
updateTsConfig(cwd);
|
|
707
446
|
if (force) {
|
|
@@ -712,18 +451,17 @@ async function scaffold(options = {}) {
|
|
|
712
451
|
logger.log("");
|
|
713
452
|
logger.log("Your project structure:");
|
|
714
453
|
logger.log("");
|
|
715
|
-
logger.log("
|
|
454
|
+
logger.log(" AGENTS.md # Architecture documentation");
|
|
455
|
+
logger.log(" CLAUDE.md -> AGENTS.md # Compatibility symlink");
|
|
456
|
+
logger.log(" vite.config.ts # Uses builder(); Cloudflare config is generated");
|
|
457
|
+
logger.log(" tsconfig.json # Includes agents and generated .agents types");
|
|
716
458
|
logger.log(" agents/");
|
|
717
|
-
logger.log(" \u251C\u2500\u2500 Thread.ts # Durable Object for threads");
|
|
718
|
-
logger.log(" \u251C\u2500\u2500 AgentBuilder.ts # Durable Object for agent state");
|
|
719
459
|
logger.log(" \u251C\u2500\u2500 agents/ # Agent definitions");
|
|
720
460
|
logger.log(" \u251C\u2500\u2500 prompts/ # Prompt definitions");
|
|
721
461
|
logger.log(" \u251C\u2500\u2500 models/ # Model configurations");
|
|
722
462
|
logger.log(" \u251C\u2500\u2500 tools/ # Custom tools");
|
|
723
463
|
logger.log(" \u251C\u2500\u2500 hooks/ # Lifecycle hooks");
|
|
724
464
|
logger.log(" \u2514\u2500\u2500 api/ # Thread API endpoints");
|
|
725
|
-
logger.log(" worker/");
|
|
726
|
-
logger.log(" \u2514\u2500\u2500 index.ts # Cloudflare Worker entry point");
|
|
727
465
|
logger.log("");
|
|
728
466
|
}
|
|
729
467
|
var STAGE_LABELS = {
|
|
@@ -1251,7 +989,6 @@ var GENERATED_STANDARD_AGENTS_PACKAGES = [
|
|
|
1251
989
|
"@standardagents/spec",
|
|
1252
990
|
...FIRST_PARTY_PROVIDER_PACKAGES
|
|
1253
991
|
];
|
|
1254
|
-
var PLATFORM_RUNTIME_PACKAGE = "@standardagents/platform-runtime";
|
|
1255
992
|
var PACKAGE_MANAGERS = ["npm", "pnpm", "yarn", "bun"];
|
|
1256
993
|
var MISSING_PLATFORM_PROJECT_NAME_MESSAGE = "The platform did not return a project name. Please run the init command again to start a new project setup.";
|
|
1257
994
|
var LEGACY_BOOTSTRAP_RESPONSE_MESSAGE = "The platform returned an older onboarding response. Please run the init command again to start a new project setup.";
|
|
@@ -1458,20 +1195,33 @@ ${details}`));
|
|
|
1458
1195
|
child.on("error", reject);
|
|
1459
1196
|
});
|
|
1460
1197
|
}
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
child.on("spawn", () => {
|
|
1471
|
-
child.unref();
|
|
1472
|
-
resolve();
|
|
1473
|
-
});
|
|
1198
|
+
var DEV_SERVER_LOG_FILE = ".agentbuilder-dev.log";
|
|
1199
|
+
function startDetachedDevServer(command, args, cwd) {
|
|
1200
|
+
const logPath = path7.join(cwd, DEV_SERVER_LOG_FILE);
|
|
1201
|
+
const logFd = fs3.openSync(logPath, "w");
|
|
1202
|
+
const child = spawn(command, args, {
|
|
1203
|
+
cwd,
|
|
1204
|
+
stdio: ["ignore", logFd, logFd],
|
|
1205
|
+
shell: false,
|
|
1206
|
+
detached: true
|
|
1474
1207
|
});
|
|
1208
|
+
child.unref();
|
|
1209
|
+
fs3.closeSync(logFd);
|
|
1210
|
+
return { logPath };
|
|
1211
|
+
}
|
|
1212
|
+
function readLogTail(logPath, maxLines = 20) {
|
|
1213
|
+
try {
|
|
1214
|
+
const text = fs3.readFileSync(logPath, "utf-8").trimEnd();
|
|
1215
|
+
if (!text) return "";
|
|
1216
|
+
return text.split("\n").slice(-maxLines).join("\n");
|
|
1217
|
+
} catch {
|
|
1218
|
+
return "";
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
function devCommandHint(packageManager) {
|
|
1222
|
+
if (packageManager === "npm") return "npm run dev";
|
|
1223
|
+
if (packageManager === "bun") return "bun run dev";
|
|
1224
|
+
return `${packageManager} dev`;
|
|
1475
1225
|
}
|
|
1476
1226
|
function canConnectToPort(port) {
|
|
1477
1227
|
return new Promise((resolve) => {
|
|
@@ -1497,17 +1247,17 @@ function buildDevServerCommand(packageManager, port) {
|
|
|
1497
1247
|
const viteArgs = ["--host", "127.0.0.1", "--port", String(port), "--strictPort"];
|
|
1498
1248
|
return packageManager === "npm" ? ["run", "dev", "--", ...viteArgs] : ["dev", ...viteArgs];
|
|
1499
1249
|
}
|
|
1500
|
-
async function waitForLocalDevServer(url) {
|
|
1501
|
-
const deadline = Date.now() +
|
|
1250
|
+
async function waitForLocalDevServer(url, timeoutMs = 6e4) {
|
|
1251
|
+
const deadline = Date.now() + timeoutMs;
|
|
1502
1252
|
while (Date.now() < deadline) {
|
|
1503
1253
|
try {
|
|
1504
1254
|
const response = await fetch(url, { cache: "no-store" });
|
|
1505
|
-
if (response.ok) return;
|
|
1255
|
+
if (response.ok) return true;
|
|
1506
1256
|
} catch {
|
|
1507
1257
|
}
|
|
1508
1258
|
await sleep(500);
|
|
1509
1259
|
}
|
|
1510
|
-
|
|
1260
|
+
return false;
|
|
1511
1261
|
}
|
|
1512
1262
|
function sleep(ms) {
|
|
1513
1263
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -1540,7 +1290,8 @@ function isStandardAgentsProjectDir(targetPath) {
|
|
|
1540
1290
|
if (!fs3.existsSync(agentsDir) || !fs3.statSync(agentsDir).isDirectory()) {
|
|
1541
1291
|
return false;
|
|
1542
1292
|
}
|
|
1543
|
-
|
|
1293
|
+
if (hasBuilderDependency(targetPath)) return true;
|
|
1294
|
+
return fs3.existsSync(path7.join(targetPath, "vite.config.ts")) && fs3.existsSync(path7.join(targetPath, "tsconfig.json"));
|
|
1544
1295
|
}
|
|
1545
1296
|
async function resolveProjectTarget(cwd, initialProjectName, options, promptProjectName = prompt) {
|
|
1546
1297
|
if (!initialProjectName && isStandardAgentsProjectDir(cwd)) {
|
|
@@ -1785,7 +1536,7 @@ async function ensurePlatformAuth(options, quietLogs = false, context = {}) {
|
|
|
1785
1536
|
return { connected: true, mode: "standardagents" };
|
|
1786
1537
|
}
|
|
1787
1538
|
function getCliVersion() {
|
|
1788
|
-
return "0.
|
|
1539
|
+
return "0.17.0-next.a4b7340";
|
|
1789
1540
|
}
|
|
1790
1541
|
function getSipVersion() {
|
|
1791
1542
|
return "1.0.1";
|
|
@@ -1868,18 +1619,14 @@ function validateWorkspacePackageDir(packageName, packageDir) {
|
|
|
1868
1619
|
);
|
|
1869
1620
|
}
|
|
1870
1621
|
}
|
|
1871
|
-
function rewriteStandardAgentsDependenciesForWorkspace(projectPath, workspaceRoot
|
|
1622
|
+
function rewriteStandardAgentsDependenciesForWorkspace(projectPath, workspaceRoot) {
|
|
1872
1623
|
const packageJsonPath = path7.join(projectPath, "package.json");
|
|
1873
1624
|
const packageJson = JSON.parse(fs3.readFileSync(packageJsonPath, "utf-8"));
|
|
1874
1625
|
const dependencies = packageJson.dependencies ?? {};
|
|
1875
1626
|
const linkedPackages = [];
|
|
1876
|
-
const
|
|
1877
|
-
...GENERATED_STANDARD_AGENTS_PACKAGES,
|
|
1878
|
-
...Object.keys(extraPackageDirs)
|
|
1879
|
-
];
|
|
1880
|
-
for (const packageName of packageNames) {
|
|
1627
|
+
for (const packageName of GENERATED_STANDARD_AGENTS_PACKAGES) {
|
|
1881
1628
|
if (!(packageName in dependencies)) continue;
|
|
1882
|
-
const packageDir =
|
|
1629
|
+
const packageDir = workspacePackageDir(workspaceRoot, packageName);
|
|
1883
1630
|
validateWorkspacePackageDir(packageName, packageDir);
|
|
1884
1631
|
dependencies[packageName] = `link:${packageDir}`;
|
|
1885
1632
|
linkedPackages.push(packageName);
|
|
@@ -1891,40 +1638,6 @@ function rewriteStandardAgentsDependenciesForWorkspace(projectPath, workspaceRoo
|
|
|
1891
1638
|
}
|
|
1892
1639
|
return linkedPackages;
|
|
1893
1640
|
}
|
|
1894
|
-
function resolvePlatformRuntimePackageDir() {
|
|
1895
|
-
const explicitRoot = process.env.STANDARDAGENTS_PLATFORM_RUNTIME_ROOT?.trim();
|
|
1896
|
-
if (!explicitRoot) return null;
|
|
1897
|
-
const packageDir = path7.resolve(explicitRoot);
|
|
1898
|
-
validateWorkspacePackageDir(PLATFORM_RUNTIME_PACKAGE, packageDir);
|
|
1899
|
-
return packageDir;
|
|
1900
|
-
}
|
|
1901
|
-
function addProjectDependency(projectPath, packageName, version) {
|
|
1902
|
-
const packageJsonPath = path7.join(projectPath, "package.json");
|
|
1903
|
-
const packageJson = JSON.parse(fs3.readFileSync(packageJsonPath, "utf-8"));
|
|
1904
|
-
packageJson.dependencies = {
|
|
1905
|
-
...packageJson.dependencies ?? {},
|
|
1906
|
-
[packageName]: packageJson.dependencies?.[packageName] ?? version
|
|
1907
|
-
};
|
|
1908
|
-
fs3.writeFileSync(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}
|
|
1909
|
-
`, "utf-8");
|
|
1910
|
-
}
|
|
1911
|
-
function ensurePlatformRuntimeRegistration(projectPath) {
|
|
1912
|
-
const workerIndexPath = path7.join(projectPath, "worker", "index.ts");
|
|
1913
|
-
if (!fs3.existsSync(workerIndexPath)) return false;
|
|
1914
|
-
const source = fs3.readFileSync(workerIndexPath, "utf-8");
|
|
1915
|
-
if (source.includes(`from "${PLATFORM_RUNTIME_PACKAGE}"`) || source.includes(`from '${PLATFORM_RUNTIME_PACKAGE}'`)) {
|
|
1916
|
-
return false;
|
|
1917
|
-
}
|
|
1918
|
-
const registration = [
|
|
1919
|
-
`import { ProviderRegistry } from "@standardagents/builder/runtime"`,
|
|
1920
|
-
`import { createProviderFromEnv } from "${PLATFORM_RUNTIME_PACKAGE}"`,
|
|
1921
|
-
"",
|
|
1922
|
-
"ProviderRegistry.setProviderOverride(createProviderFromEnv)",
|
|
1923
|
-
""
|
|
1924
|
-
].join("\n");
|
|
1925
|
-
fs3.writeFileSync(workerIndexPath, `${registration}${source}`, "utf-8");
|
|
1926
|
-
return true;
|
|
1927
|
-
}
|
|
1928
1641
|
function preparePlatformProjectDependencies(projectPath, packageManager) {
|
|
1929
1642
|
if (process.env.STANDARDAGENTS_WORKSPACE !== "1") {
|
|
1930
1643
|
return [];
|
|
@@ -1936,14 +1649,7 @@ function preparePlatformProjectDependencies(projectPath, packageManager) {
|
|
|
1936
1649
|
if (!workspaceRoot) {
|
|
1937
1650
|
throw new Error("STANDARDAGENTS_WORKSPACE=1 was set, but no Standard Agents workspace root was found");
|
|
1938
1651
|
}
|
|
1939
|
-
|
|
1940
|
-
const platformRuntimePackageDir = resolvePlatformRuntimePackageDir();
|
|
1941
|
-
if (platformRuntimePackageDir) {
|
|
1942
|
-
addProjectDependency(projectPath, PLATFORM_RUNTIME_PACKAGE, "workspace:*");
|
|
1943
|
-
ensurePlatformRuntimeRegistration(projectPath);
|
|
1944
|
-
extraPackageDirs[PLATFORM_RUNTIME_PACKAGE] = platformRuntimePackageDir;
|
|
1945
|
-
}
|
|
1946
|
-
return rewriteStandardAgentsDependenciesForWorkspace(projectPath, workspaceRoot, extraPackageDirs);
|
|
1652
|
+
return rewriteStandardAgentsDependenciesForWorkspace(projectPath, workspaceRoot);
|
|
1947
1653
|
}
|
|
1948
1654
|
function shellQuote(value) {
|
|
1949
1655
|
return `"${value.replace(/(["\\$`])/g, "\\$1")}"`;
|
|
@@ -2135,6 +1841,43 @@ function resolvePlatformProjectDirectoryName(project, requestedProjectName) {
|
|
|
2135
1841
|
function resolvePlatformProjectPackageManager(projectPackageManager, requestedPackageManager) {
|
|
2136
1842
|
return resolvePackageManager(projectPackageManager ?? void 0, requestedPackageManager);
|
|
2137
1843
|
}
|
|
1844
|
+
function sanitizeGitRemoteUrl(remoteUrl) {
|
|
1845
|
+
try {
|
|
1846
|
+
const url = new URL(remoteUrl);
|
|
1847
|
+
url.username = "";
|
|
1848
|
+
url.password = "";
|
|
1849
|
+
return url.toString();
|
|
1850
|
+
} catch {
|
|
1851
|
+
return remoteUrl.replace(/\/\/[^/@\s]+@/, "//");
|
|
1852
|
+
}
|
|
1853
|
+
}
|
|
1854
|
+
function cloneDisplayUrl(project) {
|
|
1855
|
+
return project.repo_html_url || sanitizeGitRemoteUrl(project.repo_clone_url);
|
|
1856
|
+
}
|
|
1857
|
+
function gitCloneArgs(project, projectName) {
|
|
1858
|
+
const args = [];
|
|
1859
|
+
if (project.git_extra_header) {
|
|
1860
|
+
args.push("-c", `http.extraHeader=${project.git_extra_header}`);
|
|
1861
|
+
}
|
|
1862
|
+
args.push("clone", project.repo_clone_url, projectName);
|
|
1863
|
+
return args;
|
|
1864
|
+
}
|
|
1865
|
+
function platformGitCredentialHelperCommand(cliEntry = process.argv[1] ?? "") {
|
|
1866
|
+
if (process.env.STANDARDAGENTS_WORKSPACE === "1" && cliEntry && fs3.existsSync(cliEntry)) {
|
|
1867
|
+
return `!node ${shellQuote(path7.resolve(cliEntry))} git-credential`;
|
|
1868
|
+
}
|
|
1869
|
+
if (process.env.STANDARD_AGENTS_GIT_HELPER?.trim()) {
|
|
1870
|
+
return process.env.STANDARD_AGENTS_GIT_HELPER.trim();
|
|
1871
|
+
}
|
|
1872
|
+
const cliVersion = getCliVersion();
|
|
1873
|
+
{
|
|
1874
|
+
return `!npx -y @standardagents/cli@${cliVersion} git-credential`;
|
|
1875
|
+
}
|
|
1876
|
+
}
|
|
1877
|
+
async function configurePlatformGitCredentialHelper(projectPath) {
|
|
1878
|
+
await runCommand("git", ["config", "credential.helper", platformGitCredentialHelperCommand()], projectPath);
|
|
1879
|
+
await runCommand("git", ["config", "credential.useHttpPath", "true"], projectPath);
|
|
1880
|
+
}
|
|
2138
1881
|
function isRetryablePlatformAuthStatus(status) {
|
|
2139
1882
|
return status === 502 || status === 503 || status === 504;
|
|
2140
1883
|
}
|
|
@@ -2230,6 +1973,71 @@ function upsertEnvLine(lines, key, value) {
|
|
|
2230
1973
|
function hasEnvLine(lines, key) {
|
|
2231
1974
|
return lines.some((line) => line.startsWith(`${key}=`));
|
|
2232
1975
|
}
|
|
1976
|
+
function appendGitignoreEntries(projectPath, heading, entries) {
|
|
1977
|
+
const gitignorePath = path7.join(projectPath, ".gitignore");
|
|
1978
|
+
const gitignoreContent = fs3.existsSync(gitignorePath) ? fs3.readFileSync(gitignorePath, "utf-8") : "";
|
|
1979
|
+
const existingEntries = new Set(gitignoreContent.split(/\r?\n/));
|
|
1980
|
+
const missingEntries = entries.filter((entry) => !existingEntries.has(entry));
|
|
1981
|
+
if (missingEntries.length === 0) return;
|
|
1982
|
+
const prefix = gitignoreContent.length === 0 ? "" : gitignoreContent.endsWith("\n") ? "\n" : "\n\n";
|
|
1983
|
+
fs3.appendFileSync(gitignorePath, `${prefix}${heading}
|
|
1984
|
+
${missingEntries.join("\n")}
|
|
1985
|
+
`);
|
|
1986
|
+
}
|
|
1987
|
+
function writeStandardAgentsSupportFiles(projectPath, params) {
|
|
1988
|
+
const written = [];
|
|
1989
|
+
for (const supportFile of renderAgentBuilderSupportFiles({
|
|
1990
|
+
projectName: params.projectName,
|
|
1991
|
+
packageManager: params.packageManager,
|
|
1992
|
+
versions: {
|
|
1993
|
+
standardAgents: getCliVersion(),
|
|
1994
|
+
sip: getSipVersion()
|
|
1995
|
+
}
|
|
1996
|
+
})) {
|
|
1997
|
+
const targetPath = path7.join(projectPath, supportFile.path);
|
|
1998
|
+
if (fs3.existsSync(targetPath)) continue;
|
|
1999
|
+
fs3.mkdirSync(path7.dirname(targetPath), { recursive: true });
|
|
2000
|
+
fs3.writeFileSync(targetPath, supportFile.content, "utf-8");
|
|
2001
|
+
written.push(supportFile.path);
|
|
2002
|
+
}
|
|
2003
|
+
if (written.includes("package.json")) {
|
|
2004
|
+
appendGitignoreEntries(projectPath, "# Standard Agents generated local support files", [
|
|
2005
|
+
"package.json",
|
|
2006
|
+
"package-lock.json",
|
|
2007
|
+
"pnpm-lock.yaml",
|
|
2008
|
+
"yarn.lock",
|
|
2009
|
+
"bun.lock",
|
|
2010
|
+
"bun.lockb",
|
|
2011
|
+
"node_modules"
|
|
2012
|
+
]);
|
|
2013
|
+
}
|
|
2014
|
+
appendGitignoreEntries(projectPath, "# Standard Agents local dev state", [
|
|
2015
|
+
".agents",
|
|
2016
|
+
".wrangler",
|
|
2017
|
+
"dist"
|
|
2018
|
+
]);
|
|
2019
|
+
return written;
|
|
2020
|
+
}
|
|
2021
|
+
function supportFiles(options = {}) {
|
|
2022
|
+
let packageManager;
|
|
2023
|
+
try {
|
|
2024
|
+
packageManager = resolvePackageManager(options.packageManager, detectPackageManager());
|
|
2025
|
+
} catch (error) {
|
|
2026
|
+
logger.error(error instanceof Error ? error.message : String(error));
|
|
2027
|
+
process.exit(1);
|
|
2028
|
+
}
|
|
2029
|
+
const cwd = process.cwd();
|
|
2030
|
+
const projectName = normalizeProjectName(options.projectName ?? path7.basename(cwd)) || "standard-agents";
|
|
2031
|
+
const written = writeStandardAgentsSupportFiles(cwd, {
|
|
2032
|
+
projectName,
|
|
2033
|
+
packageManager
|
|
2034
|
+
});
|
|
2035
|
+
if (written.length === 0) {
|
|
2036
|
+
logger.info("Standard Agents local support files already exist");
|
|
2037
|
+
return;
|
|
2038
|
+
}
|
|
2039
|
+
logger.success(`Wrote Standard Agents local support files: ${written.join(", ")}`);
|
|
2040
|
+
}
|
|
2233
2041
|
function writeStandardAgentsEnv(projectPath, params) {
|
|
2234
2042
|
const envPath = path7.join(projectPath, ".dev.vars");
|
|
2235
2043
|
const existing = fs3.existsSync(envPath) ? fs3.readFileSync(envPath, "utf-8") : "";
|
|
@@ -2258,21 +2066,42 @@ function writeStandardAgentsEnv(projectPath, params) {
|
|
|
2258
2066
|
lines = upsertEnvLine(lines, "PLATFORM_ENDPOINT", params.platformEndpoint);
|
|
2259
2067
|
lines = upsertEnvLine(lines, "STANDARD_AGENTS_API_URL", params.platformEndpoint);
|
|
2260
2068
|
fs3.writeFileSync(envPath, lines.join("\n").replace(/\n{3,}/g, "\n\n").trim() + "\n", "utf-8");
|
|
2261
|
-
|
|
2262
|
-
const gitignoreContent = fs3.existsSync(gitignorePath) ? fs3.readFileSync(gitignorePath, "utf-8") : "";
|
|
2263
|
-
if (!gitignoreContent.split(/\r?\n/).includes(".dev.vars")) {
|
|
2264
|
-
const prefix = gitignoreContent.length === 0 ? "" : gitignoreContent.endsWith("\n") ? "\n" : "\n\n";
|
|
2265
|
-
fs3.appendFileSync(gitignorePath, `${prefix}# Standard Agents local platform token
|
|
2266
|
-
.dev.vars
|
|
2267
|
-
`);
|
|
2268
|
-
}
|
|
2069
|
+
appendGitignoreEntries(projectPath, "# Standard Agents local platform token", [".dev.vars"]);
|
|
2269
2070
|
return envPath;
|
|
2270
2071
|
}
|
|
2072
|
+
async function resolveBootstrapProject(endpoint, code, fetchImpl = fetch) {
|
|
2073
|
+
const consumed = await exchangeBootstrapCode(endpoint, code, fetchImpl);
|
|
2074
|
+
const cookie = consumed.session_cookie;
|
|
2075
|
+
const listResponse = await fetchImpl(`${endpoint}/projects`, {
|
|
2076
|
+
headers: { Accept: "application/json", Cookie: cookie }
|
|
2077
|
+
});
|
|
2078
|
+
if (!listResponse.ok) {
|
|
2079
|
+
throw new Error(`Could not load your Standard Agents instance (${listResponse.status}).`);
|
|
2080
|
+
}
|
|
2081
|
+
const listBody = await listResponse.json().catch(() => ({}));
|
|
2082
|
+
const projectId = listBody.projects?.find(
|
|
2083
|
+
(entry) => typeof entry?.id === "string"
|
|
2084
|
+
)?.id;
|
|
2085
|
+
if (!projectId) {
|
|
2086
|
+
throw new Error("No Standard Agents instance found for this account. Create one in the dashboard first.");
|
|
2087
|
+
}
|
|
2088
|
+
const handoffResponse = await fetchImpl(`${endpoint}/projects/${projectId}/cli-handoff`, {
|
|
2089
|
+
method: "POST",
|
|
2090
|
+
headers: { Accept: "application/json", "Content-Type": "application/json", Cookie: cookie },
|
|
2091
|
+
body: "{}"
|
|
2092
|
+
});
|
|
2093
|
+
if (!handoffResponse.ok) {
|
|
2094
|
+
const text = await handoffResponse.text().catch(() => "");
|
|
2095
|
+
throw new Error(`Could not prepare your instance for local setup (${handoffResponse.status})${text ? `: ${text}` : ""}`);
|
|
2096
|
+
}
|
|
2097
|
+
const handoffBody = await handoffResponse.json().catch(() => ({}));
|
|
2098
|
+
if (!handoffBody.project?.repo_clone_url || !handoffBody.project.api_key) {
|
|
2099
|
+
throw new Error("Instance handoff response was missing clone details.");
|
|
2100
|
+
}
|
|
2101
|
+
return handoffBody.project;
|
|
2102
|
+
}
|
|
2271
2103
|
async function runPlatformInit(projectNameArg, options) {
|
|
2272
2104
|
const cwd = process.cwd();
|
|
2273
|
-
if (options.bootstrap) {
|
|
2274
|
-
logger.warning("Legacy bootstrap codes now continue through browser onboarding.");
|
|
2275
|
-
}
|
|
2276
2105
|
let pm;
|
|
2277
2106
|
try {
|
|
2278
2107
|
pm = resolvePackageManager(options.packageManager, detectPackageManager());
|
|
@@ -2286,23 +2115,34 @@ async function runPlatformInit(projectNameArg, options) {
|
|
|
2286
2115
|
process.exit(1);
|
|
2287
2116
|
}
|
|
2288
2117
|
const endpoint = normalizeApiUrl(options.apiUrl || options.endpoint);
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
endpoint,
|
|
2294
|
-
|
|
2295
|
-
|
|
2118
|
+
let project;
|
|
2119
|
+
if (options.bootstrap?.trim()) {
|
|
2120
|
+
logger.info("Connecting to your Standard Agents instance...");
|
|
2121
|
+
try {
|
|
2122
|
+
project = await resolveBootstrapProject(endpoint, options.bootstrap.trim());
|
|
2123
|
+
} catch (error) {
|
|
2124
|
+
logger.error(error instanceof Error ? error.message : String(error));
|
|
2125
|
+
process.exit(1);
|
|
2126
|
+
}
|
|
2127
|
+
} else {
|
|
2128
|
+
logger.info("Opening Standard Agents platform signup/login...");
|
|
2129
|
+
let session;
|
|
2130
|
+
try {
|
|
2131
|
+
session = await startPlatformCliSession({
|
|
2132
|
+
endpoint,
|
|
2133
|
+
projectName: requestedProjectName,
|
|
2134
|
+
packageManager: pm
|
|
2135
|
+
});
|
|
2136
|
+
} catch (error) {
|
|
2137
|
+
logger.error(error instanceof Error ? error.message : String(error));
|
|
2138
|
+
process.exit(1);
|
|
2139
|
+
}
|
|
2140
|
+
openUrl(session.auth_url);
|
|
2141
|
+
logger.info("Finish the browser steps. I will stay here and continue automatically.");
|
|
2142
|
+
project = await waitForPlatformProject(session, (progress) => {
|
|
2143
|
+
logger.info(progress.message);
|
|
2296
2144
|
});
|
|
2297
|
-
} catch (error) {
|
|
2298
|
-
logger.error(error instanceof Error ? error.message : String(error));
|
|
2299
|
-
process.exit(1);
|
|
2300
2145
|
}
|
|
2301
|
-
openUrl(session.auth_url);
|
|
2302
|
-
logger.info("Finish the browser steps. I will stay here and continue automatically.");
|
|
2303
|
-
const project = await waitForPlatformProject(session, (progress) => {
|
|
2304
|
-
logger.info(progress.message);
|
|
2305
|
-
});
|
|
2306
2146
|
const projectName = resolvePlatformProjectDirectoryName(project, requestedProjectName);
|
|
2307
2147
|
const projectPackageManager = resolvePlatformProjectPackageManager(project.package_manager, pm);
|
|
2308
2148
|
const projectPath = path7.join(cwd, projectName);
|
|
@@ -2311,28 +2151,77 @@ async function runPlatformInit(projectNameArg, options) {
|
|
|
2311
2151
|
process.exit(1);
|
|
2312
2152
|
}
|
|
2313
2153
|
logger.success("Browser setup complete.");
|
|
2314
|
-
logger.info(`Cloning ${project
|
|
2315
|
-
await runCommand("git",
|
|
2154
|
+
logger.info(`Cloning ${cloneDisplayUrl(project)}...`);
|
|
2155
|
+
await runCommand("git", gitCloneArgs(project, projectName), cwd);
|
|
2156
|
+
if (project.git_extra_header && project.repo_html_url) {
|
|
2157
|
+
await runCommand("git", ["remote", "set-url", "origin", project.repo_html_url], projectPath);
|
|
2158
|
+
}
|
|
2159
|
+
const supportFiles2 = writeStandardAgentsSupportFiles(projectPath, {
|
|
2160
|
+
projectName: project.name || projectName,
|
|
2161
|
+
packageManager: projectPackageManager
|
|
2162
|
+
});
|
|
2163
|
+
if (supportFiles2.length > 0) {
|
|
2164
|
+
logger.success(`Wrote generated local support files: ${supportFiles2.join(", ")}.`);
|
|
2165
|
+
}
|
|
2316
2166
|
const envPath = writeStandardAgentsEnv(projectPath, {
|
|
2317
2167
|
apiKey: project.api_key,
|
|
2318
2168
|
platformEndpoint: endpoint
|
|
2319
2169
|
});
|
|
2320
2170
|
logger.success(`Wrote Standard Agents credentials to ${path7.relative(cwd, envPath)}.`);
|
|
2171
|
+
if (project.git_extra_header) {
|
|
2172
|
+
await configurePlatformGitCredentialHelper(projectPath);
|
|
2173
|
+
logger.success("Configured git credentials for the platform repository.");
|
|
2174
|
+
}
|
|
2321
2175
|
const linkedPackages = preparePlatformProjectDependencies(projectPath, projectPackageManager);
|
|
2322
2176
|
if (linkedPackages.length > 0) {
|
|
2323
2177
|
logger.info(`Workspace mode detected: linked ${linkedPackages.length} Standard Agents packages locally.`);
|
|
2324
2178
|
}
|
|
2325
2179
|
logger.info(`Installing dependencies with ${projectPackageManager}...`);
|
|
2326
2180
|
await runCommand(projectPackageManager, ["install"], projectPath);
|
|
2181
|
+
const repoUrl = project.repo_html_url ?? project.repo_clone_url;
|
|
2182
|
+
const tokenLocation = path7.relative(cwd, envPath);
|
|
2183
|
+
if (options.dev === false) {
|
|
2184
|
+
logger.success("Your Standard Agents instance is ready.");
|
|
2185
|
+
logger.log(`Repository: ${repoUrl}`);
|
|
2186
|
+
logger.log(`Local token: ${tokenLocation}`);
|
|
2187
|
+
logger.log("");
|
|
2188
|
+
logger.log("Start it whenever you like:");
|
|
2189
|
+
logger.log(` cd ${projectName}`);
|
|
2190
|
+
logger.log(` ${devCommandHint(projectPackageManager)}`);
|
|
2191
|
+
return;
|
|
2192
|
+
}
|
|
2327
2193
|
const devPort = await findAvailablePort(5173);
|
|
2328
2194
|
const devUrl = `http://127.0.0.1:${devPort}`;
|
|
2329
2195
|
logger.info(`Starting local dev server at ${devUrl}...`);
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2196
|
+
const { logPath } = startDetachedDevServer(
|
|
2197
|
+
projectPackageManager,
|
|
2198
|
+
buildDevServerCommand(projectPackageManager, devPort),
|
|
2199
|
+
projectPath
|
|
2200
|
+
);
|
|
2201
|
+
const ready = await waitForLocalDevServer(devUrl);
|
|
2202
|
+
if (ready) {
|
|
2203
|
+
openUrl(devUrl);
|
|
2204
|
+
logger.success("Project is connected to Standard Agents.");
|
|
2205
|
+
logger.log(`Repository: ${repoUrl}`);
|
|
2206
|
+
logger.log(`Dev server: ${devUrl}`);
|
|
2207
|
+
logger.log(`Local token: ${tokenLocation}`);
|
|
2208
|
+
return;
|
|
2209
|
+
}
|
|
2210
|
+
logger.warning(`The dev server didn't respond at ${devUrl} within 60s.`);
|
|
2211
|
+
const tail = readLogTail(logPath);
|
|
2212
|
+
if (tail) {
|
|
2213
|
+
logger.log("");
|
|
2214
|
+
logger.log(`Last dev server output (full log: ${path7.relative(cwd, logPath)}):`);
|
|
2215
|
+
logger.log(tail);
|
|
2216
|
+
}
|
|
2217
|
+
logger.log("");
|
|
2218
|
+
logger.success("Your Standard Agents instance is cloned, configured, and ready.");
|
|
2219
|
+
logger.log(`Repository: ${repoUrl}`);
|
|
2220
|
+
logger.log(`Local token: ${tokenLocation}`);
|
|
2221
|
+
logger.log("");
|
|
2222
|
+
logger.log("Once any error above is resolved, start it with:");
|
|
2223
|
+
logger.log(` cd ${projectName}`);
|
|
2224
|
+
logger.log(` ${devCommandHint(projectPackageManager)}`);
|
|
2336
2225
|
}
|
|
2337
2226
|
async function init(projectNameArg, options = {}) {
|
|
2338
2227
|
if (!options.local) {
|
|
@@ -2625,17 +2514,10 @@ export default defineConfig({
|
|
|
2625
2514
|
}
|
|
2626
2515
|
try {
|
|
2627
2516
|
const installCmd = pm === "npm" ? "install" : "add";
|
|
2628
|
-
const devFlag = pm === "npm" ? "--save-dev" : "-D";
|
|
2629
2517
|
if (packageSpecifier === "workspace:*") {
|
|
2630
2518
|
logInfo("Using local workspace @standardagents/* packages (workspace:*).");
|
|
2631
2519
|
}
|
|
2632
2520
|
await withTuiSpinner(initTuiMode, "Installing dependencies...", async () => {
|
|
2633
|
-
await runCommand(pm, [
|
|
2634
|
-
installCmd,
|
|
2635
|
-
devFlag,
|
|
2636
|
-
"@cloudflare/vite-plugin",
|
|
2637
|
-
"wrangler"
|
|
2638
|
-
], projectPath, { quiet: initTuiMode });
|
|
2639
2521
|
const standardAgentsPackage = (packageName) => `${packageName}@${resolveStandardAgentsPackageSpecifier(packageName, packageSpecifier)}`;
|
|
2640
2522
|
const deps = [
|
|
2641
2523
|
standardAgentsPackage("@standardagents/builder"),
|
|
@@ -2752,14 +2634,6 @@ export default defineConfig({
|
|
|
2752
2634
|
logSuccess("Added .dev.vars to .gitignore");
|
|
2753
2635
|
}
|
|
2754
2636
|
}
|
|
2755
|
-
logInfo("Refreshing wrangler type bindings...");
|
|
2756
|
-
try {
|
|
2757
|
-
await withTuiSpinner(initTuiMode, "Generating wrangler types...", async () => {
|
|
2758
|
-
await runCommand("npx", ["wrangler", "types"], projectPath, { quiet: initTuiMode });
|
|
2759
|
-
});
|
|
2760
|
-
} catch (error) {
|
|
2761
|
-
logWarning('Could not generate types automatically. Run "npx wrangler types" manually.');
|
|
2762
|
-
}
|
|
2763
2637
|
const nextRunCommand = resolvePostInitRunCommand(pm, projectPath, packageSpecifier === "workspace:*");
|
|
2764
2638
|
if (initTuiMode) {
|
|
2765
2639
|
clearTerminalScreen();
|
|
@@ -2856,8 +2730,19 @@ async function loginWithBootstrap(projectPath, options, fetchImpl = fetch) {
|
|
|
2856
2730
|
}
|
|
2857
2731
|
throw new Error("Bootstrap code required. Run: npx @standardagents/cli login --bootstrap <code>");
|
|
2858
2732
|
}
|
|
2733
|
+
const state = await consumeBootstrapLogin({ ...options, endpoint, bootstrap: bootstrapCode }, fetchImpl);
|
|
2734
|
+
persistBootstrapState(projectPath, state);
|
|
2735
|
+
syncProjectAuthEnv(projectPath, endpoint, state);
|
|
2736
|
+
return { state, reused: false };
|
|
2737
|
+
}
|
|
2738
|
+
async function consumeBootstrapLogin(options, fetchImpl = fetch) {
|
|
2739
|
+
const endpoint = resolvePlatformEndpoint({ endpoint: options.endpoint });
|
|
2740
|
+
const bootstrapCode = options.bootstrap?.trim();
|
|
2741
|
+
if (!bootstrapCode) {
|
|
2742
|
+
throw new Error("Bootstrap code required. Run: npx @standardagents/cli login --bootstrap <code>");
|
|
2743
|
+
}
|
|
2859
2744
|
const consumed = await exchangeBootstrapCode(endpoint, bootstrapCode, fetchImpl);
|
|
2860
|
-
|
|
2745
|
+
return {
|
|
2861
2746
|
version: 1,
|
|
2862
2747
|
endpoint,
|
|
2863
2748
|
authenticated_at: Date.now(),
|
|
@@ -2865,9 +2750,6 @@ async function loginWithBootstrap(projectPath, options, fetchImpl = fetch) {
|
|
|
2865
2750
|
user: consumed.user,
|
|
2866
2751
|
account: consumed.account
|
|
2867
2752
|
};
|
|
2868
|
-
persistBootstrapState(projectPath, state);
|
|
2869
|
-
syncProjectAuthEnv(projectPath, endpoint, state);
|
|
2870
|
-
return { state, reused: false };
|
|
2871
2753
|
}
|
|
2872
2754
|
async function loginWithPlatform(options) {
|
|
2873
2755
|
const endpoint = resolvePlatformEndpoint({ endpoint: options.endpoint });
|
|
@@ -3050,12 +2932,31 @@ function readCliAuthState() {
|
|
|
3050
2932
|
const parsed = JSON.parse(fs3.readFileSync(file, "utf8"));
|
|
3051
2933
|
return {
|
|
3052
2934
|
active_org_id: parsed.active_org_id ?? null,
|
|
3053
|
-
orgs: parsed.orgs ?? {}
|
|
2935
|
+
orgs: parsed.orgs ?? {},
|
|
2936
|
+
git_auth: parseCliGitAuthRecord(parsed.git_auth)
|
|
3054
2937
|
};
|
|
3055
2938
|
} catch {
|
|
3056
2939
|
return { active_org_id: null, orgs: {} };
|
|
3057
2940
|
}
|
|
3058
2941
|
}
|
|
2942
|
+
function parseCliGitAuthRecord(value) {
|
|
2943
|
+
if (!value || typeof value !== "object") return null;
|
|
2944
|
+
const candidate = value;
|
|
2945
|
+
if (candidate.version !== 1) return null;
|
|
2946
|
+
if (typeof candidate.endpoint !== "string" || typeof candidate.session_cookie !== "string" || typeof candidate.account_id !== "string" || typeof candidate.user_id !== "string" || typeof candidate.user_email !== "string" || typeof candidate.updated_at !== "number") {
|
|
2947
|
+
return null;
|
|
2948
|
+
}
|
|
2949
|
+
return {
|
|
2950
|
+
version: 1,
|
|
2951
|
+
endpoint: candidate.endpoint,
|
|
2952
|
+
session_cookie: candidate.session_cookie,
|
|
2953
|
+
account_id: candidate.account_id,
|
|
2954
|
+
account_slug: typeof candidate.account_slug === "string" ? candidate.account_slug : void 0,
|
|
2955
|
+
user_id: candidate.user_id,
|
|
2956
|
+
user_email: candidate.user_email,
|
|
2957
|
+
updated_at: candidate.updated_at
|
|
2958
|
+
};
|
|
2959
|
+
}
|
|
3059
2960
|
function writeCliAuthState(state) {
|
|
3060
2961
|
ensureStateDir();
|
|
3061
2962
|
fs3.writeFileSync(stateFilePath(), JSON.stringify(state, null, 2) + "\n", "utf8");
|
|
@@ -3064,6 +2965,25 @@ function hasStoredCliAuth() {
|
|
|
3064
2965
|
const state = readCliAuthState();
|
|
3065
2966
|
return Object.keys(state.orgs).length > 0;
|
|
3066
2967
|
}
|
|
2968
|
+
function saveCliGitAuth(input) {
|
|
2969
|
+
const state = readCliAuthState();
|
|
2970
|
+
const record = {
|
|
2971
|
+
version: 1,
|
|
2972
|
+
endpoint: input.endpoint.replace(/\/+$/, ""),
|
|
2973
|
+
session_cookie: input.sessionCookie,
|
|
2974
|
+
account_id: input.account.id,
|
|
2975
|
+
account_slug: input.account.slug,
|
|
2976
|
+
user_id: input.user.id,
|
|
2977
|
+
user_email: input.user.email,
|
|
2978
|
+
updated_at: Date.now()
|
|
2979
|
+
};
|
|
2980
|
+
state.git_auth = record;
|
|
2981
|
+
writeCliAuthState(state);
|
|
2982
|
+
return record;
|
|
2983
|
+
}
|
|
2984
|
+
function resolveCliGitAuth() {
|
|
2985
|
+
return readCliAuthState().git_auth ?? null;
|
|
2986
|
+
}
|
|
3067
2987
|
function resolveTargetOrgId(state, orgInput) {
|
|
3068
2988
|
if (orgInput) {
|
|
3069
2989
|
const trimmed = orgInput.trim();
|
|
@@ -3948,14 +3868,14 @@ async function pack(agentName, options) {
|
|
|
3948
3868
|
sharedWith: agent.sharedWith
|
|
3949
3869
|
});
|
|
3950
3870
|
}
|
|
3951
|
-
for (const
|
|
3871
|
+
for (const prompt5 of analysis.constituents.prompts) {
|
|
3952
3872
|
selectionItems.push({
|
|
3953
|
-
name:
|
|
3873
|
+
name: prompt5.name,
|
|
3954
3874
|
type: "prompt",
|
|
3955
|
-
filePath:
|
|
3956
|
-
mode:
|
|
3957
|
-
isShared:
|
|
3958
|
-
sharedWith:
|
|
3875
|
+
filePath: prompt5.filePath,
|
|
3876
|
+
mode: prompt5.sharedWith.length > 0 ? "copy" : "extract",
|
|
3877
|
+
isShared: prompt5.sharedWith.length > 0,
|
|
3878
|
+
sharedWith: prompt5.sharedWith
|
|
3959
3879
|
});
|
|
3960
3880
|
}
|
|
3961
3881
|
for (const tool of analysis.constituents.tools) {
|
|
@@ -4163,349 +4083,74 @@ async function listPacked() {
|
|
|
4163
4083
|
console.log("");
|
|
4164
4084
|
}
|
|
4165
4085
|
}
|
|
4166
|
-
var
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
4173
|
-
const eqIndex = trimmed.indexOf("=");
|
|
4174
|
-
if (eqIndex === -1) continue;
|
|
4175
|
-
const key = trimmed.slice(0, eqIndex).trim();
|
|
4176
|
-
let value = trimmed.slice(eqIndex + 1).trim();
|
|
4177
|
-
if (value.startsWith('"') && value.endsWith('"')) {
|
|
4178
|
-
value = value.slice(1, -1).replace(/\\"/g, '"');
|
|
4179
|
-
} else if (value.startsWith("'") && value.endsWith("'")) {
|
|
4180
|
-
value = value.slice(1, -1);
|
|
4181
|
-
}
|
|
4182
|
-
result[key] = value;
|
|
4183
|
-
}
|
|
4184
|
-
return result;
|
|
4185
|
-
}
|
|
4186
|
-
function compareVersions(a, b) {
|
|
4187
|
-
const [coreA, preA] = a.replace(/^v/, "").split("-", 2);
|
|
4188
|
-
const [coreB, preB] = b.replace(/^v/, "").split("-", 2);
|
|
4189
|
-
const partsA = coreA.split(".").map(Number);
|
|
4190
|
-
const partsB = coreB.split(".").map(Number);
|
|
4191
|
-
for (let i = 0; i < 3; i++) {
|
|
4192
|
-
const va = partsA[i] ?? 0;
|
|
4193
|
-
const vb = partsB[i] ?? 0;
|
|
4194
|
-
if (va < vb) return -1;
|
|
4195
|
-
if (va > vb) return 1;
|
|
4196
|
-
}
|
|
4197
|
-
if (preA && !preB) return -1;
|
|
4198
|
-
if (!preA && preB) return 1;
|
|
4199
|
-
return 0;
|
|
4200
|
-
}
|
|
4201
|
-
function validateBundleSize(sizeBytes) {
|
|
4202
|
-
if (sizeBytes > FREE_TIER_BUNDLE_LIMIT) {
|
|
4203
|
-
return `Bundle size (${formatBytes(sizeBytes)}) exceeds the free tier limit (${formatBytes(FREE_TIER_BUNDLE_LIMIT)}). A paid plan may be required.`;
|
|
4204
|
-
}
|
|
4205
|
-
return null;
|
|
4206
|
-
}
|
|
4207
|
-
function createManifest(agents, builderVersion) {
|
|
4208
|
-
return {
|
|
4209
|
-
agents,
|
|
4210
|
-
builder_version: builderVersion
|
|
4211
|
-
};
|
|
4212
|
-
}
|
|
4213
|
-
function formatBytes(bytes) {
|
|
4214
|
-
if (bytes < 1024) return `${bytes} B`;
|
|
4215
|
-
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
4216
|
-
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
4217
|
-
}
|
|
4218
|
-
function formatDeployError(response) {
|
|
4219
|
-
if (response.error) {
|
|
4220
|
-
return `${response.error.code}: ${response.error.message}`;
|
|
4221
|
-
}
|
|
4222
|
-
if (response.errors && response.errors.length > 0) {
|
|
4223
|
-
return response.errors.join("\n");
|
|
4086
|
+
var ARTIFACT_DEPLOY_REMOTE_NAME = "origin";
|
|
4087
|
+
function normalizeGitRemoteHost(remote) {
|
|
4088
|
+
try {
|
|
4089
|
+
return new URL(remote).hostname.toLowerCase();
|
|
4090
|
+
} catch {
|
|
4091
|
+
return null;
|
|
4224
4092
|
}
|
|
4225
|
-
return "Unknown error";
|
|
4226
|
-
}
|
|
4227
|
-
function detectProject() {
|
|
4228
|
-
const hasWranglerJsonc = fs3.existsSync("wrangler.jsonc") || fs3.existsSync("wrangler.json");
|
|
4229
|
-
const hasAgentsDir = fs3.existsSync("agents/agents");
|
|
4230
|
-
return hasWranglerJsonc || hasAgentsDir;
|
|
4231
4093
|
}
|
|
4232
|
-
function
|
|
4233
|
-
const
|
|
4234
|
-
if (!
|
|
4235
|
-
return
|
|
4094
|
+
function isStandardAgentsArtifactRemote(remote) {
|
|
4095
|
+
const host = normalizeGitRemoteHost(remote);
|
|
4096
|
+
if (!host) return false;
|
|
4097
|
+
return host === "standardagents.ai" || host.endsWith(".standardagents.ai") || host === "standardagentbuilder.com" || host.endsWith(".standardagentbuilder.com") || host === "artifacts.cloudflare.net" || host.endsWith(".artifacts.cloudflare.net") || host === "artifacts.cloudflare.com" || host.endsWith(".artifacts.cloudflare.com") || host === "git.cloudflare.com";
|
|
4236
4098
|
}
|
|
4237
|
-
function
|
|
4238
|
-
return
|
|
4099
|
+
function gitOutput(args) {
|
|
4100
|
+
return execFileSync("git", args, {
|
|
4101
|
+
encoding: "utf-8",
|
|
4102
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
4103
|
+
}).trim();
|
|
4239
4104
|
}
|
|
4240
|
-
function
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
}
|
|
4244
|
-
return { Authorization: `Bearer ${auth.apiKey}` };
|
|
4245
|
-
}
|
|
4246
|
-
function resolveDeployAuth(options, projectPath = process.cwd()) {
|
|
4247
|
-
const envFileVars = loadEnvFileVars(projectPath);
|
|
4248
|
-
const endpoint = resolveEndpoint(options, envFileVars);
|
|
4249
|
-
if (options.apiKey?.trim()) {
|
|
4250
|
-
return { endpoint, auth: { kind: "api-key", apiKey: options.apiKey.trim() } };
|
|
4251
|
-
}
|
|
4252
|
-
const bootstrap = loadBootstrapState(projectPath);
|
|
4253
|
-
if (bootstrap?.endpoint === endpoint && bootstrap.session_cookie) {
|
|
4254
|
-
return {
|
|
4255
|
-
endpoint,
|
|
4256
|
-
auth: {
|
|
4257
|
-
kind: "session-cookie",
|
|
4258
|
-
cookie: bootstrap.session_cookie
|
|
4259
|
-
}
|
|
4260
|
-
};
|
|
4261
|
-
}
|
|
4262
|
-
const apiKey = process.env.PLATFORM_API_KEY || envFileVars.PLATFORM_API_KEY;
|
|
4263
|
-
if (apiKey) {
|
|
4264
|
-
return { endpoint, auth: { kind: "api-key", apiKey } };
|
|
4265
|
-
}
|
|
4266
|
-
if (bootstrap?.endpoint === endpoint && !bootstrap.session_cookie) {
|
|
4105
|
+
function resolveArtifactGitDeployTarget(runner = gitOutput, remoteName = ARTIFACT_DEPLOY_REMOTE_NAME) {
|
|
4106
|
+
const remoteUrl = runner(["remote", "get-url", remoteName]).trim();
|
|
4107
|
+
if (!isStandardAgentsArtifactRemote(remoteUrl)) {
|
|
4267
4108
|
throw new Error(
|
|
4268
|
-
"
|
|
4109
|
+
`Remote "${remoteName}" is not a Standard Agents Artifacts remote. Deployments now run from pushes to platform-owned repositories.`
|
|
4269
4110
|
);
|
|
4270
4111
|
}
|
|
4271
|
-
|
|
4272
|
-
|
|
4273
|
-
|
|
4274
|
-
}
|
|
4275
|
-
function discoverAgents() {
|
|
4276
|
-
const agentsDir = "agents/agents";
|
|
4277
|
-
if (!fs3.existsSync(agentsDir)) return [];
|
|
4278
|
-
const scriptExtensions = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mts", ".mjs"]);
|
|
4279
|
-
const files = fs3.readdirSync(agentsDir).filter((f) => scriptExtensions.has(path7.extname(f)));
|
|
4280
|
-
return files.map((file) => {
|
|
4281
|
-
const filePath = path7.join(agentsDir, file);
|
|
4282
|
-
const realPath = fs3.realpathSync(filePath);
|
|
4283
|
-
if (!realPath.startsWith(fs3.realpathSync("."))) {
|
|
4284
|
-
return path7.basename(file, path7.extname(file));
|
|
4285
|
-
}
|
|
4286
|
-
const content = fs3.readFileSync(filePath, "utf-8");
|
|
4287
|
-
const nameMatch = content.match(/defineAgent\s*\(\s*\{[\s\S]*?\bname\s*:\s*['"]([^'"]+)['"]/);
|
|
4288
|
-
return nameMatch ? nameMatch[1] : path7.basename(file, path7.extname(file));
|
|
4289
|
-
});
|
|
4290
|
-
}
|
|
4291
|
-
function getBuilderVersion() {
|
|
4292
|
-
const searchPaths = [
|
|
4293
|
-
"node_modules/@standardagents/builder/package.json",
|
|
4294
|
-
"../node_modules/@standardagents/builder/package.json"
|
|
4295
|
-
];
|
|
4296
|
-
for (const p of searchPaths) {
|
|
4297
|
-
if (fs3.existsSync(p)) {
|
|
4298
|
-
const pkg = JSON.parse(fs3.readFileSync(p, "utf-8"));
|
|
4299
|
-
return pkg.version;
|
|
4300
|
-
}
|
|
4301
|
-
}
|
|
4302
|
-
throw new Error("Could not find @standardagents/builder. Is it installed?");
|
|
4303
|
-
}
|
|
4304
|
-
function detectPackageManager3() {
|
|
4305
|
-
const userAgent = process.env.npm_config_user_agent;
|
|
4306
|
-
if (userAgent) {
|
|
4307
|
-
if (userAgent.includes("pnpm")) return "pnpm";
|
|
4308
|
-
if (userAgent.includes("yarn")) return "yarn";
|
|
4309
|
-
if (userAgent.includes("bun")) return "bun";
|
|
4310
|
-
}
|
|
4311
|
-
if (fs3.existsSync("pnpm-lock.yaml")) return "pnpm";
|
|
4312
|
-
if (fs3.existsSync("yarn.lock")) return "yarn";
|
|
4313
|
-
if (fs3.existsSync("bun.lockb") || fs3.existsSync("bun.lock")) return "bun";
|
|
4314
|
-
return "npm";
|
|
4315
|
-
}
|
|
4316
|
-
function buildProject(endpoint) {
|
|
4317
|
-
const pm = detectPackageManager3();
|
|
4318
|
-
const buildCmd = pm === "npm" ? "npx vite build" : `${pm} exec vite build`;
|
|
4319
|
-
execSync(buildCmd, {
|
|
4320
|
-
stdio: "inherit",
|
|
4321
|
-
env: {
|
|
4322
|
-
...process.env,
|
|
4323
|
-
STANDARD_AGENTS_API_URL: endpoint,
|
|
4324
|
-
PLATFORM_ENDPOINT: endpoint
|
|
4325
|
-
}
|
|
4326
|
-
});
|
|
4327
|
-
}
|
|
4328
|
-
function findWorkerBundle() {
|
|
4329
|
-
const searchDirs = [".wrangler/tmp", "dist"];
|
|
4330
|
-
for (const dir of searchDirs) {
|
|
4331
|
-
if (!fs3.existsSync(dir)) continue;
|
|
4332
|
-
const bundle = findBundleInDir(dir);
|
|
4333
|
-
if (bundle) return bundle;
|
|
4112
|
+
const branch = runner(["rev-parse", "--abbrev-ref", "HEAD"]).trim();
|
|
4113
|
+
if (!branch || branch === "HEAD") {
|
|
4114
|
+
throw new Error("Cannot deploy from a detached HEAD. Check out a branch before pushing.");
|
|
4334
4115
|
}
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
const jsFiles = entries.filter((e) => e.isFile() && (e.name.endsWith(".js") || e.name.endsWith(".mjs")));
|
|
4342
|
-
jsFiles.sort((a, b) => {
|
|
4343
|
-
const aIsIndex = a.name === "index.js" || a.name === "index.mjs" ? 0 : 1;
|
|
4344
|
-
const bIsIndex = b.name === "index.js" || b.name === "index.mjs" ? 0 : 1;
|
|
4345
|
-
if (aIsIndex !== bIsIndex) return aIsIndex - bIsIndex;
|
|
4346
|
-
const aSize = fs3.statSync(path7.join(dir, a.name)).size;
|
|
4347
|
-
const bSize = fs3.statSync(path7.join(dir, b.name)).size;
|
|
4348
|
-
return bSize - aSize;
|
|
4349
|
-
});
|
|
4350
|
-
for (const entry of jsFiles) {
|
|
4351
|
-
const fullPath = path7.join(dir, entry.name);
|
|
4352
|
-
const content = fs3.readFileSync(fullPath);
|
|
4353
|
-
if (content.length > 0 && content.toString("utf-8", 0, 1e4).includes("export")) {
|
|
4354
|
-
return { bundlePath: fullPath, bundleContent: content };
|
|
4355
|
-
}
|
|
4356
|
-
}
|
|
4357
|
-
for (const entry of entries) {
|
|
4358
|
-
if (entry.isDirectory() && entry.name !== "client" && entry.name !== "node_modules") {
|
|
4359
|
-
const result = findBundleInDir(path7.join(dir, entry.name));
|
|
4360
|
-
if (result) return result;
|
|
4361
|
-
}
|
|
4362
|
-
}
|
|
4363
|
-
return null;
|
|
4364
|
-
}
|
|
4365
|
-
async function checkPlatformVersion(endpoint, builderVersion, authHeaders = {}) {
|
|
4366
|
-
const res = await fetch(`${endpoint}/manifest`, { headers: authHeaders });
|
|
4367
|
-
if (!res.ok) {
|
|
4368
|
-
throw new Error(`Failed to check platform version: ${res.status} ${res.statusText}`);
|
|
4369
|
-
}
|
|
4370
|
-
const manifest = await res.json();
|
|
4371
|
-
if (compareVersions(builderVersion, manifest.minimum_builder_version) < 0) {
|
|
4372
|
-
throw new Error(
|
|
4373
|
-
`Builder version ${builderVersion} is below the platform minimum (${manifest.minimum_builder_version}).
|
|
4374
|
-
Please upgrade @standardagents/builder:
|
|
4375
|
-
npm install @standardagents/builder@latest`
|
|
4376
|
-
);
|
|
4377
|
-
}
|
|
4378
|
-
return manifest;
|
|
4116
|
+
return {
|
|
4117
|
+
remoteName,
|
|
4118
|
+
remoteUrl,
|
|
4119
|
+
branch,
|
|
4120
|
+
refspec: `HEAD:${branch}`
|
|
4121
|
+
};
|
|
4379
4122
|
}
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
formData.append("manifest", new Blob([JSON.stringify(manifest)], { type: "application/json" }), "manifest.json");
|
|
4384
|
-
formData.append("builder_version", builderVersion);
|
|
4385
|
-
formData.append("agent_count", String(manifest.agents.length));
|
|
4386
|
-
const res = await fetch(`${endpoint}/deploys`, {
|
|
4387
|
-
method: "POST",
|
|
4388
|
-
headers: typeof auth === "string" ? authHeadersForDeploy({ kind: "api-key", apiKey: auth }) : authHeadersForDeploy(auth),
|
|
4389
|
-
body: formData
|
|
4123
|
+
function pushArtifactRemote(target) {
|
|
4124
|
+
execFileSync("git", ["push", target.remoteName, target.refspec], {
|
|
4125
|
+
stdio: "inherit"
|
|
4390
4126
|
});
|
|
4391
|
-
let body;
|
|
4392
|
-
try {
|
|
4393
|
-
body = await res.json();
|
|
4394
|
-
} catch {
|
|
4395
|
-
throw new Error(`Deploy failed (${res.status}): Invalid response from server`);
|
|
4396
|
-
}
|
|
4397
|
-
if (!res.ok) {
|
|
4398
|
-
const errorMsg = formatDeployError(body);
|
|
4399
|
-
throw new Error(`Deploy failed (${res.status}): ${errorMsg}`);
|
|
4400
|
-
}
|
|
4401
|
-
return body;
|
|
4402
4127
|
}
|
|
4403
|
-
async function deploy(
|
|
4128
|
+
async function deploy() {
|
|
4404
4129
|
console.log("");
|
|
4405
4130
|
logger.info(`${chalk.bold("Standard Agents Deploy")}
|
|
4406
4131
|
`);
|
|
4407
|
-
|
|
4408
|
-
logger.error("This does not appear to be a Standard Agents project.");
|
|
4409
|
-
logger.info("Run this command from a directory with wrangler.jsonc and agents/agents/.");
|
|
4410
|
-
process.exit(1);
|
|
4411
|
-
}
|
|
4412
|
-
let endpoint;
|
|
4413
|
-
let auth;
|
|
4414
|
-
try {
|
|
4415
|
-
({ endpoint, auth } = resolveDeployAuth(options));
|
|
4416
|
-
} catch (err) {
|
|
4417
|
-
logger.error(err.message);
|
|
4418
|
-
process.exit(1);
|
|
4419
|
-
}
|
|
4420
|
-
logger.success(
|
|
4421
|
-
auth.kind === "session-cookie" ? "Configuration loaded (org-scoped session auth)" : "Configuration loaded (API key auth)"
|
|
4422
|
-
);
|
|
4423
|
-
const agents = discoverAgents();
|
|
4424
|
-
if (agents.length === 0) {
|
|
4425
|
-
const agentsDir = path7.resolve("agents/agents");
|
|
4426
|
-
logger.error(`No deployable agents found in ${agentsDir}.`);
|
|
4427
|
-
if (!fs3.existsSync(agentsDir)) {
|
|
4428
|
-
logger.info("Create agents/agents/ and add at least one file exporting defineAgent(...).");
|
|
4429
|
-
} else {
|
|
4430
|
-
const visibleEntries = fs3.readdirSync(agentsDir).filter((entry) => !entry.startsWith("."));
|
|
4431
|
-
if (visibleEntries.length === 0) {
|
|
4432
|
-
logger.info("agents/agents/ exists but is empty. Add at least one agent file.");
|
|
4433
|
-
} else {
|
|
4434
|
-
const preview = visibleEntries.slice(0, 5).join(", ");
|
|
4435
|
-
const suffix = visibleEntries.length > 5 ? ", ..." : "";
|
|
4436
|
-
logger.info(`Found non-hidden entries in agents/agents/: ${preview}${suffix}`);
|
|
4437
|
-
}
|
|
4438
|
-
}
|
|
4439
|
-
logger.info(`Current working directory: ${process.cwd()}`);
|
|
4440
|
-
logger.info("Run deploy from your project root where agents/agents/ lives.");
|
|
4441
|
-
process.exit(1);
|
|
4442
|
-
}
|
|
4443
|
-
logger.success(`Found ${agents.length} agent${agents.length === 1 ? "" : "s"}: ${agents.join(", ")}`);
|
|
4444
|
-
let builderVersion;
|
|
4445
|
-
try {
|
|
4446
|
-
builderVersion = getBuilderVersion();
|
|
4447
|
-
} catch (err) {
|
|
4448
|
-
logger.error(err.message);
|
|
4449
|
-
process.exit(1);
|
|
4450
|
-
}
|
|
4451
|
-
logger.info(`Builder version: ${builderVersion}`);
|
|
4452
|
-
try {
|
|
4453
|
-
const platformManifest = await checkPlatformVersion(endpoint, builderVersion, authHeadersForDeploy(auth));
|
|
4454
|
-
if (compareVersions(builderVersion, platformManifest.latest_builder_version) < 0) {
|
|
4455
|
-
logger.warning(
|
|
4456
|
-
`A newer builder version is available (${platformManifest.latest_builder_version}). Consider upgrading.`
|
|
4457
|
-
);
|
|
4458
|
-
}
|
|
4459
|
-
} catch (err) {
|
|
4460
|
-
logger.error(err.message);
|
|
4461
|
-
process.exit(1);
|
|
4462
|
-
}
|
|
4463
|
-
logger.info("Building project...\n");
|
|
4464
|
-
try {
|
|
4465
|
-
buildProject(endpoint);
|
|
4466
|
-
} catch {
|
|
4467
|
-
console.log("");
|
|
4468
|
-
logger.error("Build failed. See output above for details.");
|
|
4469
|
-
process.exit(1);
|
|
4470
|
-
}
|
|
4471
|
-
console.log("");
|
|
4472
|
-
logger.success("Build complete");
|
|
4473
|
-
let bundlePath;
|
|
4474
|
-
let bundleContent;
|
|
4475
|
-
try {
|
|
4476
|
-
({ bundlePath, bundleContent } = findWorkerBundle());
|
|
4477
|
-
} catch (err) {
|
|
4478
|
-
logger.error(err.message);
|
|
4479
|
-
process.exit(1);
|
|
4480
|
-
}
|
|
4481
|
-
const manifest = createManifest(agents, builderVersion);
|
|
4482
|
-
logger.success(`Bundle: ${bundlePath} (${formatBytes(bundleContent.length)})`);
|
|
4483
|
-
const sizeWarning = validateBundleSize(bundleContent.length);
|
|
4484
|
-
if (sizeWarning) {
|
|
4485
|
-
logger.warning(sizeWarning);
|
|
4486
|
-
}
|
|
4487
|
-
logger.info("Uploading...");
|
|
4132
|
+
let target;
|
|
4488
4133
|
try {
|
|
4489
|
-
|
|
4490
|
-
console.log("");
|
|
4491
|
-
logger.success(chalk.bold("Deploy successful!"));
|
|
4492
|
-
console.log(` Deploy ID: ${result.deploy.id}`);
|
|
4493
|
-
console.log(` Status: ${result.deploy.status}`);
|
|
4494
|
-
const organizationSlug = result.deploy.organization?.slug ?? result.deploy.org_slug;
|
|
4495
|
-
if (organizationSlug) {
|
|
4496
|
-
console.log(` URL: https://${organizationSlug}.standardagents.ai`);
|
|
4497
|
-
}
|
|
4498
|
-
console.log("");
|
|
4134
|
+
target = resolveArtifactGitDeployTarget();
|
|
4499
4135
|
} catch (err) {
|
|
4500
4136
|
logger.error(err.message);
|
|
4137
|
+
logger.info("Run this command from a clone created by Standard Agents, or push to the platform git remote manually.");
|
|
4501
4138
|
process.exit(1);
|
|
4502
4139
|
}
|
|
4140
|
+
logger.info("Deployments build on the Standard Agents platform from Artifacts git pushes.");
|
|
4141
|
+
logger.log(`Remote: ${target.remoteUrl}`);
|
|
4142
|
+
logger.log(`Branch: ${target.branch}`);
|
|
4143
|
+
logger.log("");
|
|
4144
|
+
pushArtifactRemote(target);
|
|
4145
|
+
logger.success("Push complete. The platform build runner will deploy this commit from the Artifacts push event.");
|
|
4503
4146
|
}
|
|
4504
4147
|
var PROJECT_SIGNAL_PATHS = [
|
|
4505
4148
|
".agents",
|
|
4506
|
-
"
|
|
4507
|
-
"
|
|
4508
|
-
"
|
|
4149
|
+
"agents",
|
|
4150
|
+
"vite.config.ts",
|
|
4151
|
+
"vite.config.js",
|
|
4152
|
+
"vite.config.mts",
|
|
4153
|
+
"vite.config.mjs"
|
|
4509
4154
|
];
|
|
4510
4155
|
function hasProjectSignals(cwd) {
|
|
4511
4156
|
const hits = PROJECT_SIGNAL_PATHS.filter((signal) => fs3.existsSync(path7.join(cwd, signal))).length;
|
|
@@ -4568,7 +4213,7 @@ function getHomeActions(context) {
|
|
|
4568
4213
|
{
|
|
4569
4214
|
id: "deploy",
|
|
4570
4215
|
label: "Deploy",
|
|
4571
|
-
description: "
|
|
4216
|
+
description: "Push this linked project to StandardAgents for a platform build.",
|
|
4572
4217
|
argv: ["deploy"]
|
|
4573
4218
|
},
|
|
4574
4219
|
{
|
|
@@ -4924,7 +4569,7 @@ function isOpaqueModelId(modelId) {
|
|
|
4924
4569
|
function getProviderDefinition(name) {
|
|
4925
4570
|
return PROVIDER_DEFINITIONS.find((provider) => provider.name === name);
|
|
4926
4571
|
}
|
|
4927
|
-
function
|
|
4572
|
+
function parseEnvFile(content) {
|
|
4928
4573
|
const result = {};
|
|
4929
4574
|
for (const line of content.split("\n")) {
|
|
4930
4575
|
const trimmed = line.trim();
|
|
@@ -5028,7 +4673,7 @@ function loadProjectEnv(projectRoot, processEnv = process.env) {
|
|
|
5028
4673
|
for (const fileName of envFiles) {
|
|
5029
4674
|
const filePath = path7.join(projectRoot, fileName);
|
|
5030
4675
|
if (!fs3.existsSync(filePath)) continue;
|
|
5031
|
-
Object.assign(result,
|
|
4676
|
+
Object.assign(result, parseEnvFile(fs3.readFileSync(filePath, "utf8")));
|
|
5032
4677
|
}
|
|
5033
4678
|
for (const [key, value] of Object.entries(processEnv)) {
|
|
5034
4679
|
if (typeof value === "string") {
|
|
@@ -5279,6 +4924,224 @@ async function availableModels(options = {}) {
|
|
|
5279
4924
|
writeError(message);
|
|
5280
4925
|
}
|
|
5281
4926
|
}
|
|
4927
|
+
function parseKeyValueLines(input) {
|
|
4928
|
+
const result = {};
|
|
4929
|
+
for (const line of input.split(/\r?\n/)) {
|
|
4930
|
+
if (!line.trim()) continue;
|
|
4931
|
+
const index = line.indexOf("=");
|
|
4932
|
+
if (index <= 0) continue;
|
|
4933
|
+
result[line.slice(0, index)] = line.slice(index + 1);
|
|
4934
|
+
}
|
|
4935
|
+
return result;
|
|
4936
|
+
}
|
|
4937
|
+
function findDotDevVars(startDir = process.cwd()) {
|
|
4938
|
+
let current = path7.resolve(startDir);
|
|
4939
|
+
while (true) {
|
|
4940
|
+
const candidate = path7.join(current, ".dev.vars");
|
|
4941
|
+
if (fs3.existsSync(candidate)) return candidate;
|
|
4942
|
+
const parent = path7.dirname(current);
|
|
4943
|
+
if (parent === current) return null;
|
|
4944
|
+
current = parent;
|
|
4945
|
+
}
|
|
4946
|
+
}
|
|
4947
|
+
function normalizeEndpoint(value) {
|
|
4948
|
+
return value.replace(/\/+$/, "");
|
|
4949
|
+
}
|
|
4950
|
+
function normalizeGitHost(host) {
|
|
4951
|
+
return host.trim().toLowerCase().replace(/:\d+$/, "");
|
|
4952
|
+
}
|
|
4953
|
+
function isStandardAgentsGitHost(host) {
|
|
4954
|
+
const normalized = normalizeGitHost(host);
|
|
4955
|
+
return normalized === "standardagents.ai" || normalized.endsWith(".standardagents.ai") || normalized === "standardagentbuilder.com" || normalized.endsWith(".standardagentbuilder.com") || normalized === "artifacts.cloudflare.net" || normalized.endsWith(".artifacts.cloudflare.net") || normalized === "artifacts.cloudflare.com" || normalized.endsWith(".artifacts.cloudflare.com") || normalized === "git.cloudflare.com";
|
|
4956
|
+
}
|
|
4957
|
+
function loadLocalConfig(options) {
|
|
4958
|
+
const envPath = findDotDevVars(options.startDir);
|
|
4959
|
+
const fileVars = envPath ? parseKeyValueLines(fs3.readFileSync(envPath, "utf-8")) : {};
|
|
4960
|
+
const endpoint = normalizeEndpoint(
|
|
4961
|
+
options.endpoint || process.env.STANDARD_AGENTS_API_URL || process.env.PLATFORM_ENDPOINT || fileVars.STANDARD_AGENTS_API_URL || fileVars.PLATFORM_ENDPOINT || ""
|
|
4962
|
+
);
|
|
4963
|
+
const apiKey = process.env.STANDARD_AGENTS_API_KEY || fileVars.STANDARD_AGENTS_API_KEY || "";
|
|
4964
|
+
if (endpoint && apiKey) {
|
|
4965
|
+
return { endpoint, auth: { kind: "api-key", apiKey } };
|
|
4966
|
+
}
|
|
4967
|
+
const cookie = process.env.STANDARD_AGENTS_SESSION_COOKIE || process.env.STANDARDAGENTS_BOOTSTRAP_SESSION_COOKIE || fileVars.STANDARDAGENTS_BOOTSTRAP_SESSION_COOKIE || "";
|
|
4968
|
+
if (endpoint && cookie) {
|
|
4969
|
+
return { endpoint, auth: { kind: "session-cookie", cookie } };
|
|
4970
|
+
}
|
|
4971
|
+
const globalAuth = resolveCliGitAuth();
|
|
4972
|
+
if (!globalAuth) return null;
|
|
4973
|
+
const requestedEndpoint = endpoint || normalizeEndpoint(options.endpoint || "");
|
|
4974
|
+
if (requestedEndpoint && requestedEndpoint !== globalAuth.endpoint) {
|
|
4975
|
+
return null;
|
|
4976
|
+
}
|
|
4977
|
+
return {
|
|
4978
|
+
endpoint: globalAuth.endpoint,
|
|
4979
|
+
auth: { kind: "session-cookie", cookie: globalAuth.session_cookie }
|
|
4980
|
+
};
|
|
4981
|
+
}
|
|
4982
|
+
function remoteFromCredentialRequest(request) {
|
|
4983
|
+
if (!request.protocol || !request.host) return null;
|
|
4984
|
+
if (!isStandardAgentsGitHost(request.host)) return null;
|
|
4985
|
+
const repoPath = request.path ? `/${request.path.replace(/^\/+/, "")}` : "";
|
|
4986
|
+
return `${request.protocol}://${normalizeGitHost(request.host)}${repoPath}`;
|
|
4987
|
+
}
|
|
4988
|
+
async function readStdin() {
|
|
4989
|
+
const chunks = [];
|
|
4990
|
+
for await (const chunk of process.stdin) {
|
|
4991
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk)));
|
|
4992
|
+
}
|
|
4993
|
+
return Buffer.concat(chunks).toString("utf-8");
|
|
4994
|
+
}
|
|
4995
|
+
async function gitCredential(operation, options = {}) {
|
|
4996
|
+
if (operation !== "get") return;
|
|
4997
|
+
const config = loadLocalConfig(options);
|
|
4998
|
+
if (!config) return;
|
|
4999
|
+
const input = options.input ?? await readStdin();
|
|
5000
|
+
const remote = remoteFromCredentialRequest(parseKeyValueLines(input));
|
|
5001
|
+
if (!remote) return;
|
|
5002
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
5003
|
+
const headers = {
|
|
5004
|
+
"Content-Type": "application/json"
|
|
5005
|
+
};
|
|
5006
|
+
if (config.auth.kind === "api-key") {
|
|
5007
|
+
headers.Authorization = `Bearer ${config.auth.apiKey}`;
|
|
5008
|
+
} else {
|
|
5009
|
+
headers.Cookie = config.auth.cookie;
|
|
5010
|
+
}
|
|
5011
|
+
const response = await fetchImpl(`${config.endpoint}/projects/git-token`, {
|
|
5012
|
+
method: "POST",
|
|
5013
|
+
headers,
|
|
5014
|
+
body: JSON.stringify({ remote, scope: "write" })
|
|
5015
|
+
}).catch(() => null);
|
|
5016
|
+
if (!response?.ok) return;
|
|
5017
|
+
const body = await response.json().catch(() => null);
|
|
5018
|
+
const tokenSecret = body?.artifact_git?.token_secret;
|
|
5019
|
+
if (!tokenSecret) return;
|
|
5020
|
+
const write = options.write ?? ((text) => {
|
|
5021
|
+
process.stdout.write(text);
|
|
5022
|
+
});
|
|
5023
|
+
write(`username=x
|
|
5024
|
+
password=${tokenSecret}
|
|
5025
|
+
|
|
5026
|
+
`);
|
|
5027
|
+
}
|
|
5028
|
+
var DEFAULT_GIT_HELPER_COMMAND = "!npx -y @standardagents/cli@latest git-credential";
|
|
5029
|
+
function prompt4(question) {
|
|
5030
|
+
const rl = readline.createInterface({
|
|
5031
|
+
input: process.stdin,
|
|
5032
|
+
output: process.stdout
|
|
5033
|
+
});
|
|
5034
|
+
return new Promise((resolve) => {
|
|
5035
|
+
rl.question(question, (answer) => {
|
|
5036
|
+
rl.close();
|
|
5037
|
+
resolve(answer.trim());
|
|
5038
|
+
});
|
|
5039
|
+
});
|
|
5040
|
+
}
|
|
5041
|
+
function defaultGitRunner(args) {
|
|
5042
|
+
const result = spawnSync("git", args, { encoding: "utf8" });
|
|
5043
|
+
return {
|
|
5044
|
+
status: result.status,
|
|
5045
|
+
stdout: result.stdout || "",
|
|
5046
|
+
stderr: result.stderr || ""
|
|
5047
|
+
};
|
|
5048
|
+
}
|
|
5049
|
+
function runGit(args, runner) {
|
|
5050
|
+
const result = runner(args);
|
|
5051
|
+
if (result.status !== 0) {
|
|
5052
|
+
throw new Error(result.stderr.trim() || `git ${args.join(" ")} failed`);
|
|
5053
|
+
}
|
|
5054
|
+
return result;
|
|
5055
|
+
}
|
|
5056
|
+
function configureStandardAgentsGitCredentials(options = {}) {
|
|
5057
|
+
const runner = options.gitRunner ?? defaultGitRunner;
|
|
5058
|
+
const helperCommand = options.helperCommand?.trim() || process.env.STANDARD_AGENTS_GIT_HELPER || DEFAULT_GIT_HELPER_COMMAND;
|
|
5059
|
+
const existing = runGit(["config", "--global", "--get-all", "credential.helper"], runner).stdout.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
5060
|
+
let helperAdded = false;
|
|
5061
|
+
if (!existing.includes(helperCommand)) {
|
|
5062
|
+
runGit(["config", "--global", "--add", "credential.helper", helperCommand], runner);
|
|
5063
|
+
helperAdded = true;
|
|
5064
|
+
}
|
|
5065
|
+
runGit(["config", "--global", "credential.useHttpPath", "true"], runner);
|
|
5066
|
+
return { helperCommand, helperAdded };
|
|
5067
|
+
}
|
|
5068
|
+
async function completeBrowserGitLogin(options, endpoint) {
|
|
5069
|
+
let authAppUrl = resolvePlatformAuthBrowserUrl(endpoint);
|
|
5070
|
+
let sessionId = null;
|
|
5071
|
+
let wsUrl = null;
|
|
5072
|
+
let wsExpiresAt = 0;
|
|
5073
|
+
try {
|
|
5074
|
+
const started = await startCliAuthSession(endpoint);
|
|
5075
|
+
sessionId = started.session_id;
|
|
5076
|
+
authAppUrl = started.auth_url;
|
|
5077
|
+
wsUrl = started.ws_url;
|
|
5078
|
+
wsExpiresAt = started.expires_at;
|
|
5079
|
+
} catch (error) {
|
|
5080
|
+
const message = error instanceof Error ? error.message : "Failed to start realtime auth session";
|
|
5081
|
+
logger.warning(`${message} Switching to manual bootstrap command entry.`);
|
|
5082
|
+
}
|
|
5083
|
+
logger.log(`Auth app: ${authAppUrl}`);
|
|
5084
|
+
if (options.open !== false) {
|
|
5085
|
+
const opened = openBrowser(authAppUrl);
|
|
5086
|
+
if (opened) {
|
|
5087
|
+
logger.info("Opened browser for authentication.");
|
|
5088
|
+
} else {
|
|
5089
|
+
logger.warning("Could not automatically open browser. Open the URL above manually.");
|
|
5090
|
+
}
|
|
5091
|
+
}
|
|
5092
|
+
if (wsUrl && wsExpiresAt > 0) {
|
|
5093
|
+
try {
|
|
5094
|
+
const completion = await waitForCliAuthCompletion(wsUrl, wsExpiresAt);
|
|
5095
|
+
return consumeBootstrapLogin({ ...options, endpoint, bootstrap: completion.bootstrapCode });
|
|
5096
|
+
} catch (error) {
|
|
5097
|
+
const message = error instanceof Error ? error.message : "Realtime auth handoff failed";
|
|
5098
|
+
logger.warning(`${message} Enter bootstrap code manually to continue.`);
|
|
5099
|
+
}
|
|
5100
|
+
}
|
|
5101
|
+
if (!process.stdin.isTTY) {
|
|
5102
|
+
throw new Error("Non-interactive shell detected. Run: npx @standardagents/cli git-login --bootstrap <code>");
|
|
5103
|
+
}
|
|
5104
|
+
const input = await prompt4("Bootstrap code or command: ");
|
|
5105
|
+
const bootstrapCode = parseBootstrapCodeInput(input);
|
|
5106
|
+
if (!bootstrapCode) {
|
|
5107
|
+
if (sessionId) {
|
|
5108
|
+
await cancelCliAuthSession(endpoint, sessionId);
|
|
5109
|
+
}
|
|
5110
|
+
throw new Error("No bootstrap code provided. Run: npx @standardagents/cli git-login --bootstrap <code>");
|
|
5111
|
+
}
|
|
5112
|
+
if (sessionId) {
|
|
5113
|
+
await cancelCliAuthSession(endpoint, sessionId);
|
|
5114
|
+
}
|
|
5115
|
+
return consumeBootstrapLogin({ ...options, endpoint, bootstrap: bootstrapCode });
|
|
5116
|
+
}
|
|
5117
|
+
async function gitLogin(options = {}) {
|
|
5118
|
+
const endpoint = resolvePlatformEndpoint({ endpoint: options.endpoint });
|
|
5119
|
+
logger.log("");
|
|
5120
|
+
logger.info("Starting Standard Agents Git authentication...");
|
|
5121
|
+
logger.log(`Platform API: ${endpoint}`);
|
|
5122
|
+
const state = options.bootstrap?.trim() ? await consumeBootstrapLogin({ ...options, endpoint, bootstrap: options.bootstrap.trim() }) : await completeBrowserGitLogin(options, endpoint);
|
|
5123
|
+
if (!state.session_cookie) {
|
|
5124
|
+
throw new Error("Platform login did not return a session cookie for Git authentication.");
|
|
5125
|
+
}
|
|
5126
|
+
const record = saveCliGitAuth({
|
|
5127
|
+
endpoint,
|
|
5128
|
+
sessionCookie: state.session_cookie,
|
|
5129
|
+
account: state.account,
|
|
5130
|
+
user: state.user
|
|
5131
|
+
});
|
|
5132
|
+
let configured = null;
|
|
5133
|
+
if (options.config !== false) {
|
|
5134
|
+
configured = configureStandardAgentsGitCredentials(options);
|
|
5135
|
+
}
|
|
5136
|
+
logger.log("");
|
|
5137
|
+
logger.success("Git authentication configured.");
|
|
5138
|
+
logger.log(`Account: ${record.account_id}${record.account_slug ? ` (${record.account_slug})` : ""}`);
|
|
5139
|
+
logger.log(`User: ${record.user_email}`);
|
|
5140
|
+
if (configured) {
|
|
5141
|
+
logger.log(`Credential helper: ${configured.helperCommand}${configured.helperAdded ? "" : " (already installed)"}`);
|
|
5142
|
+
}
|
|
5143
|
+
logger.log("");
|
|
5144
|
+
}
|
|
5282
5145
|
|
|
5283
5146
|
// src/index.ts
|
|
5284
5147
|
async function settleStdinForInitHandoff(stdin = process.stdin) {
|
|
@@ -5299,8 +5162,8 @@ async function settleStdinForInitHandoff(stdin = process.stdin) {
|
|
|
5299
5162
|
}
|
|
5300
5163
|
}
|
|
5301
5164
|
var program = new Command();
|
|
5302
|
-
program.name("agents").description("CLI tool for Standard Agents / AgentBuilder").version("0.
|
|
5303
|
-
program.command("init [project-name]").description("Create a new Standard Agents project").option("-y, --yes", "Skip prompts and use defaults").option("--local", "Use local project scaffolding instead of browser platform onboarding").option("--cli", "Use classic line-by-line CLI prompts instead of the TUI wizard").option("--api-url <url>", "Standard Agents platform API URL").option("--endpoint <url>", "Platform API endpoint for auth/bootstrap exchange").option("--package-manager <manager>", "Package manager for generated project: npm, pnpm, yarn, or bun").option("--template <template>", "Vite template to use", "vanilla-ts").option("--workspace", "Install @standardagents packages as workspace:* (local pnpm workspace development)").addOption(new Option("--bootstrap <code>", "Exchange a web onboarding bootstrap code")).action(init);
|
|
5165
|
+
program.name("agents").description("CLI tool for Standard Agents / AgentBuilder").version("0.17.0-next.a4b7340");
|
|
5166
|
+
program.command("init [project-name]").description("Create a new Standard Agents project").option("-y, --yes", "Skip prompts and use defaults").option("--local", "Use local project scaffolding instead of browser platform onboarding").option("--cli", "Use classic line-by-line CLI prompts instead of the TUI wizard").option("--api-url <url>", "Standard Agents platform API URL").option("--endpoint <url>", "Platform API endpoint for auth/bootstrap exchange").option("--package-manager <manager>", "Package manager for generated project: npm, pnpm, yarn, or bun").option("--template <template>", "Vite template to use", "vanilla-ts").option("--workspace", "Install @standardagents packages as workspace:* (local pnpm workspace development)").option("--no-dev", "Clone and configure the project without starting the dev server").addOption(new Option("--bootstrap <code>", "Exchange a web onboarding bootstrap code")).action(init);
|
|
5304
5167
|
program.command("login").description("Authenticate this machine (or use --bootstrap for project bootstrap auth)").option("--bootstrap <code>", "Bootstrap code from web onboarding").option("--endpoint <url>", "Platform API endpoint (default: https://api.standardagents.ai)").option("--no-open", "Do not auto-open browser URL").action(login);
|
|
5305
5168
|
program.command("logout").description("Clear stored StandardAgents auth and local org-scoped project auth").option("--org <org-id-or-slug>", "Org ID or slug to logout (defaults to active org)").option("--endpoint <url>", "Platform API endpoint (default: https://api.standardagents.ai)").action(logout);
|
|
5306
5169
|
program.command("scaffold").description("Add Standard Agents to an existing Vite project").option("--force", "Overwrite existing configuration").action(scaffold);
|
|
@@ -5308,7 +5171,10 @@ program.command("init-chat [project-name]").description("Scaffold a frontend cha
|
|
|
5308
5171
|
program.command("pack [agent-name]").description("Pack an agent with all its dependencies").option("--output <dir>", "Output directory (default: agents/packed)").option("--npm", "Generate npm-ready package structure").option("--version <version>", "Package version (default: 1.0.0)").option("--no-remove", "Keep original files after packing").option("--no-interactive", "Skip interactive item mode selector").action(pack);
|
|
5309
5172
|
program.command("unpack [package]").description("Unpack a packed agent to the local agents directory").option("--no-signatures", "Remove package signatures (fully editable)").action(unpack);
|
|
5310
5173
|
program.command("list-packed").description("List all discovered packed agents").action(listPacked);
|
|
5311
|
-
program.command("deploy").description("
|
|
5174
|
+
program.command("deploy").description("Push the current branch to the Standard Agents Artifacts remote").action(deploy);
|
|
5175
|
+
program.command("git-credential <operation>").description("Git credential helper for Standard Agents platform repositories").option("--endpoint <url>", "Platform API endpoint").action(gitCredential);
|
|
5176
|
+
program.command("git-login").description("Authenticate Git for Standard Agents platform repositories").option("--bootstrap <code>", "Bootstrap code from web onboarding").option("--endpoint <url>", "Platform API endpoint (default: https://api.standardagents.ai)").option("--helper-command <command>", "Credential helper command to add to global git config").option("--no-config", "Store Git auth but do not update global git config").option("--no-open", "Do not auto-open browser URL").action(gitLogin);
|
|
5177
|
+
program.command("support-files").description("Write generated local support files for a Standard Agents platform repository").option("--project-name <name>", "Project name to use in the generated package manifest").option("--package-manager <manager>", "Package manager: npm, pnpm, yarn, or bun").action(supportFiles);
|
|
5312
5178
|
program.command("skill").description("Install the bundled AgentBuilder guidance into a supported coding agent").option("--agent <target>", "Install target: codex or claude").option("--dir <path>", "Install directory override for the selected target").option("--force", "Overwrite an existing installed skill").action(skill);
|
|
5313
5179
|
program.command("current-models").description("Print the live curated model guide from standardagentspec.com").option("--url <url>", "Override the models markdown URL").action(currentModels);
|
|
5314
5180
|
program.command("available-models").description("List every available model for one configured provider in the current project").option("--provider <provider>", "Provider to query, for example cerebras or openai").action(availableModels);
|