evals 2.3.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
 
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
  ```
@@ -23,7 +23,7 @@ Do not proceed until the user approves.
23
23
 
24
24
  ## Prerequisites
25
25
 
26
- The AX CLI must be **arize-ax-cli `0.28.0` or newer** (Step 1 installs the latest) and needs **Python 3.11+** — a hard requirement. If Python is missing, stop and have the user install it from https://www.python.org/downloads/ and re-run. **Node.js 18+ with npx** is optional but installs the Arize skills; without it, don't stop — continue and use the docs paths in Step 6 (the Vercel AI SDK v7 starter needs Node.js 22+).
26
+ The AX CLI must be **arize-ax-cli `0.29.0` or newer** (Step 1 installs the latest) and needs **Python 3.11+** — a hard requirement. If Python is missing, stop and have the user install it from https://www.python.org/downloads/ and re-run. **Node.js 18+ with npx** is optional but installs the Arize skills; without it, don't stop — continue and use the docs paths in Step 6 (the Vercel AI SDK v7 starter needs Node.js 22+).
27
27
 
28
28
  ## Step 1: Install or update the AX CLI and Arize skills
29
29
 
@@ -77,9 +77,11 @@ If a `default` profile exists but the probe failed, it's signed out or expired,
77
77
  - **No key anywhere** — sign up or sign in with browser OAuth:
78
78
 
79
79
  ```bash
80
- ax profiles create default --auth-method oauth
80
+ ax profiles create default --auth-method oauth --utm-params "utm_source=npmevals&utm_medium=cli&utm_campaign=prompt-first-onboarding"
81
81
  ```
82
82
 
83
+ The `--utm-params` flag tags a new sign-up with onboarding attribution. It's already included on the three browser OAuth commands that take it — the two `ax profiles create --auth-method oauth` calls and the `ax auth login` fallback. Pass those verbatim; don't drop it, change the values, or add the flag to the api-key `profiles create` or any other `ax` command.
84
+
83
85
  Always pass the positional profile name `default`. Without it, the CLI prompts `profile name [default]:`, receives EOF from an agent-run command, and exits with `Goodbye!` without creating a profile.
84
86
 
85
87
  The rest of this step applies only to the **browser OAuth** branch.
@@ -105,7 +107,7 @@ Did you just sign up for a new account with email and password?
105
107
  **If the user says yes (new email/password signup):** the localhost callback will never fire and the command will wait forever, so this is the one time you break the "keep it alive" rule. Once they confirm they've clicked the validation link and their account exists, terminate the waiting OAuth command (send Ctrl-C / kill that process), then re-run it:
106
108
 
107
109
  ```bash
108
- ax profiles create default --auth-method oauth
110
+ ax profiles create default --auth-method oauth --utm-params "utm_source=npmevals&utm_medium=cli&utm_campaign=prompt-first-onboarding"
109
111
  ```
110
112
 
111
113
  The second run is now a plain sign-in for the validated account. Its callback lands normally, so handle it with all the standard rules below — keep it alive and wait for it to exit on its own.
@@ -121,7 +123,7 @@ ax spaces list --limit 1 --output json
121
123
  If the probe succeeds, continue. If the default OAuth profile already existed and the probe returns an authentication error, the profile is signed out or expired — run the fallback:
122
124
 
123
125
  ```bash
124
- ax auth login
126
+ ax auth login --utm-params "utm_source=npmevals&utm_medium=cli&utm_campaign=prompt-first-onboarding"
125
127
  ```
126
128
 
127
129
  Handle `ax auth login` with the same rules: keep its callback server alive, wait for it to exit or print a success line, then rerun the probe. Do not run `ax auth login` immediately after creating an OAuth profile; the profile creation already performed login.
@@ -142,7 +144,21 @@ If `ARIZE_SPACE_ID` is already set (environment or `.env` / `.env.local`), use i
142
144
 
143
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.
144
146
 
145
- ## 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.
146
162
 
147
163
  Inspect the current folder to decide whether an app already exists. Do not change files during inspection. Look for:
148
164
 
@@ -154,7 +170,7 @@ Inspect the current folder to decide whether an app already exists. Do not chang
154
170
 
155
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).
156
172
 
157
- Then branch on what you found:
173
+ Then branch on what you found — a folder with no app means option 2:
158
174
 
159
175
  ### If an app exists in the current folder
160
176
 
@@ -178,8 +194,138 @@ Go straight to the starter-app choice — do not ask whether to instrument the e
178
194
 
179
195
  If the user picks an unsupported pairing, explain the supported options and ask again.
180
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
+
181
325
  ## Step 5: Present the plan and get approval
182
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
+
183
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.
184
330
 
185
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.
@@ -343,6 +489,15 @@ You're set up. To go further:
343
489
  - AX CLI: https://arize.com/docs/api-clients/cli/overview
344
490
  ```
345
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
+
346
501
  ## Critical rules
347
502
 
348
503
  - Get the user's approval (Step 5) before creating AX resources, editing files, or installing dependencies.
@@ -351,5 +506,6 @@ You're set up. To go further:
351
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.
352
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).
353
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.
354
510
 
355
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.3.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")…"