prizmkit 1.1.108 → 1.1.110

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 (46) 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 +44 -71
  14. package/bundled/dev-pipeline/templates/bootstrap-tier2.md +48 -75
  15. package/bundled/dev-pipeline/templates/bootstrap-tier3.md +52 -78
  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/context-budget-rules.md +8 -8
  20. package/bundled/dev-pipeline/templates/sections/phase-browser-verification-auto.md +33 -55
  21. package/bundled/dev-pipeline/templates/sections/phase-browser-verification-opencli.md +28 -33
  22. package/bundled/dev-pipeline/templates/sections/phase-browser-verification.md +22 -62
  23. package/bundled/dev-pipeline/templates/sections/phase-commit-full.md +2 -2
  24. package/bundled/dev-pipeline/templates/sections/phase-commit.md +1 -1
  25. package/bundled/dev-pipeline/templates/sections/phase-context-snapshot-base.md +1 -1
  26. package/bundled/dev-pipeline/templates/sections/phase-critic-plan-full.md +1 -1
  27. package/bundled/dev-pipeline/templates/sections/phase-critic-plan.md +1 -1
  28. package/bundled/dev-pipeline/templates/sections/phase-implement-agent.md +1 -1
  29. package/bundled/dev-pipeline/templates/sections/phase-implement-full.md +1 -1
  30. package/bundled/dev-pipeline/templates/sections/phase-plan-agent.md +1 -1
  31. package/bundled/dev-pipeline/templates/sections/phase-plan-lite.md +1 -1
  32. package/bundled/dev-pipeline/templates/sections/phase-prizmkit-test.md +2 -2
  33. package/bundled/dev-pipeline/templates/sections/phase-review-agent.md +1 -1
  34. package/bundled/dev-pipeline/templates/sections/phase-review-full.md +1 -1
  35. package/bundled/dev-pipeline/templates/sections/phase-specify-plan-full.md +7 -6
  36. package/bundled/dev-pipeline/templates/sections/phase0-init.md +1 -1
  37. package/bundled/dev-pipeline/templates/sections/subagent-timeout-recovery.md +1 -1
  38. package/bundled/dev-pipeline/templates/sections/test-failure-recovery-agent.md +1 -1
  39. package/bundled/dev-pipeline/templates/sections/test-failure-recovery-lite.md +1 -1
  40. package/bundled/dev-pipeline/tests/test_generate_bootstrap_prompt.py +152 -3
  41. package/bundled/dev-pipeline/tests/test_generate_bugfix_prompt.py +2 -1
  42. package/bundled/dev-pipeline/tests/test_generate_refactor_prompt.py +2 -1
  43. package/bundled/dev-pipeline/tests/test_runtime_helper.py +211 -0
  44. package/bundled/dev-pipeline/tests/test_unified_cli.py +5 -0
  45. package/bundled/skills/_metadata.json +1 -1
  46. 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."
@@ -46,15 +46,15 @@ You are running in **headless non-interactive mode** with a FINITE context windo
46
46
 
47
47
  1. **context-snapshot.md is your single source of truth** — After Phase 1 builds it, ALWAYS read context-snapshot.md instead of re-reading individual source files
48
48
  2. **Never re-read your own writes** — After you create/modify a file, do NOT read it back to verify. Trust your write was correct.
49
- 3. **Never re-read unmodified files** — Once you have read a file into context, do NOT read it again unless it was modified by an Edit/Write operation after your last read. Use `grep -n '<pattern>' <file>` or `sed -n '<start>,<end>p' <file>` for targeted line lookups instead of full-file Read. Before issuing a Read, ask yourself: "Have I read this file before, and has it changed since?" If the answer is "no, it hasn't changed" — do NOT read it. This applies to all files including those summarized in context-snapshot.md Section 4. Subagents (Critic, Reviewer) must receive context-snapshot.md and rely on it rather than independently re-reading the same files the orchestrator already read.
49
+ 3. **Never re-read unmodified files** — Once you have read a file into context, do NOT read it again unless it was modified by an Edit/Write operation after your last read. Use platform file/search tools for targeted lookup; when shell-free helper lookup is needed, run `{{RUNTIME_HELPER_CMD}} text search <file> --pattern "<pattern>" --json`, then read only the smallest bounded range with the platform file-reading tool instead of full-file Read. Before issuing a Read, ask yourself: "Have I read this file before, and has it changed since?" If the answer is "no, it hasn't changed" — do NOT read it. This applies to all files including those summarized in context-snapshot.md Section 4. Subagents (Critic, Reviewer) must receive context-snapshot.md and rely on it rather than independently re-reading the same files the orchestrator already read.
50
50
  4. **Stay focused** — Do NOT explore code unrelated to this feature. No curiosity-driven reads.
51
51
  4. **One task at a time** — In Phase 3 (implement), complete and test one task before starting the next.
52
- 5. **Minimize tool output** — Never load full command output into context. First capture to a temp file (`cmd 2>&1 | tee /tmp/out.txt | tail -20`), then scan the head/tail to identify relevant fields, and use targeted filtering (`grep`, `sed`, `awk`) to extract only the information needed for the current task. Only read the filtered result — never the raw full output.
52
+ 5. **Minimize tool output** — Never load full command output into context. First capture command output to a temp file using the command/tool output option or the host-appropriate redirection, then inspect only the final relevant lines and use targeted search helpers to extract the information needed for the current task. Only read the filtered result — never the raw full output.
53
53
  6. **No intermediate commits** — Do NOT run `git add`/`git commit` during Phase 1-3. All changes are committed once at the end in Phase 4 via `/prizmkit-committer`.
54
- 7. **Capture test output once** — When running test suites, always use `<test-command> 2>&1 | tee /tmp/test-out.txt | tail -20`. Then grep `/tmp/test-out.txt` for details. Never re-run the suite just to apply a different filter.
54
+ 7. **Capture test output once** — When running test suites, capture output once to `/tmp/test-out.txt` using the command/tool output option or the host-appropriate redirection, surface only the final relevant lines, then search `/tmp/test-out.txt` for details. Never re-run the suite just to apply a different filter.
55
55
  9. **Package version verification (BLOCKING)** — Before writing ANY dependency version, verify it exists via registry query (`npm view <pkg> dist-tags.latest`, `pip index versions <pkg>`, etc.). NEVER guess version numbers.
56
56
  10. **Build artifact hygiene** — After build/compile, ensure output is in `.gitignore`. Never commit binaries/build output.
57
- 11. **Read offset safety (BLOCKING)** — If Read returns "shorter than offset"/"File is empty"/"Wasted call" — do NOT retry same offset. Run `wc -l <file>` to get real line count, then `sed -n` for exact range. 2 consecutive offset errors → STOP Reading that file. Never guess offsets `grep -n '<anchor>'` first.
57
+ 11. **Read offset safety (BLOCKING)** — If Read returns "shorter than offset"/"File is empty"/"Wasted call" — do NOT retry same offset. Use the platform file-reading tool to refresh bounded line information, or locate an anchor with `{{RUNTIME_HELPER_CMD}} text search <file> --pattern "<anchor>" --json` before reading a small bounded range. 2 consecutive offset errors → STOP Reading that file. Never guess offsets or prescribe POSIX-only lookup commands.
58
58
 
59
59
  ---
60
60
 
@@ -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,22 +82,22 @@ 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)
98
- - **Section 2 — Project Structure**: run the following to get a visual directory tree, then paste output:
98
+ - **Section 2 — Project Structure**: run the helper to get a visual directory tree, then paste output:
99
99
  ```bash
100
- find . -maxdepth 2 -type d -not -path '*/node_modules/*' -not -path '*/.git/*' -not -path '*/dist/*' -not -path '*/build/*' -not -path '*/__pycache__/*' -not -path '*/vendor/*' | sed -e 's;[^/]*/;|____;g;s;____|; |;g'
100
+ {{RUNTIME_HELPER_CMD}} artifact tree . --max-depth 2
101
101
  ```
102
102
  - **Section 3 — Prizm Context**: content of root.prizm and relevant L1/L2 docs
103
103
  - **Section 4 — Existing Source Files**: **full verbatim content** of each related file in fenced code blocks (with `### path/to/file` heading and line count). Include ALL files needed for implementation and review — downstream phases read this section instead of re-reading individual source files
@@ -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`:
@@ -126,9 +126,9 @@ Before proceeding past CP-1:
126
126
  **Build artifacts**: After any build/compile command (`go build`, `npm run build`, `tsc`, etc.), ensure the output binary or build directory is in `.gitignore`:
127
127
  ```bash
128
128
  # Example for Go
129
- grep -q '^/binary-name$' .gitignore || echo '/binary-name' >> .gitignore
129
+ {{RUNTIME_HELPER_CMD}} text contains .gitignore --pattern "/binary-name" --found-marker IGNORED --missing-marker NEEDS_IGNORE_ENTRY
130
130
  ```
131
- Never commit compiled binaries, build output, or generated artifacts.
131
+ If the helper prints `NEEDS_IGNORE_ENTRY`, edit `.gitignore` and add `/binary-name` as a single line. Never commit compiled binaries, build output, or generated artifacts.
132
132
 
133
133
  **3a.** Run `/prizmkit-implement` — this handles the implementation cycle:
134
134
  - Reads plan.md Tasks section from `.prizmkit/specs/{{FEATURE_SLUG}}/`
@@ -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 the installed skill from the Claude user skills directory 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,29 +235,17 @@ 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)
272
- 6. Open the app in playwright-cli: `playwright-cli open http://localhost:$DEV_PORT`
247
+ 5. Wait for server to be ready: run `{{RUNTIME_HELPER_CMD}} web wait-ready --url http://localhost:{{DEV_PORT}} --timeout 30 --interval 2`
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
 
275
251
  **Step 2 — Verification**:
@@ -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}} port check {{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}} port check {{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 |
@@ -355,7 +328,7 @@ Append results to `context-snapshot.md`:
355
328
  ```
356
329
  ## Browser Verification
357
330
  Tool: <playwright-cli or opencli>
358
- URL: http://localhost:$DEV_PORT
331
+ URL: http://localhost:{{DEV_PORT}}
359
332
  Dev Server Command: <actual command used>
360
333
  Tool version: <version>
361
334
  Steps executed: [list of commands used]
@@ -393,7 +366,7 @@ This single commit includes: feature code + tests + .prizmkit/prizm-docs/ update
393
366
  ```bash
394
367
  git status --short
395
368
  ```
396
- Working tree MUST be clean after this step. If any feature-related files remain, stage them into the SAME commit via `git add <file> && git commit --amend --no-edit`, do NOT create a separate commit.
369
+ Working tree MUST be clean after this step. If any feature-related files remain, stage them explicitly and amend the SAME commit with `git commit --amend --no-edit`; do NOT create a separate commit.
397
370
 
398
371
  **Exception**: `session-summary.md` in the artifact directory is a local cross-session artifact generated by `/prizmkit-committer` — it is NOT committed to git. Ignore it in the clean-tree check.
399
372