@orchagent/cli 0.3.87 → 0.3.89
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/config.js +29 -6
- package/dist/commands/dag.js +259 -0
- package/dist/commands/env.js +15 -4
- package/dist/commands/fork.js +6 -6
- package/dist/commands/index.js +8 -4
- package/dist/commands/metrics.js +137 -0
- package/dist/commands/publish.js +20 -19
- package/dist/commands/replay.js +198 -0
- package/dist/commands/trace.js +311 -0
- package/package.json +1 -1
- package/dist/commands/call.js +0 -23
- package/dist/commands/keys.js +0 -22
package/dist/commands/config.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.setConfigValue = setConfigValue;
|
|
4
4
|
exports.registerConfigCommand = registerConfigCommand;
|
|
5
|
+
const output_1 = require("../lib/output");
|
|
5
6
|
const config_1 = require("../lib/config");
|
|
6
7
|
const errors_1 = require("../lib/errors");
|
|
7
8
|
const adapters_1 = require("../adapters");
|
|
@@ -49,13 +50,17 @@ async function setConfigValue(key, value) {
|
|
|
49
50
|
process.stdout.write(`Set default-provider to: ${value}\n`);
|
|
50
51
|
}
|
|
51
52
|
}
|
|
52
|
-
async function getConfigValue(key) {
|
|
53
|
+
async function getConfigValue(key, options = {}) {
|
|
53
54
|
if (!isValidKey(key)) {
|
|
54
55
|
throw new errors_1.CliError(`Unknown config key: ${key}. Supported keys: ${SUPPORTED_KEYS.join(', ')}`);
|
|
55
56
|
}
|
|
56
57
|
if (key === 'default-format') {
|
|
57
58
|
const resolved = await (0, config_1.getResolvedConfig)();
|
|
58
59
|
const formats = await (0, config_1.getDefaultFormats)(resolved);
|
|
60
|
+
if (options.json) {
|
|
61
|
+
(0, output_1.printJson)({ key, value: formats.length > 0 ? formats : [] });
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
59
64
|
if (formats.length === 0) {
|
|
60
65
|
process.stdout.write('(not set)\n');
|
|
61
66
|
}
|
|
@@ -65,6 +70,10 @@ async function getConfigValue(key) {
|
|
|
65
70
|
}
|
|
66
71
|
if (key === 'default-scope') {
|
|
67
72
|
const scope = await (0, config_1.getDefaultScope)();
|
|
73
|
+
if (options.json) {
|
|
74
|
+
(0, output_1.printJson)({ key, value: scope ?? null });
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
68
77
|
if (!scope) {
|
|
69
78
|
process.stdout.write('(not set)\n');
|
|
70
79
|
}
|
|
@@ -74,6 +83,10 @@ async function getConfigValue(key) {
|
|
|
74
83
|
}
|
|
75
84
|
if (key === 'default-provider') {
|
|
76
85
|
const provider = await (0, config_1.getDefaultProvider)();
|
|
86
|
+
if (options.json) {
|
|
87
|
+
(0, output_1.printJson)({ key, value: provider ?? null });
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
77
90
|
if (!provider) {
|
|
78
91
|
process.stdout.write('(not set)\n');
|
|
79
92
|
}
|
|
@@ -89,8 +102,16 @@ async function unsetConfigValue(key) {
|
|
|
89
102
|
await (0, config_1.unsetConfigKey)(key);
|
|
90
103
|
process.stdout.write(`Unset ${key}\n`);
|
|
91
104
|
}
|
|
92
|
-
async function listConfigValues() {
|
|
105
|
+
async function listConfigValues(options = {}) {
|
|
93
106
|
const config = await (0, config_1.loadConfig)();
|
|
107
|
+
if (options.json) {
|
|
108
|
+
(0, output_1.printJson)({
|
|
109
|
+
default_format: config.default_formats ?? [],
|
|
110
|
+
default_scope: config.default_scope ?? null,
|
|
111
|
+
default_provider: config.default_provider ?? null,
|
|
112
|
+
});
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
94
115
|
process.stdout.write('CLI Configuration:\n\n');
|
|
95
116
|
// default-format
|
|
96
117
|
const formats = config.default_formats ?? [];
|
|
@@ -131,8 +152,9 @@ function registerConfigCommand(program) {
|
|
|
131
152
|
config
|
|
132
153
|
.command('get <key>')
|
|
133
154
|
.description('Get a configuration value')
|
|
134
|
-
.
|
|
135
|
-
|
|
155
|
+
.option('--json', 'Output as JSON')
|
|
156
|
+
.action(async (key, options) => {
|
|
157
|
+
await getConfigValue(key, options);
|
|
136
158
|
});
|
|
137
159
|
config
|
|
138
160
|
.command('unset <key>')
|
|
@@ -143,7 +165,8 @@ function registerConfigCommand(program) {
|
|
|
143
165
|
config
|
|
144
166
|
.command('list')
|
|
145
167
|
.description('List all configuration values')
|
|
146
|
-
.
|
|
147
|
-
|
|
168
|
+
.option('--json', 'Output as JSON')
|
|
169
|
+
.action(async (options) => {
|
|
170
|
+
await listConfigValues(options);
|
|
148
171
|
});
|
|
149
172
|
}
|
|
@@ -0,0 +1,259 @@
|
|
|
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.registerDagCommand = registerDagCommand;
|
|
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
|
+
const output_1 = require("../lib/output");
|
|
12
|
+
const spinner_1 = require("../lib/spinner");
|
|
13
|
+
// ============================================
|
|
14
|
+
// HELPERS
|
|
15
|
+
// ============================================
|
|
16
|
+
async function resolveWorkspaceId(config, slug) {
|
|
17
|
+
const configFile = await (0, config_1.loadConfig)();
|
|
18
|
+
const targetSlug = slug ?? configFile.workspace;
|
|
19
|
+
if (!targetSlug) {
|
|
20
|
+
throw new errors_1.CliError('No workspace specified. Use --workspace <slug> or run `orch workspace use <slug>` first.');
|
|
21
|
+
}
|
|
22
|
+
const response = await (0, api_1.request)(config, 'GET', '/workspaces');
|
|
23
|
+
const workspace = response.workspaces.find((w) => w.slug === targetSlug);
|
|
24
|
+
if (!workspace) {
|
|
25
|
+
throw new errors_1.CliError(`Workspace '${targetSlug}' not found.`);
|
|
26
|
+
}
|
|
27
|
+
return workspace.id;
|
|
28
|
+
}
|
|
29
|
+
function isUuid(value) {
|
|
30
|
+
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value);
|
|
31
|
+
}
|
|
32
|
+
function isShortUuid(value) {
|
|
33
|
+
return /^[0-9a-f]{7,}$/i.test(value) && !value.includes('/');
|
|
34
|
+
}
|
|
35
|
+
async function resolveShortRunId(config, workspaceId, shortId) {
|
|
36
|
+
const result = await (0, api_1.request)(config, 'GET', `/workspaces/${workspaceId}/runs?limit=200&run_id_prefix=${encodeURIComponent(shortId)}`);
|
|
37
|
+
if (result.runs.length === 0) {
|
|
38
|
+
throw new errors_1.CliError(`No run found matching '${shortId}'.`);
|
|
39
|
+
}
|
|
40
|
+
if (result.runs.length > 1) {
|
|
41
|
+
throw new errors_1.CliError(`Ambiguous run ID '${shortId}' — matches ${result.runs.length} runs. Use more characters.`);
|
|
42
|
+
}
|
|
43
|
+
return result.runs[0].id;
|
|
44
|
+
}
|
|
45
|
+
// ============================================
|
|
46
|
+
// FORMATTERS
|
|
47
|
+
// ============================================
|
|
48
|
+
function statusColor(status) {
|
|
49
|
+
switch (status) {
|
|
50
|
+
case 'completed':
|
|
51
|
+
return chalk_1.default.green(status);
|
|
52
|
+
case 'failed':
|
|
53
|
+
case 'timeout':
|
|
54
|
+
case 'dead_letter':
|
|
55
|
+
return chalk_1.default.red(status);
|
|
56
|
+
case 'running':
|
|
57
|
+
return chalk_1.default.yellow(status);
|
|
58
|
+
case 'queued':
|
|
59
|
+
case 'claimed':
|
|
60
|
+
return chalk_1.default.cyan(status);
|
|
61
|
+
default:
|
|
62
|
+
return chalk_1.default.gray(status);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function statusIcon(status) {
|
|
66
|
+
switch (status) {
|
|
67
|
+
case 'completed':
|
|
68
|
+
return chalk_1.default.green('✓');
|
|
69
|
+
case 'failed':
|
|
70
|
+
case 'timeout':
|
|
71
|
+
case 'dead_letter':
|
|
72
|
+
return chalk_1.default.red('✗');
|
|
73
|
+
case 'running':
|
|
74
|
+
return chalk_1.default.yellow('◉');
|
|
75
|
+
case 'queued':
|
|
76
|
+
case 'claimed':
|
|
77
|
+
return chalk_1.default.cyan('○');
|
|
78
|
+
default:
|
|
79
|
+
return chalk_1.default.gray('?');
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
function formatDuration(ms) {
|
|
83
|
+
if (ms == null)
|
|
84
|
+
return '-';
|
|
85
|
+
if (ms < 1000)
|
|
86
|
+
return `${ms}ms`;
|
|
87
|
+
if (ms < 60000)
|
|
88
|
+
return `${(ms / 1000).toFixed(1)}s`;
|
|
89
|
+
return `${(ms / 60000).toFixed(1)}m`;
|
|
90
|
+
}
|
|
91
|
+
function formatCost(usd) {
|
|
92
|
+
if (usd === 0)
|
|
93
|
+
return '-';
|
|
94
|
+
if (usd < 0.01)
|
|
95
|
+
return `$${usd.toFixed(6)}`;
|
|
96
|
+
return `$${usd.toFixed(4)}`;
|
|
97
|
+
}
|
|
98
|
+
function formatTokens(n) {
|
|
99
|
+
if (n >= 1_000_000)
|
|
100
|
+
return `${(n / 1_000_000).toFixed(1)}M`;
|
|
101
|
+
if (n >= 1_000)
|
|
102
|
+
return `${(n / 1_000).toFixed(1)}K`;
|
|
103
|
+
return String(n);
|
|
104
|
+
}
|
|
105
|
+
// ============================================
|
|
106
|
+
// ASCII DAG RENDERER
|
|
107
|
+
// ============================================
|
|
108
|
+
function renderDagHeader(dag) {
|
|
109
|
+
const liveTag = dag.is_live ? chalk_1.default.blue(' [LIVE]') : '';
|
|
110
|
+
process.stdout.write(chalk_1.default.bold(`\nOrchestration DAG`) + liveTag + '\n' +
|
|
111
|
+
` Root: ${dag.root_run_id.slice(0, 8)}...\n` +
|
|
112
|
+
` Agents: ${dag.node_count}\n` +
|
|
113
|
+
` Duration: ${formatDuration(dag.total_duration_ms)}\n` +
|
|
114
|
+
` Cost: ${formatCost(dag.total_cost_usd)}\n`);
|
|
115
|
+
if (dag.active_count > 0 || dag.failed_count > 0) {
|
|
116
|
+
const parts = [];
|
|
117
|
+
if (dag.completed_count > 0)
|
|
118
|
+
parts.push(chalk_1.default.green(`${dag.completed_count} completed`));
|
|
119
|
+
if (dag.active_count > 0)
|
|
120
|
+
parts.push(chalk_1.default.yellow(`${dag.active_count} active`));
|
|
121
|
+
if (dag.failed_count > 0)
|
|
122
|
+
parts.push(chalk_1.default.red(`${dag.failed_count} failed`));
|
|
123
|
+
process.stdout.write(` Status: ${parts.join(', ')}\n`);
|
|
124
|
+
}
|
|
125
|
+
if (dag.most_expensive_agent) {
|
|
126
|
+
process.stdout.write(` Costly: ${chalk_1.default.yellow(dag.most_expensive_agent)}\n`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
function renderDagTree(node, prefix, isLast, isRoot) {
|
|
130
|
+
// Connector characters
|
|
131
|
+
const connector = isRoot ? '' : (isLast ? '└── ' : '├── ');
|
|
132
|
+
const childPrefix = isRoot ? '' : (isLast ? ' ' : '│ ');
|
|
133
|
+
// Status icon + agent name
|
|
134
|
+
const icon = statusIcon(node.status);
|
|
135
|
+
const name = chalk_1.default.bold(node.agent_name);
|
|
136
|
+
const version = chalk_1.default.gray(node.agent_version);
|
|
137
|
+
// Metrics line
|
|
138
|
+
const metricParts = [];
|
|
139
|
+
metricParts.push(statusColor(node.status));
|
|
140
|
+
if (node.duration_ms != null)
|
|
141
|
+
metricParts.push(chalk_1.default.gray(formatDuration(node.duration_ms)));
|
|
142
|
+
if (node.self_cost_usd > 0)
|
|
143
|
+
metricParts.push(chalk_1.default.gray(formatCost(node.self_cost_usd)));
|
|
144
|
+
if (node.llm_model)
|
|
145
|
+
metricParts.push(chalk_1.default.gray(node.llm_model));
|
|
146
|
+
const metrics = metricParts.join(chalk_1.default.gray(' | '));
|
|
147
|
+
// Trace summary
|
|
148
|
+
const ts = node.trace_summary;
|
|
149
|
+
const traceParts = [];
|
|
150
|
+
if (ts.llm_calls > 0)
|
|
151
|
+
traceParts.push(`${ts.llm_calls} LLM`);
|
|
152
|
+
if (ts.tool_calls > 0)
|
|
153
|
+
traceParts.push(`${ts.tool_calls} tool`);
|
|
154
|
+
if (ts.errors > 0)
|
|
155
|
+
traceParts.push(chalk_1.default.red(`${ts.errors} err`));
|
|
156
|
+
if (ts.total_tokens > 0)
|
|
157
|
+
traceParts.push(`${formatTokens(ts.total_tokens)} tok`);
|
|
158
|
+
const traceInfo = traceParts.length > 0 ? chalk_1.default.gray(` (${traceParts.join(', ')})`) : '';
|
|
159
|
+
process.stdout.write(`${prefix}${connector}${icon} ${name} ${version}\n` +
|
|
160
|
+
`${prefix}${childPrefix} ${metrics}${traceInfo}\n`);
|
|
161
|
+
// Render children
|
|
162
|
+
for (let i = 0; i < node.children.length; i++) {
|
|
163
|
+
const isChildLast = i === node.children.length - 1;
|
|
164
|
+
renderDagTree(node.children[i], prefix + childPrefix, isChildLast, false);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
function clearScreen() {
|
|
168
|
+
process.stdout.write('\x1b[2J\x1b[H');
|
|
169
|
+
}
|
|
170
|
+
// ============================================
|
|
171
|
+
// COMMAND
|
|
172
|
+
// ============================================
|
|
173
|
+
function registerDagCommand(program) {
|
|
174
|
+
program
|
|
175
|
+
.command('dag <run-id>')
|
|
176
|
+
.description('Visualize the orchestration call graph for a run. Shows all agents in the chain with real-time status.')
|
|
177
|
+
.option('--workspace <slug>', 'Workspace slug (default: current workspace)')
|
|
178
|
+
.option('--live', 'Keep polling for updates while the run is active')
|
|
179
|
+
.option('--interval <seconds>', 'Poll interval in seconds for --live mode', '2')
|
|
180
|
+
.option('--json', 'Output as JSON')
|
|
181
|
+
.action(async (runId, options) => {
|
|
182
|
+
const config = await (0, config_1.getResolvedConfig)();
|
|
183
|
+
if (!config.apiKey) {
|
|
184
|
+
throw new errors_1.CliError('Missing API key. Run `orch login` first.');
|
|
185
|
+
}
|
|
186
|
+
const workspaceId = await resolveWorkspaceId(config, options.workspace);
|
|
187
|
+
// Resolve short run IDs
|
|
188
|
+
let resolvedRunId = runId;
|
|
189
|
+
if (isUuid(runId)) {
|
|
190
|
+
resolvedRunId = runId;
|
|
191
|
+
}
|
|
192
|
+
else if (isShortUuid(runId)) {
|
|
193
|
+
resolvedRunId = await resolveShortRunId(config, workspaceId, runId);
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
throw new errors_1.CliError(`Invalid run ID '${runId}'. Provide a full UUID or a short hex prefix (7+ characters).`);
|
|
197
|
+
}
|
|
198
|
+
const interval = Math.max(1, Math.min(30, parseFloat(options.interval || '2')));
|
|
199
|
+
// Fetch DAG
|
|
200
|
+
const spinner = (0, spinner_1.createSpinner)('Fetching orchestration DAG...');
|
|
201
|
+
spinner.start();
|
|
202
|
+
let dag;
|
|
203
|
+
try {
|
|
204
|
+
dag = await (0, api_1.request)(config, 'GET', `/workspaces/${workspaceId}/runs/${resolvedRunId}/dag`);
|
|
205
|
+
spinner.stop();
|
|
206
|
+
}
|
|
207
|
+
catch (e) {
|
|
208
|
+
spinner.stop();
|
|
209
|
+
const msg = e instanceof Error ? e.message : 'Unknown error';
|
|
210
|
+
if (msg.includes('404') || msg.includes('not found') || msg.includes('Not part of')) {
|
|
211
|
+
throw new errors_1.CliError(`Run ${resolvedRunId.slice(0, 8)}... is not part of an orchestration chain.`);
|
|
212
|
+
}
|
|
213
|
+
throw e;
|
|
214
|
+
}
|
|
215
|
+
if (options.json && !options.live) {
|
|
216
|
+
(0, output_1.printJson)(dag);
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
// Render initial DAG
|
|
220
|
+
renderDagHeader(dag);
|
|
221
|
+
process.stdout.write('\n');
|
|
222
|
+
renderDagTree(dag.tree, ' ', true, true);
|
|
223
|
+
process.stdout.write('\n');
|
|
224
|
+
// Live mode: poll for updates
|
|
225
|
+
if (options.live && dag.is_live) {
|
|
226
|
+
process.stdout.write(chalk_1.default.gray(`Live mode: polling every ${interval}s. Press Ctrl+C to stop.\n\n`));
|
|
227
|
+
while (true) {
|
|
228
|
+
await new Promise((resolve) => setTimeout(resolve, interval * 1000));
|
|
229
|
+
try {
|
|
230
|
+
dag = await (0, api_1.request)(config, 'GET', `/workspaces/${workspaceId}/runs/${resolvedRunId}/dag`);
|
|
231
|
+
}
|
|
232
|
+
catch {
|
|
233
|
+
// Ignore transient errors during polling
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
if (options.json) {
|
|
237
|
+
(0, output_1.printJson)(dag);
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
clearScreen();
|
|
241
|
+
renderDagHeader(dag);
|
|
242
|
+
process.stdout.write('\n');
|
|
243
|
+
renderDagTree(dag.tree, ' ', true, true);
|
|
244
|
+
process.stdout.write('\n');
|
|
245
|
+
}
|
|
246
|
+
if (!dag.is_live) {
|
|
247
|
+
process.stdout.write(chalk_1.default.green('Execution complete.\n'));
|
|
248
|
+
break;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
else if (options.live && !dag.is_live) {
|
|
253
|
+
process.stdout.write(chalk_1.default.gray('Run is not active. Showing final state.\n'));
|
|
254
|
+
}
|
|
255
|
+
// Footer hints
|
|
256
|
+
process.stdout.write(chalk_1.default.gray(`View trace: orch trace ${resolvedRunId.slice(0, 8)}\n`) +
|
|
257
|
+
chalk_1.default.gray(`View logs: orch logs ${resolvedRunId.slice(0, 8)}\n`));
|
|
258
|
+
});
|
|
259
|
+
}
|
package/dist/commands/env.js
CHANGED
|
@@ -43,6 +43,7 @@ const fs = __importStar(require("fs/promises"));
|
|
|
43
43
|
const config_1 = require("../lib/config");
|
|
44
44
|
const api_1 = require("../lib/api");
|
|
45
45
|
const errors_1 = require("../lib/errors");
|
|
46
|
+
const output_1 = require("../lib/output");
|
|
46
47
|
const analytics_1 = require("../lib/analytics");
|
|
47
48
|
async function resolveWorkspaceId(config, slug) {
|
|
48
49
|
const configFile = await (0, config_1.loadConfig)();
|
|
@@ -83,6 +84,10 @@ function statusColor(status) {
|
|
|
83
84
|
async function listEnvs(config, options) {
|
|
84
85
|
const workspaceId = await resolveWorkspaceId(config, options.workspace);
|
|
85
86
|
const result = await (0, api_1.listEnvironments)(config, workspaceId);
|
|
87
|
+
if (options.json) {
|
|
88
|
+
(0, output_1.printJson)(result);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
86
91
|
if (result.environments.length === 0) {
|
|
87
92
|
console.log(chalk_1.default.gray('No environments found.'));
|
|
88
93
|
console.log(chalk_1.default.gray('Use `orchagent env create` to create one, or include a Dockerfile in your agent bundle.'));
|
|
@@ -108,7 +113,7 @@ async function listEnvs(config, options) {
|
|
|
108
113
|
statusColor(env.build?.status),
|
|
109
114
|
env.agent_count.toString(),
|
|
110
115
|
env.environment.is_predefined ? chalk_1.default.blue('predefined') : chalk_1.default.gray('custom'),
|
|
111
|
-
env.environment.id
|
|
116
|
+
env.environment.id,
|
|
112
117
|
]);
|
|
113
118
|
}
|
|
114
119
|
console.log();
|
|
@@ -123,8 +128,12 @@ async function listEnvs(config, options) {
|
|
|
123
128
|
}
|
|
124
129
|
}
|
|
125
130
|
}
|
|
126
|
-
async function getEnvStatus(config, environmentId) {
|
|
131
|
+
async function getEnvStatus(config, environmentId, options) {
|
|
127
132
|
const result = await (0, api_1.getEnvironment)(config, environmentId);
|
|
133
|
+
if (options.json) {
|
|
134
|
+
(0, output_1.printJson)(result);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
128
137
|
console.log();
|
|
129
138
|
console.log(chalk_1.default.bold(`Environment: ${result.environment.name}`));
|
|
130
139
|
console.log();
|
|
@@ -206,6 +215,7 @@ function registerEnvCommand(program) {
|
|
|
206
215
|
.command('list')
|
|
207
216
|
.description('List environments in workspace')
|
|
208
217
|
.option('-w, --workspace <slug>', 'Workspace slug')
|
|
218
|
+
.option('--json', 'Output as JSON')
|
|
209
219
|
.action(async (options) => {
|
|
210
220
|
const config = await (0, config_1.getResolvedConfig)();
|
|
211
221
|
await listEnvs(config, options);
|
|
@@ -213,9 +223,10 @@ function registerEnvCommand(program) {
|
|
|
213
223
|
env
|
|
214
224
|
.command('status <environment-id>')
|
|
215
225
|
.description('Check environment build status')
|
|
216
|
-
.
|
|
226
|
+
.option('--json', 'Output as JSON')
|
|
227
|
+
.action(async (environmentId, options) => {
|
|
217
228
|
const config = await (0, config_1.getResolvedConfig)();
|
|
218
|
-
await getEnvStatus(config, environmentId);
|
|
229
|
+
await getEnvStatus(config, environmentId, options);
|
|
219
230
|
});
|
|
220
231
|
env
|
|
221
232
|
.command('create')
|
package/dist/commands/fork.js
CHANGED
|
@@ -36,16 +36,16 @@ async function resolveWorkspace(config, workspaceSlug) {
|
|
|
36
36
|
function registerForkCommand(program) {
|
|
37
37
|
program
|
|
38
38
|
.command('fork <agent>')
|
|
39
|
-
.description('Fork
|
|
39
|
+
.description('Fork an agent into your workspace')
|
|
40
40
|
.option('--name <new-name>', 'Rename the forked agent')
|
|
41
41
|
.option('-w, --workspace <workspace-slug>', 'Target workspace slug')
|
|
42
42
|
.option('--json', 'Output raw JSON')
|
|
43
43
|
.addHelpText('after', `
|
|
44
44
|
Examples:
|
|
45
|
-
orch fork orchagent/
|
|
46
|
-
orch fork orchagent/
|
|
47
|
-
orch fork orchagent/
|
|
48
|
-
orch fork
|
|
45
|
+
orch fork orchagent/security-agent
|
|
46
|
+
orch fork orchagent/security-agent --workspace acme-corp
|
|
47
|
+
orch fork orchagent/security-agent --name my-security-scanner
|
|
48
|
+
orch fork joe/my-agent --workspace acme-corp # fork your own private agent into another workspace
|
|
49
49
|
`)
|
|
50
50
|
.action(async (agentRef, options) => {
|
|
51
51
|
const write = (message) => {
|
|
@@ -58,7 +58,7 @@ Examples:
|
|
|
58
58
|
}
|
|
59
59
|
const { org, agent, version } = (0, agent_ref_1.parseAgentRef)(agentRef);
|
|
60
60
|
write('Resolving source agent...\n');
|
|
61
|
-
const source = await (0, api_1.
|
|
61
|
+
const source = await (0, api_1.getAgentWithFallback)(config, org, agent, version);
|
|
62
62
|
if (!source.id) {
|
|
63
63
|
throw new errors_1.CliError(`Could not resolve source agent ID for '${org}/${agent}@${version}'.`);
|
|
64
64
|
}
|
package/dist/commands/index.js
CHANGED
|
@@ -3,12 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.registerCommands = registerCommands;
|
|
4
4
|
const login_1 = require("./login");
|
|
5
5
|
const logout_1 = require("./logout");
|
|
6
|
-
const call_1 = require("./call");
|
|
7
6
|
const agents_1 = require("./agents");
|
|
8
7
|
const init_1 = require("./init");
|
|
9
8
|
const publish_1 = require("./publish");
|
|
10
9
|
const whoami_1 = require("./whoami");
|
|
11
|
-
const keys_1 = require("./keys");
|
|
12
10
|
const run_1 = require("./run");
|
|
13
11
|
const info_1 = require("./info");
|
|
14
12
|
const skill_1 = require("./skill");
|
|
@@ -40,17 +38,19 @@ const diff_1 = require("./diff");
|
|
|
40
38
|
const health_1 = require("./health");
|
|
41
39
|
const dev_1 = require("./dev");
|
|
42
40
|
const estimate_1 = require("./estimate");
|
|
41
|
+
const replay_1 = require("./replay");
|
|
42
|
+
const trace_1 = require("./trace");
|
|
43
|
+
const metrics_1 = require("./metrics");
|
|
44
|
+
const dag_1 = require("./dag");
|
|
43
45
|
function registerCommands(program) {
|
|
44
46
|
(0, login_1.registerLoginCommand)(program);
|
|
45
47
|
(0, logout_1.registerLogoutCommand)(program);
|
|
46
48
|
(0, whoami_1.registerWhoamiCommand)(program);
|
|
47
49
|
(0, init_1.registerInitCommand)(program);
|
|
48
50
|
(0, publish_1.registerPublishCommand)(program);
|
|
49
|
-
(0, call_1.registerCallCommand)(program);
|
|
50
51
|
(0, run_1.registerRunCommand)(program);
|
|
51
52
|
(0, info_1.registerInfoCommand)(program);
|
|
52
53
|
(0, agents_1.registerAgentsCommand)(program);
|
|
53
|
-
(0, keys_1.registerKeysCommand)(program);
|
|
54
54
|
(0, skill_1.registerSkillCommand)(program);
|
|
55
55
|
(0, delete_1.registerDeleteCommand)(program);
|
|
56
56
|
(0, fork_1.registerForkCommand)(program);
|
|
@@ -80,4 +80,8 @@ function registerCommands(program) {
|
|
|
80
80
|
(0, health_1.registerHealthCommand)(program);
|
|
81
81
|
(0, dev_1.registerDevCommand)(program);
|
|
82
82
|
(0, estimate_1.registerEstimateCommand)(program);
|
|
83
|
+
(0, replay_1.registerReplayCommand)(program);
|
|
84
|
+
(0, trace_1.registerTraceCommand)(program);
|
|
85
|
+
(0, metrics_1.registerMetricsCommand)(program);
|
|
86
|
+
(0, dag_1.registerDagCommand)(program);
|
|
83
87
|
}
|
|
@@ -0,0 +1,137 @@
|
|
|
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.registerMetricsCommand = registerMetricsCommand;
|
|
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
|
+
const output_1 = require("../lib/output");
|
|
12
|
+
// ============================================
|
|
13
|
+
// HELPERS
|
|
14
|
+
// ============================================
|
|
15
|
+
async function resolveWorkspaceId(config, slug) {
|
|
16
|
+
const configFile = await (0, config_1.loadConfig)();
|
|
17
|
+
const targetSlug = slug ?? configFile.workspace;
|
|
18
|
+
if (!targetSlug) {
|
|
19
|
+
throw new errors_1.CliError('No workspace specified. Use --workspace <slug> or run `orch workspace use <slug>` first.');
|
|
20
|
+
}
|
|
21
|
+
const response = await (0, api_1.request)(config, 'GET', '/workspaces');
|
|
22
|
+
const workspace = response.workspaces.find((w) => w.slug === targetSlug);
|
|
23
|
+
if (!workspace) {
|
|
24
|
+
throw new errors_1.CliError(`Workspace '${targetSlug}' not found.`);
|
|
25
|
+
}
|
|
26
|
+
return workspace.id;
|
|
27
|
+
}
|
|
28
|
+
function formatDuration(ms) {
|
|
29
|
+
if (ms === 0)
|
|
30
|
+
return '-';
|
|
31
|
+
if (ms < 1000)
|
|
32
|
+
return `${ms}ms`;
|
|
33
|
+
return `${(ms / 1000).toFixed(1)}s`;
|
|
34
|
+
}
|
|
35
|
+
function rateColor(rate) {
|
|
36
|
+
if (rate >= 95)
|
|
37
|
+
return chalk_1.default.green(`${rate}%`);
|
|
38
|
+
if (rate >= 80)
|
|
39
|
+
return chalk_1.default.yellow(`${rate}%`);
|
|
40
|
+
return chalk_1.default.red(`${rate}%`);
|
|
41
|
+
}
|
|
42
|
+
function padRight(str, len) {
|
|
43
|
+
return str.length >= len ? str.slice(0, len) : str + ' '.repeat(len - str.length);
|
|
44
|
+
}
|
|
45
|
+
function padLeft(str, len) {
|
|
46
|
+
return str.length >= len ? str.slice(0, len) : ' '.repeat(len - str.length) + str;
|
|
47
|
+
}
|
|
48
|
+
// ============================================
|
|
49
|
+
// COMMAND
|
|
50
|
+
// ============================================
|
|
51
|
+
function registerMetricsCommand(program) {
|
|
52
|
+
program
|
|
53
|
+
.command('metrics')
|
|
54
|
+
.description('Show agent performance metrics for a workspace')
|
|
55
|
+
.option('--workspace <slug>', 'Workspace slug (default: active workspace)')
|
|
56
|
+
.option('--days <n>', 'Number of days to analyze', '30')
|
|
57
|
+
.option('--agent <name>', 'Filter to a specific agent')
|
|
58
|
+
.option('--json', 'Output as JSON')
|
|
59
|
+
.action(async (options) => {
|
|
60
|
+
const config = await (0, config_1.getResolvedConfig)();
|
|
61
|
+
const workspaceId = await resolveWorkspaceId(config, options.workspace);
|
|
62
|
+
const days = parseInt(options.days || '30', 10);
|
|
63
|
+
if (isNaN(days) || days < 1 || days > 365) {
|
|
64
|
+
process.stderr.write(chalk_1.default.red('Error: --days must be between 1 and 365\n'));
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
const params = new URLSearchParams({ days: String(days) });
|
|
68
|
+
if (options.agent)
|
|
69
|
+
params.set('agent_name', options.agent);
|
|
70
|
+
let data;
|
|
71
|
+
try {
|
|
72
|
+
data = await (0, api_1.request)(config, 'GET', `/workspaces/${workspaceId}/metrics/dashboard?${params}`, { headers: { 'X-Workspace-Id': workspaceId } });
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
if (err instanceof api_1.ApiError && err.status === 403) {
|
|
76
|
+
process.stderr.write(chalk_1.default.red('Error: Not a member of this workspace\n'));
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|
|
79
|
+
throw err;
|
|
80
|
+
}
|
|
81
|
+
if (options.json) {
|
|
82
|
+
(0, output_1.printJson)(data);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const { overview, agents } = data;
|
|
86
|
+
// Header
|
|
87
|
+
process.stdout.write('\n');
|
|
88
|
+
process.stdout.write(chalk_1.default.bold('Agent Metrics') + chalk_1.default.gray(` (last ${days}d)\n`));
|
|
89
|
+
process.stdout.write('='.repeat(50) + '\n\n');
|
|
90
|
+
// Overview stats
|
|
91
|
+
if (overview.total_runs === 0) {
|
|
92
|
+
process.stdout.write(chalk_1.default.yellow('No runs in this period.\n\n'));
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
process.stdout.write(` Total Runs: ${chalk_1.default.bold(String(overview.total_runs))}\n`);
|
|
96
|
+
process.stdout.write(` Success Rate: ${rateColor(overview.success_rate)}\n`);
|
|
97
|
+
process.stdout.write(` Error Rate: ${overview.error_rate}% ${chalk_1.default.gray(`(${overview.failed} failed, ${overview.timeout} timeout)`)}\n`);
|
|
98
|
+
process.stdout.write(` p50 Latency: ${chalk_1.default.cyan(formatDuration(overview.p50_latency_ms))}\n`);
|
|
99
|
+
process.stdout.write(` p95 Latency: ${chalk_1.default.yellow(formatDuration(overview.p95_latency_ms))}\n`);
|
|
100
|
+
process.stdout.write(` Avg Latency: ${formatDuration(overview.avg_latency_ms)}\n`);
|
|
101
|
+
process.stdout.write(` Runs/Day: ${overview.runs_per_day}\n`);
|
|
102
|
+
// Per-agent table
|
|
103
|
+
if (agents.length > 0) {
|
|
104
|
+
process.stdout.write(`\n${chalk_1.default.bold('Per Agent')}\n`);
|
|
105
|
+
process.stdout.write('-'.repeat(90) + '\n');
|
|
106
|
+
// Header
|
|
107
|
+
process.stdout.write(padRight('Agent', 25) +
|
|
108
|
+
padLeft('Runs', 8) +
|
|
109
|
+
padLeft('Success', 10) +
|
|
110
|
+
padLeft('p50', 10) +
|
|
111
|
+
padLeft('p95', 10) +
|
|
112
|
+
padLeft('Errors', 8) +
|
|
113
|
+
' Top Error\n');
|
|
114
|
+
process.stdout.write('-'.repeat(90) + '\n');
|
|
115
|
+
for (const agent of agents) {
|
|
116
|
+
const nameStr = agent.agent_name.length > 22
|
|
117
|
+
? agent.agent_name.slice(0, 22) + '..'
|
|
118
|
+
: agent.agent_name;
|
|
119
|
+
const errorStr = agent.top_error
|
|
120
|
+
? agent.top_error.slice(0, 20)
|
|
121
|
+
: '-';
|
|
122
|
+
process.stdout.write(padRight(nameStr, 25) +
|
|
123
|
+
padLeft(String(agent.total_runs), 8) +
|
|
124
|
+
padLeft(agent.success_rate >= 95 ? chalk_1.default.green(`${agent.success_rate}%`) :
|
|
125
|
+
agent.success_rate >= 80 ? chalk_1.default.yellow(`${agent.success_rate}%`) :
|
|
126
|
+
chalk_1.default.red(`${agent.success_rate}%`),
|
|
127
|
+
// chalk adds escape chars — pad the raw value, then colorize
|
|
128
|
+
10) +
|
|
129
|
+
padLeft(formatDuration(agent.p50_latency_ms), 10) +
|
|
130
|
+
padLeft(formatDuration(agent.p95_latency_ms), 10) +
|
|
131
|
+
padLeft(String(agent.failed + agent.timeout), 8) +
|
|
132
|
+
' ' + chalk_1.default.gray(errorStr) + '\n');
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
process.stdout.write('\n');
|
|
136
|
+
});
|
|
137
|
+
}
|
package/dist/commands/publish.js
CHANGED
|
@@ -982,6 +982,26 @@ function registerPublishCommand(program) {
|
|
|
982
982
|
` the field to use the default) and republish each dependency.\n\n`);
|
|
983
983
|
}
|
|
984
984
|
}
|
|
985
|
+
// C-1: Block publish if tool/agent type has no required_secrets declared.
|
|
986
|
+
// Prompt and skill types are exempt (prompt agents get LLM keys from platform,
|
|
987
|
+
// skills don't run standalone).
|
|
988
|
+
// An explicit empty array (required_secrets: []) is a valid declaration
|
|
989
|
+
// meaning "this agent deliberately needs no secrets."
|
|
990
|
+
// Runs before dry-run so --dry-run catches the same errors as real publish (BUG-11).
|
|
991
|
+
if ((canonicalType === 'tool' || canonicalType === 'agent') &&
|
|
992
|
+
manifest.required_secrets === undefined &&
|
|
993
|
+
options.requiredSecrets !== false) {
|
|
994
|
+
process.stderr.write(chalk_1.default.red(`\nError: ${canonicalType} agents must declare required_secrets in orchagent.json.\n\n`) +
|
|
995
|
+
` Add the env vars your code needs at runtime:\n` +
|
|
996
|
+
` ${chalk_1.default.cyan('"required_secrets": ["ANTHROPIC_API_KEY", "MY_TOKEN"]')}\n\n` +
|
|
997
|
+
` If this agent genuinely needs no secrets, add an empty array:\n` +
|
|
998
|
+
` ${chalk_1.default.cyan('"required_secrets": []')}\n\n` +
|
|
999
|
+
` These are matched by name against your workspace secrets vault.\n` +
|
|
1000
|
+
` Use ${chalk_1.default.cyan('--no-required-secrets')} to skip this check.\n`);
|
|
1001
|
+
const err = new errors_1.CliError('Missing required_secrets declaration', errors_1.ExitCodes.INVALID_INPUT);
|
|
1002
|
+
err.displayed = true;
|
|
1003
|
+
throw err;
|
|
1004
|
+
}
|
|
985
1005
|
// Handle dry-run for agents
|
|
986
1006
|
if (options.dryRun) {
|
|
987
1007
|
const preview = await (0, api_1.previewAgentVersion)(config, manifest.name, workspaceId);
|
|
@@ -1166,25 +1186,6 @@ function registerPublishCommand(program) {
|
|
|
1166
1186
|
` env var to detect the reserved port.\n\n`);
|
|
1167
1187
|
}
|
|
1168
1188
|
}
|
|
1169
|
-
// C-1: Block publish if tool/agent type has no required_secrets declared.
|
|
1170
|
-
// Prompt and skill types are exempt (prompt agents get LLM keys from platform,
|
|
1171
|
-
// skills don't run standalone).
|
|
1172
|
-
// An explicit empty array (required_secrets: []) is a valid declaration
|
|
1173
|
-
// meaning "this agent deliberately needs no secrets."
|
|
1174
|
-
if ((canonicalType === 'tool' || canonicalType === 'agent') &&
|
|
1175
|
-
manifest.required_secrets === undefined &&
|
|
1176
|
-
options.requiredSecrets !== false) {
|
|
1177
|
-
process.stderr.write(chalk_1.default.red(`\nError: ${canonicalType} agents must declare required_secrets in orchagent.json.\n\n`) +
|
|
1178
|
-
` Add the env vars your code needs at runtime:\n` +
|
|
1179
|
-
` ${chalk_1.default.cyan('"required_secrets": ["ANTHROPIC_API_KEY", "MY_TOKEN"]')}\n\n` +
|
|
1180
|
-
` If this agent genuinely needs no secrets, add an empty array:\n` +
|
|
1181
|
-
` ${chalk_1.default.cyan('"required_secrets": []')}\n\n` +
|
|
1182
|
-
` These are matched by name against your workspace secrets vault.\n` +
|
|
1183
|
-
` Use ${chalk_1.default.cyan('--no-required-secrets')} to skip this check.\n`);
|
|
1184
|
-
const err = new errors_1.CliError('Missing required_secrets declaration', errors_1.ExitCodes.INVALID_INPUT);
|
|
1185
|
-
err.displayed = true;
|
|
1186
|
-
throw err;
|
|
1187
|
-
}
|
|
1188
1189
|
// Create the agent (server auto-assigns version)
|
|
1189
1190
|
let result;
|
|
1190
1191
|
try {
|
|
@@ -0,0 +1,198 @@
|
|
|
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.registerReplayCommand = registerReplayCommand;
|
|
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
|
+
const output_1 = require("../lib/output");
|
|
12
|
+
// ============================================
|
|
13
|
+
// HELPERS
|
|
14
|
+
// ============================================
|
|
15
|
+
async function resolveWorkspaceId(config, slug) {
|
|
16
|
+
const configFile = await (0, config_1.loadConfig)();
|
|
17
|
+
const targetSlug = slug ?? configFile.workspace;
|
|
18
|
+
if (!targetSlug) {
|
|
19
|
+
throw new errors_1.CliError('No workspace specified. Use --workspace <slug> or run `orch workspace use <slug>` first.');
|
|
20
|
+
}
|
|
21
|
+
const response = await (0, api_1.request)(config, 'GET', '/workspaces');
|
|
22
|
+
const workspace = response.workspaces.find((w) => w.slug === targetSlug);
|
|
23
|
+
if (!workspace) {
|
|
24
|
+
throw new errors_1.CliError(`Workspace '${targetSlug}' not found.`);
|
|
25
|
+
}
|
|
26
|
+
return workspace.id;
|
|
27
|
+
}
|
|
28
|
+
function isUuid(value) {
|
|
29
|
+
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value);
|
|
30
|
+
}
|
|
31
|
+
function isShortUuid(value) {
|
|
32
|
+
return /^[0-9a-f]{7,}$/i.test(value) && !value.includes('/');
|
|
33
|
+
}
|
|
34
|
+
async function resolveShortRunId(config, workspaceId, shortId) {
|
|
35
|
+
const result = await (0, api_1.request)(config, 'GET', `/workspaces/${workspaceId}/runs?limit=200&run_id_prefix=${encodeURIComponent(shortId)}`);
|
|
36
|
+
if (result.runs.length === 0) {
|
|
37
|
+
throw new errors_1.CliError(`No run found matching '${shortId}'.`);
|
|
38
|
+
}
|
|
39
|
+
if (result.runs.length > 1) {
|
|
40
|
+
throw new errors_1.CliError(`Ambiguous run ID '${shortId}' — matches ${result.runs.length} runs. Use more characters to narrow it down.`);
|
|
41
|
+
}
|
|
42
|
+
return result.runs[0].id;
|
|
43
|
+
}
|
|
44
|
+
function statusColor(status) {
|
|
45
|
+
if (!status)
|
|
46
|
+
return '-';
|
|
47
|
+
switch (status) {
|
|
48
|
+
case 'completed':
|
|
49
|
+
return chalk_1.default.green(status);
|
|
50
|
+
case 'failed':
|
|
51
|
+
return chalk_1.default.red(status);
|
|
52
|
+
case 'running':
|
|
53
|
+
case 'queued':
|
|
54
|
+
case 'claimed':
|
|
55
|
+
return chalk_1.default.yellow(status);
|
|
56
|
+
case 'timeout':
|
|
57
|
+
return chalk_1.default.red(status);
|
|
58
|
+
default:
|
|
59
|
+
return status;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function formatDuration(ms) {
|
|
63
|
+
if (ms == null)
|
|
64
|
+
return '-';
|
|
65
|
+
if (ms < 1000)
|
|
66
|
+
return `${ms}ms`;
|
|
67
|
+
if (ms < 60000)
|
|
68
|
+
return `${(ms / 1000).toFixed(1)}s`;
|
|
69
|
+
return `${(ms / 60000).toFixed(1)}m`;
|
|
70
|
+
}
|
|
71
|
+
const POLL_INTERVAL_MS = 2000;
|
|
72
|
+
const MAX_POLL_MS = 600000; // 10 minutes
|
|
73
|
+
// ============================================
|
|
74
|
+
// COMMAND REGISTRATION
|
|
75
|
+
// ============================================
|
|
76
|
+
function registerReplayCommand(program) {
|
|
77
|
+
program
|
|
78
|
+
.command('replay <run-id>')
|
|
79
|
+
.description('Replay a previous run. Re-executes with the same input and config from the original snapshot.')
|
|
80
|
+
.option('--workspace <slug>', 'Workspace slug (default: current workspace)')
|
|
81
|
+
.option('--reason <text>', 'Reason for replay (stored in audit log)')
|
|
82
|
+
.option('--override-policy <id>', 'Override provider policy ID for this replay')
|
|
83
|
+
.option('--no-wait', 'Queue the replay and return immediately without waiting for results')
|
|
84
|
+
.option('--json', 'Output as JSON')
|
|
85
|
+
.action(async (runId, options) => {
|
|
86
|
+
const config = await (0, config_1.getResolvedConfig)();
|
|
87
|
+
if (!config.apiKey) {
|
|
88
|
+
throw new errors_1.CliError('Missing API key. Run `orch login` first.');
|
|
89
|
+
}
|
|
90
|
+
const workspaceId = await resolveWorkspaceId(config, options.workspace);
|
|
91
|
+
// Resolve short run IDs
|
|
92
|
+
let resolvedRunId = runId;
|
|
93
|
+
if (isUuid(runId)) {
|
|
94
|
+
resolvedRunId = runId;
|
|
95
|
+
}
|
|
96
|
+
else if (isShortUuid(runId)) {
|
|
97
|
+
resolvedRunId = await resolveShortRunId(config, workspaceId, runId);
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
throw new errors_1.CliError(`Invalid run ID '${runId}'. Provide a full UUID or a short hex prefix (7+ characters).`);
|
|
101
|
+
}
|
|
102
|
+
// Submit replay request
|
|
103
|
+
const body = {};
|
|
104
|
+
if (options.reason)
|
|
105
|
+
body.reason = options.reason;
|
|
106
|
+
if (options.overridePolicy)
|
|
107
|
+
body.override_provider_policy_id = options.overridePolicy;
|
|
108
|
+
const replay = await (0, api_1.request)(config, 'POST', `/workspaces/${workspaceId}/runs/${resolvedRunId}/replay`, {
|
|
109
|
+
body: JSON.stringify(body),
|
|
110
|
+
headers: { 'Content-Type': 'application/json' },
|
|
111
|
+
});
|
|
112
|
+
if (options.json && options.wait === false) {
|
|
113
|
+
(0, output_1.printJson)(replay);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
if (options.wait === false) {
|
|
117
|
+
process.stdout.write(chalk_1.default.green('Replay queued.\n') +
|
|
118
|
+
` Run ID: ${replay.run_id}\n` +
|
|
119
|
+
` Job ID: ${replay.job_id}\n` +
|
|
120
|
+
` Replaying: ${replay.replay_of_run_id}\n` +
|
|
121
|
+
chalk_1.default.gray('\nCheck status: orch logs ' + replay.run_id.slice(0, 8) + '\n'));
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
// Poll for completion
|
|
125
|
+
if (!options.json) {
|
|
126
|
+
process.stderr.write(chalk_1.default.gray(`Replaying run ${resolvedRunId.slice(0, 8)}... `));
|
|
127
|
+
}
|
|
128
|
+
const startTime = Date.now();
|
|
129
|
+
let lastStatus = 'queued';
|
|
130
|
+
let pollResult = null;
|
|
131
|
+
while (Date.now() - startTime < MAX_POLL_MS) {
|
|
132
|
+
await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
|
|
133
|
+
try {
|
|
134
|
+
pollResult = await (0, api_1.request)(config, 'GET', `/workspaces/${workspaceId}/runs/${replay.run_id}`);
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
// Run may not exist yet if job worker hasn't picked it up
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
lastStatus = pollResult.status;
|
|
141
|
+
if (!options.json) {
|
|
142
|
+
const elapsed = ((Date.now() - startTime) / 1000).toFixed(0);
|
|
143
|
+
process.stderr.write(`\r${chalk_1.default.gray(`Replaying run ${resolvedRunId.slice(0, 8)}... ${statusColor(lastStatus)} (${elapsed}s)`)}`);
|
|
144
|
+
}
|
|
145
|
+
if (['completed', 'failed', 'timeout', 'dead_letter', 'cancelled'].includes(lastStatus)) {
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (!options.json) {
|
|
150
|
+
process.stderr.write('\n');
|
|
151
|
+
}
|
|
152
|
+
// Fetch final logs
|
|
153
|
+
const logs = await (0, api_1.request)(config, 'GET', `/workspaces/${workspaceId}/runs/${replay.run_id}/logs`);
|
|
154
|
+
if (options.json) {
|
|
155
|
+
(0, output_1.printJson)({
|
|
156
|
+
replay: {
|
|
157
|
+
run_id: replay.run_id,
|
|
158
|
+
replay_of_run_id: replay.replay_of_run_id,
|
|
159
|
+
job_id: replay.job_id,
|
|
160
|
+
},
|
|
161
|
+
result: logs,
|
|
162
|
+
});
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
// Render results
|
|
166
|
+
renderReplayResult(replay, logs);
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
// ============================================
|
|
170
|
+
// RENDER REPLAY RESULT
|
|
171
|
+
// ============================================
|
|
172
|
+
function renderReplayResult(replay, logs) {
|
|
173
|
+
process.stdout.write(chalk_1.default.bold(`\nReplay ${replay.run_id}\n`) +
|
|
174
|
+
` Original: ${replay.replay_of_run_id.slice(0, 8)}\n` +
|
|
175
|
+
` Agent: ${logs.agent_name ?? '-'}@${logs.agent_version ?? '-'}\n` +
|
|
176
|
+
` Status: ${statusColor(logs.run_status)}\n` +
|
|
177
|
+
` Duration: ${formatDuration(logs.execution_time_ms)}\n`);
|
|
178
|
+
if (logs.exit_code != null) {
|
|
179
|
+
const exitLabel = logs.exit_code === 0 ? chalk_1.default.green(String(logs.exit_code)) : chalk_1.default.red(String(logs.exit_code));
|
|
180
|
+
process.stdout.write(` Exit code: ${exitLabel}\n`);
|
|
181
|
+
}
|
|
182
|
+
if (logs.output_data != null && Object.keys(logs.output_data).length > 0) {
|
|
183
|
+
process.stdout.write('\n' + chalk_1.default.bold.green('--- output ---') + '\n' +
|
|
184
|
+
JSON.stringify(logs.output_data, null, 2) + '\n');
|
|
185
|
+
}
|
|
186
|
+
if (logs.error_message) {
|
|
187
|
+
process.stdout.write('\n' + chalk_1.default.red.bold('Error:\n') + chalk_1.default.red(logs.error_message) + '\n');
|
|
188
|
+
}
|
|
189
|
+
if (logs.stdout) {
|
|
190
|
+
process.stdout.write('\n' + chalk_1.default.bold.cyan('--- stdout ---') + '\n' + logs.stdout + '\n');
|
|
191
|
+
}
|
|
192
|
+
if (logs.stderr) {
|
|
193
|
+
process.stdout.write('\n' + chalk_1.default.bold.yellow('--- stderr ---') + '\n' + logs.stderr + '\n');
|
|
194
|
+
}
|
|
195
|
+
process.stdout.write('\n');
|
|
196
|
+
// Footer hint
|
|
197
|
+
process.stdout.write(chalk_1.default.gray(`View trace: orch trace ${replay.run_id.slice(0, 8)}\n`));
|
|
198
|
+
}
|
|
@@ -0,0 +1,311 @@
|
|
|
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.registerTraceCommand = registerTraceCommand;
|
|
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
|
+
const output_1 = require("../lib/output");
|
|
12
|
+
// ============================================
|
|
13
|
+
// HELPERS
|
|
14
|
+
// ============================================
|
|
15
|
+
async function resolveWorkspaceId(config, slug) {
|
|
16
|
+
const configFile = await (0, config_1.loadConfig)();
|
|
17
|
+
const targetSlug = slug ?? configFile.workspace;
|
|
18
|
+
if (!targetSlug) {
|
|
19
|
+
throw new errors_1.CliError('No workspace specified. Use --workspace <slug> or run `orch workspace use <slug>` first.');
|
|
20
|
+
}
|
|
21
|
+
const response = await (0, api_1.request)(config, 'GET', '/workspaces');
|
|
22
|
+
const workspace = response.workspaces.find((w) => w.slug === targetSlug);
|
|
23
|
+
if (!workspace) {
|
|
24
|
+
throw new errors_1.CliError(`Workspace '${targetSlug}' not found.`);
|
|
25
|
+
}
|
|
26
|
+
return workspace.id;
|
|
27
|
+
}
|
|
28
|
+
function isUuid(value) {
|
|
29
|
+
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value);
|
|
30
|
+
}
|
|
31
|
+
function isShortUuid(value) {
|
|
32
|
+
return /^[0-9a-f]{7,}$/i.test(value) && !value.includes('/');
|
|
33
|
+
}
|
|
34
|
+
async function resolveShortRunId(config, workspaceId, shortId) {
|
|
35
|
+
const result = await (0, api_1.request)(config, 'GET', `/workspaces/${workspaceId}/runs?limit=200&run_id_prefix=${encodeURIComponent(shortId)}`);
|
|
36
|
+
if (result.runs.length === 0) {
|
|
37
|
+
throw new errors_1.CliError(`No run found matching '${shortId}'.`);
|
|
38
|
+
}
|
|
39
|
+
if (result.runs.length > 1) {
|
|
40
|
+
throw new errors_1.CliError(`Ambiguous run ID '${shortId}' — matches ${result.runs.length} runs. Use more characters to narrow it down.`);
|
|
41
|
+
}
|
|
42
|
+
return result.runs[0].id;
|
|
43
|
+
}
|
|
44
|
+
function statusColor(status) {
|
|
45
|
+
if (!status)
|
|
46
|
+
return '-';
|
|
47
|
+
switch (status) {
|
|
48
|
+
case 'completed':
|
|
49
|
+
return chalk_1.default.green(status);
|
|
50
|
+
case 'failed':
|
|
51
|
+
return chalk_1.default.red(status);
|
|
52
|
+
case 'running':
|
|
53
|
+
return chalk_1.default.yellow(status);
|
|
54
|
+
case 'timeout':
|
|
55
|
+
return chalk_1.default.red(status);
|
|
56
|
+
default:
|
|
57
|
+
return status;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function formatDuration(ms) {
|
|
61
|
+
if (ms == null)
|
|
62
|
+
return '-';
|
|
63
|
+
if (ms < 1000)
|
|
64
|
+
return `${ms}ms`;
|
|
65
|
+
if (ms < 60000)
|
|
66
|
+
return `${(ms / 1000).toFixed(1)}s`;
|
|
67
|
+
return `${(ms / 60000).toFixed(1)}m`;
|
|
68
|
+
}
|
|
69
|
+
function formatCost(usd) {
|
|
70
|
+
if (usd == null || usd === 0)
|
|
71
|
+
return '-';
|
|
72
|
+
if (usd < 0.01)
|
|
73
|
+
return `$${usd.toFixed(6)}`;
|
|
74
|
+
return `$${usd.toFixed(4)}`;
|
|
75
|
+
}
|
|
76
|
+
function formatTokens(input, output) {
|
|
77
|
+
const parts = [];
|
|
78
|
+
if (input)
|
|
79
|
+
parts.push(`${input.toLocaleString()} in`);
|
|
80
|
+
if (output)
|
|
81
|
+
parts.push(`${output.toLocaleString()} out`);
|
|
82
|
+
return parts.length > 0 ? parts.join(', ') : '-';
|
|
83
|
+
}
|
|
84
|
+
// ============================================
|
|
85
|
+
// COMMAND REGISTRATION
|
|
86
|
+
// ============================================
|
|
87
|
+
function registerTraceCommand(program) {
|
|
88
|
+
program
|
|
89
|
+
.command('trace <run-id>')
|
|
90
|
+
.description('View the execution trace for a run. Shows LLM calls, tool calls, decisions, and errors in timeline order.')
|
|
91
|
+
.option('--workspace <slug>', 'Workspace slug (default: current workspace)')
|
|
92
|
+
.option('--json', 'Output as JSON')
|
|
93
|
+
.action(async (runId, options) => {
|
|
94
|
+
const config = await (0, config_1.getResolvedConfig)();
|
|
95
|
+
if (!config.apiKey) {
|
|
96
|
+
throw new errors_1.CliError('Missing API key. Run `orch login` first.');
|
|
97
|
+
}
|
|
98
|
+
const workspaceId = await resolveWorkspaceId(config, options.workspace);
|
|
99
|
+
// Resolve short run IDs
|
|
100
|
+
let resolvedRunId = runId;
|
|
101
|
+
if (isUuid(runId)) {
|
|
102
|
+
resolvedRunId = runId;
|
|
103
|
+
}
|
|
104
|
+
else if (isShortUuid(runId)) {
|
|
105
|
+
resolvedRunId = await resolveShortRunId(config, workspaceId, runId);
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
throw new errors_1.CliError(`Invalid run ID '${runId}'. Provide a full UUID or a short hex prefix (7+ characters).`);
|
|
109
|
+
}
|
|
110
|
+
// Fetch run detail for context
|
|
111
|
+
const run = await (0, api_1.request)(config, 'GET', `/workspaces/${workspaceId}/runs/${resolvedRunId}`);
|
|
112
|
+
// Fetch trace header
|
|
113
|
+
let trace;
|
|
114
|
+
try {
|
|
115
|
+
const traceResp = await (0, api_1.request)(config, 'GET', `/workspaces/${workspaceId}/runs/${resolvedRunId}/trace`);
|
|
116
|
+
trace = traceResp.trace;
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
throw new errors_1.CliError(`No trace available for run ${resolvedRunId.slice(0, 8)}. Traces are captured for cloud runs only.`);
|
|
120
|
+
}
|
|
121
|
+
// Fetch all trace events (paginate if needed)
|
|
122
|
+
const allEvents = [];
|
|
123
|
+
let offset = 0;
|
|
124
|
+
const pageSize = 500;
|
|
125
|
+
while (true) {
|
|
126
|
+
const eventsResp = await (0, api_1.request)(config, 'GET', `/workspaces/${workspaceId}/traces/${trace.id}/events?limit=${pageSize}&offset=${offset}`);
|
|
127
|
+
allEvents.push(...eventsResp.events);
|
|
128
|
+
if (eventsResp.next_cursor === null || allEvents.length >= eventsResp.total) {
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
offset = parseInt(eventsResp.next_cursor, 10);
|
|
132
|
+
}
|
|
133
|
+
if (options.json) {
|
|
134
|
+
(0, output_1.printJson)({ run, trace, events: allEvents });
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
renderTrace(run, trace, allEvents);
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
// ============================================
|
|
141
|
+
// TRACE RENDERING
|
|
142
|
+
// ============================================
|
|
143
|
+
function renderTrace(run, trace, events) {
|
|
144
|
+
// Header
|
|
145
|
+
process.stdout.write(chalk_1.default.bold(`\nTrace for run ${run.id}\n`) +
|
|
146
|
+
` Agent: ${run.agent_name ?? '-'}@${run.agent_version ?? '-'}\n` +
|
|
147
|
+
` Status: ${statusColor(run.status)}\n` +
|
|
148
|
+
` Duration: ${formatDuration(run.duration_ms)}\n` +
|
|
149
|
+
` Source: ${run.trigger_source ?? '-'}\n`);
|
|
150
|
+
// Aggregate stats
|
|
151
|
+
const stats = computeStats(events);
|
|
152
|
+
if (stats.totalLlmCalls > 0 || stats.totalToolCalls > 0) {
|
|
153
|
+
process.stdout.write('\n' + chalk_1.default.bold(' Summary\n'));
|
|
154
|
+
if (stats.totalLlmCalls > 0) {
|
|
155
|
+
process.stdout.write(` LLM calls: ${stats.totalLlmCalls}` +
|
|
156
|
+
` (${formatTokens(stats.totalTokenInput, stats.totalTokenOutput)})` +
|
|
157
|
+
` cost: ${formatCost(stats.totalCostUsd)}\n`);
|
|
158
|
+
}
|
|
159
|
+
if (stats.totalToolCalls > 0) {
|
|
160
|
+
process.stdout.write(` Tool calls: ${stats.totalToolCalls}\n`);
|
|
161
|
+
}
|
|
162
|
+
if (stats.providers.length > 0) {
|
|
163
|
+
process.stdout.write(` Providers: ${stats.providers.join(', ')}\n`);
|
|
164
|
+
}
|
|
165
|
+
if (stats.totalErrors > 0) {
|
|
166
|
+
process.stdout.write(` Errors: ${chalk_1.default.red(String(stats.totalErrors))}\n`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
if (events.length === 0) {
|
|
170
|
+
process.stdout.write(chalk_1.default.gray('\n No trace events recorded.\n\n'));
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
// Timeline
|
|
174
|
+
process.stdout.write('\n' + chalk_1.default.bold(' Timeline\n'));
|
|
175
|
+
for (const event of events) {
|
|
176
|
+
renderEvent(event);
|
|
177
|
+
}
|
|
178
|
+
process.stdout.write('\n');
|
|
179
|
+
// Footer hint
|
|
180
|
+
process.stdout.write(chalk_1.default.gray(`View logs: orch logs ${run.id.slice(0, 8)}\n`));
|
|
181
|
+
process.stdout.write(chalk_1.default.gray(`Replay: orch replay ${run.id.slice(0, 8)}\n`));
|
|
182
|
+
}
|
|
183
|
+
function computeStats(events) {
|
|
184
|
+
const stats = {
|
|
185
|
+
totalLlmCalls: 0,
|
|
186
|
+
totalToolCalls: 0,
|
|
187
|
+
totalErrors: 0,
|
|
188
|
+
totalTokenInput: 0,
|
|
189
|
+
totalTokenOutput: 0,
|
|
190
|
+
totalCostUsd: 0,
|
|
191
|
+
providers: [],
|
|
192
|
+
};
|
|
193
|
+
const providerSet = new Set();
|
|
194
|
+
for (const e of events) {
|
|
195
|
+
if (e.event_type === 'llm_call_succeeded') {
|
|
196
|
+
stats.totalLlmCalls++;
|
|
197
|
+
stats.totalTokenInput += e.token_input ?? 0;
|
|
198
|
+
stats.totalTokenOutput += e.token_output ?? 0;
|
|
199
|
+
stats.totalCostUsd += e.cost_usd ?? 0;
|
|
200
|
+
if (e.provider)
|
|
201
|
+
providerSet.add(e.provider);
|
|
202
|
+
}
|
|
203
|
+
else if (e.event_type === 'llm_call_failed') {
|
|
204
|
+
stats.totalLlmCalls++;
|
|
205
|
+
stats.totalErrors++;
|
|
206
|
+
if (e.provider)
|
|
207
|
+
providerSet.add(e.provider);
|
|
208
|
+
}
|
|
209
|
+
else if (e.event_type === 'tool_call_succeeded') {
|
|
210
|
+
stats.totalToolCalls++;
|
|
211
|
+
}
|
|
212
|
+
else if (e.event_type === 'tool_call_failed') {
|
|
213
|
+
stats.totalToolCalls++;
|
|
214
|
+
stats.totalErrors++;
|
|
215
|
+
}
|
|
216
|
+
else if (e.event_type === 'error') {
|
|
217
|
+
stats.totalErrors++;
|
|
218
|
+
}
|
|
219
|
+
else if (e.event_type === 'policy_violation') {
|
|
220
|
+
stats.totalErrors++;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
stats.providers = Array.from(providerSet);
|
|
224
|
+
return stats;
|
|
225
|
+
}
|
|
226
|
+
function renderEvent(event) {
|
|
227
|
+
const seq = chalk_1.default.gray(` #${String(event.sequence_no).padStart(2, ' ')} `);
|
|
228
|
+
switch (event.event_type) {
|
|
229
|
+
case 'llm_call_started': {
|
|
230
|
+
const provider = event.provider ?? '?';
|
|
231
|
+
const model = event.model ?? '?';
|
|
232
|
+
process.stdout.write(seq + chalk_1.default.blue('LLM ') + chalk_1.default.gray(`${provider}/${model} started\n`));
|
|
233
|
+
break;
|
|
234
|
+
}
|
|
235
|
+
case 'llm_call_succeeded': {
|
|
236
|
+
const provider = event.provider ?? '?';
|
|
237
|
+
const model = event.model ?? '?';
|
|
238
|
+
const tokens = formatTokens(event.token_input, event.token_output);
|
|
239
|
+
const cost = formatCost(event.cost_usd);
|
|
240
|
+
const dur = formatDuration(event.duration_ms);
|
|
241
|
+
process.stdout.write(seq + chalk_1.default.green('LLM ') +
|
|
242
|
+
`${provider}/${model}` +
|
|
243
|
+
chalk_1.default.gray(` | ${tokens} | ${cost} | ${dur}`) + '\n');
|
|
244
|
+
break;
|
|
245
|
+
}
|
|
246
|
+
case 'llm_call_failed': {
|
|
247
|
+
const provider = event.provider ?? '?';
|
|
248
|
+
const model = event.model ?? '?';
|
|
249
|
+
const errMsg = event.error_message || event.error_type || 'unknown error';
|
|
250
|
+
const dur = formatDuration(event.duration_ms);
|
|
251
|
+
process.stdout.write(seq + chalk_1.default.red('LLM ') +
|
|
252
|
+
`${provider}/${model} ` +
|
|
253
|
+
chalk_1.default.red(errMsg) +
|
|
254
|
+
chalk_1.default.gray(` | ${dur}`) + '\n');
|
|
255
|
+
break;
|
|
256
|
+
}
|
|
257
|
+
case 'tool_call_started': {
|
|
258
|
+
const toolName = event.payload?.tool_name || '?';
|
|
259
|
+
process.stdout.write(seq + chalk_1.default.cyan('TOOL ') + chalk_1.default.gray(`${toolName} started\n`));
|
|
260
|
+
break;
|
|
261
|
+
}
|
|
262
|
+
case 'tool_call_succeeded': {
|
|
263
|
+
const toolName = event.payload?.tool_name || '?';
|
|
264
|
+
const dur = formatDuration(event.duration_ms);
|
|
265
|
+
process.stdout.write(seq + chalk_1.default.green('TOOL ') + `${toolName}` +
|
|
266
|
+
chalk_1.default.gray(` | ${dur}`) + '\n');
|
|
267
|
+
break;
|
|
268
|
+
}
|
|
269
|
+
case 'tool_call_failed': {
|
|
270
|
+
const toolName = event.payload?.tool_name || '?';
|
|
271
|
+
const errMsg = event.error_message || event.error_type || 'unknown error';
|
|
272
|
+
const dur = formatDuration(event.duration_ms);
|
|
273
|
+
process.stdout.write(seq + chalk_1.default.red('TOOL ') + `${toolName} ` +
|
|
274
|
+
chalk_1.default.red(errMsg) +
|
|
275
|
+
chalk_1.default.gray(` | ${dur}`) + '\n');
|
|
276
|
+
break;
|
|
277
|
+
}
|
|
278
|
+
case 'decision': {
|
|
279
|
+
const desc = event.payload?.description || 'decision';
|
|
280
|
+
process.stdout.write(seq + chalk_1.default.magenta('DECIDE ') + chalk_1.default.gray(desc) + '\n');
|
|
281
|
+
break;
|
|
282
|
+
}
|
|
283
|
+
case 'fallback_transition': {
|
|
284
|
+
const from = event.payload?.from_provider || '?';
|
|
285
|
+
const to = event.payload?.to_provider || '?';
|
|
286
|
+
const reason = event.payload?.reason || '';
|
|
287
|
+
process.stdout.write(seq + chalk_1.default.yellow('FALLBACK ') +
|
|
288
|
+
`${from} -> ${to}` +
|
|
289
|
+
(reason ? chalk_1.default.gray(` (${reason})`) : '') + '\n');
|
|
290
|
+
break;
|
|
291
|
+
}
|
|
292
|
+
case 'policy_violation': {
|
|
293
|
+
const vType = event.payload?.violation_type || 'violation';
|
|
294
|
+
const detail = event.payload?.detail || '';
|
|
295
|
+
process.stdout.write(seq + chalk_1.default.red('POLICY ') + chalk_1.default.red(vType) +
|
|
296
|
+
(detail ? chalk_1.default.gray(` — ${detail}`) : '') + '\n');
|
|
297
|
+
break;
|
|
298
|
+
}
|
|
299
|
+
case 'error': {
|
|
300
|
+
const errType = event.error_type || 'error';
|
|
301
|
+
const errMsg = event.error_message || '';
|
|
302
|
+
process.stdout.write(seq + chalk_1.default.red('ERROR ') + chalk_1.default.red(errType) +
|
|
303
|
+
(errMsg ? chalk_1.default.gray(` — ${errMsg}`) : '') + '\n');
|
|
304
|
+
break;
|
|
305
|
+
}
|
|
306
|
+
default: {
|
|
307
|
+
// Unknown event type — show raw
|
|
308
|
+
process.stdout.write(seq + chalk_1.default.gray(event.event_type) + '\n');
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
package/package.json
CHANGED
package/dist/commands/call.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.registerCallCommand = registerCallCommand;
|
|
4
|
-
/**
|
|
5
|
-
* Deprecated: The 'call' command has been merged into 'run'.
|
|
6
|
-
* Cloud execution is now the default behavior of 'orchagent run'.
|
|
7
|
-
* This file provides a thin alias that prints a deprecation notice and exits.
|
|
8
|
-
*/
|
|
9
|
-
function registerCallCommand(program) {
|
|
10
|
-
program
|
|
11
|
-
.command('call')
|
|
12
|
-
.description('Deprecated: use "orchagent run" instead')
|
|
13
|
-
.allowUnknownOption()
|
|
14
|
-
.allowExcessArguments()
|
|
15
|
-
.action(() => {
|
|
16
|
-
process.stderr.write(`The 'call' command has been merged into 'run'.\n\n` +
|
|
17
|
-
`Cloud execution is now the default behavior of 'orchagent run':\n` +
|
|
18
|
-
` orchagent run <agent> --data '{...}' # runs on server (cloud)\n` +
|
|
19
|
-
` orchagent run <agent> --local --data '...' # runs locally\n\n` +
|
|
20
|
-
`Replace 'orchagent call' with 'orchagent run' in your commands.\n`);
|
|
21
|
-
process.exit(1);
|
|
22
|
-
});
|
|
23
|
-
}
|
package/dist/commands/keys.js
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
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.registerKeysCommand = registerKeysCommand;
|
|
7
|
-
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
-
function registerKeysCommand(program) {
|
|
9
|
-
program
|
|
10
|
-
.command('keys')
|
|
11
|
-
.description('(Deprecated) Use "orch secrets" instead')
|
|
12
|
-
.allowUnknownOption(true)
|
|
13
|
-
.action(() => {
|
|
14
|
-
process.stderr.write(chalk_1.default.yellow('\nThe `orch keys` command has been removed.\n\n') +
|
|
15
|
-
`LLM API keys are now managed through the unified workspace secrets vault.\n` +
|
|
16
|
-
`Use ${chalk_1.default.cyan('orch secrets')} instead:\n\n` +
|
|
17
|
-
` ${chalk_1.default.cyan('orch secrets set ANTHROPIC_API_KEY <key>')} Add an LLM key\n` +
|
|
18
|
-
` ${chalk_1.default.cyan('orch secrets list')} List all secrets\n` +
|
|
19
|
-
` ${chalk_1.default.cyan('orch secrets delete ANTHROPIC_API_KEY')} Remove a key\n\n`);
|
|
20
|
-
process.exit(1);
|
|
21
|
-
});
|
|
22
|
-
}
|