@orchagent/cli 0.2.22 → 0.2.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/commands/call.js +4 -0
- package/dist/commands/docs.js +34 -0
- package/dist/commands/doctor.js +1 -1
- package/dist/commands/github.js +2 -2
- package/dist/commands/index.js +2 -0
- package/dist/commands/keys.js +2 -2
- package/dist/commands/login.js +1 -1
- package/dist/commands/publish.js +164 -37
- package/dist/commands/run.js +29 -5
- package/dist/commands/search.js +2 -8
- package/dist/commands/skill.js +6 -0
- package/dist/commands/status.js +19 -2
- package/dist/index.js +7 -2
- package/dist/lib/api.js +13 -0
- package/dist/lib/browser-auth.js +2 -2
- package/dist/lib/bundle.js +2 -2
- package/dist/lib/doctor/checks/connectivity.js +1 -1
- package/dist/lib/doctor/checks/llm.js +11 -0
- package/dist/lib/doctor/output.js +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
package/dist/commands/call.js
CHANGED
|
@@ -100,6 +100,7 @@ function registerCallCommand(program) {
|
|
|
100
100
|
.option('--endpoint <endpoint>', 'Override agent endpoint')
|
|
101
101
|
.option('--tenant <tenant>', 'Tenant identifier for multi-tenant callers')
|
|
102
102
|
.option('--data <json>', 'JSON payload (string or @file, @- for stdin)')
|
|
103
|
+
.option('--input <json>', 'Alias for --data')
|
|
103
104
|
.option('--key <key>', 'LLM API key (overrides env vars)')
|
|
104
105
|
.option('--provider <provider>', 'LLM provider (openai, anthropic, gemini)')
|
|
105
106
|
.option('--json', 'Output raw JSON')
|
|
@@ -119,6 +120,9 @@ Examples:
|
|
|
119
120
|
Note: Use 'call' for server-side execution (requires login), 'run' for local execution.
|
|
120
121
|
`)
|
|
121
122
|
.action(async (agentRef, file, options) => {
|
|
123
|
+
// Merge --input alias into --data
|
|
124
|
+
const dataValue = options.data || options.input;
|
|
125
|
+
options.data = dataValue;
|
|
122
126
|
const resolved = await (0, config_1.getResolvedConfig)();
|
|
123
127
|
if (!resolved.apiKey) {
|
|
124
128
|
throw new errors_1.CliError('Missing API key. Run `orchagent login` first.');
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.registerDocsCommand = registerDocsCommand;
|
|
7
|
+
const open_1 = __importDefault(require("open"));
|
|
8
|
+
const DOCS_BASE = 'https://docs.orchagent.io';
|
|
9
|
+
const DOCS_ROUTES = {
|
|
10
|
+
'': '/',
|
|
11
|
+
'cli': '/using-agents/cli-commands',
|
|
12
|
+
'agents': '/building-agents/agent-types',
|
|
13
|
+
'skills': '/building-agents/orchestration',
|
|
14
|
+
'sdk': '/building-agents/sdk',
|
|
15
|
+
'api': '/api-reference/overview',
|
|
16
|
+
'quickstart': '/quickstart',
|
|
17
|
+
};
|
|
18
|
+
function registerDocsCommand(program) {
|
|
19
|
+
program
|
|
20
|
+
.command('docs')
|
|
21
|
+
.description('Open documentation in browser')
|
|
22
|
+
.argument('[topic]', 'Topic: cli, agents, skills, sdk, api, quickstart')
|
|
23
|
+
.action(async (topic) => {
|
|
24
|
+
if (topic && !(topic in DOCS_ROUTES)) {
|
|
25
|
+
const validTopics = Object.keys(DOCS_ROUTES).filter(k => k).join(', ');
|
|
26
|
+
process.stderr.write(`Unknown topic "${topic}". Valid topics: ${validTopics}\n`);
|
|
27
|
+
process.stderr.write('Opening docs homepage instead.\n\n');
|
|
28
|
+
}
|
|
29
|
+
const route = DOCS_ROUTES[topic ?? ''] ?? '/';
|
|
30
|
+
const url = `${DOCS_BASE}${route}`;
|
|
31
|
+
process.stdout.write(`Opening ${url}\n`);
|
|
32
|
+
await (0, open_1.default)(url);
|
|
33
|
+
});
|
|
34
|
+
}
|
package/dist/commands/doctor.js
CHANGED
|
@@ -6,7 +6,7 @@ const output_1 = require("../lib/output");
|
|
|
6
6
|
function registerDoctorCommand(program) {
|
|
7
7
|
program
|
|
8
8
|
.command('doctor')
|
|
9
|
-
.description('Diagnose setup issues with
|
|
9
|
+
.description('Diagnose setup issues with orchagent CLI')
|
|
10
10
|
.option('-v, --verbose', 'Show detailed output for each check')
|
|
11
11
|
.option('--json', 'Output results as JSON')
|
|
12
12
|
.action(async (options) => {
|
package/dist/commands/github.js
CHANGED
|
@@ -55,7 +55,7 @@ function successHtml() {
|
|
|
55
55
|
<html>
|
|
56
56
|
<head>
|
|
57
57
|
<meta charset="utf-8">
|
|
58
|
-
<title>
|
|
58
|
+
<title>orchagent CLI - GitHub Connected</title>
|
|
59
59
|
<style>
|
|
60
60
|
body {
|
|
61
61
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
@@ -114,7 +114,7 @@ function errorHtml(message) {
|
|
|
114
114
|
<html>
|
|
115
115
|
<head>
|
|
116
116
|
<meta charset="utf-8">
|
|
117
|
-
<title>
|
|
117
|
+
<title>orchagent CLI - GitHub Connection Error</title>
|
|
118
118
|
<style>
|
|
119
119
|
body {
|
|
120
120
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
package/dist/commands/index.js
CHANGED
|
@@ -20,6 +20,7 @@ const doctor_1 = require("./doctor");
|
|
|
20
20
|
const status_1 = require("./status");
|
|
21
21
|
const workspace_1 = require("./workspace");
|
|
22
22
|
const tree_1 = require("./tree");
|
|
23
|
+
const docs_1 = require("./docs");
|
|
23
24
|
function registerCommands(program) {
|
|
24
25
|
(0, login_1.registerLoginCommand)(program);
|
|
25
26
|
(0, whoami_1.registerWhoamiCommand)(program);
|
|
@@ -40,4 +41,5 @@ function registerCommands(program) {
|
|
|
40
41
|
(0, status_1.registerStatusCommand)(program);
|
|
41
42
|
(0, workspace_1.registerWorkspaceCommand)(program);
|
|
42
43
|
(0, tree_1.registerTreeCommand)(program);
|
|
44
|
+
(0, docs_1.registerDocsCommand)(program);
|
|
43
45
|
}
|
package/dist/commands/keys.js
CHANGED
|
@@ -38,7 +38,7 @@ const readline = __importStar(require("readline"));
|
|
|
38
38
|
const config_1 = require("../lib/config");
|
|
39
39
|
const api_1 = require("../lib/api");
|
|
40
40
|
const errors_1 = require("../lib/errors");
|
|
41
|
-
const VALID_PROVIDERS = ['openai', 'anthropic', 'gemini'];
|
|
41
|
+
const VALID_PROVIDERS = ['openai', 'anthropic', 'gemini', 'ollama'];
|
|
42
42
|
async function promptForKey(provider) {
|
|
43
43
|
// Use hidden input to avoid exposing keys in terminal history/logs
|
|
44
44
|
return new Promise((resolve, reject) => {
|
|
@@ -113,7 +113,7 @@ async function listKeys(config) {
|
|
|
113
113
|
if (keys.length === 0) {
|
|
114
114
|
process.stdout.write('No LLM keys configured.\n');
|
|
115
115
|
process.stdout.write('\nAdd a key with: orchagent keys add <provider>\n');
|
|
116
|
-
process.stdout.write('Providers: openai, anthropic, gemini\n');
|
|
116
|
+
process.stdout.write('Providers: openai, anthropic, gemini, ollama\n');
|
|
117
117
|
return;
|
|
118
118
|
}
|
|
119
119
|
process.stdout.write('Configured LLM keys:\n\n');
|
package/dist/commands/login.js
CHANGED
|
@@ -23,7 +23,7 @@ async function promptForKey() {
|
|
|
23
23
|
function registerLoginCommand(program) {
|
|
24
24
|
program
|
|
25
25
|
.command('login')
|
|
26
|
-
.description('Authenticate with
|
|
26
|
+
.description('Authenticate with orchagent via browser or API key')
|
|
27
27
|
.option('--key <key>', 'API key (for CI/CD, non-interactive)')
|
|
28
28
|
.option('--port <port>', `Localhost port for browser callback (default: ${DEFAULT_AUTH_PORT})`, String(DEFAULT_AUTH_PORT))
|
|
29
29
|
.action(async (options) => {
|
package/dist/commands/publish.js
CHANGED
|
@@ -13,6 +13,36 @@ const api_1 = require("../lib/api");
|
|
|
13
13
|
const errors_1 = require("../lib/errors");
|
|
14
14
|
const analytics_1 = require("../lib/analytics");
|
|
15
15
|
const bundle_1 = require("../lib/bundle");
|
|
16
|
+
/**
|
|
17
|
+
* Handle security flagged error response (422 with error: 'content_flagged')
|
|
18
|
+
* Returns true if the error was handled, false otherwise
|
|
19
|
+
*/
|
|
20
|
+
function handleSecurityFlaggedError(err) {
|
|
21
|
+
if (!(err instanceof api_1.ApiError) || err.status !== 422) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
const payload = err.payload;
|
|
25
|
+
if (payload?.error !== 'content_flagged') {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
process.stderr.write('\n');
|
|
29
|
+
process.stderr.write('Error: Skill flagged for security review\n\n');
|
|
30
|
+
if (payload.concerns && payload.concerns.length > 0) {
|
|
31
|
+
process.stderr.write('Concerns found:\n');
|
|
32
|
+
for (const concern of payload.concerns) {
|
|
33
|
+
const severityLabel = concern.severity.toUpperCase();
|
|
34
|
+
const fileInfo = concern.file_path ? ` in ${concern.file_path}` : '';
|
|
35
|
+
process.stderr.write(` [${severityLabel}] ${concern.category}${fileInfo}\n`);
|
|
36
|
+
process.stderr.write(` "${concern.description}"\n\n`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (payload.summary) {
|
|
40
|
+
process.stderr.write(`Summary: ${payload.summary}\n\n`);
|
|
41
|
+
}
|
|
42
|
+
process.stderr.write('Please review and remove suspicious patterns before publishing.\n');
|
|
43
|
+
process.stderr.write('If you believe this is a false positive, contact support@orchagent.com\n');
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
16
46
|
/**
|
|
17
47
|
* Check if orchagent-sdk is listed in requirements.txt or pyproject.toml
|
|
18
48
|
*/
|
|
@@ -60,6 +90,65 @@ async function parseSkillMd(filePath) {
|
|
|
60
90
|
return null;
|
|
61
91
|
}
|
|
62
92
|
}
|
|
93
|
+
/**
|
|
94
|
+
* Binary file extensions to skip when collecting skill files (SC-05)
|
|
95
|
+
*/
|
|
96
|
+
const BINARY_EXTENSIONS = new Set([
|
|
97
|
+
'.png', '.jpg', '.jpeg', '.gif', '.ico', '.webp', '.bmp', '.tiff',
|
|
98
|
+
'.pdf', '.zip', '.tar', '.gz', '.7z', '.rar',
|
|
99
|
+
'.exe', '.dll', '.so', '.dylib', '.bin',
|
|
100
|
+
'.woff', '.woff2', '.ttf', '.eot', '.otf',
|
|
101
|
+
'.mp3', '.mp4', '.wav', '.avi', '.mov', '.mkv',
|
|
102
|
+
'.pyc', '.pyo', '.class', '.o', '.obj',
|
|
103
|
+
]);
|
|
104
|
+
/**
|
|
105
|
+
* Collect all text files in the skill directory for SC-05 multi-file support
|
|
106
|
+
*/
|
|
107
|
+
async function collectSkillFiles(skillDir, maxFiles = 20, maxTotalSize = 500_000) {
|
|
108
|
+
const files = [];
|
|
109
|
+
let totalSize = 0;
|
|
110
|
+
async function walkDir(dir, relativePath = '') {
|
|
111
|
+
if (files.length >= maxFiles || totalSize >= maxTotalSize)
|
|
112
|
+
return;
|
|
113
|
+
const entries = await promises_1.default.readdir(dir, { withFileTypes: true });
|
|
114
|
+
for (const entry of entries) {
|
|
115
|
+
if (files.length >= maxFiles || totalSize >= maxTotalSize)
|
|
116
|
+
break;
|
|
117
|
+
const fullPath = path_1.default.join(dir, entry.name);
|
|
118
|
+
const relPath = relativePath ? `${relativePath}/${entry.name}` : entry.name;
|
|
119
|
+
// Skip hidden files and common non-content directories
|
|
120
|
+
if (entry.name.startsWith('.') || entry.name === 'node_modules' || entry.name === '__pycache__') {
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
if (entry.isDirectory()) {
|
|
124
|
+
await walkDir(fullPath, relPath);
|
|
125
|
+
}
|
|
126
|
+
else if (entry.isFile()) {
|
|
127
|
+
// Skip binary files
|
|
128
|
+
const ext = path_1.default.extname(entry.name).toLowerCase();
|
|
129
|
+
if (BINARY_EXTENSIONS.has(ext))
|
|
130
|
+
continue;
|
|
131
|
+
try {
|
|
132
|
+
const stat = await promises_1.default.stat(fullPath);
|
|
133
|
+
if (totalSize + stat.size > maxTotalSize)
|
|
134
|
+
continue;
|
|
135
|
+
const content = await promises_1.default.readFile(fullPath, 'utf-8');
|
|
136
|
+
files.push({
|
|
137
|
+
path: relPath,
|
|
138
|
+
content,
|
|
139
|
+
size: stat.size,
|
|
140
|
+
});
|
|
141
|
+
totalSize += stat.size;
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
// Skip files that can't be read (binary, permissions, etc.)
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
await walkDir(skillDir);
|
|
150
|
+
return files;
|
|
151
|
+
}
|
|
63
152
|
function registerPublishCommand(program) {
|
|
64
153
|
program
|
|
65
154
|
.command('publish')
|
|
@@ -86,10 +175,14 @@ function registerPublishCommand(program) {
|
|
|
86
175
|
if (skillData) {
|
|
87
176
|
// Publish as a skill (server auto-assigns version)
|
|
88
177
|
const org = await (0, api_1.getOrg)(config);
|
|
178
|
+
// SC-05: Collect all files in the skill directory for multi-file support
|
|
179
|
+
const skillFiles = await collectSkillFiles(cwd);
|
|
180
|
+
const hasMultipleFiles = skillFiles.length > 1;
|
|
89
181
|
// Handle dry-run for skills
|
|
90
182
|
if (options.dryRun) {
|
|
91
183
|
const preview = await (0, api_1.previewAgentVersion)(config, skillData.frontmatter.name);
|
|
92
184
|
const skillBodyBytes = Buffer.byteLength(skillData.body, 'utf-8');
|
|
185
|
+
const totalFilesSize = skillFiles.reduce((sum, f) => sum + f.size, 0);
|
|
93
186
|
const versionInfo = preview.existing_versions.length > 0
|
|
94
187
|
? `${preview.next_version} (new version, ${preview.existing_versions[preview.existing_versions.length - 1]} exists)`
|
|
95
188
|
: `${preview.next_version} (first version)`;
|
|
@@ -97,6 +190,9 @@ function registerPublishCommand(program) {
|
|
|
97
190
|
process.stderr.write('Validating...\n');
|
|
98
191
|
process.stderr.write(` ✓ SKILL.md found and valid\n`);
|
|
99
192
|
process.stderr.write(` ✓ Skill prompt (${skillBodyBytes.toLocaleString()} bytes)\n`);
|
|
193
|
+
if (hasMultipleFiles) {
|
|
194
|
+
process.stderr.write(` ✓ Skill files: ${skillFiles.length} files (${(totalFilesSize / 1024).toFixed(1)} KB)\n`);
|
|
195
|
+
}
|
|
100
196
|
process.stderr.write(` ✓ Authentication valid (org: ${org.slug})\n`);
|
|
101
197
|
process.stderr.write('\nSkill Preview:\n');
|
|
102
198
|
process.stderr.write(` Name: ${skillData.frontmatter.name}\n`);
|
|
@@ -104,25 +200,47 @@ function registerPublishCommand(program) {
|
|
|
104
200
|
process.stderr.write(` Version: ${versionInfo}\n`);
|
|
105
201
|
process.stderr.write(` Visibility: ${options.public ? 'public' : 'private'}\n`);
|
|
106
202
|
process.stderr.write(` Providers: any\n`);
|
|
203
|
+
if (hasMultipleFiles) {
|
|
204
|
+
process.stderr.write(` Files: ${skillFiles.length} files\n`);
|
|
205
|
+
for (const f of skillFiles.slice(0, 5)) {
|
|
206
|
+
process.stderr.write(` - ${f.path}\n`);
|
|
207
|
+
}
|
|
208
|
+
if (skillFiles.length > 5) {
|
|
209
|
+
process.stderr.write(` ... and ${skillFiles.length - 5} more\n`);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
107
212
|
process.stderr.write(`\nWould publish: ${preview.org_slug}/${skillData.frontmatter.name}@${preview.next_version}\n`);
|
|
108
213
|
process.stderr.write(`API endpoint: POST ${config.apiUrl}/${preview.org_slug}/${skillData.frontmatter.name}/${preview.next_version}/run\n\n`);
|
|
109
214
|
process.stderr.write('No changes made (dry run)\n');
|
|
110
215
|
return;
|
|
111
216
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
217
|
+
try {
|
|
218
|
+
const skillResult = await (0, api_1.createAgent)(config, {
|
|
219
|
+
name: skillData.frontmatter.name,
|
|
220
|
+
type: 'skill',
|
|
221
|
+
description: skillData.frontmatter.description,
|
|
222
|
+
prompt: skillData.body,
|
|
223
|
+
is_public: options.public ? true : false,
|
|
224
|
+
supported_providers: ['any'],
|
|
225
|
+
default_skills: skillsFromFlag,
|
|
226
|
+
skills_locked: options.skillsLocked || undefined,
|
|
227
|
+
// SC-05: Include all skill files for UI preview
|
|
228
|
+
skill_files: hasMultipleFiles ? skillFiles : undefined,
|
|
229
|
+
});
|
|
230
|
+
const skillVersion = skillResult.agent?.version || 'v1';
|
|
231
|
+
await (0, analytics_1.track)('cli_publish', { agent_type: 'skill', multi_file: hasMultipleFiles });
|
|
232
|
+
process.stdout.write(`\nPublished skill: ${org.slug}/${skillData.frontmatter.name}@${skillVersion}\n`);
|
|
233
|
+
if (hasMultipleFiles) {
|
|
234
|
+
process.stdout.write(`Files: ${skillFiles.length} files included\n`);
|
|
235
|
+
}
|
|
236
|
+
process.stdout.write(`Public: ${options.public ? 'yes' : 'no'}\n`);
|
|
237
|
+
}
|
|
238
|
+
catch (err) {
|
|
239
|
+
if (handleSecurityFlaggedError(err)) {
|
|
240
|
+
process.exit(1);
|
|
241
|
+
}
|
|
242
|
+
throw err;
|
|
243
|
+
}
|
|
126
244
|
return;
|
|
127
245
|
}
|
|
128
246
|
// Read manifest
|
|
@@ -290,29 +408,38 @@ function registerPublishCommand(program) {
|
|
|
290
408
|
return;
|
|
291
409
|
}
|
|
292
410
|
// Create the agent (server auto-assigns version)
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
411
|
+
let result;
|
|
412
|
+
try {
|
|
413
|
+
result = await (0, api_1.createAgent)(config, {
|
|
414
|
+
name: manifest.name,
|
|
415
|
+
type: manifest.type,
|
|
416
|
+
description: manifest.description,
|
|
417
|
+
prompt,
|
|
418
|
+
url: agentUrl,
|
|
419
|
+
input_schema: inputSchema,
|
|
420
|
+
output_schema: outputSchema,
|
|
421
|
+
tags: manifest.tags,
|
|
422
|
+
is_public: options.public ? true : false,
|
|
423
|
+
supported_providers: supportedProviders,
|
|
424
|
+
default_models: manifest.default_models,
|
|
425
|
+
// Local run fields for code agents
|
|
426
|
+
source_url: manifest.source_url,
|
|
427
|
+
pip_package: manifest.pip_package,
|
|
428
|
+
run_command: manifest.run_command,
|
|
429
|
+
// SDK compatibility flag
|
|
430
|
+
sdk_compatible: sdkCompatible || undefined,
|
|
431
|
+
// Orchestration manifest (includes dependencies)
|
|
432
|
+
manifest: manifest.manifest,
|
|
433
|
+
default_skills: skillsFromFlag || manifest.default_skills,
|
|
434
|
+
skills_locked: manifest.skills_locked || options.skillsLocked || undefined,
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
catch (err) {
|
|
438
|
+
if (handleSecurityFlaggedError(err)) {
|
|
439
|
+
process.exit(1);
|
|
440
|
+
}
|
|
441
|
+
throw err;
|
|
442
|
+
}
|
|
316
443
|
const assignedVersion = result.agent?.version || 'v1';
|
|
317
444
|
const agentId = result.agent?.id;
|
|
318
445
|
// Upload code bundle if this is a hosted code agent
|
package/dist/commands/run.js
CHANGED
|
@@ -176,6 +176,7 @@ async function promptUserForDeps(depStatuses) {
|
|
|
176
176
|
process.stderr.write(` [2] Download ${downloadableCount} available deps, run locally\n`);
|
|
177
177
|
}
|
|
178
178
|
process.stderr.write(' [3] Cancel\n\n');
|
|
179
|
+
process.stderr.write('Tip: Use --with-deps to skip this prompt in scripts.\n\n');
|
|
179
180
|
return new Promise((resolve) => {
|
|
180
181
|
rl.question('Choose [1/2/3]: ', (answer) => {
|
|
181
182
|
rl.close();
|
|
@@ -233,11 +234,19 @@ async function downloadDependenciesRecursively(config, depStatuses, visited = ne
|
|
|
233
234
|
}
|
|
234
235
|
}
|
|
235
236
|
}
|
|
236
|
-
async function executePromptLocally(agentData, inputData, skillPrompts = [], config) {
|
|
237
|
-
|
|
237
|
+
async function executePromptLocally(agentData, inputData, skillPrompts = [], config, providerOverride) {
|
|
238
|
+
// If provider override specified, validate and use only that provider
|
|
239
|
+
if (providerOverride) {
|
|
240
|
+
(0, llm_1.validateProvider)(providerOverride);
|
|
241
|
+
}
|
|
242
|
+
// Determine which providers to check for keys
|
|
243
|
+
const providersToCheck = providerOverride
|
|
244
|
+
? [providerOverride]
|
|
245
|
+
: agentData.supported_providers;
|
|
246
|
+
const detected = await (0, llm_1.detectLlmKey)(providersToCheck, config);
|
|
238
247
|
if (!detected) {
|
|
239
|
-
const providers =
|
|
240
|
-
throw new errors_1.CliError(`No LLM key found
|
|
248
|
+
const providers = providersToCheck.join(', ');
|
|
249
|
+
throw new errors_1.CliError(`No LLM key found for: ${providers}\n` +
|
|
241
250
|
`Set an environment variable (e.g., OPENAI_API_KEY) or configure in web dashboard`);
|
|
242
251
|
}
|
|
243
252
|
const { provider, key, model: serverModel } = detected;
|
|
@@ -663,12 +672,16 @@ function registerRunCommand(program) {
|
|
|
663
672
|
.description('Download and run an agent locally')
|
|
664
673
|
.option('--local', 'Run locally using local LLM keys (default for run command)')
|
|
665
674
|
.option('--input <json>', 'JSON input data')
|
|
675
|
+
.option('--data <json>', 'Alias for --input')
|
|
666
676
|
.option('--download-only', 'Just download the agent, do not execute')
|
|
667
677
|
.option('--with-deps', 'Automatically download all dependencies (skip prompt)')
|
|
668
678
|
.option('--json', 'Output raw JSON')
|
|
669
679
|
.option('--skills <skills>', 'Add skills (comma-separated)')
|
|
670
680
|
.option('--skills-only <skills>', 'Use only these skills')
|
|
671
681
|
.option('--no-skills', 'Ignore default skills')
|
|
682
|
+
.option('--here', 'Shorthand for --input \'{"path": "."}\'')
|
|
683
|
+
.option('--path <dir>', 'Shorthand for --input \'{"path": "<dir>"}\'')
|
|
684
|
+
.option('--provider <name>', 'LLM provider to use (openai, anthropic, gemini, ollama)')
|
|
672
685
|
.addHelpText('after', `
|
|
673
686
|
Examples:
|
|
674
687
|
orch run orchagent/leak-finder --input '{"path": "."}'
|
|
@@ -679,6 +692,17 @@ Examples:
|
|
|
679
692
|
Note: Use 'run' for local execution, 'call' for server-side execution.
|
|
680
693
|
`)
|
|
681
694
|
.action(async (agentRef, args, options) => {
|
|
695
|
+
// Merge --data alias into --input
|
|
696
|
+
if (options.data && !options.input) {
|
|
697
|
+
options.input = options.data;
|
|
698
|
+
}
|
|
699
|
+
// Handle --here and --path shortcuts
|
|
700
|
+
if (options.here) {
|
|
701
|
+
options.input = JSON.stringify({ path: process.cwd() });
|
|
702
|
+
}
|
|
703
|
+
else if (options.path) {
|
|
704
|
+
options.input = JSON.stringify({ path: options.path });
|
|
705
|
+
}
|
|
682
706
|
const resolved = await (0, config_1.getResolvedConfig)();
|
|
683
707
|
const parsed = parseAgentRef(agentRef);
|
|
684
708
|
const org = parsed.org ?? resolved.defaultOrg;
|
|
@@ -819,7 +843,7 @@ Note: Use 'run' for local execution, 'call' for server-side execution.
|
|
|
819
843
|
}
|
|
820
844
|
// Execute locally
|
|
821
845
|
process.stderr.write(`Executing locally...\n\n`);
|
|
822
|
-
const result = await executePromptLocally(agentData, inputData, skillPrompts, resolved);
|
|
846
|
+
const result = await executePromptLocally(agentData, inputData, skillPrompts, resolved, options.provider);
|
|
823
847
|
if (options.json) {
|
|
824
848
|
(0, output_1.printJson)(result);
|
|
825
849
|
}
|
package/dist/commands/search.js
CHANGED
|
@@ -5,7 +5,6 @@ const config_1 = require("../lib/config");
|
|
|
5
5
|
const api_1 = require("../lib/api");
|
|
6
6
|
const output_1 = require("../lib/output");
|
|
7
7
|
const analytics_1 = require("../lib/analytics");
|
|
8
|
-
const errors_1 = require("../lib/errors");
|
|
9
8
|
const DEFAULT_LIMIT = 20;
|
|
10
9
|
function registerSearchCommand(program) {
|
|
11
10
|
program
|
|
@@ -20,14 +19,9 @@ function registerSearchCommand(program) {
|
|
|
20
19
|
.action(async (query, options) => {
|
|
21
20
|
const config = await (0, config_1.getResolvedConfig)();
|
|
22
21
|
const limit = parseInt(options.limit, 10) || DEFAULT_LIMIT;
|
|
23
|
-
//
|
|
22
|
+
// Default to popular when no args
|
|
24
23
|
if (!query && !options.popular && !options.recent) {
|
|
25
|
-
|
|
26
|
-
'Usage:\n' +
|
|
27
|
-
' orchagent search <query> Search by keyword\n' +
|
|
28
|
-
' orchagent search --popular Top agents by stars\n' +
|
|
29
|
-
' orchagent search --recent Most recently published\n\n' +
|
|
30
|
-
'Browse all agents at: https://orchagent.io/explore');
|
|
24
|
+
options.popular = true;
|
|
31
25
|
}
|
|
32
26
|
let agents;
|
|
33
27
|
if (query) {
|
package/dist/commands/skill.js
CHANGED
|
@@ -11,6 +11,7 @@ const config_1 = require("../lib/config");
|
|
|
11
11
|
const api_1 = require("../lib/api");
|
|
12
12
|
const errors_1 = require("../lib/errors");
|
|
13
13
|
const analytics_1 = require("../lib/analytics");
|
|
14
|
+
const package_json_1 = __importDefault(require("../../package.json"));
|
|
14
15
|
const DEFAULT_VERSION = 'v1';
|
|
15
16
|
/**
|
|
16
17
|
* AI tool skill directories.
|
|
@@ -220,6 +221,11 @@ ${skillData.prompt}
|
|
|
220
221
|
skill: `${org}/${parsed.skill}`,
|
|
221
222
|
global: Boolean(options.global),
|
|
222
223
|
});
|
|
224
|
+
// Report authenticated install to backend (fire-and-forget)
|
|
225
|
+
// This tracks unique installers for manipulation-resistant metrics
|
|
226
|
+
if (resolved.apiKey) {
|
|
227
|
+
(0, api_1.reportInstall)(resolved, org, parsed.skill, parsed.version, package_json_1.default.version).catch(() => { });
|
|
228
|
+
}
|
|
223
229
|
process.stdout.write(`Installed ${org}/${parsed.skill}@${parsed.version}\n`);
|
|
224
230
|
process.stdout.write(`\nAvailable for:\n`);
|
|
225
231
|
for (const tool of installed) {
|
package/dist/commands/status.js
CHANGED
|
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.registerStatusCommand = registerStatusCommand;
|
|
7
7
|
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const config_1 = require("../lib/config");
|
|
8
9
|
const output_1 = require("../lib/output");
|
|
9
10
|
const STATUS_URL = 'https://api.orchagent.io/health/detailed';
|
|
10
11
|
const STATUS_PAGE_URL = 'https://status.orchagent.io';
|
|
@@ -51,7 +52,7 @@ function formatLatency(latencyMs) {
|
|
|
51
52
|
}
|
|
52
53
|
function printHumanStatus(data) {
|
|
53
54
|
const overallStatus = getOverallStatus(data.services);
|
|
54
|
-
process.stdout.write(`\
|
|
55
|
+
process.stdout.write(`\norchagent Status: ${overallStatus}\n\n`);
|
|
55
56
|
for (const service of data.services) {
|
|
56
57
|
const icon = getStatusIcon(service.status);
|
|
57
58
|
const label = getStatusLabel(service.status);
|
|
@@ -64,7 +65,7 @@ function printHumanStatus(data) {
|
|
|
64
65
|
function registerStatusCommand(program) {
|
|
65
66
|
program
|
|
66
67
|
.command('status')
|
|
67
|
-
.description('Check
|
|
68
|
+
.description('Check orchagent service status')
|
|
68
69
|
.option('--json', 'Output raw JSON')
|
|
69
70
|
.action(async (options) => {
|
|
70
71
|
try {
|
|
@@ -86,6 +87,22 @@ function registerStatusCommand(program) {
|
|
|
86
87
|
return;
|
|
87
88
|
}
|
|
88
89
|
printHumanStatus(data);
|
|
90
|
+
// Also verify actual API connectivity
|
|
91
|
+
const config = await (0, config_1.getResolvedConfig)();
|
|
92
|
+
const apiUrl = `${config.apiUrl.replace(/\/$/, '')}/health`;
|
|
93
|
+
try {
|
|
94
|
+
const apiResponse = await fetch(apiUrl, {
|
|
95
|
+
signal: AbortSignal.timeout(5000),
|
|
96
|
+
});
|
|
97
|
+
if (!apiResponse.ok) {
|
|
98
|
+
process.stderr.write('\n' + chalk_1.default.yellow('⚠️ Status page shows operational, but API returned error.') + '\n');
|
|
99
|
+
process.stderr.write(' Run "orchagent doctor" for detailed diagnostics.\n');
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
process.stderr.write('\n' + chalk_1.default.yellow('⚠️ Status page shows operational, but could not reach API.') + '\n');
|
|
104
|
+
process.stderr.write(' Run "orchagent doctor" for detailed diagnostics.\n');
|
|
105
|
+
}
|
|
89
106
|
}
|
|
90
107
|
catch (err) {
|
|
91
108
|
if (options.json) {
|
package/dist/index.js
CHANGED
|
@@ -53,13 +53,18 @@ const package_json_1 = __importDefault(require("../package.json"));
|
|
|
53
53
|
const program = new commander_1.Command();
|
|
54
54
|
program
|
|
55
55
|
.name('orchagent')
|
|
56
|
-
.description('
|
|
56
|
+
.description('orchagent CLI')
|
|
57
57
|
.version(package_json_1.default.version)
|
|
58
58
|
.addHelpText('after', `
|
|
59
59
|
Quick Reference:
|
|
60
60
|
run Download and run an agent locally (your machine)
|
|
61
|
-
call Execute an agent on
|
|
61
|
+
call Execute an agent on orchagent servers (requires login)
|
|
62
62
|
info Show agent details and input/output schemas
|
|
63
|
+
|
|
64
|
+
Documentation: https://docs.orchagent.io
|
|
65
|
+
orchagent docs Open docs in browser
|
|
66
|
+
orchagent docs cli CLI command reference
|
|
67
|
+
orchagent docs agents Building agents guide
|
|
63
68
|
`);
|
|
64
69
|
(0, commands_1.registerCommands)(program);
|
|
65
70
|
program
|
package/dist/lib/api.js
CHANGED
|
@@ -56,6 +56,7 @@ exports.downloadCodeBundleAuthenticated = downloadCodeBundleAuthenticated;
|
|
|
56
56
|
exports.checkAgentDelete = checkAgentDelete;
|
|
57
57
|
exports.deleteAgent = deleteAgent;
|
|
58
58
|
exports.previewAgentVersion = previewAgentVersion;
|
|
59
|
+
exports.reportInstall = reportInstall;
|
|
59
60
|
const errors_1 = require("./errors");
|
|
60
61
|
const DEFAULT_TIMEOUT_MS = 15000;
|
|
61
62
|
async function safeFetch(url, options) {
|
|
@@ -301,3 +302,15 @@ async function deleteAgent(config, agentId, confirmationName) {
|
|
|
301
302
|
async function previewAgentVersion(config, agentName) {
|
|
302
303
|
return request(config, 'GET', `/agents/preview?name=${encodeURIComponent(agentName)}`);
|
|
303
304
|
}
|
|
305
|
+
/**
|
|
306
|
+
* Report a skill installation to the backend.
|
|
307
|
+
* Only tracks authenticated installs (requires API key).
|
|
308
|
+
* Fire-and-forget - errors are silently ignored.
|
|
309
|
+
*/
|
|
310
|
+
async function reportInstall(config, org, skill, version, cliVersion) {
|
|
311
|
+
if (!config.apiKey)
|
|
312
|
+
return;
|
|
313
|
+
await request(config, 'POST', `/agents/${org}/${skill}/${version}/install`, {
|
|
314
|
+
headers: { 'X-CLI-Version': cliVersion },
|
|
315
|
+
});
|
|
316
|
+
}
|
package/dist/lib/browser-auth.js
CHANGED
|
@@ -160,7 +160,7 @@ function successHtml() {
|
|
|
160
160
|
<html>
|
|
161
161
|
<head>
|
|
162
162
|
<meta charset="utf-8">
|
|
163
|
-
<title>
|
|
163
|
+
<title>orchagent CLI - Authentication Successful</title>
|
|
164
164
|
<style>
|
|
165
165
|
body {
|
|
166
166
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
@@ -219,7 +219,7 @@ function errorHtml(message) {
|
|
|
219
219
|
<html>
|
|
220
220
|
<head>
|
|
221
221
|
<meta charset="utf-8">
|
|
222
|
-
<title>
|
|
222
|
+
<title>orchagent CLI - Authentication Error</title>
|
|
223
223
|
<style>
|
|
224
224
|
body {
|
|
225
225
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
package/dist/lib/bundle.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Code bundling utilities for hosted code agents.
|
|
4
4
|
*
|
|
5
|
-
* Creates zip bundles from project directories for upload to
|
|
5
|
+
* Creates zip bundles from project directories for upload to orchagent.
|
|
6
6
|
*/
|
|
7
7
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
8
8
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
@@ -91,7 +91,7 @@ const DEFAULT_EXCLUDES = [
|
|
|
91
91
|
'pytest.ini',
|
|
92
92
|
'.coveragerc',
|
|
93
93
|
'coverage/**',
|
|
94
|
-
//
|
|
94
|
+
// orchagent
|
|
95
95
|
'orchagent.json',
|
|
96
96
|
'bundle.zip',
|
|
97
97
|
'*.zip',
|
|
@@ -24,7 +24,7 @@ async function checkGatewayHealth() {
|
|
|
24
24
|
name: 'gateway_reachable',
|
|
25
25
|
status: 'error',
|
|
26
26
|
message: `Gateway returned ${response.status}`,
|
|
27
|
-
fix: 'Check if
|
|
27
|
+
fix: 'Check if orchagent API is operational at https://status.orchagent.io',
|
|
28
28
|
details: {
|
|
29
29
|
url: healthUrl,
|
|
30
30
|
status: response.status,
|
|
@@ -39,6 +39,17 @@ async function checkServerLlmKeys() {
|
|
|
39
39
|
};
|
|
40
40
|
}
|
|
41
41
|
const providers = keys.map((k) => k.provider);
|
|
42
|
+
// Warn if only one provider configured (no fallback for rate limits)
|
|
43
|
+
if (keys.length === 1) {
|
|
44
|
+
return {
|
|
45
|
+
category: 'llm',
|
|
46
|
+
name: 'server_llm_keys',
|
|
47
|
+
status: 'warning',
|
|
48
|
+
message: `Only 1 LLM provider configured (${providers[0]}). Consider adding a backup for rate limit fallback.`,
|
|
49
|
+
fix: 'Run: orchagent keys add <provider>',
|
|
50
|
+
details: { count: keys.length, providers },
|
|
51
|
+
};
|
|
52
|
+
}
|
|
42
53
|
return {
|
|
43
54
|
category: 'llm',
|
|
44
55
|
name: 'server_llm_keys',
|
|
@@ -58,7 +58,7 @@ function groupByCategory(results) {
|
|
|
58
58
|
function printHumanOutput(results, summary, verbose) {
|
|
59
59
|
// Header
|
|
60
60
|
process.stdout.write('\n');
|
|
61
|
-
process.stdout.write(chalk_1.default.bold('
|
|
61
|
+
process.stdout.write(chalk_1.default.bold('orchagent Doctor\n'));
|
|
62
62
|
process.stdout.write('================\n\n');
|
|
63
63
|
// Group and print results
|
|
64
64
|
const groups = groupByCategory(results);
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@orchagent/cli",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"description": "Command-line interface for the
|
|
3
|
+
"version": "0.2.24",
|
|
4
|
+
"description": "Command-line interface for the orchagent AI agent marketplace",
|
|
5
5
|
"license": "MIT",
|
|
6
|
-
"author": "
|
|
6
|
+
"author": "orchagent <hello@orchagent.io>",
|
|
7
7
|
"homepage": "https://orchagent.io",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|