prizmkit 1.1.104 → 1.1.106

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 (24) hide show
  1. package/bundled/VERSION.json +3 -3
  2. package/bundled/dev-pipeline/README.md +6 -7
  3. package/bundled/dev-pipeline/assets/prizm-dev-team-integration.md +3 -3
  4. package/bundled/dev-pipeline/prizmkit_runtime/gitops.py +0 -1
  5. package/bundled/dev-pipeline/prizmkit_runtime/runner_bookkeeping.py +83 -12
  6. package/bundled/dev-pipeline/prizmkit_runtime/runner_classification.py +38 -2
  7. package/bundled/dev-pipeline/prizmkit_runtime/runners.py +497 -154
  8. package/bundled/dev-pipeline/prizmkit_runtime/sessions.py +98 -9
  9. package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +37 -28
  10. package/bundled/dev-pipeline/scripts/generate-recovery-prompt.py +4 -3
  11. package/bundled/dev-pipeline/templates/bootstrap-tier2.md +62 -38
  12. package/bundled/dev-pipeline/templates/bootstrap-tier3.md +57 -49
  13. package/bundled/dev-pipeline/templates/sections/critical-paths-agent.md +0 -1
  14. package/bundled/dev-pipeline/templates/sections/critical-paths-full.md +0 -1
  15. package/bundled/dev-pipeline/templates/sections/directory-convention-agent.md +2 -2
  16. package/bundled/dev-pipeline/templates/sections/directory-convention-full.md +2 -2
  17. package/bundled/dev-pipeline/templates/sections/phase-implement-agent.md +1 -0
  18. package/bundled/dev-pipeline/templates/sections/phase-implement-full.md +1 -0
  19. package/bundled/dev-pipeline/tests/test_generate_bootstrap_prompt.py +46 -0
  20. package/bundled/dev-pipeline/tests/test_python_runner_parity.py +308 -0
  21. package/bundled/dev-pipeline/tests/test_unified_cli.py +1 -0
  22. package/bundled/skills/_metadata.json +1 -1
  23. package/package.json +1 -1
  24. package/bundled/dev-pipeline/templates/agent-prompts/dev-implement.md +0 -71
@@ -1,5 +1,5 @@
1
1
  {
2
- "frameworkVersion": "1.1.104",
3
- "bundledAt": "2026-07-06T16:42:02.971Z",
4
- "bundledFrom": "05c5c13"
2
+ "frameworkVersion": "1.1.106",
3
+ "bundledAt": "2026-07-07T02:54:30.507Z",
4
+ "bundledFrom": "8e4fe49"
5
5
  }
@@ -678,10 +678,9 @@ cli.py feature run command
678
678
  +- AI CLI session # claude -p "$(cat prompt)" --dangerously-skip-permissions
679
679
  | | # cbc --print -y < prompt
680
680
  | | # codex --ask-for-approval never --sandbox danger-full-access exec --cd "$PROJECT_ROOT" --skip-git-repo-check - < prompt
681
- | +- prizm-dev-team # Multi-agent team implements the feature
682
- | +- Orchestrator # Main: init, context, plan, retrospective, commit
683
- | +- Dev x N # Implementation with TDD
684
- | +- Reviewer # Analyze + code review
681
+ | +- session orchestrator # Main: init, context, plan, direct implementation, review gate, retrospective, commit
682
+ | +- Critic # Optional plan challenge
683
+ | +- Reviewer # Code review via /prizmkit-code-review
685
684
  |
686
685
  +- check-session-status.py # Parse session outcome
687
686
  +- update-feature-status.py # Update feature state (completed/failed/retry)
@@ -696,8 +695,8 @@ The bootstrap prompt adapts based on feature complexity:
696
695
  | Tier | Template | Agents | Use Case |
697
696
  |------|----------|--------|----------|
698
697
  | Tier 1 (lite) | `bootstrap-tier1.md` | Single agent handles everything | Low complexity features |
699
- | Tier 2 (standard) | `bootstrap-tier2.md` | Orchestrator + Dev + Reviewer subagents | Medium complexity |
700
- | Tier 3 (full) | `bootstrap-tier3.md` | Full team with spec/plan/analyze/implement/review phases | High/critical complexity |
698
+ | Tier 2 (standard) | `bootstrap-tier2.md` | Orchestrator implements directly + optional Critic/Reviewer | Medium/high complexity |
699
+ | Tier 3 (full) | `bootstrap-tier3.md` | Orchestrator implements directly + Critic/Reviewer review phases | High/critical complexity |
701
700
 
702
701
  **Self-evolve mode:** Uses Tier 3 template with additional framework guardrails for developing the PrizmKit framework itself.
703
702
 
@@ -919,7 +918,7 @@ cli.py bugfix run command
919
918
  | Claude Code | `.claude/agents/prizm-dev-team-*.md` | `.claude/team-info.json` |
920
919
  | CodeBuddy | `.codebuddy/agents/prizm-dev-team-*.md` | `~/.codebuddy/teams/prizm-dev-team/config.json` |
921
920
 
922
- Agent files are 2 types: `prizm-dev-team-dev.md` (implementation) and `prizm-dev-team-reviewer.md` (review). Paths are auto-resolved by `generate-bootstrap-prompt.py`.
921
+ Agent files include Reviewer/Critic definitions used by feature prompt flows. `prizm-dev-team-dev.md` remains available for targeted fix/specialized handoffs such as the internal `/prizmkit-code-review` fix loop, but top-level feature implementation is performed directly by the main orchestrator with `/prizmkit-implement`. Paths are auto-resolved by `generate-bootstrap-prompt.py`.
923
922
 
924
923
  ---
925
924
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## Overview
4
4
 
5
- dev-pipeline drives the prizm-dev-team multi-agent team through an outer shell loop. Each iteration spawns a new AI CLI session with a bootstrap prompt that instructs the agent to create and orchestrate the team for one feature.
5
+ dev-pipeline drives feature sessions through the unified Python outer loop. Each iteration spawns a new AI CLI session with a bootstrap prompt that makes the main session orchestrator responsible for implementation, while Critic and Reviewer agents remain available for challenge/review phases.
6
6
 
7
7
  ## Architecture
8
8
 
@@ -19,7 +19,7 @@ dev-pipeline (outer loop)
19
19
  ├── Phase 1-2: Context snapshot + Specify + Plan (Orchestrator)
20
20
  ├── Phase 3: Analyze (Reviewer agent) [tier2] / Phase 4: Analyze [tier3]
21
21
  ├── Phase 3.5: Plan Challenge (Critic agent(s), 1 or 3 parallel) [tier2+]
22
- ├── Phase 4: Implement (Dev agent) [tier2] / Phase 5: Implement [tier3]
22
+ ├── Phase 4: Implement (main orchestrator runs /prizmkit-implement directly)
23
23
  ├── Phase 5: Review (Reviewer agent)
24
24
  └── Phase 6: Retrospective & Commit (Orchestrator)
25
25
 
@@ -30,7 +30,7 @@ dev-pipeline (outer loop)
30
30
 
31
31
  | Agent | Definition Path | Type |
32
32
  |-------|----------------|------|
33
- | Dev | `.claude/agents/prizm-dev-team-dev.md` (or `.codebuddy/agents/`) | prizm-dev-team-dev |
33
+ | Dev | `.claude/agents/prizm-dev-team-dev.md` (or `.codebuddy/agents/`) | prizm-dev-team-dev; reserved for targeted fix/specialized handoffs, not top-level feature implementation |
34
34
  | Reviewer | `.claude/agents/prizm-dev-team-reviewer.md` (or `.codebuddy/agents/`) | prizm-dev-team-reviewer |
35
35
  | Critic | `.claude/agents/prizm-dev-team-critic.md` (or `.codebuddy/agents/`) | prizm-dev-team-critic |
36
36
 
@@ -565,7 +565,6 @@ def branch_ensure_return_plan(context: BranchContext) -> GitCommandPlan:
565
565
  ),
566
566
  _git("stash", "push", "-m", "pipeline-ensure-return-stash", allow_failure=True, description="stash checkout blockers"),
567
567
  _git("checkout", context.base_branch, allow_failure=True, description="return to original branch"),
568
- _git("stash", "pop", allow_failure=True, description="restore stashed checkout blockers"),
569
568
  ),
570
569
  never_fails=True,
571
570
  notes=("Always returns success to support trap/finally cleanup paths.",),
@@ -7,10 +7,11 @@ legacy ordering around branch creation and final status updates.
7
7
 
8
8
  from __future__ import annotations
9
9
 
10
+ from collections.abc import Sequence
10
11
  from dataclasses import dataclass
11
12
  from pathlib import Path
12
13
 
13
- from .gitops import GitCommandResult, git_status_safe, run_git_command
14
+ from .gitops import HIDDEN_TOOL_WORKTREE_EXCLUDES, GitCommandResult, git_status_safe, run_git_command
14
15
  from .runner_models import RunnerFamily
15
16
 
16
17
 
@@ -27,25 +28,95 @@ class BookkeepingResult:
27
28
  return self.result is None or self.result.return_code == 0
28
29
 
29
30
 
30
- def has_workspace_changes(project_root: Path) -> bool:
31
- """Return true when git status has non-hidden-tool worktree changes."""
32
- return bool(git_status_safe(project_root).strip())
31
+ def _bookkeeping_paths(project_root: Path, family: RunnerFamily, item_id: str) -> tuple[str, ...]:
32
+ return (
33
+ _repo_path(project_root, family.plan_path),
34
+ _repo_path(project_root, family.state_dir / item_id / "status.json"),
35
+ )
36
+
37
+
38
+ def _repo_path(project_root: Path, path: Path) -> str:
39
+ try:
40
+ return path.resolve().relative_to(project_root.resolve()).as_posix()
41
+ except ValueError:
42
+ return path.as_posix()
43
+
44
+
45
+ def _changed_paths_in(project_root: Path, paths: Sequence[str]) -> tuple[str, ...]:
46
+ result = run_git_command(project_root, ("status", "--porcelain", "--", *paths))
47
+ if result.return_code != 0:
48
+ return ()
49
+ changed: list[str] = []
50
+ for line in result.stdout.splitlines():
51
+ path = line[3:].strip()
52
+ if " -> " in path:
53
+ path = path.split(" -> ", 1)[1].strip()
54
+ if path:
55
+ changed.append(path)
56
+ return tuple(changed)
57
+
58
+
59
+ def commit_bookkeeping_changes(
60
+ project_root: Path,
61
+ family: RunnerFamily,
62
+ item_id: str,
63
+ message: str,
64
+ ) -> BookkeepingResult:
65
+ """Stage and commit only runner-owned bookkeeping paths when present."""
66
+ paths = _changed_paths_in(project_root, _bookkeeping_paths(project_root, family, item_id))
67
+ if not paths:
68
+ return BookkeepingResult(attempted=False, committed=False)
69
+ run_git_command(project_root, ("add", "-A", "--", *paths))
70
+ result = run_git_command(project_root, ("commit", "--no-verify", "-m", message))
71
+ return BookkeepingResult(attempted=True, committed=result.return_code == 0, result=result)
33
72
 
34
73
 
35
- def commit_all_changes(project_root: Path, message: str) -> BookkeepingResult:
36
- """Stage and commit current workspace changes when present."""
37
- if not has_workspace_changes(project_root):
74
+ def commit_task_branch_changes(
75
+ project_root: Path,
76
+ family: RunnerFamily,
77
+ item_id: str,
78
+ status: str,
79
+ ) -> BookkeepingResult:
80
+ """Commit task branch code, artifacts, and status without switching branches."""
81
+ message = f"chore({item_id}): save {family.kind} {status} state"
82
+ if status == "completed":
83
+ message = f"chore({item_id}): complete {family.kind} task"
84
+ if not git_status_safe(project_root).strip():
38
85
  return BookkeepingResult(attempted=False, committed=False)
39
- run_git_command(project_root, ("add", "-A", "--", "."))
86
+ run_git_command(project_root, ("add", "-A", "--", ".", *HIDDEN_TOOL_WORKTREE_EXCLUDES))
40
87
  result = run_git_command(project_root, ("commit", "--no-verify", "-m", message))
41
88
  return BookkeepingResult(attempted=True, committed=result.return_code == 0, result=result)
42
89
 
43
90
 
91
+ def commit_wip_changes(
92
+ project_root: Path,
93
+ family: RunnerFamily,
94
+ item_id: str,
95
+ status: str,
96
+ ) -> BookkeepingResult:
97
+ """Commit all visible task-branch changes as preserved WIP."""
98
+ if not git_status_safe(project_root).strip():
99
+ return BookkeepingResult(attempted=False, committed=False)
100
+ run_git_command(project_root, ("add", "-A", "--", ".", *HIDDEN_TOOL_WORKTREE_EXCLUDES))
101
+ result = run_git_command(
102
+ project_root,
103
+ (
104
+ "commit",
105
+ "--no-verify",
106
+ "-m",
107
+ f"wip({item_id}): preserve {family.kind} {status} state",
108
+ "-m",
109
+ "Pipeline preserved task branch work without merging it to the base branch.",
110
+ ),
111
+ )
112
+ return BookkeepingResult(attempted=True, committed=result.return_code == 0, result=result)
113
+
114
+
44
115
  def commit_pre_branch_bookkeeping(project_root: Path, family: RunnerFamily, item_id: str) -> BookkeepingResult:
45
- """Commit status/list changes before creating the item dev branch."""
46
- return commit_all_changes(project_root, f"chore({item_id}): mark in_progress")
116
+ """Commit in-progress status on the current task branch."""
117
+ return commit_bookkeeping_changes(project_root, family, item_id, f"chore({item_id}): mark in_progress")
47
118
 
48
119
 
49
120
  def commit_final_bookkeeping(project_root: Path, family: RunnerFamily, item_id: str, status: str) -> BookkeepingResult:
50
- """Commit final list/state changes after returning to the base branch."""
51
- return commit_all_changes(project_root, f"chore({item_id}): update {family.kind} status {status}")
121
+ """Commit final runner-owned status changes on the current task branch."""
122
+ return commit_bookkeeping_changes(project_root, family, item_id, f"chore({item_id}): update {family.kind} status {status}")
@@ -43,10 +43,18 @@ def classify_session(
43
43
  ) -> SessionClassification:
44
44
  """Classify raw AI session signals with durable success precedence."""
45
45
  fingerprint = progress_fingerprint(project_root, prompt)
46
- if _has_commit_since(project_root, base_head):
47
- return SessionClassification("success", reason="commit_since_base", progress_fingerprint=fingerprint)
46
+ has_commit_since_base = _has_commit_since(project_root, base_head)
47
+
48
+ if _is_terminal_success(result) and _has_completed_workflow_artifact(prompt):
49
+ return SessionClassification(
50
+ "success",
51
+ reason="terminal_success_with_completed_checkpoint",
52
+ progress_fingerprint=fingerprint,
53
+ )
48
54
 
49
55
  if _is_context_overflow(result):
56
+ if has_commit_since_base:
57
+ return SessionClassification("success", reason="commit_since_base", progress_fingerprint=fingerprint)
50
58
  no_progress_count = _next_no_progress_count(previous_fingerprint, fingerprint, previous_no_progress_count)
51
59
  if no_progress_count >= 2:
52
60
  return SessionClassification(
@@ -72,6 +80,8 @@ def classify_session(
72
80
  return SessionClassification("timed_out", reason="timeout", progress_fingerprint=fingerprint)
73
81
  if result.exit_code not in (0, None):
74
82
  return SessionClassification("crashed", reason=f"exit_code={result.exit_code}", progress_fingerprint=fingerprint)
83
+ if has_commit_since_base:
84
+ return SessionClassification("success", reason="commit_since_base", progress_fingerprint=fingerprint)
75
85
  if _has_workspace_changes(project_root):
76
86
  _auto_commit_workspace(project_root)
77
87
  return SessionClassification("success", reason="auto_commit_uncommitted_changes", progress_fingerprint=fingerprint)
@@ -100,6 +110,32 @@ def progress_fingerprint(project_root: Path, prompt: PromptGenerationResult | No
100
110
  }
101
111
 
102
112
 
113
+ def _is_terminal_success(result: AISessionResult) -> bool:
114
+ return (
115
+ result.exit_code in (0, None)
116
+ and not result.timed_out
117
+ and result.termination_reason not in {"timeout", "stale_session"}
118
+ and not result.fatal_error_code
119
+ and not result.progress_summary.fatal_error_code
120
+ and result.progress_summary.result_subtype == "success"
121
+ )
122
+
123
+
124
+ def _has_completed_workflow_artifact(prompt: PromptGenerationResult | None) -> bool:
125
+ if prompt is None:
126
+ return False
127
+ if prompt.checkpoint_path and prompt.checkpoint_path.is_file():
128
+ try:
129
+ data = json.loads(prompt.checkpoint_path.read_text(encoding="utf-8"))
130
+ except (OSError, json.JSONDecodeError):
131
+ data = {}
132
+ if isinstance(data, dict) and _checkpoint_cursor(data) == "complete":
133
+ return True
134
+ if prompt.artifact_path and (prompt.artifact_path / "completion-summary.json").is_file():
135
+ return True
136
+ return False
137
+
138
+
103
139
  def _next_no_progress_count(previous: object | None, current: object, count: int) -> int:
104
140
  if previous and previous == current:
105
141
  return max(0, count) + 1