evals 2.5.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/start.ps1 CHANGED
@@ -32,18 +32,33 @@ $VendorUrl = if ($env:ARIZE_VENDOR_URL) { $env:ARIZE_VENDOR_URL } else { 'https:
32
32
  # Prefer the richer, bundled-prompt `npx evals` experience when Node is present.
33
33
  # This script is the no-npm fallback; if npx exists, hand off to it.
34
34
  # Set $env:ARIZE_SKIP_NPX=1 to force this shell path even when npx is available.
35
+ #
36
+ # Only hand off on Node 20+, which is what the Ink UI needs (see bin.js). Handing
37
+ # an older Node to npx would swap a working flow for a hard failure — this script
38
+ # needs no Node at all, so stay here instead. Keep the floor in step with bin.js.
35
39
  if (-not $env:ARIZE_SKIP_NPX -and (Get-Command npx -ErrorAction SilentlyContinue)) {
36
- npx --yes evals
37
- exit $LASTEXITCODE
40
+ $nodeMajor = 0
41
+ $nodeVersion = $null
42
+ if (Get-Command node -ErrorAction SilentlyContinue) {
43
+ $nodeVersion = (& node --version 2>$null)
44
+ if ($nodeVersion -match '^v?(\d+)') { $nodeMajor = [int]$Matches[1] }
45
+ }
46
+ if ($nodeMajor -ge 20) {
47
+ npx --yes evals
48
+ exit $LASTEXITCODE
49
+ }
50
+ $shown = if ($nodeVersion) { $nodeVersion } else { 'not found' }
51
+ Write-Host "Node $shown is too old for the npx UI — continuing without it."
52
+ Write-Host ""
38
53
  }
39
54
 
40
55
  # Supported agents: id -> label, install URL, and whether the REPL is seeded with `-i`.
41
56
  $Agents = [ordered]@{
42
- 'claude' = @{ Label = 'Claude Code'; Install = 'https://docs.claude.com/en/docs/claude-code'; Flag = $null }
43
- 'codex' = @{ Label = 'OpenAI Codex'; Install = 'https://developers.openai.com/codex/cli'; Flag = $null }
44
- 'cursor-agent' = @{ Label = 'Cursor'; Install = 'https://docs.cursor.com/en/cli/overview'; Flag = $null }
45
- 'copilot' = @{ Label = 'GitHub Copilot'; Install = 'https://github.com/features/copilot/cli'; Flag = '-i' }
46
- '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' }
47
62
  }
48
63
 
49
64
  function Test-Agent([string]$id) {
@@ -87,80 +102,167 @@ function Resolve-Agent {
87
102
  # --- Welcome ---
88
103
  Write-Host ""
89
104
  Write-Host "Arize AX" -ForegroundColor Magenta -NoNewline
90
- Write-Host " - Evals & Observability for Agentic AI" -ForegroundColor DarkGray
105
+ Write-Host " - Observability and Evals for Agentic AI" -ForegroundColor DarkGray
91
106
  Write-Host ""
92
107
  Write-Host "Let's get you tracing. I'll launch your coding agent with a guided prompt that"
93
108
  Write-Host "walks you through signup, instrumenting your app, and seeing your first traces."
94
109
  Write-Host ""
95
110
 
96
- $chosen = Resolve-Agent
97
- 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
+ }
98
120
 
99
121
  # A directory, not a bare temp file: Step 4A looks for the offline bundle *beside*
100
122
  # the prompt, so the prompt needs a directory of its own.
101
- $promptDir = Join-Path ([System.IO.Path]::GetTempPath()) ("arize-onboarding-" + [System.Guid]::NewGuid().ToString('N').Substring(0, 8))
102
- New-Item -ItemType Directory -Path $promptDir -Force | Out-Null
103
- $promptFile = Join-Path $promptDir 'onboarding-prompt.md'
104
- try {
105
- Write-Host "Fetching the onboarding prompt..."
106
- try {
107
- Invoke-RestMethod -Uri $PromptUrl -OutFile $promptFile
108
- } catch {
109
- Write-Host "Failed to download the onboarding prompt from $PromptUrl" -ForegroundColor Red
110
- Write-Host "Check your connection and try again."
111
- exit 1
123
+ #
124
+ # ~/.arize/onboarding, not a temp path: the agent is asked to read a file outside
125
+ # its workspace, and a named path is an approval a human can grant with confidence.
126
+ # Sits beside Step 4A's own ~/.arize/harness install, which we must never touch.
127
+ #
128
+ # GetFolderPath('UserProfile') rather than $HOME: on Windows PowerShell 5.1 $HOME
129
+ # comes from HOMEDRIVE+HOMEPATH, which for domain users can point at a redirected
130
+ # network share that is slow or offline. This returns USERPROFILE on Windows and
131
+ # $HOME under PowerShell Core on macOS/Linux one expression for both.
132
+ function Clear-BundleDir($dir) {
133
+ # Delete only what we stage, by name. Wheel filenames carry a version we can't
134
+ # know, so those go by extension, non-recursively, in this directory only.
135
+ Get-ChildItem -LiteralPath $dir -File -Filter '*.whl' -ErrorAction SilentlyContinue |
136
+ Remove-Item -Force -ErrorAction SilentlyContinue
137
+ foreach ($name in @('harness-install.sh', 'harness-install.bat', 'LICENSE-coding-harness-tracing', 'MANIFEST')) {
138
+ Remove-Item -LiteralPath (Join-Path $dir $name) -Force -ErrorAction SilentlyContinue
112
139
  }
140
+ # No -Recurse anywhere: a non-empty directory fails here rather than taking
141
+ # something we didn't put there with it, and Remove-Item's habit of recursing
142
+ # through a directory junction can't bite us.
143
+ Remove-Item -LiteralPath $dir -Force -ErrorAction SilentlyContinue
144
+ return -not (Test-Path -LiteralPath $dir)
145
+ }
113
146
 
114
- # Fetch the bundled tracing harness so Step 4A can install it without piping a
115
- # downloaded script into a shell the thing auto-approval permission
116
- # classifiers refuse. `npx evals` ships these files; this path pulls them from
117
- # the CDN, using vendor/MANIFEST because a launcher cannot glob a CDN and must
118
- # not hardcode versioned wheel names.
119
- #
120
- # Best-effort throughout. Any failure leaves no arize-offline directory and the
121
- # prompt takes its documented network path instead. Staged under a temp name and
122
- # renamed, so the directory Step 4A keys off only ever appears complete.
123
- Write-Host "Fetching the tracing harness..."
124
- $staging = Join-Path $promptDir '.staging'
125
- try {
126
- New-Item -ItemType Directory -Path $staging -Force | Out-Null
127
- $manifestPath = Join-Path $staging 'MANIFEST'
128
- Invoke-RestMethod -Uri "$VendorUrl/MANIFEST" -OutFile $manifestPath
129
-
130
- foreach ($line in Get-Content $manifestPath) {
131
- if (-not $line.Trim()) { continue }
132
- # MANIFEST is `shasum -a 256` format: "<sha256> <filename>".
133
- $parts = $line -split '\s+', 2
134
- $expected = $parts[0]
135
- $name = $parts[1].Trim()
136
- $dest = Join-Path $staging $name
137
- Invoke-RestMethod -Uri "$VendorUrl/$name" -OutFile $dest
138
- $actual = (Get-FileHash -Path $dest -Algorithm SHA256).Hash.ToLower()
139
- if ($actual -ne $expected.ToLower()) {
140
- throw "checksum mismatch for $name"
141
- }
142
- }
147
+ # -LiteralPath throughout: a home path containing [ or ] is a real wildcard
148
+ # footgun for the non-literal forms. Keep this list in step with cli.js
149
+ # OFFLINE_FILES and start.sh.
150
+ function Clear-PromptDir($dir) {
151
+ if (-not (Test-Path -LiteralPath $dir)) { return $true }
152
+ foreach ($sub in Get-ChildItem -LiteralPath $dir -Directory -Force -ErrorAction SilentlyContinue) {
153
+ $ours = ($sub.Name -eq 'arize-offline') -or $sub.Name.StartsWith('.staging')
154
+ if (-not $ours) { return $false }
155
+ if (-not (Clear-BundleDir $sub.FullName)) { return $false }
156
+ }
157
+ foreach ($name in @('onboarding-prompt.md', 'harness.env')) {
158
+ Remove-Item -LiteralPath (Join-Path $dir $name) -Force -ErrorAction SilentlyContinue
159
+ }
160
+ # Anything left is not ours.
161
+ return -not (Get-ChildItem -LiteralPath $dir -Force -ErrorAction SilentlyContinue)
162
+ }
143
163
 
144
- Move-Item -Path $staging -Destination (Join-Path $promptDir 'arize-offline')
164
+ $candidate = if ($env:ARIZE_ONBOARDING_DIR) {
165
+ $env:ARIZE_ONBOARDING_DIR
166
+ } else {
167
+ $profileDir = [Environment]::GetFolderPath('UserProfile')
168
+ if (-not $profileDir) { $profileDir = $HOME }
169
+ if ($profileDir) { Join-Path (Join-Path $profileDir '.arize') 'onboarding' } else { $null }
170
+ }
171
+
172
+ # Try the work and degrade, rather than probing for writability — a probe races
173
+ # and can't see a full disk. Covers a read-only home, a directory owned by another
174
+ # user, an offline redirected profile, and a file in there we refuse to delete.
175
+ $promptDir = $null
176
+ if ($candidate -and (Clear-PromptDir $candidate)) {
177
+ try {
178
+ New-Item -ItemType Directory -Path $candidate -Force -ErrorAction Stop | Out-Null
179
+ $promptDir = $candidate
145
180
  } catch {
146
- Remove-Item $staging -Recurse -Force -ErrorAction SilentlyContinue
147
- Write-Host " (not available — Step 4A will download the installer instead)"
181
+ $promptDir = $null
148
182
  }
183
+ }
184
+ if (-not $promptDir) {
185
+ $promptDir = Join-Path ([System.IO.Path]::GetTempPath()) ("arize-onboarding-" + [System.Guid]::NewGuid().ToString('N').Substring(0, 8))
186
+ New-Item -ItemType Directory -Path $promptDir -Force | Out-Null
187
+ if ($candidate) {
188
+ Write-Host "Couldn't use $candidate — staging in $promptDir instead."
189
+ Write-Host "Instrumenting an app still works; tracing this coding agent (Step 4A) needs a writable home directory."
190
+ }
191
+ }
192
+ $promptFile = Join-Path $promptDir 'onboarding-prompt.md'
149
193
 
150
- $seed = "Read the file $promptFile and follow it to set up Arize AX tracing in this project, walking me through each step and asking me questions as needed."
194
+ Write-Host "Fetching the onboarding prompt..."
195
+ try {
196
+ Invoke-RestMethod -Uri $PromptUrl -OutFile $promptFile
197
+ } catch {
198
+ Write-Host "Failed to download the onboarding prompt from $PromptUrl" -ForegroundColor Red
199
+ Write-Host "Check your connection and try again."
200
+ exit 1
201
+ }
151
202
 
152
- Write-Host ("Launching {0}..." -f $Agents[$chosen].Label)
153
- Write-Host ""
203
+ # Fetch the bundled tracing harness so Step 4A can install it without piping a
204
+ # downloaded script into a shell — the thing auto-approval permission
205
+ # classifiers refuse. `npx evals` ships these files; this path pulls them from
206
+ # the CDN, using vendor/MANIFEST because a launcher cannot glob a CDN and must
207
+ # not hardcode versioned wheel names.
208
+ #
209
+ # Best-effort throughout. Any failure leaves no arize-offline directory and the
210
+ # prompt takes its documented network path instead. Staged under a temp name and
211
+ # renamed, so the directory Step 4A keys off only ever appears complete.
212
+ Write-Host "Fetching the tracing harness..."
213
+ $staging = Join-Path $promptDir '.staging'
214
+ try {
215
+ New-Item -ItemType Directory -Path $staging -Force | Out-Null
216
+ $manifestPath = Join-Path $staging 'MANIFEST'
217
+ Invoke-RestMethod -Uri "$VendorUrl/MANIFEST" -OutFile $manifestPath
154
218
 
155
- # Launch interactive + seeded. No skip-permissions the agent's approval
156
- # model and the prompt's own approval gate must stay intact. External commands
157
- # attach to the console, so the agent gets a real terminal.
158
- $flag = $Agents[$chosen].Flag
159
- if ($flag) {
160
- & $chosen $flag $seed
161
- } else {
162
- & $chosen $seed
219
+ foreach ($line in Get-Content $manifestPath) {
220
+ if (-not $line.Trim()) { continue }
221
+ # MANIFEST is `shasum -a 256` format: "<sha256> <filename>".
222
+ $parts = $line -split '\s+', 2
223
+ $expected = $parts[0]
224
+ $name = $parts[1].Trim()
225
+ $dest = Join-Path $staging $name
226
+ Invoke-RestMethod -Uri "$VendorUrl/$name" -OutFile $dest
227
+ $actual = (Get-FileHash -Path $dest -Algorithm SHA256).Hash.ToLower()
228
+ if ($actual -ne $expected.ToLower()) {
229
+ throw "checksum mismatch for $name"
230
+ }
163
231
  }
164
- } finally {
165
- Remove-Item $promptDir -Recurse -Force -ErrorAction SilentlyContinue
232
+
233
+ Move-Item -LiteralPath $staging -Destination (Join-Path $promptDir 'arize-offline')
234
+ } catch {
235
+ Clear-BundleDir $staging | Out-Null
236
+ Write-Host " (not available — Step 4A will download the installer instead)"
237
+ }
238
+
239
+ # Single quotes around the path: the home directory is likelier to contain a space
240
+ # than the old temp path was, and single quotes survive the console handoff below
241
+ # where embedded double quotes would not.
242
+ # No "in this project": this may well be run from a home directory, and Step 4 is
243
+ # what scopes the work. Keep this wording in step with cli.js and start.sh.
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."
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
+
253
+ Write-Host ("Launching {0}..." -f $Agents[$chosen].Label)
254
+ Write-Host ""
255
+
256
+ # Launch interactive + seeded. No skip-permissions — the agent's approval
257
+ # model and the prompt's own approval gate must stay intact. External commands
258
+ # attach to the console, so the agent gets a real terminal.
259
+ #
260
+ # No try/finally around this any more: the staging directory persists so the agent
261
+ # can still reach the prompt in a session that outlives this script. It is cleared
262
+ # at the start of the next launch instead.
263
+ $flag = $Agents[$chosen].Flag
264
+ if ($flag) {
265
+ & $chosen $flag $seed
266
+ } else {
267
+ & $chosen $seed
166
268
  }
package/start.sh CHANGED
@@ -28,20 +28,35 @@ VENDOR_URL="${ARIZE_VENDOR_URL:-https://cdn.jsdelivr.net/npm/evals/vendor}"
28
28
  # Prefer the richer, bundled-prompt `npx evals` experience when Node is present.
29
29
  # This shell script is the no-npm fallback; if npx exists, hand off to it.
30
30
  # Set ARIZE_SKIP_NPX=1 to force this shell path even when npx is available.
31
+ #
32
+ # Only hand off on Node 20+, which is what the Ink UI needs (see bin.js). Handing
33
+ # an older Node to npx would swap a working flow for a hard failure — this script
34
+ # needs no Node at all, so stay here instead. Keep the floor in step with bin.js.
35
+ node_major() {
36
+ command -v node >/dev/null 2>&1 || return 1
37
+ v="$(node --version 2>/dev/null)" || return 1
38
+ v="${v#v}"
39
+ echo "${v%%.*}"
40
+ }
31
41
  if [ -z "${ARIZE_SKIP_NPX:-}" ] && command -v npx >/dev/null 2>&1; then
32
- exec npx --yes evals
42
+ major="$(node_major || echo 0)"
43
+ if [ "${major:-0}" -ge 20 ] 2>/dev/null; then
44
+ exec npx --yes evals
45
+ fi
46
+ echo "Node $(node --version 2>/dev/null || echo 'not found') is too old for the npx UI — continuing without it."
47
+ echo
33
48
  fi
34
49
 
35
50
  # Supported agents: id | display label | argv to start the REPL seeded with a prompt.
36
51
  # The seed prompt is appended as the final argument at launch.
37
- AGENT_IDS=(claude codex cursor-agent copilot gemini)
52
+ AGENT_IDS=(claude codex cursor-agent copilot agy)
38
53
  agent_label() {
39
54
  case "$1" in
40
55
  claude) echo "Claude Code" ;;
41
56
  codex) echo "OpenAI Codex" ;;
42
57
  cursor-agent) echo "Cursor" ;;
43
58
  copilot) echo "GitHub Copilot" ;;
44
- gemini) echo "Gemini CLI" ;;
59
+ agy) echo "Antigravity CLI" ;;
45
60
  *) echo "$1" ;;
46
61
  esac
47
62
  }
@@ -51,7 +66,7 @@ agent_install_url() {
51
66
  codex) echo "https://developers.openai.com/codex/cli" ;;
52
67
  cursor-agent) echo "https://docs.cursor.com/en/cli/overview" ;;
53
68
  copilot) echo "https://github.com/features/copilot/cli" ;;
54
- gemini) echo "https://github.com/google-gemini/gemini-cli" ;;
69
+ agy) echo "https://antigravity.google/docs/cli/getting-started" ;;
55
70
  esac
56
71
  }
57
72
 
@@ -62,7 +77,7 @@ while [[ $# -gt 0 ]]; do
62
77
  --agent) AGENT="${2:-}"; shift 2 ;;
63
78
  --agent=*) AGENT="${1#*=}"; shift ;;
64
79
  -h|--help)
65
- echo "Usage: start.sh [--agent <claude|codex|cursor-agent|copilot|gemini>]"
80
+ echo "Usage: start.sh [--agent <claude|codex|cursor-agent|copilot|agy>]"
66
81
  exit 0 ;;
67
82
  *) echo "Unknown argument: $1" >&2; exit 1 ;;
68
83
  esac
@@ -70,11 +85,11 @@ done
70
85
 
71
86
  # --- Welcome ---
72
87
  if [ -t 1 ] && [ "${TERM:-}" != "dumb" ]; then
73
- _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'
74
89
  else
75
90
  _pink=""; _dim=""; _reset=""
76
91
  fi
77
- 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"
78
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"
79
94
 
80
95
  # Detect installed agents (PATH lookup only — never executes them).
@@ -133,15 +148,72 @@ choose_agent() {
133
148
  done
134
149
  }
135
150
 
136
- 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
137
159
 
138
160
  # A directory, not a bare temp file: Step 4A looks for the offline bundle *beside*
139
- # the prompt, so the prompt needs a directory of its own rather than sharing
140
- # /tmp with everything else.
141
- PROMPT_DIR="$(mktemp -d "${TMPDIR:-/tmp}/arize-onboarding-XXXXXX")"
161
+ # the prompt, so the prompt needs a directory of its own.
162
+ #
163
+ # ~/.arize/onboarding, not a temp path: the agent is asked to read a file outside
164
+ # its workspace, and that approval is one a human can grant with confidence for a
165
+ # named path but not for /tmp/arize-onboarding-8fJ2x1. Sits beside Step 4A's own
166
+ # ~/.arize/harness install, which we must never touch.
167
+ #
168
+ # Cleared at launch and left in place afterwards — no EXIT trap — so the agent can
169
+ # still reach the prompt in a session that outlives this script, and so we can
170
+ # exec rather than waiting on a child just to clean up.
171
+ clear_bundle_dir() {
172
+ # Delete only what we stage, by name. Wheel filenames carry a version we can't
173
+ # know, so those go by extension, non-recursively, in this directory only.
174
+ rm -f "$1"/*.whl
175
+ rm -f "$1/harness-install.sh" "$1/harness-install.bat" \
176
+ "$1/LICENSE-coding-harness-tracing" "$1/MANIFEST"
177
+ # rmdir, never rm -r: a non-empty directory fails here instead of taking
178
+ # something we didn't put there down with it.
179
+ rmdir "$1" 2>/dev/null
180
+ }
181
+
182
+ # Never a recursive delete. Worst case on a bad path is unlinking a few names that
183
+ # don't exist. Keep this list in step with cli.js OFFLINE_FILES and start.ps1.
184
+ clear_prompt_dir() {
185
+ [ -d "$1" ] || return 0
186
+ for sub in "$1"/arize-offline "$1"/.staging*; do
187
+ [ -d "$sub" ] && clear_bundle_dir "$sub"
188
+ done
189
+ rm -f "$1/onboarding-prompt.md" "$1/harness.env"
190
+ # Anything left is not ours: bail out and let the caller fall back.
191
+ rmdir "$1" 2>/dev/null || { [ -z "$(ls -A "$1" 2>/dev/null)" ]; return $?; }
192
+ }
193
+
194
+ # $HOME unset (containers, cron, some CI) must degrade, never abort — hence
195
+ # ${HOME:-} and not ${HOME:?}. Same for a read-only home, a directory owned by a
196
+ # past `sudo`, or a full disk: try the work, fall back to a temp dir on failure.
197
+ PROMPT_DIR=""
198
+ if [ -n "${ARIZE_ONBOARDING_DIR:-}" ]; then
199
+ CANDIDATE="$ARIZE_ONBOARDING_DIR"
200
+ elif [ -n "${HOME:-}" ]; then
201
+ CANDIDATE="$HOME/.arize/onboarding"
202
+ else
203
+ CANDIDATE=""
204
+ fi
205
+
206
+ if [ -n "$CANDIDATE" ] && clear_prompt_dir "$CANDIDATE" \
207
+ && mkdir -p "$CANDIDATE" 2>/dev/null && chmod 700 "$CANDIDATE" 2>/dev/null; then
208
+ PROMPT_DIR="$CANDIDATE"
209
+ else
210
+ PROMPT_DIR="$(mktemp -d "${TMPDIR:-/tmp}/arize-onboarding-XXXXXX")"
211
+ if [ -n "$CANDIDATE" ]; then
212
+ echo "Couldn't use $CANDIDATE — staging in $PROMPT_DIR instead."
213
+ echo "Instrumenting an app still works; tracing this coding agent (Step 4A) needs a writable home directory."
214
+ fi
215
+ fi
142
216
  PROMPT_FILE="$PROMPT_DIR/onboarding-prompt.md"
143
- cleanup() { rm -rf "$PROMPT_DIR"; }
144
- trap cleanup EXIT
145
217
 
146
218
  if command -v curl >/dev/null 2>&1; then
147
219
  fetch() { curl -fsSL "$1" -o "$2"; }
@@ -198,18 +270,28 @@ if ! stage_offline_bundle; then
198
270
  echo " (not available — Step 4A will download the installer instead)"
199
271
  fi
200
272
 
201
- SEED="Read the file $PROMPT_FILE and follow it to set up Arize AX tracing in this project, walking me through each step and asking me questions as needed."
273
+ # No "in this project": this may well be run from a home directory, and Step 4 is
274
+ # what scopes the work. Keep this wording in step with cli.js and start.ps1.
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."
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
202
283
 
203
284
  echo "Launching $(agent_label "$CHOSEN")…"
204
285
  echo
205
286
 
206
287
  # Launch interactive + seeded, on the real terminal. No skip-permissions —
207
288
  # the agent's approval model and the prompt's own approval gate must stay intact.
208
- # Run as a child (not exec) so the EXIT trap cleans up the temp prompt file.
289
+ # exec, now that the staging directory persists and there is no EXIT trap to run:
290
+ # the agent replaces this shell, so signals and the exit code reach it directly.
209
291
  run_agent() {
210
292
  case "$CHOSEN" in
211
- copilot|gemini) "$CHOSEN" -i "$SEED" ;;
212
- *) "$CHOSEN" "$SEED" ;;
293
+ copilot|agy) exec "$CHOSEN" -i "$SEED" ;;
294
+ *) exec "$CHOSEN" "$SEED" ;;
213
295
  esac
214
296
  }
215
297
 
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
- e17d86afa36365ddd451325b7b2ed3e35ba85801fb10e35401fded609095f550 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": "e17d86afa36365ddd451325b7b2ed3e35ba85801fb10e35401fded609095f550",
8
+ "wheelSha256": "e8b1f9519ddf75de49fe5334e9df38e6f76d169fd34be2322e678cce9ecf01e0",
9
9
  "files": [
10
10
  "LICENSE-coding-harness-tracing",
11
11
  "MANIFEST",