@orchagent/cli 0.3.104 → 0.3.107

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.
@@ -91,6 +91,8 @@ async function getAgentInfo(config, org, agent, version, workspaceId) {
91
91
  default_skills: meta.default_skills || [],
92
92
  custom_tools: extractCustomTools(manifest),
93
93
  environment: manifest?.environment,
94
+ required_secrets: meta.required_secrets || [],
95
+ optional_secrets: meta.optional_secrets || [],
94
96
  };
95
97
  }
96
98
  catch (err) {
@@ -139,6 +141,8 @@ async function getAgentInfo(config, org, agent, version, workspaceId) {
139
141
  default_skills: targetAgent.default_skills || [],
140
142
  custom_tools: extractCustomTools(agentManifest),
141
143
  environment: agentManifest?.environment,
144
+ required_secrets: targetAgent.required_secrets || [],
145
+ optional_secrets: targetAgent.optional_secrets || [],
142
146
  };
143
147
  }
144
148
  function registerInfoCommand(program) {
@@ -180,6 +184,15 @@ function registerInfoCommand(program) {
180
184
  process.stdout.write(`Callable: ${chalk_1.default.green('yes')} — other agents can invoke this via the orchagent SDK\n`);
181
185
  }
182
186
  process.stdout.write(`Providers: ${agentData.supported_providers.join(', ')}\n`);
187
+ // Display secrets
188
+ const hasRequired = agentData.required_secrets && agentData.required_secrets.length > 0;
189
+ const hasOptional = agentData.optional_secrets && agentData.optional_secrets.length > 0;
190
+ if (hasRequired) {
191
+ process.stdout.write(`Secrets (required): ${agentData.required_secrets.join(', ')}\n`);
192
+ }
193
+ if (hasOptional) {
194
+ process.stdout.write(`Secrets (optional): ${agentData.optional_secrets.join(', ')}\n`);
195
+ }
183
196
  if (agentData.type === 'tool') {
184
197
  // Don't show internal routing URLs - they confuse users
185
198
  if (agentData.url && !agentData.url.includes('.internal')) {
@@ -469,6 +469,8 @@ async function checkWorkspaceLlmKeys(config, workspaceId, workspaceSlug, executi
469
469
  if (executionEngine !== 'direct_llm' && executionEngine !== 'managed_loop') {
470
470
  return;
471
471
  }
472
+ // Reverse map: secret name → provider (e.g. ANTHROPIC_API_KEY → anthropic)
473
+ const SECRET_NAME_TO_PROVIDER = Object.fromEntries(Object.entries(PROVIDER_TO_SECRET_NAME).map(([provider, name]) => [name, provider]));
472
474
  let secrets;
473
475
  try {
474
476
  const result = await (0, api_1.request)(config, 'GET', `/workspaces/${workspaceId}/secrets`);
@@ -479,8 +481,18 @@ async function checkWorkspaceLlmKeys(config, workspaceId, workspaceSlug, executi
479
481
  catch {
480
482
  return; // Can't reach API or unexpected response — skip warning silently
481
483
  }
482
- const llmKeys = secrets.filter(s => s.secret_type === 'llm_key' && s.llm_provider);
483
- const availableProviders = new Set(llmKeys.map(s => s.llm_provider));
484
+ // Resolve providers from both secret_type metadata AND secret name.
485
+ // Gateway resolves LLM keys by name, but `orch secrets set` creates them
486
+ // with secret_type='custom'. Match by name to avoid false warnings.
487
+ const availableProviders = new Set();
488
+ for (const s of secrets) {
489
+ if (s.secret_type === 'llm_key' && s.llm_provider) {
490
+ availableProviders.add(s.llm_provider);
491
+ }
492
+ if (s.name && s.name in SECRET_NAME_TO_PROVIDER) {
493
+ availableProviders.add(SECRET_NAME_TO_PROVIDER[s.name]);
494
+ }
495
+ }
484
496
  // Determine which providers the agent needs
485
497
  const needsAny = supportedProviders.includes('any');
486
498
  if (needsAny) {
@@ -1231,6 +1243,7 @@ function registerPublishCommand(program) {
1231
1243
  sdk_compatible: sdkCompatible || undefined,
1232
1244
  manifest: manifest.manifest,
1233
1245
  required_secrets: manifest.required_secrets,
1246
+ optional_secrets: manifest.optional_secrets,
1234
1247
  default_skills: skillsFromFlag || manifest.default_skills,
1235
1248
  skills_locked: manifest.skills_locked || options.skillsLocked || undefined,
1236
1249
  allow_local_download: options.localDownload !== false,
@@ -1332,6 +1345,7 @@ function registerPublishCommand(program) {
1332
1345
  // Orchestration manifest (includes dependencies)
1333
1346
  manifest: manifest.manifest,
1334
1347
  required_secrets: manifest.required_secrets,
1348
+ optional_secrets: manifest.optional_secrets,
1335
1349
  default_skills: skillsFromFlag || manifest.default_skills,
1336
1350
  skills_locked: manifest.skills_locked || options.skillsLocked || undefined,
1337
1351
  allow_local_download: options.localDownload !== false,
@@ -10,6 +10,13 @@ const config_1 = require("../lib/config");
10
10
  const api_1 = require("../lib/api");
11
11
  const errors_1 = require("../lib/errors");
12
12
  const output_1 = require("../lib/output");
13
+ // Known LLM key names → provider. Must stay in sync with gateway's
14
+ // _PROVIDER_TO_SECRET_NAME (db.py) and publish.ts PROVIDER_TO_SECRET_NAME.
15
+ const LLM_KEY_NAME_TO_PROVIDER = {
16
+ ANTHROPIC_API_KEY: 'anthropic',
17
+ OPENAI_API_KEY: 'openai',
18
+ GEMINI_API_KEY: 'gemini',
19
+ };
13
20
  // ============================================
14
21
  // HELPERS
15
22
  // ============================================
@@ -145,11 +152,13 @@ function registerSecretsCommand(program) {
145
152
  }
146
153
  }
147
154
  else {
148
- // Create new secret
155
+ // Create new secret — auto-classify LLM keys by name
156
+ const llmProvider = LLM_KEY_NAME_TO_PROVIDER[name];
149
157
  const body = {
150
158
  name,
151
159
  value,
152
- secret_type: 'custom',
160
+ secret_type: llmProvider ? 'llm_key' : 'custom',
161
+ ...(llmProvider && { llm_provider: llmProvider }),
153
162
  };
154
163
  if (options.description !== undefined) {
155
164
  body.description = options.description;
@@ -298,7 +298,8 @@ function registerSkillCommand(program) {
298
298
  skill
299
299
  .command('create [name]')
300
300
  .description('Create a new skill from template')
301
- .action(async (name) => {
301
+ .option('-y, --yes', 'Skip confirmation prompt')
302
+ .action(async (name, options) => {
302
303
  const cwd = process.cwd();
303
304
  const skillName = name || path_1.default.basename(cwd);
304
305
  const skillPath = path_1.default.join(cwd, 'SKILL.md');
@@ -311,6 +312,20 @@ function registerSkillCommand(program) {
311
312
  if (err.code !== 'ENOENT')
312
313
  throw err;
313
314
  }
315
+ // Confirm before writing to CWD (TTY only, skip with --yes)
316
+ if (!options.yes && process.stdout.isTTY) {
317
+ const readline = await Promise.resolve().then(() => __importStar(require('readline/promises')));
318
+ const rl = readline.createInterface({
319
+ input: process.stdin,
320
+ output: process.stdout,
321
+ });
322
+ const answer = await rl.question(`Create ${skillPath}? (y/N): `);
323
+ rl.close();
324
+ if (answer.trim().toLowerCase() !== 'y' && answer.trim().toLowerCase() !== 'yes') {
325
+ process.stdout.write('Aborted.\n');
326
+ return;
327
+ }
328
+ }
314
329
  const template = `---
315
330
  name: ${skillName}
316
331
  description: When to use this skill
package/dist/lib/llm.js CHANGED
@@ -37,10 +37,10 @@ exports.PROVIDER_ENV_VARS = {
37
37
  gemini: 'GEMINI_API_KEY',
38
38
  ollama: 'OLLAMA_HOST',
39
39
  };
40
- // Default models for each provider (best models)
40
+ // Default models for each provider
41
41
  exports.DEFAULT_MODELS = {
42
42
  openai: 'gpt-5.2',
43
- anthropic: 'claude-opus-4-5-20251101',
43
+ anthropic: 'claude-sonnet-4-6',
44
44
  gemini: 'gemini-2.5-pro',
45
45
  ollama: 'llama3.2',
46
46
  };
@@ -11,6 +11,7 @@ exports.createProgressSpinner = createProgressSpinner;
11
11
  exports.formatElapsed = formatElapsed;
12
12
  exports.createElapsedSpinner = createElapsedSpinner;
13
13
  const ora_1 = __importDefault(require("ora"));
14
+ const errors_1 = require("./errors");
14
15
  // Global flag to control spinner visibility (set via --no-progress)
15
16
  let progressEnabled = true;
16
17
  /**
@@ -99,7 +100,10 @@ async function withSpinner(text, fn, options) {
99
100
  : options?.failText || (err instanceof Error ? err.message : 'Failed');
100
101
  spinner.fail(failMsg);
101
102
  // Mark as already displayed so exitWithError doesn't print again
102
- if (err instanceof Error) {
103
+ if (err instanceof errors_1.CliError) {
104
+ err.displayed = true;
105
+ }
106
+ else if (err instanceof Error) {
103
107
  ;
104
108
  err._displayed = true;
105
109
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orchagent/cli",
3
- "version": "0.3.104",
3
+ "version": "0.3.107",
4
4
  "description": "Command-line interface for orchagent — deploy and run AI agents for your team",
5
5
  "license": "MIT",
6
6
  "author": "orchagent <hello@orchagent.io>",