@orchagent/cli 0.3.77 → 0.3.79

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.
@@ -256,7 +256,7 @@ const DISCORD_PACKAGE_JSON = `{
256
256
  const DISCORD_JS_ENV_EXAMPLE = `# Required — get your bot token from https://discord.com/developers/applications
257
257
  DISCORD_BOT_TOKEN=
258
258
 
259
- # Required for local dev auto-injected in production via supported_providers
259
+ # Required add to workspace secrets: orch secrets set ANTHROPIC_API_KEY <key>
260
260
  ANTHROPIC_API_KEY=
261
261
 
262
262
  # Required — comma-separated Discord channel IDs where the bot should respond
@@ -364,7 +364,7 @@ Edit \`main.py\` to customize:
364
364
  | Variable | Required | Description |
365
365
  |----------|----------|-------------|
366
366
  | \`DISCORD_BOT_TOKEN\` | Yes | Discord bot token (workspace secret) |
367
- | \`ANTHROPIC_API_KEY\` | Auto | Injected by orchagent via \`supported_providers\` |
367
+ | \`ANTHROPIC_API_KEY\` | Yes | Anthropic API key (workspace secret via \`required_secrets\`) |
368
368
  | \`DISCORD_CHANNEL_IDS\` | Yes | Comma-separated channel IDs (workspace secret) |
369
369
  | \`MODEL\` | No | Claude model (default: claude-sonnet-4-5-20250929) |
370
370
  | \`MAX_TOKENS\` | No | Max response tokens (default: 1024) |
@@ -422,7 +422,7 @@ Edit \`main.js\` to customize:
422
422
  | Variable | Required | Description |
423
423
  |----------|----------|-------------|
424
424
  | \`DISCORD_BOT_TOKEN\` | Yes | Discord bot token (workspace secret) |
425
- | \`ANTHROPIC_API_KEY\` | Auto | Injected by orchagent via \`supported_providers\` |
425
+ | \`ANTHROPIC_API_KEY\` | Yes | Anthropic API key (workspace secret via \`required_secrets\`) |
426
426
  | \`DISCORD_CHANNEL_IDS\` | Yes | Comma-separated channel IDs (workspace secret) |
427
427
  | \`MODEL\` | No | Claude model (default: claude-sonnet-4-5-20250929) |
428
428
  | \`MAX_TOKENS\` | No | Max response tokens (default: 1024) |
@@ -782,7 +782,7 @@ anthropic>=0.40.0,<1.0.0
782
782
  const DISCORD_ENV_EXAMPLE = `# Required — get your bot token from https://discord.com/developers/applications
783
783
  DISCORD_BOT_TOKEN=
784
784
 
785
- # Required for local dev auto-injected in production via supported_providers
785
+ # Required add to workspace secrets: orch secrets set ANTHROPIC_API_KEY <key>
786
786
  ANTHROPIC_API_KEY=
787
787
 
788
788
  # Required — comma-separated Discord channel IDs where the bot should respond
@@ -942,8 +942,7 @@ function registerInitCommand(program) {
942
942
  entrypoint: 'main.py',
943
943
  supported_providers: ['anthropic'],
944
944
  default_models: { anthropic: 'claude-sonnet-4-5-20250929' },
945
- required_secrets: [],
946
- optional_secrets: ['DISCORD_BOT_TOKEN', 'DISCORD_CHANNEL_IDS', 'TELEGRAM_BOT_TOKEN', 'SLACK_BOT_TOKEN', 'SLACK_APP_TOKEN'],
945
+ required_secrets: ['ANTHROPIC_API_KEY'],
947
946
  tags: ['support', 'discord', 'telegram', 'slack', 'always-on', 'multi-platform'],
948
947
  bundle: {
949
948
  include: ['*.py', 'connectors/*.py', 'knowledge/*.md', 'requirements.txt'],
@@ -1069,7 +1068,7 @@ function registerInitCommand(program) {
1069
1068
  runtime: { command: 'node main.js' },
1070
1069
  entrypoint: 'main.js',
1071
1070
  supported_providers: ['anthropic'],
1072
- required_secrets: ['DISCORD_BOT_TOKEN', 'DISCORD_CHANNEL_IDS'],
1071
+ required_secrets: ['ANTHROPIC_API_KEY', 'DISCORD_BOT_TOKEN', 'DISCORD_CHANNEL_IDS'],
1073
1072
  tags: ['discord', 'always-on', 'javascript'],
1074
1073
  };
1075
1074
  await promises_1.default.writeFile(manifestPath, JSON.stringify(manifest, null, 2) + '\n');
@@ -1147,7 +1146,7 @@ function registerInitCommand(program) {
1147
1146
  manifest.description = 'An always-on Discord bot powered by Claude';
1148
1147
  manifest.runtime = { command: 'python main.py' };
1149
1148
  manifest.supported_providers = ['anthropic'];
1150
- manifest.required_secrets = ['DISCORD_BOT_TOKEN', 'DISCORD_CHANNEL_IDS'];
1149
+ manifest.required_secrets = ['ANTHROPIC_API_KEY', 'DISCORD_BOT_TOKEN', 'DISCORD_CHANNEL_IDS'];
1151
1150
  manifest.tags = ['discord', 'always-on'];
1152
1151
  }
1153
1152
  else if (initMode.flavor === 'code_runtime') {
@@ -1,172 +1,22 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
35
5
  Object.defineProperty(exports, "__esModule", { value: true });
36
6
  exports.registerKeysCommand = registerKeysCommand;
37
- const readline = __importStar(require("readline"));
38
- const config_1 = require("../lib/config");
39
- const api_1 = require("../lib/api");
40
- const errors_1 = require("../lib/errors");
41
- const VALID_PROVIDERS = ['openai', 'anthropic', 'gemini', 'ollama'];
42
- async function promptForKey(provider) {
43
- // Use hidden input to avoid exposing keys in terminal history/logs
44
- return new Promise((resolve, reject) => {
45
- const rl = readline.createInterface({
46
- input: process.stdin,
47
- output: process.stdout,
48
- });
49
- // Mask input by not echoing characters
50
- process.stdout.write(`Enter API key for ${provider}: `);
51
- if (process.stdin.isTTY) {
52
- // For TTY, read without echo
53
- const stdin = process.stdin;
54
- stdin.setRawMode(true);
55
- stdin.resume();
56
- stdin.setEncoding('utf8');
57
- let key = '';
58
- const onData = (char) => {
59
- if (char === '\n' || char === '\r') {
60
- stdin.setRawMode(false);
61
- stdin.removeListener('data', onData);
62
- rl.close();
63
- process.stdout.write('\n');
64
- resolve(key.trim());
65
- }
66
- else if (char === '\u0003') {
67
- // Ctrl+C
68
- stdin.setRawMode(false);
69
- rl.close();
70
- reject(new errors_1.CliError('Cancelled'));
71
- }
72
- else if (char === '\u007F' || char === '\b') {
73
- // Backspace
74
- if (key.length > 0) {
75
- key = key.slice(0, -1);
76
- }
77
- }
78
- else {
79
- key += char;
80
- }
81
- };
82
- stdin.on('data', onData);
83
- }
84
- else {
85
- // Non-TTY (piped input), just read normally
86
- rl.question('', (answer) => {
87
- rl.close();
88
- resolve(answer.trim());
89
- });
90
- }
91
- });
92
- }
93
- async function addKey(config, provider, options) {
94
- let apiKey = options.key;
95
- if (!apiKey) {
96
- apiKey = await promptForKey(provider);
97
- }
98
- if (!apiKey) {
99
- throw new errors_1.CliError('API key is required');
100
- }
101
- await (0, api_1.request)(config, 'POST', '/llm-keys', {
102
- body: JSON.stringify({
103
- provider,
104
- api_key: apiKey,
105
- endpoint_url: options.endpoint,
106
- }),
107
- headers: { 'Content-Type': 'application/json' },
108
- });
109
- process.stdout.write(`Saved ${provider} API key.\n`);
110
- }
111
- async function listKeys(config) {
112
- const keys = await (0, api_1.request)(config, 'GET', '/llm-keys');
113
- if (keys.length === 0) {
114
- process.stdout.write('No LLM keys configured.\n');
115
- process.stdout.write('\nAdd a key with: orchagent keys add <provider>\n');
116
- process.stdout.write('Providers: openai, anthropic, gemini, ollama\n');
117
- return;
118
- }
119
- process.stdout.write('Configured LLM keys:\n\n');
120
- for (const key of keys) {
121
- const endpoint = key.has_custom_endpoint ? ' (custom endpoint)' : '';
122
- process.stdout.write(` ${key.provider}${endpoint}\n`);
123
- }
124
- process.stdout.write('\n');
125
- }
126
- async function removeKey(config, provider) {
127
- await (0, api_1.request)(config, 'DELETE', `/llm-keys/${provider}`);
128
- process.stdout.write(`Removed ${provider} API key.\n`);
129
- }
7
+ const chalk_1 = __importDefault(require("chalk"));
130
8
  function registerKeysCommand(program) {
131
- const keys = program
9
+ program
132
10
  .command('keys')
133
- .description('Manage LLM API keys for calling agents');
134
- keys
135
- .command('add <provider>')
136
- .description('Add or update an LLM API key')
137
- .option('--key <key>', 'API key (will prompt if not provided)')
138
- .option('--endpoint <url>', 'Custom endpoint URL (enterprise proxy or self-hosted model)')
139
- .action(async (provider, options) => {
140
- const config = await (0, config_1.getResolvedConfig)();
141
- if (!config.apiKey) {
142
- throw new errors_1.CliError('Missing API key. Run `orchagent login` first.');
143
- }
144
- if (!VALID_PROVIDERS.includes(provider)) {
145
- throw new errors_1.CliError(`Invalid provider: ${provider}. Valid providers: ${VALID_PROVIDERS.join(', ')}`);
146
- }
147
- await addKey(config, provider, options);
148
- });
149
- keys
150
- .command('list')
151
- .description('List configured LLM API keys')
152
- .action(async () => {
153
- const config = await (0, config_1.getResolvedConfig)();
154
- if (!config.apiKey) {
155
- throw new errors_1.CliError('Missing API key. Run `orchagent login` first.');
156
- }
157
- await listKeys(config);
158
- });
159
- keys
160
- .command('remove <provider>')
161
- .description('Remove an LLM API key')
162
- .action(async (provider) => {
163
- const config = await (0, config_1.getResolvedConfig)();
164
- if (!config.apiKey) {
165
- throw new errors_1.CliError('Missing API key. Run `orchagent login` first.');
166
- }
167
- if (!VALID_PROVIDERS.includes(provider)) {
168
- throw new errors_1.CliError(`Invalid provider: ${provider}. Valid providers: ${VALID_PROVIDERS.join(', ')}`);
169
- }
170
- await removeKey(config, provider);
11
+ .description('(Deprecated) Use "orch secrets" instead')
12
+ .allowUnknownOption(true)
13
+ .action(() => {
14
+ process.stderr.write(chalk_1.default.yellow('\nThe `orch keys` command has been removed.\n\n') +
15
+ `LLM API keys are now managed through the unified workspace secrets vault.\n` +
16
+ `Use ${chalk_1.default.cyan('orch secrets')} instead:\n\n` +
17
+ ` ${chalk_1.default.cyan('orch secrets set ANTHROPIC_API_KEY <key>')} Add an LLM key\n` +
18
+ ` ${chalk_1.default.cyan('orch secrets list')} List all secrets\n` +
19
+ ` ${chalk_1.default.cyan('orch secrets delete ANTHROPIC_API_KEY')} Remove a key\n\n`);
20
+ process.exit(1);
171
21
  });
172
22
  }
package/dist/lib/api.js CHANGED
@@ -46,7 +46,6 @@ exports.updateOrg = updateOrg;
46
46
  exports.getPublicAgent = getPublicAgent;
47
47
  exports.listMyAgents = listMyAgents;
48
48
  exports.createAgent = createAgent;
49
- exports.listLlmKeys = listLlmKeys;
50
49
  exports.downloadCodeBundle = downloadCodeBundle;
51
50
  exports.uploadCodeBundle = uploadCodeBundle;
52
51
  exports.getMyAgent = getMyAgent;
@@ -306,9 +305,6 @@ async function createAgent(config, data, workspaceId) {
306
305
  headers,
307
306
  });
308
307
  }
309
- async function listLlmKeys(config) {
310
- return request(config, 'GET', '/llm-keys');
311
- }
312
308
  /**
313
309
  * Download a code-runtime bundle for local execution.
314
310
  */
@@ -1,8 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.runLlmChecks = runLlmChecks;
4
- const config_1 = require("../../config");
5
- const api_1 = require("../../api");
6
4
  // All supported LLM providers (single source of truth)
7
5
  const PROVIDERS = [
8
6
  { id: 'openai', displayName: 'OpenAI', envVars: ['OPENAI_API_KEY'], keyPrefix: 'sk-' },
@@ -26,13 +24,18 @@ function getFormatHint(provider, value) {
26
24
  return null;
27
25
  }
28
26
  /**
29
- * Gather per-provider status from server keys and local env vars.
27
+ * Run all LLM configuration checks with per-provider breakdown.
28
+ *
29
+ * Checks local environment variables for LLM provider keys.
30
+ * Server-side keys are managed through the workspace secrets vault
31
+ * (use `orch secrets list` to check).
30
32
  */
31
- function gatherProviderStatuses(serverProviders) {
32
- return PROVIDERS.map((provider) => {
33
- // Server status
34
- const server = serverProviders === null ? null : serverProviders.includes(provider.id);
35
- // Local status — check each env var
33
+ async function runLlmChecks(options) {
34
+ const results = [];
35
+ // Per-provider results (local env vars only)
36
+ let configuredCount = 0;
37
+ let firstUnconfigured;
38
+ for (const provider of PROVIDERS) {
36
39
  let local = false;
37
40
  let localEnvVar;
38
41
  let formatHint;
@@ -47,96 +50,37 @@ function gatherProviderStatuses(serverProviders) {
47
50
  break;
48
51
  }
49
52
  }
50
- return {
51
- providerId: provider.id,
52
- displayName: provider.displayName,
53
- server,
54
- local,
55
- localEnvVar,
56
- formatHint,
57
- };
58
- });
59
- }
60
- /**
61
- * Build a human-readable location string from server/local status.
62
- */
63
- function locationString(status) {
64
- if (status.server === null) {
65
- // Server unknown (offline)
66
- if (status.local)
67
- return 'Server unknown, local configured';
68
- return 'Server unknown, not local';
69
- }
70
- if (status.server && status.local)
71
- return 'Configured (server + local)';
72
- if (status.server)
73
- return 'Configured (server)';
74
- if (status.local)
75
- return 'Configured (local)';
76
- return 'Not configured';
77
- }
78
- /**
79
- * Run all LLM configuration checks with per-provider breakdown.
80
- *
81
- * When skipServer is true, server status is null for all providers
82
- * (shown as "unknown" in output). Use this when the gateway is unreachable.
83
- */
84
- async function runLlmChecks(options) {
85
- let serverProviders = null;
86
- if (!options?.skipServer) {
87
- try {
88
- const config = await (0, config_1.getResolvedConfig)();
89
- if (config.apiKey) {
90
- const keys = await (0, api_1.listLlmKeys)(config);
91
- serverProviders = keys.map((k) => k.provider);
92
- }
93
- }
94
- catch (err) {
95
- // If we can't reach the server, treat as unknown
96
- if (err instanceof api_1.ApiError && err.status === 401) {
97
- // Auth failed — server providers unknown
98
- }
99
- // Network error or other — server providers unknown
100
- }
101
- }
102
- const statuses = gatherProviderStatuses(serverProviders);
103
- const results = [];
104
- // Per-provider results
105
- for (const status of statuses) {
106
- const configured = status.server === true || status.local;
53
+ if (local)
54
+ configuredCount++;
55
+ else if (!firstUnconfigured)
56
+ firstUnconfigured = provider.id;
107
57
  results.push({
108
58
  category: 'llm',
109
- name: `llm_provider_${status.providerId}`,
110
- status: configured ? 'success' : 'info',
111
- message: `${status.providerId} — ${locationString(status)}`,
59
+ name: `llm_provider_${provider.id}`,
60
+ status: local ? 'success' : 'info',
61
+ message: `${provider.id} — ${local ? 'Configured (local)' : 'Not configured locally'}`,
112
62
  details: {
113
- providerId: status.providerId,
114
- displayName: status.displayName,
115
- server: status.server,
116
- local: status.local,
117
- ...(status.localEnvVar && { localEnvVar: status.localEnvVar }),
118
- ...(status.formatHint && { formatHint: status.formatHint }),
63
+ providerId: provider.id,
64
+ displayName: provider.displayName,
65
+ server: null,
66
+ local,
67
+ ...(localEnvVar && { localEnvVar }),
68
+ ...(formatHint && { formatHint }),
119
69
  },
120
70
  });
121
71
  }
122
72
  // Summary result
123
- const configuredCount = statuses.filter((s) => s.server === true || s.local).length;
124
- const firstUnconfigured = statuses.find((s) => s.server !== true && !s.local);
125
73
  let summaryStatus;
126
74
  let summaryMessage;
127
75
  let summaryFix;
128
76
  if (configuredCount === 0) {
129
77
  summaryStatus = 'warning';
130
- summaryMessage = 'No LLM providers configured';
131
- summaryFix = firstUnconfigured ? `Run: orchagent keys add ${firstUnconfigured.providerId}` : undefined;
78
+ summaryMessage = 'No LLM providers configured locally';
79
+ summaryFix = 'For cloud runs, add keys to your workspace vault: orch secrets set ANTHROPIC_API_KEY <key>';
132
80
  }
133
81
  else {
134
82
  summaryStatus = 'success';
135
- summaryMessage =
136
- configuredCount < 2
137
- ? 'Tip: Multiple providers enable automatic rate limit fallback.'
138
- : `${configuredCount} providers configured`;
139
- summaryFix = firstUnconfigured ? `Run: orchagent keys add ${firstUnconfigured.providerId}` : undefined;
83
+ summaryMessage = `${configuredCount} local provider${configuredCount > 1 ? 's' : ''} configured`;
140
84
  }
141
85
  results.push({
142
86
  category: 'llm',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orchagent/cli",
3
- "version": "0.3.77",
3
+ "version": "0.3.79",
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>",