prizmkit 1.1.108 → 1.1.109

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 (39) hide show
  1. package/bundled/VERSION.json +3 -3
  2. package/bundled/dev-pipeline/prizmkit_runtime/cli.py +20 -0
  3. package/bundled/dev-pipeline/prizmkit_runtime/commands.py +1 -0
  4. package/bundled/dev-pipeline/prizmkit_runtime/gitops.py +21 -0
  5. package/bundled/dev-pipeline/prizmkit_runtime/interoperability.py +1 -0
  6. package/bundled/dev-pipeline/prizmkit_runtime/platform_detection.py +208 -0
  7. package/bundled/dev-pipeline/prizmkit_runtime/runtime_helper.py +508 -0
  8. package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +3 -1
  9. package/bundled/dev-pipeline/scripts/generate-bugfix-prompt.py +3 -1
  10. package/bundled/dev-pipeline/scripts/generate-refactor-prompt.py +3 -1
  11. package/bundled/dev-pipeline/scripts/prizmkit-runtime-helper.py +27 -0
  12. package/bundled/dev-pipeline/scripts/utils.py +48 -77
  13. package/bundled/dev-pipeline/templates/bootstrap-tier1.md +33 -60
  14. package/bundled/dev-pipeline/templates/bootstrap-tier2.md +35 -62
  15. package/bundled/dev-pipeline/templates/bootstrap-tier3.md +40 -66
  16. package/bundled/dev-pipeline/templates/bugfix-bootstrap-prompt.md +2 -2
  17. package/bundled/dev-pipeline/templates/refactor-bootstrap-prompt.md +2 -2
  18. package/bundled/dev-pipeline/templates/sections/checkpoint-system.md +1 -1
  19. package/bundled/dev-pipeline/templates/sections/phase-browser-verification-auto.md +31 -54
  20. package/bundled/dev-pipeline/templates/sections/phase-browser-verification-opencli.md +21 -30
  21. package/bundled/dev-pipeline/templates/sections/phase-browser-verification.md +22 -62
  22. package/bundled/dev-pipeline/templates/sections/phase-context-snapshot-base.md +1 -1
  23. package/bundled/dev-pipeline/templates/sections/phase-critic-plan-full.md +1 -1
  24. package/bundled/dev-pipeline/templates/sections/phase-critic-plan.md +1 -1
  25. package/bundled/dev-pipeline/templates/sections/phase-plan-agent.md +1 -1
  26. package/bundled/dev-pipeline/templates/sections/phase-plan-lite.md +1 -1
  27. package/bundled/dev-pipeline/templates/sections/phase-prizmkit-test.md +2 -2
  28. package/bundled/dev-pipeline/templates/sections/phase-review-agent.md +1 -1
  29. package/bundled/dev-pipeline/templates/sections/phase-review-full.md +1 -1
  30. package/bundled/dev-pipeline/templates/sections/phase-specify-plan-full.md +7 -6
  31. package/bundled/dev-pipeline/templates/sections/phase0-init.md +1 -1
  32. package/bundled/dev-pipeline/templates/sections/subagent-timeout-recovery.md +1 -1
  33. package/bundled/dev-pipeline/tests/test_generate_bootstrap_prompt.py +45 -3
  34. package/bundled/dev-pipeline/tests/test_generate_bugfix_prompt.py +2 -1
  35. package/bundled/dev-pipeline/tests/test_generate_refactor_prompt.py +2 -1
  36. package/bundled/dev-pipeline/tests/test_runtime_helper.py +211 -0
  37. package/bundled/dev-pipeline/tests/test_unified_cli.py +5 -0
  38. package/bundled/skills/_metadata.json +1 -1
  39. package/package.json +1 -1
@@ -9,8 +9,50 @@ import json
9
9
  import logging
10
10
  import os
11
11
  import re
12
+ import shlex
12
13
  import sys
13
14
 
15
+ _PIPELINE_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
16
+ if _PIPELINE_ROOT not in sys.path:
17
+ sys.path.insert(0, _PIPELINE_ROOT)
18
+
19
+
20
+ def shell_quote(value):
21
+ """Return a shell-safe token for prompt command examples."""
22
+ return shlex.quote(str(value))
23
+
24
+
25
+ def runtime_python_command():
26
+ """Return the current Python executable for rendered prompt commands."""
27
+ return shell_quote(sys.executable or "python3")
28
+
29
+
30
+ def runtime_helper_command(script_dir):
31
+ """Return the installed-project helper command prefix for prompt templates."""
32
+ helper_path = os.path.join(
33
+ ".prizmkit", "dev-pipeline", "scripts", "prizmkit-runtime-helper.py"
34
+ )
35
+ return "{} {}".format(runtime_python_command(), helper_path)
36
+
37
+
38
+ def checkpoint_python_command():
39
+ """Return the checkpoint update Python command prefix for prompt templates."""
40
+ return "{} {}".format(
41
+ runtime_python_command(),
42
+ os.path.join(".prizmkit", "dev-pipeline", "scripts", "update-checkpoint.py"),
43
+ )
44
+
45
+
46
+ def helper_replacements(script_dir):
47
+ """Return common prompt placeholders for Python runtime helpers."""
48
+ return {
49
+ "{{PYTHON_CMD}}": runtime_python_command(),
50
+ "{{RUNTIME_HELPER_CMD}}": runtime_helper_command(script_dir),
51
+ "{{CHECKPOINT_PYTHON_CMD}}": checkpoint_python_command(),
52
+ }
53
+
54
+
55
+
14
56
 
15
57
  def load_json_file(path):
16
58
  """Load and return parsed JSON from a file.
@@ -99,7 +141,7 @@ A checkpoint file tracks your progress through this workflow:
99
141
  Use this helper to update checkpoint status. Do not hand-edit `workflow-checkpoint.json` directly.
100
142
 
101
143
  ```bash
102
- python3 .prizmkit/dev-pipeline/scripts/update-checkpoint.py \\
144
+ {{CHECKPOINT_PYTHON_CMD}} \\
103
145
  --checkpoint-path {{CHECKPOINT_PATH}} \\
104
146
  --step <step-id-or-skill-name> \\
105
147
  --status <in_progress|completed|failed|skipped> \\
@@ -560,84 +602,13 @@ def enrich_global_context(global_context, project_root):
560
602
  return global_context
561
603
 
562
604
 
563
-
564
- def read_json_object(path):
565
- """Read a JSON object, returning an empty dict when unavailable."""
566
- try:
567
- with open(path, "r", encoding="utf-8") as f:
568
- data = json.load(f)
569
- except (IOError, OSError, json.JSONDecodeError):
570
- return {}
571
- return data if isinstance(data, dict) else {}
572
-
573
-
574
- def platform_from_command(command):
575
- """Map an AI CLI command/config value to a PrizmKit platform name."""
576
- cmd = str(command or "").strip().lower()
577
- if not cmd:
578
- return ""
579
- base = os.path.basename(cmd.split()[0])
580
- if base in ("claude", "claude-code") or "claude" in base:
581
- return "claude"
582
- if base in ("codex", "openai-codex") or "codex" in base:
583
- return "codex"
584
- if base in ("cbc", "codebuddy") or "codebuddy" in base:
585
- return "codebuddy"
586
- return ""
587
-
588
-
589
- def valid_prompt_platform(value):
590
- """Normalize a platform value for prompt path rendering."""
591
- value = str(value or "").strip().lower()
592
- if value in ("claude", "codex", "codebuddy"):
593
- return value
594
- return ""
595
-
596
-
597
605
  def resolve_prompt_platform(project_root):
598
- """Resolve the platform whose agent paths should appear in prompts.
599
-
600
- Explicit ``PRIZMKIT_PLATFORM`` wins. Otherwise prefer active/configured AI
601
- CLI because mixed installs contain several platform directories. Filesystem
602
- markers are only a final fallback.
603
- """
604
- explicit = valid_prompt_platform(os.environ.get("PRIZMKIT_PLATFORM", ""))
605
- if explicit:
606
- return explicit
607
-
608
- for env_name in ("AI_CLI", "CLAUDECODE", "CLAUDE_CODE"):
609
- detected = platform_from_command(os.environ.get(env_name, ""))
610
- if detected:
611
- return detected
612
-
613
- config = read_json_object(os.path.join(project_root, ".prizmkit", "config.json"))
614
- for key in ("ai_cli", "aiCli"):
615
- detected = platform_from_command(config.get(key, ""))
616
- if detected:
617
- return detected
618
- detected = valid_prompt_platform(config.get("platform", ""))
619
- if detected:
620
- return detected
621
-
622
- manifest = read_json_object(os.path.join(project_root, ".prizmkit", "manifest.json"))
623
- options = manifest.get("options", {}) if isinstance(manifest.get("options"), dict) else {}
624
- for value in (manifest.get("aiCli", ""), options.get("aiCli", "")):
625
- detected = platform_from_command(value)
626
- if detected:
627
- return detected
628
- detected = valid_prompt_platform(manifest.get("platform", ""))
629
- if detected:
630
- return detected
631
-
632
- marker_order = (
633
- ("claude", os.path.join(project_root, ".claude", "agents")),
634
- ("codex", os.path.join(project_root, ".codex", "agents")),
635
- ("codebuddy", os.path.join(project_root, ".codebuddy", "agents")),
636
- )
637
- for candidate, marker in marker_order:
638
- if os.path.isdir(marker):
639
- return candidate
606
+ """Resolve the platform whose agent paths should appear in prompts."""
607
+ from prizmkit_runtime.platform_detection import resolve_platform
640
608
 
609
+ resolution = resolve_platform(project_root)
610
+ if resolution.platform:
611
+ return resolution.platform
641
612
  raise RuntimeError(
642
613
  "PrizmKit agents not found. None of .claude/agents/, .codex/agents/, or .codebuddy/agents/ exists. "
643
614
  "Run `npx prizmkit install` first, set .prizmkit/config.json ai_cli/platform, or set PRIZMKIT_PLATFORM=claude|codex|codebuddy explicitly."
@@ -72,7 +72,7 @@ You are running in **headless non-interactive mode** with a FINITE context windo
72
72
  {{IF_INIT_NEEDED}}
73
73
  ### Phase 0: Project Bootstrap
74
74
  - Run `/prizmkit-init` (invoke the prizmkit-init skill)
75
- - Run `python3 {{INIT_SCRIPT_PATH}} --project-root {{PROJECT_ROOT}} --feature-id {{FEATURE_ID}} --feature-slug {{FEATURE_SLUG}}`
75
+ - Run `{{PYTHON_CMD}} {{INIT_SCRIPT_PATH}} --project-root {{PROJECT_ROOT}} --feature-id {{FEATURE_ID}} --feature-slug {{FEATURE_SLUG}}`
76
76
  - **CP-0**: Verify `.prizmkit/prizm-docs/root.prizm`, `.prizmkit/config.json` exist
77
77
  {{END_IF_INIT_NEEDED}}
78
78
  {{IF_INIT_DONE}}
@@ -82,16 +82,16 @@ You are running in **headless non-interactive mode** with a FINITE context windo
82
82
  ### Phase 1: Build Context Snapshot
83
83
 
84
84
  ```bash
85
- ls .prizmkit/specs/{{FEATURE_SLUG}}/context-snapshot.md 2>/dev/null && echo "EXISTS" || echo "MISSING"
85
+ {{RUNTIME_HELPER_CMD}} artifact exists .prizmkit/specs/{{FEATURE_SLUG}}/context-snapshot.md
86
86
  ```
87
87
 
88
88
  If MISSING — build it now:
89
89
  1. Read `.prizmkit/prizm-docs/root.prizm` and relevant L1 prizm docs
90
- 2. Detect source code directories: read KEY_FILES and STRUCTURE sections from `root.prizm` to identify where source code lives (e.g. `src/`, `app/`, `lib/`, `cmd/`, `packages/`, or project root). If `root.prizm` is missing, scan the project tree:
90
+ 2. Detect source code directories from KEY_FILES and STRUCTURE sections in `root.prizm`; if root docs are unavailable, use the helper to list likely source files:
91
91
  ```bash
92
- find . -maxdepth 2 -type f \( -name "*.js" -o -name "*.ts" -o -name "*.py" -o -name "*.go" -o -name "*.java" -o -name "*.rb" -o -name "*.rs" \) -not -path '*/node_modules/*' -not -path '*/.git/*' -not -path '*/dist/*' -not -path '*/build/*' -not -path '*/vendor/*' | head -30
92
+ {{RUNTIME_HELPER_CMD}} artifact source-files . --json
93
93
  ```
94
- Identify the top-level source directories from the results.
94
+ Identify the top-level source directories from the helper output.
95
95
  3. Scan the detected source directories for files related to this feature; read each one
96
96
  4. Write `.prizmkit/specs/{{FEATURE_SLUG}}/context-snapshot.md`:
97
97
  - **Section 1 — Feature Brief**: feature description + acceptance criteria (copy from above)
@@ -106,7 +106,7 @@ If MISSING — build it now:
106
106
  ### Phase 2: Plan & Tasks
107
107
 
108
108
  ```bash
109
- ls .prizmkit/specs/{{FEATURE_SLUG}}/ 2>/dev/null
109
+ {{RUNTIME_HELPER_CMD}} artifact exists .prizmkit/specs/{{FEATURE_SLUG}}
110
110
  ```
111
111
 
112
112
  If plan.md missing, run `/prizmkit-plan` with `artifact_dir=.prizmkit/specs/{{FEATURE_SLUG}}/` to generate `plan.md`:
@@ -157,7 +157,7 @@ The skill runs an internal review-fix loop (Reviewer Agent → filter → orches
157
157
  **Gate Check — Review Report**:
158
158
  After `/prizmkit-code-review` returns, verify the review report:
159
159
  ```bash
160
- grep -q "## Verdict" .prizmkit/specs/{{FEATURE_SLUG}}/review-report.md && echo "GATE:PASS" || echo "GATE:MISSING"
160
+ {{RUNTIME_HELPER_CMD}} text contains .prizmkit/specs/{{FEATURE_SLUG}}/review-report.md --pattern "## Verdict"
161
161
  ```
162
162
  If GATE:MISSING:
163
163
  - Do not re-run `/prizmkit-code-review` in an unbounded report-repair loop.
@@ -177,8 +177,8 @@ Run `/prizmkit-test scope=this-change artifact_dir=.prizmkit/specs/{{FEATURE_SLU
177
177
 
178
178
  Before invoking the skill, create a current-run marker so stale reports are ignored:
179
179
  ```bash
180
- mkdir -p .prizmkit/specs/{{FEATURE_SLUG}}
181
- touch .prizmkit/specs/{{FEATURE_SLUG}}/.prizmkit-test-started
180
+ {{RUNTIME_HELPER_CMD}} artifact ensure-dir .prizmkit/specs/{{FEATURE_SLUG}}
181
+ {{RUNTIME_HELPER_CMD}} artifact touch .prizmkit/specs/{{FEATURE_SLUG}}/.prizmkit-test-started
182
182
  ```
183
183
 
184
184
  Gate requirements:
@@ -209,13 +209,13 @@ You MUST execute this phase. Do NOT skip it.
209
209
 
210
210
  0a. Check if `playwright-cli` is installed:
211
211
  ```bash
212
- which playwright-cli 2>/dev/null && playwright-cli --version 2>/dev/null || echo "NOT_INSTALLED"
212
+ {{RUNTIME_HELPER_CMD}} executable version playwright-cli --arg=--version
213
213
  ```
214
214
  If output is `NOT_INSTALLED`, install it:
215
215
  ```bash
216
216
  npm install -g @playwright/cli@latest
217
217
  ```
218
- Then verify installation succeeded: `playwright-cli --version`. If installation fails, log `## Browser Verification: SKIPPED — playwright-cli installation failed` in context-snapshot.md and proceed to the next phase.
218
+ Then verify installation succeeded: `{{RUNTIME_HELPER_CMD}} executable version playwright-cli --arg=--version`. If installation fails, log `## Browser Verification: SKIPPED — playwright-cli installation failed` in context-snapshot.md and proceed to the next phase.
219
219
 
220
220
  0b. Learn playwright-cli usage (run once per session):
221
221
  ```bash
@@ -224,21 +224,9 @@ playwright-cli --help
224
224
 
225
225
  0c. Check if playwright-cli skill is installed for the current AI platform:
226
226
  ```bash
227
- CURRENT_PLATFORM=""
228
- if which claude >/dev/null 2>&1; then
229
- CURRENT_PLATFORM="claude"; SKILL_DIR="$HOME/.claude/skills"
230
- elif which cbc >/dev/null 2>&1; then
231
- CURRENT_PLATFORM="codebuddy"; SKILL_DIR="$HOME/.cbc/skills"
232
- else
233
- CURRENT_PLATFORM="unknown"
234
- fi
235
- if [ -d "$SKILL_DIR/playwright-cli" ] || ls "$SKILL_DIR"/playwright* 2>/dev/null | grep -q .; then
236
- echo "SKILL_EXISTS"
237
- else
238
- echo "SKILL_MISSING"
239
- fi
227
+ {{RUNTIME_HELPER_CMD}} platform skill playwright-cli --prefix
240
228
  ```
241
- If `SKILL_MISSING`: run `playwright-cli install --skills`. If current platform is NOT claude, copy installed skill from `$HOME/.claude/skills/playwright-cli` to `$SKILL_DIR/playwright-cli`.
229
+ If `SKILL_MISSING`: run `playwright-cli install --skills`. If current platform is NOT claude, copy installed skill from `$HOME/.claude/skills/playwright-cli` to the path shown by the helper output for the current platform.
242
230
 
243
231
  0d. Read the installed playwright-cli skill (SKILL.md) for workflow guidance. Use its recommended patterns to construct your verification flow.
244
232
 
@@ -247,28 +235,16 @@ If `SKILL_MISSING`: run `playwright-cli install --skills`. If current platform i
247
235
  You know this project's tech stack. Detect and start the dev server yourself:
248
236
 
249
237
  1. Identify the dev server start command from project config (`package.json` scripts, `Makefile`, `docker-compose.yml`, etc.)
250
- 2. **Detect the dev server port** use the pre-detected port from pipeline if available, otherwise extract from project config. Do NOT hardcode or guess the port:
251
- ```bash
252
- DEV_PORT={{DEV_PORT}}
253
- if [ "$DEV_PORT" = "{{DEV_PORT}}" ]; then
254
- DEV_PORT=$(node -e "const s=require('./package.json').scripts.dev; const m=s.match(/-p\s+(\d+)/); console.log(m?m[1]:'')")
255
- if [ -z "$DEV_PORT" ]; then
256
- DEV_PORT=$(echo "$NEXT_PUBLIC_SITE_URL" | sed -nE 's|.*:([0-9]+).*|\1|p')
257
- fi
258
- DEV_PORT=${DEV_PORT:-3000}
259
- fi
260
- echo "Detected DEV_PORT=$DEV_PORT"
261
- ```
238
+ 2. Determine the dev server port from the pre-detected pipeline value (`{{DEV_PORT}}`) or project config. Do NOT hardcode or guess the port. Record it as `DEV_PORT` in your notes.
262
239
  3. Verify the port is available:
263
240
  ```bash
264
- lsof -ti:$DEV_PORT 2>/dev/null && echo "PORT_IN_USE" || echo "PORT_FREE"
241
+ {{RUNTIME_HELPER_CMD}} port check $DEV_PORT
265
242
  ```
266
243
  4. Start the dev server in background, capture PID:
267
244
  ```bash
268
- <start-command> &
269
- DEV_SERVER_PID=$!
245
+ {{RUNTIME_HELPER_CMD}} process start --pid-file .prizmkit/state/browser-dev-server.pid -- <start-command tokens>
270
246
  ```
271
- 5. Wait for server to be ready: poll `http://localhost:$DEV_PORT` with `curl -s -o /dev/null -w "%{http_code}"` until it returns 200 or 302 (max 30 seconds, 2s interval)
247
+ 5. Wait for server to be ready: run `{{RUNTIME_HELPER_CMD}} web wait-ready --url http://localhost:$DEV_PORT --timeout 30 --interval 2`
272
248
  6. Open the app in playwright-cli: `playwright-cli open http://localhost:$DEV_PORT`
273
249
  7. If the page requires authentication, use playwright-cli to register a test user and log in first
274
250
 
@@ -282,8 +258,8 @@ Construct your verification workflow based on: (1) the playwright-cli skill docu
282
258
  **Step 3 — Cleanup (REQUIRED — you started it, you stop it)**:
283
259
 
284
260
  1. Close the playwright-cli browser: `playwright-cli close`
285
- 2. Kill the dev server process: `kill $DEV_SERVER_PID 2>/dev/null || true`
286
- 3. Verify port is released: `lsof -ti:$DEV_PORT | xargs kill -9 2>/dev/null || true`
261
+ 2. Kill the dev server process: `{{RUNTIME_HELPER_CMD}} process cleanup-pid <pid-from-.prizmkit/state/browser-dev-server.pid>`
262
+ 3. Verify port is released: `{{RUNTIME_HELPER_CMD}} process cleanup-port $DEV_PORT`
287
263
  {{END_IF_BROWSER_TOOL_PLAYWRIGHT}}
288
264
  {{IF_BROWSER_TOOL_OPENCLI}}
289
265
  **Using: opencli** (reuses Chrome logged-in sessions)
@@ -296,45 +272,42 @@ Construct your verification workflow based on: (1) the playwright-cli skill docu
296
272
 
297
273
  0a. Check if `opencli` is installed:
298
274
  ```bash
299
- which opencli 2>/dev/null && opencli --version 2>/dev/null || echo "NOT_INSTALLED"
275
+ {{RUNTIME_HELPER_CMD}} executable version opencli --arg=--version
300
276
  ```
301
277
  If `NOT_INSTALLED`: `npm install -g @jackwener/opencli@latest`. If installation fails, log `## Browser Verification: SKIPPED — opencli installation failed` and proceed.
302
278
 
303
279
  0b. Verify Browser Bridge: `opencli doctor`. If fails, log skip and proceed.
304
280
 
305
- 0c. Learn usage: `opencli browser --help 2>/dev/null || opencli --help`
281
+ 0c. Learn usage: `opencli browser --help`
306
282
 
307
- **Step 1 — Start Dev Server**: (same port detection as playwright path)
308
- ```bash
309
- DEV_PORT={{DEV_PORT}}
310
- if [ "$DEV_PORT" = "{{DEV_PORT}}" ]; then
311
- DEV_PORT=$(node -e "const s=require('./package.json').scripts.dev; const m=s.match(/-p\s+(\d+)/); console.log(m?m[1]:'')" 2>/dev/null)
312
- DEV_PORT=${DEV_PORT:-3000}
313
- fi
314
- ```
315
- Start server, wait for ready, then: `opencli browser open http://localhost:$DEV_PORT && opencli browser state`
283
+ **Step 1 — Start Dev Server**:
284
+ 1. Determine `DEV_PORT` from the pipeline value (`{{DEV_PORT}}`) or project config; do not guess.
285
+ 2. Verify port available: `{{RUNTIME_HELPER_CMD}} port check <DEV_PORT>`
286
+ 3. Start server: `{{RUNTIME_HELPER_CMD}} process start --pid-file .prizmkit/state/browser-dev-server.pid -- <start-command tokens>`
287
+ 4. Wait for ready: `{{RUNTIME_HELPER_CMD}} web wait-ready --url http://localhost:<DEV_PORT> --timeout 30 --interval 2`
288
+ 5. Open: `opencli browser open http://localhost:<DEV_PORT>`; then inspect: `opencli browser state`
316
289
 
317
290
  **Step 2 — Verification**:
318
291
 
319
292
  Use `opencli browser state` to discover elements with `[N]` indices, then verify:
320
293
  {{BROWSER_VERIFY_STEPS}}
321
294
 
322
- Chain commands: `opencli browser click <N> && opencli browser wait time 1 && opencli browser state`
295
+ Run page-changing commands sequentially, then run `opencli browser state` to refresh indices.
323
296
 
324
297
  **Step 3 — Cleanup**:
325
298
  1. `opencli browser close`
326
- 2. `kill $DEV_SERVER_PID 2>/dev/null || true`
327
- 3. `lsof -ti:$DEV_PORT | xargs kill -9 2>/dev/null || true`
299
+ 2. `{{RUNTIME_HELPER_CMD}} process cleanup-pid <pid-from-.prizmkit/state/browser-dev-server.pid>`
300
+ 3. `{{RUNTIME_HELPER_CMD}} process cleanup-port $DEV_PORT`
328
301
  {{END_IF_BROWSER_TOOL_OPENCLI}}
329
302
  {{IF_BROWSER_TOOL_AUTO}}
330
303
  **Tool Selection**: Choose the best browser tool at runtime.
331
304
 
332
305
  **Step 0 — Detect available tools**:
333
306
  ```bash
334
- echo "=== playwright-cli ===" && which playwright-cli 2>/dev/null && playwright-cli --version 2>/dev/null || echo "NOT_INSTALLED"
335
- echo "=== opencli ===" && which opencli 2>/dev/null && opencli --version 2>/dev/null || echo "NOT_INSTALLED"
307
+ {{RUNTIME_HELPER_CMD}} executable version playwright-cli --arg=--version
308
+ {{RUNTIME_HELPER_CMD}} executable version opencli --arg=--version
336
309
  ```
337
- If opencli installed: `opencli doctor 2>/dev/null || echo "OPENCLI_BRIDGE_FAILED"`
310
+ If opencli is installed, run `opencli doctor`. If it fails, mark OpenCLI unusable and choose playwright-cli or skip browser verification.
338
311
 
339
312
  **Decision table**:
340
313
  | Condition | Tool |
@@ -78,7 +78,7 @@ You are running in **headless non-interactive mode** with a FINITE context windo
78
78
  ## Subagent Timeout Recovery
79
79
 
80
80
  If any agent times out:
81
- 1. `ls .prizmkit/specs/{{FEATURE_SLUG}}/` — check what exists
81
+ 1. `{{RUNTIME_HELPER_CMD}} artifact list .prizmkit/specs/{{FEATURE_SLUG}}` — check what exists
82
82
  2. If `context-snapshot.md` exists: open recovery prompt with `"Read .prizmkit/specs/{{FEATURE_SLUG}}/context-snapshot.md for project context and any Implementation Log/Review Notes from previous agents. Run git diff HEAD to see actual code changes already made. Do NOT re-read individual source files unless the File Manifest directs you to."` + only remaining steps + `model: "lite"`
83
83
  3. Max 2 retries per phase. After 2 failures, orchestrator completes the work directly and appends a Recovery Note to context-snapshot.md.
84
84
 
@@ -89,7 +89,7 @@ If any agent times out:
89
89
  {{IF_INIT_NEEDED}}
90
90
  ### Phase 0: Project Bootstrap
91
91
  - Run `/prizmkit-init` (invoke the prizmkit-init skill)
92
- - Run `python3 {{INIT_SCRIPT_PATH}} --project-root {{PROJECT_ROOT}} --feature-id {{FEATURE_ID}} --feature-slug {{FEATURE_SLUG}}`
92
+ - Run `{{PYTHON_CMD}} {{INIT_SCRIPT_PATH}} --project-root {{PROJECT_ROOT}} --feature-id {{FEATURE_ID}} --feature-slug {{FEATURE_SLUG}}`
93
93
  - **CP-0**: Verify `.prizmkit/prizm-docs/root.prizm`, `.prizmkit/config.json` exist
94
94
  {{END_IF_INIT_NEEDED}}
95
95
  {{IF_INIT_DONE}}
@@ -109,16 +109,16 @@ If failure-log.md exists:
109
109
  - Do NOT delete failure-log.md until this session completes all phases and commits successfully
110
110
 
111
111
  ```bash
112
- ls .prizmkit/specs/{{FEATURE_SLUG}}/context-snapshot.md 2>/dev/null && echo "EXISTS" || echo "MISSING"
112
+ {{RUNTIME_HELPER_CMD}} artifact exists .prizmkit/specs/{{FEATURE_SLUG}}/context-snapshot.md
113
113
  ```
114
114
 
115
115
  If MISSING — build it now:
116
116
  1. Read `.prizmkit/prizm-docs/root.prizm` and relevant L1/L2 prizm docs
117
- 2. Detect source code directories: read KEY_FILES and STRUCTURE sections from `root.prizm` to identify where source code lives (e.g. `src/`, `app/`, `lib/`, `cmd/`, `packages/`, or project root). If `root.prizm` is missing, scan the project tree:
117
+ 2. Detect source code directories from KEY_FILES and STRUCTURE sections in `root.prizm`; if root docs are unavailable, use the helper to list likely source files:
118
118
  ```bash
119
- find . -maxdepth 2 -type f \( -name "*.js" -o -name "*.ts" -o -name "*.py" -o -name "*.go" -o -name "*.java" -o -name "*.rb" -o -name "*.rs" \) -not -path '*/node_modules/*' -not -path '*/.git/*' -not -path '*/dist/*' -not -path '*/build/*' -not -path '*/vendor/*' | head -30
119
+ {{RUNTIME_HELPER_CMD}} artifact source-files . --json
120
120
  ```
121
- Identify the top-level source directories from the results.
121
+ Identify the top-level source directories from the helper output.
122
122
  3. Scan the detected source directories for files related to this feature; read each one
123
123
  4. Write `.prizmkit/specs/{{FEATURE_SLUG}}/context-snapshot.md`:
124
124
  - **Section 1 — Feature Brief**: feature description + acceptance criteria (copy from above)
@@ -144,7 +144,7 @@ If MISSING — build it now:
144
144
  ### Phase 2: Plan & Tasks (you, the orchestrator)
145
145
 
146
146
  ```bash
147
- ls .prizmkit/specs/{{FEATURE_SLUG}}/plan.md 2>/dev/null
147
+ {{RUNTIME_HELPER_CMD}} artifact exists .prizmkit/specs/{{FEATURE_SLUG}}/plan.md
148
148
  ```
149
149
 
150
150
  If either missing, run `/prizmkit-plan` with `artifact_dir=.prizmkit/specs/{{FEATURE_SLUG}}/` to generate missing files:
@@ -183,7 +183,7 @@ Wait for Reviewer to return.
183
183
 
184
184
  **Guard**: Verify critic agent file exists before spawning:
185
185
  ```bash
186
- ls {{CRITIC_SUBAGENT_PATH}} 2>/dev/null && echo "CRITIC:READY" || echo "CRITIC:MISSING"
186
+ {{RUNTIME_HELPER_CMD}} artifact exists {{CRITIC_SUBAGENT_PATH}} --exists-marker CRITIC:READY --missing-marker CRITIC:MISSING
187
187
  ```
188
188
  If CRITIC:MISSING — skip Phase 3.5 entirely and proceed to Phase 4. Log: "Critic agent not installed — skipping Plan Challenge."
189
189
 
@@ -314,7 +314,7 @@ The skill runs an internal review-fix loop (Reviewer Agent → filter → orches
314
314
  **Gate Check — Review Report**:
315
315
  After `/prizmkit-code-review` returns, verify the review report:
316
316
  ```bash
317
- grep -q "## Verdict" .prizmkit/specs/{{FEATURE_SLUG}}/review-report.md && echo "GATE:PASS" || echo "GATE:MISSING"
317
+ {{RUNTIME_HELPER_CMD}} text contains .prizmkit/specs/{{FEATURE_SLUG}}/review-report.md --pattern "## Verdict"
318
318
  ```
319
319
  If GATE:MISSING:
320
320
  - Do not re-run `/prizmkit-code-review` in an unbounded report-repair loop.
@@ -334,8 +334,8 @@ Run `/prizmkit-test scope=this-change artifact_dir=.prizmkit/specs/{{FEATURE_SLU
334
334
 
335
335
  Before invoking the skill, create a current-run marker so stale reports are ignored:
336
336
  ```bash
337
- mkdir -p .prizmkit/specs/{{FEATURE_SLUG}}
338
- touch .prizmkit/specs/{{FEATURE_SLUG}}/.prizmkit-test-started
337
+ {{RUNTIME_HELPER_CMD}} artifact ensure-dir .prizmkit/specs/{{FEATURE_SLUG}}
338
+ {{RUNTIME_HELPER_CMD}} artifact touch .prizmkit/specs/{{FEATURE_SLUG}}/.prizmkit-test-started
339
339
  ```
340
340
 
341
341
  Gate requirements:
@@ -366,13 +366,13 @@ You MUST execute this phase. Do NOT skip it.
366
366
 
367
367
  0a. Check if `playwright-cli` is installed:
368
368
  ```bash
369
- which playwright-cli 2>/dev/null && playwright-cli --version 2>/dev/null || echo "NOT_INSTALLED"
369
+ {{RUNTIME_HELPER_CMD}} executable version playwright-cli --arg=--version
370
370
  ```
371
371
  If output is `NOT_INSTALLED`, install it:
372
372
  ```bash
373
373
  npm install -g @playwright/cli@latest
374
374
  ```
375
- Then verify installation succeeded: `playwright-cli --version`. If installation fails, log `## Browser Verification: SKIPPED — playwright-cli installation failed` in context-snapshot.md and proceed to the next phase.
375
+ Then verify installation succeeded: `{{RUNTIME_HELPER_CMD}} executable version playwright-cli --arg=--version`. If installation fails, log `## Browser Verification: SKIPPED — playwright-cli installation failed` in context-snapshot.md and proceed to the next phase.
376
376
 
377
377
  0b. Learn playwright-cli usage (run once per session):
378
378
  ```bash
@@ -381,21 +381,9 @@ playwright-cli --help
381
381
 
382
382
  0c. Check if playwright-cli skill is installed for the current AI platform:
383
383
  ```bash
384
- CURRENT_PLATFORM=""
385
- if which claude >/dev/null 2>&1; then
386
- CURRENT_PLATFORM="claude"; SKILL_DIR="$HOME/.claude/skills"
387
- elif which cbc >/dev/null 2>&1; then
388
- CURRENT_PLATFORM="codebuddy"; SKILL_DIR="$HOME/.cbc/skills"
389
- else
390
- CURRENT_PLATFORM="unknown"
391
- fi
392
- if [ -d "$SKILL_DIR/playwright-cli" ] || ls "$SKILL_DIR"/playwright* 2>/dev/null | grep -q .; then
393
- echo "SKILL_EXISTS"
394
- else
395
- echo "SKILL_MISSING"
396
- fi
384
+ {{RUNTIME_HELPER_CMD}} platform skill playwright-cli --prefix
397
385
  ```
398
- If `SKILL_MISSING`: run `playwright-cli install --skills`. If current platform is NOT claude, copy installed skill from `$HOME/.claude/skills/playwright-cli` to `$SKILL_DIR/playwright-cli`.
386
+ If `SKILL_MISSING`: run `playwright-cli install --skills`. If current platform is NOT claude, copy installed skill from `$HOME/.claude/skills/playwright-cli` to the path shown by the helper output for the current platform.
399
387
 
400
388
  0d. Read the installed playwright-cli skill (SKILL.md) for workflow guidance. Use its recommended patterns to construct your verification flow.
401
389
 
@@ -404,28 +392,16 @@ If `SKILL_MISSING`: run `playwright-cli install --skills`. If current platform i
404
392
  You know this project's tech stack. Detect and start the dev server yourself:
405
393
 
406
394
  1. Identify the dev server start command from project config (`package.json` scripts, `Makefile`, `docker-compose.yml`, etc.)
407
- 2. **Detect the dev server port** use the pre-detected port from pipeline if available, otherwise extract from project config. Do NOT hardcode or guess the port:
408
- ```bash
409
- DEV_PORT={{DEV_PORT}}
410
- if [ "$DEV_PORT" = "{{DEV_PORT}}" ]; then
411
- DEV_PORT=$(node -e "const s=require('./package.json').scripts.dev; const m=s.match(/-p\s+(\d+)/); console.log(m?m[1]:'')")
412
- if [ -z "$DEV_PORT" ]; then
413
- DEV_PORT=$(echo "$NEXT_PUBLIC_SITE_URL" | sed -nE 's|.*:([0-9]+).*|\1|p')
414
- fi
415
- DEV_PORT=${DEV_PORT:-3000}
416
- fi
417
- echo "Detected DEV_PORT=$DEV_PORT"
418
- ```
395
+ 2. Determine the dev server port from the pre-detected pipeline value (`{{DEV_PORT}}`) or project config. Do NOT hardcode or guess the port. Record it as `DEV_PORT` in your notes.
419
396
  3. Verify the port is available:
420
397
  ```bash
421
- lsof -ti:$DEV_PORT 2>/dev/null && echo "PORT_IN_USE" || echo "PORT_FREE"
398
+ {{RUNTIME_HELPER_CMD}} port check $DEV_PORT
422
399
  ```
423
400
  4. Start the dev server in background, capture PID:
424
401
  ```bash
425
- <start-command> &
426
- DEV_SERVER_PID=$!
402
+ {{RUNTIME_HELPER_CMD}} process start --pid-file .prizmkit/state/browser-dev-server.pid -- <start-command tokens>
427
403
  ```
428
- 5. Wait for server to be ready: poll `http://localhost:$DEV_PORT` with `curl -s -o /dev/null -w "%{http_code}"` until it returns 200 or 302 (max 30 seconds, 2s interval)
404
+ 5. Wait for server to be ready: run `{{RUNTIME_HELPER_CMD}} web wait-ready --url http://localhost:$DEV_PORT --timeout 30 --interval 2`
429
405
  6. Open the app in playwright-cli: `playwright-cli open http://localhost:$DEV_PORT`
430
406
  7. If the page requires authentication, use playwright-cli to register a test user and log in first
431
407
 
@@ -439,8 +415,8 @@ Construct your verification workflow based on: (1) the playwright-cli skill docu
439
415
  **Step 3 — Cleanup (REQUIRED — you started it, you stop it)**:
440
416
 
441
417
  1. Close the playwright-cli browser: `playwright-cli close`
442
- 2. Kill the dev server process: `kill $DEV_SERVER_PID 2>/dev/null || true`
443
- 3. Verify port is released: `lsof -ti:$DEV_PORT | xargs kill -9 2>/dev/null || true`
418
+ 2. Kill the dev server process: `{{RUNTIME_HELPER_CMD}} process cleanup-pid <pid-from-.prizmkit/state/browser-dev-server.pid>`
419
+ 3. Verify port is released: `{{RUNTIME_HELPER_CMD}} process cleanup-port $DEV_PORT`
444
420
  {{END_IF_BROWSER_TOOL_PLAYWRIGHT}}
445
421
  {{IF_BROWSER_TOOL_OPENCLI}}
446
422
  **Using: opencli** (reuses Chrome logged-in sessions)
@@ -453,45 +429,42 @@ Construct your verification workflow based on: (1) the playwright-cli skill docu
453
429
 
454
430
  0a. Check if `opencli` is installed:
455
431
  ```bash
456
- which opencli 2>/dev/null && opencli --version 2>/dev/null || echo "NOT_INSTALLED"
432
+ {{RUNTIME_HELPER_CMD}} executable version opencli --arg=--version
457
433
  ```
458
434
  If `NOT_INSTALLED`: `npm install -g @jackwener/opencli@latest`. If installation fails, log `## Browser Verification: SKIPPED — opencli installation failed` and proceed.
459
435
 
460
436
  0b. Verify Browser Bridge: `opencli doctor`. If fails, log skip and proceed.
461
437
 
462
- 0c. Learn usage: `opencli browser --help 2>/dev/null || opencli --help`
438
+ 0c. Learn usage: `opencli browser --help`
463
439
 
464
- **Step 1 — Start Dev Server**: (same port detection as playwright path)
465
- ```bash
466
- DEV_PORT={{DEV_PORT}}
467
- if [ "$DEV_PORT" = "{{DEV_PORT}}" ]; then
468
- DEV_PORT=$(node -e "const s=require('./package.json').scripts.dev; const m=s.match(/-p\s+(\d+)/); console.log(m?m[1]:'')" 2>/dev/null)
469
- DEV_PORT=${DEV_PORT:-3000}
470
- fi
471
- ```
472
- Start server, wait for ready, then: `opencli browser open http://localhost:$DEV_PORT && opencli browser state`
440
+ **Step 1 — Start Dev Server**:
441
+ 1. Determine `DEV_PORT` from the pipeline value (`{{DEV_PORT}}`) or project config; do not guess.
442
+ 2. Verify port available: `{{RUNTIME_HELPER_CMD}} port check <DEV_PORT>`
443
+ 3. Start server: `{{RUNTIME_HELPER_CMD}} process start --pid-file .prizmkit/state/browser-dev-server.pid -- <start-command tokens>`
444
+ 4. Wait for ready: `{{RUNTIME_HELPER_CMD}} web wait-ready --url http://localhost:<DEV_PORT> --timeout 30 --interval 2`
445
+ 5. Open: `opencli browser open http://localhost:<DEV_PORT>`; then inspect: `opencli browser state`
473
446
 
474
447
  **Step 2 — Verification**:
475
448
 
476
449
  Use `opencli browser state` to discover elements with `[N]` indices, then verify:
477
450
  {{BROWSER_VERIFY_STEPS}}
478
451
 
479
- Chain commands: `opencli browser click <N> && opencli browser wait time 1 && opencli browser state`
452
+ Run page-changing commands sequentially, then run `opencli browser state` to refresh indices.
480
453
 
481
454
  **Step 3 — Cleanup**:
482
455
  1. `opencli browser close`
483
- 2. `kill $DEV_SERVER_PID 2>/dev/null || true`
484
- 3. `lsof -ti:$DEV_PORT | xargs kill -9 2>/dev/null || true`
456
+ 2. `{{RUNTIME_HELPER_CMD}} process cleanup-pid <pid-from-.prizmkit/state/browser-dev-server.pid>`
457
+ 3. `{{RUNTIME_HELPER_CMD}} process cleanup-port $DEV_PORT`
485
458
  {{END_IF_BROWSER_TOOL_OPENCLI}}
486
459
  {{IF_BROWSER_TOOL_AUTO}}
487
460
  **Tool Selection**: Choose the best browser tool at runtime.
488
461
 
489
462
  **Step 0 — Detect available tools**:
490
463
  ```bash
491
- echo "=== playwright-cli ===" && which playwright-cli 2>/dev/null && playwright-cli --version 2>/dev/null || echo "NOT_INSTALLED"
492
- echo "=== opencli ===" && which opencli 2>/dev/null && opencli --version 2>/dev/null || echo "NOT_INSTALLED"
464
+ {{RUNTIME_HELPER_CMD}} executable version playwright-cli --arg=--version
465
+ {{RUNTIME_HELPER_CMD}} executable version opencli --arg=--version
493
466
  ```
494
- If opencli installed: `opencli doctor 2>/dev/null || echo "OPENCLI_BRIDGE_FAILED"`
467
+ If opencli is installed, run `opencli doctor`. If it fails, mark OpenCLI unusable and choose playwright-cli or skip browser verification.
495
468
 
496
469
  **Decision table**:
497
470
  | Condition | Tool |