evals 2.6.0 → 2.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -8,7 +8,9 @@ Go from zero to your first [Arize AX](https://arize.com/docs/ax) traces in one c
8
8
  npx evals
9
9
  ```
10
10
 
11
- You'll see a picker of the coding agents installed on your machine (Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI). Pick one and it launches in your current directory, seeded with the onboarding prompt — so run `npx evals` from the project you want to instrument.
11
+ You'll see a picker of the coding agents installed on your machine (Claude Code, Codex, Cursor, GitHub Copilot, Antigravity CLI). Pick one and it launches in your current directory, seeded with the onboarding prompt — so run `npx evals` from the project you want to instrument.
12
+
13
+ **Pasted `npx evals` into a coding agent?** If an agent runs it as a shell command there is no interactive terminal, so nothing is launched. It stages the onboarding prompt and prints two lines asking you to re-run in a terminal, with the staged prompt path in case you would rather point your agent at it yourself. Agents treat command output as data rather than instructions, so this deliberately asks *you* rather than trying to hand the flow to them.
12
14
 
13
15
  No coding agent installed? The picker shows install links instead.
14
16
 
@@ -44,7 +46,7 @@ The agent runs with its **normal permission model** — `evals` never passes ski
44
46
 
45
47
  | Variable | Applies to | Effect |
46
48
  |----------|-----------|--------|
47
- | `ARIZE_AGENT=<id>` | `start.sh` / `start.ps1` | Skip the picker and use this agent (`claude`, `codex`, `cursor-agent`, `copilot`, `gemini`). |
49
+ | `ARIZE_AGENT=<id>` | `start.sh` / `start.ps1` | Skip the picker and use this agent (`claude`, `codex`, `cursor-agent`, `copilot`, `agy`). |
48
50
  | `ARIZE_SKIP_NPX=1` | `start.sh` / `start.ps1` | Force the shell path even when Node/npx is available. |
49
51
  | `ARIZE_PROMPT_URL=<url>` | `start.sh` / `start.ps1` | Fetch the onboarding prompt from a custom URL (supports `file://`). |
50
52
  | `ARIZE_ONBOARDING_DIR=<dir>` | all three | Stage the prompt somewhere other than `~/.arize/onboarding`. |
package/cli.js CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  import React, { useState, useEffect } from 'react';
4
4
  import { render, Box, Text, useInput, useApp, Static } from 'ink';
5
- import Gradient from 'ink-gradient';
6
5
  import { exec, spawn } from 'child_process';
7
6
  import {
8
7
  existsSync,
@@ -25,6 +24,13 @@ import { fileURLToPath } from 'url';
25
24
 
26
25
  const e = React.createElement;
27
26
 
27
+ // Arize brand magenta, from the 2026 rebrand design system. The mark is a single
28
+ // flat fill (`--brand-accent-ink`, the hex in arize-mark.svg) — the brand has no
29
+ // gradient anywhere, so the logo doesn't get one either. Interactive accents use
30
+ // Pink 400 (`--brand-accent`), which the palette keeps distinct from the mark.
31
+ const BRAND_MARK = '#EC2088';
32
+ const BRAND_ACCENT = '#FF3CA8';
33
+
28
34
  // The onboarding prompt is bundled with this package (onboarding-prompt.md).
29
35
  // This repo is its only home — there is no docs original to sync against, so
30
36
  // edit it here. We read it, write it to a temp file, and tell the agent to read
@@ -205,7 +211,7 @@ export const AGENTS = [
205
211
  { id: 'codex', label: 'OpenAI Codex', bin: 'codex', args: (s) => [s], installUrl: 'https://developers.openai.com/codex/cli' },
206
212
  { id: 'cursor-agent', label: 'Cursor', bin: 'cursor-agent', args: (s) => [s], installUrl: 'https://docs.cursor.com/en/cli/overview' },
207
213
  { id: 'copilot', label: 'GitHub Copilot', bin: 'copilot', args: (s) => ['-i', s], installUrl: 'https://github.com/features/copilot/cli' },
208
- { id: 'gemini', label: 'Gemini CLI', bin: 'gemini', args: (s) => ['-i', s], installUrl: 'https://github.com/google-gemini/gemini-cli' }
214
+ { id: 'agy', label: 'Antigravity CLI', bin: 'agy', args: (s) => ['-i', s], installUrl: 'https://antigravity.google/docs/cli/getting-started' }
209
215
  ];
210
216
 
211
217
  // PATH scan — detects an agent without executing it (running it could hang).
@@ -226,33 +232,21 @@ export function isInstalled(bin) {
226
232
  return false;
227
233
  }
228
234
 
229
- // "ARIZE EVALS" - EXACTLY matched width (both 44 chars)
235
+ // "ARIZE AX" on one line 66 columns wide, so Header() drops to the compact
236
+ // two-row art below 68 and to plain text below 30.
230
237
  const largeLogo = `
231
- █████╗ ██████╗ ██╗ ███████╗ ███████╗
232
- ██╔══██╗ ██╔══██╗ ██║ ╚══███╔╝ ██╔════╝
233
- ███████║ ██████╔╝ ██║ ███╔╝ █████╗
234
- ██╔══██║ ██╔══██╗ ██║ ███╔╝ ██╔══╝
235
- ██║ ██║ ██║ ██║ ██║ ███████╗ ███████╗
236
- ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚══════╝ ╚══════╝
237
- ███████╗ ██╗ ██╗ █████╗ ██╗ ███████╗
238
- ██╔════╝ ██║ ██║ ██╔══██╗ ██║ ██╔════╝
239
- █████╗ ██║ ██║ ███████║ ██║ ███████╗
240
- ██╔══╝ ╚██╗ ██╔╝ ██╔══██║ ██║ ╚════██║
241
- ███████╗ ╚████╔╝ ██║ ██║ ███████╗███████║
242
- ╚══════╝ ╚═══╝ ╚═╝ ╚═╝ ╚══════╝╚══════╝`;
238
+ █████╗ ██████╗ ██╗ ███████╗ ███████╗ █████╗ ██╗ ██╗
239
+ ██╔══██╗ ██╔══██╗ ██║ ╚══███╔╝ ██╔════╝ ██╔══██╗ ╚██╗██╔╝
240
+ ███████║ ██████╔╝ ██║ ███╔╝ █████╗ ███████║ ╚███╔╝
241
+ ██╔══██║ ██╔══██╗ ██║ ███╔╝ ██╔══╝ ██╔══██║ ██╔██╗
242
+ ██║ ██║ ██║ ██║ ██║ ███████╗ ███████╗ ██║ ██║ ██╔╝ ██╗
243
+ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚══════╝ ╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝`;
243
244
 
244
245
  const mediumLogo = `
245
- █████╗ ██████╗ ██╗ ███████╗ ███████╗
246
- ██╔══██╗ ██╔══██╗ ██║ ╚══███╔╝ ██╔════╝
247
- ███████║ ██████╔╝ ██║ ███╔╝ █████╗
248
- ██╔══██║ ██╔══██╗ ██║ ███╔╝ ██╔══╝
249
- ██║ ██║ ██║ ██║ ██║ ███████╗ ███████╗
250
- ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚══════╝ ╚══════╝
251
- █▀▀ █ █ ▄▀█ █ █▀
252
- ██▄ ▀▄▀ █▀█ █▄▄ ▄█`;
253
-
254
- const smallLogo = `ARIZE
255
- EVALS`;
246
+ ▄▀█ █▀▄ █ ▀█ █▀▀ ▄▀█ ▀▄▀
247
+ █▀█ █▀▄ █ █▄ ██▄ █▀█ ▄▀▄`;
248
+
249
+ const smallLogo = `ARIZE AX`;
256
250
 
257
251
  // Tag every URL the app opens with utm_source=npmevals (idempotent). Applied
258
252
  // centrally in openUrlInBrowser so all opened links (the agent install links)
@@ -285,31 +279,30 @@ function openUrlInBrowser(rawUrl) {
285
279
  });
286
280
  }
287
281
 
288
- // Header with hot pink to dark blue gradient
282
+ // Header the brand mark in flat brand magenta
289
283
  function Header() {
290
284
  const terminalWidth = process.stdout.columns || 80;
291
285
 
292
286
  let logo;
293
- if (terminalWidth >= 45) {
287
+ if (terminalWidth >= 68) {
294
288
  logo = largeLogo;
295
- } else if (terminalWidth >= 35) {
289
+ } else if (terminalWidth >= 30) {
296
290
  logo = mediumLogo;
297
291
  } else {
298
292
  logo = smallLogo;
299
293
  }
300
294
 
301
295
  return e(Box, { flexDirection: 'column', marginBottom: 1 },
302
- e(Gradient, { colors: ['#FF008C', '#FF1493', '#8B5CF6', '#1E3A8A'] },
303
- e(Text, null, logo)
304
- ),
305
- e(Text, { color: 'gray', italic: true }, 'Evals and Observability for Agentic AI')
296
+ e(Text, { color: BRAND_MARK }, logo),
297
+ e(Text, { color: 'gray', italic: true }, 'Observability and Evals for Agentic AI')
306
298
  );
307
299
  }
308
300
 
309
301
  // Character-by-character shimmer component
310
302
  function ShimmerText({ text, shimmerPos }) {
311
- const baseColor = '#FF1493';
312
- const shimmerColors = ['#FF5AA7', '#FF85C0', '#FFB8D9', '#FFE0EE', '#FFB8D9', '#FF85C0', '#FF5AA7'];
303
+ const baseColor = BRAND_ACCENT;
304
+ // Pink 300 / 200 / 100 off the brand ramp, peaking at white.
305
+ const shimmerColors = ['#FF6BBA', '#FFB5D6', '#FEEDF3', '#FFFFFF', '#FEEDF3', '#FFB5D6', '#FF6BBA'];
313
306
  const shimmerWidth = shimmerColors.length;
314
307
 
315
308
  const chars = text.split('').map((char, i) => {
@@ -326,19 +319,22 @@ function ShimmerText({ text, shimmerPos }) {
326
319
  return e(Box, null, ...chars);
327
320
  }
328
321
 
329
- // Menu item component - single line, hot pink selected with character shimmer
322
+ // Menu item component - single line, brand pink selected with character shimmer
330
323
  function MenuItem({ name, subtext, isSelected, shimmerPos }) {
324
+ // subtext is optional: the detected-agent items are just the agent's name.
325
+ const tail = subtext ? [e(Text, { color: 'gray', key: 'sub' }, ' — ' + subtext)] : [];
326
+
331
327
  if (isSelected) {
332
328
  return e(Box, null,
333
- e(Text, { bold: true, color: '#FF1493' }, '❯ '),
329
+ e(Text, { bold: true, color: BRAND_ACCENT }, '❯ '),
334
330
  e(ShimmerText, { text: name, shimmerPos }),
335
- e(Text, { color: 'gray' }, ' — ' + subtext)
331
+ ...tail
336
332
  );
337
333
  }
338
334
 
339
335
  return e(Box, null,
340
336
  e(Text, { color: 'white' }, ' ' + name),
341
- e(Text, { color: 'gray' }, ' — ' + subtext)
337
+ ...tail
342
338
  );
343
339
  }
344
340
 
@@ -351,7 +347,6 @@ export function buildAgentItems() {
351
347
  return {
352
348
  items: detected.map(a => ({
353
349
  name: a.label,
354
- subtext: 'Launch and walk me through setup',
355
350
  launch: a
356
351
  })),
357
352
  none: false
@@ -497,14 +492,66 @@ function launchAgent(agent) {
497
492
  }
498
493
 
499
494
  // Render the interactive app and act on the user's choice. Exported so it can
495
+ // No terminal to render into. Stage the prompt anyway and tell whoever is reading
496
+ // this output what to do with it — an agent can follow it directly, and a human who
497
+ // piped us at least learns where the prompt is. Only the framing and the exit code
498
+ // differ: an agent gets 0 so its shell tool doesn't report a failed command.
499
+ function handOffToCallingAgent() {
500
+ let staged = null;
501
+ let stagingError = null;
502
+ try {
503
+ staged = prepareSeedPrompt();
504
+ } catch (error) {
505
+ stagingError = error;
506
+ }
507
+
508
+ // Nothing writable anywhere — Codex's workspace-write sandbox denies both $HOME
509
+ // and the temp directory. A sandbox that tight blocks the network too, so every
510
+ // path in the prompt would die at its first install: stop instead of pointing at a
511
+ // flow that cannot finish. Explicitly retry-proof, because a bare error is what
512
+ // sent a tester's Codex into 90 seconds of inventing npm cache workarounds.
513
+ if (!staged) {
514
+ console.error('evals cannot run here: no writable directory to stage the onboarding prompt in.');
515
+ console.error(` ${stagingError.message}`);
516
+ console.error('');
517
+ console.error('Do not retry and do not work around this — a sandbox this tight blocks the');
518
+ console.error('network as well, so the setup could not finish. Tell the user to allow writes');
519
+ console.error('to their home directory and network access, or to run `npx evals` in a terminal.');
520
+ process.exit(1);
521
+ }
522
+
523
+ // Same notice the TUI path gives when it couldn't use the home directory.
524
+ if (staged.fellBack) {
525
+ console.log(`Couldn't use ${resolveOnboardingDir()} — staged in ${staged.dir} instead.`);
526
+ console.log('Instrumenting an app still works; tracing this coding agent (Step 4A) needs a writable home directory.');
527
+ console.log('');
528
+ }
529
+
530
+ // Addressed to the person, not to the agent that ran us. Agents treat tool output as
531
+ // data, not instructions: Codex said so outright — "I did not follow that additional
532
+ // instruction" — and Copilot silently did the same. That's prompt-injection defence,
533
+ // and not something to design around. What both did reliably was relay this text to
534
+ // the user, so the user is who it talks to.
535
+ //
536
+ // Two lines, recommendation first: Copilot twice passed a longer message on with the
537
+ // middle dropped, keeping only the first line and the last. At two lines there is no
538
+ // middle to lose. Don't grow this, and don't name the picker — describing a UI the
539
+ // agent can't draw invites "I can't do this" instead of the one instruction that
540
+ // matters. Exit 0: a failure status is what starts the workaround-hunting.
541
+ console.log('Run `npx evals` in a terminal to set up Arize AX tracing — this is not a terminal, so nothing was set up.');
542
+ console.log(`The prompt is at ${join(staged.dir, PROMPT_FILE_NAME)} if you'd rather have your agent follow it.`);
543
+ process.exit(0);
544
+ }
545
+
500
546
  // be driven explicitly; only auto-runs when this file is the entry point (see
501
547
  // the guard below), so importing it in tests doesn't launch the TUI.
502
548
  export async function main() {
503
- // Ink needs an interactive terminal.
549
+ // Ink needs an interactive terminal — but erroring out is the wrong answer when the
550
+ // caller is a coding agent that ran `npx evals` as a shell command, which is how
551
+ // testers keep reaching us. Stage the prompt and tell the user where to go instead.
504
552
  if (!process.stdin.isTTY || !process.stdout.isTTY) {
505
- console.error('Error: This command requires an interactive terminal.');
506
- console.error('Please run `npx evals` from your terminal (not from a script or non-interactive environment).');
507
- process.exit(1);
553
+ handOffToCallingAgent();
554
+ return;
508
555
  }
509
556
 
510
557
  // Handle uncaught errors
@@ -229,7 +229,7 @@ If the user picks an unsupported pairing, explain the supported options and ask
229
229
 
230
230
  Only for option 3. This traces the **agent harness**, not an app: every session the user runs, in every project on this machine. It edits files under their home directory, nothing in the current repo. When done, go to Step 8 — Steps 5 to 7 are app-only.
231
231
 
232
- Installer harness names: `claude`, `codex`, `cursor`, `copilot`, `gemini`, `kiro`, `opencode`, `omp` — note Cursor is `cursor`, not `cursor-agent`. Default to the agent you are running inside: state which you are and confirm, rather than asking.
232
+ Installer harness names: `claude`, `codex`, `cursor`, `copilot`, `antigravity`, `gemini`, `kiro`, `opencode`, `omp` — note Cursor is `cursor`, not `cursor-agent`, and Antigravity is `antigravity`, not `agy`. Default to the agent you are running inside: state which you are and confirm, rather than asking.
233
233
 
234
234
  Per-agent setup, including the Claude Code and Cursor marketplace-plugin routes, is at `https://arize.com/docs/ax/integrations/platforms/<agent>/<agent>-tracing` (e.g. `.../claude-code/claude-code-tracing`) — the source of truth if anything below fails.
235
235
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "evals",
3
- "version": "2.6.0",
3
+ "version": "2.7.0",
4
4
  "description": "Arize AX onboarding — instrument your app with tracing via your coding agent",
5
5
  "type": "module",
6
6
  "main": "cli.js",
@@ -16,7 +16,6 @@
16
16
  },
17
17
  "dependencies": {
18
18
  "ink": "^6.0.0",
19
- "ink-gradient": "^3.0.0",
20
19
  "react": "^19.0.0"
21
20
  },
22
21
  "bin": {
package/start.ps1 CHANGED
@@ -54,11 +54,11 @@ if (-not $env:ARIZE_SKIP_NPX -and (Get-Command npx -ErrorAction SilentlyContinue
54
54
 
55
55
  # Supported agents: id -> label, install URL, and whether the REPL is seeded with `-i`.
56
56
  $Agents = [ordered]@{
57
- 'claude' = @{ Label = 'Claude Code'; Install = 'https://docs.claude.com/en/docs/claude-code'; Flag = $null }
58
- 'codex' = @{ Label = 'OpenAI Codex'; Install = 'https://developers.openai.com/codex/cli'; Flag = $null }
59
- 'cursor-agent' = @{ Label = 'Cursor'; Install = 'https://docs.cursor.com/en/cli/overview'; Flag = $null }
60
- 'copilot' = @{ Label = 'GitHub Copilot'; Install = 'https://github.com/features/copilot/cli'; Flag = '-i' }
61
- 'gemini' = @{ Label = 'Gemini CLI'; Install = 'https://github.com/google-gemini/gemini-cli'; Flag = '-i' }
57
+ 'claude' = @{ Label = 'Claude Code'; Install = 'https://docs.claude.com/en/docs/claude-code'; Flag = $null }
58
+ 'codex' = @{ Label = 'OpenAI Codex'; Install = 'https://developers.openai.com/codex/cli'; Flag = $null }
59
+ 'cursor-agent' = @{ Label = 'Cursor'; Install = 'https://docs.cursor.com/en/cli/overview'; Flag = $null }
60
+ 'copilot' = @{ Label = 'GitHub Copilot'; Install = 'https://github.com/features/copilot/cli'; Flag = '-i' }
61
+ 'agy' = @{ Label = 'Antigravity CLI'; Install = 'https://antigravity.google/docs/cli/getting-started'; Flag = '-i' }
62
62
  }
63
63
 
64
64
  function Test-Agent([string]$id) {
@@ -102,14 +102,21 @@ function Resolve-Agent {
102
102
  # --- Welcome ---
103
103
  Write-Host ""
104
104
  Write-Host "Arize AX" -ForegroundColor Magenta -NoNewline
105
- Write-Host " - Evals & Observability for Agentic AI" -ForegroundColor DarkGray
105
+ Write-Host " - Observability and Evals for Agentic AI" -ForegroundColor DarkGray
106
106
  Write-Host ""
107
107
  Write-Host "Let's get you tracing. I'll launch your coding agent with a guided prompt that"
108
108
  Write-Host "walks you through signup, instrumenting your app, and seeing your first traces."
109
109
  Write-Host ""
110
110
 
111
- $chosen = Resolve-Agent
112
- if (-not $chosen) { exit 1 }
111
+ # No terminal on stdout? Then there is no picker to draw and nothing to launch, which
112
+ # is how testers keep reaching us: they type this command as a prompt and their coding
113
+ # agent runs it. Stage the prompt anyway and point the user at a terminal at the end.
114
+ if ([Console]::IsOutputRedirected) {
115
+ $chosen = $null
116
+ } else {
117
+ $chosen = Resolve-Agent
118
+ if (-not $chosen) { exit 1 }
119
+ }
113
120
 
114
121
  # A directory, not a bare temp file: Step 4A looks for the offline bundle *beside*
115
122
  # the prompt, so the prompt needs a directory of its own.
@@ -236,6 +243,13 @@ try {
236
243
  # what scopes the work. Keep this wording in step with cli.js and start.sh.
237
244
  $seed = "Read the file '$promptFile' and follow it to set up Arize AX tracing, walking me through each step and asking me questions as needed."
238
245
 
246
+ if (-not $chosen) {
247
+ # Addressed to the person, two lines, recommendation first - see the note in cli.js.
248
+ Write-Host "Re-run this in a terminal to set up Arize AX tracing - this is not a terminal, so nothing was set up."
249
+ Write-Host "The prompt is at $promptFile if you'd rather have your agent follow it."
250
+ exit 0
251
+ }
252
+
239
253
  Write-Host ("Launching {0}..." -f $Agents[$chosen].Label)
240
254
  Write-Host ""
241
255
 
package/start.sh CHANGED
@@ -49,14 +49,14 @@ fi
49
49
 
50
50
  # Supported agents: id | display label | argv to start the REPL seeded with a prompt.
51
51
  # The seed prompt is appended as the final argument at launch.
52
- AGENT_IDS=(claude codex cursor-agent copilot gemini)
52
+ AGENT_IDS=(claude codex cursor-agent copilot agy)
53
53
  agent_label() {
54
54
  case "$1" in
55
55
  claude) echo "Claude Code" ;;
56
56
  codex) echo "OpenAI Codex" ;;
57
57
  cursor-agent) echo "Cursor" ;;
58
58
  copilot) echo "GitHub Copilot" ;;
59
- gemini) echo "Gemini CLI" ;;
59
+ agy) echo "Antigravity CLI" ;;
60
60
  *) echo "$1" ;;
61
61
  esac
62
62
  }
@@ -66,7 +66,7 @@ agent_install_url() {
66
66
  codex) echo "https://developers.openai.com/codex/cli" ;;
67
67
  cursor-agent) echo "https://docs.cursor.com/en/cli/overview" ;;
68
68
  copilot) echo "https://github.com/features/copilot/cli" ;;
69
- gemini) echo "https://github.com/google-gemini/gemini-cli" ;;
69
+ agy) echo "https://antigravity.google/docs/cli/getting-started" ;;
70
70
  esac
71
71
  }
72
72
 
@@ -77,7 +77,7 @@ while [[ $# -gt 0 ]]; do
77
77
  --agent) AGENT="${2:-}"; shift 2 ;;
78
78
  --agent=*) AGENT="${1#*=}"; shift ;;
79
79
  -h|--help)
80
- echo "Usage: start.sh [--agent <claude|codex|cursor-agent|copilot|gemini>]"
80
+ echo "Usage: start.sh [--agent <claude|codex|cursor-agent|copilot|agy>]"
81
81
  exit 0 ;;
82
82
  *) echo "Unknown argument: $1" >&2; exit 1 ;;
83
83
  esac
@@ -85,11 +85,11 @@ done
85
85
 
86
86
  # --- Welcome ---
87
87
  if [ -t 1 ] && [ "${TERM:-}" != "dumb" ]; then
88
- _pink=$'\033[1;38;2;255;0;140m'; _dim=$'\033[2m'; _reset=$'\033[0m'
88
+ _pink=$'\033[1;38;2;236;32;136m'; _dim=$'\033[2m'; _reset=$'\033[0m'
89
89
  else
90
90
  _pink=""; _dim=""; _reset=""
91
91
  fi
92
- printf '\n%sArize AX%s %s— Evals & Observability for Agentic AI%s\n\n' "$_pink" "$_reset" "$_dim" "$_reset"
92
+ printf '\n%sArize AX%s %s— Observability and Evals for Agentic AI%s\n\n' "$_pink" "$_reset" "$_dim" "$_reset"
93
93
  printf "Let's get you tracing. I'll launch your coding agent with a guided prompt that\nwalks you through signup, instrumenting your app, and seeing your first traces.\n\n"
94
94
 
95
95
  # Detect installed agents (PATH lookup only — never executes them).
@@ -148,7 +148,14 @@ choose_agent() {
148
148
  done
149
149
  }
150
150
 
151
- CHOSEN="$(choose_agent)" || exit 1
151
+ # No terminal on stdout? Then there is no picker to draw and nothing to launch, which
152
+ # is how testers keep reaching us: they type this command as a prompt and their coding
153
+ # agent runs it. Stage the prompt anyway and point the user at a terminal at the end.
154
+ if [[ ! -t 1 ]]; then
155
+ CHOSEN=""
156
+ else
157
+ CHOSEN="$(choose_agent)" || exit 1
158
+ fi
152
159
 
153
160
  # A directory, not a bare temp file: Step 4A looks for the offline bundle *beside*
154
161
  # the prompt, so the prompt needs a directory of its own.
@@ -267,6 +274,13 @@ fi
267
274
  # what scopes the work. Keep this wording in step with cli.js and start.ps1.
268
275
  SEED="Read the file '$PROMPT_FILE' and follow it to set up Arize AX tracing, walking me through each step and asking me questions as needed."
269
276
 
277
+ if [[ -z "$CHOSEN" ]]; then
278
+ # Addressed to the person, two lines, recommendation first — see the note in cli.js.
279
+ echo "Re-run this in a terminal to set up Arize AX tracing — this is not a terminal, so nothing was set up."
280
+ echo "The prompt is at $PROMPT_FILE if you'd rather have your agent follow it."
281
+ exit 0
282
+ fi
283
+
270
284
  echo "Launching $(agent_label "$CHOSEN")…"
271
285
  echo
272
286
 
@@ -276,7 +290,7 @@ echo
276
290
  # the agent replaces this shell, so signals and the exit code reach it directly.
277
291
  run_agent() {
278
292
  case "$CHOSEN" in
279
- copilot|gemini) exec "$CHOSEN" -i "$SEED" ;;
293
+ copilot|agy) exec "$CHOSEN" -i "$SEED" ;;
280
294
  *) exec "$CHOSEN" "$SEED" ;;
281
295
  esac
282
296
  }
package/vendor/MANIFEST CHANGED
@@ -1,6 +1,6 @@
1
1
  a9cede65f98d3415b13e1c6a437d0fdee27286bfff0186dd72bb65d9869b7864 LICENSE-coding-harness-tracing
2
2
  62f22742b58a1a33014a2b6b706588a8d7e2a88ae7bd1a6ebe8c992928483775 certifi-2026.7.22-py3-none-any.whl
3
- c41daa85c05f38eabd63fd0c7a2c021ffc0ecb7483485f7dd1b8a637f983b778 coding_harness_tracing-0.1.0-py3-none-any.whl
3
+ e8b1f9519ddf75de49fe5334e9df38e6f76d169fd34be2322e678cce9ecf01e0 coding_harness_tracing-0.1.0-py3-none-any.whl
4
4
  aca14e09ca99c253d2a142e2d5c5c38c8c7cf90840d3cb10b241c29929871fa4 harness-install.bat
5
5
  a7ba18a98280e236b20ab4cb9f8a4006068b454586a2af50bf23fb0dbe70583d harness-install.sh
6
6
  b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61 python_dotenv-1.2.1-py3-none-any.whl
@@ -5,7 +5,7 @@
5
5
  "source": "git",
6
6
  "wheel": "coding_harness_tracing-0.1.0-py3-none-any.whl",
7
7
  "wheelVersion": "0.1.0",
8
- "wheelSha256": "c41daa85c05f38eabd63fd0c7a2c021ffc0ecb7483485f7dd1b8a637f983b778",
8
+ "wheelSha256": "e8b1f9519ddf75de49fe5334e9df38e6f76d169fd34be2322e678cce9ecf01e0",
9
9
  "files": [
10
10
  "LICENSE-coding-harness-tracing",
11
11
  "MANIFEST",