@standardagents/cli 0.13.2 → 0.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -10,7 +10,7 @@ import { parse, modify, applyEdits } from 'jsonc-parser';
10
10
  import { loadFile, writeFile, generateCode } from 'magicast';
11
11
  import { addVitePlugin } from 'magicast/helpers';
12
12
  import net from 'net';
13
- import { fileURLToPath } from 'url';
13
+ import { fileURLToPath, pathToFileURL } from 'url';
14
14
  import os from 'os';
15
15
  import { copySkill, readSkillFile } from '@standardagents/skill';
16
16
 
@@ -534,10 +534,10 @@ Agents orchestrate conversations by defining prompts, stop conditions, and turn
534
534
  | \`stopOnResponse\` | \`boolean\` | No | Stop turn when LLM returns text (default: true) |
535
535
  | \`stopTool\` | \`string\` | No | Tool that stops this side's turn |
536
536
  | \`stopToolResponseProperty\` | \`string\` | No | Property to extract from stop tool result |
537
- | \`endConversationTool\` | \`string\` | No | Tool that ends the entire conversation |
538
- | \`failSessionTool\` | \`string\` | No | Tool that fails and ends the entire conversation |
539
- | \`statusTool\` | \`string\` | No | Tool that reports subagent status to a parent registry |
540
- | \`maxTurns\` | \`number\` | No | Maximum turns for this side |
537
+ | \`maxSteps\` | \`number\` | No | Maximum step budget for this side |
538
+ | \`sessionStop\` | \`string \\| SessionToolBinding\` | No | Terminal success lifecycle binding |
539
+ | \`sessionFail\` | \`string \\| SessionToolBinding\` | No | Terminal failure lifecycle binding |
540
+ | \`sessionStatus\` | \`string \\| SessionToolBinding\` | No | Non-terminal status lifecycle binding |
541
541
  | \`manualStopCondition\` | \`boolean\` | No | Enable custom stop handling via hooks |
542
542
 
543
543
  ## Basic Example (AI-Human)
@@ -552,8 +552,8 @@ export default defineAgent({
552
552
  label: 'Support',
553
553
  prompt: 'customer_support',
554
554
  stopOnResponse: true,
555
- endConversationTool: 'close_ticket',
556
- maxTurns: 50,
555
+ sessionStop: 'close_ticket',
556
+ maxSteps: 50,
557
557
  },
558
558
  tags: ['support', 'tier-1'],
559
559
  });
@@ -597,9 +597,9 @@ export default defineAgent({
597
597
  sideA: {
598
598
  label: 'Worker',
599
599
  prompt: 'research_worker',
600
- statusTool: 'set_subagent_status',
601
- failSessionTool: 'fail_research_subagent',
602
- endConversationTool: 'finish_subagent',
600
+ sessionStatus: 'set_subagent_status',
601
+ sessionFail: 'fail_research_subagent',
602
+ sessionStop: 'finish_subagent',
603
603
  },
604
604
  sideB: {
605
605
  label: 'Reviewer',
@@ -629,10 +629,10 @@ Other prompts can then include the agent name in their \`tools\` array to enable
629
629
 
630
630
  ## Stop Conditions (Priority Order)
631
631
 
632
- 1. **failSessionTool** - Ends entire conversation with a terminal failure
633
- 2. **endConversationTool** - Ends entire conversation successfully
632
+ 1. **sessionFail** - Ends entire conversation with a terminal failure
633
+ 2. **sessionStop** - Ends entire conversation successfully
634
634
  3. **stopTool** - Ends current side's turn
635
- 4. **maxTurns** - Ends side's participation when reached
635
+ 4. **maxSteps** - Ends side execution when the safety budget is reached
636
636
  5. **stopOnResponse** - Ends turn when LLM returns text
637
637
  6. **maxSessionTurns** - Ends conversation (hard limit: 250)
638
638
 
@@ -662,7 +662,7 @@ This convention is enforced by the builder UI and makes agents easily identifiab
662
662
 
663
663
  - **Use descriptive names** (\`customer_support_agent\` not \`agent1\`)
664
664
  - **Always use the _agent suffix** - names like \`support_agent\`, \`research_agent\`
665
- - **Always set maxTurns** as a safety limit
665
+ - **Always set maxSteps or maxSessionTurns** as safety limits
666
666
  - **Match stop conditions to use case** - chat apps use stopOnResponse, workflows use stopTool
667
667
  - **Use labels** for clarity in logs and UI
668
668
  - **Organize with tags** for filtering
@@ -1278,13 +1278,15 @@ Full reference: https://docs.standardagentbuilder.com/core-concepts/api
1278
1278
  `;
1279
1279
 
1280
1280
  // src/commands/scaffold.ts
1281
+ function getScaffoldCompatibilityDate() {
1282
+ return "2025-08-13";
1283
+ }
1281
1284
  var WRANGLER_TEMPLATE = (name) => {
1282
- const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
1283
1285
  return `{
1284
1286
  "$schema": "node_modules/wrangler/config-schema.json",
1285
1287
  "name": "${name}",
1286
1288
  "main": "worker/index.ts",
1287
- "compatibility_date": "${today}",
1289
+ "compatibility_date": "${getScaffoldCompatibilityDate()}",
1288
1290
  "compatibility_flags": ["nodejs_compat"],
1289
1291
  "observability": {
1290
1292
  "enabled": true
@@ -1807,6 +1809,33 @@ function runCommand(command, args, cwd, env) {
1807
1809
  function toKebabCase(str) {
1808
1810
  return str.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
1809
1811
  }
1812
+ function findWorkspaceRoot(startDir) {
1813
+ let currentDir = startDir;
1814
+ while (true) {
1815
+ if (fs3.existsSync(path3.join(currentDir, "pnpm-workspace.yaml"))) {
1816
+ return currentDir;
1817
+ }
1818
+ const parentDir = path3.dirname(currentDir);
1819
+ if (parentDir === currentDir) {
1820
+ return null;
1821
+ }
1822
+ currentDir = parentDir;
1823
+ }
1824
+ }
1825
+ function getPnpmWorkspaceFilterTarget(projectPath) {
1826
+ if (process.env.STANDARDAGENTS_WORKSPACE !== "1") {
1827
+ return null;
1828
+ }
1829
+ const workspaceRoot = findWorkspaceRoot(projectPath);
1830
+ if (!workspaceRoot) {
1831
+ return null;
1832
+ }
1833
+ const relativeProjectPath = path3.relative(workspaceRoot, projectPath).split(path3.sep).join("/");
1834
+ return {
1835
+ cwd: workspaceRoot,
1836
+ filterTarget: relativeProjectPath.startsWith(".") ? relativeProjectPath : `./${relativeProjectPath}`
1837
+ };
1838
+ }
1810
1839
  function detectPackageManager() {
1811
1840
  const userAgent = process.env.npm_config_user_agent;
1812
1841
  if (userAgent) {
@@ -1820,15 +1849,62 @@ function detectPackageManager() {
1820
1849
  if (fs3.existsSync("package-lock.json")) return "npm";
1821
1850
  return "npm";
1822
1851
  }
1852
+ function normalizeScaffoldedPackageJson(packageJson, projectName, versions) {
1853
+ const normalized = { ...packageJson };
1854
+ normalized.name = toKebabCase(projectName);
1855
+ normalized.devDependencies = {
1856
+ ...normalized.devDependencies || {},
1857
+ vite: versions.vite,
1858
+ typescript: versions.typescript,
1859
+ "@cloudflare/vite-plugin": versions.cloudflareVitePlugin,
1860
+ wrangler: versions.wrangler
1861
+ };
1862
+ return normalized;
1863
+ }
1864
+ function applyPackageSpecifiers(packageJson, key, specifiers) {
1865
+ packageJson[key] = {
1866
+ ...packageJson[key] || {}
1867
+ };
1868
+ for (const specifier of specifiers) {
1869
+ const atIndex = specifier.lastIndexOf("@");
1870
+ if (atIndex <= 0) {
1871
+ packageJson[key][specifier] = "^4.0.0";
1872
+ continue;
1873
+ }
1874
+ const name = specifier.slice(0, atIndex);
1875
+ const version = specifier.slice(atIndex + 1);
1876
+ packageJson[key][name] = version;
1877
+ }
1878
+ }
1823
1879
  function getWorkspacePackageVersion() {
1824
1880
  if (process.env.STANDARDAGENTS_WORKSPACE === "1") {
1825
1881
  return "workspace:*";
1826
1882
  }
1827
- return "0.13.2";
1883
+ return "0.14.1";
1828
1884
  }
1829
1885
  function getSipPackageVersion() {
1830
1886
  return "1.0.1";
1831
1887
  }
1888
+ function getScaffoldToolchainVersions() {
1889
+ return {
1890
+ vite: "^7.0.6",
1891
+ typescript: "^5.9.0",
1892
+ cloudflareVitePlugin: "^1.17.0",
1893
+ wrangler: "^4.54.0"
1894
+ };
1895
+ }
1896
+ async function runPackageBinary(packageManager, binary, binaryArgs, cwd, env) {
1897
+ switch (packageManager) {
1898
+ case "pnpm":
1899
+ return runCommand("pnpm", ["exec", binary, ...binaryArgs], cwd, env);
1900
+ case "yarn":
1901
+ return runCommand("yarn", ["exec", binary, ...binaryArgs], cwd, env);
1902
+ case "bun":
1903
+ return runCommand("bunx", [binary, ...binaryArgs], cwd, env);
1904
+ default:
1905
+ return runCommand("npx", [binary, ...binaryArgs], cwd, env);
1906
+ }
1907
+ }
1832
1908
  async function selectPackageManager(detected) {
1833
1909
  const options = ["npm", "pnpm", "yarn", "bun"];
1834
1910
  const detectedIndex = options.indexOf(detected);
@@ -1961,11 +2037,12 @@ export default defineConfig({
1961
2037
  const packageJsonPath = path3.join(projectPath, "package.json");
1962
2038
  if (fs3.existsSync(packageJsonPath)) {
1963
2039
  const packageJson = JSON.parse(fs3.readFileSync(packageJsonPath, "utf-8"));
1964
- const kebabName = toKebabCase(projectName);
1965
- if (packageJson.name !== kebabName) {
1966
- packageJson.name = kebabName;
1967
- fs3.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + "\n", "utf-8");
1968
- }
2040
+ const normalizedPackageJson = normalizeScaffoldedPackageJson(
2041
+ packageJson,
2042
+ projectName,
2043
+ getScaffoldToolchainVersions()
2044
+ );
2045
+ fs3.writeFileSync(packageJsonPath, JSON.stringify(normalizedPackageJson, null, 2) + "\n", "utf-8");
1969
2046
  }
1970
2047
  logger.log("");
1971
2048
  logger.info("Step 2: Configuring environment variables...");
@@ -2025,12 +2102,33 @@ export default defineConfig({
2025
2102
  const devFlag = pm === "npm" ? "--save-dev" : "-D";
2026
2103
  const workspacePackageVersion = getWorkspacePackageVersion();
2027
2104
  const sipPackageVersion = getSipPackageVersion();
2028
- await runCommand(pm, [
2029
- installCmd,
2030
- devFlag,
2031
- "@cloudflare/vite-plugin",
2032
- "wrangler"
2033
- ], projectPath);
2105
+ const isWorkspaceMode = pm === "pnpm" && process.env.STANDARDAGENTS_WORKSPACE === "1";
2106
+ const pnpmWorkspaceFilter = pm === "pnpm" ? getPnpmWorkspaceFilterTarget(projectPath) : null;
2107
+ const installPackages = async (packages, { dev = false } = {}) => {
2108
+ if (pm === "pnpm" && pnpmWorkspaceFilter) {
2109
+ await runCommand(
2110
+ pm,
2111
+ [
2112
+ installCmd,
2113
+ ...dev ? [devFlag] : [],
2114
+ ...packages,
2115
+ "--filter",
2116
+ pnpmWorkspaceFilter.filterTarget
2117
+ ],
2118
+ pnpmWorkspaceFilter.cwd
2119
+ );
2120
+ return;
2121
+ }
2122
+ await runCommand(
2123
+ pm,
2124
+ [
2125
+ installCmd,
2126
+ ...dev ? [devFlag] : [],
2127
+ ...packages
2128
+ ],
2129
+ projectPath
2130
+ );
2131
+ };
2034
2132
  const deps = [
2035
2133
  `@standardagents/builder@${workspacePackageVersion}`,
2036
2134
  `@standardagents/spec@${workspacePackageVersion}`,
@@ -2058,7 +2156,22 @@ export default defineConfig({
2058
2156
  if (xaiKey) {
2059
2157
  deps.push(`@standardagents/xai@${workspacePackageVersion}`);
2060
2158
  }
2061
- await runCommand(pm, [installCmd, ...deps], projectPath);
2159
+ if (isWorkspaceMode) {
2160
+ const packageJson = JSON.parse(fs3.readFileSync(packageJsonPath, "utf-8"));
2161
+ applyPackageSpecifiers(packageJson, "devDependencies", [
2162
+ `@cloudflare/vite-plugin@${getScaffoldToolchainVersions().cloudflareVitePlugin}`,
2163
+ `wrangler@${getScaffoldToolchainVersions().wrangler}`
2164
+ ]);
2165
+ applyPackageSpecifiers(packageJson, "dependencies", deps);
2166
+ fs3.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + "\n", "utf-8");
2167
+ logger.info("Workspace mode detected: wrote dependency specs to package.json and deferred install.");
2168
+ } else {
2169
+ await installPackages([
2170
+ `@cloudflare/vite-plugin@${getScaffoldToolchainVersions().cloudflareVitePlugin}`,
2171
+ `wrangler@${getScaffoldToolchainVersions().wrangler}`
2172
+ ], { dev: true });
2173
+ await installPackages(deps);
2174
+ }
2062
2175
  } catch (error) {
2063
2176
  logger.error("Failed to install dependencies");
2064
2177
  process.exit(1);
@@ -2137,10 +2250,14 @@ export default defineConfig({
2137
2250
  logger.log("");
2138
2251
  logger.info("Step 5: Generating Cloudflare types...");
2139
2252
  logger.log("");
2140
- try {
2141
- await runCommand("npx", ["wrangler", "types"], projectPath);
2142
- } catch (error) {
2143
- logger.warning('Could not generate types automatically. Run "npx wrangler types" manually.');
2253
+ if (pm === "pnpm" && process.env.STANDARDAGENTS_WORKSPACE === "1") {
2254
+ logger.info("Workspace mode detected: skipping Wrangler type generation until dependencies are installed.");
2255
+ } else {
2256
+ try {
2257
+ await runPackageBinary(pm, "wrangler", ["types"], projectPath);
2258
+ } catch (error) {
2259
+ logger.warning("Could not generate types automatically. Run your package manager's Wrangler types command manually.");
2260
+ }
2144
2261
  }
2145
2262
  logger.log("");
2146
2263
  logger.success("Project created successfully!");
@@ -3570,10 +3687,431 @@ async function skill(options = {}) {
3570
3687
  process.exit(1);
3571
3688
  }
3572
3689
  }
3690
+ var UUID_LIKE_MODEL_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
3691
+ var CLOUDFLARE_PROVIDER_MODEL_ID = /^@cf\//i;
3692
+ var PAGE_SIZE = 100;
3693
+ var MAX_PAGES = 1e3;
3694
+ var CURRENT_MODELS_URLS = [
3695
+ "https://standardagentspec.org/models.md",
3696
+ "https://standardagentspec.com/models.md"
3697
+ ];
3698
+ var PROVIDER_DEFINITIONS = [
3699
+ {
3700
+ name: "cloudflare",
3701
+ packageName: "@standardagents/cloudflare",
3702
+ exportName: "cloudflare",
3703
+ label: "Cloudflare Workers AI",
3704
+ envKeys: ["CLOUDFLARE_API_TOKEN", "CLOUDFLARE_ACCOUNT_ID"]
3705
+ },
3706
+ {
3707
+ name: "cerebras",
3708
+ packageName: "@standardagents/cerebras",
3709
+ exportName: "cerebras",
3710
+ label: "Cerebras",
3711
+ envKeys: ["CEREBRAS_API_KEY"]
3712
+ },
3713
+ {
3714
+ name: "google",
3715
+ packageName: "@standardagents/google",
3716
+ exportName: "google",
3717
+ label: "Google Gemini",
3718
+ envKeys: ["GOOGLE_API_KEY"]
3719
+ },
3720
+ {
3721
+ name: "groq",
3722
+ packageName: "@standardagents/groq",
3723
+ exportName: "groq",
3724
+ label: "Groq",
3725
+ envKeys: ["GROQ_API_KEY"]
3726
+ },
3727
+ {
3728
+ name: "openai",
3729
+ packageName: "@standardagents/openai",
3730
+ exportName: "openai",
3731
+ label: "OpenAI",
3732
+ envKeys: ["OPENAI_API_KEY"]
3733
+ },
3734
+ {
3735
+ name: "openrouter",
3736
+ packageName: "@standardagents/openrouter",
3737
+ exportName: "openrouter",
3738
+ label: "OpenRouter",
3739
+ envKeys: ["OPENROUTER_API_KEY"]
3740
+ },
3741
+ {
3742
+ name: "xai",
3743
+ packageName: "@standardagents/xai",
3744
+ exportName: "xai",
3745
+ label: "xai",
3746
+ envKeys: ["XAI_API_KEY"]
3747
+ }
3748
+ ];
3749
+ function isOpaqueModelId(modelId) {
3750
+ if (!modelId) return true;
3751
+ return UUID_LIKE_MODEL_ID.test(modelId) || CLOUDFLARE_PROVIDER_MODEL_ID.test(modelId);
3752
+ }
3753
+ function getProviderDefinition(name) {
3754
+ return PROVIDER_DEFINITIONS.find((provider) => provider.name === name);
3755
+ }
3756
+ function parseEnvFile2(content) {
3757
+ const result = {};
3758
+ for (const line of content.split("\n")) {
3759
+ const trimmed = line.trim();
3760
+ if (!trimmed || trimmed.startsWith("#")) continue;
3761
+ const withoutExport = trimmed.startsWith("export ") ? trimmed.slice("export ".length).trim() : trimmed;
3762
+ const eqIndex = withoutExport.indexOf("=");
3763
+ if (eqIndex === -1) continue;
3764
+ const key = withoutExport.slice(0, eqIndex).trim();
3765
+ let value = withoutExport.slice(eqIndex + 1).trim();
3766
+ if (value.startsWith('"') && value.endsWith('"')) {
3767
+ value = value.slice(1, -1).replace(/\\"/g, '"');
3768
+ } else if (value.startsWith("'") && value.endsWith("'")) {
3769
+ value = value.slice(1, -1);
3770
+ }
3771
+ result[key] = value;
3772
+ }
3773
+ return result;
3774
+ }
3775
+ function findProjectRoot(startDir = process.cwd()) {
3776
+ let currentDir = path3.resolve(startDir);
3777
+ while (true) {
3778
+ if (fs3.existsSync(path3.join(currentDir, "package.json"))) {
3779
+ return currentDir;
3780
+ }
3781
+ const parentDir = path3.dirname(currentDir);
3782
+ if (parentDir === currentDir) {
3783
+ return path3.resolve(startDir);
3784
+ }
3785
+ currentDir = parentDir;
3786
+ }
3787
+ }
3788
+ function readProjectPackageJson(projectRoot) {
3789
+ const packagePath = path3.join(projectRoot, "package.json");
3790
+ if (!fs3.existsSync(packagePath)) {
3791
+ return {};
3792
+ }
3793
+ return JSON.parse(fs3.readFileSync(packagePath, "utf8"));
3794
+ }
3795
+ function getDeclaredProviderPackages(projectRoot) {
3796
+ const pkg = readProjectPackageJson(projectRoot);
3797
+ const combined = {
3798
+ ...pkg.dependencies ?? {},
3799
+ ...pkg.devDependencies ?? {},
3800
+ ...pkg.optionalDependencies ?? {},
3801
+ ...pkg.peerDependencies ?? {}
3802
+ };
3803
+ return PROVIDER_DEFINITIONS.map((provider) => provider.packageName).filter((packageName) => typeof combined[packageName] === "string");
3804
+ }
3805
+ function resolvePackageEntry(packageName, projectRoot) {
3806
+ const packageDir = findInstalledPackageDir(packageName, projectRoot);
3807
+ if (!packageDir) {
3808
+ return null;
3809
+ }
3810
+ const packageJsonPath = path3.join(packageDir, "package.json");
3811
+ try {
3812
+ const packageJson = JSON.parse(fs3.readFileSync(packageJsonPath, "utf8"));
3813
+ const exportPath = resolvePackageExportPath(packageJson.exports) || packageJson.main || "index.js";
3814
+ return path3.join(packageDir, exportPath);
3815
+ } catch {
3816
+ return null;
3817
+ }
3818
+ }
3819
+ function findInstalledPackageDir(packageName, projectRoot) {
3820
+ let currentDir = path3.resolve(projectRoot);
3821
+ while (true) {
3822
+ const candidate = path3.join(currentDir, "node_modules", ...packageName.split("/"));
3823
+ if (fs3.existsSync(candidate)) {
3824
+ return candidate;
3825
+ }
3826
+ const parentDir = path3.dirname(currentDir);
3827
+ if (parentDir === currentDir) {
3828
+ return null;
3829
+ }
3830
+ currentDir = parentDir;
3831
+ }
3832
+ }
3833
+ function resolvePackageExportPath(exportsField) {
3834
+ if (typeof exportsField === "string") {
3835
+ return exportsField;
3836
+ }
3837
+ if (!exportsField || typeof exportsField !== "object") {
3838
+ return null;
3839
+ }
3840
+ const rootExport = exportsField["."];
3841
+ if (typeof rootExport === "string") {
3842
+ return rootExport;
3843
+ }
3844
+ if (!rootExport || typeof rootExport !== "object") {
3845
+ return null;
3846
+ }
3847
+ const rootExportRecord = rootExport;
3848
+ const candidate = rootExportRecord.import || rootExportRecord.default || rootExportRecord.require;
3849
+ return typeof candidate === "string" ? candidate : null;
3850
+ }
3851
+ function isProviderPackageInstalled(packageName, projectRoot) {
3852
+ return resolvePackageEntry(packageName, projectRoot) !== null;
3853
+ }
3854
+ function loadProjectEnv(projectRoot, processEnv = process.env) {
3855
+ const result = {};
3856
+ const envFiles = [".env", ".env.local", ".dev.vars", ".dev.vars.local"];
3857
+ for (const fileName of envFiles) {
3858
+ const filePath = path3.join(projectRoot, fileName);
3859
+ if (!fs3.existsSync(filePath)) continue;
3860
+ Object.assign(result, parseEnvFile2(fs3.readFileSync(filePath, "utf8")));
3861
+ }
3862
+ for (const [key, value] of Object.entries(processEnv)) {
3863
+ if (typeof value === "string") {
3864
+ result[key] = value;
3865
+ }
3866
+ }
3867
+ return result;
3868
+ }
3869
+ function detectProviders(projectRoot, env = loadProjectEnv(projectRoot)) {
3870
+ const declaredPackages = new Set(getDeclaredProviderPackages(projectRoot));
3871
+ return PROVIDER_DEFINITIONS.filter((provider) => declaredPackages.has(provider.packageName)).map((provider) => {
3872
+ const installed = isProviderPackageInstalled(provider.packageName, projectRoot);
3873
+ const missingEnvKeys = provider.envKeys.filter((envKey) => !env[envKey]);
3874
+ return {
3875
+ ...provider,
3876
+ declared: true,
3877
+ installed,
3878
+ configured: installed && missingEnvKeys.length === 0,
3879
+ missingEnvKeys
3880
+ };
3881
+ });
3882
+ }
3883
+ async function loadProviderFactory(provider, projectRoot) {
3884
+ const entryPath = resolvePackageEntry(provider.packageName, projectRoot);
3885
+ if (!entryPath) {
3886
+ throw new Error(`Provider package ${provider.packageName} is not installed in ${projectRoot}.`);
3887
+ }
3888
+ const moduleUrl = entryPath.startsWith("file:") ? entryPath : pathToFileURL(entryPath).href;
3889
+ const providerModule = await import(moduleUrl);
3890
+ const factory = providerModule[provider.exportName];
3891
+ if (typeof factory !== "function") {
3892
+ throw new Error(`Provider package ${provider.packageName} does not export ${provider.exportName}().`);
3893
+ }
3894
+ return factory;
3895
+ }
3896
+ function buildProviderConfig(provider, env) {
3897
+ const apiKey = env[provider.envKeys[0]] || "";
3898
+ if (provider.name === "cloudflare") {
3899
+ const accountId = env.CLOUDFLARE_ACCOUNT_ID;
3900
+ return {
3901
+ apiKey,
3902
+ accountId,
3903
+ baseUrl: accountId ? `https://api.cloudflare.com/client/v4/accounts/${accountId}/ai/v1` : void 0
3904
+ };
3905
+ }
3906
+ return { apiKey };
3907
+ }
3908
+ async function collectProviderModels(providerName, providerInstance) {
3909
+ const rawModels = [];
3910
+ if (providerInstance.getModelsPage) {
3911
+ for (let page = 1; page <= MAX_PAGES; page += 1) {
3912
+ const result = await providerInstance.getModelsPage({ page, perPage: PAGE_SIZE });
3913
+ rawModels.push(...result.models);
3914
+ if (!result.hasNextPage) {
3915
+ return normalizeProviderModels(providerName, rawModels);
3916
+ }
3917
+ }
3918
+ throw new Error(`Provider ${providerName} exceeded ${MAX_PAGES} model pages without terminating pagination.`);
3919
+ }
3920
+ if (providerInstance.getModels) {
3921
+ rawModels.push(...await providerInstance.getModels());
3922
+ return normalizeProviderModels(providerName, rawModels);
3923
+ }
3924
+ throw new Error(`Provider ${providerName} does not support model discovery.`);
3925
+ }
3926
+ async function fetchAvailableModelsForProvider(providerName, projectRoot, env, factoryLoader = loadProviderFactory) {
3927
+ const provider = getProviderDefinition(providerName);
3928
+ if (!provider) {
3929
+ throw new Error(`Unknown provider "${providerName}".`);
3930
+ }
3931
+ const factory = await factoryLoader(provider, projectRoot);
3932
+ const providerInstance = factory(buildProviderConfig(provider, env));
3933
+ return collectProviderModels(provider.name, providerInstance);
3934
+ }
3935
+ async function fetchCurrentModelsMarkdown(urls = CURRENT_MODELS_URLS) {
3936
+ let lastError = null;
3937
+ for (const url of urls) {
3938
+ try {
3939
+ const response = await fetch(url);
3940
+ if (!response.ok) {
3941
+ throw new Error(`HTTP ${response.status} ${response.statusText}`.trim());
3942
+ }
3943
+ return {
3944
+ url,
3945
+ content: await response.text()
3946
+ };
3947
+ } catch (error) {
3948
+ lastError = error instanceof Error ? new Error(`Failed to fetch ${url}: ${error.message}`) : new Error(`Failed to fetch ${url}.`);
3949
+ }
3950
+ }
3951
+ throw lastError ?? new Error("No current models URLs configured.");
3952
+ }
3953
+ function buildProviderSelectionHelp(providers) {
3954
+ const providerNames = providers.map((provider) => provider.name).join(", ");
3955
+ const examples = providers.map((provider) => ` agents available-models --provider=${provider.name}`).join("\n");
3956
+ return [
3957
+ `Multiple configured providers were found: ${providerNames}`,
3958
+ "Re-run with a specific provider to fetch all model IDs:",
3959
+ examples
3960
+ ].join("\n");
3961
+ }
3962
+ function describeProviderAvailability(provider) {
3963
+ if (!provider.installed) {
3964
+ return `${provider.name}: not installed`;
3965
+ }
3966
+ if (provider.missingEnvKeys.length > 0) {
3967
+ return `${provider.name}: missing ${provider.missingEnvKeys.join(", ")}`;
3968
+ }
3969
+ return `${provider.name}: unavailable`;
3970
+ }
3971
+ function formatAvailableModelsOutput(provider, models) {
3972
+ const lines = [
3973
+ `# ${provider.label} models`,
3974
+ "",
3975
+ "Use the `model` values exactly as shown in `defineModel({ model: ... })`.",
3976
+ "",
3977
+ "| model | label | context | notes |",
3978
+ "| --- | --- | ---: | --- |"
3979
+ ];
3980
+ for (const model of models) {
3981
+ const context = model.contextLength ? model.contextLength.toLocaleString("en-US") : "";
3982
+ lines.push(
3983
+ `| \`${escapeTableCell(model.value)}\` | ${escapeTableCell(model.label)} | ${context} | ${escapeTableCell(model.description)} |`
3984
+ );
3985
+ }
3986
+ return `${lines.join("\n")}
3987
+ `;
3988
+ }
3989
+ function normalizeProviderModels(providerName, rawModels) {
3990
+ const deduped = /* @__PURE__ */ new Map();
3991
+ for (const model of rawModels) {
3992
+ const value = getExecutableModelId(providerName, model);
3993
+ if (!value) continue;
3994
+ if (!deduped.has(value)) {
3995
+ deduped.set(value, {
3996
+ value,
3997
+ label: model.name || value,
3998
+ description: model.description || "",
3999
+ contextLength: model.contextLength,
4000
+ slug: model.slug
4001
+ });
4002
+ }
4003
+ }
4004
+ return [...deduped.values()].sort((left, right) => left.value.localeCompare(right.value));
4005
+ }
4006
+ function getExecutableModelId(providerName, model) {
4007
+ if (model.id && !isOpaqueModelId(model.id)) {
4008
+ return model.id;
4009
+ }
4010
+ if (providerName === "cloudflare") {
4011
+ const publicCloudflareId = [model.name, model.slug].find((value) => typeof value === "string" && value.includes("/"));
4012
+ if (publicCloudflareId) {
4013
+ return publicCloudflareId.startsWith("@cf/") ? publicCloudflareId : `@cf/${publicCloudflareId.replace(/^@cf\//, "")}`;
4014
+ }
4015
+ }
4016
+ return model.slug || model.name || model.id;
4017
+ }
4018
+ function escapeTableCell(value) {
4019
+ return value.replace(/\|/g, "\\|").replace(/\n/g, "<br />");
4020
+ }
4021
+
4022
+ // src/commands/current-models.ts
4023
+ async function currentModels(options = {}) {
4024
+ try {
4025
+ const { content } = await fetchCurrentModelsMarkdown(
4026
+ options.url ? [options.url] : void 0
4027
+ );
4028
+ process.stdout.write(content.endsWith("\n") ? content : `${content}
4029
+ `);
4030
+ } catch (error) {
4031
+ const message = error instanceof Error ? error.message : "Failed to fetch current models.";
4032
+ process.stderr.write(`${message}
4033
+ `);
4034
+ process.exit(1);
4035
+ }
4036
+ }
4037
+
4038
+ // src/commands/available-models.ts
4039
+ function writeError(message) {
4040
+ process.stderr.write(`${message}
4041
+ `);
4042
+ process.exit(1);
4043
+ }
4044
+ async function availableModels(options = {}) {
4045
+ const projectRoot = findProjectRoot(process.cwd());
4046
+ const env = loadProjectEnv(projectRoot);
4047
+ const detectedProviders = detectProviders(projectRoot, env);
4048
+ if (detectedProviders.length === 0) {
4049
+ writeError(
4050
+ [
4051
+ `No installed provider packages were found in ${projectRoot}.`,
4052
+ "Add a provider package such as `@standardagents/cerebras`, then run this command again."
4053
+ ].join("\n")
4054
+ );
4055
+ }
4056
+ const providerName = options.provider?.trim();
4057
+ if (providerName) {
4058
+ const provider2 = detectedProviders.find((candidate) => candidate.name === providerName);
4059
+ if (!getProviderDefinition(providerName)) {
4060
+ writeError(
4061
+ `Unknown provider "${providerName}". Supported providers: ${detectedProviders.map((candidate) => candidate.name).join(", ")}.`
4062
+ );
4063
+ }
4064
+ if (!provider2) {
4065
+ writeError(
4066
+ [
4067
+ `Provider "${providerName}" is not installed in ${projectRoot}.`,
4068
+ `Install ${getProviderDefinition(providerName)?.packageName || providerName} and try again.`
4069
+ ].join("\n")
4070
+ );
4071
+ }
4072
+ if (!provider2.configured) {
4073
+ writeError(
4074
+ [
4075
+ `Provider "${providerName}" is missing required environment variables.`,
4076
+ `Missing: ${provider2.missingEnvKeys.join(", ")}`
4077
+ ].join("\n")
4078
+ );
4079
+ }
4080
+ try {
4081
+ const models = await fetchAvailableModelsForProvider(provider2.name, projectRoot, env);
4082
+ process.stdout.write(formatAvailableModelsOutput(provider2, models));
4083
+ return;
4084
+ } catch (error) {
4085
+ const message = error instanceof Error ? error.message : `Failed to fetch models for ${providerName}.`;
4086
+ writeError(message);
4087
+ }
4088
+ }
4089
+ const configuredProviders = detectedProviders.filter((provider2) => provider2.configured);
4090
+ if (configuredProviders.length === 0) {
4091
+ const missingSummary = detectedProviders.map((provider2) => describeProviderAvailability(provider2)).join("\n");
4092
+ writeError(
4093
+ [
4094
+ "No installed providers are fully configured yet.",
4095
+ missingSummary
4096
+ ].join("\n")
4097
+ );
4098
+ }
4099
+ if (configuredProviders.length > 1) {
4100
+ writeError(buildProviderSelectionHelp(configuredProviders));
4101
+ }
4102
+ const provider = configuredProviders[0];
4103
+ try {
4104
+ const models = await fetchAvailableModelsForProvider(provider.name, projectRoot, env);
4105
+ process.stdout.write(formatAvailableModelsOutput(provider, models));
4106
+ } catch (error) {
4107
+ const message = error instanceof Error ? error.message : `Failed to fetch models for ${provider.name}.`;
4108
+ writeError(message);
4109
+ }
4110
+ }
3573
4111
 
3574
4112
  // src/index.ts
3575
4113
  var program = new Command();
3576
- program.name("agents").description("CLI tool for Standard Agents / AgentBuilder").version("0.13.2");
4114
+ program.name("agents").description("CLI tool for Standard Agents / AgentBuilder").version("0.14.1");
3577
4115
  program.command("init [project-name]").description("Create a new Standard Agents project (runs create vite, then scaffold)").option("-y, --yes", "Skip prompts and use defaults").option("--template <template>", "Vite template to use", "vanilla-ts").action(init);
3578
4116
  program.command("scaffold").description("Add Standard Agents to an existing Vite project").option("--force", "Overwrite existing configuration").action(scaffold);
3579
4117
  program.command("init-chat [project-name]").description("Scaffold a frontend chat application").option("-y, --yes", "Skip prompts and use defaults").option("--framework <framework>", "Framework to use (vite or nextjs)").action(initChat);
@@ -3582,6 +4120,8 @@ program.command("unpack [package]").description("Unpack a packed agent to the lo
3582
4120
  program.command("list-packed").description("List all discovered packed agents").action(listPacked);
3583
4121
  program.command("deploy").description("Build and deploy your project to the Standard Agents platform").option("--api-key <key>", "Platform API key (overrides PLATFORM_API_KEY env var)").option("--endpoint <url>", "Platform API endpoint (default: https://api.standardagents.ai)").action(deploy);
3584
4122
  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);
4123
+ program.command("current-models").description("Print the live curated model guide from standardagentspec.com").option("--url <url>", "Override the models markdown URL").action(currentModels);
4124
+ 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);
3585
4125
  program.parse();
3586
4126
  //# sourceMappingURL=index.js.map
3587
4127
  //# sourceMappingURL=index.js.map