pantheon-opencode 1.5.0-beta.1 → 1.5.0-beta.10
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 +1026 -0
- package/README.md +171 -16
- package/README.pt-BR.md +99 -13
- package/bin/pantheon-init.mjs +178 -21
- package/package.json +23 -14
- package/plugin.json +1 -1
- package/pyproject.toml +65 -0
- package/scripts/code_mode_server.py +431 -55
- package/scripts/cost.mjs +30 -14
- package/scripts/doctor.mjs +178 -9
- package/scripts/install/cli-ui.mjs +17 -11
- package/scripts/install/config-migration.mjs +4 -6
- package/scripts/install/opencode.mjs +137 -35
- package/scripts/install/plugin.mjs +3 -33
- package/scripts/install/shared.mjs +43 -2
- package/scripts/install/strings.mjs +129 -0
- package/scripts/install-mcp.mjs +1 -0
- package/scripts/manifest-inventory.mjs +410 -0
- package/scripts/mcp_persistence_server.py +537 -128
- package/scripts/package-evidence.mjs +242 -0
- package/scripts/probe-context-rehydrate.mjs +240 -0
- package/scripts/probe-pantheon-cost.mjs +313 -0
- package/scripts/release-beta-version.mjs +56 -60
- package/scripts/sync-artifacts.mjs +169 -0
- package/scripts/sync-tui.mjs +121 -53
- package/scripts/test-opencode-v1-v2-sandbox.sh +367 -96
- package/scripts/validation-policy.mjs +7 -7
- package/scripts/version-check.mjs +113 -108
- package/scripts/versioning.mjs +230 -86
- package/src/agents/mnemosyne.md +1 -1
- package/src/agents/zeus.md +2 -2
- package/src/mcp/code_mode_server.py +431 -55
- package/src/mcp/mcp_persistence_server.py +537 -128
- package/src/pantheon/auto-wake.ts +1 -5
- package/src/pantheon/background-job-board.ts +43 -1
- package/src/pantheon/compaction-handoff.ts +304 -0
- package/src/pantheon/cost-command.ts +345 -62
- package/src/pantheon/delegate-manager.ts +390 -8
- package/src/pantheon/delegation-finalize.ts +32 -0
- package/src/pantheon/delegation.ts +235 -18
- package/src/pantheon/file-persistence-salvage.ts +64 -0
- package/src/pantheon/file-persistence.ts +194 -45
- 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/shared-board.ts +37 -0
- package/src/pantheon/task-result-guard.ts +107 -0
- package/src/pantheon/token-opt.ts +146 -12
- package/src/pantheon/tool-ceiling.ts +159 -0
- package/src/pantheon/v2-events.ts +18 -1
- package/src/plugin-v2.ts +2 -14
- package/src/plugin.ts +28 -17
- package/src/plugins/pantheon-hooks.ts +51 -0
- package/src/plugins/tui/dist/server.d.ts +1 -1
- package/src/plugins/tui/dist/server.d.ts.map +1 -1
- package/src/plugins/tui/dist/server.js +1 -1
- package/src/plugins/tui/dist/server.js.map +1 -1
- package/src/plugins/tui/dist/tui.d.ts +116 -27
- package/src/plugins/tui/dist/tui.d.ts.map +1 -1
- package/src/plugins/tui/dist/tui.js +414 -150
- package/src/plugins/tui/dist/tui.js.map +1 -1
- package/src/plugins/tui/dist/tui.tsx +447 -84
- package/src/plugins/tui/package-lock.json +2 -2
- package/src/plugins/tui/package.json +1 -1
- package/src/plugins/tui/src/index.tsx +447 -84
- package/.pantheon/code-mode/.gitkeep +0 -0
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-1.json +0 -8
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-10.json +0 -8
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-11.json +0 -8
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-2.json +0 -8
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-3.json +0 -8
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-4.json +0 -8
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-5.json +0 -8
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-6.json +0 -8
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-7.json +0 -8
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-8.json +0 -8
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-9.json +0 -8
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/heartbeat.json +0 -8
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/session.json +0 -11
- package/src/pantheon/delegate-task-adapter.ts +0 -444
|
@@ -13,6 +13,11 @@
|
|
|
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 pantheon_cost probe for the requested
|
|
17
|
+
# version (with --run vX) or both versions alone.
|
|
18
|
+
# The probe's synthetic checks run in explicit --fixture mode.
|
|
19
|
+
# --rehydrate Offline context_rehydrate + context_session_summary
|
|
20
|
+
# probe for the requested version (with --run vX) or both.
|
|
16
21
|
# --reset Wipe the sandbox root.
|
|
17
22
|
# --help Usage.
|
|
18
23
|
#
|
|
@@ -25,11 +30,8 @@
|
|
|
25
30
|
# PANTHEON_SANDBOX_MODEL Model used by init/prompts
|
|
26
31
|
# (default: opencode-go/mimo-v2.5)
|
|
27
32
|
# PANTHEON_PROMPT_TIMEOUT Per-prompt timeout in seconds (default: 300)
|
|
28
|
-
#
|
|
29
|
-
#
|
|
30
|
-
#
|
|
31
|
-
# Exit codes: 0 = no real failures (AMBIENTAL issues do not fail the run),
|
|
32
|
-
# 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),
|
|
33
35
|
# 2 = usage error, 3 = sandbox not prepared.
|
|
34
36
|
set -euo pipefail
|
|
35
37
|
|
|
@@ -49,11 +51,15 @@ V1_BIN="${OPENCODE_V1_BIN:-opencode}"
|
|
|
49
51
|
V2_BIN="${OPENCODE_V2_BIN:-opencode2}"
|
|
50
52
|
|
|
51
53
|
REPORT_FILE="$SANDBOX_ROOT/prompts-report.md"
|
|
54
|
+
COST_REPORT_FILE="$SANDBOX_ROOT/pantheon-cost-report.md"
|
|
55
|
+
REHYDRATE_REPORT_FILE="$SANDBOX_ROOT/context-rehydrate-report.md"
|
|
52
56
|
EXTRACT_PY="$SANDBOX_ROOT/.prompt-extract-json.py"
|
|
53
57
|
|
|
54
58
|
MODE_PREPARE=0
|
|
55
59
|
MODE_RESET=0
|
|
56
60
|
MODE_PROMPTS=0
|
|
61
|
+
MODE_COST=0
|
|
62
|
+
MODE_REHYDRATE=0
|
|
57
63
|
RUN_VERSION=""
|
|
58
64
|
|
|
59
65
|
usage() {
|
|
@@ -105,8 +111,8 @@ write_run_test_sh() {
|
|
|
105
111
|
cat > "$SANDBOX_ROOT/run-test.sh" <<'RUNTEST'
|
|
106
112
|
#!/usr/bin/env bash
|
|
107
113
|
# Generated by pantheon-opencode scripts/test-opencode-v1-v2-sandbox.sh --prepare
|
|
108
|
-
# Validates the global install: binaries, 5
|
|
109
|
-
# AND the CONTENT of
|
|
114
|
+
# Validates the global install: binaries, exactly 5 connected MCPs per version,
|
|
115
|
+
# doctor 0 errors, AND the CONTENT of pantheon://agents (zeus/hermes present).
|
|
110
116
|
set -euo pipefail
|
|
111
117
|
|
|
112
118
|
SANDBOX_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
@@ -124,9 +130,68 @@ export HOME="$SANDBOX_HOME"
|
|
|
124
130
|
export PATH="$NPM_PREFIX/bin:$SANDBOX_VENV/bin:$PATH"
|
|
125
131
|
export npm_config_prefix="$NPM_PREFIX"
|
|
126
132
|
|
|
133
|
+
STATUS_FAIL=0
|
|
134
|
+
STATUS_PASS=0
|
|
135
|
+
|
|
136
|
+
record_status() { # label status detail
|
|
137
|
+
local label="$1" status="$2" detail="$3"
|
|
138
|
+
case "$status" in
|
|
139
|
+
PASS) STATUS_PASS=$((STATUS_PASS + 1)) ;;
|
|
140
|
+
FAIL) STATUS_FAIL=$((STATUS_FAIL + 1)) ;;
|
|
141
|
+
*) STATUS_FAIL=$((STATUS_FAIL + 1)); status="FAIL" ;;
|
|
142
|
+
esac
|
|
143
|
+
printf '%s: %s — %s\n' "$status" "$label" "$detail"
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
check_binary() { # label binary
|
|
147
|
+
local label="$1" bin="$2" out rc=0
|
|
148
|
+
if ! command -v "$bin" >/dev/null 2>&1; then
|
|
149
|
+
record_status "$label" "FAIL" "binary '$bin' is not installed in the sandbox prefix"
|
|
150
|
+
return 0
|
|
151
|
+
fi
|
|
152
|
+
set +e
|
|
153
|
+
out="$("$bin" --version 2>&1)"
|
|
154
|
+
rc=$?
|
|
155
|
+
set -e
|
|
156
|
+
if [ "$rc" -eq 0 ]; then
|
|
157
|
+
record_status "$label" "PASS" "${out:-version command exited 0}"
|
|
158
|
+
else
|
|
159
|
+
record_status "$label" "FAIL" "version check exited $rc"
|
|
160
|
+
fi
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
check_mcp() { # label binary project
|
|
164
|
+
local label="$1" bin="$2" project="$3" out connected_count rc=0
|
|
165
|
+
if ! command -v "$bin" >/dev/null 2>&1; then
|
|
166
|
+
record_status "$label MCP" "FAIL" "binary '$bin' is not installed in the sandbox prefix"
|
|
167
|
+
return 0
|
|
168
|
+
fi
|
|
169
|
+
if [ ! -d "$project" ]; then
|
|
170
|
+
record_status "$label MCP" "FAIL" "project directory is missing: $project"
|
|
171
|
+
return 0
|
|
172
|
+
fi
|
|
173
|
+
set +e
|
|
174
|
+
out="$(cd "$project" && "$bin" mcp list 2>&1)"
|
|
175
|
+
rc=$?
|
|
176
|
+
set -e
|
|
177
|
+
out="$(printf '%s' "$out" | sed -E $'s/\x1B\\[[0-?]*[ -/]*[@-~]//g')"
|
|
178
|
+
printf '%s\n' "$out"
|
|
179
|
+
if [ "$rc" -ne 0 ]; then
|
|
180
|
+
record_status "$label MCP" "FAIL" "mcp list exited $rc"
|
|
181
|
+
return 0
|
|
182
|
+
fi
|
|
183
|
+
connected_count="$(printf '%s' "$out" | grep -Eic '(^|[^[:alnum:]_])connected([^[:alnum:]_]|$)')" || connected_count=0
|
|
184
|
+
if [ "$connected_count" -eq 5 ] \
|
|
185
|
+
&& ! printf '%s' "$out" | grep -Eiq 'failed|✘'; then
|
|
186
|
+
record_status "$label MCP" "PASS" "exactly 5 connected MCPs"
|
|
187
|
+
else
|
|
188
|
+
record_status "$label MCP" "FAIL" "expected exactly 5 connected MCPs; found $connected_count or failures reported"
|
|
189
|
+
fi
|
|
190
|
+
}
|
|
191
|
+
|
|
127
192
|
echo "--- Binaries ---"
|
|
128
|
-
opencode
|
|
129
|
-
opencode2
|
|
193
|
+
check_binary "V1 binary" opencode
|
|
194
|
+
check_binary "V2 binary" opencode2
|
|
130
195
|
|
|
131
196
|
echo "--- Building tarball ---"
|
|
132
197
|
cd "$REPO_DIR"
|
|
@@ -134,42 +199,70 @@ npm pack 2>/dev/null || { echo "ERROR: npm pack failed"; exit 1; }
|
|
|
134
199
|
TGZ=$(ls -t pantheon-opencode-*.tgz | head -1)
|
|
135
200
|
npm rm -g pantheon-opencode 2>/dev/null || true
|
|
136
201
|
npm install -g "$TGZ"
|
|
202
|
+
if ! git -C "$REPO_DIR" ls-files --error-unmatch -- "$TGZ" >/dev/null 2>&1; then rm -f -- "$TGZ"; fi
|
|
137
203
|
|
|
138
204
|
echo "--- Init (headless) ---"
|
|
139
205
|
pantheon-opencode init --headless -y
|
|
140
206
|
|
|
141
|
-
echo "--- MCP
|
|
142
|
-
opencode
|
|
143
|
-
|
|
144
|
-
echo "--- MCP List (V2) ---"
|
|
145
|
-
opencode2 mcp list
|
|
207
|
+
echo "--- MCP Validation ---"
|
|
208
|
+
check_mcp "V1" opencode "$SANDBOX_DIR/project-v1"
|
|
209
|
+
check_mcp "V2" opencode2 "$SANDBOX_DIR/project-v2"
|
|
146
210
|
|
|
147
211
|
echo "--- Doctor ---"
|
|
148
|
-
pantheon-opencode
|
|
212
|
+
if command -v pantheon-opencode >/dev/null 2>&1; then
|
|
213
|
+
set +e
|
|
214
|
+
DOCTOR_OUTPUT="$(pantheon-opencode doctor --target "$SANDBOX_DIR" 2>&1)"
|
|
215
|
+
DOCTOR_RC=$?
|
|
216
|
+
set -e
|
|
217
|
+
if [ "$DOCTOR_RC" -eq 0 ]; then
|
|
218
|
+
record_status "doctor" "PASS" "exit 0"
|
|
219
|
+
else
|
|
220
|
+
record_status "doctor" "FAIL" "doctor exited $DOCTOR_RC"
|
|
221
|
+
fi
|
|
222
|
+
else
|
|
223
|
+
record_status "doctor" "FAIL" "pantheon-opencode is not installed in the sandbox prefix"
|
|
224
|
+
fi
|
|
149
225
|
|
|
150
226
|
echo "--- Gate (b): pantheon://agents CONTENT check ---"
|
|
151
227
|
RESOURCES_SRV="$PANTHEON_GLOBAL/scripts/mcp_resources_server.py"
|
|
152
228
|
if [ ! -f "$RESOURCES_SRV" ]; then
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
229
|
+
record_status "pantheon://agents resource" "FAIL" "resources server not found at $RESOURCES_SRV"
|
|
230
|
+
else
|
|
231
|
+
set +e
|
|
232
|
+
AGENTS_CONTENT="$("$SANDBOX_VENV/bin/python" - "$RESOURCES_SRV" <<'PYEOF'
|
|
156
233
|
import asyncio, importlib.util, sys
|
|
234
|
+
from pathlib import Path
|
|
235
|
+
resource_path = Path(sys.argv[1]).resolve()
|
|
236
|
+
sys.path.insert(0, str(resource_path.parent))
|
|
157
237
|
spec = importlib.util.spec_from_file_location("mrs", sys.argv[1])
|
|
158
238
|
mod = importlib.util.module_from_spec(spec)
|
|
159
239
|
spec.loader.exec_module(mod)
|
|
160
240
|
print(asyncio.run(mod.list_agents()))
|
|
161
241
|
PYEOF
|
|
162
242
|
)"
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
243
|
+
AGENTS_RC=$?
|
|
244
|
+
set -e
|
|
245
|
+
printf '%s\n' "$AGENTS_CONTENT" | head -8
|
|
246
|
+
if [ "$AGENTS_RC" -ne 0 ]; then
|
|
247
|
+
record_status "pantheon://agents resource" "FAIL" "resource probe exited $AGENTS_RC"
|
|
248
|
+
elif printf '%s\n' "$AGENTS_CONTENT" | grep -qi 'zeus' \
|
|
249
|
+
&& printf '%s\n' "$AGENTS_CONTENT" | grep -qi 'hermes'; then
|
|
250
|
+
record_status "pantheon://agents resource" "PASS" "pantheon://agents content includes zeus and hermes"
|
|
251
|
+
else
|
|
252
|
+
record_status "pantheon://agents resource" "FAIL" "content missing zeus/hermes (connectivity alone is not enough)"
|
|
253
|
+
fi
|
|
169
254
|
fi
|
|
170
|
-
|
|
171
255
|
echo ""
|
|
172
256
|
echo "=== VALIDATION COMPLETE ==="
|
|
257
|
+
if [ "$STATUS_FAIL" -gt 0 ] || [ "$STATUS_PASS" -eq 0 ]; then
|
|
258
|
+
FINAL_VERDICT="FAIL"
|
|
259
|
+
else
|
|
260
|
+
FINAL_VERDICT="PASS"
|
|
261
|
+
fi
|
|
262
|
+
printf 'Final verdict: %s\n' "$FINAL_VERDICT"
|
|
263
|
+
if [ "$FINAL_VERDICT" != "PASS" ]; then
|
|
264
|
+
exit 1
|
|
265
|
+
fi
|
|
173
266
|
echo "Next: open the isolated TUI with: $SANDBOX_DIR/start-pantheon.sh"
|
|
174
267
|
RUNTEST
|
|
175
268
|
chmod +x "$SANDBOX_ROOT/run-test.sh"
|
|
@@ -195,12 +288,11 @@ install_binaries() {
|
|
|
195
288
|
tgz=$(ls -t pantheon-opencode-*.tgz | head -1)
|
|
196
289
|
npm rm -g pantheon-opencode 2>/dev/null || true
|
|
197
290
|
npm install -g "$REPO_DIR/$tgz" || die "install of $tgz failed"
|
|
291
|
+
if ! git -C "$REPO_DIR" ls-files --error-unmatch -- "$tgz" >/dev/null 2>&1; then rm -f -- "$tgz"; fi
|
|
198
292
|
log "--- Installing OpenCode V1 ($OPENCODE_V1_SPEC) ---"
|
|
199
|
-
npm install -g "$OPENCODE_V1_SPEC"
|
|
200
|
-
|| 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"
|
|
201
294
|
log "--- Installing OpenCode V2 ($OPENCODE_V2_SPEC) ---"
|
|
202
|
-
npm install -g "$OPENCODE_V2_SPEC"
|
|
203
|
-
|| 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"
|
|
204
296
|
}
|
|
205
297
|
|
|
206
298
|
prepare_project() {
|
|
@@ -271,19 +363,14 @@ PYEOF
|
|
|
271
363
|
|
|
272
364
|
# ── Prompt battery ────────────────────────────────────────────────────────────
|
|
273
365
|
|
|
274
|
-
# Known environmental failure signatures (never fail the run).
|
|
275
|
-
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'
|
|
276
|
-
|
|
277
366
|
PROMPT_IDS=()
|
|
278
367
|
PROMPT_TEXTS=()
|
|
279
368
|
PROMPT_MARKERS=()
|
|
280
|
-
PROMPT_AMB_MARKERS=()
|
|
281
369
|
PROMPT_VERIFY=()
|
|
282
370
|
|
|
283
|
-
add_prompt() { # id marker
|
|
371
|
+
add_prompt() { # id marker ignored verify text
|
|
284
372
|
PROMPT_IDS+=("$1")
|
|
285
373
|
PROMPT_MARKERS+=("$2")
|
|
286
|
-
PROMPT_AMB_MARKERS+=("$3")
|
|
287
374
|
PROMPT_VERIFY+=("$4")
|
|
288
375
|
PROMPT_TEXTS+=("$5")
|
|
289
376
|
}
|
|
@@ -293,9 +380,8 @@ build_battery() {
|
|
|
293
380
|
PROMPT_IDS=()
|
|
294
381
|
PROMPT_TEXTS=()
|
|
295
382
|
PROMPT_MARKERS=()
|
|
296
|
-
PROMPT_AMB_MARKERS=()
|
|
297
383
|
PROMPT_VERIFY=()
|
|
298
|
-
add_prompt "agents-resource" "AGENTS-OK" "
|
|
384
|
+
add_prompt "agents-resource" "AGENTS-OK" "" "" \
|
|
299
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."
|
|
300
386
|
add_prompt "memory-store" "MEMORY-STORE-OK" "" "" \
|
|
301
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"
|
|
@@ -304,7 +390,7 @@ build_battery() {
|
|
|
304
390
|
add_prompt "tmp-write-read" "TMP-OK" "" \
|
|
305
391
|
"${TMPDIR:-/tmp}/pantheon-sandbox-probe-$v.txt::TMP-OK" \
|
|
306
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"
|
|
307
|
-
add_prompt "delegation" "DELEGATION-OK" "
|
|
393
|
+
add_prompt "delegation" "DELEGATION-OK" "" "" \
|
|
308
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"
|
|
309
395
|
}
|
|
310
396
|
|
|
@@ -322,10 +408,9 @@ ATTEMPT_RESULT=""
|
|
|
322
408
|
ATTEMPT_DETAIL=""
|
|
323
409
|
|
|
324
410
|
run_prompt_attempt() { # v idx current_bin — sets ATTEMPT_RESULT / ATTEMPT_DETAIL
|
|
325
|
-
local v="$1" idx="$2" bin="$3" id marker
|
|
411
|
+
local v="$1" idx="$2" bin="$3" id marker verify text
|
|
326
412
|
id="${PROMPT_IDS[$idx]}"
|
|
327
413
|
marker="${PROMPT_MARKERS[$idx]}"
|
|
328
|
-
amb_marker="${PROMPT_AMB_MARKERS[$idx]}"
|
|
329
414
|
verify="${PROMPT_VERIFY[$idx]}"
|
|
330
415
|
text="${PROMPT_TEXTS[$idx]}"
|
|
331
416
|
|
|
@@ -352,75 +437,59 @@ run_prompt_attempt() { # v idx current_bin — sets ATTEMPT_RESULT / ATTEMPT_DET
|
|
|
352
437
|
rm -f "$out_file" "$err_file"
|
|
353
438
|
|
|
354
439
|
if [ "$rc" -eq 124 ]; then
|
|
355
|
-
ATTEMPT_RESULT="
|
|
356
|
-
ATTEMPT_DETAIL="timeout after ${PANTHEON_PROMPT_TIMEOUT}s
|
|
440
|
+
ATTEMPT_RESULT="FAIL"
|
|
441
|
+
ATTEMPT_DETAIL="timeout after ${PANTHEON_PROMPT_TIMEOUT}s"
|
|
442
|
+
elif [ "$rc" -ne 0 ]; then
|
|
443
|
+
ATTEMPT_RESULT="FAIL"
|
|
444
|
+
ATTEMPT_DETAIL="marker $marker absent; exit $rc; snippet: $(printf '%s' "$raw" | cut -c1-160)"
|
|
357
445
|
elif printf '%s' "$extracted" | grep -q "$marker"; then
|
|
358
446
|
ATTEMPT_RESULT="PASS"
|
|
359
447
|
ATTEMPT_DETAIL="marker $marker found"
|
|
360
|
-
elif [ -n "$amb_marker" ] && printf '%s' "$extracted" | grep -q "$amb_marker"; then
|
|
361
|
-
ATTEMPT_RESULT="AMBIENTAL"
|
|
362
|
-
ATTEMPT_DETAIL="explicit $amb_marker"
|
|
363
448
|
elif [ -n "$verify" ] \
|
|
364
449
|
&& [ "$(cat "${verify%%::*}" 2>/dev/null)" = "${verify##*::}" ]; then
|
|
365
450
|
ATTEMPT_RESULT="PASS"
|
|
366
451
|
ATTEMPT_DETAIL="probe file verified: ${verify%%::*} contains ${verify##*::}"
|
|
367
|
-
elif printf '%s' "$raw" | grep -Eiq "$AMBIENTAL_RE"; then
|
|
368
|
-
local sig
|
|
369
|
-
sig="$(printf '%s' "$raw" | grep -Eio "$AMBIENTAL_RE" | head -1)"
|
|
370
|
-
ATTEMPT_RESULT="AMBIENTAL"
|
|
371
|
-
ATTEMPT_DETAIL="environmental signature: $sig"
|
|
372
452
|
else
|
|
373
453
|
ATTEMPT_RESULT="FAIL"
|
|
374
454
|
ATTEMPT_DETAIL="marker $marker absent; rc=$rc; snippet: $(printf '%s' "$raw" | cut -c1-160)"
|
|
375
455
|
fi
|
|
376
456
|
}
|
|
377
457
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
run_prompt() { # v idx current_bin — ONE retry after cooldown for real FAIL only
|
|
382
|
-
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
|
|
383
460
|
id="${PROMPT_IDS[$idx]}"
|
|
384
461
|
run_prompt_attempt "$v" "$idx" "$bin"
|
|
385
|
-
if [ "$ATTEMPT_RESULT" = "FAIL" ]; then
|
|
386
|
-
first_detail="$ATTEMPT_DETAIL"
|
|
387
|
-
log "[$v] prompt $id FAIL on first attempt — retrying once after ${RETRY_COOLDOWN}s cooldown"
|
|
388
|
-
sleep "$RETRY_COOLDOWN"
|
|
389
|
-
run_prompt_attempt "$v" "$idx" "$bin"
|
|
390
|
-
RETRIES_USED=$((RETRIES_USED + 1))
|
|
391
|
-
if [ "$ATTEMPT_RESULT" != "FAIL" ]; then
|
|
392
|
-
ATTEMPT_DETAIL="$ATTEMPT_DETAIL [retry used — first attempt: $first_detail]"
|
|
393
|
-
else
|
|
394
|
-
ATTEMPT_DETAIL="$ATTEMPT_DETAIL [FAIL persisted after retry — first attempt: $first_detail]"
|
|
395
|
-
fi
|
|
396
|
-
fi
|
|
397
462
|
record "$v" "$id" "$ATTEMPT_RESULT" "$ATTEMPT_DETAIL"
|
|
398
463
|
}
|
|
399
464
|
|
|
400
465
|
check_mcp_list() { # v
|
|
401
|
-
local v="$1" bin out rc=0
|
|
466
|
+
local v="$1" bin out connected_count rc=0
|
|
402
467
|
if ! bin="$(sandbox_bin_v "$v")"; then
|
|
403
|
-
record "$v" "mcp-list" "
|
|
468
|
+
record "$v" "mcp-list" "FAIL" "binary not installed in sandbox prefix"
|
|
404
469
|
return 0
|
|
405
470
|
fi
|
|
406
471
|
set +e
|
|
407
472
|
out="$(cd "$(project_for "$v")" && "$bin" mcp list 2>&1)"
|
|
408
473
|
rc=$?
|
|
409
474
|
set -e
|
|
475
|
+
out="$(printf '%s' "$out" | sed -E $'s/\x1B\\[[0-?]*[ -/]*[@-~]//g')"
|
|
410
476
|
if [ "$rc" -ne 0 ]; then
|
|
411
477
|
record "$v" "mcp-list" "FAIL" "opencode mcp list exited $rc"
|
|
412
|
-
|
|
478
|
+
return 0
|
|
479
|
+
fi
|
|
480
|
+
connected_count="$(printf '%s' "$out" | grep -Eic '(^|[^[:alnum:]_])connected([^[:alnum:]_]|$)')" || connected_count=0
|
|
481
|
+
if [ "$connected_count" -eq 5 ] \
|
|
413
482
|
&& ! printf '%s' "$out" | grep -Eiq "failed|✘"; then
|
|
414
|
-
record "$v" "mcp-list" "PASS" "$
|
|
483
|
+
record "$v" "mcp-list" "PASS" "$connected_count connected (expected exactly 5)"
|
|
415
484
|
else
|
|
416
|
-
record "$v" "mcp-list" "FAIL" "
|
|
485
|
+
record "$v" "mcp-list" "FAIL" "expected exactly 5 connected MCPs; found $connected_count or failures reported"
|
|
417
486
|
fi
|
|
418
487
|
}
|
|
419
488
|
|
|
420
489
|
check_doctor() { # v
|
|
421
490
|
local v="$1" pan rc=0
|
|
422
491
|
if ! pan="$(sandbox_bin_for "pantheon-opencode")"; then
|
|
423
|
-
record "$v" "doctor" "
|
|
492
|
+
record "$v" "doctor" "FAIL" "pantheon-opencode not installed in sandbox prefix"
|
|
424
493
|
return 0
|
|
425
494
|
fi
|
|
426
495
|
set +e
|
|
@@ -434,17 +503,101 @@ check_doctor() { # v
|
|
|
434
503
|
fi
|
|
435
504
|
}
|
|
436
505
|
|
|
506
|
+
installed_package_root() {
|
|
507
|
+
local pan resolved
|
|
508
|
+
if ! pan="$(sandbox_bin_for "pantheon-opencode")"; then
|
|
509
|
+
return 1
|
|
510
|
+
fi
|
|
511
|
+
resolved="$(readlink -f "$pan" 2>/dev/null || true)"
|
|
512
|
+
[ -n "$resolved" ] || return 1
|
|
513
|
+
dirname "$(dirname "$resolved")"
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
run_cost_probe() { # v
|
|
517
|
+
local v="$1" package_root probe raw status detail
|
|
518
|
+
if ! package_root="$(installed_package_root)"; then
|
|
519
|
+
record "$v" "pantheon-cost" "FAIL" "sandbox package is not installed"
|
|
520
|
+
return 0
|
|
521
|
+
fi
|
|
522
|
+
probe="$package_root/scripts/probe-pantheon-cost.mjs"
|
|
523
|
+
if [ ! -f "$probe" ]; then
|
|
524
|
+
record "$v" "pantheon-cost" "FAIL" "installed package has no offline cost probe"
|
|
525
|
+
return 0
|
|
526
|
+
fi
|
|
527
|
+
if ! command -v node >/dev/null 2>&1; then
|
|
528
|
+
record "$v" "pantheon-cost" "FAIL" "node runtime is not available"
|
|
529
|
+
return 0
|
|
530
|
+
fi
|
|
531
|
+
set +e
|
|
532
|
+
raw="$(node "$probe" --version "$v" --fixture --json 2>&1)"
|
|
533
|
+
local rc=$?
|
|
534
|
+
set -e
|
|
535
|
+
case "$raw" in
|
|
536
|
+
*'"status":"PASS"'*) status="PASS" ;;
|
|
537
|
+
*'"status":"NOT_TESTED"'*) status="FAIL" ;;
|
|
538
|
+
*'"status":"AMBIENTAL"'*) status="FAIL" ;;
|
|
539
|
+
*) status="FAIL" ;;
|
|
540
|
+
esac
|
|
541
|
+
detail="$(printf '%s' "$raw" | tr '\n' ' ' | cut -c1-400)"
|
|
542
|
+
if [ "$rc" -ne 0 ] && [ "$status" = "PASS" ]; then
|
|
543
|
+
status="FAIL"
|
|
544
|
+
detail="$detail (probe exit $rc)"
|
|
545
|
+
elif [ "$rc" -ne 0 ] && [ "$status" != "FAIL" ]; then
|
|
546
|
+
detail="$detail (probe exit $rc)"
|
|
547
|
+
fi
|
|
548
|
+
record "$v" "pantheon-cost" "$status" "$detail"
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
run_rehydrate_probe() { # v
|
|
552
|
+
local v="$1" package_root probe raw status detail
|
|
553
|
+
if ! package_root="$(installed_package_root)"; then
|
|
554
|
+
record "$v" "context-rehydrate" "FAIL" "sandbox package is not installed"
|
|
555
|
+
return 0
|
|
556
|
+
fi
|
|
557
|
+
probe="$package_root/scripts/probe-context-rehydrate.mjs"
|
|
558
|
+
if [ ! -f "$probe" ]; then
|
|
559
|
+
record "$v" "context-rehydrate" "FAIL" "installed package has no offline context probe"
|
|
560
|
+
return 0
|
|
561
|
+
fi
|
|
562
|
+
if ! command -v node >/dev/null 2>&1; then
|
|
563
|
+
record "$v" "context-rehydrate" "FAIL" "node runtime is not available"
|
|
564
|
+
return 0
|
|
565
|
+
fi
|
|
566
|
+
set +e
|
|
567
|
+
raw="$(timeout 30 node "$probe" --version "$v" --json 2>&1)"
|
|
568
|
+
local rc=$?
|
|
569
|
+
set -e
|
|
570
|
+
case "$raw" in
|
|
571
|
+
*'"status":"PASS"'*) status="PASS" ;;
|
|
572
|
+
*'"status":"NOT_TESTED"'*) status="FAIL" ;;
|
|
573
|
+
*'"status":"AMBIENTAL"'*) status="FAIL" ;;
|
|
574
|
+
*) status="FAIL" ;;
|
|
575
|
+
esac
|
|
576
|
+
detail="$(printf '%s' "$raw" | tr '\n' ' ' | cut -c1-400)"
|
|
577
|
+
if [ "$rc" -eq 124 ]; then
|
|
578
|
+
status="FAIL"
|
|
579
|
+
detail="context probe timed out after 30s"
|
|
580
|
+
elif [ "$rc" -ne 0 ] && [ "$status" = "PASS" ]; then
|
|
581
|
+
# A non-zero probe exit must never be reported as PASS.
|
|
582
|
+
status="FAIL"
|
|
583
|
+
detail="$detail (probe exit $rc)"
|
|
584
|
+
elif [ "$rc" -ne 0 ] && [ "$status" != "FAIL" ]; then
|
|
585
|
+
detail="$detail (probe exit $rc)"
|
|
586
|
+
fi
|
|
587
|
+
record "$v" "context-rehydrate" "$status" "$detail"
|
|
588
|
+
}
|
|
589
|
+
|
|
437
590
|
run_version_prompts() { # v
|
|
438
591
|
local v="$1" bin
|
|
439
592
|
if ! bin="$(sandbox_bin_v "$v")"; then
|
|
440
|
-
log "Binary '$(bin_for "$v")' not in sandbox prefix —
|
|
593
|
+
log "Binary '$(bin_for "$v")' not in sandbox prefix — failing all $v checks."
|
|
441
594
|
build_battery "$v"
|
|
442
595
|
local i
|
|
443
596
|
for i in "${!PROMPT_IDS[@]}"; do
|
|
444
|
-
record "$v" "${PROMPT_IDS[$i]}" "
|
|
597
|
+
record "$v" "${PROMPT_IDS[$i]}" "FAIL" "binary $(bin_for "$v") not installed in sandbox"
|
|
445
598
|
done
|
|
446
|
-
record "$v" "mcp-list" "
|
|
447
|
-
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"
|
|
448
601
|
return 0
|
|
449
602
|
fi
|
|
450
603
|
prepare_project "$v"
|
|
@@ -459,8 +612,17 @@ run_version_prompts() { # v
|
|
|
459
612
|
check_doctor "$v"
|
|
460
613
|
}
|
|
461
614
|
|
|
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
|
|
618
|
+
printf 'PASS'
|
|
619
|
+
else
|
|
620
|
+
printf 'FAIL'
|
|
621
|
+
fi
|
|
622
|
+
}
|
|
623
|
+
|
|
462
624
|
write_report() { # versions...
|
|
463
|
-
local versions=("$@") total_fail=0 total_pass=0
|
|
625
|
+
local versions=("$@") total_fail=0 total_pass=0
|
|
464
626
|
{
|
|
465
627
|
printf '# Pantheon Sandbox Prompts Report\n\n'
|
|
466
628
|
printf -- '- **Date:** %s\n' "$(date -u '+%Y-%m-%d %H:%M UTC')"
|
|
@@ -475,26 +637,108 @@ write_report() { # versions...
|
|
|
475
637
|
for id in "${PROMPT_IDS[@]}" mcp-list doctor; do
|
|
476
638
|
res="${RESULTS["$v:$id"]:-SKIP}"
|
|
477
639
|
case "$res" in
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
FAIL) total_fail=$((total_fail + 1)) ;;
|
|
640
|
+
PASS) total_pass=$((total_pass + 1)) ;;
|
|
641
|
+
*) total_fail=$((total_fail + 1)) ;;
|
|
481
642
|
esac
|
|
482
643
|
printf '| %s | %s | %s |\n' "$id" "$res" "${DETAILS["$v:$id"]:-—}"
|
|
483
644
|
done
|
|
484
645
|
printf '\n'
|
|
485
646
|
done
|
|
486
647
|
printf '## Summary\n\n'
|
|
487
|
-
printf -- '- PASS: %d\n-
|
|
488
|
-
"$total_pass" "$total_fail"
|
|
489
|
-
|
|
490
|
-
printf '**Verdict: PASS** — no real failures (AMBIENTAL issues do not block).\n'
|
|
491
|
-
else
|
|
492
|
-
printf '**Verdict: FAIL** — real failures detected (see table above).\n'
|
|
493
|
-
fi
|
|
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))")"
|
|
494
651
|
} > "$REPORT_FILE"
|
|
495
652
|
log "Report written to $REPORT_FILE"
|
|
496
653
|
}
|
|
497
654
|
|
|
655
|
+
write_cost_report() { # versions...
|
|
656
|
+
local versions=("$@") total_fail=0 total_pass=0
|
|
657
|
+
{
|
|
658
|
+
printf '# Pantheon Cost Probe Report\n\n'
|
|
659
|
+
printf -- '- **Date:** %s\n' "$(date -u '+%Y-%m-%d %H:%M UTC')"
|
|
660
|
+
printf -- '- **Sandbox:** %s\n\n' "$SANDBOX_ROOT"
|
|
661
|
+
printf '| Version | Result | Detail |\n|---|---|---|\n'
|
|
662
|
+
local v result
|
|
663
|
+
for v in "${versions[@]}"; do
|
|
664
|
+
result="${RESULTS["$v:pantheon-cost"]:-NOT_TESTED}"
|
|
665
|
+
case "$result" in
|
|
666
|
+
PASS) total_pass=$((total_pass + 1)) ;;
|
|
667
|
+
*) total_fail=$((total_fail + 1)) ;;
|
|
668
|
+
esac
|
|
669
|
+
printf '| %s | %s | %s |\n' "$v" "$result" "${DETAILS["$v:pantheon-cost"]:-—}"
|
|
670
|
+
done
|
|
671
|
+
printf '\n## Summary\n\n'
|
|
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))")"
|
|
675
|
+
} > "$COST_REPORT_FILE"
|
|
676
|
+
log "Cost probe report written to $COST_REPORT_FILE"
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
write_rehydrate_report() { # versions...
|
|
680
|
+
local versions=("$@") total_fail=0 total_pass=0
|
|
681
|
+
{
|
|
682
|
+
printf '# Pantheon Context Rehydration Probe Report\n\n'
|
|
683
|
+
printf -- '- **Date:** %s\n' "$(date -u '+%Y-%m-%d %H:%M UTC')"
|
|
684
|
+
printf -- '- **Sandbox:** %s\n\n' "$SANDBOX_ROOT"
|
|
685
|
+
printf '| Version | Probe | Result | Detail |\n|---|---|---|---|\n'
|
|
686
|
+
local v result
|
|
687
|
+
for v in "${versions[@]}"; do
|
|
688
|
+
result="${RESULTS["$v:context-rehydrate"]:-NOT_TESTED}"
|
|
689
|
+
case "$result" in
|
|
690
|
+
PASS) total_pass=$((total_pass + 1)) ;;
|
|
691
|
+
*) total_fail=$((total_fail + 1)) ;;
|
|
692
|
+
esac
|
|
693
|
+
printf '| %s | context_rehydrate + context_session_summary | %s | %s |\n' \
|
|
694
|
+
"$v" "$result" "${DETAILS["$v:context-rehydrate"]:-—}"
|
|
695
|
+
done
|
|
696
|
+
printf '\n## Summary\n\n'
|
|
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))")"
|
|
700
|
+
} > "$REHYDRATE_REPORT_FILE"
|
|
701
|
+
log "Context probe report written to $REHYDRATE_REPORT_FILE"
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
run_cost() { # versions...
|
|
705
|
+
local versions=("$@") v fail=0
|
|
706
|
+
mkdir -p "$SANDBOX_ROOT"
|
|
707
|
+
for v in "${versions[@]}"; do
|
|
708
|
+
log "[$v] pantheon_cost offline probe ..."
|
|
709
|
+
run_cost_probe "$v"
|
|
710
|
+
log "[$v] pantheon-cost → ${RESULTS["$v:pantheon-cost"]}"
|
|
711
|
+
done
|
|
712
|
+
write_cost_report "${versions[@]}"
|
|
713
|
+
for v in "${versions[@]}"; do
|
|
714
|
+
[ "${RESULTS["$v:pantheon-cost"]:-}" = "PASS" ] || fail=$((fail + 1))
|
|
715
|
+
done
|
|
716
|
+
if [ "$fail" -gt 0 ]; then
|
|
717
|
+
log "Cost probe: $fail check(s) without explicit PASS."
|
|
718
|
+
exit 1
|
|
719
|
+
fi
|
|
720
|
+
log "Cost probe: PASS."
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
run_rehydrate() { # versions...
|
|
724
|
+
local versions=("$@") v fail=0
|
|
725
|
+
mkdir -p "$SANDBOX_ROOT"
|
|
726
|
+
for v in "${versions[@]}"; do
|
|
727
|
+
log "[$v] context_rehydrate/session_summary offline probe ..."
|
|
728
|
+
run_rehydrate_probe "$v"
|
|
729
|
+
log "[$v] context probe → ${RESULTS["$v:context-rehydrate"]}"
|
|
730
|
+
done
|
|
731
|
+
write_rehydrate_report "${versions[@]}"
|
|
732
|
+
for v in "${versions[@]}"; do
|
|
733
|
+
[ "${RESULTS["$v:context-rehydrate"]:-}" = "PASS" ] || fail=$((fail + 1))
|
|
734
|
+
done
|
|
735
|
+
if [ "$fail" -gt 0 ]; then
|
|
736
|
+
log "Context probe: $fail check(s) without explicit PASS."
|
|
737
|
+
exit 1
|
|
738
|
+
fi
|
|
739
|
+
log "Context probe: PASS."
|
|
740
|
+
}
|
|
741
|
+
|
|
498
742
|
run_battery() { # versions...
|
|
499
743
|
local versions=("$@")
|
|
500
744
|
mkdir -p "$SANDBOX_ROOT"
|
|
@@ -507,14 +751,14 @@ run_battery() { # versions...
|
|
|
507
751
|
local v fail=0 id
|
|
508
752
|
for v in "${versions[@]}"; do
|
|
509
753
|
for id in "${PROMPT_IDS[@]}" mcp-list doctor; do
|
|
510
|
-
[ "${RESULTS["$v:$id"]:-}" = "
|
|
754
|
+
[ "${RESULTS["$v:$id"]:-}" = "PASS" ] || fail=$((fail + 1))
|
|
511
755
|
done
|
|
512
756
|
done
|
|
513
757
|
if [ "$fail" -gt 0 ]; then
|
|
514
|
-
log "Prompts battery: $fail
|
|
758
|
+
log "Prompts battery: $fail check(s) without explicit PASS."
|
|
515
759
|
exit 1
|
|
516
760
|
fi
|
|
517
|
-
log "Prompts battery:
|
|
761
|
+
log "Prompts battery: PASS."
|
|
518
762
|
}
|
|
519
763
|
|
|
520
764
|
# ── Base validation (no prompts) ──────────────────────────────────────────────
|
|
@@ -535,13 +779,13 @@ run_base() { # v
|
|
|
535
779
|
check_doctor "$v"
|
|
536
780
|
log "[$v] doctor → ${RESULTS["$v:doctor"]}"
|
|
537
781
|
local fail=0
|
|
538
|
-
[ "${RESULTS["$v:mcp-list"]}" = "
|
|
539
|
-
[ "${RESULTS["$v:doctor"]}" = "
|
|
782
|
+
[ "${RESULTS["$v:mcp-list"]}" = "PASS" ] || fail=$((fail + 1))
|
|
783
|
+
[ "${RESULTS["$v:doctor"]}" = "PASS" ] || fail=$((fail + 1))
|
|
540
784
|
if [ "$fail" -gt 0 ]; then
|
|
541
|
-
log "Base validation $v: $fail
|
|
785
|
+
log "Base validation $v: $fail check(s) without explicit PASS."
|
|
542
786
|
exit 1
|
|
543
787
|
fi
|
|
544
|
-
log "Base validation $v:
|
|
788
|
+
log "Base validation $v: PASS."
|
|
545
789
|
}
|
|
546
790
|
|
|
547
791
|
# ── CLI ───────────────────────────────────────────────────────────────────────
|
|
@@ -551,6 +795,8 @@ while [ $# -gt 0 ]; do
|
|
|
551
795
|
--prepare) MODE_PREPARE=1 ;;
|
|
552
796
|
--reset) MODE_RESET=1 ;;
|
|
553
797
|
--prompts) MODE_PROMPTS=1 ;;
|
|
798
|
+
--cost) MODE_COST=1 ;;
|
|
799
|
+
--rehydrate) MODE_REHYDRATE=1 ;;
|
|
554
800
|
--run)
|
|
555
801
|
shift
|
|
556
802
|
case "${1:-}" in
|
|
@@ -569,7 +815,9 @@ if [ "$MODE_RESET" -eq 1 ]; then
|
|
|
569
815
|
exit 0
|
|
570
816
|
fi
|
|
571
817
|
|
|
572
|
-
if [ "$MODE_PREPARE" -eq 0 ] && [ -z "$RUN_VERSION" ]
|
|
818
|
+
if [ "$MODE_PREPARE" -eq 0 ] && [ -z "$RUN_VERSION" ] \
|
|
819
|
+
&& [ "$MODE_PROMPTS" -eq 0 ] && [ "$MODE_COST" -eq 0 ] \
|
|
820
|
+
&& [ "$MODE_REHYDRATE" -eq 0 ]; then
|
|
573
821
|
usage
|
|
574
822
|
fi
|
|
575
823
|
|
|
@@ -585,7 +833,30 @@ if [ -n "$RUN_VERSION" ]; then
|
|
|
585
833
|
sandbox_env
|
|
586
834
|
run_base "$RUN_VERSION"
|
|
587
835
|
fi
|
|
836
|
+
if [ "$MODE_COST" -eq 1 ]; then
|
|
837
|
+
sandbox_env
|
|
838
|
+
run_cost "$RUN_VERSION"
|
|
839
|
+
fi
|
|
840
|
+
if [ "$MODE_REHYDRATE" -eq 1 ]; then
|
|
841
|
+
sandbox_env
|
|
842
|
+
run_rehydrate "$RUN_VERSION"
|
|
843
|
+
fi
|
|
588
844
|
elif [ "$MODE_PROMPTS" -eq 1 ]; then
|
|
589
845
|
sandbox_env
|
|
590
846
|
run_battery v1 v2
|
|
847
|
+
if [ "$MODE_COST" -eq 1 ]; then
|
|
848
|
+
run_cost v1 v2
|
|
849
|
+
fi
|
|
850
|
+
if [ "$MODE_REHYDRATE" -eq 1 ]; then
|
|
851
|
+
run_rehydrate v1 v2
|
|
852
|
+
fi
|
|
853
|
+
elif [ "$MODE_COST" -eq 1 ]; then
|
|
854
|
+
sandbox_env
|
|
855
|
+
run_cost v1 v2
|
|
856
|
+
if [ "$MODE_REHYDRATE" -eq 1 ]; then
|
|
857
|
+
run_rehydrate v1 v2
|
|
858
|
+
fi
|
|
859
|
+
elif [ "$MODE_REHYDRATE" -eq 1 ]; then
|
|
860
|
+
sandbox_env
|
|
861
|
+
run_rehydrate v1 v2
|
|
591
862
|
fi
|