pantheon-opencode 1.4.3 → 1.5.0-beta.2

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.
Files changed (99) hide show
  1. package/.pantheon/code-mode/README.md +93 -0
  2. package/.pantheon/code-mode/checkpoint-session.py +7 -0
  3. package/.pantheon/code-mode/checkpoint-session.sh +11 -0
  4. package/.pantheon/code-mode/checkpoint_session.py +481 -0
  5. package/.pantheon/code-mode/compress-inline.py +450 -0
  6. package/.pantheon/code-mode/eval-llm-judge.py +255 -0
  7. package/.pantheon/code-mode/eval-monte-carlo.py +368 -0
  8. package/.pantheon/code-mode/eval-run.py +197 -0
  9. package/.pantheon/code-mode/eval-static.py +321 -0
  10. package/.pantheon/code-mode/example-sync.sh +5 -0
  11. package/.pantheon/code-mode/session-end-save.py +186 -0
  12. package/.pantheon/code-mode/session-end-save.sh +18 -0
  13. package/.pantheon/code-mode/test-allowed.sh +5 -0
  14. package/.pantheon/code-mode/test-auto-continue-checkpoint.sh +179 -0
  15. package/.pantheon/code-mode/test-env.sh +7 -0
  16. package/.pantheon/code-mode/test-prlimit.sh +9 -0
  17. package/.pantheon/code-mode/test-timeout.sh +6 -0
  18. package/README.md +161 -1101
  19. package/README.pt-BR.md +222 -0
  20. package/bin/pantheon-init.mjs +30 -11
  21. package/opencode.json +1 -0
  22. package/package.json +14 -3
  23. package/plugin.json +15 -0
  24. package/scripts/_pantheon_paths.py +48 -7
  25. package/scripts/ci-validate-yaml.py +7 -2
  26. package/scripts/code_mode_server.py +33 -2
  27. package/scripts/cost.mjs +30 -14
  28. package/scripts/doctor.mjs +135 -127
  29. package/scripts/generate-preset-docs.mjs +127 -66
  30. package/scripts/generate-prompts.sh +2 -2
  31. package/scripts/install/cli-ui.mjs +8 -1
  32. package/scripts/install/config-migration.mjs +401 -0
  33. package/scripts/install/health-check.mjs +3 -3
  34. package/scripts/install/model-picker.mjs +72 -23
  35. package/scripts/install/opencode-version.mjs +47 -0
  36. package/scripts/install/opencode.mjs +261 -88
  37. package/scripts/install/plugin.mjs +112 -42
  38. package/scripts/install/shared.mjs +13 -158
  39. package/scripts/install-mcp.mjs +44 -232
  40. package/scripts/mcp_persistence_server.py +382 -16
  41. package/scripts/mcp_resources_server.py +144 -40
  42. package/scripts/memory_mcp_server.py +2 -2
  43. package/scripts/probe-context-rehydrate.mjs +240 -0
  44. package/scripts/probe-pantheon-cost.mjs +304 -0
  45. package/scripts/recover-zenodo-deposition.mjs +146 -0
  46. package/scripts/sync-tui.mjs +32 -7
  47. package/scripts/test-opencode-v1-v2-sandbox.sh +944 -0
  48. package/scripts/uninstall.mjs +298 -954
  49. package/scripts/validate-zenodo-release.mjs +154 -0
  50. package/scripts/zenodo-artifact.mjs +21 -0
  51. package/scripts/zenodo-release-state.mjs +53 -0
  52. package/src/agents/zeus.md +25 -14
  53. package/src/mcp/_pantheon_paths.py +48 -7
  54. package/src/mcp/code_mode_server.py +33 -2
  55. package/src/mcp/eval_store.py +1 -1
  56. package/src/mcp/mcp_persistence_server.py +382 -16
  57. package/src/mcp/mcp_resources_server.py +144 -40
  58. package/src/mcp/pantheon_vision_server.py +1 -1
  59. package/src/mcp/toon_codec.py +491 -0
  60. package/src/pantheon/background-job-board.ts +67 -1
  61. package/src/pantheon/cost-command.ts +60 -39
  62. package/src/pantheon/delegate-manager.ts +669 -0
  63. package/src/pantheon/delegation-classifier.ts +307 -0
  64. package/src/pantheon/delegation-enforce.ts +13 -12
  65. package/src/pantheon/delegation-finalize.ts +374 -0
  66. package/src/pantheon/delegation-notify.ts +212 -0
  67. package/src/pantheon/delegation-toast.ts +73 -0
  68. package/src/pantheon/delegation.ts +1120 -0
  69. package/src/pantheon/goal-loop.ts +2 -2
  70. package/src/pantheon/goal-store.ts +1 -1
  71. package/src/pantheon/hashline/tool.ts +2 -2
  72. package/src/pantheon/model-command.ts +2 -1
  73. package/src/pantheon/permission-eval.ts +284 -0
  74. package/src/pantheon/step-cap.ts +110 -0
  75. package/src/pantheon/token-opt.ts +781 -0
  76. package/src/pantheon/toon-codec.ts +481 -0
  77. package/src/pantheon/tui-version-check.ts +1 -3
  78. package/src/pantheon/v2-bridge.ts +129 -0
  79. package/src/pantheon/v2-events.ts +131 -0
  80. package/src/pantheon/v2-hooks.ts +287 -0
  81. package/src/pantheon/v2-tool-definitions.ts +331 -0
  82. package/src/pantheon/zeus-delegate-with-retry.ts +406 -0
  83. package/src/plugin-v2/index.ts +21 -0
  84. package/src/plugin-v2.ts +824 -0
  85. package/src/plugin.ts +236 -42
  86. package/src/plugins/tui/dist/server.d.ts +1 -1
  87. package/src/plugins/tui/dist/server.d.ts.map +1 -1
  88. package/src/plugins/tui/dist/server.js +1 -1
  89. package/src/plugins/tui/dist/server.js.map +1 -1
  90. package/src/plugins/tui/dist/tui.d.ts +10 -7
  91. package/src/plugins/tui/dist/tui.d.ts.map +1 -1
  92. package/src/plugins/tui/dist/tui.js +11 -8
  93. package/src/plugins/tui/dist/tui.js.map +1 -1
  94. package/src/plugins/tui/dist/tui.tsx +22 -16
  95. package/src/plugins/tui/package-lock.json +51 -51
  96. package/src/plugins/tui/package.json +7 -7
  97. package/src/plugins/tui/src/index.tsx +28 -24
  98. package/src/skills/README.md +0 -2
  99. package/src/pantheon/tool-context.ts +0 -41
@@ -0,0 +1,186 @@
1
+ #!/usr/bin/env python3
2
+ """Session-end save — exports Vector DB entries to timestamped backup."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import argparse
7
+ import json
8
+ import os
9
+ import subprocess
10
+ import sys
11
+ from datetime import UTC, datetime
12
+ from pathlib import Path
13
+
14
+ # Bootstrap: resolve PANTHEON_HOME before _pantheon_paths is available
15
+ _home_env = os.environ.get("PANTHEON_HOME")
16
+ if _home_env:
17
+ _BOOT_HOME = Path(_home_env).expanduser().resolve()
18
+ else:
19
+ _xdg = os.environ.get("XDG_CONFIG_HOME")
20
+ _BOOT_HOME = (
21
+ Path(_xdg).expanduser().resolve() / "opencode"
22
+ if _xdg
23
+ else Path.home() / ".config" / "opencode"
24
+ )
25
+ sys.path.insert(0, str(_BOOT_HOME / "scripts"))
26
+
27
+ from _pantheon_paths import pantheon_home, pantheon_project
28
+ _PROJECT = pantheon_project()
29
+ if _PROJECT is None:
30
+ print("ERROR: PANTHEON_PROJECT not set and CWD unavailable")
31
+ sys.exit(1)
32
+ PROJECT_ROOT: Path = _PROJECT
33
+ OUTPUT_DIR: Path = PROJECT_ROOT / ".pantheon" / "memory-bank" / ".tmp"
34
+
35
+
36
+ def parse_args() -> argparse.Namespace:
37
+ parser = argparse.ArgumentParser(description="Session-end memory save")
38
+ parser.add_argument("--dry-run", action="store_true", help="Preview without saving")
39
+ parser.add_argument("--agent", default="unknown", help="Agent name triggering save")
40
+ return parser.parse_args()
41
+
42
+
43
+ def detect_agent(args_agent: str) -> str:
44
+ """Return agent name: CLI arg first, then env/fallback."""
45
+ if args_agent and args_agent != "unknown":
46
+ return args_agent
47
+ # Fall back to env var
48
+ from_env = sys.argv[0]
49
+ for candidate in ("zeus", "hermes", "aphrodite", "demeter",
50
+ "themis", "apollo", "athena", "talos",
51
+ "prometheus", "hephaestus", "iris",
52
+ "nyx", "gaia", "mnemosyne"):
53
+ if candidate in from_env.lower():
54
+ return candidate
55
+ return "unknown"
56
+
57
+
58
+ def try_export_memory() -> list[dict] | None:
59
+ """Try to export entries from pantheon-memory via MCP.
60
+
61
+ Tries three strategies:
62
+ 1. Import memory_mcp_server module and call export directly
63
+ 2. If ChromaDB unavailable, create placeholder (no crash)
64
+
65
+ Returns list of dicts with keys: content, importance, category, session_id
66
+ Returns None if absolutely unavailable (MCP down, no data).
67
+ Client-side filtering by importance >= 0.4.
68
+ """
69
+ # Strategy 1: Try direct module import
70
+ sys.path.insert(0, str(pantheon_home() / "scripts"))
71
+ try:
72
+ import vector_memory.index as vmi
73
+ # Use memory_sessions-like approach via ChromaDB
74
+ import chromadb
75
+ db_path = pantheon_home() / "memory" / "chroma_db"
76
+ if db_path.exists():
77
+ client = chromadb.PersistentClient(str(db_path))
78
+ collection = client.get_or_create_collection("pantheon_memory")
79
+ results = collection.get()
80
+ if results["ids"]:
81
+ entries = []
82
+ for i, doc_id in enumerate(results["ids"]):
83
+ meta = results["metadatas"][i] if results["metadatas"] else {}
84
+ doc = results["documents"][i] if results["documents"] else ""
85
+ entries.append({
86
+ "id": doc_id,
87
+ "content": doc[:200] if doc else "",
88
+ "importance": meta.get("importance", 0.5),
89
+ "category": meta.get("category", "memory"),
90
+ "session_id": meta.get("session_id", ""),
91
+ "agent": meta.get("agent", "unknown"),
92
+ })
93
+ # Client-side filter by importance >= 0.4
94
+ filtered = [e for e in entries if e["importance"] >= 0.4]
95
+ if filtered:
96
+ return filtered
97
+ # If we have entries but all below threshold, don't return None
98
+ # (means MCP is working, just no high-importance entries yet)
99
+ return []
100
+ except ImportError:
101
+ pass
102
+ except Exception as e:
103
+ print(f" (MCP export note: {e})")
104
+ pass
105
+
106
+ # Strategy 2: MCP unavailable — return None (caller handles placeholder)
107
+ return None
108
+
109
+
110
+ def write_session_save(entries: list[dict], agent: str, dry_run: bool = False) -> Path | None:
111
+ """Write session save file. Returns path if written, None if dry-run."""
112
+ timestamp = datetime.now(UTC).strftime("%Y%m%d-%H%M%S")
113
+ filename = f"session-save-{timestamp}.md"
114
+ filepath = OUTPUT_DIR / filename
115
+
116
+ if dry_run:
117
+ print(f"[dry-run] Would save to: {filepath}")
118
+ print(f"[dry-run] Entries: {len(entries)} from agent '{agent}'")
119
+ return None
120
+
121
+ OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
122
+
123
+ lines = [
124
+ f"# Session Save — {timestamp}",
125
+ f"**Agent:** {agent}",
126
+ f"**Entries:** {len(entries)}",
127
+ "",
128
+ "## Entries",
129
+ ]
130
+
131
+ if not entries:
132
+ lines.append("*(No entries with importance >= 0.4)*")
133
+ else:
134
+ for entry in entries:
135
+ content = entry.get("content", "—")
136
+ importance = entry.get("importance", 0)
137
+ category = entry.get("category", "memory")
138
+ lines.append(f"- [{importance:.1f}] ({category}) {content[:200]}")
139
+
140
+ filepath.write_text("\n".join(lines) + "\n")
141
+ print(f" Saved {len(entries)} entries to {filepath}")
142
+ return filepath
143
+
144
+
145
+ def update_deepwork_status(entries_count: int, agent: str) -> None:
146
+ """Append save record to active deepwork STATUS.md if found."""
147
+ deepwork_dir = PROJECT_ROOT / ".pantheon" / "deepwork"
148
+ if not deepwork_dir.exists():
149
+ return
150
+ for status_file in sorted(deepwork_dir.glob("*/STATUS.md")):
151
+ timestamp = datetime.now(UTC).strftime("%Y-%m-%d %H:%M")
152
+ line = f"- {timestamp}: Session save — {entries_count} entries (agent: {agent})"
153
+ with open(status_file, "a") as f:
154
+ f.write(f"{line}\n")
155
+ print(f" Updated {status_file}")
156
+
157
+
158
+ def main() -> None:
159
+ args = parse_args()
160
+ agent = detect_agent(args.agent)
161
+
162
+ print(f"Running session-end save (agent: {agent})")
163
+
164
+ if args.dry_run:
165
+ print(" --dry-run mode — no files will be written")
166
+
167
+ entries = try_export_memory()
168
+
169
+ if entries is None:
170
+ print(" pantheon-memory unavailable. Writing placeholder.")
171
+ entries = []
172
+
173
+ path = write_session_save(entries, agent, dry_run=args.dry_run)
174
+
175
+ if path and not args.dry_run:
176
+ update_deepwork_status(len(entries), agent)
177
+
178
+ print()
179
+ print(f" Agent: {agent}")
180
+ print(f" Entries: {len(entries)}")
181
+ print(f" Dry-run: {args.dry_run}")
182
+ print("Session-end save complete.")
183
+
184
+
185
+ if __name__ == "__main__":
186
+ main()
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env bash
2
+ # Wrapper for session-end-save.py
3
+ # Usage: ./session-end-save.sh [agent_name] [--dry-run]
4
+ #
5
+ # Persists Vector DB entries to a timestamped backup file in
6
+ # .pantheon/memory-bank/.tmp/ with client-side importance filtering.
7
+ #
8
+ # Arguments:
9
+ # agent_name — name of the agent triggering the save (default: unknown)
10
+ # --dry-run — preview without writing
11
+
12
+ set -euo pipefail
13
+
14
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
15
+ AGENT="${1:-unknown}"
16
+ shift || true
17
+
18
+ python3 "$SCRIPT_DIR/session-end-save.py" --agent "$AGENT" "$@"
@@ -0,0 +1,5 @@
1
+ #!/bin/bash
2
+ # ---
3
+ # allowed_args: [foo, bar]
4
+ # ---
5
+ echo $*
@@ -0,0 +1,179 @@
1
+ #!/bin/bash
2
+ # Test: auto-continue-checkpoint.sh
3
+ # Validates the checkpoint script creates checkpoints and heartbeat files correctly.
4
+ # Usage: bash .pantheon/code-mode/test-auto-continue-checkpoint.sh
5
+
6
+ set -euo pipefail
7
+
8
+ TEST_DIR="$(mktemp -d)/test-auto-continue"
9
+ trap 'rm -rf "$TEST_DIR"' EXIT
10
+ SCRIPT=".pantheon/code-mode/auto-continue-checkpoint.sh"
11
+
12
+ # Ensure script exists
13
+ if [ ! -f "$SCRIPT" ]; then
14
+ echo "❌ FAIL: $SCRIPT not found"
15
+ exit 1
16
+ fi
17
+
18
+ echo "=== RED: Testing checkpoint script ==="
19
+
20
+ # 1. Create a deepwork directory with a STATUS.md
21
+ DEEPDIR="$TEST_DIR/test-slug"
22
+ mkdir -p "$DEEPDIR"
23
+ cat > "$DEEPDIR/STATUS.md" << 'EOF'
24
+ # STATUS — test-slug
25
+ **Date:** 2026-07-16T20:00:00Z
26
+ **Phase:** 2
27
+ **Turns:** 15
28
+ **Status:** In Progress
29
+ EOF
30
+
31
+ # 2. Run the checkpoint script targeting our test directory
32
+ # We need to run from repo root and use SLUG that maps to our test dir
33
+ # The script uses .pantheon/deepwork/<slug>, so we need to symlink or override
34
+ # Strategy: create a temporary .pantheon/deepwork/test-slug dir
35
+ # Resolve the repo/runtime root from this script's location so the test never
36
+ # depends on a hardcoded checkout path (the tarball must be machine-path-free).
37
+ REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")/../.." && pwd)"
38
+ mkdir -p "$REPO_ROOT/.pantheon/deepwork/test-slug"
39
+
40
+ # Copy STATUS.md into the real deepwork path
41
+ cp "$DEEPDIR/STATUS.md" "$REPO_ROOT/.pantheon/deepwork/test-slug/STATUS.md"
42
+
43
+ # Run the actual script
44
+ bash "$REPO_ROOT/$SCRIPT" "test-slug"
45
+
46
+ # 3. VERIFY: checkpoint file created in the real deepwork path
47
+ if [ ! -f "$REPO_ROOT/.pantheon/deepwork/test-slug/checkpoint-1.json" ]; then
48
+ echo "❌ FAIL: checkpoint-1.json not created"
49
+ # Cleanup
50
+ rm -rf "$REPO_ROOT/.pantheon/deepwork/test-slug"
51
+ rm -rf "$TEST_DIR"
52
+ exit 1
53
+ fi
54
+ echo " ✅ checkpoint-1.json created"
55
+
56
+ # 4. VERIFY: heartbeat file created
57
+ if [ ! -f "$REPO_ROOT/.pantheon/deepwork/test-slug/heartbeat.json" ]; then
58
+ echo "❌ FAIL: heartbeat.json not created"
59
+ rm -rf "$REPO_ROOT/.pantheon/deepwork/test-slug"
60
+ rm -rf "$TEST_DIR"
61
+ exit 1
62
+ fi
63
+ echo " ✅ heartbeat.json created"
64
+
65
+ # 5. VERIFY: checkpoint content is valid JSON
66
+ if ! jq empty "$REPO_ROOT/.pantheon/deepwork/test-slug/checkpoint-1.json" 2>/dev/null; then
67
+ echo "❌ FAIL: checkpoint-1.json is not valid JSON"
68
+ rm -rf "$REPO_ROOT/.pantheon/deepwork/test-slug"
69
+ rm -rf "$TEST_DIR"
70
+ exit 1
71
+ fi
72
+ echo " ✅ checkpoint-1.json is valid JSON"
73
+
74
+ # 6. VERIFY: heartbeat content is valid JSON
75
+ if ! jq empty "$REPO_ROOT/.pantheon/deepwork/test-slug/heartbeat.json" 2>/dev/null; then
76
+ echo "❌ FAIL: heartbeat.json is not valid JSON"
77
+ rm -rf "$REPO_ROOT/.pantheon/deepwork/test-slug"
78
+ rm -rf "$TEST_DIR"
79
+ exit 1
80
+ fi
81
+ echo " ✅ heartbeat.json is valid JSON"
82
+
83
+ # 7. VERIFY: checkpoint fields
84
+ SLUG_CHECK=$(jq -r '.slug' "$REPO_ROOT/.pantheon/deepwork/test-slug/checkpoint-1.json")
85
+ PHASE_CHECK=$(jq -r '.phase' "$REPO_ROOT/.pantheon/deepwork/test-slug/checkpoint-1.json")
86
+ TURNS_CHECK=$(jq -r '.turn_count' "$REPO_ROOT/.pantheon/deepwork/test-slug/checkpoint-1.json")
87
+
88
+ if [ "$SLUG_CHECK" != "test-slug" ]; then
89
+ echo "❌ FAIL: slug mismatch: got '$SLUG_CHECK'"
90
+ rm -rf "$REPO_ROOT/.pantheon/deepwork/test-slug"
91
+ rm -rf "$TEST_DIR"
92
+ exit 1
93
+ fi
94
+ echo " ✅ checkpoint slug = '$SLUG_CHECK'"
95
+
96
+ if [ "$PHASE_CHECK" != "2" ]; then
97
+ echo "❌ FAIL: phase mismatch: got '$PHASE_CHECK'"
98
+ rm -rf "$REPO_ROOT/.pantheon/deepwork/test-slug"
99
+ rm -rf "$TEST_DIR"
100
+ exit 1
101
+ fi
102
+ echo " ✅ checkpoint phase = $PHASE_CHECK"
103
+
104
+ if [ "$TURNS_CHECK" != "15" ]; then
105
+ echo "❌ FAIL: turn_count mismatch: got '$TURNS_CHECK'"
106
+ rm -rf "$REPO_ROOT/.pantheon/deepwork/test-slug"
107
+ rm -rf "$TEST_DIR"
108
+ exit 1
109
+ fi
110
+ echo " ✅ checkpoint turn_count = $TURNS_CHECK"
111
+
112
+ # 8. VERIFY: heartbeat fields
113
+ HB_SLUG=$(jq -r '.slug' "$REPO_ROOT/.pantheon/deepwork/test-slug/heartbeat.json")
114
+ HB_STATUS=$(jq -r '.status' "$REPO_ROOT/.pantheon/deepwork/test-slug/heartbeat.json")
115
+
116
+ if [ "$HB_SLUG" != "test-slug" ]; then
117
+ echo "❌ FAIL: heartbeat slug mismatch: got '$HB_SLUG'"
118
+ rm -rf "$REPO_ROOT/.pantheon/deepwork/test-slug"
119
+ rm -rf "$TEST_DIR"
120
+ exit 1
121
+ fi
122
+ echo " ✅ heartbeat slug = '$HB_SLUG'"
123
+
124
+ if [ "$HB_STATUS" != "alive" ]; then
125
+ echo "❌ FAIL: heartbeat status mismatch: got '$HB_STATUS'"
126
+ rm -rf "$REPO_ROOT/.pantheon/deepwork/test-slug"
127
+ rm -rf "$TEST_DIR"
128
+ exit 1
129
+ fi
130
+ echo " ✅ heartbeat status = '$HB_STATUS'"
131
+
132
+ # 9. VERIFY: running a second time creates checkpoint-2.json
133
+ bash "$REPO_ROOT/$SCRIPT" "test-slug"
134
+
135
+ if [ ! -f "$REPO_ROOT/.pantheon/deepwork/test-slug/checkpoint-2.json" ]; then
136
+ echo "❌ FAIL: checkpoint-2.json not created on second run"
137
+ rm -rf "$REPO_ROOT/.pantheon/deepwork/test-slug"
138
+ rm -rf "$TEST_DIR"
139
+ exit 1
140
+ fi
141
+ echo " ✅ checkpoint-2.json created (auto-increment works)"
142
+
143
+ # 10. VERIFY: second checkpoint has updated heartbeat
144
+ HB_TIMESTAMP=$(jq -r '.last_action' "$REPO_ROOT/.pantheon/deepwork/test-slug/heartbeat.json")
145
+ if [ -z "$HB_TIMESTAMP" ]; then
146
+ echo "❌ FAIL: heartbeat timestamp empty after second run"
147
+ rm -rf "$REPO_ROOT/.pantheon/deepwork/test-slug"
148
+ rm -rf "$TEST_DIR"
149
+ exit 1
150
+ fi
151
+ echo " ✅ heartbeat timestamp updated = '$HB_TIMESTAMP'"
152
+
153
+ # 11. VERIFY: without STATUS.md, script still works (defaults to 0)
154
+ bash "$REPO_ROOT/$SCRIPT" "empty-test"
155
+ if [ ! -f "$REPO_ROOT/.pantheon/deepwork/empty-test/checkpoint-1.json" ]; then
156
+ echo "❌ FAIL: checkpoint not created for slug without STATUS.md"
157
+ rm -rf "$REPO_ROOT/.pantheon/deepwork/empty-test"
158
+ rm -rf "$REPO_ROOT/.pantheon/deepwork/test-slug"
159
+ rm -rf "$TEST_DIR"
160
+ exit 1
161
+ fi
162
+
163
+ PHASE_DEFAULT=$(jq -r '.phase' "$REPO_ROOT/.pantheon/deepwork/empty-test/checkpoint-1.json")
164
+ if [ "$PHASE_DEFAULT" != "0" ]; then
165
+ echo "❌ FAIL: phase should default to 0 without STATUS.md, got '$PHASE_DEFAULT'"
166
+ rm -rf "$REPO_ROOT/.pantheon/deepwork/empty-test"
167
+ rm -rf "$REPO_ROOT/.pantheon/deepwork/test-slug"
168
+ rm -rf "$TEST_DIR"
169
+ exit 1
170
+ fi
171
+ echo " ✅ checkpoint works without STATUS.md (phase=0 default)"
172
+
173
+ # Cleanup all test artifacts
174
+ rm -rf "$REPO_ROOT/.pantheon/deepwork/test-slug"
175
+ rm -rf "$REPO_ROOT/.pantheon/deepwork/empty-test"
176
+ rm -rf "$TEST_DIR"
177
+
178
+ echo ""
179
+ echo "=== ✅ ALL CHECKPOINT TESTS PASSED ==="
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ # ---
3
+ # timeout: 5
4
+ # ---
5
+ env | wc -l
6
+ echo "---"
7
+ env | sort
@@ -0,0 +1,9 @@
1
+ #!/bin/bash
2
+ # ---
3
+ # timeout: 5
4
+ # ---
5
+ echo "pid: $$"
6
+ cat /proc/self/limits | grep -E "Max cpu|Max address|Max processes" 2>&1 | head -n 5
7
+ echo "--- prlimit in cmd check ---"
8
+ # Show that prlimit limits are applied: prlimit --cpu=10 should show cpu 10
9
+ prlimit --output RESOURCE,SOFT,HARD 2>&1 | head -n 20
@@ -0,0 +1,6 @@
1
+ #!/bin/bash
2
+ # ---
3
+ # timeout: 2
4
+ # ---
5
+ sleep 10
6
+ echo "should not reach"