@orchagent/cli 0.3.49 → 0.3.52
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/commands/agent-keys.js +84 -0
- package/dist/commands/index.js +2 -0
- package/dist/commands/publish.js +70 -6
- package/dist/commands/run.js +779 -122
- package/dist/lib/api.js +17 -0
- package/dist/lib/errors.js +1 -0
- package/dist/lib/sse.js +41 -0
- package/package.json +3 -2
- package/src/resources/agent_runner.py +791 -0
|
@@ -0,0 +1,84 @@
|
|
|
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.registerAgentKeysCommand = registerAgentKeysCommand;
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const config_1 = require("../lib/config");
|
|
9
|
+
const api_1 = require("../lib/api");
|
|
10
|
+
const errors_1 = require("../lib/errors");
|
|
11
|
+
/**
|
|
12
|
+
* Resolve an agent reference ("org/agent" or just "agent") to an agent ID.
|
|
13
|
+
* Uses the authenticated list-agents endpoint and finds the latest version.
|
|
14
|
+
*/
|
|
15
|
+
async function resolveAgentId(config, ref) {
|
|
16
|
+
const parts = ref.split('/');
|
|
17
|
+
const agentName = parts.length >= 2 ? parts[1] : parts[0];
|
|
18
|
+
const agents = await (0, api_1.listMyAgents)(config);
|
|
19
|
+
const matching = agents.filter(a => a.name === agentName);
|
|
20
|
+
if (matching.length === 0) {
|
|
21
|
+
throw new errors_1.CliError(`Agent '${ref}' not found. Run 'orchagent agents' to list your agents.`);
|
|
22
|
+
}
|
|
23
|
+
// Use the latest version
|
|
24
|
+
const latest = matching.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime())[0];
|
|
25
|
+
return { agent: latest, agentId: latest.id };
|
|
26
|
+
}
|
|
27
|
+
function registerAgentKeysCommand(program) {
|
|
28
|
+
const agentKeys = program
|
|
29
|
+
.command('agent-keys')
|
|
30
|
+
.description('Manage agent service keys');
|
|
31
|
+
agentKeys
|
|
32
|
+
.command('list <agent>')
|
|
33
|
+
.description('List service keys for an agent (org/name or name)')
|
|
34
|
+
.action(async (ref) => {
|
|
35
|
+
const config = await (0, config_1.getResolvedConfig)();
|
|
36
|
+
if (!config.apiKey) {
|
|
37
|
+
throw new errors_1.CliError('Missing API key. Run `orchagent login` first.');
|
|
38
|
+
}
|
|
39
|
+
const { agent, agentId } = await resolveAgentId(config, ref);
|
|
40
|
+
const result = await (0, api_1.listAgentKeys)(config, agentId);
|
|
41
|
+
if (result.keys.length === 0) {
|
|
42
|
+
process.stdout.write(`No service keys for ${agent.name}.\n`);
|
|
43
|
+
process.stdout.write(`\nCreate one with: orchagent agent-keys create ${ref}\n`);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
process.stdout.write(`Service keys for ${agent.name}:\n\n`);
|
|
47
|
+
process.stdout.write(` ${'ID'.padEnd(38)} ${'PREFIX'.padEnd(14)} ${'CREATED'.padEnd(22)} LAST USED\n`);
|
|
48
|
+
process.stdout.write(` ${'─'.repeat(38)} ${'─'.repeat(14)} ${'─'.repeat(22)} ${'─'.repeat(22)}\n`);
|
|
49
|
+
for (const key of result.keys) {
|
|
50
|
+
const created = new Date(key.created_at).toLocaleDateString();
|
|
51
|
+
const lastUsed = key.last_used_at
|
|
52
|
+
? new Date(key.last_used_at).toLocaleDateString()
|
|
53
|
+
: chalk_1.default.gray('never');
|
|
54
|
+
process.stdout.write(` ${key.id.padEnd(38)} ${key.prefix.padEnd(14)} ${created.padEnd(22)} ${lastUsed}\n`);
|
|
55
|
+
}
|
|
56
|
+
process.stdout.write('\n');
|
|
57
|
+
});
|
|
58
|
+
agentKeys
|
|
59
|
+
.command('create <agent>')
|
|
60
|
+
.description('Create a new service key for an agent')
|
|
61
|
+
.action(async (ref) => {
|
|
62
|
+
const config = await (0, config_1.getResolvedConfig)();
|
|
63
|
+
if (!config.apiKey) {
|
|
64
|
+
throw new errors_1.CliError('Missing API key. Run `orchagent login` first.');
|
|
65
|
+
}
|
|
66
|
+
const { agent } = await resolveAgentId(config, ref);
|
|
67
|
+
const result = await (0, api_1.createAgentKey)(config, agent.id);
|
|
68
|
+
process.stdout.write(`\nNew service key for ${agent.name}:\n\n`);
|
|
69
|
+
process.stdout.write(` ${result.key}\n\n`);
|
|
70
|
+
process.stderr.write(chalk_1.default.yellow('Save this key now — it cannot be retrieved again.\n'));
|
|
71
|
+
});
|
|
72
|
+
agentKeys
|
|
73
|
+
.command('delete <agent> <key-id>')
|
|
74
|
+
.description('Delete a service key')
|
|
75
|
+
.action(async (ref, keyId) => {
|
|
76
|
+
const config = await (0, config_1.getResolvedConfig)();
|
|
77
|
+
if (!config.apiKey) {
|
|
78
|
+
throw new errors_1.CliError('Missing API key. Run `orchagent login` first.');
|
|
79
|
+
}
|
|
80
|
+
const { agent, agentId } = await resolveAgentId(config, ref);
|
|
81
|
+
await (0, api_1.deleteAgentKey)(config, agentId, keyId);
|
|
82
|
+
process.stdout.write(`Deleted key ${keyId} from ${agent.name}.\n`);
|
|
83
|
+
});
|
|
84
|
+
}
|
package/dist/commands/index.js
CHANGED
|
@@ -27,6 +27,7 @@ const list_1 = require("./list");
|
|
|
27
27
|
const test_1 = require("./test");
|
|
28
28
|
const security_1 = require("./security");
|
|
29
29
|
const billing_1 = require("./billing");
|
|
30
|
+
const agent_keys_1 = require("./agent-keys");
|
|
30
31
|
function registerCommands(program) {
|
|
31
32
|
(0, login_1.registerLoginCommand)(program);
|
|
32
33
|
(0, whoami_1.registerWhoamiCommand)(program);
|
|
@@ -54,4 +55,5 @@ function registerCommands(program) {
|
|
|
54
55
|
(0, test_1.registerTestCommand)(program);
|
|
55
56
|
(0, security_1.registerSecurityCommand)(program);
|
|
56
57
|
(0, billing_1.registerBillingCommand)(program);
|
|
58
|
+
(0, agent_keys_1.registerAgentKeysCommand)(program);
|
|
57
59
|
}
|
package/dist/commands/publish.js
CHANGED
|
@@ -14,6 +14,7 @@ const chalk_1 = __importDefault(require("chalk"));
|
|
|
14
14
|
const config_1 = require("../lib/config");
|
|
15
15
|
const api_1 = require("../lib/api");
|
|
16
16
|
const errors_1 = require("../lib/errors");
|
|
17
|
+
const api_2 = require("../lib/api");
|
|
17
18
|
const analytics_1 = require("../lib/analytics");
|
|
18
19
|
const bundle_1 = require("../lib/bundle");
|
|
19
20
|
/**
|
|
@@ -268,15 +269,38 @@ function registerPublishCommand(program) {
|
|
|
268
269
|
if (!manifest.name) {
|
|
269
270
|
throw new errors_1.CliError('orchagent.json must have name');
|
|
270
271
|
}
|
|
271
|
-
// Warn about deprecated
|
|
272
|
+
// Warn about deprecated prompt field
|
|
272
273
|
if (manifest.prompt) {
|
|
273
274
|
process.stderr.write(chalk_1.default.yellow('Warning: "prompt" field in orchagent.json is ignored. Use prompt.md file instead.\n'));
|
|
274
275
|
}
|
|
275
|
-
|
|
276
|
-
|
|
276
|
+
// Auto-migrate inline schemas to schema.json
|
|
277
|
+
const schemaPath = path_1.default.join(cwd, 'schema.json');
|
|
278
|
+
let schemaFileExists = false;
|
|
279
|
+
try {
|
|
280
|
+
await promises_1.default.access(schemaPath);
|
|
281
|
+
schemaFileExists = true;
|
|
277
282
|
}
|
|
278
|
-
|
|
279
|
-
|
|
283
|
+
catch {
|
|
284
|
+
// File doesn't exist
|
|
285
|
+
}
|
|
286
|
+
if ((manifest.input_schema || manifest.output_schema) && !schemaFileExists) {
|
|
287
|
+
// Auto-create schema.json from inline schemas
|
|
288
|
+
const schemaContent = {};
|
|
289
|
+
if (manifest.input_schema)
|
|
290
|
+
schemaContent.input = manifest.input_schema;
|
|
291
|
+
if (manifest.output_schema)
|
|
292
|
+
schemaContent.output = manifest.output_schema;
|
|
293
|
+
if (options.dryRun) {
|
|
294
|
+
process.stderr.write(chalk_1.default.cyan('Would create schema.json from inline schemas in orchagent.json\n'));
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
await promises_1.default.writeFile(schemaPath, JSON.stringify(schemaContent, null, 2) + '\n');
|
|
298
|
+
process.stderr.write(chalk_1.default.green('Created schema.json from inline schemas in orchagent.json\n'));
|
|
299
|
+
process.stderr.write(chalk_1.default.yellow('You can now remove input_schema/output_schema from orchagent.json\n'));
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
else if ((manifest.input_schema || manifest.output_schema) && schemaFileExists) {
|
|
303
|
+
process.stderr.write(chalk_1.default.yellow('Warning: inline schemas in orchagent.json are ignored (schema.json takes priority).\n'));
|
|
280
304
|
}
|
|
281
305
|
// Check for misplaced manifest fields at top level (common user error)
|
|
282
306
|
const manifestFields = ['manifest_version', 'dependencies', 'max_hops', 'timeout_ms', 'per_call_downstream_cap'];
|
|
@@ -361,7 +385,6 @@ function registerPublishCommand(program) {
|
|
|
361
385
|
let inputSchema;
|
|
362
386
|
let outputSchema;
|
|
363
387
|
let schemaFromFile = false;
|
|
364
|
-
const schemaPath = path_1.default.join(cwd, 'schema.json');
|
|
365
388
|
try {
|
|
366
389
|
const raw = await promises_1.default.readFile(schemaPath, 'utf-8');
|
|
367
390
|
const schemas = JSON.parse(raw);
|
|
@@ -560,6 +583,34 @@ function registerPublishCommand(program) {
|
|
|
560
583
|
});
|
|
561
584
|
}
|
|
562
585
|
catch (err) {
|
|
586
|
+
// Improve SECURITY_BLOCKED error display
|
|
587
|
+
if (err instanceof api_2.ApiError && err.status === 422) {
|
|
588
|
+
const payload = err.payload;
|
|
589
|
+
const errorCode = payload?.error?.code;
|
|
590
|
+
if (errorCode === 'SECURITY_BLOCKED') {
|
|
591
|
+
const analysis = payload?.security_analysis;
|
|
592
|
+
const blockReason = payload?.error?.message || 'Security pattern detected';
|
|
593
|
+
process.stderr.write(chalk_1.default.red(`\nPublish blocked: ${blockReason}\n\n`));
|
|
594
|
+
// Show matched patterns with file:line
|
|
595
|
+
const matches = (analysis?.matches || []);
|
|
596
|
+
if (matches.length > 0) {
|
|
597
|
+
process.stderr.write(chalk_1.default.yellow('Patterns detected:\n'));
|
|
598
|
+
for (const match of matches.slice(0, 5)) {
|
|
599
|
+
const severity = String(match.severity || '').toUpperCase();
|
|
600
|
+
const file = match.file_path || 'unknown';
|
|
601
|
+
const line = match.line_number || '?';
|
|
602
|
+
const desc = match.description || match.pattern_id || '';
|
|
603
|
+
process.stderr.write(` ${chalk_1.default.red(severity)} ${file}:${line} — ${desc}\n`);
|
|
604
|
+
}
|
|
605
|
+
process.stderr.write('\n');
|
|
606
|
+
}
|
|
607
|
+
process.stderr.write('Skills are scanned for patterns that could instruct AI agents to\n' +
|
|
608
|
+
'perform harmful actions (shell injection, data exfiltration, etc.).\n\n' +
|
|
609
|
+
'Code-execution references (eval, subprocess, importlib) are allowed\n' +
|
|
610
|
+
'since the E2B sandbox is the security boundary for code execution.\n');
|
|
611
|
+
throw new errors_1.CliError('Publish blocked by security scan', errors_1.ExitCodes.PERMISSION_DENIED);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
563
614
|
throw err;
|
|
564
615
|
}
|
|
565
616
|
const assignedVersion = result.agent?.version || 'v1';
|
|
@@ -636,6 +687,19 @@ function registerPublishCommand(program) {
|
|
|
636
687
|
process.stdout.write(`Type: ${manifest.type}${shouldUploadBundle ? ' (hosted)' : ''}\n`);
|
|
637
688
|
process.stdout.write(`Providers: ${supportedProviders.join(', ')}\n`);
|
|
638
689
|
process.stdout.write(`Visibility: private\n`);
|
|
690
|
+
// Show security review result if available
|
|
691
|
+
const secReview = result.security_review;
|
|
692
|
+
if (secReview?.verdict) {
|
|
693
|
+
if (secReview.verdict === 'passed') {
|
|
694
|
+
process.stdout.write(`Security: ${chalk_1.default.green('passed')}\n`);
|
|
695
|
+
}
|
|
696
|
+
else if (secReview.verdict === 'flagged') {
|
|
697
|
+
process.stdout.write(`Security: ${chalk_1.default.yellow('flagged')} — ${secReview.summary || 'review recommended'}\n`);
|
|
698
|
+
}
|
|
699
|
+
else {
|
|
700
|
+
process.stdout.write(`Security: ${secReview.verdict}\n`);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
639
703
|
if (result.service_key) {
|
|
640
704
|
process.stdout.write(`\nService key (save this - shown only once):\n`);
|
|
641
705
|
process.stdout.write(` ${result.service_key}\n`);
|