@orchagent/cli 0.3.62 → 0.3.64

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.
@@ -226,13 +226,10 @@ async function importFromGitHub(config, repo, options) {
226
226
  selectedPath = selection.path;
227
227
  }
228
228
  }
229
- // Determine visibility (default to public)
230
- const isPublic = options.private ? false : true;
231
229
  const importResult = await (0, api_1.request)(config, 'POST', '/github/import', {
232
230
  body: JSON.stringify({
233
231
  repo,
234
232
  path: selectedPath,
235
- is_public: isPublic,
236
233
  name: options.name,
237
234
  }),
238
235
  headers: { 'Content-Type': 'application/json' },
@@ -240,7 +237,6 @@ async function importFromGitHub(config, repo, options) {
240
237
  await (0, analytics_1.track)('cli_github_import', {
241
238
  repo,
242
239
  path: selectedPath,
243
- is_public: isPublic,
244
240
  type: importResult.agent.type,
245
241
  });
246
242
  if (options.json) {
@@ -253,7 +249,6 @@ async function importFromGitHub(config, repo, options) {
253
249
  process.stdout.write(` Agent: ${importResult.agent.name}\n`);
254
250
  process.stdout.write(` Version: ${importResult.agent.version}\n`);
255
251
  process.stdout.write(` Type: ${importResult.agent.type}\n`);
256
- process.stdout.write(` Public: ${isPublic ? chalk_1.default.green('Yes') : chalk_1.default.yellow('No')}\n`);
257
252
  process.stdout.write('\n');
258
253
  }
259
254
  async function getSyncConfig(config, agentId, options) {
@@ -335,8 +330,6 @@ function registerGitHubCommand(program) {
335
330
  .command('import <repo>')
336
331
  .description('Import an agent or skill from GitHub')
337
332
  .option('--path <path>', 'Path to manifest within repo (scans if not specified)')
338
- .option('--public', 'Make the agent public (default)')
339
- .option('--private', 'Make the agent private')
340
333
  .option('--name <name>', 'Override agent name')
341
334
  .option('--json', 'Output raw JSON')
342
335
  .action(async (repo, options) => {
@@ -33,6 +33,7 @@ const schedule_1 = require("./schedule");
33
33
  const service_1 = require("./service");
34
34
  const transfer_1 = require("./transfer");
35
35
  const pull_1 = require("./pull");
36
+ const logs_1 = require("./logs");
36
37
  function registerCommands(program) {
37
38
  (0, login_1.registerLoginCommand)(program);
38
39
  (0, whoami_1.registerWhoamiCommand)(program);
@@ -66,4 +67,5 @@ function registerCommands(program) {
66
67
  (0, service_1.registerServiceCommand)(program);
67
68
  (0, transfer_1.registerTransferCommand)(program);
68
69
  (0, pull_1.registerPullCommand)(program);
70
+ (0, logs_1.registerLogsCommand)(program);
69
71
  }
@@ -60,6 +60,7 @@ async function getAgentInfo(config, org, agent, version) {
60
60
  version: publicMeta.version,
61
61
  description: (publicMeta.description ?? undefined),
62
62
  supported_providers: publicMeta.supported_providers || ['any'],
63
+ callable: publicMeta.callable ?? false,
63
64
  input_schema: publicMeta.input_schema,
64
65
  output_schema: publicMeta.output_schema,
65
66
  source_url: meta.source_url,
@@ -103,6 +104,7 @@ async function getAgentInfo(config, org, agent, version) {
103
104
  version: targetAgent.version,
104
105
  description: targetAgent.description,
105
106
  prompt: targetAgent.prompt,
107
+ callable: targetAgent.callable ?? false,
106
108
  input_schema: targetAgent.input_schema,
107
109
  output_schema: targetAgent.output_schema,
108
110
  supported_providers: targetAgent.supported_providers || ['any'],
@@ -140,6 +142,9 @@ function registerInfoCommand(program) {
140
142
  process.stdout.write(`${agentData.description}\n\n`);
141
143
  }
142
144
  process.stdout.write(`Type: ${agentData.type}\n`);
145
+ if (agentData.callable) {
146
+ process.stdout.write(`Callable: ${chalk_1.default.green('yes')} — other agents can invoke this via the orchagent SDK\n`);
147
+ }
143
148
  process.stdout.write(`Providers: ${agentData.supported_providers.join(', ')}\n`);
144
149
  // Display pricing information
145
150
  const priceStr = (0, pricing_1.formatPrice)(agentData);
@@ -72,6 +72,9 @@ def main():
72
72
  user_input = data.get("input", "")
73
73
 
74
74
  # --- Your logic here ---
75
+ # To use workspace secrets, add them to "required_secrets" in orchagent.json:
76
+ # "required_secrets": ["MY_API_KEY"]
77
+ # Then access via: os.environ["MY_API_KEY"]
75
78
  result = f"Received: {user_input}"
76
79
  # --- End your logic ---
77
80
 
@@ -83,15 +86,15 @@ if __name__ == "__main__":
83
86
  main()
84
87
  `;
85
88
  function readmeTemplate(agentName, flavor) {
86
- const inputField = flavor === 'managed_loop' ? 'task' : 'input';
87
- const inputDescription = flavor === 'managed_loop' ? 'The task to perform' : 'The input to process';
89
+ const inputField = flavor === 'managed_loop' || flavor === 'orchestrator' ? 'task' : 'input';
90
+ const inputDescription = flavor === 'managed_loop' || flavor === 'orchestrator' ? 'The task to perform' : 'The input to process';
88
91
  const cloudExample = flavor === 'code_runtime'
89
92
  ? `orchagent run ${agentName} --data '{"input": "Hello world"}'`
90
93
  : `orchagent run ${agentName} --data '{"${inputField}": "Hello world"}'`;
91
94
  const localExample = flavor === 'code_runtime'
92
95
  ? `orchagent run ${agentName} --local --data '{"input": "Hello world"}'`
93
96
  : `orchagent run ${agentName} --local --data '{"${inputField}": "Hello world"}'`;
94
- return `# ${agentName}
97
+ let readme = `# ${agentName}
95
98
 
96
99
  A brief description of what this agent does.
97
100
 
@@ -121,6 +124,20 @@ ${localExample}
121
124
  |-------|------|-------------|
122
125
  | \`result\` | string | The agent's response |
123
126
  `;
127
+ if (flavor === 'orchestrator') {
128
+ readme += `
129
+ ## Dependencies
130
+
131
+ This orchestrator calls other agents. Update \`manifest.dependencies\` in \`orchagent.json\` with your actual dependencies.
132
+
133
+ **Publish order:** Publish dependency agents first, then this orchestrator.
134
+
135
+ | Dependency | Version | Description |
136
+ |------------|---------|-------------|
137
+ | \`org/agent-name\` | v1 | TODO: describe what this agent does |
138
+ `;
139
+ }
140
+ return readme;
124
141
  }
125
142
  const AGENT_PROMPT_TEMPLATE = `You are a helpful AI agent.
126
143
 
@@ -154,6 +171,65 @@ const AGENT_SCHEMA_TEMPLATE = `{
154
171
  }
155
172
  }
156
173
  `;
174
+ const ORCHESTRATOR_MAIN_PY = `"""
175
+ orchagent orchestrator entrypoint.
176
+
177
+ Reads JSON input from stdin, calls dependency agents via the orchagent SDK,
178
+ and writes JSON output to stdout.
179
+
180
+ Usage:
181
+ echo '{"task": "do something"}' | python main.py
182
+ """
183
+
184
+ import asyncio
185
+ import json
186
+ import sys
187
+
188
+ from orchagent import AgentClient
189
+
190
+
191
+ def main():
192
+ # Read JSON input from stdin
193
+ raw = sys.stdin.read()
194
+ try:
195
+ data = json.loads(raw) if raw.strip() else {}
196
+ except json.JSONDecodeError:
197
+ print(json.dumps({"error": "Invalid JSON input"}))
198
+ sys.exit(1)
199
+
200
+ task = data.get("task", "")
201
+
202
+ # --- Your orchestration logic here ---
203
+ # The AgentClient reads ORCHAGENT_SERVICE_KEY from the environment automatically.
204
+ # Do NOT add ORCHAGENT_SERVICE_KEY to required_secrets — the gateway injects it.
205
+ client = AgentClient()
206
+
207
+ # Call a dependency agent (must be listed in manifest.dependencies)
208
+ result = asyncio.run(
209
+ client.call("org/agent-name@v1", {"input": task})
210
+ )
211
+
212
+ # You can chain multiple calls, run them in parallel, or add conditional logic:
213
+ #
214
+ # Sequential:
215
+ # result2 = asyncio.run(client.call("org/another-agent@v1", {"input": result}))
216
+ #
217
+ # Parallel:
218
+ # r1, r2 = asyncio.run(asyncio.gather(
219
+ # client.call("org/agent-a@v1", {"input": task}),
220
+ # client.call("org/agent-b@v1", {"input": task}),
221
+ # ))
222
+ # --- End orchestration logic ---
223
+
224
+ # Write JSON output to stdout
225
+ print(json.dumps({"result": result, "success": True}))
226
+
227
+
228
+ if __name__ == "__main__":
229
+ main()
230
+ `;
231
+ const ORCHESTRATOR_REQUIREMENTS = `orchagent-sdk>=0.1.0
232
+ `;
157
233
  const SKILL_TEMPLATE = `---
158
234
  name: my-skill
159
235
  description: When to use this skill
@@ -186,6 +262,7 @@ function registerInitCommand(program) {
186
262
  .description('Initialize a new agent project')
187
263
  .argument('[name]', 'Agent name (default: current directory name)')
188
264
  .option('--type <type>', 'Type: prompt, tool, agent, or skill (legacy aliases: agentic, code)', 'prompt')
265
+ .option('--orchestrator', 'Create an orchestrator agent with dependency scaffolding and SDK boilerplate')
189
266
  .option('--run-mode <mode>', 'Run mode for agents: on_demand or always_on', 'on_demand')
190
267
  .action(async (name, options) => {
191
268
  const cwd = process.cwd();
@@ -193,7 +270,13 @@ function registerInitCommand(program) {
193
270
  if (!['on_demand', 'always_on'].includes(runMode)) {
194
271
  throw new errors_1.CliError("Invalid --run-mode. Use 'on_demand' or 'always_on'.");
195
272
  }
196
- const initMode = resolveInitFlavor(options.type);
273
+ let initMode = resolveInitFlavor(options.type);
274
+ if (options.orchestrator) {
275
+ if (initMode.type === 'skill') {
276
+ throw new errors_1.CliError('Cannot use --orchestrator with --type skill. Orchestrators are agent-type agents that call other agents.');
277
+ }
278
+ initMode = { type: 'agent', flavor: 'orchestrator' };
279
+ }
197
280
  // When a name is provided, create a subdirectory for the project
198
281
  const targetDir = name ? path_1.default.join(cwd, name) : cwd;
199
282
  const agentName = name || path_1.default.basename(cwd);
@@ -244,7 +327,7 @@ function registerInitCommand(program) {
244
327
  throw err;
245
328
  }
246
329
  }
247
- if (initMode.flavor !== 'code_runtime' && runMode === 'always_on') {
330
+ if (initMode.flavor !== 'code_runtime' && initMode.flavor !== 'orchestrator' && runMode === 'always_on') {
248
331
  throw new errors_1.CliError("run_mode=always_on requires runtime.command in orchagent.json (e.g. \"runtime\": { \"command\": \"python main.py\" }). Use --type tool for code-runtime agents.");
249
332
  }
250
333
  // Create manifest and type-specific files
@@ -252,17 +335,38 @@ function registerInitCommand(program) {
252
335
  manifest.name = agentName;
253
336
  manifest.type = initMode.type;
254
337
  manifest.run_mode = runMode;
255
- if (initMode.flavor === 'managed_loop') {
338
+ if (initMode.flavor === 'orchestrator') {
339
+ manifest.description = 'An orchestrator agent that coordinates other agents';
340
+ manifest.runtime = { command: 'python main.py' };
341
+ manifest.manifest = {
342
+ manifest_version: 1,
343
+ dependencies: [{ id: 'org/agent-name', version: 'v1' }],
344
+ max_hops: 3,
345
+ timeout_ms: 120000,
346
+ per_call_downstream_cap: 50,
347
+ };
348
+ manifest.required_secrets = [];
349
+ }
350
+ else if (initMode.flavor === 'managed_loop') {
256
351
  manifest.description = 'An AI agent with tool use';
257
352
  manifest.supported_providers = ['anthropic'];
258
353
  manifest.loop = { max_turns: 25 };
354
+ manifest.required_secrets = [];
259
355
  }
260
356
  else if (initMode.flavor === 'code_runtime') {
261
357
  manifest.description = 'A code-runtime agent';
262
358
  manifest.runtime = { command: 'python main.py' };
359
+ manifest.required_secrets = [];
263
360
  }
264
361
  await promises_1.default.writeFile(manifestPath, JSON.stringify(manifest, null, 2) + '\n');
265
- if (initMode.flavor === 'code_runtime') {
362
+ if (initMode.flavor === 'orchestrator') {
363
+ const entrypointPath = path_1.default.join(targetDir, 'main.py');
364
+ const requirementsPath = path_1.default.join(targetDir, 'requirements.txt');
365
+ await promises_1.default.writeFile(entrypointPath, ORCHESTRATOR_MAIN_PY);
366
+ await promises_1.default.writeFile(requirementsPath, ORCHESTRATOR_REQUIREMENTS);
367
+ await promises_1.default.writeFile(schemaPath, AGENT_SCHEMA_TEMPLATE);
368
+ }
369
+ else if (initMode.flavor === 'code_runtime') {
266
370
  const entrypointPath = path_1.default.join(targetDir, 'main.py');
267
371
  await promises_1.default.writeFile(entrypointPath, CODE_TEMPLATE_PY);
268
372
  await promises_1.default.writeFile(schemaPath, SCHEMA_TEMPLATE);
@@ -281,19 +385,32 @@ function registerInitCommand(program) {
281
385
  process.stdout.write(`Initialized agent "${agentName}" in ${targetDir}\n`);
282
386
  process.stdout.write(`\nFiles created:\n`);
283
387
  const prefix = name ? name + '/' : '';
284
- process.stdout.write(` ${prefix}orchagent.json - Agent configuration\n`);
285
- if (initMode.flavor === 'code_runtime') {
286
- process.stdout.write(` ${prefix}main.py - Agent entrypoint (stdin/stdout JSON)\n`);
388
+ process.stdout.write(` ${prefix}orchagent.json - Agent configuration\n`);
389
+ if (initMode.flavor === 'orchestrator') {
390
+ process.stdout.write(` ${prefix}main.py - Orchestrator entrypoint (SDK calls)\n`);
391
+ process.stdout.write(` ${prefix}requirements.txt - Python dependencies (orchagent-sdk)\n`);
392
+ }
393
+ else if (initMode.flavor === 'code_runtime') {
394
+ process.stdout.write(` ${prefix}main.py - Agent entrypoint (stdin/stdout JSON)\n`);
287
395
  }
288
396
  else {
289
- process.stdout.write(` ${prefix}prompt.md - Prompt template\n`);
397
+ process.stdout.write(` ${prefix}prompt.md - Prompt template\n`);
290
398
  }
291
- process.stdout.write(` ${prefix}schema.json - Input/output schemas\n`);
292
- process.stdout.write(` ${prefix}README.md - Agent documentation\n`);
399
+ process.stdout.write(` ${prefix}schema.json - Input/output schemas\n`);
400
+ process.stdout.write(` ${prefix}README.md - Agent documentation\n`);
293
401
  process.stdout.write(` Run mode: ${runMode}\n`);
294
- process.stdout.write(` Execution: ${initMode.flavor}\n`);
402
+ process.stdout.write(` Execution: ${initMode.flavor === 'orchestrator' ? 'code_runtime (orchestrator)' : initMode.flavor}\n`);
295
403
  process.stdout.write(`\nNext steps:\n`);
296
- if (initMode.flavor === 'code_runtime') {
404
+ if (initMode.flavor === 'orchestrator') {
405
+ const stepNum = name ? 2 : 1;
406
+ if (name) {
407
+ process.stdout.write(` 1. cd ${name}\n`);
408
+ }
409
+ process.stdout.write(` ${stepNum}. Update manifest.dependencies in orchagent.json with your actual agents\n`);
410
+ process.stdout.write(` ${stepNum + 1}. Edit main.py with your orchestration logic\n`);
411
+ process.stdout.write(` ${stepNum + 2}. Publish dependency agents first, then: orchagent publish\n`);
412
+ }
413
+ else if (initMode.flavor === 'code_runtime') {
297
414
  const stepNum = name ? 2 : 1;
298
415
  if (name) {
299
416
  process.stdout.write(` 1. cd ${name}\n`);
@@ -0,0 +1,182 @@
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.registerLogsCommand = registerLogsCommand;
7
+ const cli_table3_1 = __importDefault(require("cli-table3"));
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ const config_1 = require("../lib/config");
10
+ const api_1 = require("../lib/api");
11
+ const errors_1 = require("../lib/errors");
12
+ const output_1 = require("../lib/output");
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 formatDate(iso) {
30
+ if (!iso)
31
+ return '-';
32
+ return new Date(iso).toLocaleString();
33
+ }
34
+ function statusColor(status) {
35
+ if (!status)
36
+ return '-';
37
+ switch (status) {
38
+ case 'completed':
39
+ return chalk_1.default.green(status);
40
+ case 'failed':
41
+ return chalk_1.default.red(status);
42
+ case 'running':
43
+ return chalk_1.default.yellow(status);
44
+ case 'timeout':
45
+ return chalk_1.default.red(status);
46
+ default:
47
+ return status;
48
+ }
49
+ }
50
+ function formatDuration(ms) {
51
+ if (ms == null)
52
+ return '-';
53
+ if (ms < 1000)
54
+ return `${ms}ms`;
55
+ if (ms < 60000)
56
+ return `${(ms / 1000).toFixed(1)}s`;
57
+ return `${(ms / 60000).toFixed(1)}m`;
58
+ }
59
+ /** Detect if a string looks like a UUID (run ID) */
60
+ function isUuid(value) {
61
+ return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value);
62
+ }
63
+ // ============================================
64
+ // COMMAND REGISTRATION
65
+ // ============================================
66
+ function registerLogsCommand(program) {
67
+ program
68
+ .command('logs [target]')
69
+ .description('View execution logs. Use with no args to list recent runs, an agent name to filter, or a run ID for full detail.')
70
+ .option('--workspace <slug>', 'Workspace slug (default: current workspace)')
71
+ .option('--status <status>', 'Filter by status: running, completed, failed, timeout')
72
+ .option('--limit <n>', 'Number of runs to show (default: 20)', '20')
73
+ .option('--json', 'Output as JSON')
74
+ .action(async (target, options) => {
75
+ const config = await (0, config_1.getResolvedConfig)();
76
+ if (!config.apiKey) {
77
+ throw new errors_1.CliError('Missing API key. Run `orch login` first.');
78
+ }
79
+ const workspaceId = await resolveWorkspaceId(config, options.workspace);
80
+ // If target looks like a UUID, show detailed logs for that run
81
+ if (target && isUuid(target)) {
82
+ await showRunLogs(config, workspaceId, target, options.json);
83
+ return;
84
+ }
85
+ // Otherwise list runs, optionally filtered by agent name
86
+ await listRuns(config, workspaceId, target, options);
87
+ });
88
+ }
89
+ // ============================================
90
+ // LIST RUNS
91
+ // ============================================
92
+ async function listRuns(config, workspaceId, agentName, options) {
93
+ const params = new URLSearchParams();
94
+ if (agentName)
95
+ params.set('agent_name', agentName);
96
+ if (options.status)
97
+ params.set('status', options.status);
98
+ const limit = parseInt(options.limit ?? '20', 10);
99
+ params.set('limit', String(Math.min(Math.max(1, limit), 200)));
100
+ const qs = params.toString() ? `?${params.toString()}` : '';
101
+ const result = await (0, api_1.request)(config, 'GET', `/workspaces/${workspaceId}/runs${qs}`);
102
+ if (options.json) {
103
+ (0, output_1.printJson)(result);
104
+ return;
105
+ }
106
+ if (result.runs.length === 0) {
107
+ if (agentName) {
108
+ process.stdout.write(`No runs found for agent '${agentName}'.\n`);
109
+ }
110
+ else {
111
+ process.stdout.write('No runs found in this workspace.\n');
112
+ }
113
+ return;
114
+ }
115
+ const table = new cli_table3_1.default({
116
+ head: [
117
+ chalk_1.default.bold('Run ID'),
118
+ chalk_1.default.bold('Agent'),
119
+ chalk_1.default.bold('Status'),
120
+ chalk_1.default.bold('Duration'),
121
+ chalk_1.default.bold('Source'),
122
+ chalk_1.default.bold('Started'),
123
+ chalk_1.default.bold('Error'),
124
+ ],
125
+ });
126
+ result.runs.forEach((r) => {
127
+ const errorPreview = r.error_message
128
+ ? chalk_1.default.red(r.error_message.length > 50 ? r.error_message.slice(0, 50) + '...' : r.error_message)
129
+ : chalk_1.default.gray('-');
130
+ table.push([
131
+ r.id.slice(0, 8),
132
+ `${r.agent_name}@${r.agent_version}`,
133
+ statusColor(r.status),
134
+ formatDuration(r.duration_ms),
135
+ r.trigger_source ?? '-',
136
+ formatDate(r.started_at || r.created_at),
137
+ errorPreview,
138
+ ]);
139
+ });
140
+ process.stdout.write(table.toString() + '\n');
141
+ if (result.total > result.runs.length) {
142
+ process.stdout.write(chalk_1.default.gray(`\nShowing ${result.runs.length} of ${result.total} runs. Use --limit to see more.\n`));
143
+ }
144
+ process.stdout.write(chalk_1.default.gray('\nView detailed logs for a run: orch logs <run-id>\n'));
145
+ }
146
+ // ============================================
147
+ // SHOW RUN LOGS
148
+ // ============================================
149
+ async function showRunLogs(config, workspaceId, runId, json) {
150
+ const result = await (0, api_1.request)(config, 'GET', `/workspaces/${workspaceId}/runs/${runId}/logs`);
151
+ if (json) {
152
+ (0, output_1.printJson)(result);
153
+ return;
154
+ }
155
+ // Header
156
+ process.stdout.write(chalk_1.default.bold(`\nRun ${runId}\n`) +
157
+ `Agent: ${result.agent_name ?? '-'}@${result.agent_version ?? '-'}\n` +
158
+ `Status: ${statusColor(result.run_status)}\n` +
159
+ `Duration: ${formatDuration(result.execution_time_ms)}\n`);
160
+ if (result.exit_code != null) {
161
+ const exitLabel = result.exit_code === 0 ? chalk_1.default.green(String(result.exit_code)) : chalk_1.default.red(String(result.exit_code));
162
+ process.stdout.write(`Exit code: ${exitLabel}\n`);
163
+ }
164
+ // Error message
165
+ if (result.error_message) {
166
+ process.stdout.write('\n' + chalk_1.default.red.bold('Error:\n') + chalk_1.default.red(result.error_message) + '\n');
167
+ }
168
+ // Stdout
169
+ if (result.stdout) {
170
+ process.stdout.write('\n' + chalk_1.default.bold.cyan('--- stdout ---') + '\n' + result.stdout + '\n');
171
+ }
172
+ // Stderr
173
+ if (result.stderr) {
174
+ process.stdout.write('\n' + chalk_1.default.bold.yellow('--- stderr ---') + '\n' + result.stderr + '\n');
175
+ }
176
+ // No execution log available
177
+ if (!result.has_execution_log && !result.error_message) {
178
+ process.stdout.write(chalk_1.default.gray('\nNo sandbox output available for this run. ' +
179
+ 'Execution logs are captured for agents with a code runtime (tool/agent types with runtime.command).\n'));
180
+ }
181
+ process.stdout.write('\n');
182
+ }