@orchagent/cli 0.3.83 → 0.3.85
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/adapters/claude-code.js +4 -8
- package/dist/commands/billing.js +21 -107
- package/dist/commands/github.js +1 -1
- package/dist/commands/info.js +1 -15
- package/dist/commands/init.js +151 -9
- package/dist/commands/install.js +2 -48
- package/dist/commands/logs.js +40 -4
- package/dist/commands/publish.js +98 -15
- package/dist/commands/pull.js +8 -2
- package/dist/commands/run.js +29 -105
- package/dist/commands/schedule.js +29 -2
- package/dist/commands/secrets.js +2 -1
- package/dist/commands/security.js +2 -2
- package/dist/commands/service.js +18 -11
- package/dist/commands/skill.js +8 -63
- package/dist/commands/test.js +1 -1
- package/dist/lib/api.js +0 -12
- package/dist/lib/doctor/checks/environment.js +145 -0
- package/dist/lib/doctor/output.js +1 -1
- package/dist/lib/errors.js +8 -1
- package/dist/lib/spinner.js +5 -0
- package/package.json +3 -2
- package/dist/lib/pricing.js +0 -22
package/dist/commands/publish.js
CHANGED
|
@@ -39,6 +39,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
39
39
|
exports.extractTemplateVariables = extractTemplateVariables;
|
|
40
40
|
exports.deriveInputSchema = deriveInputSchema;
|
|
41
41
|
exports.scanUndeclaredEnvVars = scanUndeclaredEnvVars;
|
|
42
|
+
exports.scanReservedPort = scanReservedPort;
|
|
42
43
|
exports.detectSdkCompatible = detectSdkCompatible;
|
|
43
44
|
exports.checkDependencies = checkDependencies;
|
|
44
45
|
exports.registerPublishCommand = registerPublishCommand;
|
|
@@ -167,6 +168,68 @@ async function scanUndeclaredEnvVars(agentDir, requiredSecrets) {
|
|
|
167
168
|
// Return env vars that are referenced but not declared or auto-injected
|
|
168
169
|
return [...found].filter(v => !declared.has(v) && !autoInjected.has(v)).sort();
|
|
169
170
|
}
|
|
171
|
+
/**
|
|
172
|
+
* Scan code files for patterns that bind to port 8080 — the platform reserves
|
|
173
|
+
* this port for the always-on service health server. Returns true if a likely
|
|
174
|
+
* port-8080 binding is detected.
|
|
175
|
+
*/
|
|
176
|
+
async function scanReservedPort(agentDir) {
|
|
177
|
+
// Patterns that indicate binding to port 8080 in Python / JS / TS
|
|
178
|
+
const pyPatterns = [
|
|
179
|
+
/\.listen\s*\(\s*8080\b/, // server.listen(8080
|
|
180
|
+
/\.run\s*\([^)]*port\s*=\s*8080\b/, // app.run(port=8080
|
|
181
|
+
/\.run\s*\([^)]*host\s*=\s*['"][^'"]*['"],?\s*8080\b/, // app.run("0.0.0.0", 8080
|
|
182
|
+
/bind\s*\(\s*\(?['"][^'"]*['"]\s*,\s*8080\b/, // bind(("0.0.0.0", 8080
|
|
183
|
+
/PORT\s*=\s*8080\b/, // PORT = 8080
|
|
184
|
+
/port\s*=\s*8080\b/, // port=8080
|
|
185
|
+
];
|
|
186
|
+
const jsPatterns = [
|
|
187
|
+
/\.listen\s*\(\s*8080\b/, // app.listen(8080
|
|
188
|
+
/port\s*[:=]\s*8080\b/, // port: 8080 or port = 8080
|
|
189
|
+
/PORT\s*[:=]\s*8080\b/, // PORT = 8080
|
|
190
|
+
];
|
|
191
|
+
async function scanDir(dir, depth) {
|
|
192
|
+
let entries;
|
|
193
|
+
try {
|
|
194
|
+
entries = await promises_1.default.readdir(dir, { withFileTypes: true });
|
|
195
|
+
if (!entries || !Array.isArray(entries))
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
198
|
+
catch {
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
for (const entry of entries) {
|
|
202
|
+
const name = entry.name;
|
|
203
|
+
const fullPath = path_1.default.join(dir, name);
|
|
204
|
+
if (entry.isDirectory() && depth < 2 && !name.startsWith('.') && name !== 'node_modules' && name !== '__pycache__' && name !== 'venv' && name !== '.venv') {
|
|
205
|
+
if (await scanDir(fullPath, depth + 1))
|
|
206
|
+
return true;
|
|
207
|
+
}
|
|
208
|
+
else if (entry.isFile() && name.endsWith('.py')) {
|
|
209
|
+
try {
|
|
210
|
+
const content = await promises_1.default.readFile(fullPath, 'utf-8');
|
|
211
|
+
for (const re of pyPatterns) {
|
|
212
|
+
if (re.test(content))
|
|
213
|
+
return true;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
catch { /* skip */ }
|
|
217
|
+
}
|
|
218
|
+
else if (entry.isFile() && (name.endsWith('.js') || name.endsWith('.ts'))) {
|
|
219
|
+
try {
|
|
220
|
+
const content = await promises_1.default.readFile(fullPath, 'utf-8');
|
|
221
|
+
for (const re of jsPatterns) {
|
|
222
|
+
if (re.test(content))
|
|
223
|
+
return true;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
catch { /* skip */ }
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
return scanDir(agentDir, 0);
|
|
232
|
+
}
|
|
170
233
|
/**
|
|
171
234
|
* Check if orchagent-sdk is listed in requirements.txt or pyproject.toml
|
|
172
235
|
*/
|
|
@@ -319,11 +382,8 @@ function inferExecutionEngineFromManifest(manifest, rawType) {
|
|
|
319
382
|
return 'managed_loop';
|
|
320
383
|
if (rawType === 'tool' || rawType === 'code')
|
|
321
384
|
return 'code_runtime';
|
|
322
|
-
if (rawType === 'agentic')
|
|
385
|
+
if (rawType === 'agentic' || rawType === 'agent')
|
|
323
386
|
return 'managed_loop';
|
|
324
|
-
if (rawType === 'agent' && (manifest.custom_tools?.length || manifest.max_turns)) {
|
|
325
|
-
return 'managed_loop';
|
|
326
|
-
}
|
|
327
387
|
return 'direct_llm';
|
|
328
388
|
}
|
|
329
389
|
function commandForEntrypoint(entrypoint) {
|
|
@@ -485,6 +545,7 @@ function registerPublishCommand(program) {
|
|
|
485
545
|
description: skillData.frontmatter.description,
|
|
486
546
|
prompt: skillData.body,
|
|
487
547
|
is_public: false,
|
|
548
|
+
callable: false,
|
|
488
549
|
supported_providers: ['any'],
|
|
489
550
|
default_skills: skillsFromFlag,
|
|
490
551
|
skills_locked: options.skillsLocked || undefined,
|
|
@@ -495,7 +556,7 @@ function registerPublishCommand(program) {
|
|
|
495
556
|
const skillVersion = skillResult.agent?.version || 'v1';
|
|
496
557
|
const skillAgentId = skillResult.agent?.id;
|
|
497
558
|
await (0, analytics_1.track)('cli_publish', { agent_type: 'skill', multi_file: hasMultipleFiles });
|
|
498
|
-
process.stdout.write(`\
|
|
559
|
+
process.stdout.write(`\n${chalk_1.default.green('✔')} Published ${org.slug}/${skillData.frontmatter.name}@${skillVersion} successfully!\n\n`);
|
|
499
560
|
if (hasMultipleFiles) {
|
|
500
561
|
process.stdout.write(`Files: ${skillFiles.length} files included\n`);
|
|
501
562
|
}
|
|
@@ -542,7 +603,7 @@ function registerPublishCommand(program) {
|
|
|
542
603
|
const { canonicalType, rawType } = canonicalizeManifestType(manifest.type);
|
|
543
604
|
const runMode = normalizeRunMode(manifest.run_mode);
|
|
544
605
|
const executionEngine = inferExecutionEngineFromManifest(manifest, rawType);
|
|
545
|
-
const callable = Boolean(manifest.callable);
|
|
606
|
+
const callable = manifest.callable !== undefined ? Boolean(manifest.callable) : true;
|
|
546
607
|
if (canonicalType === 'skill') {
|
|
547
608
|
throw new errors_1.CliError("Use SKILL.md for publishing skills. Remove orchagent.json and run 'orchagent publish' from a skill directory.");
|
|
548
609
|
}
|
|
@@ -706,6 +767,7 @@ function registerPublishCommand(program) {
|
|
|
706
767
|
}
|
|
707
768
|
let agentUrl = options.url;
|
|
708
769
|
let shouldUploadBundle = false;
|
|
770
|
+
let servicesUpdated = 0;
|
|
709
771
|
let runtimeConfig;
|
|
710
772
|
let bundleEntrypoint = manifest.entrypoint;
|
|
711
773
|
if (executionEngine === 'code_runtime') {
|
|
@@ -766,12 +828,13 @@ function registerPublishCommand(program) {
|
|
|
766
828
|
` Publish each dependency first, then re-run this publish.\n\n`);
|
|
767
829
|
}
|
|
768
830
|
if (notCallable.length > 0) {
|
|
769
|
-
process.stderr.write(chalk_1.default.yellow(`\n⚠ Dependencies
|
|
831
|
+
process.stderr.write(chalk_1.default.yellow(`\n⚠ Dependencies have callable: false:\n`));
|
|
770
832
|
for (const dep of notCallable) {
|
|
771
833
|
process.stderr.write(chalk_1.default.yellow(` - ${dep.ref}\n`));
|
|
772
834
|
}
|
|
773
|
-
process.stderr.write(`\n
|
|
774
|
-
`
|
|
835
|
+
process.stderr.write(`\n These agents have explicitly set callable: false, which blocks\n` +
|
|
836
|
+
` agent-to-agent calls at runtime. Set callable: true (or remove\n` +
|
|
837
|
+
` the field to use the default) and republish each dependency.\n\n`);
|
|
775
838
|
}
|
|
776
839
|
}
|
|
777
840
|
// Handle dry-run for agents
|
|
@@ -882,18 +945,35 @@ function registerPublishCommand(program) {
|
|
|
882
945
|
` (Platform-injected vars like LLM API keys are already excluded.)\n\n`);
|
|
883
946
|
}
|
|
884
947
|
}
|
|
948
|
+
// Warn if always_on code binds to port 8080 (reserved for platform health server)
|
|
949
|
+
if (runMode === 'always_on' && executionEngine === 'code_runtime') {
|
|
950
|
+
const usesReservedPort = await scanReservedPort(cwd);
|
|
951
|
+
if (usesReservedPort) {
|
|
952
|
+
process.stderr.write(chalk_1.default.yellow(`\n⚠ Your code appears to bind to port 8080, which is reserved by the\n`) +
|
|
953
|
+
chalk_1.default.yellow(` platform health server for always-on services.\n\n`) +
|
|
954
|
+
` Your service will crash with EADDRINUSE at runtime.\n` +
|
|
955
|
+
` Use a different port (e.g. 3000) or read the ORCHAGENT_HEALTH_PORT\n` +
|
|
956
|
+
` env var to detect the reserved port.\n\n`);
|
|
957
|
+
}
|
|
958
|
+
}
|
|
885
959
|
// C-1: Block publish if tool/agent type has no required_secrets declared.
|
|
886
960
|
// Prompt and skill types are exempt (prompt agents get LLM keys from platform,
|
|
887
961
|
// skills don't run standalone).
|
|
962
|
+
// An explicit empty array (required_secrets: []) is a valid declaration
|
|
963
|
+
// meaning "this agent deliberately needs no secrets."
|
|
888
964
|
if ((canonicalType === 'tool' || canonicalType === 'agent') &&
|
|
889
|
-
|
|
965
|
+
manifest.required_secrets === undefined &&
|
|
890
966
|
options.requiredSecrets !== false) {
|
|
891
967
|
process.stderr.write(chalk_1.default.red(`\nError: ${canonicalType} agents must declare required_secrets in orchagent.json.\n\n`) +
|
|
892
968
|
` Add the env vars your code needs at runtime:\n` +
|
|
893
969
|
` ${chalk_1.default.cyan('"required_secrets": ["ANTHROPIC_API_KEY", "MY_TOKEN"]')}\n\n` +
|
|
970
|
+
` If this agent genuinely needs no secrets, add an empty array:\n` +
|
|
971
|
+
` ${chalk_1.default.cyan('"required_secrets": []')}\n\n` +
|
|
894
972
|
` These are matched by name against your workspace secrets vault.\n` +
|
|
895
973
|
` Use ${chalk_1.default.cyan('--no-required-secrets')} to skip this check.\n`);
|
|
896
|
-
|
|
974
|
+
const err = new errors_1.CliError('Missing required_secrets declaration', errors_1.ExitCodes.INVALID_INPUT);
|
|
975
|
+
err.displayed = true;
|
|
976
|
+
throw err;
|
|
897
977
|
}
|
|
898
978
|
// Create the agent (server auto-assigns version)
|
|
899
979
|
let result;
|
|
@@ -1045,9 +1125,9 @@ function registerPublishCommand(program) {
|
|
|
1045
1125
|
process.stdout.write(` ${chalk_1.default.cyan('Using workspace default environment')}\n`);
|
|
1046
1126
|
}
|
|
1047
1127
|
}
|
|
1048
|
-
//
|
|
1128
|
+
// Store service update count for success message
|
|
1049
1129
|
if (uploadResult.services_updated && uploadResult.services_updated > 0) {
|
|
1050
|
-
|
|
1130
|
+
servicesUpdated = uploadResult.services_updated;
|
|
1051
1131
|
}
|
|
1052
1132
|
}
|
|
1053
1133
|
finally {
|
|
@@ -1062,7 +1142,11 @@ function registerPublishCommand(program) {
|
|
|
1062
1142
|
callable,
|
|
1063
1143
|
hosted: shouldUploadBundle,
|
|
1064
1144
|
});
|
|
1065
|
-
process.stdout.write(`\
|
|
1145
|
+
process.stdout.write(`\n${chalk_1.default.green('✔')} Published ${org.slug}/${manifest.name}@${assignedVersion} successfully!\n`);
|
|
1146
|
+
if (servicesUpdated > 0) {
|
|
1147
|
+
process.stdout.write(`${chalk_1.default.green('✔')} Updated ${servicesUpdated} running service(s) to ${assignedVersion} successfully!\n`);
|
|
1148
|
+
}
|
|
1149
|
+
process.stdout.write(`\n`);
|
|
1066
1150
|
process.stdout.write(`Type: ${canonicalType}\n`);
|
|
1067
1151
|
process.stdout.write(`Run mode: ${runMode}\n`);
|
|
1068
1152
|
process.stdout.write(`Execution engine: ${executionEngine}${shouldUploadBundle ? ' (hosted)' : ''}\n`);
|
|
@@ -1120,6 +1204,5 @@ function registerPublishCommand(program) {
|
|
|
1120
1204
|
process.stdout.write(`\nNote: Hosted code execution is in beta. Contact support for full deployment.\n`);
|
|
1121
1205
|
}
|
|
1122
1206
|
process.stdout.write(`\nView analytics and usage: https://orchagent.io/dashboard\n`);
|
|
1123
|
-
process.stdout.write(`\nSkill: orch skill install orchagent-public/agent-builder — gives your AI the full platform builder reference\n`);
|
|
1124
1207
|
});
|
|
1125
1208
|
}
|
package/dist/commands/pull.js
CHANGED
|
@@ -29,7 +29,13 @@ function parsePullRef(value) {
|
|
|
29
29
|
}
|
|
30
30
|
function canonicalType(typeValue) {
|
|
31
31
|
const normalized = (typeValue || 'agent').toLowerCase();
|
|
32
|
-
|
|
32
|
+
if (['prompt', 'tool', 'agent', 'skill'].includes(normalized))
|
|
33
|
+
return normalized;
|
|
34
|
+
if (normalized === 'code')
|
|
35
|
+
return 'tool';
|
|
36
|
+
if (normalized === 'agentic')
|
|
37
|
+
return 'agent';
|
|
38
|
+
return 'agent';
|
|
33
39
|
}
|
|
34
40
|
function resolveEngine(data) {
|
|
35
41
|
const ee = data.execution_engine;
|
|
@@ -200,7 +206,7 @@ function buildManifest(data) {
|
|
|
200
206
|
const manifest = {
|
|
201
207
|
name: data.name,
|
|
202
208
|
description: data.description || '',
|
|
203
|
-
type: canonicalType(data.type)
|
|
209
|
+
type: canonicalType(data.type),
|
|
204
210
|
};
|
|
205
211
|
if (data.run_mode)
|
|
206
212
|
manifest.run_mode = data.run_mode;
|
package/dist/commands/run.js
CHANGED
|
@@ -55,7 +55,6 @@ const output_1 = require("../lib/output");
|
|
|
55
55
|
const spinner_1 = require("../lib/spinner");
|
|
56
56
|
const llm_1 = require("../lib/llm");
|
|
57
57
|
const analytics_1 = require("../lib/analytics");
|
|
58
|
-
const pricing_1 = require("../lib/pricing");
|
|
59
58
|
const package_json_1 = __importDefault(require("../../package.json"));
|
|
60
59
|
const DEFAULT_VERSION = 'latest';
|
|
61
60
|
const AGENTS_DIR = path_1.default.join(os_1.default.homedir(), '.orchagent', 'agents');
|
|
@@ -462,16 +461,10 @@ async function downloadAgent(config, org, agent, version, workspaceId) {
|
|
|
462
461
|
}
|
|
463
462
|
}
|
|
464
463
|
// Non-owner - block with helpful message
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
`Run without --local: orch run ${org}/${agent}@${version} --data '{...}'`);
|
|
470
|
-
}
|
|
471
|
-
else {
|
|
472
|
-
throw new errors_1.CliError(`This agent is server-only and cannot be downloaded.\n\n` +
|
|
473
|
-
`Run without --local: orch run ${org}/${agent}@${version} --data '{...}'`);
|
|
474
|
-
}
|
|
464
|
+
// Use the gateway message which has the correct type label (agent/tool/skill/prompt)
|
|
465
|
+
const serverMsg = payload?.error?.message || 'This agent is server-only.';
|
|
466
|
+
throw new errors_1.CliError(`${serverMsg}\n\n` +
|
|
467
|
+
`Run without --local: orch run ${org}/${agent}@${version} --data '{...}'`);
|
|
475
468
|
}
|
|
476
469
|
}
|
|
477
470
|
if (!(err instanceof api_1.ApiError) || err.status !== 404)
|
|
@@ -682,7 +675,7 @@ async function executePromptLocally(agentData, inputData, skillPrompts = [], con
|
|
|
682
675
|
if (allProviders.length === 0) {
|
|
683
676
|
const providers = providersToCheck.join(', ');
|
|
684
677
|
throw new errors_1.CliError(`No LLM key found for: ${providers}\n` +
|
|
685
|
-
`Set an environment variable (e.g., OPENAI_API_KEY), run '
|
|
678
|
+
`Set an environment variable (e.g., OPENAI_API_KEY), run 'orch secrets set <PROVIDER>_API_KEY <key>', or configure in web dashboard`);
|
|
686
679
|
}
|
|
687
680
|
if (modelOverride && !providerOverride && allProviders.length > 1) {
|
|
688
681
|
process.stderr.write(`Warning: --model specified without --provider. The model '${modelOverride}' will be used for all ${allProviders.length} fallback providers, which may cause errors if the model is incompatible.\n` +
|
|
@@ -709,7 +702,7 @@ async function executePromptLocally(agentData, inputData, skillPrompts = [], con
|
|
|
709
702
|
if (!detected) {
|
|
710
703
|
const providers = providersToCheck.join(', ');
|
|
711
704
|
throw new errors_1.CliError(`No LLM key found for: ${providers}\n` +
|
|
712
|
-
`Set an environment variable (e.g., OPENAI_API_KEY), run '
|
|
705
|
+
`Set an environment variable (e.g., OPENAI_API_KEY), run 'orch secrets set <PROVIDER>_API_KEY <key>', or configure in web dashboard`);
|
|
713
706
|
}
|
|
714
707
|
const { provider, key, model: serverModel } = detected;
|
|
715
708
|
const model = modelOverride || serverModel || agentData.default_models?.[provider] || (0, llm_1.getDefaultModel)(provider);
|
|
@@ -743,7 +736,7 @@ async function executeAgentLocally(agentDir, prompt, inputData, outputSchema, cu
|
|
|
743
736
|
if (allProviders.length === 0) {
|
|
744
737
|
const providers = providersToCheck.join(', ');
|
|
745
738
|
throw new errors_1.CliError(`No LLM key found for: ${providers}\n` +
|
|
746
|
-
`Set an environment variable (e.g., ANTHROPIC_API_KEY), run '
|
|
739
|
+
`Set an environment variable (e.g., ANTHROPIC_API_KEY), run 'orch secrets set <PROVIDER>_API_KEY <key>', or configure in web dashboard`);
|
|
747
740
|
}
|
|
748
741
|
const primary = allProviders[0];
|
|
749
742
|
const model = modelOverride || primary.model || (0, llm_1.getDefaultModel)(primary.provider);
|
|
@@ -1703,58 +1696,6 @@ async function executeCloud(agentRef, file, options) {
|
|
|
1703
1696
|
}
|
|
1704
1697
|
}
|
|
1705
1698
|
}
|
|
1706
|
-
// Pre-call balance check for paid agents
|
|
1707
|
-
let pricingInfo;
|
|
1708
|
-
if ((0, pricing_1.isPaidAgent)(agentMeta)) {
|
|
1709
|
-
let isOwner = false;
|
|
1710
|
-
try {
|
|
1711
|
-
const callerOrg = await (0, api_1.getOrg)(resolved, workspaceId);
|
|
1712
|
-
const agentOrgId = agentMeta.org_id;
|
|
1713
|
-
const agentOrgSlug = agentMeta.org_slug;
|
|
1714
|
-
if (agentOrgId && callerOrg.id === agentOrgId) {
|
|
1715
|
-
isOwner = true;
|
|
1716
|
-
}
|
|
1717
|
-
else if (agentOrgSlug && callerOrg.slug === agentOrgSlug) {
|
|
1718
|
-
isOwner = true;
|
|
1719
|
-
}
|
|
1720
|
-
}
|
|
1721
|
-
catch {
|
|
1722
|
-
isOwner = false;
|
|
1723
|
-
}
|
|
1724
|
-
if (isOwner) {
|
|
1725
|
-
if (!options.json)
|
|
1726
|
-
process.stderr.write(`Cost: FREE (author)\n\n`);
|
|
1727
|
-
}
|
|
1728
|
-
else {
|
|
1729
|
-
const price = agentMeta.price_per_call_cents;
|
|
1730
|
-
pricingInfo = { price_cents: price ?? null };
|
|
1731
|
-
if (!price || price <= 0) {
|
|
1732
|
-
if (!options.json)
|
|
1733
|
-
process.stderr.write(`Warning: Pricing data unavailable. The server will verify payment.\n\n`);
|
|
1734
|
-
}
|
|
1735
|
-
else {
|
|
1736
|
-
try {
|
|
1737
|
-
const balanceData = await (0, api_1.getCreditsBalance)(resolved);
|
|
1738
|
-
const balance = balanceData.balance_cents;
|
|
1739
|
-
if (balance < price) {
|
|
1740
|
-
process.stderr.write(`Insufficient credits:\n` +
|
|
1741
|
-
` Balance: $${(balance / 100).toFixed(2)}\n` +
|
|
1742
|
-
` Required: $${(price / 100).toFixed(2)}\n\n` +
|
|
1743
|
-
`Add credits:\n` +
|
|
1744
|
-
` orch billing add 5\n` +
|
|
1745
|
-
` orch billing balance # check current balance\n`);
|
|
1746
|
-
process.exit(errors_1.ExitCodes.PERMISSION_DENIED);
|
|
1747
|
-
}
|
|
1748
|
-
if (!options.json)
|
|
1749
|
-
process.stderr.write(`Cost: $${(price / 100).toFixed(2)}/call\n\n`);
|
|
1750
|
-
}
|
|
1751
|
-
catch (err) {
|
|
1752
|
-
if (!options.json)
|
|
1753
|
-
process.stderr.write(`Warning: Could not verify balance. The server will check payment.\n\n`);
|
|
1754
|
-
}
|
|
1755
|
-
}
|
|
1756
|
-
}
|
|
1757
|
-
}
|
|
1758
1699
|
const endpoint = options.endpoint?.trim() || agentMeta.default_endpoint || 'analyze';
|
|
1759
1700
|
const headers = {
|
|
1760
1701
|
Authorization: `Bearer ${resolved.apiKey}`,
|
|
@@ -1834,12 +1775,6 @@ async function executeCloud(agentRef, file, options) {
|
|
|
1834
1775
|
...(options.model && { model: options.model }),
|
|
1835
1776
|
};
|
|
1836
1777
|
}
|
|
1837
|
-
else if (cloudEngine !== 'code_runtime') {
|
|
1838
|
-
const searchedProviders = effectiveProvider ? [effectiveProvider] : supportedProviders;
|
|
1839
|
-
const providerList = searchedProviders.join(', ');
|
|
1840
|
-
process.stderr.write(`Warning: No LLM key found for provider(s): ${providerList}\n` +
|
|
1841
|
-
`Set an env var (e.g., OPENAI_API_KEY), run 'orchagent keys add <provider>', use --key, or configure in web dashboard\n\n`);
|
|
1842
|
-
}
|
|
1843
1778
|
if (options.skills) {
|
|
1844
1779
|
headers['X-OrchAgent-Skills'] = options.skills;
|
|
1845
1780
|
}
|
|
@@ -2033,7 +1968,7 @@ async function executeCloud(agentRef, file, options) {
|
|
|
2033
1968
|
});
|
|
2034
1969
|
}
|
|
2035
1970
|
catch (err) {
|
|
2036
|
-
spinner?.
|
|
1971
|
+
spinner?.stop();
|
|
2037
1972
|
throw err;
|
|
2038
1973
|
}
|
|
2039
1974
|
if (!response.ok) {
|
|
@@ -2048,20 +1983,8 @@ async function executeCloud(agentRef, file, options) {
|
|
|
2048
1983
|
const errorCode = typeof payload === 'object' && payload
|
|
2049
1984
|
? payload.error?.code
|
|
2050
1985
|
: undefined;
|
|
2051
|
-
if (response.status === 402 || errorCode === 'INSUFFICIENT_CREDITS') {
|
|
2052
|
-
spinner?.fail('Insufficient credits');
|
|
2053
|
-
let errorMessage = 'Insufficient credits to run this agent.\n\n';
|
|
2054
|
-
if (pricingInfo?.price_cents) {
|
|
2055
|
-
errorMessage += `This agent costs $${(pricingInfo.price_cents / 100).toFixed(2)} per call.\n\n`;
|
|
2056
|
-
}
|
|
2057
|
-
errorMessage +=
|
|
2058
|
-
'Add credits:\n' +
|
|
2059
|
-
' orch billing add 5\n' +
|
|
2060
|
-
' orch billing balance # check current balance\n';
|
|
2061
|
-
throw new errors_1.CliError(errorMessage, errors_1.ExitCodes.PERMISSION_DENIED);
|
|
2062
|
-
}
|
|
2063
1986
|
if (errorCode === 'CLI_VERSION_TOO_OLD') {
|
|
2064
|
-
spinner?.
|
|
1987
|
+
spinner?.stop();
|
|
2065
1988
|
const minVersion = typeof payload === 'object' && payload
|
|
2066
1989
|
? payload.error?.min_version
|
|
2067
1990
|
: undefined;
|
|
@@ -2070,7 +1993,7 @@ async function executeCloud(agentRef, file, options) {
|
|
|
2070
1993
|
'Update with: npm update -g @orchagent/cli');
|
|
2071
1994
|
}
|
|
2072
1995
|
if (errorCode === 'LLM_KEY_REQUIRED') {
|
|
2073
|
-
spinner?.
|
|
1996
|
+
spinner?.stop();
|
|
2074
1997
|
throw new errors_1.CliError('This public agent requires you to provide an LLM key.\n' +
|
|
2075
1998
|
'Use --key <key> --provider <provider> or set OPENAI_API_KEY/ANTHROPIC_API_KEY env var.');
|
|
2076
1999
|
}
|
|
@@ -2078,7 +2001,7 @@ async function executeCloud(agentRef, file, options) {
|
|
|
2078
2001
|
const rateLimitMsg = typeof payload === 'object' && payload
|
|
2079
2002
|
? payload.error?.message || 'Rate limit exceeded'
|
|
2080
2003
|
: 'Rate limit exceeded';
|
|
2081
|
-
spinner?.
|
|
2004
|
+
spinner?.stop();
|
|
2082
2005
|
throw new errors_1.CliError(rateLimitMsg + '\n\n' +
|
|
2083
2006
|
'This is the LLM provider\'s rate limit on your API key, not an OrchAgent limit.\n' +
|
|
2084
2007
|
'To switch providers: orch run <agent> --provider <gemini|anthropic|openai>', errors_1.ExitCodes.RATE_LIMITED);
|
|
@@ -2094,18 +2017,29 @@ async function executeCloud(agentRef, file, options) {
|
|
|
2094
2017
|
: undefined;
|
|
2095
2018
|
const refSuffix = requestId ? `\n\nref: ${requestId}` : '';
|
|
2096
2019
|
if (errorCode === 'SANDBOX_ERROR') {
|
|
2097
|
-
spinner?.
|
|
2020
|
+
spinner?.stop();
|
|
2098
2021
|
const hint = typeof payload === 'object' && payload
|
|
2099
2022
|
? payload.error?.hint
|
|
2100
2023
|
: undefined;
|
|
2024
|
+
// Detect platform errors that surface as SANDBOX_ERROR (BUG-11)
|
|
2025
|
+
const lowerMessage = (message || '').toLowerCase();
|
|
2026
|
+
const isPlatformError = /\b403\b/.test(message || '') ||
|
|
2027
|
+
/\b401\b/.test(message || '') ||
|
|
2028
|
+
lowerMessage.includes('proxy token') ||
|
|
2029
|
+
lowerMessage.includes('orchagent_service_key') ||
|
|
2030
|
+
lowerMessage.includes('orchagent_billing_org');
|
|
2031
|
+
const attribution = isPlatformError
|
|
2032
|
+
? `This may be a platform configuration issue, not an error in the agent's code.\n` +
|
|
2033
|
+
`If this persists, contact support with the ref below.`
|
|
2034
|
+
: `This is an error in the agent's code, not the platform.\n` +
|
|
2035
|
+
`Check the agent code and requirements, then republish.`;
|
|
2101
2036
|
throw new errors_1.CliError(`${message}\n\n` +
|
|
2102
|
-
|
|
2103
|
-
`Check the agent code and requirements, then republish.` +
|
|
2037
|
+
attribution +
|
|
2104
2038
|
(hint ? `\n\nHint: ${hint}` : '') +
|
|
2105
2039
|
refSuffix);
|
|
2106
2040
|
}
|
|
2107
2041
|
if (errorCode === 'SANDBOX_TIMEOUT') {
|
|
2108
|
-
spinner?.
|
|
2042
|
+
spinner?.stop();
|
|
2109
2043
|
throw new errors_1.CliError(`${message}\n\n` +
|
|
2110
2044
|
`The agent did not complete in time. Try:\n` +
|
|
2111
2045
|
` - Simplifying the input\n` +
|
|
@@ -2114,7 +2048,7 @@ async function executeCloud(agentRef, file, options) {
|
|
|
2114
2048
|
refSuffix);
|
|
2115
2049
|
}
|
|
2116
2050
|
if (errorCode === 'MISSING_SECRETS') {
|
|
2117
|
-
spinner?.
|
|
2051
|
+
spinner?.stop();
|
|
2118
2052
|
// Extract secret names from gateway message:
|
|
2119
2053
|
// "Agent requires secret(s) not found in workspace: NAME1, NAME2. Add them in Settings > Secrets."
|
|
2120
2054
|
const secretNames = [];
|
|
@@ -2145,13 +2079,13 @@ async function executeCloud(agentRef, file, options) {
|
|
|
2145
2079
|
throw new errors_1.CliError(hint + refSuffix);
|
|
2146
2080
|
}
|
|
2147
2081
|
if (response.status >= 500) {
|
|
2148
|
-
spinner?.
|
|
2082
|
+
spinner?.stop();
|
|
2149
2083
|
throw new errors_1.CliError(`${message}\n\n` +
|
|
2150
2084
|
`This is a platform error — try again in a moment.\n` +
|
|
2151
2085
|
`If it persists, contact support.` +
|
|
2152
2086
|
refSuffix);
|
|
2153
2087
|
}
|
|
2154
|
-
spinner?.
|
|
2088
|
+
spinner?.stop();
|
|
2155
2089
|
throw new errors_1.CliError(message + refSuffix);
|
|
2156
2090
|
}
|
|
2157
2091
|
// Handle SSE streaming response
|
|
@@ -2235,9 +2169,6 @@ async function executeCloud(agentRef, file, options) {
|
|
|
2235
2169
|
return;
|
|
2236
2170
|
}
|
|
2237
2171
|
spinner?.succeed(`Ran ${org}/${parsed.agent}@${parsed.version}`);
|
|
2238
|
-
if (!options.json && (0, pricing_1.isPaidAgent)(agentMeta) && pricingInfo?.price_cents && pricingInfo.price_cents > 0) {
|
|
2239
|
-
process.stderr.write(`\nCost: $${(pricingInfo.price_cents / 100).toFixed(2)} USD\n`);
|
|
2240
|
-
}
|
|
2241
2172
|
const inputType = hasInjection
|
|
2242
2173
|
? 'file_injection'
|
|
2243
2174
|
: unkeyedFileArgs.length > 0
|
|
@@ -2606,13 +2537,6 @@ Examples:
|
|
|
2606
2537
|
orch run joe/summarizer --local --data '{"text": "Hello world"}'
|
|
2607
2538
|
orch run orchagent/leak-finder --local --download-only
|
|
2608
2539
|
|
|
2609
|
-
Paid Agents:
|
|
2610
|
-
Paid agents charge per call and deduct from your prepaid credits.
|
|
2611
|
-
Check your balance: orch billing balance
|
|
2612
|
-
Add credits: orch billing add 5
|
|
2613
|
-
|
|
2614
|
-
Same-author calls are FREE - you won't be charged for calling your own agents.
|
|
2615
|
-
|
|
2616
2540
|
File handling (cloud):
|
|
2617
2541
|
For prompt agents, file content is read and sent as JSON mapped to the agent's
|
|
2618
2542
|
input schema. Use --file-field to specify the field name (auto-detected by default).
|
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.registerScheduleCommand = registerScheduleCommand;
|
|
7
7
|
const cli_table3_1 = __importDefault(require("cli-table3"));
|
|
8
8
|
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
+
const promises_1 = __importDefault(require("readline/promises"));
|
|
9
10
|
const config_1 = require("../lib/config");
|
|
10
11
|
const api_1 = require("../lib/api");
|
|
11
12
|
const errors_1 = require("../lib/errors");
|
|
@@ -64,7 +65,8 @@ async function resolveScheduleId(config, partialId, workspaceId) {
|
|
|
64
65
|
function registerScheduleCommand(program) {
|
|
65
66
|
const schedule = program
|
|
66
67
|
.command('schedule')
|
|
67
|
-
.description('Manage scheduled agent runs (cron and webhooks)')
|
|
68
|
+
.description('Manage scheduled agent runs (cron and webhooks)')
|
|
69
|
+
.action(() => { schedule.help(); });
|
|
68
70
|
// orch schedule list
|
|
69
71
|
schedule
|
|
70
72
|
.command('list')
|
|
@@ -282,6 +284,7 @@ function registerScheduleCommand(program) {
|
|
|
282
284
|
schedule
|
|
283
285
|
.command('delete <schedule-id>')
|
|
284
286
|
.description('Delete a schedule')
|
|
287
|
+
.option('-y, --yes', 'Skip confirmation prompt')
|
|
285
288
|
.option('--workspace <slug>', 'Workspace slug (default: current workspace)')
|
|
286
289
|
.action(async (scheduleId, options) => {
|
|
287
290
|
const config = await (0, config_1.getResolvedConfig)();
|
|
@@ -289,6 +292,18 @@ function registerScheduleCommand(program) {
|
|
|
289
292
|
throw new errors_1.CliError('Missing API key. Run `orch login` first.');
|
|
290
293
|
}
|
|
291
294
|
const workspaceId = await resolveWorkspaceId(config, options.workspace);
|
|
295
|
+
if (!options.yes) {
|
|
296
|
+
const rl = promises_1.default.createInterface({
|
|
297
|
+
input: process.stdin,
|
|
298
|
+
output: process.stdout,
|
|
299
|
+
});
|
|
300
|
+
const answer = await rl.question(`Delete schedule ${scheduleId}? (y/N): `);
|
|
301
|
+
rl.close();
|
|
302
|
+
if (answer.trim().toLowerCase() !== 'y' && answer.trim().toLowerCase() !== 'yes') {
|
|
303
|
+
process.stdout.write('Cancelled.\n');
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
292
307
|
await (0, api_1.request)(config, 'DELETE', `/workspaces/${workspaceId}/schedules/${scheduleId}`);
|
|
293
308
|
process.stdout.write(chalk_1.default.green('\u2713') + ` Schedule ${scheduleId} deleted\n`);
|
|
294
309
|
});
|
|
@@ -338,6 +353,7 @@ function registerScheduleCommand(program) {
|
|
|
338
353
|
.command('info <schedule-id>')
|
|
339
354
|
.description('Show detailed schedule information with recent runs and events')
|
|
340
355
|
.option('--workspace <slug>', 'Workspace slug (default: current workspace)')
|
|
356
|
+
.option('--reveal', 'Show full webhook URL (for webhook schedules)')
|
|
341
357
|
.option('--json', 'Output as JSON')
|
|
342
358
|
.action(async (partialScheduleId, options) => {
|
|
343
359
|
const config = await (0, config_1.getResolvedConfig)();
|
|
@@ -346,8 +362,9 @@ function registerScheduleCommand(program) {
|
|
|
346
362
|
}
|
|
347
363
|
const workspaceId = await resolveWorkspaceId(config, options.workspace);
|
|
348
364
|
const scheduleId = await resolveScheduleId(config, partialScheduleId, workspaceId);
|
|
365
|
+
const revealParam = options.reveal ? '?reveal_webhook=true' : '';
|
|
349
366
|
const [scheduleRes, runsRes, eventsRes] = await Promise.all([
|
|
350
|
-
(0, api_1.request)(config, 'GET', `/workspaces/${workspaceId}/schedules/${scheduleId}`),
|
|
367
|
+
(0, api_1.request)(config, 'GET', `/workspaces/${workspaceId}/schedules/${scheduleId}${revealParam}`),
|
|
351
368
|
(0, api_1.request)(config, 'GET', `/workspaces/${workspaceId}/schedules/${scheduleId}/runs?limit=5`),
|
|
352
369
|
(0, api_1.request)(config, 'GET', `/workspaces/${workspaceId}/schedules/${scheduleId}/events?limit=5`),
|
|
353
370
|
]);
|
|
@@ -364,6 +381,12 @@ function registerScheduleCommand(program) {
|
|
|
364
381
|
process.stdout.write(` Cron: ${s.cron_expression}\n`);
|
|
365
382
|
process.stdout.write(` Timezone: ${s.timezone}\n`);
|
|
366
383
|
}
|
|
384
|
+
if (s.webhook_url) {
|
|
385
|
+
process.stdout.write(` Webhook: ${s.webhook_url}\n`);
|
|
386
|
+
}
|
|
387
|
+
else if (s.schedule_type === 'webhook' && !options.reveal) {
|
|
388
|
+
process.stdout.write(` Webhook: ${chalk_1.default.gray('(redacted — use --reveal to show)')}\n`);
|
|
389
|
+
}
|
|
367
390
|
process.stdout.write(` Enabled: ${s.enabled ? chalk_1.default.green('yes') : chalk_1.default.red('no')}\n`);
|
|
368
391
|
process.stdout.write(` Auto-update: ${s.auto_update === false ? chalk_1.default.yellow('pinned') : chalk_1.default.green('yes')}\n`);
|
|
369
392
|
if (s.auto_disabled_at) {
|
|
@@ -374,6 +397,10 @@ function registerScheduleCommand(program) {
|
|
|
374
397
|
if (s.next_run_at) {
|
|
375
398
|
process.stdout.write(` Next Run: ${formatDate(s.next_run_at)}\n`);
|
|
376
399
|
}
|
|
400
|
+
if (s.input_data && Object.keys(s.input_data).length > 0) {
|
|
401
|
+
const inputStr = JSON.stringify(s.input_data);
|
|
402
|
+
process.stdout.write(` Input: ${inputStr.length > 100 ? inputStr.slice(0, 100) + '...' : inputStr}\n`);
|
|
403
|
+
}
|
|
377
404
|
if (s.alert_webhook_url) {
|
|
378
405
|
process.stdout.write(` Alert URL: ${s.alert_webhook_url.slice(0, 50)}...\n`);
|
|
379
406
|
}
|
package/dist/commands/secrets.js
CHANGED
|
@@ -54,7 +54,8 @@ async function findSecretByName(config, workspaceId, name) {
|
|
|
54
54
|
function registerSecretsCommand(program) {
|
|
55
55
|
const secrets = program
|
|
56
56
|
.command('secrets')
|
|
57
|
-
.description('Manage workspace secrets (injected as env vars into agent sandboxes)')
|
|
57
|
+
.description('Manage workspace secrets (injected as env vars into agent sandboxes)')
|
|
58
|
+
.action(() => { secrets.help(); });
|
|
58
59
|
// orch secrets list
|
|
59
60
|
secrets
|
|
60
61
|
.command('list')
|
|
@@ -222,7 +222,7 @@ Examples:
|
|
|
222
222
|
});
|
|
223
223
|
}
|
|
224
224
|
catch (err) {
|
|
225
|
-
spinner.
|
|
225
|
+
spinner.stop();
|
|
226
226
|
throw err;
|
|
227
227
|
}
|
|
228
228
|
if (!response.ok) {
|
|
@@ -239,7 +239,7 @@ Examples:
|
|
|
239
239
|
payload.message ||
|
|
240
240
|
response.statusText
|
|
241
241
|
: response.statusText;
|
|
242
|
-
spinner.
|
|
242
|
+
spinner.stop();
|
|
243
243
|
throw new errors_1.CliError(message);
|
|
244
244
|
}
|
|
245
245
|
spinner.succeed(`Scan completed for ${agentId}`);
|