pantheon-opencode 1.5.0-beta.2 → 1.5.0-beta.4
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/.pantheon/code-mode/manifest.json +21 -0
- package/CHANGELOG.md +835 -0
- package/README.md +103 -15
- package/README.pt-BR.md +57 -13
- package/package.json +8 -3
- package/plugin.json +1 -1
- package/pyproject.toml +57 -0
- package/scripts/code_mode_server.py +403 -42
- package/scripts/install/opencode.mjs +42 -0
- package/scripts/install/plugin.mjs +3 -33
- package/scripts/manifest-inventory.mjs +410 -0
- package/scripts/mcp_persistence_server.py +516 -163
- package/scripts/package-evidence.mjs +242 -0
- package/scripts/probe-pantheon-cost.mjs +10 -1
- package/scripts/release-beta-version.mjs +61 -60
- package/scripts/sync-tui.mjs +76 -54
- package/scripts/test-opencode-v1-v2-sandbox.sh +79 -161
- package/scripts/validation-policy.mjs +7 -7
- package/scripts/version-check.mjs +113 -108
- package/scripts/versioning.mjs +131 -88
- package/src/agents/zeus.md +2 -2
- package/src/mcp/code_mode_server.py +403 -42
- package/src/mcp/mcp_persistence_server.py +516 -163
- package/src/pantheon/background-job-board.ts +14 -0
- package/src/pantheon/compaction-handoff.ts +304 -0
- package/src/pantheon/cost-command.ts +62 -42
- package/src/pantheon/delegate-manager.ts +109 -12
- package/src/pantheon/native-probe.ts +234 -0
- package/src/pantheon/native-task-status.ts +139 -0
- package/src/pantheon/provider-capabilities.ts +221 -0
- package/src/pantheon/provider-stream-tracker.ts +182 -0
- package/src/pantheon/task-result-guard.ts +107 -0
- package/src/pantheon/token-opt.ts +18 -110
- package/src/pantheon/tool-ceiling.ts +159 -0
- package/src/pantheon/v2-events.ts +10 -1
- package/src/plugin.ts +19 -1
- package/src/plugins/tui/package-lock.json +2 -2
- package/src/plugins/tui/package.json +1 -1
|
@@ -13,10 +13,10 @@
|
|
|
13
13
|
# (config is regenerated for that version first).
|
|
14
14
|
# --prompts Prompt battery via `opencode run --format json` for every
|
|
15
15
|
# requested version (with --run vX) or both versions alone.
|
|
16
|
-
# --cost Offline
|
|
16
|
+
# --cost Offline pantheon_cost probe for the requested
|
|
17
17
|
# version (with --run vX) or both versions alone.
|
|
18
18
|
# The probe's synthetic checks run in explicit --fixture mode.
|
|
19
|
-
# --rehydrate Offline
|
|
19
|
+
# --rehydrate Offline context_rehydrate + context_session_summary
|
|
20
20
|
# probe for the requested version (with --run vX) or both.
|
|
21
21
|
# --reset Wipe the sandbox root.
|
|
22
22
|
# --help Usage.
|
|
@@ -30,11 +30,8 @@
|
|
|
30
30
|
# PANTHEON_SANDBOX_MODEL Model used by init/prompts
|
|
31
31
|
# (default: opencode-go/mimo-v2.5)
|
|
32
32
|
# PANTHEON_PROMPT_TIMEOUT Per-prompt timeout in seconds (default: 300)
|
|
33
|
-
#
|
|
34
|
-
#
|
|
35
|
-
#
|
|
36
|
-
# Exit codes: 0 = no real failures (AMBIENTAL issues do not fail the run),
|
|
37
|
-
# 1 = real FAIL (see prompts-report.md in the sandbox root),
|
|
33
|
+
# Exit codes: 0 = every required check returned explicit PASS,
|
|
34
|
+
# 1 = any failure or untested check (see reports in the sandbox root),
|
|
38
35
|
# 2 = usage error, 3 = sandbox not prepared.
|
|
39
36
|
set -euo pipefail
|
|
40
37
|
|
|
@@ -134,18 +131,14 @@ export PATH="$NPM_PREFIX/bin:$SANDBOX_VENV/bin:$PATH"
|
|
|
134
131
|
export npm_config_prefix="$NPM_PREFIX"
|
|
135
132
|
|
|
136
133
|
STATUS_FAIL=0
|
|
137
|
-
STATUS_AMBIENTAL=0
|
|
138
|
-
STATUS_NOT_TESTED=0
|
|
139
134
|
STATUS_PASS=0
|
|
140
|
-
MCP_AMBIENTAL_RE='needs authentication|unauthorized|authentication failure|api key|credentials|401|docker|econnrefused|enotfound|etimedout|econnreset|connection refused|rate.?limit|429|quota|overloaded|edgesout|npm err'
|
|
141
135
|
|
|
142
136
|
record_status() { # label status detail
|
|
143
137
|
local label="$1" status="$2" detail="$3"
|
|
144
138
|
case "$status" in
|
|
145
139
|
PASS) STATUS_PASS=$((STATUS_PASS + 1)) ;;
|
|
146
140
|
FAIL) STATUS_FAIL=$((STATUS_FAIL + 1)) ;;
|
|
147
|
-
|
|
148
|
-
NOT_TESTED) STATUS_NOT_TESTED=$((STATUS_NOT_TESTED + 1)) ;;
|
|
141
|
+
*) STATUS_FAIL=$((STATUS_FAIL + 1)); status="FAIL" ;;
|
|
149
142
|
esac
|
|
150
143
|
printf '%s: %s — %s\n' "$status" "$label" "$detail"
|
|
151
144
|
}
|
|
@@ -153,7 +146,7 @@ record_status() { # label status detail
|
|
|
153
146
|
check_binary() { # label binary
|
|
154
147
|
local label="$1" bin="$2" out rc=0
|
|
155
148
|
if ! command -v "$bin" >/dev/null 2>&1; then
|
|
156
|
-
record_status "$label" "
|
|
149
|
+
record_status "$label" "FAIL" "binary '$bin' is not installed in the sandbox prefix"
|
|
157
150
|
return 0
|
|
158
151
|
fi
|
|
159
152
|
set +e
|
|
@@ -162,8 +155,6 @@ check_binary() { # label binary
|
|
|
162
155
|
set -e
|
|
163
156
|
if [ "$rc" -eq 0 ]; then
|
|
164
157
|
record_status "$label" "PASS" "${out:-version command exited 0}"
|
|
165
|
-
elif printf '%s' "$out" | grep -Eiq "$MCP_AMBIENTAL_RE"; then
|
|
166
|
-
record_status "$label" "AMBIENTAL" "version check unavailable (exit $rc)"
|
|
167
158
|
else
|
|
168
159
|
record_status "$label" "FAIL" "version check exited $rc"
|
|
169
160
|
fi
|
|
@@ -172,11 +163,11 @@ check_binary() { # label binary
|
|
|
172
163
|
check_mcp() { # label binary project
|
|
173
164
|
local label="$1" bin="$2" project="$3" out connected_count rc=0
|
|
174
165
|
if ! command -v "$bin" >/dev/null 2>&1; then
|
|
175
|
-
record_status "$label MCP" "
|
|
166
|
+
record_status "$label MCP" "FAIL" "binary '$bin' is not installed in the sandbox prefix"
|
|
176
167
|
return 0
|
|
177
168
|
fi
|
|
178
169
|
if [ ! -d "$project" ]; then
|
|
179
|
-
record_status "$label MCP" "
|
|
170
|
+
record_status "$label MCP" "FAIL" "project directory is missing: $project"
|
|
180
171
|
return 0
|
|
181
172
|
fi
|
|
182
173
|
set +e
|
|
@@ -186,20 +177,13 @@ check_mcp() { # label binary project
|
|
|
186
177
|
out="$(printf '%s' "$out" | sed -E $'s/\x1B\\[[0-?]*[ -/]*[@-~]//g')"
|
|
187
178
|
printf '%s\n' "$out"
|
|
188
179
|
if [ "$rc" -ne 0 ]; then
|
|
189
|
-
|
|
190
|
-
record_status "$label MCP" "AMBIENTAL" "mcp list environmental failure (exit $rc)"
|
|
191
|
-
else
|
|
192
|
-
record_status "$label MCP" "FAIL" "mcp list exited $rc"
|
|
193
|
-
fi
|
|
180
|
+
record_status "$label MCP" "FAIL" "mcp list exited $rc"
|
|
194
181
|
return 0
|
|
195
182
|
fi
|
|
196
183
|
connected_count="$(printf '%s' "$out" | grep -Eic '(^|[^[:alnum:]_])connected([^[:alnum:]_]|$)')" || connected_count=0
|
|
197
184
|
if [ "$connected_count" -eq 5 ] \
|
|
198
|
-
&& ! printf '%s' "$out" | grep -Eiq 'failed|✘'
|
|
199
|
-
&& ! printf '%s' "$out" | grep -Eiq "$MCP_AMBIENTAL_RE"; then
|
|
185
|
+
&& ! printf '%s' "$out" | grep -Eiq 'failed|✘'; then
|
|
200
186
|
record_status "$label MCP" "PASS" "exactly 5 connected MCPs"
|
|
201
|
-
elif printf '%s' "$out" | grep -Eiq "$MCP_AMBIENTAL_RE"; then
|
|
202
|
-
record_status "$label MCP" "AMBIENTAL" "environmental MCP status; found $connected_count connected"
|
|
203
187
|
else
|
|
204
188
|
record_status "$label MCP" "FAIL" "expected exactly 5 connected MCPs; found $connected_count or failures reported"
|
|
205
189
|
fi
|
|
@@ -232,19 +216,17 @@ if command -v pantheon-opencode >/dev/null 2>&1; then
|
|
|
232
216
|
set -e
|
|
233
217
|
if [ "$DOCTOR_RC" -eq 0 ]; then
|
|
234
218
|
record_status "doctor" "PASS" "exit 0"
|
|
235
|
-
elif printf '%s' "$DOCTOR_OUTPUT" | grep -Eiq "$MCP_AMBIENTAL_RE"; then
|
|
236
|
-
record_status "doctor" "AMBIENTAL" "environmental doctor failure (exit $DOCTOR_RC)"
|
|
237
219
|
else
|
|
238
220
|
record_status "doctor" "FAIL" "doctor exited $DOCTOR_RC"
|
|
239
221
|
fi
|
|
240
222
|
else
|
|
241
|
-
record_status "doctor" "
|
|
223
|
+
record_status "doctor" "FAIL" "pantheon-opencode is not installed in the sandbox prefix"
|
|
242
224
|
fi
|
|
243
225
|
|
|
244
226
|
echo "--- Gate (b): pantheon://agents CONTENT check ---"
|
|
245
227
|
RESOURCES_SRV="$PANTHEON_GLOBAL/scripts/mcp_resources_server.py"
|
|
246
228
|
if [ ! -f "$RESOURCES_SRV" ]; then
|
|
247
|
-
record_status "pantheon://agents resource" "
|
|
229
|
+
record_status "pantheon://agents resource" "FAIL" "resources server not found at $RESOURCES_SRV"
|
|
248
230
|
else
|
|
249
231
|
set +e
|
|
250
232
|
AGENTS_CONTENT="$("$SANDBOX_VENV/bin/python" - "$RESOURCES_SRV" <<'PYEOF'
|
|
@@ -262,11 +244,7 @@ PYEOF
|
|
|
262
244
|
set -e
|
|
263
245
|
printf '%s\n' "$AGENTS_CONTENT" | head -8
|
|
264
246
|
if [ "$AGENTS_RC" -ne 0 ]; then
|
|
265
|
-
|
|
266
|
-
record_status "pantheon://agents resource" "AMBIENTAL" "resource probe environmental failure (exit $AGENTS_RC)"
|
|
267
|
-
else
|
|
268
|
-
record_status "pantheon://agents resource" "FAIL" "resource probe exited $AGENTS_RC"
|
|
269
|
-
fi
|
|
247
|
+
record_status "pantheon://agents resource" "FAIL" "resource probe exited $AGENTS_RC"
|
|
270
248
|
elif printf '%s\n' "$AGENTS_CONTENT" | grep -qi 'zeus' \
|
|
271
249
|
&& printf '%s\n' "$AGENTS_CONTENT" | grep -qi 'hermes'; then
|
|
272
250
|
record_status "pantheon://agents resource" "PASS" "pantheon://agents content includes zeus and hermes"
|
|
@@ -276,17 +254,13 @@ PYEOF
|
|
|
276
254
|
fi
|
|
277
255
|
echo ""
|
|
278
256
|
echo "=== VALIDATION COMPLETE ==="
|
|
279
|
-
if [ "$STATUS_FAIL" -gt 0 ]; then
|
|
257
|
+
if [ "$STATUS_FAIL" -gt 0 ] || [ "$STATUS_PASS" -eq 0 ]; then
|
|
280
258
|
FINAL_VERDICT="FAIL"
|
|
281
|
-
elif [ "$STATUS_NOT_TESTED" -gt 0 ]; then
|
|
282
|
-
FINAL_VERDICT="NOT_TESTED"
|
|
283
|
-
elif [ "$STATUS_AMBIENTAL" -gt 0 ]; then
|
|
284
|
-
FINAL_VERDICT="AMBIENTAL"
|
|
285
259
|
else
|
|
286
260
|
FINAL_VERDICT="PASS"
|
|
287
261
|
fi
|
|
288
262
|
printf 'Final verdict: %s\n' "$FINAL_VERDICT"
|
|
289
|
-
if [ "$FINAL_VERDICT"
|
|
263
|
+
if [ "$FINAL_VERDICT" != "PASS" ]; then
|
|
290
264
|
exit 1
|
|
291
265
|
fi
|
|
292
266
|
echo "Next: open the isolated TUI with: $SANDBOX_DIR/start-pantheon.sh"
|
|
@@ -316,11 +290,9 @@ install_binaries() {
|
|
|
316
290
|
npm install -g "$REPO_DIR/$tgz" || die "install of $tgz failed"
|
|
317
291
|
if ! git -C "$REPO_DIR" ls-files --error-unmatch -- "$tgz" >/dev/null 2>&1; then rm -f -- "$tgz"; fi
|
|
318
292
|
log "--- Installing OpenCode V1 ($OPENCODE_V1_SPEC) ---"
|
|
319
|
-
npm install -g "$OPENCODE_V1_SPEC"
|
|
320
|
-
|| warn "V1 binary install failed ($OPENCODE_V1_SPEC) — v1 prompts will be AMBIENTAL"
|
|
293
|
+
npm install -g "$OPENCODE_V1_SPEC" || die "install of $OPENCODE_V1_SPEC failed"
|
|
321
294
|
log "--- Installing OpenCode V2 ($OPENCODE_V2_SPEC) ---"
|
|
322
|
-
npm install -g "$OPENCODE_V2_SPEC"
|
|
323
|
-
|| warn "V2 binary install failed ($OPENCODE_V2_SPEC) — v2 prompts will be AMBIENTAL"
|
|
295
|
+
npm install -g "$OPENCODE_V2_SPEC" || die "install of $OPENCODE_V2_SPEC failed"
|
|
324
296
|
}
|
|
325
297
|
|
|
326
298
|
prepare_project() {
|
|
@@ -391,20 +363,14 @@ PYEOF
|
|
|
391
363
|
|
|
392
364
|
# ── Prompt battery ────────────────────────────────────────────────────────────
|
|
393
365
|
|
|
394
|
-
# Known environmental failure signatures (never fail the run).
|
|
395
|
-
AMBIENTAL_RE='bifrost|unauthorized|authentication failure|api key|credentials|401|docker|econnrefused|enotfound|etimedout|econnreset|connection refused|rate.?limit|429|quota|overloaded|edgesout|npm err'
|
|
396
|
-
MCP_AMBIENTAL_RE='needs authentication|unauthorized|authentication failure|api key|credentials|401|docker|econnrefused|enotfound|etimedout|econnreset|connection refused|rate.?limit|429|quota|overloaded|edgesout|npm err'
|
|
397
|
-
|
|
398
366
|
PROMPT_IDS=()
|
|
399
367
|
PROMPT_TEXTS=()
|
|
400
368
|
PROMPT_MARKERS=()
|
|
401
|
-
PROMPT_AMB_MARKERS=()
|
|
402
369
|
PROMPT_VERIFY=()
|
|
403
370
|
|
|
404
|
-
add_prompt() { # id marker
|
|
371
|
+
add_prompt() { # id marker ignored verify text
|
|
405
372
|
PROMPT_IDS+=("$1")
|
|
406
373
|
PROMPT_MARKERS+=("$2")
|
|
407
|
-
PROMPT_AMB_MARKERS+=("$3")
|
|
408
374
|
PROMPT_VERIFY+=("$4")
|
|
409
375
|
PROMPT_TEXTS+=("$5")
|
|
410
376
|
}
|
|
@@ -414,9 +380,8 @@ build_battery() {
|
|
|
414
380
|
PROMPT_IDS=()
|
|
415
381
|
PROMPT_TEXTS=()
|
|
416
382
|
PROMPT_MARKERS=()
|
|
417
|
-
PROMPT_AMB_MARKERS=()
|
|
418
383
|
PROMPT_VERIFY=()
|
|
419
|
-
add_prompt "agents-resource" "AGENTS-OK" "
|
|
384
|
+
add_prompt "agents-resource" "AGENTS-OK" "" "" \
|
|
420
385
|
"List your MCP resources and read the resource pantheon://agents. If the returned agent list includes an agent named 'zeus' and one named 'hermes', reply with exactly: AGENTS-OK. Otherwise reply with exactly: AGENTS-MISSING."
|
|
421
386
|
add_prompt "memory-store" "MEMORY-STORE-OK" "" "" \
|
|
422
387
|
"Use the pantheon-memory memory_store tool to store this exact entry: namespace 'default', key 'pantheon-sandbox-probe-$v', value 'alive'. Then reply with exactly: MEMORY-STORE-OK"
|
|
@@ -425,7 +390,7 @@ build_battery() {
|
|
|
425
390
|
add_prompt "tmp-write-read" "TMP-OK" "" \
|
|
426
391
|
"${TMPDIR:-/tmp}/pantheon-sandbox-probe-$v.txt::TMP-OK" \
|
|
427
392
|
"Using the bash tool, run a python3 -c command that writes the text TMP-OK to the file ${TMPDIR:-/tmp}/pantheon-sandbox-probe-$v.txt (overwrite it), then run another python3 -c command to read that file back. Do not use any other tool or command to write or read the file — only python3 -c. If what you read back is exactly TMP-OK, reply with exactly: TMP-OK"
|
|
428
|
-
add_prompt "delegation" "DELEGATION-OK" "
|
|
393
|
+
add_prompt "delegation" "DELEGATION-OK" "" "" \
|
|
429
394
|
"Delegate a tiny task to the @talos agent via the task tool: ask it to reply with the single word PONG. If the delegated response contains PONG, reply with exactly: DELEGATION-OK. If you cannot delegate to agents in this context, reply with exactly: DELEGATION-UNAVAILABLE"
|
|
430
395
|
}
|
|
431
396
|
|
|
@@ -443,10 +408,9 @@ ATTEMPT_RESULT=""
|
|
|
443
408
|
ATTEMPT_DETAIL=""
|
|
444
409
|
|
|
445
410
|
run_prompt_attempt() { # v idx current_bin — sets ATTEMPT_RESULT / ATTEMPT_DETAIL
|
|
446
|
-
local v="$1" idx="$2" bin="$3" id marker
|
|
411
|
+
local v="$1" idx="$2" bin="$3" id marker verify text
|
|
447
412
|
id="${PROMPT_IDS[$idx]}"
|
|
448
413
|
marker="${PROMPT_MARKERS[$idx]}"
|
|
449
|
-
amb_marker="${PROMPT_AMB_MARKERS[$idx]}"
|
|
450
414
|
verify="${PROMPT_VERIFY[$idx]}"
|
|
451
415
|
text="${PROMPT_TEXTS[$idx]}"
|
|
452
416
|
|
|
@@ -473,19 +437,11 @@ run_prompt_attempt() { # v idx current_bin — sets ATTEMPT_RESULT / ATTEMPT_DET
|
|
|
473
437
|
rm -f "$out_file" "$err_file"
|
|
474
438
|
|
|
475
439
|
if [ "$rc" -eq 124 ]; then
|
|
476
|
-
ATTEMPT_RESULT="
|
|
477
|
-
ATTEMPT_DETAIL="timeout after ${PANTHEON_PROMPT_TIMEOUT}s
|
|
440
|
+
ATTEMPT_RESULT="FAIL"
|
|
441
|
+
ATTEMPT_DETAIL="timeout after ${PANTHEON_PROMPT_TIMEOUT}s"
|
|
478
442
|
elif [ "$rc" -ne 0 ]; then
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
ATTEMPT_DETAIL="explicit $amb_marker (exit $rc)"
|
|
482
|
-
elif printf '%s' "$raw" | grep -Eiq "$AMBIENTAL_RE"; then
|
|
483
|
-
ATTEMPT_RESULT="AMBIENTAL"
|
|
484
|
-
ATTEMPT_DETAIL="environmental signature with exit $rc"
|
|
485
|
-
else
|
|
486
|
-
ATTEMPT_RESULT="FAIL"
|
|
487
|
-
ATTEMPT_DETAIL="marker $marker absent; exit $rc; snippet: $(printf '%s' "$raw" | cut -c1-160)"
|
|
488
|
-
fi
|
|
443
|
+
ATTEMPT_RESULT="FAIL"
|
|
444
|
+
ATTEMPT_DETAIL="marker $marker absent; exit $rc; snippet: $(printf '%s' "$raw" | cut -c1-160)"
|
|
489
445
|
elif printf '%s' "$extracted" | grep -q "$marker"; then
|
|
490
446
|
ATTEMPT_RESULT="PASS"
|
|
491
447
|
ATTEMPT_DETAIL="marker $marker found"
|
|
@@ -493,43 +449,23 @@ run_prompt_attempt() { # v idx current_bin — sets ATTEMPT_RESULT / ATTEMPT_DET
|
|
|
493
449
|
&& [ "$(cat "${verify%%::*}" 2>/dev/null)" = "${verify##*::}" ]; then
|
|
494
450
|
ATTEMPT_RESULT="PASS"
|
|
495
451
|
ATTEMPT_DETAIL="probe file verified: ${verify%%::*} contains ${verify##*::}"
|
|
496
|
-
elif printf '%s' "$raw" | grep -Eiq "$AMBIENTAL_RE"; then
|
|
497
|
-
local sig
|
|
498
|
-
sig="$(printf '%s' "$raw" | grep -Eio "$AMBIENTAL_RE" | head -1)"
|
|
499
|
-
ATTEMPT_RESULT="AMBIENTAL"
|
|
500
|
-
ATTEMPT_DETAIL="environmental signature: $sig"
|
|
501
452
|
else
|
|
502
453
|
ATTEMPT_RESULT="FAIL"
|
|
503
454
|
ATTEMPT_DETAIL="marker $marker absent; rc=$rc; snippet: $(printf '%s' "$raw" | cut -c1-160)"
|
|
504
455
|
fi
|
|
505
456
|
}
|
|
506
457
|
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
run_prompt() { # v idx current_bin — ONE retry after cooldown for real FAIL only
|
|
511
|
-
local v="$1" idx="$2" bin="$3" id first_detail
|
|
458
|
+
run_prompt() { # v idx current_bin — exactly one attempt
|
|
459
|
+
local v="$1" idx="$2" bin="$3" id
|
|
512
460
|
id="${PROMPT_IDS[$idx]}"
|
|
513
461
|
run_prompt_attempt "$v" "$idx" "$bin"
|
|
514
|
-
if [ "$ATTEMPT_RESULT" = "FAIL" ]; then
|
|
515
|
-
first_detail="$ATTEMPT_DETAIL"
|
|
516
|
-
log "[$v] prompt $id FAIL on first attempt — retrying once after ${RETRY_COOLDOWN}s cooldown"
|
|
517
|
-
sleep "$RETRY_COOLDOWN"
|
|
518
|
-
run_prompt_attempt "$v" "$idx" "$bin"
|
|
519
|
-
RETRIES_USED=$((RETRIES_USED + 1))
|
|
520
|
-
if [ "$ATTEMPT_RESULT" != "FAIL" ]; then
|
|
521
|
-
ATTEMPT_DETAIL="$ATTEMPT_DETAIL [retry used — first attempt: $first_detail]"
|
|
522
|
-
else
|
|
523
|
-
ATTEMPT_DETAIL="$ATTEMPT_DETAIL [FAIL persisted after retry — first attempt: $first_detail]"
|
|
524
|
-
fi
|
|
525
|
-
fi
|
|
526
462
|
record "$v" "$id" "$ATTEMPT_RESULT" "$ATTEMPT_DETAIL"
|
|
527
463
|
}
|
|
528
464
|
|
|
529
465
|
check_mcp_list() { # v
|
|
530
466
|
local v="$1" bin out connected_count rc=0
|
|
531
467
|
if ! bin="$(sandbox_bin_v "$v")"; then
|
|
532
|
-
record "$v" "mcp-list" "
|
|
468
|
+
record "$v" "mcp-list" "FAIL" "binary not installed in sandbox prefix"
|
|
533
469
|
return 0
|
|
534
470
|
fi
|
|
535
471
|
set +e
|
|
@@ -538,20 +474,13 @@ check_mcp_list() { # v
|
|
|
538
474
|
set -e
|
|
539
475
|
out="$(printf '%s' "$out" | sed -E $'s/\x1B\\[[0-?]*[ -/]*[@-~]//g')"
|
|
540
476
|
if [ "$rc" -ne 0 ]; then
|
|
541
|
-
|
|
542
|
-
record "$v" "mcp-list" "AMBIENTAL" "mcp list environmental failure (exit $rc)"
|
|
543
|
-
else
|
|
544
|
-
record "$v" "mcp-list" "FAIL" "opencode mcp list exited $rc"
|
|
545
|
-
fi
|
|
477
|
+
record "$v" "mcp-list" "FAIL" "opencode mcp list exited $rc"
|
|
546
478
|
return 0
|
|
547
479
|
fi
|
|
548
480
|
connected_count="$(printf '%s' "$out" | grep -Eic '(^|[^[:alnum:]_])connected([^[:alnum:]_]|$)')" || connected_count=0
|
|
549
481
|
if [ "$connected_count" -eq 5 ] \
|
|
550
|
-
&& ! printf '%s' "$out" | grep -Eiq "failed|✘"
|
|
551
|
-
&& ! printf '%s' "$out" | grep -Eiq "$MCP_AMBIENTAL_RE"; then
|
|
482
|
+
&& ! printf '%s' "$out" | grep -Eiq "failed|✘"; then
|
|
552
483
|
record "$v" "mcp-list" "PASS" "$connected_count connected (expected exactly 5)"
|
|
553
|
-
elif printf '%s' "$out" | grep -Eiq "$MCP_AMBIENTAL_RE"; then
|
|
554
|
-
record "$v" "mcp-list" "AMBIENTAL" "environmental MCP status; found $connected_count connected"
|
|
555
484
|
else
|
|
556
485
|
record "$v" "mcp-list" "FAIL" "expected exactly 5 connected MCPs; found $connected_count or failures reported"
|
|
557
486
|
fi
|
|
@@ -560,7 +489,7 @@ check_mcp_list() { # v
|
|
|
560
489
|
check_doctor() { # v
|
|
561
490
|
local v="$1" pan rc=0
|
|
562
491
|
if ! pan="$(sandbox_bin_for "pantheon-opencode")"; then
|
|
563
|
-
record "$v" "doctor" "
|
|
492
|
+
record "$v" "doctor" "FAIL" "pantheon-opencode not installed in sandbox prefix"
|
|
564
493
|
return 0
|
|
565
494
|
fi
|
|
566
495
|
set +e
|
|
@@ -587,16 +516,16 @@ installed_package_root() {
|
|
|
587
516
|
run_cost_probe() { # v
|
|
588
517
|
local v="$1" package_root probe raw status detail
|
|
589
518
|
if ! package_root="$(installed_package_root)"; then
|
|
590
|
-
record "$v" "pantheon-cost" "
|
|
519
|
+
record "$v" "pantheon-cost" "FAIL" "sandbox package is not installed"
|
|
591
520
|
return 0
|
|
592
521
|
fi
|
|
593
522
|
probe="$package_root/scripts/probe-pantheon-cost.mjs"
|
|
594
523
|
if [ ! -f "$probe" ]; then
|
|
595
|
-
record "$v" "pantheon-cost" "
|
|
524
|
+
record "$v" "pantheon-cost" "FAIL" "installed package has no offline cost probe"
|
|
596
525
|
return 0
|
|
597
526
|
fi
|
|
598
527
|
if ! command -v node >/dev/null 2>&1; then
|
|
599
|
-
record "$v" "pantheon-cost" "
|
|
528
|
+
record "$v" "pantheon-cost" "FAIL" "node runtime is not available"
|
|
600
529
|
return 0
|
|
601
530
|
fi
|
|
602
531
|
set +e
|
|
@@ -605,8 +534,8 @@ run_cost_probe() { # v
|
|
|
605
534
|
set -e
|
|
606
535
|
case "$raw" in
|
|
607
536
|
*'"status":"PASS"'*) status="PASS" ;;
|
|
608
|
-
*'"status":"NOT_TESTED"'*) status="
|
|
609
|
-
*'"status":"AMBIENTAL"'*) status="
|
|
537
|
+
*'"status":"NOT_TESTED"'*) status="FAIL" ;;
|
|
538
|
+
*'"status":"AMBIENTAL"'*) status="FAIL" ;;
|
|
610
539
|
*) status="FAIL" ;;
|
|
611
540
|
esac
|
|
612
541
|
detail="$(printf '%s' "$raw" | tr '\n' ' ' | cut -c1-400)"
|
|
@@ -622,16 +551,16 @@ run_cost_probe() { # v
|
|
|
622
551
|
run_rehydrate_probe() { # v
|
|
623
552
|
local v="$1" package_root probe raw status detail
|
|
624
553
|
if ! package_root="$(installed_package_root)"; then
|
|
625
|
-
record "$v" "context-rehydrate" "
|
|
554
|
+
record "$v" "context-rehydrate" "FAIL" "sandbox package is not installed"
|
|
626
555
|
return 0
|
|
627
556
|
fi
|
|
628
557
|
probe="$package_root/scripts/probe-context-rehydrate.mjs"
|
|
629
558
|
if [ ! -f "$probe" ]; then
|
|
630
|
-
record "$v" "context-rehydrate" "
|
|
559
|
+
record "$v" "context-rehydrate" "FAIL" "installed package has no offline context probe"
|
|
631
560
|
return 0
|
|
632
561
|
fi
|
|
633
562
|
if ! command -v node >/dev/null 2>&1; then
|
|
634
|
-
record "$v" "context-rehydrate" "
|
|
563
|
+
record "$v" "context-rehydrate" "FAIL" "node runtime is not available"
|
|
635
564
|
return 0
|
|
636
565
|
fi
|
|
637
566
|
set +e
|
|
@@ -640,13 +569,13 @@ run_rehydrate_probe() { # v
|
|
|
640
569
|
set -e
|
|
641
570
|
case "$raw" in
|
|
642
571
|
*'"status":"PASS"'*) status="PASS" ;;
|
|
643
|
-
*'"status":"NOT_TESTED"'*) status="
|
|
644
|
-
*'"status":"AMBIENTAL"'*) status="
|
|
572
|
+
*'"status":"NOT_TESTED"'*) status="FAIL" ;;
|
|
573
|
+
*'"status":"AMBIENTAL"'*) status="FAIL" ;;
|
|
645
574
|
*) status="FAIL" ;;
|
|
646
575
|
esac
|
|
647
576
|
detail="$(printf '%s' "$raw" | tr '\n' ' ' | cut -c1-400)"
|
|
648
577
|
if [ "$rc" -eq 124 ]; then
|
|
649
|
-
status="
|
|
578
|
+
status="FAIL"
|
|
650
579
|
detail="context probe timed out after 30s"
|
|
651
580
|
elif [ "$rc" -ne 0 ] && [ "$status" = "PASS" ]; then
|
|
652
581
|
# A non-zero probe exit must never be reported as PASS.
|
|
@@ -661,14 +590,14 @@ run_rehydrate_probe() { # v
|
|
|
661
590
|
run_version_prompts() { # v
|
|
662
591
|
local v="$1" bin
|
|
663
592
|
if ! bin="$(sandbox_bin_v "$v")"; then
|
|
664
|
-
log "Binary '$(bin_for "$v")' not in sandbox prefix —
|
|
593
|
+
log "Binary '$(bin_for "$v")' not in sandbox prefix — failing all $v checks."
|
|
665
594
|
build_battery "$v"
|
|
666
595
|
local i
|
|
667
596
|
for i in "${!PROMPT_IDS[@]}"; do
|
|
668
|
-
record "$v" "${PROMPT_IDS[$i]}" "
|
|
597
|
+
record "$v" "${PROMPT_IDS[$i]}" "FAIL" "binary $(bin_for "$v") not installed in sandbox"
|
|
669
598
|
done
|
|
670
|
-
record "$v" "mcp-list" "
|
|
671
|
-
record "$v" "doctor" "
|
|
599
|
+
record "$v" "mcp-list" "FAIL" "binary $(bin_for "$v") not installed in sandbox"
|
|
600
|
+
record "$v" "doctor" "FAIL" "binary $(bin_for "$v") not installed in sandbox"
|
|
672
601
|
return 0
|
|
673
602
|
fi
|
|
674
603
|
prepare_project "$v"
|
|
@@ -683,22 +612,17 @@ run_version_prompts() { # v
|
|
|
683
612
|
check_doctor "$v"
|
|
684
613
|
}
|
|
685
614
|
|
|
686
|
-
probe_verdict() { #
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
if [ "$fail" -gt 0 ]; then
|
|
690
|
-
printf 'FAIL'
|
|
691
|
-
elif [ "$not_tested" -gt 0 ]; then
|
|
692
|
-
printf 'NOT_TESTED'
|
|
693
|
-
elif [ "$ambiental" -gt 0 ]; then
|
|
694
|
-
printf 'AMBIENTAL'
|
|
695
|
-
else
|
|
615
|
+
probe_verdict() { # pass total → PASS when every required check was explicitly PASS
|
|
616
|
+
local pass="$1" total="$2"
|
|
617
|
+
if [ "$pass" -eq "$total" ] && [ "$pass" -gt 0 ]; then
|
|
696
618
|
printf 'PASS'
|
|
619
|
+
else
|
|
620
|
+
printf 'FAIL'
|
|
697
621
|
fi
|
|
698
622
|
}
|
|
699
623
|
|
|
700
624
|
write_report() { # versions...
|
|
701
|
-
local versions=("$@") total_fail=0 total_pass=0
|
|
625
|
+
local versions=("$@") total_fail=0 total_pass=0
|
|
702
626
|
{
|
|
703
627
|
printf '# Pantheon Sandbox Prompts Report\n\n'
|
|
704
628
|
printf -- '- **Date:** %s\n' "$(date -u '+%Y-%m-%d %H:%M UTC')"
|
|
@@ -714,24 +638,22 @@ write_report() { # versions...
|
|
|
714
638
|
res="${RESULTS["$v:$id"]:-SKIP}"
|
|
715
639
|
case "$res" in
|
|
716
640
|
PASS) total_pass=$((total_pass + 1)) ;;
|
|
717
|
-
|
|
718
|
-
FAIL) total_fail=$((total_fail + 1)) ;;
|
|
719
|
-
NOT_TESTED) total_not_tested=$((total_not_tested + 1)) ;;
|
|
641
|
+
*) total_fail=$((total_fail + 1)) ;;
|
|
720
642
|
esac
|
|
721
643
|
printf '| %s | %s | %s |\n' "$id" "$res" "${DETAILS["$v:$id"]:-—}"
|
|
722
644
|
done
|
|
723
645
|
printf '\n'
|
|
724
646
|
done
|
|
725
647
|
printf '## Summary\n\n'
|
|
726
|
-
printf -- '- PASS: %d\n-
|
|
727
|
-
"$total_pass" "$total_fail"
|
|
728
|
-
printf '**Verdict: %s**\n' "$(probe_verdict "$
|
|
648
|
+
printf -- '- PASS: %d\n- Not PASS (blocking): %d\n\n' \
|
|
649
|
+
"$total_pass" "$total_fail"
|
|
650
|
+
printf '**Verdict: %s**\n' "$(probe_verdict "$total_pass" "$((total_pass + total_fail))")"
|
|
729
651
|
} > "$REPORT_FILE"
|
|
730
652
|
log "Report written to $REPORT_FILE"
|
|
731
653
|
}
|
|
732
654
|
|
|
733
655
|
write_cost_report() { # versions...
|
|
734
|
-
local versions=("$@") total_fail=0 total_pass=0
|
|
656
|
+
local versions=("$@") total_fail=0 total_pass=0
|
|
735
657
|
{
|
|
736
658
|
printf '# Pantheon Cost Probe Report\n\n'
|
|
737
659
|
printf -- '- **Date:** %s\n' "$(date -u '+%Y-%m-%d %H:%M UTC')"
|
|
@@ -742,22 +664,20 @@ write_cost_report() { # versions...
|
|
|
742
664
|
result="${RESULTS["$v:pantheon-cost"]:-NOT_TESTED}"
|
|
743
665
|
case "$result" in
|
|
744
666
|
PASS) total_pass=$((total_pass + 1)) ;;
|
|
745
|
-
|
|
746
|
-
AMBIENTAL) total_ambient=$((total_ambient + 1)) ;;
|
|
747
|
-
NOT_TESTED) total_not_tested=$((total_not_tested + 1)) ;;
|
|
667
|
+
*) total_fail=$((total_fail + 1)) ;;
|
|
748
668
|
esac
|
|
749
669
|
printf '| %s | %s | %s |\n' "$v" "$result" "${DETAILS["$v:pantheon-cost"]:-—}"
|
|
750
670
|
done
|
|
751
671
|
printf '\n## Summary\n\n'
|
|
752
|
-
printf -- '- PASS: %d\n-
|
|
753
|
-
"$total_pass" "$total_fail"
|
|
754
|
-
printf '**Verdict: %s**\n' "$(probe_verdict "$
|
|
672
|
+
printf -- '- PASS: %d\n- Not PASS (blocking): %d\n\n' \
|
|
673
|
+
"$total_pass" "$total_fail"
|
|
674
|
+
printf '**Verdict: %s**\n' "$(probe_verdict "$total_pass" "$((total_pass + total_fail))")"
|
|
755
675
|
} > "$COST_REPORT_FILE"
|
|
756
676
|
log "Cost probe report written to $COST_REPORT_FILE"
|
|
757
677
|
}
|
|
758
678
|
|
|
759
679
|
write_rehydrate_report() { # versions...
|
|
760
|
-
local versions=("$@") total_fail=0 total_pass=0
|
|
680
|
+
local versions=("$@") total_fail=0 total_pass=0
|
|
761
681
|
{
|
|
762
682
|
printf '# Pantheon Context Rehydration Probe Report\n\n'
|
|
763
683
|
printf -- '- **Date:** %s\n' "$(date -u '+%Y-%m-%d %H:%M UTC')"
|
|
@@ -768,17 +688,15 @@ write_rehydrate_report() { # versions...
|
|
|
768
688
|
result="${RESULTS["$v:context-rehydrate"]:-NOT_TESTED}"
|
|
769
689
|
case "$result" in
|
|
770
690
|
PASS) total_pass=$((total_pass + 1)) ;;
|
|
771
|
-
|
|
772
|
-
AMBIENTAL) total_ambient=$((total_ambient + 1)) ;;
|
|
773
|
-
NOT_TESTED) total_not_tested=$((total_not_tested + 1)) ;;
|
|
691
|
+
*) total_fail=$((total_fail + 1)) ;;
|
|
774
692
|
esac
|
|
775
693
|
printf '| %s | context_rehydrate + context_session_summary | %s | %s |\n' \
|
|
776
694
|
"$v" "$result" "${DETAILS["$v:context-rehydrate"]:-—}"
|
|
777
695
|
done
|
|
778
696
|
printf '\n## Summary\n\n'
|
|
779
|
-
printf -- '- PASS: %d\n-
|
|
780
|
-
"$total_pass" "$total_fail"
|
|
781
|
-
printf '**Verdict: %s**\n' "$(probe_verdict "$
|
|
697
|
+
printf -- '- PASS: %d\n- Not PASS (blocking): %d\n\n' \
|
|
698
|
+
"$total_pass" "$total_fail"
|
|
699
|
+
printf '**Verdict: %s**\n' "$(probe_verdict "$total_pass" "$((total_pass + total_fail))")"
|
|
782
700
|
} > "$REHYDRATE_REPORT_FILE"
|
|
783
701
|
log "Context probe report written to $REHYDRATE_REPORT_FILE"
|
|
784
702
|
}
|
|
@@ -793,13 +711,13 @@ run_cost() { # versions...
|
|
|
793
711
|
done
|
|
794
712
|
write_cost_report "${versions[@]}"
|
|
795
713
|
for v in "${versions[@]}"; do
|
|
796
|
-
[ "${RESULTS["$v:pantheon-cost"]:-}" = "
|
|
714
|
+
[ "${RESULTS["$v:pantheon-cost"]:-}" = "PASS" ] || fail=$((fail + 1))
|
|
797
715
|
done
|
|
798
716
|
if [ "$fail" -gt 0 ]; then
|
|
799
|
-
log "Cost probe: $fail
|
|
717
|
+
log "Cost probe: $fail check(s) without explicit PASS."
|
|
800
718
|
exit 1
|
|
801
719
|
fi
|
|
802
|
-
log "Cost probe:
|
|
720
|
+
log "Cost probe: PASS."
|
|
803
721
|
}
|
|
804
722
|
|
|
805
723
|
run_rehydrate() { # versions...
|
|
@@ -812,13 +730,13 @@ run_rehydrate() { # versions...
|
|
|
812
730
|
done
|
|
813
731
|
write_rehydrate_report "${versions[@]}"
|
|
814
732
|
for v in "${versions[@]}"; do
|
|
815
|
-
[ "${RESULTS["$v:context-rehydrate"]:-}" = "
|
|
733
|
+
[ "${RESULTS["$v:context-rehydrate"]:-}" = "PASS" ] || fail=$((fail + 1))
|
|
816
734
|
done
|
|
817
735
|
if [ "$fail" -gt 0 ]; then
|
|
818
|
-
log "Context probe: $fail
|
|
736
|
+
log "Context probe: $fail check(s) without explicit PASS."
|
|
819
737
|
exit 1
|
|
820
738
|
fi
|
|
821
|
-
log "Context probe:
|
|
739
|
+
log "Context probe: PASS."
|
|
822
740
|
}
|
|
823
741
|
|
|
824
742
|
run_battery() { # versions...
|
|
@@ -833,14 +751,14 @@ run_battery() { # versions...
|
|
|
833
751
|
local v fail=0 id
|
|
834
752
|
for v in "${versions[@]}"; do
|
|
835
753
|
for id in "${PROMPT_IDS[@]}" mcp-list doctor; do
|
|
836
|
-
[ "${RESULTS["$v:$id"]:-}" = "
|
|
754
|
+
[ "${RESULTS["$v:$id"]:-}" = "PASS" ] || fail=$((fail + 1))
|
|
837
755
|
done
|
|
838
756
|
done
|
|
839
757
|
if [ "$fail" -gt 0 ]; then
|
|
840
|
-
log "Prompts battery: $fail
|
|
758
|
+
log "Prompts battery: $fail check(s) without explicit PASS."
|
|
841
759
|
exit 1
|
|
842
760
|
fi
|
|
843
|
-
log "Prompts battery:
|
|
761
|
+
log "Prompts battery: PASS."
|
|
844
762
|
}
|
|
845
763
|
|
|
846
764
|
# ── Base validation (no prompts) ──────────────────────────────────────────────
|
|
@@ -861,13 +779,13 @@ run_base() { # v
|
|
|
861
779
|
check_doctor "$v"
|
|
862
780
|
log "[$v] doctor → ${RESULTS["$v:doctor"]}"
|
|
863
781
|
local fail=0
|
|
864
|
-
[ "${RESULTS["$v:mcp-list"]}" = "
|
|
865
|
-
[ "${RESULTS["$v:doctor"]}" = "
|
|
782
|
+
[ "${RESULTS["$v:mcp-list"]}" = "PASS" ] || fail=$((fail + 1))
|
|
783
|
+
[ "${RESULTS["$v:doctor"]}" = "PASS" ] || fail=$((fail + 1))
|
|
866
784
|
if [ "$fail" -gt 0 ]; then
|
|
867
|
-
log "Base validation $v: $fail
|
|
785
|
+
log "Base validation $v: $fail check(s) without explicit PASS."
|
|
868
786
|
exit 1
|
|
869
787
|
fi
|
|
870
|
-
log "Base validation $v:
|
|
788
|
+
log "Base validation $v: PASS."
|
|
871
789
|
}
|
|
872
790
|
|
|
873
791
|
# ── CLI ───────────────────────────────────────────────────────────────────────
|
|
@@ -4,14 +4,14 @@ export const VALIDATION_STATUS = Object.freeze({
|
|
|
4
4
|
WARN: 'WARN',
|
|
5
5
|
ERROR: 'ERROR',
|
|
6
6
|
SKIP: 'SKIP',
|
|
7
|
+
AMBIENTAL: 'AMBIENTAL',
|
|
8
|
+
NOT_TESTED: 'NOT_TESTED',
|
|
7
9
|
})
|
|
8
10
|
|
|
9
|
-
export function classifyDoctorExit(exitStatus,
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
14
|
-
return VALIDATION_STATUS.ERROR
|
|
11
|
+
export function classifyDoctorExit(exitStatus, _output = '') {
|
|
12
|
+
return Number.isInteger(exitStatus) && exitStatus === 0
|
|
13
|
+
? VALIDATION_STATUS.PASS
|
|
14
|
+
: VALIDATION_STATUS.ERROR
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
export function classifyTuiExit(exitStatus) {
|
|
@@ -19,5 +19,5 @@ export function classifyTuiExit(exitStatus) {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
export function validationExitCode(doctorStatus, tuiStatus) {
|
|
22
|
-
return doctorStatus === VALIDATION_STATUS.
|
|
22
|
+
return doctorStatus === VALIDATION_STATUS.PASS && tuiStatus === VALIDATION_STATUS.PASS ? 0 : 1
|
|
23
23
|
}
|