evals 2.4.0 → 2.5.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
@@ -1,6 +1,6 @@
1
1
  # evals
2
2
 
3
- Go from zero to your first [Arize AX](https://arize.com/docs/ax) traces in one command. `evals` launches your coding agent, seeded with a guided onboarding prompt that walks you through signing up, instrumenting your app, and confirming traces land.
3
+ Go from zero to your first [Arize AX](https://arize.com/docs/ax) traces in one command. `evals` launches your coding agent, seeded with a guided onboarding prompt that walks you through signing up, adding tracing, and confirming traces land — for your app, or for the coding agent itself.
4
4
 
5
5
  ## Quick start
6
6
 
@@ -32,7 +32,9 @@ When Node **is** present, these hand off to `npx evals` for the richer UI.
32
32
 
33
33
  1. Detects an installed coding agent (never executes it — just a PATH lookup).
34
34
  2. Launches the agent in your current directory, seeded with the bundled onboarding prompt ([`onboarding-prompt.md`](./onboarding-prompt.md)).
35
- 3. The agent walks you through: create/sign in to Arize AX → detect your stack → instrument it → verify your first traces.
35
+ 3. The agent walks you through: create/sign in to Arize AX → pick what to trace → instrument it → verify your first traces.
36
+
37
+ You can trace an app in the current folder, a starter app the agent creates, or **the coding agent itself** — so every session you run, in any project, shows up in Arize AX. Agent tracing is machine-wide and captures prompts and tool output by default, so the prompt asks for that explicitly and offers per-category opt-outs.
36
38
 
37
39
  The agent runs with its **normal permission model** — `evals` never passes skip-permissions, so you approve each step, and the prompt itself gates real changes on your confirmation.
38
40
 
@@ -46,23 +48,10 @@ The agent runs with its **normal permission model** — `evals` never passes ski
46
48
 
47
49
  The shell launchers also accept `--agent <id>`.
48
50
 
49
- ## Development
50
-
51
- ```bash
52
- npm install
53
- npm test # unit tests for the pure helpers (node --test)
54
- node cli.js # run the interactive CLI locally
55
- ```
56
-
57
- `npm test` covers the headless logic (URL tagging, agent detection, the agent catalog, and the picker). The interactive Ink flow and the live agent launch need a real terminal — verify those by running `node cli.js` in a terminal and picking an agent.
58
-
59
- ### Layout
60
-
61
- - `cli.js` — the interactive `npx evals` entry point (Ink UI). Exports its pure helpers for testing; only launches the UI when run directly.
62
- - `onboarding-prompt.md` — the bundled onboarding prompt (a copy of the Arize docs landing-page prompt).
63
- - `start.sh` / `start.ps1` — the no-npm launchers, served to `curl`/`irm` via jsDelivr.
64
- - `test/` — unit tests.
65
-
66
51
  ## About Arize
67
52
 
68
53
  [Arize AX](https://arize.com/docs/ax) is the AI engineering platform for tracing, evaluating, and observing LLM and agent applications. Learn more at [arize.com](https://arize.com).
54
+
55
+ ## Contributing
56
+
57
+ Development setup and the release process live in [CONTRIBUTING.md](https://github.com/Arize-ai/npm-evals/blob/main/CONTRIBUTING.md).
package/cli.js CHANGED
@@ -4,7 +4,18 @@ import React, { useState, useEffect } from 'react';
4
4
  import { render, Box, Text, useInput, useApp, Static } from 'ink';
5
5
  import Gradient from 'ink-gradient';
6
6
  import { exec, spawn } from 'child_process';
7
- import { existsSync, readFileSync, writeFileSync, mkdtempSync, realpathSync } from 'fs';
7
+ import {
8
+ existsSync,
9
+ readFileSync,
10
+ writeFileSync,
11
+ mkdtempSync,
12
+ realpathSync,
13
+ readdirSync,
14
+ copyFileSync,
15
+ chmodSync,
16
+ renameSync,
17
+ rmSync,
18
+ } from 'fs';
8
19
  import { join } from 'path';
9
20
  import { tmpdir } from 'os';
10
21
  import { fileURLToPath } from 'url';
@@ -18,6 +29,54 @@ const e = React.createElement;
18
29
  // TODO: sync this copy with the docs source (arize.com/docs) later.
19
30
  const BUNDLED_PROMPT_PATH = fileURLToPath(new URL('./onboarding-prompt.md', import.meta.url));
20
31
 
32
+ // Wheels for the coding-agent tracing harness, built by scripts/build-harness-wheel.mjs.
33
+ // Staging these next to the prompt lets Step 4A install with no network and no
34
+ // remote code execution — which is what keeps it working under permission
35
+ // classifiers that block piping a downloaded script into a shell.
36
+ const VENDOR_DIR = fileURLToPath(new URL('./vendor', import.meta.url));
37
+ const OFFLINE_DIR_NAME = 'arize-offline';
38
+
39
+ // Files the offline install needs. Absent or incomplete vendor/ means we stage
40
+ // nothing — the prompt keys off the directory existing, so a half-populated one
41
+ // would send the agent down the offline path with no wheel to install.
42
+ const OFFLINE_FILES = ['harness-install.sh', 'harness-install.bat', 'LICENSE-coding-harness-tracing'];
43
+
44
+ // Copy the bundled wheels next to the prompt. Returns the staged directory, or
45
+ // null when this package has no usable vendor/ (a git checkout that hasn't run
46
+ // the build). The shell launchers stage the same bundle themselves, fetching it
47
+ // from jsDelivr via vendor/MANIFEST.
48
+ //
49
+ // Never throws, and never leaves a partial directory behind. Both matter: the
50
+ // prompt decides which install path to take purely on whether this directory
51
+ // exists, so a half-copied one would send the agent offline with no wheel to
52
+ // install — and this is an optional enhancement, so a broken vendor/ must not
53
+ // take the launcher down with it. Either outcome degrades to the network path.
54
+ export function stageOfflineHarness(dir, vendorDir = VENDOR_DIR) {
55
+ if (!existsSync(vendorDir)) return null;
56
+
57
+ let staging;
58
+ try {
59
+ const wheels = readdirSync(vendorDir).filter((f) => f.endsWith('.whl'));
60
+ const hasHarnessWheel = wheels.some((f) => f.startsWith('coding_harness_tracing-'));
61
+ if (!hasHarnessWheel || !OFFLINE_FILES.every((f) => existsSync(join(vendorDir, f)))) return null;
62
+
63
+ // Build under a temp name and rename into place, so the directory the prompt
64
+ // looks for only ever appears complete. Same parent, so the rename is atomic.
65
+ staging = mkdtempSync(join(dir, '.staging-'));
66
+ for (const name of [...wheels, ...OFFLINE_FILES]) {
67
+ copyFileSync(join(vendorDir, name), join(staging, name));
68
+ }
69
+ chmodSync(join(staging, 'harness-install.sh'), 0o755);
70
+
71
+ const target = join(dir, OFFLINE_DIR_NAME);
72
+ renameSync(staging, target);
73
+ return target;
74
+ } catch {
75
+ if (staging) rmSync(staging, { recursive: true, force: true });
76
+ return null;
77
+ }
78
+ }
79
+
21
80
  // Write the bundled prompt to a temp file and return a short seed instruction
22
81
  // that points the agent at it.
23
82
  function prepareSeedPrompt() {
@@ -25,6 +84,7 @@ function prepareSeedPrompt() {
25
84
  const dir = mkdtempSync(join(tmpdir(), 'arize-onboarding-'));
26
85
  const promptFile = join(dir, 'onboarding-prompt.md');
27
86
  writeFileSync(promptFile, promptText, 'utf8');
87
+ stageOfflineHarness(dir);
28
88
  return `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.`;
29
89
  }
30
90
 
@@ -13,8 +13,8 @@ Welcome to Arize AX. I'll get you set up with tracing. Here's what I'll do:
13
13
 
14
14
  1. Install the AX CLI and Arize skills
15
15
  2. Create a free Arize AX account or sign you in
16
- 3. Instrument this project or a new app
17
- 4. Capture traces from your app
16
+ 3. Add tracing to your app, a new starter app, or this coding agent itself
17
+ 4. Capture your first traces
18
18
 
19
19
  Shall I proceed?
20
20
  ```
@@ -144,7 +144,21 @@ If `ARIZE_SPACE_ID` is already set (environment or `.env` / `.env.local`), use i
144
144
 
145
145
  Capture the space's **ID** (not its display name) for `ARIZE_SPACE_ID`. The `arize-otel` tracing config requires the space ID; a name will silently fail to route traces.
146
146
 
147
- ## Step 4: Inspect the folder and choose a path
147
+ ## Step 4: Choose what to trace
148
+
149
+ Ask what the user wants to trace before inspecting anything — the third option has nothing to do with what is in the current folder:
150
+
151
+ ```text
152
+ What would you like to trace?
153
+
154
+ 1. An app in this folder
155
+ 2. A new starter app I create for you
156
+ 3. This coding agent itself — every session you run, in any project
157
+
158
+ Which one?
159
+ ```
160
+
161
+ If they pick **3**, go to [Step 4A](#step-4a-trace-this-coding-agent) and skip the folder inspection entirely. For **1** or **2**, continue below.
148
162
 
149
163
  Inspect the current folder to decide whether an app already exists. Do not change files during inspection. Look for:
150
164
 
@@ -156,7 +170,7 @@ Inspect the current folder to decide whether an app already exists. Do not chang
156
170
 
157
171
  In a monorepo, check the git root to get oriented, but only instrument apps in or below the current working directory. If the project spans more than one language, instrument each one (route each through its own integration page in Step 6).
158
172
 
159
- Then branch on what you found:
173
+ Then branch on what you found — a folder with no app means option 2:
160
174
 
161
175
  ### If an app exists in the current folder
162
176
 
@@ -180,8 +194,138 @@ Go straight to the starter-app choice — do not ask whether to instrument the e
180
194
 
181
195
  If the user picks an unsupported pairing, explain the supported options and ask again.
182
196
 
197
+ ## Step 4A: Trace this coding agent
198
+
199
+ 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.
200
+
201
+ 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.
202
+
203
+ 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.
204
+
205
+ ### Get approval — this needs its own explicit yes
206
+
207
+ Wider scope than an app install, so disclose it and wait:
208
+
209
+ ```text
210
+ This traces <agent> itself. Three things first:
211
+
212
+ - It applies to EVERY session you run, in every project on this machine.
213
+ - Unless you say otherwise I'll turn on all three capture categories: your
214
+ prompts, what tools were asked to do (commands, file paths, URLs), and what
215
+ tools returned (file contents, command output).
216
+ - It writes to ~/.arize/harness and <agent>'s settings file. Nothing in this
217
+ project changes.
218
+
219
+ Want to skip any capture category — prompts, tool commands, or tool output?
220
+ Shall I go ahead?
221
+ ```
222
+
223
+ Do not proceed without a yes. Note which categories they accepted — you enable those explicitly below, and anything you leave out stays off.
224
+
225
+ ### Write the config file
226
+
227
+ The installer reads credentials from a dotenv file, keeping the API key out of the command line, shell history, and this chat. Write it outside the project so it cannot be committed:
228
+
229
+ ```bash
230
+ mkdir -p ~/.arize && : > ~/.arize/onboarding.env && chmod 600 ~/.arize/onboarding.env
231
+ ```
232
+
233
+ Add the Step 3 space ID as file contents, plus one `true` line per category the user **accepted**. Unattended installs capture nothing unless asked to, so a category you omit is off — omit the line for anything they declined:
234
+
235
+ ```dotenv
236
+ ARIZE_SPACE_ID=<space-id-from-step-3>
237
+ ARIZE_LOG_PROMPTS=true
238
+ ARIZE_LOG_TOOL_DETAILS=true
239
+ ARIZE_LOG_TOOL_CONTENT=true
240
+ ```
241
+
242
+ Do **not** set `ARIZE_PROJECT_NAME` — each harness defaults to its own project (`claude-code`, `codex`, …), which keeps two traced agents apart, and you read the real name back after installing. Then create the key into the same file, written atomically and never printed:
243
+
244
+ ```bash
245
+ ax api-keys create --name "Coding agent tracing" --env-file ~/.arize/onboarding.env
246
+ ```
247
+
248
+ **Skip that if `ARIZE_API_KEY` already existed in Step 2** — copy the existing value in without echoing it. At most one key, ever.
249
+
250
+ ### Install, then delete the file
251
+
252
+ If a directory named `arize-offline/` sits beside this prompt file, install from it — no download, no remote script, so it is faster and far less likely to be refused:
253
+
254
+ ```bash
255
+ # keep `< /dev/null`: an installer too old for --non-interactive then fails
256
+ # fast instead of hanging on a prompt you cannot answer
257
+ ARIZE_ENV_FILE=~/.arize/onboarding.env \
258
+ bash <prompt-dir>/arize-offline/harness-install.sh \
259
+ <harness> --wheel-dir <prompt-dir>/arize-offline --non-interactive < /dev/null
260
+ ```
261
+
262
+ Otherwise fetch it (the harness name must come first, before any flag):
263
+
264
+ ```bash
265
+ ARIZE_ENV_FILE=~/.arize/onboarding.env \
266
+ bash <(curl -fsSL https://raw.githubusercontent.com/Arize-ai/coding-harness-tracing/main/install.sh) \
267
+ <harness> --non-interactive < /dev/null
268
+ ```
269
+
270
+ Delete the env file only once the install has actually run — a retry needs it, and so does the user if they end up running the command:
271
+
272
+ ```bash
273
+ rm -f ~/.arize/onboarding.env
274
+ ```
275
+
276
+ On Windows, use `harness-install.bat` from the same directory — `cmd` cannot run the `.sh`:
277
+
278
+ ```powershell
279
+ $env:ARIZE_ENV_FILE = "$HOME\.arize\onboarding.env"
280
+ & <prompt-dir>\arize-offline\harness-install.bat <harness> --wheel-dir <prompt-dir>\arize-offline --non-interactive
281
+ ```
282
+
283
+ Without `arize-offline/`, use the install command from the agent's docs page with `$env:ARIZE_ENV_FILE` set first.
284
+
285
+ An `EOFError` or hang means the installer predates `--non-interactive`: have the user run it without that flag and without `< /dev/null`, answering its prompts. On any other failure, report what it printed and stop — never retry with a different backend or type the key into a prompt.
286
+
287
+ ### If your permission layer refuses to run it
288
+
289
+ Expected on the fetched command — auto-approval modes hold back piping a downloaded script into a shell. Retry **once** with the installer downloaded to a file first; if still refused, stop and do not hunt for a phrasing that slips through. Hand it over instead:
290
+
291
+ ```text
292
+ My permission settings won't let me run the installer. It creates
293
+ ~/.arize/harness and adds hooks to <harness>'s settings file. Either run it
294
+ yourself — prefix with ! so I see the output — or tell me to go ahead and
295
+ I'll retry.
296
+
297
+ <the command, one line>
298
+ ```
299
+
300
+ A go-ahead authorizes that one command, nothing wider. **Never** frame this as bypassing a safety check, and never suggest an approval flag on the agent. **Keep the env file** until they confirm — they need those credentials.
301
+
302
+ ### Verify before asking the user for anything
303
+
304
+ ```bash
305
+ ~/.arize/harness/install.sh status --json
306
+ ```
307
+
308
+ Exit `0` means configured **and** hooks wired up; `1` nothing configured; `2` configured but hooks missing (the `unregistered` list names which to re-install). Continue only on `0`. Take the project name for polling from `harnesses[].project_name` in the payload rather than guessing it. The payload holds no secrets.
309
+
310
+ ### Get the first traces
311
+
312
+ Hooks load at session start, so **this session will never emit traces**. Do not restart or kill yourself — that would end the setup. Use a second session so you stay alive to poll:
313
+
314
+ ```text
315
+ Tracing is installed. This session won't be traced — it started before the
316
+ hooks existed. So:
317
+
318
+ 1. Open a new terminal and start <agent> there.
319
+ 2. Ask it something small, like "list the files in this folder".
320
+ 3. Tell me when you have, and I'll check for traces.
321
+ ```
322
+
323
+ Then poll with the Step 7 command and counter, passing that project name and space ID, every ~15 seconds for up to ~3 minutes. On a non-zero count go to Step 8. On timeout say so plainly and give the likely causes: the new session started before the install finished, the agent was never asked to do anything, `ARIZE_TRACE_ENABLED` is `false` in the agent's settings, or the wrong space. Never fabricate trace results.
324
+
183
325
  ## Step 5: Present the plan and get approval
184
326
 
327
+ Steps 5 to 7 cover the app paths (options 1 and 2). If you took Step 4A, its own approval gate and verification replace them — go straight to Step 8.
328
+
185
329
  Before creating any remote resource, writing files, or installing dependencies, present one consolidated plan and wait for approval. This is the gate the intro refers to — nothing so far has modified the app or created AX resources.
186
330
 
187
331
  For an existing app, cover: detected language and framework, package manager, LLM provider or agent framework, any existing tracing to preserve, the env file that will be updated, the instrumentation packages and files that will change, whether a new AX user API key will be created or the existing `ARIZE_API_KEY` reused, and the project name that will be used.
@@ -345,6 +489,15 @@ You're set up. To go further:
345
489
  - AX CLI: https://arize.com/docs/api-clients/cli/overview
346
490
  ```
347
491
 
492
+ If you took Step 4A, add the controls that matter for agent tracing:
493
+
494
+ ```text
495
+ - Your agent's tracing page: https://arize.com/docs/ax/integrations/platforms/<agent>/<agent>-tracing
496
+ - Check it's still wired up: ~/.arize/harness/install.sh status
497
+ - Pause it: set ARIZE_TRACE_ENABLED=false in <agent>'s settings
498
+ - Remove it: ~/.arize/harness/install.sh uninstall <installer-name>
499
+ ```
500
+
348
501
  ## Critical rules
349
502
 
350
503
  - Get the user's approval (Step 5) before creating AX resources, editing files, or installing dependencies.
@@ -353,5 +506,6 @@ You're set up. To go further:
353
506
  - Create at most one AX API key: skip if `ARIZE_API_KEY` already exists (reuse it), otherwise a **single** `ax api-keys create --env-file <file>`. Git-ignore that file before creating the key; never create a second key.
354
507
  - Write the space **ID** (not its name) to `ARIZE_SPACE_ID`, or traces won't route; never create an AX project explicitly (it's made on first ingestion).
355
508
  - Initialize tracing before LLM clients are created, and flush/shut down the tracer before short-lived scripts exit. Vercel AI SDK v7 also needs Node.js 22+, `@ai-sdk/otel` registered, and `experimental_telemetry: { isEnabled: true }` per call.
509
+ - Tracing the coding agent (Step 4A) is machine-wide and captures prompts and tool output by default, so it needs its own explicit yes — never fold it into another approval. Run its installer with `--non-interactive` and `< /dev/null` so it can never sit waiting on a prompt, verify with `status --json` before claiming success, and never restart or kill the session you are running in.
356
510
 
357
511
  Docs: https://arize.com/docs/llms.txt
package/package.json CHANGED
@@ -1,13 +1,15 @@
1
1
  {
2
2
  "name": "evals",
3
- "version": "2.4.0",
3
+ "version": "2.5.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",
7
7
  "scripts": {
8
8
  "postinstall": "node -e \"console.log('Arize evals installed — run: npx evals')\"",
9
9
  "start": "node cli.js",
10
- "test": "node --test"
10
+ "test": "node --test",
11
+ "build:wheel": "node scripts/build-harness-wheel.mjs",
12
+ "prepack": "npm run build:wheel"
11
13
  },
12
14
  "dependencies": {
13
15
  "ink": "^6.0.0",
@@ -21,7 +23,8 @@
21
23
  "cli.js",
22
24
  "onboarding-prompt.md",
23
25
  "start.sh",
24
- "start.ps1"
26
+ "start.ps1",
27
+ "vendor/"
25
28
  ],
26
29
  "keywords": [
27
30
  "arize",
package/start.ps1 CHANGED
@@ -26,6 +26,8 @@ $ErrorActionPreference = 'Stop'
26
26
  # files over HTTP, so it's fetchable even though the source repo is private.
27
27
  # Override with $env:ARIZE_PROMPT_URL if needed.
28
28
  $PromptUrl = if ($env:ARIZE_PROMPT_URL) { $env:ARIZE_PROMPT_URL } else { 'https://cdn.jsdelivr.net/npm/evals/onboarding-prompt.md' }
29
+ # Where the bundled harness wheels live, same package. Override for testing.
30
+ $VendorUrl = if ($env:ARIZE_VENDOR_URL) { $env:ARIZE_VENDOR_URL } else { 'https://cdn.jsdelivr.net/npm/evals/vendor' }
29
31
 
30
32
  # Prefer the richer, bundled-prompt `npx evals` experience when Node is present.
31
33
  # This script is the no-npm fallback; if npx exists, hand off to it.
@@ -94,11 +96,11 @@ Write-Host ""
94
96
  $chosen = Resolve-Agent
95
97
  if (-not $chosen) { exit 1 }
96
98
 
97
- # Download the prompt to a temp file (rename the .tmp to .md rather than
98
- # leaving both behind).
99
- $tmp = New-TemporaryFile
100
- $promptFile = [System.IO.Path]::ChangeExtension($tmp.FullName, 'md')
101
- Rename-Item -Path $tmp.FullName -NewName (Split-Path $promptFile -Leaf)
99
+ # A directory, not a bare temp file: Step 4A looks for the offline bundle *beside*
100
+ # 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'
102
104
  try {
103
105
  Write-Host "Fetching the onboarding prompt..."
104
106
  try {
@@ -109,6 +111,42 @@ try {
109
111
  exit 1
110
112
  }
111
113
 
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
+ }
143
+
144
+ Move-Item -Path $staging -Destination (Join-Path $promptDir 'arize-offline')
145
+ } catch {
146
+ Remove-Item $staging -Recurse -Force -ErrorAction SilentlyContinue
147
+ Write-Host " (not available — Step 4A will download the installer instead)"
148
+ }
149
+
112
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."
113
151
 
114
152
  Write-Host ("Launching {0}..." -f $Agents[$chosen].Label)
@@ -124,5 +162,5 @@ try {
124
162
  & $chosen $seed
125
163
  }
126
164
  } finally {
127
- Remove-Item $promptFile -ErrorAction SilentlyContinue
165
+ Remove-Item $promptDir -Recurse -Force -ErrorAction SilentlyContinue
128
166
  }
package/start.sh CHANGED
@@ -22,6 +22,8 @@ set -euo pipefail
22
22
  # files over HTTP, so it's fetchable even though the source repo is private.
23
23
  # Override with ARIZE_PROMPT_URL if needed.
24
24
  PROMPT_URL="${ARIZE_PROMPT_URL:-https://cdn.jsdelivr.net/npm/evals/onboarding-prompt.md}"
25
+ # Where the bundled harness wheels live, same package. Override for testing.
26
+ VENDOR_URL="${ARIZE_VENDOR_URL:-https://cdn.jsdelivr.net/npm/evals/vendor}"
25
27
 
26
28
  # Prefer the richer, bundled-prompt `npx evals` experience when Node is present.
27
29
  # This shell script is the no-npm fallback; if npx exists, hand off to it.
@@ -133,29 +135,69 @@ choose_agent() {
133
135
 
134
136
  CHOSEN="$(choose_agent)" || exit 1
135
137
 
136
- # Download the prompt to a temp file. (mktemp templates must end in X's on
137
- # macOS, so add the .md extension afterwards.)
138
- PROMPT_FILE="$(mktemp "${TMPDIR:-/tmp}/arize-onboarding-XXXXXX")"
139
- mv "$PROMPT_FILE" "$PROMPT_FILE.md"
140
- PROMPT_FILE="$PROMPT_FILE.md"
141
- cleanup() { rm -f "$PROMPT_FILE"; }
138
+ # 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")"
142
+ PROMPT_FILE="$PROMPT_DIR/onboarding-prompt.md"
143
+ cleanup() { rm -rf "$PROMPT_DIR"; }
142
144
  trap cleanup EXIT
143
145
 
144
- echo "Fetching the onboarding prompt…"
145
- download_failed() {
146
- echo "Failed to download the onboarding prompt from $PROMPT_URL" >&2
147
- echo "Check your connection and try again." >&2
148
- exit 1
149
- }
150
146
  if command -v curl >/dev/null 2>&1; then
151
- curl -fsSL "$PROMPT_URL" -o "$PROMPT_FILE" || download_failed
147
+ fetch() { curl -fsSL "$1" -o "$2"; }
152
148
  elif command -v wget >/dev/null 2>&1; then
153
- wget -qO "$PROMPT_FILE" "$PROMPT_URL" || download_failed
149
+ fetch() { wget -qO "$2" "$1"; }
154
150
  else
155
151
  echo "Need curl or wget to download the prompt." >&2
156
152
  exit 1
157
153
  fi
158
154
 
155
+ echo "Fetching the onboarding prompt…"
156
+ if ! fetch "$PROMPT_URL" "$PROMPT_FILE"; then
157
+ echo "Failed to download the onboarding prompt from $PROMPT_URL" >&2
158
+ echo "Check your connection and try again." >&2
159
+ exit 1
160
+ fi
161
+
162
+ # Fetch the bundled tracing harness so Step 4A can install it without piping a
163
+ # downloaded script into a shell — the thing auto-approval permission classifiers
164
+ # refuse. `npx evals` ships these files in the package; this path has to pull them
165
+ # from the CDN, which is why the build writes vendor/MANIFEST: a launcher cannot
166
+ # glob a CDN and must not hardcode versioned wheel names.
167
+ #
168
+ # Entirely best-effort. Any failure leaves no arize-offline/ directory, and the
169
+ # prompt then takes its documented network path. Staged under a temp name and
170
+ # renamed, so the directory Step 4A keys off only ever appears complete.
171
+ stage_offline_bundle() {
172
+ local staging="$PROMPT_DIR/.staging" line file
173
+ mkdir -p "$staging" || return 1
174
+ fetch "$VENDOR_URL/MANIFEST" "$staging/MANIFEST" 2>/dev/null || return 1
175
+
176
+ while IFS= read -r line; do
177
+ file="${line#* }"
178
+ [ -n "$file" ] || continue
179
+ fetch "$VENDOR_URL/$file" "$staging/$file" 2>/dev/null || return 1
180
+ done < "$staging/MANIFEST"
181
+
182
+ # MANIFEST is standard `shasum -a 256` output, so the check is the standard
183
+ # tool. A truncated CDN response would otherwise surface as a confusing pip
184
+ # error much later. Skipped, not fatal, when neither tool exists.
185
+ if command -v shasum >/dev/null 2>&1; then
186
+ ( cd "$staging" && shasum -a 256 -c MANIFEST >/dev/null 2>&1 ) || return 1
187
+ elif command -v sha256sum >/dev/null 2>&1; then
188
+ ( cd "$staging" && sha256sum -c MANIFEST >/dev/null 2>&1 ) || return 1
189
+ fi
190
+
191
+ chmod +x "$staging/harness-install.sh" 2>/dev/null || true
192
+ mv "$staging" "$PROMPT_DIR/arize-offline"
193
+ }
194
+
195
+ echo "Fetching the tracing harness…"
196
+ if ! stage_offline_bundle; then
197
+ rm -rf "$PROMPT_DIR/.staging"
198
+ echo " (not available — Step 4A will download the installer instead)"
199
+ fi
200
+
159
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."
160
202
 
161
203
  echo "Launching $(agent_label "$CHOSEN")…"