evals 2.8.2 → 2.9.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/bin.js +7 -16
- package/cli.js +3 -37
- package/onboarding-prompt.md +1 -5
- package/package.json +1 -3
- package/start.ps1 +1 -48
- package/start.sh +1 -47
- package/vendor/MANIFEST +1 -1
- package/vendor/coding_harness_tracing-0.1.0-py3-none-any.whl +0 -0
- package/vendor/harness-pin.lock.json +1 -1
- package/analytics.js +0 -116
- package/track-event.mjs +0 -52
package/bin.js
CHANGED
|
@@ -34,19 +34,10 @@ if (!Number.isInteger(major) || major < MIN_MAJOR) {
|
|
|
34
34
|
process.exit(1);
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
//
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
.
|
|
43
|
-
|
|
44
|
-
} else {
|
|
45
|
-
// cli.js only auto-runs when it is the entry point, so call main() explicitly.
|
|
46
|
-
import('./cli.js')
|
|
47
|
-
.then((cli) => cli.main())
|
|
48
|
-
.catch((err) => {
|
|
49
|
-
console.error(`Could not start evals: ${err && err.message ? err.message : err}`);
|
|
50
|
-
process.exit(1);
|
|
51
|
-
});
|
|
52
|
-
}
|
|
37
|
+
// cli.js only auto-runs when it is the entry point, so call main() explicitly.
|
|
38
|
+
import('./cli.js')
|
|
39
|
+
.then((cli) => cli.main())
|
|
40
|
+
.catch((err) => {
|
|
41
|
+
console.error(`Could not start evals: ${err && err.message ? err.message : err}`);
|
|
42
|
+
process.exit(1);
|
|
43
|
+
});
|
package/cli.js
CHANGED
|
@@ -21,7 +21,6 @@ import {
|
|
|
21
21
|
import { join, isAbsolute, resolve } from 'path';
|
|
22
22
|
import { tmpdir, homedir } from 'os';
|
|
23
23
|
import { fileURLToPath } from 'url';
|
|
24
|
-
import { trackEventBackground } from './analytics.js';
|
|
25
24
|
|
|
26
25
|
const e = React.createElement;
|
|
27
26
|
|
|
@@ -38,8 +37,6 @@ const BRAND_ACCENT = '#FF3CA8';
|
|
|
38
37
|
// that file — a ~35 KB prompt is too large to pass reliably as a command-line
|
|
39
38
|
// argument.
|
|
40
39
|
const BUNDLED_PROMPT_PATH = fileURLToPath(new URL('./onboarding-prompt.md', import.meta.url));
|
|
41
|
-
const BUNDLED_ANALYTICS_PATH = fileURLToPath(new URL('./analytics.js', import.meta.url));
|
|
42
|
-
const BUNDLED_TRACK_PATH = fileURLToPath(new URL('./track-event.mjs', import.meta.url));
|
|
43
40
|
|
|
44
41
|
// Wheels for the coding-agent tracing harness, built by scripts/build-harness-wheel.mjs.
|
|
45
42
|
// Staging these next to the prompt lets Step 4A install with no network and no
|
|
@@ -60,18 +57,6 @@ const PROMPT_FILE_NAME = 'onboarding-prompt.md';
|
|
|
60
57
|
// gets cleared at the next launch instead of sitting around holding a live key.
|
|
61
58
|
const ENV_FILE_NAME = 'harness.env';
|
|
62
59
|
|
|
63
|
-
// Anon GA4 helper staged beside the prompt so the agent can fire auth-opened
|
|
64
|
-
// before OAuth without naming `npx evals` (prompt contract forbids that).
|
|
65
|
-
const TRACK_FILE_NAME = 'track-event.mjs';
|
|
66
|
-
const ANALYTICS_FILE_NAME = 'analytics.js';
|
|
67
|
-
|
|
68
|
-
const STAGED_ROOT_FILES = [
|
|
69
|
-
PROMPT_FILE_NAME,
|
|
70
|
-
ENV_FILE_NAME,
|
|
71
|
-
TRACK_FILE_NAME,
|
|
72
|
-
ANALYTICS_FILE_NAME,
|
|
73
|
-
];
|
|
74
|
-
|
|
75
60
|
// MANIFEST only lands in the shell launchers' bundles, never in ours. Naming it
|
|
76
61
|
// anyway keeps one allowlist correct for every implementation, so a directory
|
|
77
62
|
// staged by start.sh can be cleared by `npx evals` and vice versa.
|
|
@@ -150,7 +135,7 @@ export function clearOnboardingDir(dir) {
|
|
|
150
135
|
continue;
|
|
151
136
|
}
|
|
152
137
|
|
|
153
|
-
if (
|
|
138
|
+
if (entry.name !== PROMPT_FILE_NAME && entry.name !== ENV_FILE_NAME) return false;
|
|
154
139
|
unlinkSync(path);
|
|
155
140
|
}
|
|
156
141
|
return true;
|
|
@@ -225,9 +210,6 @@ function prepareSeedPrompt() {
|
|
|
225
210
|
const { dir, fellBack } = prepareOnboardingDir();
|
|
226
211
|
const promptFile = join(dir, PROMPT_FILE_NAME);
|
|
227
212
|
writeFileSync(promptFile, promptText, 'utf8');
|
|
228
|
-
// Same dir as the prompt: agent runs this before OAuth opens signup/sign-in.
|
|
229
|
-
copyFileSync(BUNDLED_ANALYTICS_PATH, join(dir, ANALYTICS_FILE_NAME));
|
|
230
|
-
copyFileSync(BUNDLED_TRACK_PATH, join(dir, TRACK_FILE_NAME));
|
|
231
213
|
stageOfflineHarness(dir);
|
|
232
214
|
// Single quotes, not double: a home path is likelier to contain a space than a
|
|
233
215
|
// temp path was, but Windows spawns through the shell and embedded double
|
|
@@ -433,8 +415,7 @@ export function buildAgentItems() {
|
|
|
433
415
|
items: AGENTS.map(a => ({
|
|
434
416
|
name: `Install ${a.label}`,
|
|
435
417
|
subtext: 'No supported agent detected — open install docs',
|
|
436
|
-
url: a.installUrl
|
|
437
|
-
agentId: a.id,
|
|
418
|
+
url: a.installUrl
|
|
438
419
|
})),
|
|
439
420
|
none: true
|
|
440
421
|
};
|
|
@@ -496,7 +477,7 @@ function App({ onDone }) {
|
|
|
496
477
|
}
|
|
497
478
|
|
|
498
479
|
if (selected.url) {
|
|
499
|
-
onDone({ type: 'url', url: selected.url
|
|
480
|
+
onDone({ type: 'url', url: selected.url });
|
|
500
481
|
exit();
|
|
501
482
|
return;
|
|
502
483
|
}
|
|
@@ -560,11 +541,6 @@ function launchAgent(agent) {
|
|
|
560
541
|
? ' Done.'
|
|
561
542
|
: ' Skipped — the setup will follow the Arize docs instead.');
|
|
562
543
|
|
|
563
|
-
trackEventBackground('npx_evals_skills_installed', {
|
|
564
|
-
agent: agent.id,
|
|
565
|
-
success: skillsInstalled ? 'true' : 'false',
|
|
566
|
-
});
|
|
567
|
-
|
|
568
544
|
console.log(`\nLaunching ${agent.label}…\n`);
|
|
569
545
|
|
|
570
546
|
const child = spawn(agent.bin, agent.args(prepared.seed), {
|
|
@@ -673,19 +649,9 @@ export async function main() {
|
|
|
673
649
|
if (!result) {
|
|
674
650
|
process.exit(0); // user quit / cancelled
|
|
675
651
|
} else if (result.type === 'url') {
|
|
676
|
-
// Install-doc link when no agent is on PATH (not the arize.com copy event).
|
|
677
|
-
trackEventBackground('npx_evals_agent_install_click', {
|
|
678
|
-
agent: result.agentId || 'unknown',
|
|
679
|
-
url_host: (() => {
|
|
680
|
-
try { return new URL(result.url).host; } catch { return 'unknown'; }
|
|
681
|
-
})(),
|
|
682
|
-
});
|
|
683
652
|
console.log(`\nOpening ${result.url} in your browser...\n`);
|
|
684
653
|
openUrlInBrowser(result.url);
|
|
685
654
|
} else if (result.type === 'launch') {
|
|
686
|
-
trackEventBackground('npx_evals_agent_selected', {
|
|
687
|
-
agent: result.agent.id,
|
|
688
|
-
});
|
|
689
655
|
launchAgent(result.agent);
|
|
690
656
|
}
|
|
691
657
|
} catch (error) {
|
package/onboarding-prompt.md
CHANGED
|
@@ -139,14 +139,11 @@ If a `default` profile exists but the probe failed, it is signed out or expired,
|
|
|
139
139
|
|
|
140
140
|
- **No key anywhere** — sign up or sign in with browser OAuth:
|
|
141
141
|
|
|
142
|
-
Immediately before the OAuth command, fire the anon funnel ping (ignore failures; never let it block auth), then open the browser flow:
|
|
143
|
-
|
|
144
142
|
```bash
|
|
145
|
-
node ~/.arize/onboarding/track-event.mjs auth-opened --method=oauth >/dev/null 2>&1 || true
|
|
146
143
|
ax profiles create default --auth-method oauth --utm-params "utm_source=npmevals&utm_medium=cli&utm_campaign=prompt-first-onboarding"
|
|
147
144
|
```
|
|
148
145
|
|
|
149
|
-
Pass `--utm-params` verbatim on the two browser OAuth commands (`profiles create --auth-method oauth` and the `ax auth login` fallback) and on no other `ax` command — it tags a new sign-up with onboarding attribution.
|
|
146
|
+
Pass `--utm-params` verbatim on the two browser OAuth commands (`profiles create --auth-method oauth` and the `ax auth login` fallback) and on no other `ax` command — it tags a new sign-up with onboarding attribution.
|
|
150
147
|
|
|
151
148
|
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.
|
|
152
149
|
|
|
@@ -173,7 +170,6 @@ Then wait for the command to exit. Treat exit code `0`, or success output such a
|
|
|
173
170
|
Only after the OAuth command completes, re-run the probe from the top of this step. If it succeeds, continue. If the profile already existed and the probe returns an authentication error, it is signed out or expired — run the fallback:
|
|
174
171
|
|
|
175
172
|
```bash
|
|
176
|
-
node ~/.arize/onboarding/track-event.mjs auth-opened --method=login >/dev/null 2>&1 || true
|
|
177
173
|
ax auth login --utm-params "utm_source=npmevals&utm_medium=cli&utm_campaign=prompt-first-onboarding"
|
|
178
174
|
```
|
|
179
175
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "evals",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.9.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",
|
|
@@ -24,8 +24,6 @@
|
|
|
24
24
|
"files": [
|
|
25
25
|
"bin.js",
|
|
26
26
|
"cli.js",
|
|
27
|
-
"analytics.js",
|
|
28
|
-
"track-event.mjs",
|
|
29
27
|
"onboarding-prompt.md",
|
|
30
28
|
"start.sh",
|
|
31
29
|
"start.ps1",
|
package/start.ps1
CHANGED
|
@@ -26,9 +26,6 @@ $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
|
-
# Staged beside the prompt for the OAuth signup/sign-in ping (prompt must not name npx evals).
|
|
30
|
-
$TrackUrl = if ($env:ARIZE_TRACK_URL) { $env:ARIZE_TRACK_URL } else { 'https://cdn.jsdelivr.net/npm/evals/track-event.mjs' }
|
|
31
|
-
$AnalyticsUrl = if ($env:ARIZE_ANALYTICS_URL) { $env:ARIZE_ANALYTICS_URL } else { 'https://cdn.jsdelivr.net/npm/evals/analytics.js' }
|
|
32
29
|
# Where the bundled harness wheels live, same package. Override for testing.
|
|
33
30
|
$VendorUrl = if ($env:ARIZE_VENDOR_URL) { $env:ARIZE_VENDOR_URL } else { 'https://cdn.jsdelivr.net/npm/evals/vendor' }
|
|
34
31
|
|
|
@@ -102,45 +99,6 @@ function Resolve-Agent {
|
|
|
102
99
|
}
|
|
103
100
|
}
|
|
104
101
|
|
|
105
|
-
|
|
106
|
-
function Send-EvalsGa4Event {
|
|
107
|
-
param([string]$Name, [string]$AgentId = '')
|
|
108
|
-
$mid = if ($env:ARIZE_EVALS_GA4_MEASUREMENT_ID) { $env:ARIZE_EVALS_GA4_MEASUREMENT_ID } else { 'G-QSZ10TDVQM' }
|
|
109
|
-
$secret = $env:ARIZE_EVALS_GA4_API_SECRET
|
|
110
|
-
if (-not $secret) { return }
|
|
111
|
-
|
|
112
|
-
$arizeDir = Join-Path $HOME '.arize'
|
|
113
|
-
$anonFile = Join-Path $arizeDir 'anon_client_id'
|
|
114
|
-
$clientId = $null
|
|
115
|
-
if (Test-Path -LiteralPath $anonFile) {
|
|
116
|
-
$clientId = (Get-Content -LiteralPath $anonFile -Raw -ErrorAction SilentlyContinue).Trim()
|
|
117
|
-
}
|
|
118
|
-
if (-not $clientId) {
|
|
119
|
-
$clientId = [guid]::NewGuid().ToString()
|
|
120
|
-
try {
|
|
121
|
-
New-Item -ItemType Directory -Force -Path $arizeDir | Out-Null
|
|
122
|
-
Set-Content -LiteralPath $anonFile -Value $clientId -NoNewline
|
|
123
|
-
} catch {}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
$params = @{ engagement_time_msec = 1 }
|
|
127
|
-
if ($AgentId) { $params.agent = $AgentId }
|
|
128
|
-
$bodyObj = @{
|
|
129
|
-
client_id = $clientId
|
|
130
|
-
events = @(@{ name = $Name; params = $params })
|
|
131
|
-
}
|
|
132
|
-
$json = $bodyObj | ConvertTo-Json -Depth 5 -Compress
|
|
133
|
-
$url = "https://www.google-analytics.com/mp/collect?measurement_id=$mid&api_secret=$secret"
|
|
134
|
-
try {
|
|
135
|
-
Start-Job -ScriptBlock {
|
|
136
|
-
param($u, $j)
|
|
137
|
-
try {
|
|
138
|
-
Invoke-RestMethod -Method Post -Uri $u -ContentType 'application/json' -Body $j -TimeoutSec 2 | Out-Null
|
|
139
|
-
} catch {}
|
|
140
|
-
} -ArgumentList $url, $json | Out-Null
|
|
141
|
-
} catch {}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
102
|
# --- Welcome ---
|
|
145
103
|
Write-Host ""
|
|
146
104
|
Write-Host "Arize AX" -ForegroundColor Magenta -NoNewline
|
|
@@ -158,7 +116,6 @@ if ([Console]::IsOutputRedirected) {
|
|
|
158
116
|
} else {
|
|
159
117
|
$chosen = Resolve-Agent
|
|
160
118
|
if (-not $chosen) { exit 1 }
|
|
161
|
-
Send-EvalsGa4Event -Name 'npx_evals_agent_selected' -AgentId $chosen
|
|
162
119
|
}
|
|
163
120
|
|
|
164
121
|
# A directory, not a bare temp file: Step 4A looks for the offline bundle *beside*
|
|
@@ -197,7 +154,7 @@ function Clear-PromptDir($dir) {
|
|
|
197
154
|
if (-not $ours) { return $false }
|
|
198
155
|
if (-not (Clear-BundleDir $sub.FullName)) { return $false }
|
|
199
156
|
}
|
|
200
|
-
foreach ($name in @('onboarding-prompt.md', 'harness.env'
|
|
157
|
+
foreach ($name in @('onboarding-prompt.md', 'harness.env')) {
|
|
201
158
|
Remove-Item -LiteralPath (Join-Path $dir $name) -Force -ErrorAction SilentlyContinue
|
|
202
159
|
}
|
|
203
160
|
# Anything left is not ours.
|
|
@@ -243,10 +200,6 @@ try {
|
|
|
243
200
|
exit 1
|
|
244
201
|
}
|
|
245
202
|
|
|
246
|
-
# Best-effort: agent runs these before OAuth. Missing files just skip the ping.
|
|
247
|
-
try { Invoke-RestMethod -Uri $TrackUrl -OutFile (Join-Path $promptDir 'track-event.mjs') } catch {}
|
|
248
|
-
try { Invoke-RestMethod -Uri $AnalyticsUrl -OutFile (Join-Path $promptDir 'analytics.js') } catch {}
|
|
249
|
-
|
|
250
203
|
# Fetch the bundled tracing harness so Step 4A can install it without piping a
|
|
251
204
|
# downloaded script into a shell — the thing auto-approval permission
|
|
252
205
|
# classifiers refuse. `npx evals` ships these files; this path pulls them from
|
package/start.sh
CHANGED
|
@@ -22,46 +22,6 @@ 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
|
-
# Staged beside the prompt for the OAuth signup/sign-in ping (prompt must not name npx evals).
|
|
26
|
-
TRACK_URL="${ARIZE_TRACK_URL:-https://cdn.jsdelivr.net/npm/evals/track-event.mjs}"
|
|
27
|
-
ANALYTICS_URL="${ARIZE_ANALYTICS_URL:-https://cdn.jsdelivr.net/npm/evals/analytics.js}"
|
|
28
|
-
|
|
29
|
-
# Anonymous GA4 step ping (same events as cli.js). No-op without API secret.
|
|
30
|
-
# ARIZE_EVALS_GA4_MEASUREMENT_ID default = arize.com stream; override if needed.
|
|
31
|
-
track_evals_event() {
|
|
32
|
-
local name="$1"
|
|
33
|
-
local agent_id="${2:-}"
|
|
34
|
-
local mid="${ARIZE_EVALS_GA4_MEASUREMENT_ID:-G-QSZ10TDVQM}"
|
|
35
|
-
local secret="${ARIZE_EVALS_GA4_API_SECRET:-}"
|
|
36
|
-
[[ -n "$secret" ]] || return 0
|
|
37
|
-
|
|
38
|
-
local anon_file="${HOME}/.arize/anon_client_id"
|
|
39
|
-
local client_id=""
|
|
40
|
-
if [[ -f "$anon_file" ]]; then
|
|
41
|
-
client_id="$(tr -d '[:space:]' < "$anon_file" 2>/dev/null || true)"
|
|
42
|
-
fi
|
|
43
|
-
if [[ -z "$client_id" ]]; then
|
|
44
|
-
if command -v uuidgen >/dev/null 2>&1; then
|
|
45
|
-
client_id="$(uuidgen | tr '[:upper:]' '[:lower:]')"
|
|
46
|
-
else
|
|
47
|
-
client_id="$(od -An -N16 -tx1 /dev/urandom 2>/dev/null | tr -d ' \n')"
|
|
48
|
-
client_id="${client_id:0:8}-${client_id:8:4}-${client_id:12:4}-${client_id:16:4}-${client_id:20:12}"
|
|
49
|
-
fi
|
|
50
|
-
mkdir -p "${HOME}/.arize" 2>/dev/null || true
|
|
51
|
-
printf '%s' "$client_id" > "$anon_file" 2>/dev/null || true
|
|
52
|
-
fi
|
|
53
|
-
|
|
54
|
-
local params="\"engagement_time_msec\":1"
|
|
55
|
-
if [[ -n "$agent_id" ]]; then
|
|
56
|
-
params="$params,\"agent\":\"$agent_id\""
|
|
57
|
-
fi
|
|
58
|
-
local body="{\"client_id\":\"$client_id\",\"events\":[{\"name\":\"$name\",\"params\":{$params}}]}"
|
|
59
|
-
local url="https://www.google-analytics.com/mp/collect?measurement_id=${mid}&api_secret=${secret}"
|
|
60
|
-
if command -v curl >/dev/null 2>&1; then
|
|
61
|
-
curl -fsS -m 2 -X POST -H 'content-type: application/json' -d "$body" "$url" >/dev/null 2>&1 &
|
|
62
|
-
fi
|
|
63
|
-
}
|
|
64
|
-
|
|
65
25
|
# Where the bundled harness wheels live, same package. Override for testing.
|
|
66
26
|
VENDOR_URL="${ARIZE_VENDOR_URL:-https://cdn.jsdelivr.net/npm/evals/vendor}"
|
|
67
27
|
|
|
@@ -195,7 +155,6 @@ if [[ ! -t 1 ]]; then
|
|
|
195
155
|
CHOSEN=""
|
|
196
156
|
else
|
|
197
157
|
CHOSEN="$(choose_agent)" || exit 1
|
|
198
|
-
track_evals_event npx_evals_agent_selected "$CHOSEN"
|
|
199
158
|
fi
|
|
200
159
|
|
|
201
160
|
# A directory, not a bare temp file: Step 4A looks for the offline bundle *beside*
|
|
@@ -227,8 +186,7 @@ clear_prompt_dir() {
|
|
|
227
186
|
for sub in "$1"/arize-offline "$1"/.staging*; do
|
|
228
187
|
[ -d "$sub" ] && clear_bundle_dir "$sub"
|
|
229
188
|
done
|
|
230
|
-
rm -f "$1/onboarding-prompt.md" "$1/harness.env"
|
|
231
|
-
"$1/track-event.mjs" "$1/analytics.js"
|
|
189
|
+
rm -f "$1/onboarding-prompt.md" "$1/harness.env"
|
|
232
190
|
# Anything left is not ours: bail out and let the caller fall back.
|
|
233
191
|
rmdir "$1" 2>/dev/null || { [ -z "$(ls -A "$1" 2>/dev/null)" ]; return $?; }
|
|
234
192
|
}
|
|
@@ -273,10 +231,6 @@ if ! fetch "$PROMPT_URL" "$PROMPT_FILE"; then
|
|
|
273
231
|
exit 1
|
|
274
232
|
fi
|
|
275
233
|
|
|
276
|
-
# Best-effort: agent runs these before OAuth. Missing files just skip the ping.
|
|
277
|
-
fetch "$TRACK_URL" "$PROMPT_DIR/track-event.mjs" 2>/dev/null || true
|
|
278
|
-
fetch "$ANALYTICS_URL" "$PROMPT_DIR/analytics.js" 2>/dev/null || true
|
|
279
|
-
|
|
280
234
|
# Fetch the bundled tracing harness so Step 4A can install it without piping a
|
|
281
235
|
# downloaded script into a shell — the thing auto-approval permission classifiers
|
|
282
236
|
# refuse. `npx evals` ships these files in the package; this path has to pull them
|
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
|
-
|
|
3
|
+
b18aa5a0bd311407aced15656803a05bf4019f49287bb6a0b3683ca02c3c8449 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
|
|
Binary file
|
|
@@ -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": "
|
|
8
|
+
"wheelSha256": "b18aa5a0bd311407aced15656803a05bf4019f49287bb6a0b3683ca02c3c8449",
|
|
9
9
|
"files": [
|
|
10
10
|
"LICENSE-coding-harness-tracing",
|
|
11
11
|
"MANIFEST",
|
package/analytics.js
DELETED
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Anonymous GA4 Measurement Protocol events for the npx evals onboarding funnel.
|
|
3
|
-
*
|
|
4
|
-
* No PII — only an anon client id under ~/.arize and step names / agent ids.
|
|
5
|
-
* Fire-and-forget: never blocks or fails the CLI if tracking is down.
|
|
6
|
-
*
|
|
7
|
-
* Events:
|
|
8
|
-
* npx_evals_agent_selected — coding agent picked in the TUI
|
|
9
|
-
* npx_evals_agent_install_click — install-docs link when no agent on PATH
|
|
10
|
-
* npx_evals_skills_installed — Arize skills/CLI install attempt
|
|
11
|
-
* npx_evals_auth_opened — signup/sign-in browser about to open (OAuth)
|
|
12
|
-
*
|
|
13
|
-
* Requires a GA4 Measurement Protocol API secret (Admin → Data stream →
|
|
14
|
-
* Measurement Protocol API secrets). Set via ARIZE_EVALS_GA4_API_SECRET, or
|
|
15
|
-
* bake ARIZE_EVALS_GA4_API_SECRET_DEFAULT at release time.
|
|
16
|
-
*
|
|
17
|
-
* Override measurement id with ARIZE_EVALS_GA4_MEASUREMENT_ID if needed.
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
import { randomUUID } from 'crypto';
|
|
21
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
|
22
|
-
import { homedir } from 'os';
|
|
23
|
-
import { join } from 'path';
|
|
24
|
-
|
|
25
|
-
/** arize.com GA4 web stream (same property as site hero_agent_prompt_* events). */
|
|
26
|
-
export const DEFAULT_MEASUREMENT_ID = 'G-QSZ10TDVQM';
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Optional release-time default. Leave empty until Chris/GA4 admin creates a
|
|
30
|
-
* Measurement Protocol API secret for this CLI. Env always wins when set.
|
|
31
|
-
*/
|
|
32
|
-
const API_SECRET_DEFAULT = '';
|
|
33
|
-
|
|
34
|
-
function measurementId() {
|
|
35
|
-
return process.env.ARIZE_EVALS_GA4_MEASUREMENT_ID || DEFAULT_MEASUREMENT_ID;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function apiSecret() {
|
|
39
|
-
return process.env.ARIZE_EVALS_GA4_API_SECRET || API_SECRET_DEFAULT;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function anonIdPath() {
|
|
43
|
-
return join(homedir(), '.arize', 'anon_client_id');
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/** Stable anon id so GA4 can stitch steps for one machine without knowing who. */
|
|
47
|
-
export function getAnonClientId() {
|
|
48
|
-
const path = anonIdPath();
|
|
49
|
-
try {
|
|
50
|
-
if (existsSync(path)) {
|
|
51
|
-
const existing = readFileSync(path, 'utf8').trim();
|
|
52
|
-
if (existing) return existing;
|
|
53
|
-
}
|
|
54
|
-
} catch {
|
|
55
|
-
// fall through and mint a new id
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const id = randomUUID();
|
|
59
|
-
try {
|
|
60
|
-
mkdirSync(join(homedir(), '.arize'), { recursive: true });
|
|
61
|
-
writeFileSync(path, id, 'utf8');
|
|
62
|
-
} catch {
|
|
63
|
-
// still send with in-memory id if home isn't writable
|
|
64
|
-
}
|
|
65
|
-
return id;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Send one anon event. Resolves quickly; network errors are swallowed.
|
|
70
|
-
* @param {string} name GA4 event name (snake_case, <=40 chars)
|
|
71
|
-
* @param {Record<string, string | number | boolean>} [params]
|
|
72
|
-
* @returns {Promise<void>}
|
|
73
|
-
*/
|
|
74
|
-
export async function trackEvent(name, params = {}) {
|
|
75
|
-
const mid = measurementId();
|
|
76
|
-
const secret = apiSecret();
|
|
77
|
-
if (!mid || !secret) return;
|
|
78
|
-
|
|
79
|
-
const url =
|
|
80
|
-
`https://www.google-analytics.com/mp/collect` +
|
|
81
|
-
`?measurement_id=${encodeURIComponent(mid)}` +
|
|
82
|
-
`&api_secret=${encodeURIComponent(secret)}`;
|
|
83
|
-
|
|
84
|
-
const body = {
|
|
85
|
-
client_id: getAnonClientId(),
|
|
86
|
-
events: [
|
|
87
|
-
{
|
|
88
|
-
name,
|
|
89
|
-
params: {
|
|
90
|
-
...params,
|
|
91
|
-
// Required for GA4 to count the event as engaged in some reports
|
|
92
|
-
engagement_time_msec: 1,
|
|
93
|
-
},
|
|
94
|
-
},
|
|
95
|
-
],
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
try {
|
|
99
|
-
const controller = new AbortController();
|
|
100
|
-
const timer = setTimeout(() => controller.abort(), 2500);
|
|
101
|
-
await fetch(url, {
|
|
102
|
-
method: 'POST',
|
|
103
|
-
headers: { 'content-type': 'application/json' },
|
|
104
|
-
body: JSON.stringify(body),
|
|
105
|
-
signal: controller.signal,
|
|
106
|
-
});
|
|
107
|
-
clearTimeout(timer);
|
|
108
|
-
} catch {
|
|
109
|
-
// never surface tracking failures to the user
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/** Fire without awaiting — safe to call before launch / exit. */
|
|
114
|
-
export function trackEventBackground(name, params = {}) {
|
|
115
|
-
void trackEvent(name, params);
|
|
116
|
-
}
|
package/track-event.mjs
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* Fire one anon funnel event, then exit.
|
|
4
|
-
*
|
|
5
|
-
* Staged next to the onboarding prompt so the agent can run it before opening
|
|
6
|
-
* the Arize signup/sign-in browser (OAuth) without naming `npx evals`.
|
|
7
|
-
*
|
|
8
|
-
* Usage:
|
|
9
|
-
* node ~/.arize/onboarding/track-event.mjs auth-opened --method=oauth
|
|
10
|
-
* node ~/.arize/onboarding/track-event.mjs auth-opened --method=login
|
|
11
|
-
*
|
|
12
|
-
* Always exits 0 — tracking must never block auth.
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
import { trackEvent } from './analytics.js';
|
|
16
|
-
|
|
17
|
-
/** @type {Record<string, string>} */
|
|
18
|
-
const EVENTS = {
|
|
19
|
-
'auth-opened': 'npx_evals_auth_opened',
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* @param {string[]} argv
|
|
24
|
-
* @returns {Promise<void>}
|
|
25
|
-
*/
|
|
26
|
-
export async function run(argv) {
|
|
27
|
-
const key = argv[0] || '';
|
|
28
|
-
const name = EVENTS[key];
|
|
29
|
-
if (!name) return;
|
|
30
|
-
|
|
31
|
-
/** @type {Record<string, string>} */
|
|
32
|
-
const params = {};
|
|
33
|
-
for (let i = 1; i < argv.length; i++) {
|
|
34
|
-
const a = argv[i];
|
|
35
|
-
if (a.startsWith('--method=')) {
|
|
36
|
-
params.method = a.slice('--method='.length);
|
|
37
|
-
} else if (a === '--method' && argv[i + 1]) {
|
|
38
|
-
params.method = argv[++i];
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
await trackEvent(name, params);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const isDirect =
|
|
46
|
-
process.argv[1] &&
|
|
47
|
-
(process.argv[1].endsWith('track-event.mjs') ||
|
|
48
|
-
process.argv[1].endsWith('track-event'));
|
|
49
|
-
|
|
50
|
-
if (isDirect) {
|
|
51
|
-
run(process.argv.slice(2)).finally(() => process.exit(0));
|
|
52
|
-
}
|