@orchagent/cli 0.3.85 → 0.3.87
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 +21 -7
- package/dist/commands/agents.js +60 -5
- package/dist/commands/config.js +4 -0
- package/dist/commands/delete.js +3 -9
- package/dist/commands/dev.js +226 -0
- package/dist/commands/diff.js +418 -0
- package/dist/commands/estimate.js +105 -0
- package/dist/commands/fork.js +11 -1
- package/dist/commands/health.js +226 -0
- package/dist/commands/index.js +8 -0
- package/dist/commands/info.js +75 -0
- package/dist/commands/init.js +729 -38
- package/dist/commands/publish.js +244 -22
- package/dist/commands/run.js +275 -29
- package/dist/commands/schedule.js +25 -8
- package/dist/commands/skill.js +3 -3
- package/dist/commands/test.js +68 -1
- package/dist/lib/api.js +29 -4
- package/dist/lib/batch-publish.js +223 -0
- package/dist/lib/dev-server.js +425 -0
- package/dist/lib/doctor/checks/environment.js +1 -1
- package/dist/lib/key-store.js +121 -0
- package/dist/lib/spinner.js +50 -0
- package/dist/lib/test-mock-runner.js +334 -0
- package/dist/lib/update-notifier.js +1 -1
- package/package.json +1 -1
- package/src/resources/__pycache__/agent_runner.cpython-311.pyc +0 -0
- package/src/resources/__pycache__/agent_runner.cpython-312.pyc +0 -0
- package/src/resources/__pycache__/test_agent_runner_mocks.cpython-311-pytest-9.0.2.pyc +0 -0
- package/src/resources/__pycache__/test_agent_runner_mocks.cpython-312-pytest-8.4.2.pyc +0 -0
- package/src/resources/agent_runner.py +29 -2
- package/src/resources/test_agent_runner_mocks.py +290 -0
package/dist/commands/publish.js
CHANGED
|
@@ -42,17 +42,21 @@ exports.scanUndeclaredEnvVars = scanUndeclaredEnvVars;
|
|
|
42
42
|
exports.scanReservedPort = scanReservedPort;
|
|
43
43
|
exports.detectSdkCompatible = detectSdkCompatible;
|
|
44
44
|
exports.checkDependencies = checkDependencies;
|
|
45
|
+
exports.batchPublish = batchPublish;
|
|
45
46
|
exports.registerPublishCommand = registerPublishCommand;
|
|
46
47
|
const promises_1 = __importDefault(require("fs/promises"));
|
|
47
48
|
const path_1 = __importDefault(require("path"));
|
|
48
49
|
const os_1 = __importDefault(require("os"));
|
|
49
50
|
const yaml_1 = __importDefault(require("yaml"));
|
|
50
51
|
const chalk_1 = __importDefault(require("chalk"));
|
|
52
|
+
const child_process_1 = require("child_process");
|
|
51
53
|
const config_1 = require("../lib/config");
|
|
52
54
|
const api_1 = require("../lib/api");
|
|
53
55
|
const errors_1 = require("../lib/errors");
|
|
54
56
|
const analytics_1 = require("../lib/analytics");
|
|
55
57
|
const bundle_1 = require("../lib/bundle");
|
|
58
|
+
const key_store_1 = require("../lib/key-store");
|
|
59
|
+
const batch_publish_1 = require("../lib/batch-publish");
|
|
56
60
|
/**
|
|
57
61
|
* Extract template placeholders from a prompt template.
|
|
58
62
|
* Matches double-brace patterns like {{variable}}.
|
|
@@ -442,6 +446,133 @@ async function checkDependencies(config, dependencies, publishingOrgSlug, worksp
|
|
|
442
446
|
}
|
|
443
447
|
}));
|
|
444
448
|
}
|
|
449
|
+
/**
|
|
450
|
+
* Batch publish all agents found in subdirectories, in dependency order.
|
|
451
|
+
* Discovers orchagent.json/SKILL.md in immediate subdirectories,
|
|
452
|
+
* topologically sorts by manifest dependencies, and publishes leaf-first.
|
|
453
|
+
*/
|
|
454
|
+
async function batchPublish(rootDir, options) {
|
|
455
|
+
process.stderr.write(`\nScanning for agents in ${rootDir}...\n`);
|
|
456
|
+
const agents = await (0, batch_publish_1.discoverAgents)(rootDir);
|
|
457
|
+
if (agents.length === 0) {
|
|
458
|
+
throw new errors_1.CliError('No agents found. Expected subdirectories with orchagent.json or SKILL.md files.\n\n' +
|
|
459
|
+
'Example monorepo layout:\n' +
|
|
460
|
+
' my-project/\n' +
|
|
461
|
+
' leaf-tool/\n' +
|
|
462
|
+
' orchagent.json\n' +
|
|
463
|
+
' orchestrator/\n' +
|
|
464
|
+
' orchagent.json\n' +
|
|
465
|
+
' prompt.md\n\n' +
|
|
466
|
+
'Run `orch publish --all` from the parent directory.');
|
|
467
|
+
}
|
|
468
|
+
const result = (0, batch_publish_1.topoSort)(agents);
|
|
469
|
+
if (!result.ok) {
|
|
470
|
+
throw new errors_1.CliError(`Circular dependency detected between: ${result.cycle.join(' → ')}\n\n` +
|
|
471
|
+
'Break the cycle by removing a dependency in one of these agents\' orchagent.json manifest.dependencies.');
|
|
472
|
+
}
|
|
473
|
+
const sorted = result.sorted;
|
|
474
|
+
// Resolve org for display (best-effort)
|
|
475
|
+
let orgSlug;
|
|
476
|
+
try {
|
|
477
|
+
const config = await (0, config_1.getResolvedConfig)({}, options.profile);
|
|
478
|
+
const configFile = await (0, config_1.loadConfig)();
|
|
479
|
+
let workspaceId;
|
|
480
|
+
if (configFile.workspace && !options.profile) {
|
|
481
|
+
const { workspaces } = await (0, api_1.request)(config, 'GET', '/workspaces');
|
|
482
|
+
const ws = workspaces.find(w => w.slug === configFile.workspace);
|
|
483
|
+
if (ws)
|
|
484
|
+
workspaceId = ws.id;
|
|
485
|
+
}
|
|
486
|
+
const org = await (0, api_1.getOrg)(config, workspaceId);
|
|
487
|
+
orgSlug = org.slug;
|
|
488
|
+
}
|
|
489
|
+
catch {
|
|
490
|
+
// Non-critical — just won't show org prefix
|
|
491
|
+
}
|
|
492
|
+
const plan = (0, batch_publish_1.formatPublishPlan)(sorted, orgSlug);
|
|
493
|
+
process.stderr.write(plan);
|
|
494
|
+
if (options.dryRun) {
|
|
495
|
+
process.stderr.write(chalk_1.default.cyan('DRY RUN — running orch publish --dry-run in each directory:\n\n'));
|
|
496
|
+
}
|
|
497
|
+
// Build the CLI args to forward (exclude --all)
|
|
498
|
+
const forwardArgs = [];
|
|
499
|
+
if (options.profile)
|
|
500
|
+
forwardArgs.push('--profile', options.profile);
|
|
501
|
+
if (options.dryRun)
|
|
502
|
+
forwardArgs.push('--dry-run');
|
|
503
|
+
if (options.skills)
|
|
504
|
+
forwardArgs.push('--skills', options.skills);
|
|
505
|
+
if (options.skillsLocked)
|
|
506
|
+
forwardArgs.push('--skills-locked');
|
|
507
|
+
if (options.docker)
|
|
508
|
+
forwardArgs.push('--docker');
|
|
509
|
+
if (options.localDownload)
|
|
510
|
+
forwardArgs.push('--local-download');
|
|
511
|
+
if (options.requiredSecrets === false)
|
|
512
|
+
forwardArgs.push('--no-required-secrets');
|
|
513
|
+
const results = [];
|
|
514
|
+
for (let i = 0; i < sorted.length; i++) {
|
|
515
|
+
const agent = sorted[i];
|
|
516
|
+
const label = `[${i + 1}/${sorted.length}]`;
|
|
517
|
+
process.stderr.write(`${chalk_1.default.bold(label)} Publishing ${chalk_1.default.cyan(agent.name)} from ${agent.dirName}/...\n`);
|
|
518
|
+
// Spawn orch publish in the agent's directory
|
|
519
|
+
const spawnResult = (0, child_process_1.spawnSync)(process.argv[0], [process.argv[1], 'publish', ...forwardArgs], {
|
|
520
|
+
cwd: agent.dir,
|
|
521
|
+
stdio: ['inherit', 'inherit', 'inherit'],
|
|
522
|
+
env: process.env,
|
|
523
|
+
timeout: 120_000, // 2 minute timeout per agent
|
|
524
|
+
});
|
|
525
|
+
if (spawnResult.status === 0) {
|
|
526
|
+
results.push({ name: agent.name, dir: agent.dirName, success: true });
|
|
527
|
+
}
|
|
528
|
+
else {
|
|
529
|
+
const errMsg = spawnResult.error?.message || `exit code ${spawnResult.status}`;
|
|
530
|
+
results.push({ name: agent.name, dir: agent.dirName, success: false, error: errMsg });
|
|
531
|
+
// Stop on first failure — downstream agents depend on this one
|
|
532
|
+
process.stderr.write(chalk_1.default.red(`\n✗ Failed to publish ${agent.name}. Stopping — downstream agents may depend on it.\n`));
|
|
533
|
+
break;
|
|
534
|
+
}
|
|
535
|
+
if (i < sorted.length - 1) {
|
|
536
|
+
process.stderr.write('\n'); // Visual separator between publishes
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
// Summary
|
|
540
|
+
const succeeded = results.filter(r => r.success);
|
|
541
|
+
const failed = results.filter(r => !r.success);
|
|
542
|
+
const skipped = sorted.length - results.length;
|
|
543
|
+
process.stderr.write('\n' + chalk_1.default.bold('─'.repeat(50)) + '\n');
|
|
544
|
+
process.stderr.write(chalk_1.default.bold(`Batch publish summary:\n\n`));
|
|
545
|
+
for (const r of results) {
|
|
546
|
+
if (r.success) {
|
|
547
|
+
process.stderr.write(` ${chalk_1.default.green('✔')} ${r.name}\n`);
|
|
548
|
+
}
|
|
549
|
+
else {
|
|
550
|
+
process.stderr.write(` ${chalk_1.default.red('✗')} ${r.name} — ${r.error}\n`);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
if (skipped > 0) {
|
|
554
|
+
const skippedAgents = sorted.slice(results.length);
|
|
555
|
+
for (const a of skippedAgents) {
|
|
556
|
+
process.stderr.write(` ${chalk_1.default.yellow('○')} ${a.name} (skipped)\n`);
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
process.stderr.write(`\n ${succeeded.length} succeeded`);
|
|
560
|
+
if (failed.length > 0)
|
|
561
|
+
process.stderr.write(`, ${chalk_1.default.red(`${failed.length} failed`)}`);
|
|
562
|
+
if (skipped > 0)
|
|
563
|
+
process.stderr.write(`, ${chalk_1.default.yellow(`${skipped} skipped`)}`);
|
|
564
|
+
process.stderr.write('\n');
|
|
565
|
+
await (0, analytics_1.track)('cli_publish_all', {
|
|
566
|
+
total: sorted.length,
|
|
567
|
+
succeeded: succeeded.length,
|
|
568
|
+
failed: failed.length,
|
|
569
|
+
skipped,
|
|
570
|
+
dry_run: options.dryRun || false,
|
|
571
|
+
});
|
|
572
|
+
if (failed.length > 0) {
|
|
573
|
+
throw new errors_1.CliError(`Batch publish failed: ${failed[0].name}`, errors_1.ExitCodes.GENERAL_ERROR);
|
|
574
|
+
}
|
|
575
|
+
}
|
|
445
576
|
function registerPublishCommand(program) {
|
|
446
577
|
program
|
|
447
578
|
.command('publish')
|
|
@@ -454,12 +585,18 @@ function registerPublishCommand(program) {
|
|
|
454
585
|
.option('--docker', 'Include Dockerfile for custom environment (builds E2B template)')
|
|
455
586
|
.option('--local-download', 'Allow users to download and run locally (default: server-only)')
|
|
456
587
|
.option('--no-required-secrets', 'Skip required_secrets check for tool/agent types')
|
|
588
|
+
.option('--all', 'Publish all agents in subdirectories (dependency order)')
|
|
457
589
|
.action(async (options) => {
|
|
590
|
+
const cwd = process.cwd();
|
|
591
|
+
// --all: batch publish all agents in subdirectories
|
|
592
|
+
if (options.all) {
|
|
593
|
+
await batchPublish(cwd, options);
|
|
594
|
+
return;
|
|
595
|
+
}
|
|
458
596
|
const skillsFromFlag = options.skills
|
|
459
597
|
? options.skills.split(',').map(s => s.trim()).filter(Boolean)
|
|
460
598
|
: undefined;
|
|
461
599
|
const config = await (0, config_1.getResolvedConfig)({}, options.profile);
|
|
462
|
-
const cwd = process.cwd();
|
|
463
600
|
// Resolve workspace context — if `orch workspace use` was called, publish
|
|
464
601
|
// to that workspace instead of the personal org (F-5)
|
|
465
602
|
// Skip workspace resolution when using a named profile — the global
|
|
@@ -476,7 +613,7 @@ function registerPublishCommand(program) {
|
|
|
476
613
|
// Warn when publishing to the public showcase workspace
|
|
477
614
|
if (ws.slug === 'orchagent-public' && !options.dryRun) {
|
|
478
615
|
process.stderr.write(chalk_1.default.red.bold('\n PUBLIC WORKSPACE\n') +
|
|
479
|
-
chalk_1.default.red(` Everything published to "${ws.slug}" is publicly visible on orchagent.io
|
|
616
|
+
chalk_1.default.red(` Everything published to "${ws.slug}" is publicly visible on orchagent.io.\n\n`));
|
|
480
617
|
const readline = await Promise.resolve().then(() => __importStar(require('readline/promises')));
|
|
481
618
|
const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
|
|
482
619
|
const answer = await rl.question(chalk_1.default.red(' Continue? (y/N): '));
|
|
@@ -610,6 +747,11 @@ function registerPublishCommand(program) {
|
|
|
610
747
|
if (runMode === 'always_on' && executionEngine === 'direct_llm') {
|
|
611
748
|
throw new errors_1.CliError('run_mode=always_on requires runtime.command or loop configuration');
|
|
612
749
|
}
|
|
750
|
+
if (manifest.timeout_seconds !== undefined) {
|
|
751
|
+
if (!Number.isInteger(manifest.timeout_seconds) || manifest.timeout_seconds <= 0) {
|
|
752
|
+
throw new errors_1.CliError('timeout_seconds must be a positive integer');
|
|
753
|
+
}
|
|
754
|
+
}
|
|
613
755
|
// Warn about deprecated prompt field
|
|
614
756
|
if (manifest.prompt) {
|
|
615
757
|
process.stderr.write(chalk_1.default.yellow('Warning: "prompt" field in orchagent.json is ignored. Use prompt.md file instead.\n'));
|
|
@@ -681,24 +823,6 @@ function registerPublishCommand(program) {
|
|
|
681
823
|
// Validate managed-loop specific fields + normalize loop payload
|
|
682
824
|
let loopConfig;
|
|
683
825
|
if (executionEngine === 'managed_loop') {
|
|
684
|
-
if (manifest.custom_tools) {
|
|
685
|
-
const reservedNames = new Set(['bash', 'read_file', 'write_file', 'list_files', 'submit_result']);
|
|
686
|
-
const seenNames = new Set();
|
|
687
|
-
for (const tool of manifest.custom_tools) {
|
|
688
|
-
if (!tool.name || !tool.command) {
|
|
689
|
-
throw new errors_1.CliError(`Invalid custom_tool: each tool must have 'name' and 'command' fields.\n` +
|
|
690
|
-
`Found: ${JSON.stringify(tool)}`);
|
|
691
|
-
}
|
|
692
|
-
if (reservedNames.has(tool.name)) {
|
|
693
|
-
throw new errors_1.CliError(`Custom tool '${tool.name}' conflicts with a built-in tool name.\n` +
|
|
694
|
-
`Reserved names: ${[...reservedNames].join(', ')}`);
|
|
695
|
-
}
|
|
696
|
-
if (seenNames.has(tool.name)) {
|
|
697
|
-
throw new errors_1.CliError(`Duplicate custom tool name: '${tool.name}'`);
|
|
698
|
-
}
|
|
699
|
-
seenNames.add(tool.name);
|
|
700
|
-
}
|
|
701
|
-
}
|
|
702
826
|
if (manifest.max_turns !== undefined) {
|
|
703
827
|
if (typeof manifest.max_turns !== 'number' || manifest.max_turns < 1 || manifest.max_turns > 50) {
|
|
704
828
|
throw new errors_1.CliError('max_turns must be a number between 1 and 50');
|
|
@@ -717,6 +841,27 @@ function registerPublishCommand(program) {
|
|
|
717
841
|
providedLoop.max_turns = 25;
|
|
718
842
|
}
|
|
719
843
|
loopConfig = providedLoop;
|
|
844
|
+
// Validate custom_tools from the merged loopConfig (covers both top-level
|
|
845
|
+
// manifest.custom_tools and loop.custom_tools placements — BUG-15)
|
|
846
|
+
const mergedTools = Array.isArray(loopConfig.custom_tools) ? loopConfig.custom_tools : [];
|
|
847
|
+
if (mergedTools.length > 0) {
|
|
848
|
+
const reservedNames = new Set(['bash', 'read_file', 'write_file', 'list_files', 'submit_result']);
|
|
849
|
+
const seenNames = new Set();
|
|
850
|
+
for (const tool of mergedTools) {
|
|
851
|
+
if (!tool.name || !tool.command) {
|
|
852
|
+
throw new errors_1.CliError(`Invalid custom_tool: each tool must have 'name' and 'command' fields.\n` +
|
|
853
|
+
`Found: ${JSON.stringify(tool)}`);
|
|
854
|
+
}
|
|
855
|
+
if (reservedNames.has(tool.name)) {
|
|
856
|
+
throw new errors_1.CliError(`Custom tool '${tool.name}' conflicts with a built-in tool name.\n` +
|
|
857
|
+
`Reserved names: ${[...reservedNames].join(', ')}`);
|
|
858
|
+
}
|
|
859
|
+
if (seenNames.has(tool.name)) {
|
|
860
|
+
throw new errors_1.CliError(`Duplicate custom tool name: '${tool.name}'`);
|
|
861
|
+
}
|
|
862
|
+
seenNames.add(tool.name);
|
|
863
|
+
}
|
|
864
|
+
}
|
|
720
865
|
if (!manifest.supported_providers) {
|
|
721
866
|
manifest.supported_providers = ['anthropic'];
|
|
722
867
|
}
|
|
@@ -865,7 +1010,7 @@ function registerPublishCommand(program) {
|
|
|
865
1010
|
const schemaTypes = [inputSchema ? 'input' : null, outputSchema ? 'output' : null].filter(Boolean).join(' + ');
|
|
866
1011
|
process.stderr.write(` ✓ schema.json found (${schemaTypes} schemas)\n`);
|
|
867
1012
|
}
|
|
868
|
-
const customToolCount =
|
|
1013
|
+
const customToolCount = Array.isArray(loopConfig?.custom_tools) ? loopConfig.custom_tools.length : 0;
|
|
869
1014
|
process.stderr.write(` ✓ Custom tools: ${customToolCount}\n`);
|
|
870
1015
|
process.stderr.write(` ✓ Max turns: ${loopConfig?.max_turns || manifest.max_turns || 25}\n`);
|
|
871
1016
|
}
|
|
@@ -912,6 +1057,71 @@ function registerPublishCommand(program) {
|
|
|
912
1057
|
if (manifest.required_secrets?.length) {
|
|
913
1058
|
process.stderr.write(` Secrets: ${manifest.required_secrets.join(', ')}\n`);
|
|
914
1059
|
}
|
|
1060
|
+
if (manifest.environment) {
|
|
1061
|
+
const envParts = [];
|
|
1062
|
+
if (manifest.environment.python_version)
|
|
1063
|
+
envParts.push(`Python ${manifest.environment.python_version}`);
|
|
1064
|
+
if (manifest.environment.node_version)
|
|
1065
|
+
envParts.push(`Node ${manifest.environment.node_version}`);
|
|
1066
|
+
if (manifest.environment.pip_flags)
|
|
1067
|
+
envParts.push(`pip: ${manifest.environment.pip_flags}`);
|
|
1068
|
+
if (manifest.environment.npm_flags)
|
|
1069
|
+
envParts.push(`npm: ${manifest.environment.npm_flags}`);
|
|
1070
|
+
if (envParts.length) {
|
|
1071
|
+
process.stderr.write(` Environment: ${envParts.join(', ')}\n`);
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
// Server-side validation (BUG-11: dry-run missed server-side checks)
|
|
1075
|
+
process.stderr.write(`\nServer validation...\n`);
|
|
1076
|
+
try {
|
|
1077
|
+
const validation = await (0, api_1.validateAgentPublish)(config, {
|
|
1078
|
+
name: manifest.name,
|
|
1079
|
+
type: canonicalType,
|
|
1080
|
+
run_mode: runMode,
|
|
1081
|
+
runtime: runtimeConfig,
|
|
1082
|
+
loop: loopConfig,
|
|
1083
|
+
callable,
|
|
1084
|
+
description: manifest.description,
|
|
1085
|
+
prompt,
|
|
1086
|
+
url: agentUrl,
|
|
1087
|
+
input_schema: inputSchema,
|
|
1088
|
+
output_schema: outputSchema,
|
|
1089
|
+
is_public: false,
|
|
1090
|
+
supported_providers: supportedProviders,
|
|
1091
|
+
default_models: manifest.default_models,
|
|
1092
|
+
timeout_seconds: manifest.timeout_seconds,
|
|
1093
|
+
run_command: manifest.run_command,
|
|
1094
|
+
sdk_compatible: sdkCompatible || undefined,
|
|
1095
|
+
manifest: manifest.manifest,
|
|
1096
|
+
required_secrets: manifest.required_secrets,
|
|
1097
|
+
default_skills: skillsFromFlag || manifest.default_skills,
|
|
1098
|
+
skills_locked: manifest.skills_locked || options.skillsLocked || undefined,
|
|
1099
|
+
allow_local_download: options.localDownload || false,
|
|
1100
|
+
environment: manifest.environment,
|
|
1101
|
+
}, workspaceId);
|
|
1102
|
+
if (validation.warnings?.length) {
|
|
1103
|
+
for (const warning of validation.warnings) {
|
|
1104
|
+
process.stderr.write(chalk_1.default.yellow(` ⚠ ${warning}\n`));
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
if (!validation.valid) {
|
|
1108
|
+
for (const error of validation.errors) {
|
|
1109
|
+
process.stderr.write(chalk_1.default.red(` ✗ ${error}\n`));
|
|
1110
|
+
}
|
|
1111
|
+
process.stderr.write(chalk_1.default.red(`\nDry run failed: server-side validation found ${validation.errors.length} error(s)\n`));
|
|
1112
|
+
process.stderr.write('No changes made (dry run)\n');
|
|
1113
|
+
const err = new errors_1.CliError('Server-side validation failed', errors_1.ExitCodes.INVALID_INPUT);
|
|
1114
|
+
err.displayed = true;
|
|
1115
|
+
throw err;
|
|
1116
|
+
}
|
|
1117
|
+
process.stderr.write(` ✓ Server-side validation passed\n`);
|
|
1118
|
+
}
|
|
1119
|
+
catch (err) {
|
|
1120
|
+
if (err instanceof errors_1.CliError)
|
|
1121
|
+
throw err;
|
|
1122
|
+
// Network or auth errors — show warning but don't block dry-run
|
|
1123
|
+
process.stderr.write(chalk_1.default.yellow(` ⚠ Could not reach server for validation (offline?)\n`));
|
|
1124
|
+
}
|
|
915
1125
|
process.stderr.write(`\nWould publish: ${preview.org_slug}/${manifest.name}@${preview.next_version}\n`);
|
|
916
1126
|
if (shouldUploadBundle) {
|
|
917
1127
|
const bundlePreview = await (0, bundle_1.previewBundle)(cwd, {
|
|
@@ -994,6 +1204,7 @@ function registerPublishCommand(program) {
|
|
|
994
1204
|
is_public: false,
|
|
995
1205
|
supported_providers: supportedProviders,
|
|
996
1206
|
default_models: manifest.default_models,
|
|
1207
|
+
timeout_seconds: manifest.timeout_seconds,
|
|
997
1208
|
// Local run fields for code runtime agents
|
|
998
1209
|
source_url: manifest.source_url,
|
|
999
1210
|
pip_package: manifest.pip_package,
|
|
@@ -1006,6 +1217,8 @@ function registerPublishCommand(program) {
|
|
|
1006
1217
|
default_skills: skillsFromFlag || manifest.default_skills,
|
|
1007
1218
|
skills_locked: manifest.skills_locked || options.skillsLocked || undefined,
|
|
1008
1219
|
allow_local_download: options.localDownload || false,
|
|
1220
|
+
// Environment pinning
|
|
1221
|
+
environment: manifest.environment,
|
|
1009
1222
|
}, workspaceId);
|
|
1010
1223
|
}
|
|
1011
1224
|
catch (err) {
|
|
@@ -1179,8 +1392,17 @@ function registerPublishCommand(program) {
|
|
|
1179
1392
|
}
|
|
1180
1393
|
}
|
|
1181
1394
|
if (result.service_key) {
|
|
1182
|
-
process.stdout.write(`\nService key
|
|
1395
|
+
process.stdout.write(`\nService key:\n`);
|
|
1183
1396
|
process.stdout.write(` ${result.service_key}\n`);
|
|
1397
|
+
try {
|
|
1398
|
+
const keyPrefix = result.service_key.substring(0, 12);
|
|
1399
|
+
const savedPath = await (0, key_store_1.saveServiceKey)(org.slug, manifest.name, assignedVersion, result.service_key, keyPrefix);
|
|
1400
|
+
process.stdout.write(` ${chalk_1.default.gray(`Saved to ${savedPath}`)}\n`);
|
|
1401
|
+
}
|
|
1402
|
+
catch {
|
|
1403
|
+
process.stdout.write(` ${chalk_1.default.yellow('Could not save key locally. Copy it now — it cannot be retrieved from the server.')}\n`);
|
|
1404
|
+
}
|
|
1405
|
+
process.stdout.write(` Retrieve later: ${chalk_1.default.cyan(`orch agent-keys list ${org.slug}/${manifest.name}`)}\n`);
|
|
1184
1406
|
}
|
|
1185
1407
|
// Show next-step CLI command based on run mode
|
|
1186
1408
|
const runRef = `${org.slug}/${manifest.name}`;
|