@standardagents/cli 0.15.2 → 0.16.0
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 +610 -712
- 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.16.0";
|
|
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: "/" }
|
|
307
|
+
imported: "builder",
|
|
308
|
+
constructor: "builder"
|
|
347
309
|
});
|
|
348
|
-
logger.success("Added
|
|
349
|
-
}
|
|
350
|
-
if (!hasCloudflare || force) {
|
|
351
|
-
addVitePlugin(mod, {
|
|
352
|
-
from: "@cloudflare/vite-plugin",
|
|
353
|
-
imported: "cloudflare",
|
|
354
|
-
constructor: "cloudflare"
|
|
355
|
-
});
|
|
356
|
-
logger.success("Added cloudflare plugin to vite.config");
|
|
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 = {
|
|
@@ -1253,6 +991,7 @@ var GENERATED_STANDARD_AGENTS_PACKAGES = [
|
|
|
1253
991
|
];
|
|
1254
992
|
var PLATFORM_RUNTIME_PACKAGE = "@standardagents/platform-runtime";
|
|
1255
993
|
var PACKAGE_MANAGERS = ["npm", "pnpm", "yarn", "bun"];
|
|
994
|
+
var DEFAULT_PLATFORM_GIT_HELPER_COMMAND = "!npx -y @standardagents/cli@latest git-credential";
|
|
1256
995
|
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
996
|
var LEGACY_BOOTSTRAP_RESPONSE_MESSAGE = "The platform returned an older onboarding response. Please run the init command again to start a new project setup.";
|
|
1258
997
|
var INIT_WIZARD_RETURN_TO_HOME_EXIT_CODE = 90;
|
|
@@ -1458,20 +1197,33 @@ ${details}`));
|
|
|
1458
1197
|
child.on("error", reject);
|
|
1459
1198
|
});
|
|
1460
1199
|
}
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
child.on("spawn", () => {
|
|
1471
|
-
child.unref();
|
|
1472
|
-
resolve();
|
|
1473
|
-
});
|
|
1200
|
+
var DEV_SERVER_LOG_FILE = ".agentbuilder-dev.log";
|
|
1201
|
+
function startDetachedDevServer(command, args, cwd) {
|
|
1202
|
+
const logPath = path7.join(cwd, DEV_SERVER_LOG_FILE);
|
|
1203
|
+
const logFd = fs3.openSync(logPath, "w");
|
|
1204
|
+
const child = spawn(command, args, {
|
|
1205
|
+
cwd,
|
|
1206
|
+
stdio: ["ignore", logFd, logFd],
|
|
1207
|
+
shell: false,
|
|
1208
|
+
detached: true
|
|
1474
1209
|
});
|
|
1210
|
+
child.unref();
|
|
1211
|
+
fs3.closeSync(logFd);
|
|
1212
|
+
return { logPath };
|
|
1213
|
+
}
|
|
1214
|
+
function readLogTail(logPath, maxLines = 20) {
|
|
1215
|
+
try {
|
|
1216
|
+
const text = fs3.readFileSync(logPath, "utf-8").trimEnd();
|
|
1217
|
+
if (!text) return "";
|
|
1218
|
+
return text.split("\n").slice(-maxLines).join("\n");
|
|
1219
|
+
} catch {
|
|
1220
|
+
return "";
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
function devCommandHint(packageManager) {
|
|
1224
|
+
if (packageManager === "npm") return "npm run dev";
|
|
1225
|
+
if (packageManager === "bun") return "bun run dev";
|
|
1226
|
+
return `${packageManager} dev`;
|
|
1475
1227
|
}
|
|
1476
1228
|
function canConnectToPort(port) {
|
|
1477
1229
|
return new Promise((resolve) => {
|
|
@@ -1497,17 +1249,17 @@ function buildDevServerCommand(packageManager, port) {
|
|
|
1497
1249
|
const viteArgs = ["--host", "127.0.0.1", "--port", String(port), "--strictPort"];
|
|
1498
1250
|
return packageManager === "npm" ? ["run", "dev", "--", ...viteArgs] : ["dev", ...viteArgs];
|
|
1499
1251
|
}
|
|
1500
|
-
async function waitForLocalDevServer(url) {
|
|
1501
|
-
const deadline = Date.now() +
|
|
1252
|
+
async function waitForLocalDevServer(url, timeoutMs = 6e4) {
|
|
1253
|
+
const deadline = Date.now() + timeoutMs;
|
|
1502
1254
|
while (Date.now() < deadline) {
|
|
1503
1255
|
try {
|
|
1504
1256
|
const response = await fetch(url, { cache: "no-store" });
|
|
1505
|
-
if (response.ok) return;
|
|
1257
|
+
if (response.ok) return true;
|
|
1506
1258
|
} catch {
|
|
1507
1259
|
}
|
|
1508
1260
|
await sleep(500);
|
|
1509
1261
|
}
|
|
1510
|
-
|
|
1262
|
+
return false;
|
|
1511
1263
|
}
|
|
1512
1264
|
function sleep(ms) {
|
|
1513
1265
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -1540,7 +1292,8 @@ function isStandardAgentsProjectDir(targetPath) {
|
|
|
1540
1292
|
if (!fs3.existsSync(agentsDir) || !fs3.statSync(agentsDir).isDirectory()) {
|
|
1541
1293
|
return false;
|
|
1542
1294
|
}
|
|
1543
|
-
|
|
1295
|
+
if (hasBuilderDependency(targetPath)) return true;
|
|
1296
|
+
return fs3.existsSync(path7.join(targetPath, "vite.config.ts")) && fs3.existsSync(path7.join(targetPath, "tsconfig.json"));
|
|
1544
1297
|
}
|
|
1545
1298
|
async function resolveProjectTarget(cwd, initialProjectName, options, promptProjectName = prompt) {
|
|
1546
1299
|
if (!initialProjectName && isStandardAgentsProjectDir(cwd)) {
|
|
@@ -1785,7 +1538,7 @@ async function ensurePlatformAuth(options, quietLogs = false, context = {}) {
|
|
|
1785
1538
|
return { connected: true, mode: "standardagents" };
|
|
1786
1539
|
}
|
|
1787
1540
|
function getCliVersion() {
|
|
1788
|
-
return "0.
|
|
1541
|
+
return "0.16.0";
|
|
1789
1542
|
}
|
|
1790
1543
|
function getSipVersion() {
|
|
1791
1544
|
return "1.0.1";
|
|
@@ -2135,6 +1888,37 @@ function resolvePlatformProjectDirectoryName(project, requestedProjectName) {
|
|
|
2135
1888
|
function resolvePlatformProjectPackageManager(projectPackageManager, requestedPackageManager) {
|
|
2136
1889
|
return resolvePackageManager(projectPackageManager ?? void 0, requestedPackageManager);
|
|
2137
1890
|
}
|
|
1891
|
+
function sanitizeGitRemoteUrl(remoteUrl) {
|
|
1892
|
+
try {
|
|
1893
|
+
const url = new URL(remoteUrl);
|
|
1894
|
+
url.username = "";
|
|
1895
|
+
url.password = "";
|
|
1896
|
+
return url.toString();
|
|
1897
|
+
} catch {
|
|
1898
|
+
return remoteUrl.replace(/\/\/[^/@\s]+@/, "//");
|
|
1899
|
+
}
|
|
1900
|
+
}
|
|
1901
|
+
function cloneDisplayUrl(project) {
|
|
1902
|
+
return project.repo_html_url || sanitizeGitRemoteUrl(project.repo_clone_url);
|
|
1903
|
+
}
|
|
1904
|
+
function gitCloneArgs(project, projectName) {
|
|
1905
|
+
const args = [];
|
|
1906
|
+
if (project.git_extra_header) {
|
|
1907
|
+
args.push("-c", `http.extraHeader=${project.git_extra_header}`);
|
|
1908
|
+
}
|
|
1909
|
+
args.push("clone", project.repo_clone_url, projectName);
|
|
1910
|
+
return args;
|
|
1911
|
+
}
|
|
1912
|
+
function platformGitCredentialHelperCommand(cliEntry = process.argv[1] ?? "") {
|
|
1913
|
+
if (process.env.STANDARDAGENTS_WORKSPACE === "1" && cliEntry && fs3.existsSync(cliEntry)) {
|
|
1914
|
+
return `!node ${shellQuote(path7.resolve(cliEntry))} git-credential`;
|
|
1915
|
+
}
|
|
1916
|
+
return process.env.STANDARD_AGENTS_GIT_HELPER?.trim() || DEFAULT_PLATFORM_GIT_HELPER_COMMAND;
|
|
1917
|
+
}
|
|
1918
|
+
async function configurePlatformGitCredentialHelper(projectPath) {
|
|
1919
|
+
await runCommand("git", ["config", "credential.helper", platformGitCredentialHelperCommand()], projectPath);
|
|
1920
|
+
await runCommand("git", ["config", "credential.useHttpPath", "true"], projectPath);
|
|
1921
|
+
}
|
|
2138
1922
|
function isRetryablePlatformAuthStatus(status) {
|
|
2139
1923
|
return status === 502 || status === 503 || status === 504;
|
|
2140
1924
|
}
|
|
@@ -2230,6 +2014,62 @@ function upsertEnvLine(lines, key, value) {
|
|
|
2230
2014
|
function hasEnvLine(lines, key) {
|
|
2231
2015
|
return lines.some((line) => line.startsWith(`${key}=`));
|
|
2232
2016
|
}
|
|
2017
|
+
function appendGitignoreEntries(projectPath, heading, entries) {
|
|
2018
|
+
const gitignorePath = path7.join(projectPath, ".gitignore");
|
|
2019
|
+
const gitignoreContent = fs3.existsSync(gitignorePath) ? fs3.readFileSync(gitignorePath, "utf-8") : "";
|
|
2020
|
+
const existingEntries = new Set(gitignoreContent.split(/\r?\n/));
|
|
2021
|
+
const missingEntries = entries.filter((entry) => !existingEntries.has(entry));
|
|
2022
|
+
if (missingEntries.length === 0) return;
|
|
2023
|
+
const prefix = gitignoreContent.length === 0 ? "" : gitignoreContent.endsWith("\n") ? "\n" : "\n\n";
|
|
2024
|
+
fs3.appendFileSync(gitignorePath, `${prefix}${heading}
|
|
2025
|
+
${missingEntries.join("\n")}
|
|
2026
|
+
`);
|
|
2027
|
+
}
|
|
2028
|
+
function writeStandardAgentsSupportFiles(projectPath, params) {
|
|
2029
|
+
const written = [];
|
|
2030
|
+
for (const supportFile of renderAgentBuilderSupportFiles({
|
|
2031
|
+
projectName: params.projectName,
|
|
2032
|
+
packageManager: params.packageManager
|
|
2033
|
+
})) {
|
|
2034
|
+
const targetPath = path7.join(projectPath, supportFile.path);
|
|
2035
|
+
if (fs3.existsSync(targetPath)) continue;
|
|
2036
|
+
fs3.mkdirSync(path7.dirname(targetPath), { recursive: true });
|
|
2037
|
+
fs3.writeFileSync(targetPath, supportFile.content, "utf-8");
|
|
2038
|
+
written.push(supportFile.path);
|
|
2039
|
+
}
|
|
2040
|
+
if (written.includes("package.json")) {
|
|
2041
|
+
appendGitignoreEntries(projectPath, "# Standard Agents generated local support files", [
|
|
2042
|
+
"package.json",
|
|
2043
|
+
"package-lock.json",
|
|
2044
|
+
"pnpm-lock.yaml",
|
|
2045
|
+
"yarn.lock",
|
|
2046
|
+
"bun.lock",
|
|
2047
|
+
"bun.lockb",
|
|
2048
|
+
"node_modules"
|
|
2049
|
+
]);
|
|
2050
|
+
}
|
|
2051
|
+
return written;
|
|
2052
|
+
}
|
|
2053
|
+
function supportFiles(options = {}) {
|
|
2054
|
+
let packageManager;
|
|
2055
|
+
try {
|
|
2056
|
+
packageManager = resolvePackageManager(options.packageManager, detectPackageManager());
|
|
2057
|
+
} catch (error) {
|
|
2058
|
+
logger.error(error instanceof Error ? error.message : String(error));
|
|
2059
|
+
process.exit(1);
|
|
2060
|
+
}
|
|
2061
|
+
const cwd = process.cwd();
|
|
2062
|
+
const projectName = normalizeProjectName(options.projectName ?? path7.basename(cwd)) || "standard-agents";
|
|
2063
|
+
const written = writeStandardAgentsSupportFiles(cwd, {
|
|
2064
|
+
projectName,
|
|
2065
|
+
packageManager
|
|
2066
|
+
});
|
|
2067
|
+
if (written.length === 0) {
|
|
2068
|
+
logger.info("Standard Agents local support files already exist");
|
|
2069
|
+
return;
|
|
2070
|
+
}
|
|
2071
|
+
logger.success(`Wrote Standard Agents local support files: ${written.join(", ")}`);
|
|
2072
|
+
}
|
|
2233
2073
|
function writeStandardAgentsEnv(projectPath, params) {
|
|
2234
2074
|
const envPath = path7.join(projectPath, ".dev.vars");
|
|
2235
2075
|
const existing = fs3.existsSync(envPath) ? fs3.readFileSync(envPath, "utf-8") : "";
|
|
@@ -2258,21 +2098,42 @@ function writeStandardAgentsEnv(projectPath, params) {
|
|
|
2258
2098
|
lines = upsertEnvLine(lines, "PLATFORM_ENDPOINT", params.platformEndpoint);
|
|
2259
2099
|
lines = upsertEnvLine(lines, "STANDARD_AGENTS_API_URL", params.platformEndpoint);
|
|
2260
2100
|
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
|
-
}
|
|
2101
|
+
appendGitignoreEntries(projectPath, "# Standard Agents local platform token", [".dev.vars"]);
|
|
2269
2102
|
return envPath;
|
|
2270
2103
|
}
|
|
2104
|
+
async function resolveBootstrapProject(endpoint, code, fetchImpl = fetch) {
|
|
2105
|
+
const consumed = await exchangeBootstrapCode(endpoint, code, fetchImpl);
|
|
2106
|
+
const cookie = consumed.session_cookie;
|
|
2107
|
+
const listResponse = await fetchImpl(`${endpoint}/projects`, {
|
|
2108
|
+
headers: { Accept: "application/json", Cookie: cookie }
|
|
2109
|
+
});
|
|
2110
|
+
if (!listResponse.ok) {
|
|
2111
|
+
throw new Error(`Could not load your Standard Agents instance (${listResponse.status}).`);
|
|
2112
|
+
}
|
|
2113
|
+
const listBody = await listResponse.json().catch(() => ({}));
|
|
2114
|
+
const projectId = listBody.projects?.find(
|
|
2115
|
+
(entry) => typeof entry?.id === "string"
|
|
2116
|
+
)?.id;
|
|
2117
|
+
if (!projectId) {
|
|
2118
|
+
throw new Error("No Standard Agents instance found for this account. Create one in the dashboard first.");
|
|
2119
|
+
}
|
|
2120
|
+
const handoffResponse = await fetchImpl(`${endpoint}/projects/${projectId}/cli-handoff`, {
|
|
2121
|
+
method: "POST",
|
|
2122
|
+
headers: { Accept: "application/json", "Content-Type": "application/json", Cookie: cookie },
|
|
2123
|
+
body: "{}"
|
|
2124
|
+
});
|
|
2125
|
+
if (!handoffResponse.ok) {
|
|
2126
|
+
const text = await handoffResponse.text().catch(() => "");
|
|
2127
|
+
throw new Error(`Could not prepare your instance for local setup (${handoffResponse.status})${text ? `: ${text}` : ""}`);
|
|
2128
|
+
}
|
|
2129
|
+
const handoffBody = await handoffResponse.json().catch(() => ({}));
|
|
2130
|
+
if (!handoffBody.project?.repo_clone_url || !handoffBody.project.api_key) {
|
|
2131
|
+
throw new Error("Instance handoff response was missing clone details.");
|
|
2132
|
+
}
|
|
2133
|
+
return handoffBody.project;
|
|
2134
|
+
}
|
|
2271
2135
|
async function runPlatformInit(projectNameArg, options) {
|
|
2272
2136
|
const cwd = process.cwd();
|
|
2273
|
-
if (options.bootstrap) {
|
|
2274
|
-
logger.warning("Legacy bootstrap codes now continue through browser onboarding.");
|
|
2275
|
-
}
|
|
2276
2137
|
let pm;
|
|
2277
2138
|
try {
|
|
2278
2139
|
pm = resolvePackageManager(options.packageManager, detectPackageManager());
|
|
@@ -2286,23 +2147,34 @@ async function runPlatformInit(projectNameArg, options) {
|
|
|
2286
2147
|
process.exit(1);
|
|
2287
2148
|
}
|
|
2288
2149
|
const endpoint = normalizeApiUrl(options.apiUrl || options.endpoint);
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
endpoint,
|
|
2294
|
-
|
|
2295
|
-
|
|
2150
|
+
let project;
|
|
2151
|
+
if (options.bootstrap?.trim()) {
|
|
2152
|
+
logger.info("Connecting to your Standard Agents instance...");
|
|
2153
|
+
try {
|
|
2154
|
+
project = await resolveBootstrapProject(endpoint, options.bootstrap.trim());
|
|
2155
|
+
} catch (error) {
|
|
2156
|
+
logger.error(error instanceof Error ? error.message : String(error));
|
|
2157
|
+
process.exit(1);
|
|
2158
|
+
}
|
|
2159
|
+
} else {
|
|
2160
|
+
logger.info("Opening Standard Agents platform signup/login...");
|
|
2161
|
+
let session;
|
|
2162
|
+
try {
|
|
2163
|
+
session = await startPlatformCliSession({
|
|
2164
|
+
endpoint,
|
|
2165
|
+
projectName: requestedProjectName,
|
|
2166
|
+
packageManager: pm
|
|
2167
|
+
});
|
|
2168
|
+
} catch (error) {
|
|
2169
|
+
logger.error(error instanceof Error ? error.message : String(error));
|
|
2170
|
+
process.exit(1);
|
|
2171
|
+
}
|
|
2172
|
+
openUrl(session.auth_url);
|
|
2173
|
+
logger.info("Finish the browser steps. I will stay here and continue automatically.");
|
|
2174
|
+
project = await waitForPlatformProject(session, (progress) => {
|
|
2175
|
+
logger.info(progress.message);
|
|
2296
2176
|
});
|
|
2297
|
-
} catch (error) {
|
|
2298
|
-
logger.error(error instanceof Error ? error.message : String(error));
|
|
2299
|
-
process.exit(1);
|
|
2300
2177
|
}
|
|
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
2178
|
const projectName = resolvePlatformProjectDirectoryName(project, requestedProjectName);
|
|
2307
2179
|
const projectPackageManager = resolvePlatformProjectPackageManager(project.package_manager, pm);
|
|
2308
2180
|
const projectPath = path7.join(cwd, projectName);
|
|
@@ -2311,28 +2183,77 @@ async function runPlatformInit(projectNameArg, options) {
|
|
|
2311
2183
|
process.exit(1);
|
|
2312
2184
|
}
|
|
2313
2185
|
logger.success("Browser setup complete.");
|
|
2314
|
-
logger.info(`Cloning ${project
|
|
2315
|
-
await runCommand("git",
|
|
2186
|
+
logger.info(`Cloning ${cloneDisplayUrl(project)}...`);
|
|
2187
|
+
await runCommand("git", gitCloneArgs(project, projectName), cwd);
|
|
2188
|
+
if (project.git_extra_header && project.repo_html_url) {
|
|
2189
|
+
await runCommand("git", ["remote", "set-url", "origin", project.repo_html_url], projectPath);
|
|
2190
|
+
}
|
|
2191
|
+
const supportFiles2 = writeStandardAgentsSupportFiles(projectPath, {
|
|
2192
|
+
projectName: project.name || projectName,
|
|
2193
|
+
packageManager: projectPackageManager
|
|
2194
|
+
});
|
|
2195
|
+
if (supportFiles2.length > 0) {
|
|
2196
|
+
logger.success(`Wrote generated local support files: ${supportFiles2.join(", ")}.`);
|
|
2197
|
+
}
|
|
2316
2198
|
const envPath = writeStandardAgentsEnv(projectPath, {
|
|
2317
2199
|
apiKey: project.api_key,
|
|
2318
2200
|
platformEndpoint: endpoint
|
|
2319
2201
|
});
|
|
2320
2202
|
logger.success(`Wrote Standard Agents credentials to ${path7.relative(cwd, envPath)}.`);
|
|
2203
|
+
if (project.git_extra_header) {
|
|
2204
|
+
await configurePlatformGitCredentialHelper(projectPath);
|
|
2205
|
+
logger.success("Configured git credentials for the platform repository.");
|
|
2206
|
+
}
|
|
2321
2207
|
const linkedPackages = preparePlatformProjectDependencies(projectPath, projectPackageManager);
|
|
2322
2208
|
if (linkedPackages.length > 0) {
|
|
2323
2209
|
logger.info(`Workspace mode detected: linked ${linkedPackages.length} Standard Agents packages locally.`);
|
|
2324
2210
|
}
|
|
2325
2211
|
logger.info(`Installing dependencies with ${projectPackageManager}...`);
|
|
2326
2212
|
await runCommand(projectPackageManager, ["install"], projectPath);
|
|
2213
|
+
const repoUrl = project.repo_html_url ?? project.repo_clone_url;
|
|
2214
|
+
const tokenLocation = path7.relative(cwd, envPath);
|
|
2215
|
+
if (options.dev === false) {
|
|
2216
|
+
logger.success("Your Standard Agents instance is ready.");
|
|
2217
|
+
logger.log(`Repository: ${repoUrl}`);
|
|
2218
|
+
logger.log(`Local token: ${tokenLocation}`);
|
|
2219
|
+
logger.log("");
|
|
2220
|
+
logger.log("Start it whenever you like:");
|
|
2221
|
+
logger.log(` cd ${projectName}`);
|
|
2222
|
+
logger.log(` ${devCommandHint(projectPackageManager)}`);
|
|
2223
|
+
return;
|
|
2224
|
+
}
|
|
2327
2225
|
const devPort = await findAvailablePort(5173);
|
|
2328
2226
|
const devUrl = `http://127.0.0.1:${devPort}`;
|
|
2329
2227
|
logger.info(`Starting local dev server at ${devUrl}...`);
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2228
|
+
const { logPath } = startDetachedDevServer(
|
|
2229
|
+
projectPackageManager,
|
|
2230
|
+
buildDevServerCommand(projectPackageManager, devPort),
|
|
2231
|
+
projectPath
|
|
2232
|
+
);
|
|
2233
|
+
const ready = await waitForLocalDevServer(devUrl);
|
|
2234
|
+
if (ready) {
|
|
2235
|
+
openUrl(devUrl);
|
|
2236
|
+
logger.success("Project is connected to Standard Agents.");
|
|
2237
|
+
logger.log(`Repository: ${repoUrl}`);
|
|
2238
|
+
logger.log(`Dev server: ${devUrl}`);
|
|
2239
|
+
logger.log(`Local token: ${tokenLocation}`);
|
|
2240
|
+
return;
|
|
2241
|
+
}
|
|
2242
|
+
logger.warning(`The dev server didn't respond at ${devUrl} within 60s.`);
|
|
2243
|
+
const tail = readLogTail(logPath);
|
|
2244
|
+
if (tail) {
|
|
2245
|
+
logger.log("");
|
|
2246
|
+
logger.log(`Last dev server output (full log: ${path7.relative(cwd, logPath)}):`);
|
|
2247
|
+
logger.log(tail);
|
|
2248
|
+
}
|
|
2249
|
+
logger.log("");
|
|
2250
|
+
logger.success("Your Standard Agents instance is cloned, configured, and ready.");
|
|
2251
|
+
logger.log(`Repository: ${repoUrl}`);
|
|
2252
|
+
logger.log(`Local token: ${tokenLocation}`);
|
|
2253
|
+
logger.log("");
|
|
2254
|
+
logger.log("Once any error above is resolved, start it with:");
|
|
2255
|
+
logger.log(` cd ${projectName}`);
|
|
2256
|
+
logger.log(` ${devCommandHint(projectPackageManager)}`);
|
|
2336
2257
|
}
|
|
2337
2258
|
async function init(projectNameArg, options = {}) {
|
|
2338
2259
|
if (!options.local) {
|
|
@@ -2625,17 +2546,10 @@ export default defineConfig({
|
|
|
2625
2546
|
}
|
|
2626
2547
|
try {
|
|
2627
2548
|
const installCmd = pm === "npm" ? "install" : "add";
|
|
2628
|
-
const devFlag = pm === "npm" ? "--save-dev" : "-D";
|
|
2629
2549
|
if (packageSpecifier === "workspace:*") {
|
|
2630
2550
|
logInfo("Using local workspace @standardagents/* packages (workspace:*).");
|
|
2631
2551
|
}
|
|
2632
2552
|
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
2553
|
const standardAgentsPackage = (packageName) => `${packageName}@${resolveStandardAgentsPackageSpecifier(packageName, packageSpecifier)}`;
|
|
2640
2554
|
const deps = [
|
|
2641
2555
|
standardAgentsPackage("@standardagents/builder"),
|
|
@@ -2752,14 +2666,6 @@ export default defineConfig({
|
|
|
2752
2666
|
logSuccess("Added .dev.vars to .gitignore");
|
|
2753
2667
|
}
|
|
2754
2668
|
}
|
|
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
2669
|
const nextRunCommand = resolvePostInitRunCommand(pm, projectPath, packageSpecifier === "workspace:*");
|
|
2764
2670
|
if (initTuiMode) {
|
|
2765
2671
|
clearTerminalScreen();
|
|
@@ -2856,8 +2762,19 @@ async function loginWithBootstrap(projectPath, options, fetchImpl = fetch) {
|
|
|
2856
2762
|
}
|
|
2857
2763
|
throw new Error("Bootstrap code required. Run: npx @standardagents/cli login --bootstrap <code>");
|
|
2858
2764
|
}
|
|
2765
|
+
const state = await consumeBootstrapLogin({ ...options, endpoint, bootstrap: bootstrapCode }, fetchImpl);
|
|
2766
|
+
persistBootstrapState(projectPath, state);
|
|
2767
|
+
syncProjectAuthEnv(projectPath, endpoint, state);
|
|
2768
|
+
return { state, reused: false };
|
|
2769
|
+
}
|
|
2770
|
+
async function consumeBootstrapLogin(options, fetchImpl = fetch) {
|
|
2771
|
+
const endpoint = resolvePlatformEndpoint({ endpoint: options.endpoint });
|
|
2772
|
+
const bootstrapCode = options.bootstrap?.trim();
|
|
2773
|
+
if (!bootstrapCode) {
|
|
2774
|
+
throw new Error("Bootstrap code required. Run: npx @standardagents/cli login --bootstrap <code>");
|
|
2775
|
+
}
|
|
2859
2776
|
const consumed = await exchangeBootstrapCode(endpoint, bootstrapCode, fetchImpl);
|
|
2860
|
-
|
|
2777
|
+
return {
|
|
2861
2778
|
version: 1,
|
|
2862
2779
|
endpoint,
|
|
2863
2780
|
authenticated_at: Date.now(),
|
|
@@ -2865,9 +2782,6 @@ async function loginWithBootstrap(projectPath, options, fetchImpl = fetch) {
|
|
|
2865
2782
|
user: consumed.user,
|
|
2866
2783
|
account: consumed.account
|
|
2867
2784
|
};
|
|
2868
|
-
persistBootstrapState(projectPath, state);
|
|
2869
|
-
syncProjectAuthEnv(projectPath, endpoint, state);
|
|
2870
|
-
return { state, reused: false };
|
|
2871
2785
|
}
|
|
2872
2786
|
async function loginWithPlatform(options) {
|
|
2873
2787
|
const endpoint = resolvePlatformEndpoint({ endpoint: options.endpoint });
|
|
@@ -3050,12 +2964,31 @@ function readCliAuthState() {
|
|
|
3050
2964
|
const parsed = JSON.parse(fs3.readFileSync(file, "utf8"));
|
|
3051
2965
|
return {
|
|
3052
2966
|
active_org_id: parsed.active_org_id ?? null,
|
|
3053
|
-
orgs: parsed.orgs ?? {}
|
|
2967
|
+
orgs: parsed.orgs ?? {},
|
|
2968
|
+
git_auth: parseCliGitAuthRecord(parsed.git_auth)
|
|
3054
2969
|
};
|
|
3055
2970
|
} catch {
|
|
3056
2971
|
return { active_org_id: null, orgs: {} };
|
|
3057
2972
|
}
|
|
3058
2973
|
}
|
|
2974
|
+
function parseCliGitAuthRecord(value) {
|
|
2975
|
+
if (!value || typeof value !== "object") return null;
|
|
2976
|
+
const candidate = value;
|
|
2977
|
+
if (candidate.version !== 1) return null;
|
|
2978
|
+
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") {
|
|
2979
|
+
return null;
|
|
2980
|
+
}
|
|
2981
|
+
return {
|
|
2982
|
+
version: 1,
|
|
2983
|
+
endpoint: candidate.endpoint,
|
|
2984
|
+
session_cookie: candidate.session_cookie,
|
|
2985
|
+
account_id: candidate.account_id,
|
|
2986
|
+
account_slug: typeof candidate.account_slug === "string" ? candidate.account_slug : void 0,
|
|
2987
|
+
user_id: candidate.user_id,
|
|
2988
|
+
user_email: candidate.user_email,
|
|
2989
|
+
updated_at: candidate.updated_at
|
|
2990
|
+
};
|
|
2991
|
+
}
|
|
3059
2992
|
function writeCliAuthState(state) {
|
|
3060
2993
|
ensureStateDir();
|
|
3061
2994
|
fs3.writeFileSync(stateFilePath(), JSON.stringify(state, null, 2) + "\n", "utf8");
|
|
@@ -3064,6 +2997,25 @@ function hasStoredCliAuth() {
|
|
|
3064
2997
|
const state = readCliAuthState();
|
|
3065
2998
|
return Object.keys(state.orgs).length > 0;
|
|
3066
2999
|
}
|
|
3000
|
+
function saveCliGitAuth(input) {
|
|
3001
|
+
const state = readCliAuthState();
|
|
3002
|
+
const record = {
|
|
3003
|
+
version: 1,
|
|
3004
|
+
endpoint: input.endpoint.replace(/\/+$/, ""),
|
|
3005
|
+
session_cookie: input.sessionCookie,
|
|
3006
|
+
account_id: input.account.id,
|
|
3007
|
+
account_slug: input.account.slug,
|
|
3008
|
+
user_id: input.user.id,
|
|
3009
|
+
user_email: input.user.email,
|
|
3010
|
+
updated_at: Date.now()
|
|
3011
|
+
};
|
|
3012
|
+
state.git_auth = record;
|
|
3013
|
+
writeCliAuthState(state);
|
|
3014
|
+
return record;
|
|
3015
|
+
}
|
|
3016
|
+
function resolveCliGitAuth() {
|
|
3017
|
+
return readCliAuthState().git_auth ?? null;
|
|
3018
|
+
}
|
|
3067
3019
|
function resolveTargetOrgId(state, orgInput) {
|
|
3068
3020
|
if (orgInput) {
|
|
3069
3021
|
const trimmed = orgInput.trim();
|
|
@@ -3948,14 +3900,14 @@ async function pack(agentName, options) {
|
|
|
3948
3900
|
sharedWith: agent.sharedWith
|
|
3949
3901
|
});
|
|
3950
3902
|
}
|
|
3951
|
-
for (const
|
|
3903
|
+
for (const prompt5 of analysis.constituents.prompts) {
|
|
3952
3904
|
selectionItems.push({
|
|
3953
|
-
name:
|
|
3905
|
+
name: prompt5.name,
|
|
3954
3906
|
type: "prompt",
|
|
3955
|
-
filePath:
|
|
3956
|
-
mode:
|
|
3957
|
-
isShared:
|
|
3958
|
-
sharedWith:
|
|
3907
|
+
filePath: prompt5.filePath,
|
|
3908
|
+
mode: prompt5.sharedWith.length > 0 ? "copy" : "extract",
|
|
3909
|
+
isShared: prompt5.sharedWith.length > 0,
|
|
3910
|
+
sharedWith: prompt5.sharedWith
|
|
3959
3911
|
});
|
|
3960
3912
|
}
|
|
3961
3913
|
for (const tool of analysis.constituents.tools) {
|
|
@@ -4163,349 +4115,74 @@ async function listPacked() {
|
|
|
4163
4115
|
console.log("");
|
|
4164
4116
|
}
|
|
4165
4117
|
}
|
|
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");
|
|
4118
|
+
var ARTIFACT_DEPLOY_REMOTE_NAME = "origin";
|
|
4119
|
+
function normalizeGitRemoteHost(remote) {
|
|
4120
|
+
try {
|
|
4121
|
+
return new URL(remote).hostname.toLowerCase();
|
|
4122
|
+
} catch {
|
|
4123
|
+
return null;
|
|
4224
4124
|
}
|
|
4225
|
-
return "Unknown error";
|
|
4226
4125
|
}
|
|
4227
|
-
function
|
|
4228
|
-
const
|
|
4229
|
-
|
|
4230
|
-
return
|
|
4126
|
+
function isStandardAgentsArtifactRemote(remote) {
|
|
4127
|
+
const host = normalizeGitRemoteHost(remote);
|
|
4128
|
+
if (!host) return false;
|
|
4129
|
+
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";
|
|
4231
4130
|
}
|
|
4232
|
-
function
|
|
4233
|
-
|
|
4234
|
-
|
|
4235
|
-
|
|
4131
|
+
function gitOutput(args) {
|
|
4132
|
+
return execFileSync("git", args, {
|
|
4133
|
+
encoding: "utf-8",
|
|
4134
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
4135
|
+
}).trim();
|
|
4236
4136
|
}
|
|
4237
|
-
function
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
function authHeadersForDeploy(auth) {
|
|
4241
|
-
if (auth.kind === "session-cookie") {
|
|
4242
|
-
return { Cookie: auth.cookie };
|
|
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) {
|
|
4137
|
+
function resolveArtifactGitDeployTarget(runner = gitOutput, remoteName = ARTIFACT_DEPLOY_REMOTE_NAME) {
|
|
4138
|
+
const remoteUrl = runner(["remote", "get-url", remoteName]).trim();
|
|
4139
|
+
if (!isStandardAgentsArtifactRemote(remoteUrl)) {
|
|
4267
4140
|
throw new Error(
|
|
4268
|
-
"
|
|
4141
|
+
`Remote "${remoteName}" is not a Standard Agents Artifacts remote. Deployments now run from pushes to platform-owned repositories.`
|
|
4269
4142
|
);
|
|
4270
4143
|
}
|
|
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;
|
|
4334
|
-
}
|
|
4335
|
-
throw new Error(
|
|
4336
|
-
"Could not find Worker bundle in build output.\nExpected build output in .wrangler/tmp/ or dist/.\nMake sure `vite build` completed successfully."
|
|
4337
|
-
);
|
|
4338
|
-
}
|
|
4339
|
-
function findBundleInDir(dir) {
|
|
4340
|
-
const entries = fs3.readdirSync(dir, { withFileTypes: true });
|
|
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}`);
|
|
4144
|
+
const branch = runner(["rev-parse", "--abbrev-ref", "HEAD"]).trim();
|
|
4145
|
+
if (!branch || branch === "HEAD") {
|
|
4146
|
+
throw new Error("Cannot deploy from a detached HEAD. Check out a branch before pushing.");
|
|
4369
4147
|
}
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
);
|
|
4377
|
-
}
|
|
4378
|
-
return manifest;
|
|
4148
|
+
return {
|
|
4149
|
+
remoteName,
|
|
4150
|
+
remoteUrl,
|
|
4151
|
+
branch,
|
|
4152
|
+
refspec: `HEAD:${branch}`
|
|
4153
|
+
};
|
|
4379
4154
|
}
|
|
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
|
|
4155
|
+
function pushArtifactRemote(target) {
|
|
4156
|
+
execFileSync("git", ["push", target.remoteName, target.refspec], {
|
|
4157
|
+
stdio: "inherit"
|
|
4390
4158
|
});
|
|
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
4159
|
}
|
|
4403
|
-
async function deploy(
|
|
4160
|
+
async function deploy() {
|
|
4404
4161
|
console.log("");
|
|
4405
4162
|
logger.info(`${chalk.bold("Standard Agents Deploy")}
|
|
4406
4163
|
`);
|
|
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;
|
|
4164
|
+
let target;
|
|
4414
4165
|
try {
|
|
4415
|
-
|
|
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...");
|
|
4488
|
-
try {
|
|
4489
|
-
const result = await uploadDeploy(endpoint, auth, bundleContent, manifest, builderVersion);
|
|
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("");
|
|
4166
|
+
target = resolveArtifactGitDeployTarget();
|
|
4499
4167
|
} catch (err) {
|
|
4500
4168
|
logger.error(err.message);
|
|
4169
|
+
logger.info("Run this command from a clone created by Standard Agents, or push to the platform git remote manually.");
|
|
4501
4170
|
process.exit(1);
|
|
4502
4171
|
}
|
|
4172
|
+
logger.info("Deployments build on the Standard Agents platform from Artifacts git pushes.");
|
|
4173
|
+
logger.log(`Remote: ${target.remoteUrl}`);
|
|
4174
|
+
logger.log(`Branch: ${target.branch}`);
|
|
4175
|
+
logger.log("");
|
|
4176
|
+
pushArtifactRemote(target);
|
|
4177
|
+
logger.success("Push complete. The platform build runner will deploy this commit from the Artifacts push event.");
|
|
4503
4178
|
}
|
|
4504
4179
|
var PROJECT_SIGNAL_PATHS = [
|
|
4505
4180
|
".agents",
|
|
4506
|
-
"
|
|
4507
|
-
"
|
|
4508
|
-
"
|
|
4181
|
+
"agents",
|
|
4182
|
+
"vite.config.ts",
|
|
4183
|
+
"vite.config.js",
|
|
4184
|
+
"vite.config.mts",
|
|
4185
|
+
"vite.config.mjs"
|
|
4509
4186
|
];
|
|
4510
4187
|
function hasProjectSignals(cwd) {
|
|
4511
4188
|
const hits = PROJECT_SIGNAL_PATHS.filter((signal) => fs3.existsSync(path7.join(cwd, signal))).length;
|
|
@@ -4568,7 +4245,7 @@ function getHomeActions(context) {
|
|
|
4568
4245
|
{
|
|
4569
4246
|
id: "deploy",
|
|
4570
4247
|
label: "Deploy",
|
|
4571
|
-
description: "
|
|
4248
|
+
description: "Push this linked project to StandardAgents for a platform build.",
|
|
4572
4249
|
argv: ["deploy"]
|
|
4573
4250
|
},
|
|
4574
4251
|
{
|
|
@@ -4924,7 +4601,7 @@ function isOpaqueModelId(modelId) {
|
|
|
4924
4601
|
function getProviderDefinition(name) {
|
|
4925
4602
|
return PROVIDER_DEFINITIONS.find((provider) => provider.name === name);
|
|
4926
4603
|
}
|
|
4927
|
-
function
|
|
4604
|
+
function parseEnvFile(content) {
|
|
4928
4605
|
const result = {};
|
|
4929
4606
|
for (const line of content.split("\n")) {
|
|
4930
4607
|
const trimmed = line.trim();
|
|
@@ -5028,7 +4705,7 @@ function loadProjectEnv(projectRoot, processEnv = process.env) {
|
|
|
5028
4705
|
for (const fileName of envFiles) {
|
|
5029
4706
|
const filePath = path7.join(projectRoot, fileName);
|
|
5030
4707
|
if (!fs3.existsSync(filePath)) continue;
|
|
5031
|
-
Object.assign(result,
|
|
4708
|
+
Object.assign(result, parseEnvFile(fs3.readFileSync(filePath, "utf8")));
|
|
5032
4709
|
}
|
|
5033
4710
|
for (const [key, value] of Object.entries(processEnv)) {
|
|
5034
4711
|
if (typeof value === "string") {
|
|
@@ -5279,6 +4956,224 @@ async function availableModels(options = {}) {
|
|
|
5279
4956
|
writeError(message);
|
|
5280
4957
|
}
|
|
5281
4958
|
}
|
|
4959
|
+
function parseKeyValueLines(input) {
|
|
4960
|
+
const result = {};
|
|
4961
|
+
for (const line of input.split(/\r?\n/)) {
|
|
4962
|
+
if (!line.trim()) continue;
|
|
4963
|
+
const index = line.indexOf("=");
|
|
4964
|
+
if (index <= 0) continue;
|
|
4965
|
+
result[line.slice(0, index)] = line.slice(index + 1);
|
|
4966
|
+
}
|
|
4967
|
+
return result;
|
|
4968
|
+
}
|
|
4969
|
+
function findDotDevVars(startDir = process.cwd()) {
|
|
4970
|
+
let current = path7.resolve(startDir);
|
|
4971
|
+
while (true) {
|
|
4972
|
+
const candidate = path7.join(current, ".dev.vars");
|
|
4973
|
+
if (fs3.existsSync(candidate)) return candidate;
|
|
4974
|
+
const parent = path7.dirname(current);
|
|
4975
|
+
if (parent === current) return null;
|
|
4976
|
+
current = parent;
|
|
4977
|
+
}
|
|
4978
|
+
}
|
|
4979
|
+
function normalizeEndpoint(value) {
|
|
4980
|
+
return value.replace(/\/+$/, "");
|
|
4981
|
+
}
|
|
4982
|
+
function normalizeGitHost(host) {
|
|
4983
|
+
return host.trim().toLowerCase().replace(/:\d+$/, "");
|
|
4984
|
+
}
|
|
4985
|
+
function isStandardAgentsGitHost(host) {
|
|
4986
|
+
const normalized = normalizeGitHost(host);
|
|
4987
|
+
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";
|
|
4988
|
+
}
|
|
4989
|
+
function loadLocalConfig(options) {
|
|
4990
|
+
const envPath = findDotDevVars(options.startDir);
|
|
4991
|
+
const fileVars = envPath ? parseKeyValueLines(fs3.readFileSync(envPath, "utf-8")) : {};
|
|
4992
|
+
const endpoint = normalizeEndpoint(
|
|
4993
|
+
options.endpoint || process.env.STANDARD_AGENTS_API_URL || process.env.PLATFORM_ENDPOINT || fileVars.STANDARD_AGENTS_API_URL || fileVars.PLATFORM_ENDPOINT || ""
|
|
4994
|
+
);
|
|
4995
|
+
const apiKey = process.env.STANDARD_AGENTS_API_KEY || fileVars.STANDARD_AGENTS_API_KEY || "";
|
|
4996
|
+
if (endpoint && apiKey) {
|
|
4997
|
+
return { endpoint, auth: { kind: "api-key", apiKey } };
|
|
4998
|
+
}
|
|
4999
|
+
const cookie = process.env.STANDARD_AGENTS_SESSION_COOKIE || process.env.STANDARDAGENTS_BOOTSTRAP_SESSION_COOKIE || fileVars.STANDARDAGENTS_BOOTSTRAP_SESSION_COOKIE || "";
|
|
5000
|
+
if (endpoint && cookie) {
|
|
5001
|
+
return { endpoint, auth: { kind: "session-cookie", cookie } };
|
|
5002
|
+
}
|
|
5003
|
+
const globalAuth = resolveCliGitAuth();
|
|
5004
|
+
if (!globalAuth) return null;
|
|
5005
|
+
const requestedEndpoint = endpoint || normalizeEndpoint(options.endpoint || "");
|
|
5006
|
+
if (requestedEndpoint && requestedEndpoint !== globalAuth.endpoint) {
|
|
5007
|
+
return null;
|
|
5008
|
+
}
|
|
5009
|
+
return {
|
|
5010
|
+
endpoint: globalAuth.endpoint,
|
|
5011
|
+
auth: { kind: "session-cookie", cookie: globalAuth.session_cookie }
|
|
5012
|
+
};
|
|
5013
|
+
}
|
|
5014
|
+
function remoteFromCredentialRequest(request) {
|
|
5015
|
+
if (!request.protocol || !request.host) return null;
|
|
5016
|
+
if (!isStandardAgentsGitHost(request.host)) return null;
|
|
5017
|
+
const repoPath = request.path ? `/${request.path.replace(/^\/+/, "")}` : "";
|
|
5018
|
+
return `${request.protocol}://${normalizeGitHost(request.host)}${repoPath}`;
|
|
5019
|
+
}
|
|
5020
|
+
async function readStdin() {
|
|
5021
|
+
const chunks = [];
|
|
5022
|
+
for await (const chunk of process.stdin) {
|
|
5023
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk)));
|
|
5024
|
+
}
|
|
5025
|
+
return Buffer.concat(chunks).toString("utf-8");
|
|
5026
|
+
}
|
|
5027
|
+
async function gitCredential(operation, options = {}) {
|
|
5028
|
+
if (operation !== "get") return;
|
|
5029
|
+
const config = loadLocalConfig(options);
|
|
5030
|
+
if (!config) return;
|
|
5031
|
+
const input = options.input ?? await readStdin();
|
|
5032
|
+
const remote = remoteFromCredentialRequest(parseKeyValueLines(input));
|
|
5033
|
+
if (!remote) return;
|
|
5034
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
5035
|
+
const headers = {
|
|
5036
|
+
"Content-Type": "application/json"
|
|
5037
|
+
};
|
|
5038
|
+
if (config.auth.kind === "api-key") {
|
|
5039
|
+
headers.Authorization = `Bearer ${config.auth.apiKey}`;
|
|
5040
|
+
} else {
|
|
5041
|
+
headers.Cookie = config.auth.cookie;
|
|
5042
|
+
}
|
|
5043
|
+
const response = await fetchImpl(`${config.endpoint}/projects/git-token`, {
|
|
5044
|
+
method: "POST",
|
|
5045
|
+
headers,
|
|
5046
|
+
body: JSON.stringify({ remote, scope: "write" })
|
|
5047
|
+
}).catch(() => null);
|
|
5048
|
+
if (!response?.ok) return;
|
|
5049
|
+
const body = await response.json().catch(() => null);
|
|
5050
|
+
const tokenSecret = body?.artifact_git?.token_secret;
|
|
5051
|
+
if (!tokenSecret) return;
|
|
5052
|
+
const write = options.write ?? ((text) => {
|
|
5053
|
+
process.stdout.write(text);
|
|
5054
|
+
});
|
|
5055
|
+
write(`username=x
|
|
5056
|
+
password=${tokenSecret}
|
|
5057
|
+
|
|
5058
|
+
`);
|
|
5059
|
+
}
|
|
5060
|
+
var DEFAULT_GIT_HELPER_COMMAND = "!npx -y @standardagents/cli@latest git-credential";
|
|
5061
|
+
function prompt4(question) {
|
|
5062
|
+
const rl = readline.createInterface({
|
|
5063
|
+
input: process.stdin,
|
|
5064
|
+
output: process.stdout
|
|
5065
|
+
});
|
|
5066
|
+
return new Promise((resolve) => {
|
|
5067
|
+
rl.question(question, (answer) => {
|
|
5068
|
+
rl.close();
|
|
5069
|
+
resolve(answer.trim());
|
|
5070
|
+
});
|
|
5071
|
+
});
|
|
5072
|
+
}
|
|
5073
|
+
function defaultGitRunner(args) {
|
|
5074
|
+
const result = spawnSync("git", args, { encoding: "utf8" });
|
|
5075
|
+
return {
|
|
5076
|
+
status: result.status,
|
|
5077
|
+
stdout: result.stdout || "",
|
|
5078
|
+
stderr: result.stderr || ""
|
|
5079
|
+
};
|
|
5080
|
+
}
|
|
5081
|
+
function runGit(args, runner) {
|
|
5082
|
+
const result = runner(args);
|
|
5083
|
+
if (result.status !== 0) {
|
|
5084
|
+
throw new Error(result.stderr.trim() || `git ${args.join(" ")} failed`);
|
|
5085
|
+
}
|
|
5086
|
+
return result;
|
|
5087
|
+
}
|
|
5088
|
+
function configureStandardAgentsGitCredentials(options = {}) {
|
|
5089
|
+
const runner = options.gitRunner ?? defaultGitRunner;
|
|
5090
|
+
const helperCommand = options.helperCommand?.trim() || process.env.STANDARD_AGENTS_GIT_HELPER || DEFAULT_GIT_HELPER_COMMAND;
|
|
5091
|
+
const existing = runGit(["config", "--global", "--get-all", "credential.helper"], runner).stdout.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
5092
|
+
let helperAdded = false;
|
|
5093
|
+
if (!existing.includes(helperCommand)) {
|
|
5094
|
+
runGit(["config", "--global", "--add", "credential.helper", helperCommand], runner);
|
|
5095
|
+
helperAdded = true;
|
|
5096
|
+
}
|
|
5097
|
+
runGit(["config", "--global", "credential.useHttpPath", "true"], runner);
|
|
5098
|
+
return { helperCommand, helperAdded };
|
|
5099
|
+
}
|
|
5100
|
+
async function completeBrowserGitLogin(options, endpoint) {
|
|
5101
|
+
let authAppUrl = resolvePlatformAuthBrowserUrl(endpoint);
|
|
5102
|
+
let sessionId = null;
|
|
5103
|
+
let wsUrl = null;
|
|
5104
|
+
let wsExpiresAt = 0;
|
|
5105
|
+
try {
|
|
5106
|
+
const started = await startCliAuthSession(endpoint);
|
|
5107
|
+
sessionId = started.session_id;
|
|
5108
|
+
authAppUrl = started.auth_url;
|
|
5109
|
+
wsUrl = started.ws_url;
|
|
5110
|
+
wsExpiresAt = started.expires_at;
|
|
5111
|
+
} catch (error) {
|
|
5112
|
+
const message = error instanceof Error ? error.message : "Failed to start realtime auth session";
|
|
5113
|
+
logger.warning(`${message} Switching to manual bootstrap command entry.`);
|
|
5114
|
+
}
|
|
5115
|
+
logger.log(`Auth app: ${authAppUrl}`);
|
|
5116
|
+
if (options.open !== false) {
|
|
5117
|
+
const opened = openBrowser(authAppUrl);
|
|
5118
|
+
if (opened) {
|
|
5119
|
+
logger.info("Opened browser for authentication.");
|
|
5120
|
+
} else {
|
|
5121
|
+
logger.warning("Could not automatically open browser. Open the URL above manually.");
|
|
5122
|
+
}
|
|
5123
|
+
}
|
|
5124
|
+
if (wsUrl && wsExpiresAt > 0) {
|
|
5125
|
+
try {
|
|
5126
|
+
const completion = await waitForCliAuthCompletion(wsUrl, wsExpiresAt);
|
|
5127
|
+
return consumeBootstrapLogin({ ...options, endpoint, bootstrap: completion.bootstrapCode });
|
|
5128
|
+
} catch (error) {
|
|
5129
|
+
const message = error instanceof Error ? error.message : "Realtime auth handoff failed";
|
|
5130
|
+
logger.warning(`${message} Enter bootstrap code manually to continue.`);
|
|
5131
|
+
}
|
|
5132
|
+
}
|
|
5133
|
+
if (!process.stdin.isTTY) {
|
|
5134
|
+
throw new Error("Non-interactive shell detected. Run: npx @standardagents/cli git-login --bootstrap <code>");
|
|
5135
|
+
}
|
|
5136
|
+
const input = await prompt4("Bootstrap code or command: ");
|
|
5137
|
+
const bootstrapCode = parseBootstrapCodeInput(input);
|
|
5138
|
+
if (!bootstrapCode) {
|
|
5139
|
+
if (sessionId) {
|
|
5140
|
+
await cancelCliAuthSession(endpoint, sessionId);
|
|
5141
|
+
}
|
|
5142
|
+
throw new Error("No bootstrap code provided. Run: npx @standardagents/cli git-login --bootstrap <code>");
|
|
5143
|
+
}
|
|
5144
|
+
if (sessionId) {
|
|
5145
|
+
await cancelCliAuthSession(endpoint, sessionId);
|
|
5146
|
+
}
|
|
5147
|
+
return consumeBootstrapLogin({ ...options, endpoint, bootstrap: bootstrapCode });
|
|
5148
|
+
}
|
|
5149
|
+
async function gitLogin(options = {}) {
|
|
5150
|
+
const endpoint = resolvePlatformEndpoint({ endpoint: options.endpoint });
|
|
5151
|
+
logger.log("");
|
|
5152
|
+
logger.info("Starting Standard Agents Git authentication...");
|
|
5153
|
+
logger.log(`Platform API: ${endpoint}`);
|
|
5154
|
+
const state = options.bootstrap?.trim() ? await consumeBootstrapLogin({ ...options, endpoint, bootstrap: options.bootstrap.trim() }) : await completeBrowserGitLogin(options, endpoint);
|
|
5155
|
+
if (!state.session_cookie) {
|
|
5156
|
+
throw new Error("Platform login did not return a session cookie for Git authentication.");
|
|
5157
|
+
}
|
|
5158
|
+
const record = saveCliGitAuth({
|
|
5159
|
+
endpoint,
|
|
5160
|
+
sessionCookie: state.session_cookie,
|
|
5161
|
+
account: state.account,
|
|
5162
|
+
user: state.user
|
|
5163
|
+
});
|
|
5164
|
+
let configured = null;
|
|
5165
|
+
if (options.config !== false) {
|
|
5166
|
+
configured = configureStandardAgentsGitCredentials(options);
|
|
5167
|
+
}
|
|
5168
|
+
logger.log("");
|
|
5169
|
+
logger.success("Git authentication configured.");
|
|
5170
|
+
logger.log(`Account: ${record.account_id}${record.account_slug ? ` (${record.account_slug})` : ""}`);
|
|
5171
|
+
logger.log(`User: ${record.user_email}`);
|
|
5172
|
+
if (configured) {
|
|
5173
|
+
logger.log(`Credential helper: ${configured.helperCommand}${configured.helperAdded ? "" : " (already installed)"}`);
|
|
5174
|
+
}
|
|
5175
|
+
logger.log("");
|
|
5176
|
+
}
|
|
5282
5177
|
|
|
5283
5178
|
// src/index.ts
|
|
5284
5179
|
async function settleStdinForInitHandoff(stdin = process.stdin) {
|
|
@@ -5299,8 +5194,8 @@ async function settleStdinForInitHandoff(stdin = process.stdin) {
|
|
|
5299
5194
|
}
|
|
5300
5195
|
}
|
|
5301
5196
|
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);
|
|
5197
|
+
program.name("agents").description("CLI tool for Standard Agents / AgentBuilder").version("0.16.0");
|
|
5198
|
+
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
5199
|
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
5200
|
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
5201
|
program.command("scaffold").description("Add Standard Agents to an existing Vite project").option("--force", "Overwrite existing configuration").action(scaffold);
|
|
@@ -5308,7 +5203,10 @@ program.command("init-chat [project-name]").description("Scaffold a frontend cha
|
|
|
5308
5203
|
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
5204
|
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
5205
|
program.command("list-packed").description("List all discovered packed agents").action(listPacked);
|
|
5311
|
-
program.command("deploy").description("
|
|
5206
|
+
program.command("deploy").description("Push the current branch to the Standard Agents Artifacts remote").action(deploy);
|
|
5207
|
+
program.command("git-credential <operation>").description("Git credential helper for Standard Agents platform repositories").option("--endpoint <url>", "Platform API endpoint").action(gitCredential);
|
|
5208
|
+
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);
|
|
5209
|
+
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
5210
|
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
5211
|
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
5212
|
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);
|