prizmkit 1.1.153 → 1.1.155
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/adapters/codex/skill-adapter.js +1 -1
- package/bundled/adapters/pi/skill-adapter.js +2 -1
- package/bundled/dev-pipeline/.env.example +2 -6
- package/bundled/dev-pipeline/README.md +120 -113
- package/bundled/dev-pipeline/assets/skill-subagent-integration.md +1 -1
- package/bundled/dev-pipeline/prizmkit_runtime/checkpoint_state.py +355 -15
- package/bundled/dev-pipeline/prizmkit_runtime/cli.py +189 -110
- package/bundled/dev-pipeline/prizmkit_runtime/commands.py +146 -111
- package/bundled/dev-pipeline/prizmkit_runtime/daemon.py +4 -20
- package/bundled/dev-pipeline/prizmkit_runtime/gitops.py +48 -14
- package/bundled/dev-pipeline/prizmkit_runtime/interoperability.py +0 -1
- package/bundled/dev-pipeline/prizmkit_runtime/paths.py +0 -3
- package/bundled/dev-pipeline/prizmkit_runtime/reset.py +122 -15
- package/bundled/dev-pipeline/prizmkit_runtime/reset_preserve.py +1 -1
- package/bundled/dev-pipeline/prizmkit_runtime/runner_classification.py +50 -2
- package/bundled/dev-pipeline/prizmkit_runtime/runner_models.py +1 -10
- package/bundled/dev-pipeline/prizmkit_runtime/runner_prompts.py +3 -3
- package/bundled/dev-pipeline/prizmkit_runtime/runners.py +139 -74
- package/bundled/dev-pipeline/prizmkit_runtime/runtime_commit.py +482 -0
- package/bundled/dev-pipeline/prizmkit_runtime/status.py +106 -1
- package/bundled/dev-pipeline/prizmkit_runtime/test_result.py +64 -11
- package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +145 -367
- package/bundled/dev-pipeline/scripts/generate-bugfix-prompt.py +91 -62
- package/bundled/dev-pipeline/scripts/generate-refactor-prompt.py +105 -69
- package/bundled/dev-pipeline/scripts/init-bugfix-pipeline.py +2 -2
- package/bundled/dev-pipeline/scripts/prompt_framework.py +36 -41
- package/bundled/dev-pipeline/scripts/update-bug-status.py +197 -71
- package/bundled/dev-pipeline/scripts/update-checkpoint.py +77 -16
- package/bundled/dev-pipeline/scripts/update-feature-status.py +46 -121
- package/bundled/dev-pipeline/scripts/update-refactor-status.py +46 -123
- package/bundled/dev-pipeline/scripts/utils.py +119 -0
- package/bundled/dev-pipeline/templates/bootstrap-prompt.md +22 -27
- package/bundled/dev-pipeline/templates/bootstrap-tier3.md +71 -104
- package/bundled/dev-pipeline/templates/bug-fix-list-schema.json +3 -2
- package/bundled/dev-pipeline/templates/bugfix-bootstrap-prompt.md +59 -111
- package/bundled/dev-pipeline/templates/refactor-bootstrap-prompt.md +37 -72
- package/bundled/dev-pipeline/templates/sections/artifact-manifest.md +39 -0
- package/bundled/dev-pipeline/templates/sections/bugfix-critical-paths.md +3 -1
- package/bundled/dev-pipeline/templates/sections/bugfix-phase-commit-report.md +8 -25
- package/bundled/dev-pipeline/templates/sections/bugfix-phase-diagnose-plan.md +3 -3
- package/bundled/dev-pipeline/templates/sections/bugfix-phase-implement.md +2 -2
- package/bundled/dev-pipeline/templates/sections/bugfix-phase-review.md +3 -3
- package/bundled/dev-pipeline/templates/sections/bugfix-phase-test.md +2 -2
- package/bundled/dev-pipeline/templates/sections/bugfix-reminders.md +4 -4
- package/bundled/dev-pipeline/templates/sections/bugfix-session-context.md +0 -1
- package/bundled/dev-pipeline/templates/sections/checkpoint-system.md +7 -4
- package/bundled/dev-pipeline/templates/sections/context-budget-rules.md +14 -27
- package/bundled/dev-pipeline/templates/sections/feature-completion-summary.md +20 -0
- package/bundled/dev-pipeline/templates/sections/phase-commit-full.md +8 -71
- package/bundled/dev-pipeline/templates/sections/phase-implement-full.md +7 -7
- package/bundled/dev-pipeline/templates/sections/phase-prizmkit-test.md +3 -3
- package/bundled/dev-pipeline/templates/sections/phase-review-full.md +4 -4
- package/bundled/dev-pipeline/templates/sections/phase-specify-plan-full.md +5 -17
- package/bundled/dev-pipeline/templates/sections/refactor-critical-paths.md +3 -1
- package/bundled/dev-pipeline/templates/sections/refactor-phase-commit-report.md +10 -23
- package/bundled/dev-pipeline/templates/sections/refactor-phase-implement.md +2 -2
- package/bundled/dev-pipeline/templates/sections/refactor-phase-plan.md +2 -2
- package/bundled/dev-pipeline/templates/sections/refactor-phase-review.md +3 -3
- package/bundled/dev-pipeline/templates/sections/refactor-phase-test.md +2 -2
- package/bundled/dev-pipeline/templates/sections/refactor-reminders.md +7 -7
- package/bundled/dev-pipeline/templates/sections/refactor-session-context.md +0 -1
- package/bundled/dev-pipeline/templates/sections/retrospective.md +12 -0
- package/bundled/dev-pipeline/templates/sections/runtime-commit-handoff.md +35 -0
- package/bundled/dev-pipeline/templates/session-status-schema.json +45 -62
- package/bundled/dev-pipeline/tests/test_auto_skip.py +111 -32
- package/bundled/dev-pipeline/tests/test_checkpoint_state.py +617 -30
- package/bundled/dev-pipeline/tests/test_generate_bootstrap_prompt.py +262 -194
- package/bundled/dev-pipeline/tests/test_generate_bugfix_prompt.py +62 -23
- package/bundled/dev-pipeline/tests/test_generate_refactor_prompt.py +76 -28
- package/bundled/dev-pipeline/tests/test_python_runner_parity.py +281 -206
- package/bundled/dev-pipeline/tests/test_recovery_workflow.py +322 -0
- package/bundled/dev-pipeline/tests/test_reset_modes.py +935 -0
- package/bundled/dev-pipeline/tests/test_reset_preserve.py +5 -7
- package/bundled/dev-pipeline/tests/test_runtime_commit.py +608 -0
- package/bundled/dev-pipeline/tests/test_unified_cli.py +617 -188
- package/bundled/skills/_metadata.json +9 -9
- package/bundled/skills/app-planner/SKILL.md +3 -3
- package/bundled/skills/app-planner/references/generated-plan-review.md +2 -1
- package/bundled/skills/app-planner/references/rules/backend/derivation-rules.md +56 -64
- package/bundled/skills/app-planner/references/rules/backend/fixed-rules.md +85 -240
- package/bundled/skills/app-planner/references/rules/backend/question-bank.md +25 -25
- package/bundled/skills/app-planner/references/rules/backend/question-manifest.json +16 -7
- package/bundled/skills/app-planner/references/rules/backend/template.md +74 -92
- package/bundled/skills/app-planner/references/rules/database/derivation-rules.md +93 -93
- package/bundled/skills/app-planner/references/rules/database/fixed-rules.md +66 -173
- package/bundled/skills/app-planner/references/rules/database/question-bank.md +31 -26
- package/bundled/skills/app-planner/references/rules/database/question-manifest.json +13 -4
- package/bundled/skills/app-planner/references/rules/database/template.md +76 -98
- package/bundled/skills/app-planner/references/rules/frontend/derivation-rules.md +68 -95
- package/bundled/skills/app-planner/references/rules/frontend/fixed-rules.md +93 -166
- package/bundled/skills/app-planner/references/rules/frontend/question-bank.md +46 -36
- package/bundled/skills/app-planner/references/rules/frontend/question-manifest.json +11 -2
- package/bundled/skills/app-planner/references/rules/frontend/template.md +79 -257
- package/bundled/skills/app-planner/references/rules/mobile/derivation-rules.md +91 -99
- package/bundled/skills/app-planner/references/rules/mobile/fixed-rules.md +73 -246
- package/bundled/skills/app-planner/references/rules/mobile/question-bank.md +17 -17
- package/bundled/skills/app-planner/references/rules/mobile/question-manifest.json +17 -2
- package/bundled/skills/app-planner/references/rules/mobile/template.md +73 -85
- package/bundled/skills/app-planner/references/rules-configuration.md +133 -65
- package/bundled/skills/app-planner/scripts/validate-rules-configuration.py +291 -0
- package/bundled/skills/bug-planner/references/schema-validation.md +1 -1
- package/bundled/skills/bug-planner/scripts/validate-bug-list.py +1 -1
- package/bundled/skills/bugfix-pipeline-launcher/SKILL.md +21 -13
- package/bundled/skills/feature-pipeline-launcher/SKILL.md +22 -14
- package/bundled/skills/prizmkit/SKILL.md +17 -18
- package/bundled/skills/prizmkit/references/workflow-state-protocol.md +22 -18
- package/bundled/skills/prizmkit-code-review/SKILL.md +22 -58
- package/bundled/skills/prizmkit-code-review/references/independent-code-review.md +6 -6
- package/bundled/skills/prizmkit-code-review/references/review-report-template.md +2 -2
- package/bundled/skills/prizmkit-committer/SKILL.md +82 -132
- package/bundled/skills/prizmkit-deploy/SKILL.md +27 -11
- package/bundled/skills/prizmkit-deploy/assets/deploy-document-template.md +89 -0
- package/bundled/skills/prizmkit-deploy/references/ci-cd-workflows.md +44 -14
- package/bundled/skills/prizmkit-deploy/references/cloud-platform-deploy.md +19 -3
- package/bundled/skills/prizmkit-deploy/references/database-setup.md +22 -12
- package/bundled/skills/prizmkit-deploy/references/deploy-config-schema.md +3 -1
- package/bundled/skills/prizmkit-deploy/references/deploy-history-schema.md +22 -6
- package/bundled/skills/prizmkit-deploy/references/deploy-metadata-schema.json +49 -0
- package/bundled/skills/prizmkit-deploy/references/live-validation-notes.md +1 -1
- package/bundled/skills/prizmkit-deploy/references/pending-input-schema.json +164 -0
- package/bundled/skills/prizmkit-deploy/references/ssh-adapter-flow.md +9 -8
- package/bundled/skills/prizmkit-deploy/references/ssh-execution-flow.md +6 -6
- package/bundled/skills/prizmkit-implement/SKILL.md +30 -66
- package/bundled/skills/prizmkit-implement/references/implementation-subagent-procedure.md +4 -4
- package/bundled/skills/prizmkit-init/SKILL.md +4 -0
- package/bundled/skills/prizmkit-plan/SKILL.md +21 -64
- package/bundled/skills/prizmkit-plan/references/artifact-identity.md +38 -0
- package/bundled/skills/prizmkit-plan/references/independent-plan-review.md +4 -4
- package/bundled/skills/prizmkit-plan/references/review-plan-spec-loop.md +5 -5
- package/bundled/skills/prizmkit-prizm-docs/SKILL.md +11 -1
- package/bundled/skills/prizmkit-retrospective/SKILL.md +63 -77
- package/bundled/skills/prizmkit-retrospective/references/knowledge-injection-steps.md +3 -3
- package/bundled/skills/prizmkit-retrospective/references/retrospective-result-schema.json +138 -0
- package/bundled/skills/prizmkit-retrospective/references/structural-sync-steps.md +17 -23
- package/bundled/skills/prizmkit-test/SKILL.md +64 -51
- package/bundled/skills/prizmkit-test/references/boundary-contract-and-test-double-guidance.md +206 -0
- package/bundled/skills/prizmkit-test/references/independent-test-review.md +17 -9
- package/bundled/skills/prizmkit-test/references/test-coverage-model.md +45 -21
- package/bundled/skills/prizmkit-test/references/test-report-template.md +20 -13
- package/bundled/skills/prizmkit-workflow/SKILL.md +35 -37
- package/bundled/skills/prizmkit-workflow/references/artifact-identity.md +34 -0
- package/bundled/skills/prizmkit-workflow/references/workflow-state-protocol.md +22 -18
- package/bundled/skills/recovery-workflow/SKILL.md +9 -6
- package/bundled/skills/recovery-workflow/evals/evals.json +2 -2
- package/bundled/skills/recovery-workflow/references/detection.md +7 -6
- package/bundled/skills/recovery-workflow/scripts/detect-recovery-state.py +16 -6
- package/bundled/skills/refactor-pipeline-launcher/SKILL.md +21 -13
- package/bundled/templates/project-memory-template.md +19 -11
- package/package.json +1 -1
- package/src/scaffold.js +33 -22
- package/bundled/dev-pipeline/prizmkit_runtime/runner_recovery.py +0 -228
- package/bundled/dev-pipeline/scripts/generate-recovery-prompt.py +0 -767
- package/bundled/dev-pipeline/templates/sections/bugfix-artifacts.md +0 -16
- package/bundled/dev-pipeline/templates/sections/bugfix-session-status.md +0 -31
- package/bundled/dev-pipeline/templates/sections/critical-paths-agent.md +0 -7
- package/bundled/dev-pipeline/templates/sections/critical-paths-lite.md +0 -7
- package/bundled/dev-pipeline/templates/sections/directory-convention-agent.md +0 -9
- package/bundled/dev-pipeline/templates/sections/directory-convention-lite.md +0 -6
- package/bundled/dev-pipeline/templates/sections/headless-commit-authorization.md +0 -15
- package/bundled/dev-pipeline/templates/sections/phase-commit.md +0 -61
- package/bundled/dev-pipeline/templates/sections/phase-context-snapshot-agent-suffix.md +0 -24
- package/bundled/dev-pipeline/templates/sections/phase-context-snapshot-lite-suffix.md +0 -12
- package/bundled/dev-pipeline/templates/sections/phase-implement-agent.md +0 -44
- package/bundled/dev-pipeline/templates/sections/phase-implement-lite.md +0 -25
- package/bundled/dev-pipeline/templates/sections/phase-plan-agent.md +0 -20
- package/bundled/dev-pipeline/templates/sections/phase-plan-lite.md +0 -20
- package/bundled/dev-pipeline/templates/sections/phase-review-agent.md +0 -20
- package/bundled/dev-pipeline/templates/sections/refactor-artifacts.md +0 -17
- package/bundled/dev-pipeline/templates/sections/refactor-session-status.md +0 -28
- package/bundled/dev-pipeline/templates/sections/test-failure-recovery-agent.md +0 -52
- package/bundled/dev-pipeline/templates/sections/test-failure-recovery-lite.md +0 -52
- package/bundled/skills/prizmkit-code-review/references/workflow-state-protocol.md +0 -174
- package/bundled/skills/prizmkit-committer/references/workflow-state-protocol.md +0 -174
- package/bundled/skills/prizmkit-implement/references/workflow-state-protocol.md +0 -174
- package/bundled/skills/prizmkit-plan/references/workflow-state-protocol.md +0 -174
- package/bundled/skills/prizmkit-retrospective/references/workflow-state-protocol.md +0 -174
- package/bundled/skills/prizmkit-test/references/external-contract-mock-guidance.md +0 -119
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""Python foreground runner dispatch for feature, bugfix, refactor
|
|
1
|
+
"""Python foreground runner dispatch for feature, bugfix, and refactor pipelines."""
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
@@ -6,6 +6,7 @@ import json
|
|
|
6
6
|
import os
|
|
7
7
|
import signal
|
|
8
8
|
import sys
|
|
9
|
+
import tempfile
|
|
9
10
|
import threading
|
|
10
11
|
import time
|
|
11
12
|
from collections.abc import Iterator, Mapping
|
|
@@ -19,6 +20,7 @@ from .gitops import (
|
|
|
19
20
|
WorktreePolicy,
|
|
20
21
|
branch_create_plan,
|
|
21
22
|
branch_ensure_return,
|
|
23
|
+
branch_fast_forward_possible,
|
|
22
24
|
branch_merge_plan,
|
|
23
25
|
branch_save_wip,
|
|
24
26
|
current_branch,
|
|
@@ -41,10 +43,18 @@ from .runner_bookkeeping import (
|
|
|
41
43
|
commit_wip_changes,
|
|
42
44
|
)
|
|
43
45
|
from .runner_classification import classify_session, has_branch_completion_evidence, has_completed_artifact_path
|
|
44
|
-
from .runner_models import
|
|
46
|
+
from .runner_models import (
|
|
47
|
+
RunnerEnvironment,
|
|
48
|
+
RunnerFamily,
|
|
49
|
+
RunnerInvocation,
|
|
50
|
+
SessionClassification,
|
|
51
|
+
SessionPaths,
|
|
52
|
+
family_for,
|
|
53
|
+
parse_invocation,
|
|
54
|
+
)
|
|
45
55
|
from .runner_prompts import PromptGenerationResult, generate_prompt
|
|
46
|
-
from .
|
|
47
|
-
from .runner_status import get_next,
|
|
56
|
+
from .runtime_commit import REQUEST_FILENAME, RuntimeCommitResult, finalize_runtime_commit
|
|
57
|
+
from .runner_status import get_next, start_item, status_text, update_item
|
|
48
58
|
from .sessions import AISessionConfig, AISessionLauncher, detect_stream_json_support
|
|
49
59
|
from .task_checkout import (
|
|
50
60
|
CHECKOUT_MODE_BRANCH,
|
|
@@ -95,21 +105,6 @@ def run_pipeline_command(kind: str, action: str, legacy_args: tuple[str, ...], p
|
|
|
95
105
|
if action == "status":
|
|
96
106
|
status = status_text(family, invocation, paths.project_root)
|
|
97
107
|
return CommandResult(status.return_code, f"Python {kind} status", status.stdout.strip() or status.stderr.strip())
|
|
98
|
-
if action == "unskip":
|
|
99
|
-
status = run_status_action(
|
|
100
|
-
family,
|
|
101
|
-
"unskip",
|
|
102
|
-
invocation,
|
|
103
|
-
item_id=invocation.item_id,
|
|
104
|
-
project_root=paths.project_root,
|
|
105
|
-
)
|
|
106
|
-
return CommandResult(
|
|
107
|
-
status.return_code,
|
|
108
|
-
f"Python {kind} unskip",
|
|
109
|
-
status.stdout.strip() or status.stderr.strip(),
|
|
110
|
-
)
|
|
111
|
-
if action == "test-cli":
|
|
112
|
-
return _test_cli(kind, paths)
|
|
113
108
|
if action != "run":
|
|
114
109
|
return CommandResult(1, "Unsupported Python runner action", f"Unsupported action: {kind} {action}")
|
|
115
110
|
if not invocation.list_path.is_file():
|
|
@@ -121,24 +116,13 @@ def run_pipeline_command(kind: str, action: str, legacy_args: tuple[str, ...], p
|
|
|
121
116
|
return CommandResult(1, f"Python {kind} runner failed", str(exc))
|
|
122
117
|
details = result.details + ((f"last_status: {result.last_status}",) if result.last_status else ())
|
|
123
118
|
return CommandResult(
|
|
124
|
-
0 if result.completed else 1,
|
|
119
|
+
0 if result.completed or result.last_status == "dry_run" else 1,
|
|
125
120
|
f"Python {kind} runner",
|
|
126
121
|
f"processed={result.processed} completed={result.completed} stopped_reason={result.stopped_reason or 'none'}",
|
|
127
122
|
details=details,
|
|
128
123
|
)
|
|
129
124
|
|
|
130
125
|
|
|
131
|
-
def run_recovery_command(action: str, legacy_args: tuple[str, ...], paths) -> CommandResult:
|
|
132
|
-
"""Dispatch a Python recovery command."""
|
|
133
|
-
if action == "detect":
|
|
134
|
-
code, stdout, stderr, _data = run_recovery_detect(paths)
|
|
135
|
-
return CommandResult(code, "Python recovery detect", stdout.strip() or stderr.strip())
|
|
136
|
-
if action == "run":
|
|
137
|
-
code, stdout, stderr = run_recovery(paths, legacy_args)
|
|
138
|
-
return CommandResult(code, "Python recovery run", stdout.strip() or stderr.strip())
|
|
139
|
-
return CommandResult(1, "Unsupported Python recovery action", f"Unsupported action: {action}")
|
|
140
|
-
|
|
141
|
-
|
|
142
126
|
def _run_pipeline(family: RunnerFamily, invocation: RunnerInvocation, paths) -> "PipelineRunResult":
|
|
143
127
|
from .runner_models import PipelineRunResult
|
|
144
128
|
|
|
@@ -150,7 +134,12 @@ def _run_pipeline(family: RunnerFamily, invocation: RunnerInvocation, paths) ->
|
|
|
150
134
|
except KeyboardInterrupt:
|
|
151
135
|
with shield_interruption_signals():
|
|
152
136
|
return PipelineRunResult(False, 1, "interrupted", "interrupted")
|
|
153
|
-
return PipelineRunResult(
|
|
137
|
+
return PipelineRunResult(
|
|
138
|
+
status == "completed",
|
|
139
|
+
1,
|
|
140
|
+
"dry_run" if status == "dry_run" else "single_item_done",
|
|
141
|
+
status,
|
|
142
|
+
)
|
|
154
143
|
|
|
155
144
|
while True:
|
|
156
145
|
next_result = get_next(family, invocation, paths.project_root)
|
|
@@ -182,6 +171,14 @@ def _run_pipeline(family: RunnerFamily, invocation: RunnerInvocation, paths) ->
|
|
|
182
171
|
item_id = str(next_result.data.get(f"{family.kind}_id") or next_result.data.get("feature_id") or next_result.data.get("bug_id") or next_result.data.get("refactor_id") or "")
|
|
183
172
|
if not item_id:
|
|
184
173
|
return PipelineRunResult(False, processed, "missing_item_id", details=(marker[:500],))
|
|
174
|
+
if item_id in item_statuses:
|
|
175
|
+
return PipelineRunResult(
|
|
176
|
+
False,
|
|
177
|
+
processed,
|
|
178
|
+
"reselected_item",
|
|
179
|
+
item_statuses[item_id],
|
|
180
|
+
_render_item_statuses(item_statuses),
|
|
181
|
+
)
|
|
185
182
|
try:
|
|
186
183
|
final_status = _process_item(family, invocation, item_id, paths, initial_metadata=next_result.data)
|
|
187
184
|
except KeyboardInterrupt:
|
|
@@ -197,6 +194,22 @@ def _run_pipeline(family: RunnerFamily, invocation: RunnerInvocation, paths) ->
|
|
|
197
194
|
)
|
|
198
195
|
processed += 1
|
|
199
196
|
item_statuses[item_id] = final_status
|
|
197
|
+
if final_status == "dry_run":
|
|
198
|
+
return PipelineRunResult(
|
|
199
|
+
False,
|
|
200
|
+
processed,
|
|
201
|
+
"dry_run",
|
|
202
|
+
final_status,
|
|
203
|
+
_render_item_statuses(item_statuses),
|
|
204
|
+
)
|
|
205
|
+
if final_status == "skipped":
|
|
206
|
+
return PipelineRunResult(
|
|
207
|
+
False,
|
|
208
|
+
processed,
|
|
209
|
+
"item_skipped",
|
|
210
|
+
final_status,
|
|
211
|
+
_render_item_statuses(item_statuses),
|
|
212
|
+
)
|
|
200
213
|
if final_status in _completion_compatible_statuses(family):
|
|
201
214
|
if final_status == "completed":
|
|
202
215
|
_emit_info(f"Pausing 5s before next {family.kind}...")
|
|
@@ -210,7 +223,7 @@ def _run_pipeline(family: RunnerFamily, invocation: RunnerInvocation, paths) ->
|
|
|
210
223
|
return PipelineRunResult(False, processed, "item_failed", final_status, details)
|
|
211
224
|
|
|
212
225
|
|
|
213
|
-
_COMPLETION_COMPATIBLE_STATUSES = {"completed", "
|
|
226
|
+
_COMPLETION_COMPATIBLE_STATUSES = {"completed", "auto_skipped"}
|
|
214
227
|
|
|
215
228
|
|
|
216
229
|
def _completion_compatible_statuses(family: RunnerFamily) -> set[str]:
|
|
@@ -423,21 +436,10 @@ def _child_log_activity_summary(progress: Mapping[str, object]) -> str:
|
|
|
423
436
|
return _bytes_text(child_bytes)
|
|
424
437
|
|
|
425
438
|
|
|
426
|
-
def _emit_prompt_summary(
|
|
427
|
-
if prompt.pipeline_mode:
|
|
428
|
-
_emit_info(f"Pipeline mode: {_pipeline_mode_label(prompt.pipeline_mode)}")
|
|
439
|
+
def _emit_prompt_summary(_prompt: PromptGenerationResult, session_id: str) -> None:
|
|
429
440
|
_emit_info(f"Spawning AI CLI session: {session_id}")
|
|
430
441
|
|
|
431
442
|
|
|
432
|
-
def _pipeline_mode_label(mode: str) -> str:
|
|
433
|
-
labels = {
|
|
434
|
-
"lite": "lite (Tier 1 — Scoped Guidance)",
|
|
435
|
-
"standard": "standard (Tier 2 — Review Gates)",
|
|
436
|
-
"full": "full (Full Guidance)",
|
|
437
|
-
}
|
|
438
|
-
return labels.get(mode, mode)
|
|
439
|
-
|
|
440
|
-
|
|
441
443
|
def _emit_session_summary(session_result, session_paths: SessionPaths, classification) -> None:
|
|
442
444
|
lines, size = _session_log_summary(session_paths.session_log)
|
|
443
445
|
_emit_info(f"Session log: {lines} lines, {size}")
|
|
@@ -482,6 +484,8 @@ def _process_item(
|
|
|
482
484
|
*,
|
|
483
485
|
initial_metadata: dict[str, object],
|
|
484
486
|
) -> str:
|
|
487
|
+
if invocation.dry_run:
|
|
488
|
+
return _preview_item(family, invocation, item_id, paths, initial_metadata)
|
|
485
489
|
try:
|
|
486
490
|
with task_checkout_guard(family.state_dir, item_id):
|
|
487
491
|
return _process_item_locked(family, invocation, item_id, paths, initial_metadata=initial_metadata)
|
|
@@ -489,6 +493,44 @@ def _process_item(
|
|
|
489
493
|
raise
|
|
490
494
|
|
|
491
495
|
|
|
496
|
+
def _preview_item(
|
|
497
|
+
family: RunnerFamily,
|
|
498
|
+
invocation: RunnerInvocation,
|
|
499
|
+
item_id: str,
|
|
500
|
+
paths,
|
|
501
|
+
initial_metadata: dict[str, object],
|
|
502
|
+
) -> str:
|
|
503
|
+
"""Render one disposable Prompt preview without mutating task or Git state."""
|
|
504
|
+
config = load_runtime_config(paths)
|
|
505
|
+
if not config.ai_client.command:
|
|
506
|
+
raise RuntimeError("No supported AI CLI command was found")
|
|
507
|
+
metadata = _with_recovery_metadata(family, item_id, initial_metadata)
|
|
508
|
+
retry_count = int(metadata.get("retry_count") or 0)
|
|
509
|
+
session_id = f"{item_id}-dry-run"
|
|
510
|
+
_emit_item_header(family, invocation, item_id, metadata)
|
|
511
|
+
with tempfile.TemporaryDirectory(prefix="prizmkit-dry-run-") as temporary:
|
|
512
|
+
session_paths = SessionPaths.for_item(Path(temporary), item_id, session_id)
|
|
513
|
+
prompt = generate_prompt(
|
|
514
|
+
family,
|
|
515
|
+
invocation,
|
|
516
|
+
item_id=item_id,
|
|
517
|
+
session_id=session_id,
|
|
518
|
+
run_id="dry-run",
|
|
519
|
+
retry_count=retry_count,
|
|
520
|
+
session_paths=session_paths,
|
|
521
|
+
project_root=paths.project_root,
|
|
522
|
+
execution_root=paths.project_root,
|
|
523
|
+
preview=True,
|
|
524
|
+
)
|
|
525
|
+
prompt_size = prompt.output_path.stat().st_size
|
|
526
|
+
model = prompt.model or config.model or "default"
|
|
527
|
+
_emit_info(
|
|
528
|
+
f"Dry-run Prompt validated for {item_id}: model={model}, bytes={prompt_size}; "
|
|
529
|
+
"no checkout, checkpoint, task status, or AI session was created"
|
|
530
|
+
)
|
|
531
|
+
return "dry_run"
|
|
532
|
+
|
|
533
|
+
|
|
492
534
|
def _process_item_locked(
|
|
493
535
|
family: RunnerFamily,
|
|
494
536
|
invocation: RunnerInvocation,
|
|
@@ -677,8 +719,6 @@ def _process_item_locked(
|
|
|
677
719
|
execution_root=execution_root,
|
|
678
720
|
continuation=continuation,
|
|
679
721
|
)
|
|
680
|
-
if invocation.dry_run:
|
|
681
|
-
return "dry_run"
|
|
682
722
|
_emit_prompt_summary(prompt, session_id)
|
|
683
723
|
stream_json = False
|
|
684
724
|
if getattr(config.ai_client, "launch_profile", None) is None:
|
|
@@ -707,6 +747,10 @@ def _process_item_locked(
|
|
|
707
747
|
suppress_stream_output=True,
|
|
708
748
|
)
|
|
709
749
|
).run()
|
|
750
|
+
runtime_commit = _finalize_prepared_runtime_commit(
|
|
751
|
+
execution_root,
|
|
752
|
+
prompt,
|
|
753
|
+
)
|
|
710
754
|
classification = classify_session(
|
|
711
755
|
session_result,
|
|
712
756
|
project_root=execution_root,
|
|
@@ -715,6 +759,13 @@ def _process_item_locked(
|
|
|
715
759
|
previous_fingerprint=previous_fingerprint,
|
|
716
760
|
previous_no_progress_count=previous_no_progress_count,
|
|
717
761
|
)
|
|
762
|
+
if runtime_commit.status == "failed":
|
|
763
|
+
classification = SessionClassification(
|
|
764
|
+
"commit_missing",
|
|
765
|
+
reason=runtime_commit.reason,
|
|
766
|
+
progress_fingerprint=classification.progress_fingerprint,
|
|
767
|
+
checkpoint_state=classification.checkpoint_state,
|
|
768
|
+
)
|
|
718
769
|
_emit_session_summary(session_result, session_paths, classification)
|
|
719
770
|
final_session_status = classification.session_status
|
|
720
771
|
summary_path = _continuation_summary_path(execution_root, family, item_id, prompt)
|
|
@@ -938,6 +989,34 @@ def _emit_interruption_cleanup_failure(result, message: str, recovery: str) -> N
|
|
|
938
989
|
_emit_warning(recovery)
|
|
939
990
|
|
|
940
991
|
|
|
992
|
+
def _finalize_prepared_runtime_commit(
|
|
993
|
+
execution_root: Path,
|
|
994
|
+
prompt: PromptGenerationResult,
|
|
995
|
+
) -> RuntimeCommitResult:
|
|
996
|
+
"""Execute a prepared commit only when the checkpoint proves readiness."""
|
|
997
|
+
checkpoint = prompt.checkpoint_path
|
|
998
|
+
artifact = prompt.artifact_path
|
|
999
|
+
if checkpoint is None or artifact is None or not checkpoint.is_file():
|
|
1000
|
+
return RuntimeCommitResult("not_ready", "commit_handoff_unavailable")
|
|
1001
|
+
from .checkpoint_state import load_checkpoint_state
|
|
1002
|
+
|
|
1003
|
+
state = load_checkpoint_state(checkpoint, project_root=execution_root)
|
|
1004
|
+
request_path = artifact / REQUEST_FILENAME
|
|
1005
|
+
cleanup_recovery = state.semantic_complete and request_path.is_file()
|
|
1006
|
+
if not state.semantic_commit_ready and not cleanup_recovery:
|
|
1007
|
+
return RuntimeCommitResult("not_ready", "checkpoint_not_commit_ready")
|
|
1008
|
+
result = finalize_runtime_commit(
|
|
1009
|
+
execution_root,
|
|
1010
|
+
artifact_dir=artifact,
|
|
1011
|
+
checkpoint_path=checkpoint,
|
|
1012
|
+
)
|
|
1013
|
+
if result.committed:
|
|
1014
|
+
_emit_success(f"Runtime committed prepared task change: {result.commit_hash}")
|
|
1015
|
+
else:
|
|
1016
|
+
_emit_warning(f"Runtime commit preparation failed: {result.reason}")
|
|
1017
|
+
return result
|
|
1018
|
+
|
|
1019
|
+
|
|
941
1020
|
def _is_retryable_ai_outcome(session_status: str, new_status: str) -> bool:
|
|
942
1021
|
"""Return whether a persisted post-launch outcome should continue in-process."""
|
|
943
1022
|
if session_status in {
|
|
@@ -1069,7 +1148,17 @@ def _complete_success_merge(
|
|
|
1069
1148
|
return new_status
|
|
1070
1149
|
else:
|
|
1071
1150
|
_emit_info(f"Merging {branch_name} into {base_branch}...")
|
|
1072
|
-
merge = run_git_plan(
|
|
1151
|
+
merge = run_git_plan(
|
|
1152
|
+
paths.project_root,
|
|
1153
|
+
branch_merge_plan(
|
|
1154
|
+
branch_context,
|
|
1155
|
+
auto_push=env.auto_push,
|
|
1156
|
+
rebase=not branch_fast_forward_possible(
|
|
1157
|
+
paths.project_root,
|
|
1158
|
+
branch_context,
|
|
1159
|
+
),
|
|
1160
|
+
),
|
|
1161
|
+
)
|
|
1073
1162
|
_emit_git_plan_output(merge)
|
|
1074
1163
|
if merge.ok:
|
|
1075
1164
|
checkout = load_task_checkout(family.state_dir, family.task_type, item_id)
|
|
@@ -1165,28 +1254,6 @@ def _record_setup_failure(
|
|
|
1165
1254
|
branch_ensure_return(project_root, base_branch, branch_name)
|
|
1166
1255
|
return new_status
|
|
1167
1256
|
|
|
1168
|
-
def _test_cli(kind: str, paths) -> CommandResult:
|
|
1169
|
-
"""Report the AI CLI resolution used by Python runner commands."""
|
|
1170
|
-
config = load_runtime_config(paths)
|
|
1171
|
-
cli = config.ai_client.command or "(not found)"
|
|
1172
|
-
platform = config.ai_client.platform or "unresolved"
|
|
1173
|
-
details = [
|
|
1174
|
-
f"detected_cli: {cli}",
|
|
1175
|
-
f"platform: {platform}",
|
|
1176
|
-
f"source: {config.ai_client.source}",
|
|
1177
|
-
f"runtime_mode: {config.runtime_mode}",
|
|
1178
|
-
]
|
|
1179
|
-
if config.model:
|
|
1180
|
-
details.append(f"model: {config.model}")
|
|
1181
|
-
details.extend(f"note: {note}" for note in config.ai_client.notes)
|
|
1182
|
-
return CommandResult(
|
|
1183
|
-
0 if config.ai_client.command else 1,
|
|
1184
|
-
f"Python {kind} AI CLI test",
|
|
1185
|
-
"AI CLI resolution for the canonical Python runtime.",
|
|
1186
|
-
tuple(details),
|
|
1187
|
-
)
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
1257
|
def _use_worktree_for_family(env: RunnerEnvironment, family: RunnerFamily) -> bool:
|
|
1191
1258
|
return env.use_worktree and family.kind in {"feature", "bugfix"}
|
|
1192
1259
|
|
|
@@ -1218,7 +1285,6 @@ def _invocation_for_execution_family(invocation: RunnerInvocation, family: Runne
|
|
|
1218
1285
|
item_filter=invocation.item_filter,
|
|
1219
1286
|
max_retries=invocation.max_retries,
|
|
1220
1287
|
max_infra_retries=invocation.max_infra_retries,
|
|
1221
|
-
mode=invocation.mode,
|
|
1222
1288
|
dry_run=invocation.dry_run,
|
|
1223
1289
|
clean=invocation.clean,
|
|
1224
1290
|
no_reset=invocation.no_reset,
|
|
@@ -1341,7 +1407,6 @@ def _resolve_invocation_paths(invocation: RunnerInvocation, project_root: Path)
|
|
|
1341
1407
|
item_filter=invocation.item_filter,
|
|
1342
1408
|
max_retries=invocation.max_retries,
|
|
1343
1409
|
max_infra_retries=invocation.max_infra_retries,
|
|
1344
|
-
mode=invocation.mode,
|
|
1345
1410
|
dry_run=invocation.dry_run,
|
|
1346
1411
|
clean=invocation.clean,
|
|
1347
1412
|
no_reset=invocation.no_reset,
|
|
@@ -1355,6 +1420,6 @@ def _resolve_invocation_paths(invocation: RunnerInvocation, project_root: Path)
|
|
|
1355
1420
|
def _help_text(family: RunnerFamily) -> str:
|
|
1356
1421
|
return (
|
|
1357
1422
|
f"Python foreground runner for {family.kind}.\n"
|
|
1358
|
-
"Supported
|
|
1359
|
-
"--max-retries, --max-infra-retries, --
|
|
1423
|
+
"Supported options include plan list path, item id, --features for feature, "
|
|
1424
|
+
"--max-retries, --max-infra-retries, --resume-phase, and --dry-run."
|
|
1360
1425
|
)
|