prizmkit 1.1.38 → 1.1.40
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/bundled/VERSION.json +3 -3
- package/bundled/agents/prizm-dev-team-critic.md +6 -34
- package/bundled/dev-pipeline/SCHEMA_ANALYSIS.md +1 -1
- package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +0 -7
- package/bundled/dev-pipeline/scripts/generate-bugfix-prompt.py +118 -1
- package/bundled/dev-pipeline/scripts/generate-refactor-prompt.py +123 -8
- package/bundled/dev-pipeline/templates/bootstrap-tier2.md +0 -27
- package/bundled/dev-pipeline/templates/bootstrap-tier3.md +0 -27
- package/bundled/dev-pipeline/templates/bug-fix-list-schema.json +23 -4
- package/bundled/dev-pipeline/templates/bugfix-bootstrap-prompt.md +56 -0
- package/bundled/dev-pipeline/templates/feature-list-schema.json +1 -1
- package/bundled/dev-pipeline/templates/refactor-bootstrap-prompt.md +64 -4
- package/bundled/dev-pipeline/templates/refactor-list-schema.json +23 -4
- package/bundled/skills/_metadata.json +1 -1
- package/bundled/skills/bugfix-pipeline-launcher/SKILL.md +26 -4
- package/bundled/skills/feature-pipeline-launcher/SKILL.md +35 -17
- package/bundled/skills/recovery-workflow/SKILL.md +96 -7
- package/bundled/skills/refactor-pipeline-launcher/SKILL.md +32 -7
- package/package.json +1 -1
- package/bundled/dev-pipeline/templates/agent-prompts/critic-code-challenge.md +0 -13
- package/bundled/dev-pipeline/templates/sections/phase-critic-code.md +0 -25
package/bundled/VERSION.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: prizm-dev-team-critic
|
|
3
|
-
description: Adversarial challenger that questions plan fitness
|
|
3
|
+
description: Adversarial challenger that questions plan fitness against the project's existing architecture, style, and patterns. Evaluates whether plans truly fit the project before implementation begins. Does NOT verify correctness (that's Reviewer's job) — instead challenges strategic decisions and integration planning. Use when performing adversarial plan challenge.
|
|
4
4
|
tools: Read, Glob, Grep, Bash
|
|
5
5
|
disallowedTools: Agent, Write, Edit
|
|
6
6
|
model: inherit
|
|
@@ -13,9 +13,7 @@ You are the **Critic Agent**, the adversarial challenger of the PrizmKit-integra
|
|
|
13
13
|
|
|
14
14
|
You are the team's "devil's advocate" — you challenge decisions, question assumptions, and find hidden risks that others miss. You do NOT verify correctness (that is Reviewer's job) and you do NOT check document consistency (that is Analyze's job). Your unique value is asking: **"Does this BELONG in this project? Is this the RIGHT approach? What are you NOT seeing?"**
|
|
15
15
|
|
|
16
|
-
You operate in
|
|
17
|
-
1. **Plan Challenge**: Before implementation, challenge the plan's fitness for the project
|
|
18
|
-
2. **Code Challenge**: After implementation, challenge the code's integration quality
|
|
16
|
+
You operate in **Plan Challenge** mode: before implementation, you challenge the plan's fitness for the project. Code-level review is handled by the Code Review skill's built-in review-fix loop (Reviewer Agent → filter → Dev Agent).
|
|
19
17
|
|
|
20
18
|
### Project Context
|
|
21
19
|
|
|
@@ -33,7 +31,7 @@ Before any challenge, you MUST understand the project:
|
|
|
33
31
|
3. Ground every challenge in specific evidence (file paths, code patterns, existing conventions)
|
|
34
32
|
4. Write `challenge-report.md` with structured findings
|
|
35
33
|
5. Keep the report ≤50 lines — focus on HIGH and CRITICAL only, skip LOW
|
|
36
|
-
6. Clearly state
|
|
34
|
+
6. Clearly state you are operating in Plan Challenge mode
|
|
37
35
|
|
|
38
36
|
### Never Do (NEVER)
|
|
39
37
|
|
|
@@ -52,7 +50,7 @@ CRIT-01: Always read .prizm-docs/ and existing source before challenging
|
|
|
52
50
|
CRIT-02: Every challenge must reference a specific file path or code pattern as evidence
|
|
53
51
|
CRIT-03: Maximum 10 challenges per report (focus on highest impact)
|
|
54
52
|
CRIT-04: Severity levels: CRITICAL (architecture mismatch), HIGH (style/robustness gap), MEDIUM (minor inconsistency)
|
|
55
|
-
CRIT-05: If no significant challenges found, write "No significant challenges — plan
|
|
53
|
+
CRIT-05: If no significant challenges found, write "No significant challenges — plan fits the project well" and exit
|
|
56
54
|
CRIT-06: Do NOT re-raise issues already covered by Analyze (document consistency) or Reviewer (correctness)
|
|
57
55
|
CRIT-07: Read comparable existing code in the same module for style baseline before flagging style issues
|
|
58
56
|
CRIT-08: When challenging a decision, always suggest a concrete alternative
|
|
@@ -87,40 +85,14 @@ CRIT-10: In voting mode, write to your assigned report file (challenge-report-{A
|
|
|
87
85
|
|
|
88
86
|
---
|
|
89
87
|
|
|
90
|
-
## Mode 2: Code Challenge
|
|
91
|
-
|
|
92
|
-
**Precondition**: Dev has completed implementation. All tasks `[x]`, tests pass. Implementation Log exists in `context-snapshot.md`.
|
|
93
|
-
|
|
94
|
-
**Goal**: Challenge whether the implemented code integrates well with the existing project — not whether it's correct (that's Reviewer's job).
|
|
95
|
-
|
|
96
|
-
### Challenge Dimensions
|
|
97
|
-
|
|
98
|
-
| Dimension | What to Challenge | Evidence Source |
|
|
99
|
-
|-----------|------------------|----------------|
|
|
100
|
-
| **Style Consistency** | Do naming conventions, code structure, and patterns match existing code in the same module? | Read existing files in the same directory/module |
|
|
101
|
-
| **Robustness** | Are edge cases handled? Error paths? Data validation? What happens with unexpected input not covered by the spec? | Read the new code, compare error handling patterns with existing code |
|
|
102
|
-
| **Integration Cohesion** | Does the new code interact naturally with existing code? Are abstractions consistent? Are import patterns standard? | Read call sites, compare with existing integrations |
|
|
103
|
-
| **Hidden Impact** | Could the new code have side effects on existing functionality? Shared state, global config, database constraints, event handlers? | Read shared modules, config files, database schemas |
|
|
104
|
-
|
|
105
|
-
### Workflow
|
|
106
|
-
|
|
107
|
-
1. Read `context-snapshot.md` — Implementation Log section for what changed
|
|
108
|
-
2. Read `.prizm-docs/root.prizm` and affected module docs (RULES, PATTERNS)
|
|
109
|
-
3. Read the actual source files changed (from Implementation Log)
|
|
110
|
-
4. Read comparable existing files in the same module for style baseline
|
|
111
|
-
5. For each dimension, compare new code against existing code patterns
|
|
112
|
-
6. Write `challenge-report.md` to `.prizmkit/specs/<feature-slug>/` (overwrite any existing report)
|
|
113
|
-
|
|
114
|
-
---
|
|
115
|
-
|
|
116
88
|
## Output Format
|
|
117
89
|
|
|
118
90
|
Write `challenge-report.md` (or `challenge-report-{A,B,C}.md` in voting mode):
|
|
119
91
|
|
|
120
92
|
```markdown
|
|
121
|
-
## Challenge Report —
|
|
93
|
+
## Challenge Report — Plan Challenge
|
|
122
94
|
Feature: <FEATURE_ID> — <FEATURE_TITLE>
|
|
123
|
-
Mode:
|
|
95
|
+
Mode: Plan Challenge
|
|
124
96
|
Challenges Found: N (X critical, Y high, Z medium)
|
|
125
97
|
|
|
126
98
|
### CHALLENGE-1: [CRITICAL] Title
|
|
@@ -307,7 +307,7 @@ pending, in_progress, completed, failed, skipped
|
|
|
307
307
|
| Phase Implementation | `phase-implement-lite.md`, `phase-implement-full.md`, `phase-implement-agent.md` | Three execution modes |
|
|
308
308
|
| Phase Review | `phase-review-full.md`, `phase-review-agent.md` | Full & Agent variants |
|
|
309
309
|
| Phase Plan | `phase-plan-lite.md`, `phase-plan-agent.md` | Lite & Agent variants |
|
|
310
|
-
| Phase Critic | `phase-critic-plan.md`, `phase-critic-plan-full.md
|
|
310
|
+
| Phase Critic | `phase-critic-plan.md`, `phase-critic-plan-full.md` | Plan review (single and multi) |
|
|
311
311
|
| Phase Commit | `phase-commit.md`, `phase-commit-full.md` | Standard & Full variants |
|
|
312
312
|
|
|
313
313
|
### Singleton Sections
|
|
@@ -623,7 +623,6 @@ SECTION_TO_SKILL = {
|
|
|
623
623
|
[".prizmkit/specs/{slug}/plan.md"]),
|
|
624
624
|
"phase-critic-plan": ("critic-plan-review", "Critic: Plan Review", []),
|
|
625
625
|
"phase-implement": ("prizmkit-implement", "Implement + Test", []),
|
|
626
|
-
"phase-critic-code": ("critic-code-review", "Critic: Code Review", []),
|
|
627
626
|
"phase-review": ("prizmkit-code-review", "Code Review", []),
|
|
628
627
|
"phase-browser": ("browser-verification", "Browser Verification", []),
|
|
629
628
|
"phase-deploy": ("deploy-verification", "Deploy Verification", []),
|
|
@@ -1043,12 +1042,6 @@ def assemble_sections(pipeline_mode, sections_dir, init_done, is_resume,
|
|
|
1043
1042
|
load_section(sections_dir,
|
|
1044
1043
|
"test-failure-recovery-agent.md")))
|
|
1045
1044
|
|
|
1046
|
-
# --- Critic: Code Challenge (only if critic enabled, agent tiers) ---
|
|
1047
|
-
if critic_enabled and pipeline_mode in ("standard", "full"):
|
|
1048
|
-
sections.append(("phase-critic-code",
|
|
1049
|
-
load_section(sections_dir,
|
|
1050
|
-
"phase-critic-code.md")))
|
|
1051
|
-
|
|
1052
1045
|
# --- AC Verification Checklist (all tiers) ---
|
|
1053
1046
|
ac_checklist_path = os.path.join(sections_dir, "ac-verification-checklist.md")
|
|
1054
1047
|
if os.path.isfile(ac_checklist_path):
|
|
@@ -260,6 +260,39 @@ def build_replacements(args, bug, global_context, script_dir):
|
|
|
260
260
|
# Determine verification type
|
|
261
261
|
vtype = bug.get("verification_type", "automated")
|
|
262
262
|
|
|
263
|
+
# Browser interaction - extract from bug if present
|
|
264
|
+
browser_interaction = bug.get("browser_interaction")
|
|
265
|
+
browser_enabled = False
|
|
266
|
+
browser_verify_steps = ""
|
|
267
|
+
browser_tool = "auto"
|
|
268
|
+
|
|
269
|
+
# Environment override
|
|
270
|
+
browser_verify_env = os.environ.get("BROWSER_VERIFY", "").lower()
|
|
271
|
+
if browser_verify_env == "false":
|
|
272
|
+
browser_interaction = None
|
|
273
|
+
|
|
274
|
+
# Extract browser config (same logic as feature pipeline)
|
|
275
|
+
if browser_interaction and isinstance(browser_interaction, bool):
|
|
276
|
+
browser_enabled = True
|
|
277
|
+
browser_tool = "auto"
|
|
278
|
+
browser_verify_steps = " # (no specific verify goals — reproduce the bug and verify it's fixed)"
|
|
279
|
+
elif browser_interaction and isinstance(browser_interaction, dict):
|
|
280
|
+
browser_tool = browser_interaction.get("tool", "auto")
|
|
281
|
+
if browser_tool not in ("playwright-cli", "opencli", "auto"):
|
|
282
|
+
LOGGER.warning("Unknown browser_interaction.tool '%s', defaulting to 'auto'", browser_tool)
|
|
283
|
+
browser_tool = "auto"
|
|
284
|
+
|
|
285
|
+
steps = browser_interaction.get("verify_steps", [])
|
|
286
|
+
if steps:
|
|
287
|
+
browser_enabled = True
|
|
288
|
+
browser_verify_steps = "\n".join(
|
|
289
|
+
" # Step {}: {}".format(i + 1, step)
|
|
290
|
+
for i, step in enumerate(steps)
|
|
291
|
+
)
|
|
292
|
+
elif browser_interaction.get("url") or browser_interaction.get("enabled", True):
|
|
293
|
+
browser_enabled = True
|
|
294
|
+
browser_verify_steps = " # (reproduce bug and verify fix)"
|
|
295
|
+
|
|
263
296
|
replacements = {
|
|
264
297
|
"{{RUN_ID}}": args.run_id,
|
|
265
298
|
"{{SESSION_ID}}": args.session_id,
|
|
@@ -284,13 +317,17 @@ def build_replacements(args, bug, global_context, script_dir):
|
|
|
284
317
|
"{{PROJECT_ROOT}}": project_root,
|
|
285
318
|
"{{FIX_SCOPE}}": fix_scope,
|
|
286
319
|
"{{TIMESTAMP}}": "", # Placeholder, agent fills in the timestamp
|
|
320
|
+
"{{BROWSER_ENABLED}}": "true" if browser_enabled else "false",
|
|
321
|
+
"{{BROWSER_TOOL}}": browser_tool,
|
|
322
|
+
"{{BROWSER_VERIFY_STEPS}}": browser_verify_steps,
|
|
287
323
|
}
|
|
288
324
|
|
|
289
325
|
return replacements
|
|
290
326
|
|
|
291
327
|
|
|
292
328
|
def process_conditional_blocks(content, bug):
|
|
293
|
-
"""Handle conditional blocks based on verification_type."""
|
|
329
|
+
"""Handle conditional blocks based on verification_type and browser_interaction."""
|
|
330
|
+
# Handle verification type blocks
|
|
294
331
|
vtype = bug.get("verification_type", "automated")
|
|
295
332
|
is_manual_or_hybrid = vtype in ("manual", "hybrid")
|
|
296
333
|
|
|
@@ -306,6 +343,64 @@ def process_conditional_blocks(content, bug):
|
|
|
306
343
|
"", content, flags=re.DOTALL,
|
|
307
344
|
)
|
|
308
345
|
|
|
346
|
+
# Handle browser interaction blocks
|
|
347
|
+
browser_interaction = bug.get("browser_interaction")
|
|
348
|
+
browser_enabled = False
|
|
349
|
+
browser_tool = "auto"
|
|
350
|
+
|
|
351
|
+
# Check environment override
|
|
352
|
+
browser_verify_env = os.environ.get("BROWSER_VERIFY", "").lower()
|
|
353
|
+
if browser_verify_env == "false":
|
|
354
|
+
browser_interaction = None
|
|
355
|
+
|
|
356
|
+
# Determine if browser is enabled
|
|
357
|
+
if browser_interaction:
|
|
358
|
+
if isinstance(browser_interaction, bool):
|
|
359
|
+
browser_enabled = True
|
|
360
|
+
elif isinstance(browser_interaction, dict):
|
|
361
|
+
steps = browser_interaction.get("verify_steps", [])
|
|
362
|
+
if steps or browser_interaction.get("url") or browser_interaction.get("enabled", True):
|
|
363
|
+
browser_enabled = True
|
|
364
|
+
browser_tool = browser_interaction.get("tool", "auto")
|
|
365
|
+
|
|
366
|
+
# Process browser interaction blocks
|
|
367
|
+
browser_open = "{{IF_BROWSER_INTERACTION}}"
|
|
368
|
+
browser_close = "{{END_IF_BROWSER_INTERACTION}}"
|
|
369
|
+
|
|
370
|
+
if browser_enabled:
|
|
371
|
+
# Keep content, remove tags
|
|
372
|
+
content = content.replace(browser_open + "\n", "")
|
|
373
|
+
content = content.replace(browser_open, "")
|
|
374
|
+
content = content.replace(browser_close + "\n", "")
|
|
375
|
+
content = content.replace(browser_close, "")
|
|
376
|
+
else:
|
|
377
|
+
# Remove entire block
|
|
378
|
+
pattern = re.escape(browser_open) + r".*?" + re.escape(browser_close) + r"\n?"
|
|
379
|
+
content = re.sub(pattern, "", content, flags=re.DOTALL)
|
|
380
|
+
|
|
381
|
+
# Process browser tool selection blocks (nested inside browser interaction)
|
|
382
|
+
tool_variants = ["PLAYWRIGHT", "OPENCLI", "AUTO"]
|
|
383
|
+
active_variant = {
|
|
384
|
+
"playwright-cli": "PLAYWRIGHT",
|
|
385
|
+
"opencli": "OPENCLI",
|
|
386
|
+
"auto": "AUTO",
|
|
387
|
+
}.get(browser_tool, "AUTO")
|
|
388
|
+
|
|
389
|
+
for variant in tool_variants:
|
|
390
|
+
tool_open = "{{{{IF_BROWSER_TOOL_{}}}}}".format(variant)
|
|
391
|
+
tool_close = "{{{{END_IF_BROWSER_TOOL_{}}}}}".format(variant)
|
|
392
|
+
|
|
393
|
+
if variant == active_variant and browser_enabled:
|
|
394
|
+
# Keep content, remove tags
|
|
395
|
+
content = content.replace(tool_open + "\n", "")
|
|
396
|
+
content = content.replace(tool_open, "")
|
|
397
|
+
content = content.replace(tool_close + "\n", "")
|
|
398
|
+
content = content.replace(tool_close, "")
|
|
399
|
+
else:
|
|
400
|
+
# Remove entire block
|
|
401
|
+
pat = re.escape(tool_open) + r".*?" + re.escape(tool_close) + r"\n?"
|
|
402
|
+
content = re.sub(pat, "", content, flags=re.DOTALL)
|
|
403
|
+
|
|
309
404
|
return content
|
|
310
405
|
|
|
311
406
|
|
|
@@ -529,6 +624,26 @@ def main():
|
|
|
529
624
|
|
|
530
625
|
# Success
|
|
531
626
|
bug_model = bug.get("model", "")
|
|
627
|
+
# Extract browser interaction state for output
|
|
628
|
+
browser_interaction = bug.get("browser_interaction")
|
|
629
|
+
browser_enabled = False
|
|
630
|
+
browser_tool = "auto"
|
|
631
|
+
|
|
632
|
+
browser_verify_env = os.environ.get("BROWSER_VERIFY", "").lower()
|
|
633
|
+
if browser_verify_env == "false":
|
|
634
|
+
browser_interaction = None
|
|
635
|
+
|
|
636
|
+
if browser_interaction:
|
|
637
|
+
if isinstance(browser_interaction, bool):
|
|
638
|
+
browser_enabled = True
|
|
639
|
+
elif isinstance(browser_interaction, dict):
|
|
640
|
+
steps = browser_interaction.get("verify_steps", [])
|
|
641
|
+
if steps or browser_interaction.get("url") or browser_interaction.get("enabled", True):
|
|
642
|
+
browser_enabled = True
|
|
643
|
+
browser_tool = browser_interaction.get("tool", "auto")
|
|
644
|
+
if browser_tool not in ("playwright-cli", "opencli", "auto"):
|
|
645
|
+
browser_tool = "auto"
|
|
646
|
+
|
|
532
647
|
output = {
|
|
533
648
|
"success": True,
|
|
534
649
|
"output_path": os.path.abspath(args.output),
|
|
@@ -537,6 +652,8 @@ def main():
|
|
|
537
652
|
"pipeline_mode": pipeline_mode,
|
|
538
653
|
"agent_count": agent_count,
|
|
539
654
|
"critic_enabled": critic_enabled,
|
|
655
|
+
"browser_enabled": browser_enabled,
|
|
656
|
+
"browser_tool": browser_tool
|
|
540
657
|
}
|
|
541
658
|
print(json.dumps(output, indent=2, ensure_ascii=False))
|
|
542
659
|
sys.exit(0)
|
|
@@ -420,6 +420,39 @@ def build_replacements(args, refactor, refactors, global_context, script_dir):
|
|
|
420
420
|
else:
|
|
421
421
|
new_tests_str = "- (none specified)"
|
|
422
422
|
|
|
423
|
+
# Browser interaction - extract from refactor if present
|
|
424
|
+
browser_interaction = refactor.get("browser_interaction")
|
|
425
|
+
browser_enabled = False
|
|
426
|
+
browser_verify_steps = ""
|
|
427
|
+
browser_tool = "auto"
|
|
428
|
+
|
|
429
|
+
# Environment override
|
|
430
|
+
browser_verify_env = os.environ.get("BROWSER_VERIFY", "").lower()
|
|
431
|
+
if browser_verify_env == "false":
|
|
432
|
+
browser_interaction = None
|
|
433
|
+
|
|
434
|
+
# Extract browser config (same logic as feature and bugfix pipelines)
|
|
435
|
+
if browser_interaction and isinstance(browser_interaction, bool):
|
|
436
|
+
browser_enabled = True
|
|
437
|
+
browser_tool = "auto"
|
|
438
|
+
browser_verify_steps = " # (no specific verify goals — validate UI renders correctly and feature still works)"
|
|
439
|
+
elif browser_interaction and isinstance(browser_interaction, dict):
|
|
440
|
+
browser_tool = browser_interaction.get("tool", "auto")
|
|
441
|
+
if browser_tool not in ("playwright-cli", "opencli", "auto"):
|
|
442
|
+
LOGGER.warning("Unknown browser_interaction.tool '%s', defaulting to 'auto'", browser_tool)
|
|
443
|
+
browser_tool = "auto"
|
|
444
|
+
|
|
445
|
+
steps = browser_interaction.get("verify_steps", [])
|
|
446
|
+
if steps:
|
|
447
|
+
browser_enabled = True
|
|
448
|
+
browser_verify_steps = "\n".join(
|
|
449
|
+
" # Step {}: {}".format(i + 1, step)
|
|
450
|
+
for i, step in enumerate(steps)
|
|
451
|
+
)
|
|
452
|
+
elif browser_interaction.get("url") or browser_interaction.get("enabled", True):
|
|
453
|
+
browser_enabled = True
|
|
454
|
+
browser_verify_steps = " # (validate UI renders correctly and feature still works)"
|
|
455
|
+
|
|
423
456
|
replacements = {
|
|
424
457
|
"{{RUN_ID}}": args.run_id,
|
|
425
458
|
"{{SESSION_ID}}": args.session_id,
|
|
@@ -452,16 +485,17 @@ def build_replacements(args, refactor, refactors, global_context, script_dir):
|
|
|
452
485
|
),
|
|
453
486
|
"{{TIMESTAMP}}": "", # Placeholder — agent fills in timestamp
|
|
454
487
|
"{{PLATFORM_CONVENTIONS}}": read_platform_conventions(project_root),
|
|
488
|
+
"{{BROWSER_ENABLED}}": "true" if browser_enabled else "false",
|
|
489
|
+
"{{BROWSER_TOOL}}": browser_tool,
|
|
490
|
+
"{{BROWSER_VERIFY_STEPS}}": browser_verify_steps,
|
|
455
491
|
}
|
|
456
492
|
|
|
457
493
|
return replacements
|
|
458
494
|
|
|
459
495
|
|
|
460
|
-
def process_conditional_blocks(content, resume_phase):
|
|
461
|
-
"""Handle conditional blocks based on resume_phase.
|
|
462
|
-
|
|
463
|
-
- {{IF_FRESH_START}}...{{END_IF_FRESH_START}} — include only on fresh start (resume_phase == "null")
|
|
464
|
-
"""
|
|
496
|
+
def process_conditional_blocks(content, resume_phase, refactor):
|
|
497
|
+
"""Handle conditional blocks based on resume_phase and browser_interaction."""
|
|
498
|
+
# Handle fresh start blocks
|
|
465
499
|
is_resume = resume_phase != "null"
|
|
466
500
|
|
|
467
501
|
if is_resume:
|
|
@@ -475,13 +509,72 @@ def process_conditional_blocks(content, resume_phase):
|
|
|
475
509
|
content = content.replace("{{END_IF_FRESH_START}}\n", "")
|
|
476
510
|
content = content.replace("{{END_IF_FRESH_START}}", "")
|
|
477
511
|
|
|
512
|
+
# Handle browser interaction blocks
|
|
513
|
+
browser_interaction = refactor.get("browser_interaction")
|
|
514
|
+
browser_enabled = False
|
|
515
|
+
browser_tool = "auto"
|
|
516
|
+
|
|
517
|
+
# Check environment override
|
|
518
|
+
browser_verify_env = os.environ.get("BROWSER_VERIFY", "").lower()
|
|
519
|
+
if browser_verify_env == "false":
|
|
520
|
+
browser_interaction = None
|
|
521
|
+
|
|
522
|
+
# Determine if browser is enabled
|
|
523
|
+
if browser_interaction:
|
|
524
|
+
if isinstance(browser_interaction, bool):
|
|
525
|
+
browser_enabled = True
|
|
526
|
+
elif isinstance(browser_interaction, dict):
|
|
527
|
+
steps = browser_interaction.get("verify_steps", [])
|
|
528
|
+
if steps or browser_interaction.get("url") or browser_interaction.get("enabled", True):
|
|
529
|
+
browser_enabled = True
|
|
530
|
+
browser_tool = browser_interaction.get("tool", "auto")
|
|
531
|
+
|
|
532
|
+
# Process browser interaction blocks
|
|
533
|
+
browser_open = "{{IF_BROWSER_INTERACTION}}"
|
|
534
|
+
browser_close = "{{END_IF_BROWSER_INTERACTION}}"
|
|
535
|
+
|
|
536
|
+
if browser_enabled:
|
|
537
|
+
# Keep content, remove tags
|
|
538
|
+
content = content.replace(browser_open + "\n", "")
|
|
539
|
+
content = content.replace(browser_open, "")
|
|
540
|
+
content = content.replace(browser_close + "\n", "")
|
|
541
|
+
content = content.replace(browser_close, "")
|
|
542
|
+
else:
|
|
543
|
+
# Remove entire block
|
|
544
|
+
pattern = re.escape(browser_open) + r".*?" + re.escape(browser_close) + r"\n?"
|
|
545
|
+
content = re.sub(pattern, "", content, flags=re.DOTALL)
|
|
546
|
+
|
|
547
|
+
# Process browser tool selection blocks (nested inside browser interaction)
|
|
548
|
+
tool_variants = ["PLAYWRIGHT", "OPENCLI", "AUTO"]
|
|
549
|
+
active_variant = {
|
|
550
|
+
"playwright-cli": "PLAYWRIGHT",
|
|
551
|
+
"opencli": "OPENCLI",
|
|
552
|
+
"auto": "AUTO",
|
|
553
|
+
}.get(browser_tool, "AUTO")
|
|
554
|
+
|
|
555
|
+
for variant in tool_variants:
|
|
556
|
+
tool_open = "{{{{IF_BROWSER_TOOL_{}}}}}".format(variant)
|
|
557
|
+
tool_close = "{{{{END_IF_BROWSER_TOOL_{}}}}}".format(variant)
|
|
558
|
+
|
|
559
|
+
if variant == active_variant and browser_enabled:
|
|
560
|
+
# Keep content, remove tags
|
|
561
|
+
content = content.replace(tool_open + "\n", "")
|
|
562
|
+
content = content.replace(tool_open, "")
|
|
563
|
+
content = content.replace(tool_close + "\n", "")
|
|
564
|
+
content = content.replace(tool_close, "")
|
|
565
|
+
else:
|
|
566
|
+
# Remove entire block
|
|
567
|
+
pat = re.escape(tool_open) + r".*?" + re.escape(tool_close) + r"\n?"
|
|
568
|
+
content = re.sub(pat, "", content, flags=re.DOTALL)
|
|
569
|
+
|
|
478
570
|
return content
|
|
479
571
|
|
|
480
572
|
|
|
481
|
-
|
|
573
|
+
|
|
574
|
+
def render_template(template_content, replacements, resume_phase, refactor):
|
|
482
575
|
"""Render the template by processing conditionals and replacing placeholders."""
|
|
483
576
|
# Step 1: Process conditional blocks
|
|
484
|
-
content = process_conditional_blocks(template_content, resume_phase)
|
|
577
|
+
content = process_conditional_blocks(template_content, resume_phase, refactor)
|
|
485
578
|
|
|
486
579
|
# Step 2: Replace all {{PLACEHOLDER}} variables
|
|
487
580
|
for placeholder, value in replacements.items():
|
|
@@ -560,7 +653,7 @@ def main():
|
|
|
560
653
|
replacements = build_replacements(args, refactor, refactors, global_context, script_dir)
|
|
561
654
|
|
|
562
655
|
# Render the template
|
|
563
|
-
rendered = render_template(template_content, replacements, args.resume_phase)
|
|
656
|
+
rendered = render_template(template_content, replacements, args.resume_phase, refactor)
|
|
564
657
|
|
|
565
658
|
# Write the output
|
|
566
659
|
err = write_output(args.output, rendered)
|
|
@@ -610,13 +703,35 @@ def main():
|
|
|
610
703
|
|
|
611
704
|
# Success
|
|
612
705
|
refactor_model = refactor.get("model", "")
|
|
706
|
+
|
|
707
|
+
# Extract browser state for JSON output
|
|
708
|
+
browser_interaction = refactor.get("browser_interaction")
|
|
709
|
+
browser_enabled = False
|
|
710
|
+
browser_tool = "auto"
|
|
711
|
+
|
|
712
|
+
browser_verify_env = os.environ.get("BROWSER_VERIFY", "").lower()
|
|
713
|
+
if browser_verify_env == "false":
|
|
714
|
+
browser_interaction = None
|
|
715
|
+
|
|
716
|
+
if browser_interaction:
|
|
717
|
+
if isinstance(browser_interaction, bool):
|
|
718
|
+
browser_enabled = True
|
|
719
|
+
elif isinstance(browser_interaction, dict):
|
|
720
|
+
steps = browser_interaction.get("verify_steps", [])
|
|
721
|
+
if steps or browser_interaction.get("url") or browser_interaction.get("enabled", True):
|
|
722
|
+
browser_enabled = True
|
|
723
|
+
browser_tool = browser_interaction.get("tool", "auto")
|
|
724
|
+
|
|
613
725
|
output = {
|
|
614
726
|
"success": True,
|
|
615
727
|
"output_path": os.path.abspath(args.output),
|
|
728
|
+
"checkpoint_path": checkpoint_path,
|
|
616
729
|
"model": refactor_model,
|
|
617
730
|
"pipeline_mode": pipeline_mode,
|
|
618
731
|
"agent_count": agent_count,
|
|
619
732
|
"critic_enabled": critic_enabled,
|
|
733
|
+
"browser_enabled": browser_enabled,
|
|
734
|
+
"browser_tool": browser_tool,
|
|
620
735
|
}
|
|
621
736
|
print(json.dumps(output, indent=2, ensure_ascii=False))
|
|
622
737
|
sys.exit(0)
|
|
@@ -228,33 +228,6 @@ grep -q "## Implementation Log" .prizmkit/specs/{{FEATURE_SLUG}}/context-snapsho
|
|
|
228
228
|
```
|
|
229
229
|
If GATE:MISSING — send message to Dev (re-spawn if needed): "Write the '## Implementation Log' section to context-snapshot.md before I can proceed to review. Include: files changed/created, key decisions, deviations from plan, notable discoveries."
|
|
230
230
|
|
|
231
|
-
{{IF_CRITIC_ENABLED}}
|
|
232
|
-
### Phase 4.5: Code Challenge — Critic Agent
|
|
233
|
-
|
|
234
|
-
**Guard**: Verify critic agent file exists before spawning:
|
|
235
|
-
```bash
|
|
236
|
-
ls {{CRITIC_SUBAGENT_PATH}} 2>/dev/null && echo "CRITIC:READY" || echo "CRITIC:MISSING"
|
|
237
|
-
```
|
|
238
|
-
If CRITIC:MISSING — skip Phase 4.5 entirely and proceed to Phase 5. Log: "Critic agent not installed — skipping Code Challenge."
|
|
239
|
-
|
|
240
|
-
Spawn Critic agent (Agent tool, subagent_type="prizm-dev-team-critic", mode="plan", run_in_background=false).
|
|
241
|
-
|
|
242
|
-
Prompt:
|
|
243
|
-
> "Read {{CRITIC_SUBAGENT_PATH}}. For feature {{FEATURE_ID}} (slug: {{FEATURE_SLUG}}):
|
|
244
|
-
> **MODE: Code Challenge**
|
|
245
|
-
> 1. Read `.prizmkit/specs/{{FEATURE_SLUG}}/context-snapshot.md` — Implementation Log section shows what Dev changed.
|
|
246
|
-
> 2. Read `.prizm-docs/root.prizm` and relevant module docs for RULES/PATTERNS.
|
|
247
|
-
> 3. Read the actual source files changed (from Implementation Log).
|
|
248
|
-
> 4. Read comparable existing source files in the same module for style comparison.
|
|
249
|
-
> 5. Challenge code integration quality: style fit, robustness, existing code cohesion, hidden impact.
|
|
250
|
-
> Write `.prizmkit/specs/{{FEATURE_SLUG}}/challenge-report.md` (overwrite) with findings (or 'No significant challenges')."
|
|
251
|
-
|
|
252
|
-
Wait for Critic to return.
|
|
253
|
-
- Read challenge-report.md. For items marked CRITICAL/HIGH: spawn Dev to fix, then proceed to Review.
|
|
254
|
-
|
|
255
|
-
**CP-3.5**: Code challenges reviewed and resolved.
|
|
256
|
-
{{END_IF_CRITIC_ENABLED}}
|
|
257
|
-
|
|
258
231
|
### Phase 5: Review + Test — Reviewer Subagent
|
|
259
232
|
|
|
260
233
|
Spawn Reviewer subagent (Agent tool, subagent_type="prizm-dev-team-reviewer", run_in_background=false).
|
|
@@ -293,33 +293,6 @@ Wait for Dev to return. **If Dev times out before all tasks are `[x]`**:
|
|
|
293
293
|
|
|
294
294
|
All tasks `[x]`, tests pass.
|
|
295
295
|
|
|
296
|
-
{{IF_CRITIC_ENABLED}}
|
|
297
|
-
### Phase 4.5: Code Challenge — Critic Agent
|
|
298
|
-
|
|
299
|
-
**Guard**: Verify critic agent file exists before spawning:
|
|
300
|
-
```bash
|
|
301
|
-
ls {{CRITIC_SUBAGENT_PATH}} 2>/dev/null && echo "CRITIC:READY" || echo "CRITIC:MISSING"
|
|
302
|
-
```
|
|
303
|
-
If CRITIC:MISSING — skip Phase 4.5 entirely and proceed to Phase 5. Log: "Critic agent not installed — skipping Code Challenge."
|
|
304
|
-
|
|
305
|
-
Spawn Critic agent (Agent tool, subagent_type="prizm-dev-team-critic", mode="plan", run_in_background=false).
|
|
306
|
-
|
|
307
|
-
Prompt:
|
|
308
|
-
> "Read {{CRITIC_SUBAGENT_PATH}}. For feature {{FEATURE_ID}} (slug: {{FEATURE_SLUG}}):
|
|
309
|
-
> **MODE: Code Challenge**
|
|
310
|
-
> 1. Read `.prizmkit/specs/{{FEATURE_SLUG}}/context-snapshot.md` — Implementation Log section shows what Dev changed.
|
|
311
|
-
> 2. Read `.prizm-docs/root.prizm` and relevant module docs for RULES/PATTERNS.
|
|
312
|
-
> 3. Read the actual source files changed (from Implementation Log).
|
|
313
|
-
> 4. Read comparable existing source files in the same module for style comparison.
|
|
314
|
-
> 5. Challenge code integration quality: style fit, robustness, existing code cohesion, hidden impact.
|
|
315
|
-
> Write `.prizmkit/specs/{{FEATURE_SLUG}}/challenge-report.md` (overwrite) with findings (or 'No significant challenges')."
|
|
316
|
-
|
|
317
|
-
Wait for Critic to return.
|
|
318
|
-
- Read challenge-report.md. For items marked CRITICAL/HIGH: spawn Dev to fix, then proceed to Review.
|
|
319
|
-
|
|
320
|
-
**CP-3.5**: Code challenges reviewed and resolved.
|
|
321
|
-
{{END_IF_CRITIC_ENABLED}}
|
|
322
|
-
|
|
323
296
|
### Phase 5: Review + Test — Reviewer Agent
|
|
324
297
|
|
|
325
298
|
Spawn Reviewer agent (Agent tool, subagent_type="prizm-dev-team-reviewer", run_in_background=false).
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
3
|
"title": "Dev-Pipeline Bug Fix List",
|
|
4
|
-
"description": "Schema for .prizmkit/plans/bug-fix-list.json
|
|
4
|
+
"description": "Schema for .prizmkit/plans/bug-fix-list.json — standardized input for the Bug Fix Pipeline",
|
|
5
5
|
"type": "object",
|
|
6
6
|
"required": [
|
|
7
7
|
"$schema",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"title": {
|
|
52
52
|
"type": "string",
|
|
53
53
|
"minLength": 1,
|
|
54
|
-
"description": "Bug title
|
|
54
|
+
"description": "Bug title — brief description of the symptom"
|
|
55
55
|
},
|
|
56
56
|
"description": {
|
|
57
57
|
"type": "string",
|
|
@@ -175,7 +175,7 @@
|
|
|
175
175
|
},
|
|
176
176
|
"critic": {
|
|
177
177
|
"type": "boolean",
|
|
178
|
-
"description": "Enable adversarial
|
|
178
|
+
"description": "Enable adversarial plan challenge before implementation. Default: true for high severity bugs, false for others.",
|
|
179
179
|
"default": false
|
|
180
180
|
},
|
|
181
181
|
"critic_count": {
|
|
@@ -194,6 +194,25 @@
|
|
|
194
194
|
"model": {
|
|
195
195
|
"type": "string",
|
|
196
196
|
"description": "AI model ID for this bug fix. Overrides $MODEL env var."
|
|
197
|
+
},
|
|
198
|
+
"browser_interaction": {
|
|
199
|
+
"type": "object",
|
|
200
|
+
"description": "Browser verification config for bugs reproducible via UI. Supports playwright-cli and opencli. AI auto-detects dev server command, URL, and port from project config at runtime.",
|
|
201
|
+
"properties": {
|
|
202
|
+
"tool": {
|
|
203
|
+
"type": "string",
|
|
204
|
+
"enum": ["playwright-cli", "opencli", "auto"],
|
|
205
|
+
"default": "auto",
|
|
206
|
+
"description": "Browser tool to use. 'auto' (default) = AI chooses at runtime. 'playwright-cli' = local dev server verification in isolated browser. 'opencli' = reuses Chrome logged-in session, ideal for verifying bugs related to third-party integrations or OAuth flows."
|
|
207
|
+
},
|
|
208
|
+
"verify_steps": {
|
|
209
|
+
"type": "array",
|
|
210
|
+
"description": "Verification goals describing HOW to reproduce and verify the bug fix (e.g., 'Click login button and verify error message is gone', 'Open dashboard and confirm performance metrics display'). AI decides concrete browser tool actions at runtime. If omitted, AI auto-reproduces from error description.",
|
|
211
|
+
"items": {
|
|
212
|
+
"type": "string"
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
197
216
|
}
|
|
198
217
|
}
|
|
199
218
|
}
|
|
@@ -241,4 +260,4 @@
|
|
|
241
260
|
}
|
|
242
261
|
}
|
|
243
262
|
}
|
|
244
|
-
}
|
|
263
|
+
}
|