prizmkit 1.1.100 → 1.1.102
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/bin/create-prizmkit.js +4 -4
- package/bundled/VERSION.json +3 -3
- package/bundled/dev-pipeline/.env.example +3 -3
- package/bundled/dev-pipeline/README.md +110 -90
- package/bundled/dev-pipeline/assets/prizm-dev-team-integration.md +1 -1
- package/bundled/dev-pipeline/cli.py +27 -0
- package/bundled/dev-pipeline/prizmkit_runtime/__init__.py +13 -0
- package/bundled/dev-pipeline/prizmkit_runtime/__main__.py +9 -0
- package/bundled/dev-pipeline/prizmkit_runtime/cli.py +193 -0
- package/bundled/dev-pipeline/prizmkit_runtime/commands.py +313 -0
- package/bundled/dev-pipeline/prizmkit_runtime/compat.py +32 -0
- package/bundled/dev-pipeline/prizmkit_runtime/config.py +410 -0
- package/bundled/dev-pipeline/prizmkit_runtime/daemon.py +478 -0
- package/bundled/dev-pipeline/prizmkit_runtime/gitops.py +734 -0
- package/bundled/dev-pipeline/prizmkit_runtime/heartbeat.py +256 -0
- package/bundled/dev-pipeline/prizmkit_runtime/interoperability.py +109 -0
- package/bundled/dev-pipeline/prizmkit_runtime/paths.py +110 -0
- package/bundled/dev-pipeline/prizmkit_runtime/processes.py +373 -0
- package/bundled/dev-pipeline/prizmkit_runtime/reset.py +389 -0
- package/bundled/dev-pipeline/prizmkit_runtime/runner_bookkeeping.py +51 -0
- package/bundled/dev-pipeline/prizmkit_runtime/runner_classification.py +179 -0
- package/bundled/dev-pipeline/prizmkit_runtime/runner_models.py +355 -0
- package/bundled/dev-pipeline/prizmkit_runtime/runner_prompts.py +118 -0
- package/bundled/dev-pipeline/prizmkit_runtime/runner_recovery.py +187 -0
- package/bundled/dev-pipeline/prizmkit_runtime/runner_status.py +153 -0
- package/bundled/dev-pipeline/prizmkit_runtime/runners.py +425 -0
- package/bundled/dev-pipeline/prizmkit_runtime/sessions.py +560 -0
- package/bundled/dev-pipeline/prizmkit_runtime/status.py +71 -0
- package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +51 -36
- package/bundled/dev-pipeline/scripts/generate-bugfix-prompt.py +20 -5
- package/bundled/dev-pipeline/scripts/generate-recovery-prompt.py +2 -2
- package/bundled/dev-pipeline/scripts/parse-stream-progress.py +39 -0
- package/bundled/dev-pipeline/templates/agent-prompts/dev-implement.md +8 -2
- package/bundled/dev-pipeline/templates/agent-prompts/reviewer-review.md +1 -1
- package/bundled/dev-pipeline/templates/bootstrap-prompt.md +6 -2
- package/bundled/dev-pipeline/templates/bootstrap-tier1.md +14 -6
- package/bundled/dev-pipeline/templates/bootstrap-tier2.md +14 -4
- package/bundled/dev-pipeline/templates/bootstrap-tier3.md +14 -4
- package/bundled/dev-pipeline/templates/sections/context-budget-rules.md +2 -0
- package/bundled/dev-pipeline/templates/sections/log-size-awareness.md +9 -30
- package/bundled/dev-pipeline/templates/sections/phase-context-snapshot-agent-suffix.md +15 -7
- package/bundled/dev-pipeline/templates/sections/phase-implement-agent.md +42 -29
- package/bundled/dev-pipeline/templates/sections/phase-implement-full.md +41 -39
- package/bundled/dev-pipeline/templates/sections/phase-implement-lite.md +8 -17
- package/bundled/dev-pipeline/templates/sections/phase-prizmkit-test.md +2 -2
- package/bundled/dev-pipeline/templates/sections/phase-review-agent.md +1 -3
- package/bundled/dev-pipeline/templates/sections/phase-review-full.md +1 -3
- package/bundled/dev-pipeline/templates/sections/phase0-test-baseline.md +3 -8
- package/bundled/dev-pipeline/templates/sections/test-failure-recovery-agent.md +6 -2
- package/bundled/dev-pipeline/templates/sections/test-failure-recovery-lite.md +5 -1
- package/bundled/dev-pipeline/tests/test_auto_skip.py +436 -14
- package/bundled/dev-pipeline/tests/test_generate_bootstrap_prompt.py +115 -7
- package/bundled/dev-pipeline/tests/test_generate_bugfix_prompt.py +40 -0
- package/bundled/dev-pipeline/tests/test_python_runner_parity.py +1226 -0
- package/bundled/dev-pipeline/tests/test_unified_cli.py +1045 -0
- package/bundled/skills/_metadata.json +1 -1
- package/bundled/skills/bugfix-pipeline-launcher/SKILL.md +29 -34
- package/bundled/skills/bugfix-pipeline-launcher/references/configuration.md +6 -5
- package/bundled/skills/feature-pipeline-launcher/SKILL.md +29 -35
- package/bundled/skills/feature-pipeline-launcher/references/configuration.md +7 -6
- package/bundled/skills/feature-workflow/SKILL.md +3 -6
- package/bundled/skills/recovery-workflow/SKILL.md +23 -32
- package/bundled/skills/refactor-pipeline-launcher/SKILL.md +29 -35
- package/bundled/skills/refactor-pipeline-launcher/references/configuration.md +7 -6
- package/bundled/skills/refactor-workflow/SKILL.md +3 -6
- package/bundled/templates/hooks/commit-intent.json +2 -2
- package/bundled/templates/hooks/diff-prizm-docs.py +226 -0
- package/bundled/templates/hooks/prizm-pre-commit.py +45 -0
- package/bundled/templates/hooks/validate-prizm-docs.py +240 -0
- package/package.json +1 -1
- package/src/config.js +42 -19
- package/src/external-skills.js +14 -14
- package/src/index.js +3 -6
- package/src/manifest.js +11 -5
- package/src/metadata.js +7 -18
- package/src/platforms.js +25 -0
- package/src/prompts.js +0 -12
- package/src/runtimes.js +18 -11
- package/src/scaffold.js +144 -122
- package/src/upgrade.js +12 -3
- package/bundled/dev-pipeline/launch-bugfix-daemon.sh +0 -500
- package/bundled/dev-pipeline/launch-feature-daemon.sh +0 -657
- package/bundled/dev-pipeline/launch-refactor-daemon.sh +0 -502
- package/bundled/dev-pipeline/lib/branch.sh +0 -326
- package/bundled/dev-pipeline/lib/common.sh +0 -1476
- package/bundled/dev-pipeline/lib/heartbeat.sh +0 -469
- package/bundled/dev-pipeline/reset-bug.sh +0 -425
- package/bundled/dev-pipeline/reset-feature.sh +0 -436
- package/bundled/dev-pipeline/reset-refactor.sh +0 -423
- package/bundled/dev-pipeline/run-bugfix.sh +0 -1430
- package/bundled/dev-pipeline/run-feature.sh +0 -1718
- package/bundled/dev-pipeline/run-recovery.sh +0 -648
- package/bundled/dev-pipeline/run-refactor.sh +0 -1463
- package/bundled/dev-pipeline/tests/test-path-resolution.sh +0 -100
- package/bundled/dev-pipeline-windows/.env.example +0 -36
- package/bundled/dev-pipeline-windows/README.md +0 -30
- package/bundled/dev-pipeline-windows/SCHEMA_ANALYSIS.md +0 -533
- package/bundled/dev-pipeline-windows/assets/feature-list-example.json +0 -146
- package/bundled/dev-pipeline-windows/assets/prizm-dev-team-integration.md +0 -137
- package/bundled/dev-pipeline-windows/launch-bugfix-daemon.ps1 +0 -9
- package/bundled/dev-pipeline-windows/launch-feature-daemon.ps1 +0 -9
- package/bundled/dev-pipeline-windows/launch-refactor-daemon.ps1 +0 -9
- package/bundled/dev-pipeline-windows/lib/branch.ps1 +0 -235
- package/bundled/dev-pipeline-windows/lib/common.ps1 +0 -991
- package/bundled/dev-pipeline-windows/lib/daemon.ps1 +0 -140
- package/bundled/dev-pipeline-windows/lib/pipeline.ps1 +0 -1051
- package/bundled/dev-pipeline-windows/lib/reset.ps1 +0 -121
- package/bundled/dev-pipeline-windows/reset-bug.ps1 +0 -10
- package/bundled/dev-pipeline-windows/reset-feature.ps1 +0 -10
- package/bundled/dev-pipeline-windows/reset-refactor.ps1 +0 -10
- package/bundled/dev-pipeline-windows/run-bugfix.ps1 +0 -9
- package/bundled/dev-pipeline-windows/run-feature.ps1 +0 -9
- package/bundled/dev-pipeline-windows/run-recovery.ps1 +0 -179
- package/bundled/dev-pipeline-windows/run-refactor.ps1 +0 -9
- package/bundled/dev-pipeline-windows/scripts/check-session-status.py +0 -301
- package/bundled/dev-pipeline-windows/scripts/continuation.py +0 -374
- package/bundled/dev-pipeline-windows/scripts/detect-stuck.py +0 -530
- package/bundled/dev-pipeline-windows/scripts/generate-bootstrap-prompt.py +0 -2279
- package/bundled/dev-pipeline-windows/scripts/generate-bugfix-prompt.py +0 -763
- package/bundled/dev-pipeline-windows/scripts/generate-recovery-prompt.py +0 -805
- package/bundled/dev-pipeline-windows/scripts/generate-refactor-prompt.py +0 -841
- package/bundled/dev-pipeline-windows/scripts/init-bugfix-pipeline.py +0 -316
- package/bundled/dev-pipeline-windows/scripts/init-dev-team.py +0 -134
- package/bundled/dev-pipeline-windows/scripts/init-pipeline.py +0 -382
- package/bundled/dev-pipeline-windows/scripts/init-refactor-pipeline.py +0 -399
- package/bundled/dev-pipeline-windows/scripts/parse-stream-progress.py +0 -1362
- package/bundled/dev-pipeline-windows/scripts/patch-completion-notes.py +0 -191
- package/bundled/dev-pipeline-windows/scripts/prizmkit-test-gate.py +0 -446
- package/bundled/dev-pipeline-windows/scripts/update-bug-status.py +0 -1121
- package/bundled/dev-pipeline-windows/scripts/update-checkpoint.py +0 -173
- package/bundled/dev-pipeline-windows/scripts/update-feature-status.py +0 -1789
- package/bundled/dev-pipeline-windows/scripts/update-refactor-status.py +0 -1327
- package/bundled/dev-pipeline-windows/scripts/utils.py +0 -542
- package/bundled/dev-pipeline-windows/templates/agent-prompts/critic-plan-challenge.md +0 -7
- package/bundled/dev-pipeline-windows/templates/agent-prompts/dev-fix.md +0 -7
- package/bundled/dev-pipeline-windows/templates/agent-prompts/dev-implement.md +0 -65
- package/bundled/dev-pipeline-windows/templates/agent-prompts/dev-resume.md +0 -5
- package/bundled/dev-pipeline-windows/templates/agent-prompts/reviewer-review.md +0 -7
- package/bundled/dev-pipeline-windows/templates/bootstrap-prompt.md +0 -73
- package/bundled/dev-pipeline-windows/templates/bootstrap-tier1.md +0 -589
- package/bundled/dev-pipeline-windows/templates/bootstrap-tier2.md +0 -710
- package/bundled/dev-pipeline-windows/templates/bootstrap-tier3.md +0 -791
- package/bundled/dev-pipeline-windows/templates/bug-fix-list-schema.json +0 -263
- package/bundled/dev-pipeline-windows/templates/bugfix-bootstrap-prompt.md +0 -326
- package/bundled/dev-pipeline-windows/templates/feature-list-schema.json +0 -237
- package/bundled/dev-pipeline-windows/templates/refactor-bootstrap-prompt.md +0 -340
- package/bundled/dev-pipeline-windows/templates/refactor-list-schema.json +0 -270
- package/bundled/dev-pipeline-windows/templates/sections/ac-verification-checklist.md +0 -7
- package/bundled/dev-pipeline-windows/templates/sections/checkpoint-system.md +0 -91
- package/bundled/dev-pipeline-windows/templates/sections/context-budget-rules.md +0 -34
- package/bundled/dev-pipeline-windows/templates/sections/critical-paths-agent.md +0 -10
- package/bundled/dev-pipeline-windows/templates/sections/critical-paths-full.md +0 -12
- package/bundled/dev-pipeline-windows/templates/sections/critical-paths-lite.md +0 -7
- package/bundled/dev-pipeline-windows/templates/sections/directory-convention-agent.md +0 -8
- package/bundled/dev-pipeline-windows/templates/sections/directory-convention-full.md +0 -9
- package/bundled/dev-pipeline-windows/templates/sections/directory-convention-lite.md +0 -6
- package/bundled/dev-pipeline-windows/templates/sections/failure-capture.md +0 -21
- package/bundled/dev-pipeline-windows/templates/sections/feature-context.md +0 -21
- package/bundled/dev-pipeline-windows/templates/sections/log-size-awareness.md +0 -41
- package/bundled/dev-pipeline-windows/templates/sections/phase-browser-verification-auto.md +0 -283
- package/bundled/dev-pipeline-windows/templates/sections/phase-browser-verification-opencli.md +0 -112
- package/bundled/dev-pipeline-windows/templates/sections/phase-browser-verification.md +0 -168
- package/bundled/dev-pipeline-windows/templates/sections/phase-commit-full.md +0 -82
- package/bundled/dev-pipeline-windows/templates/sections/phase-commit.md +0 -75
- package/bundled/dev-pipeline-windows/templates/sections/phase-context-snapshot-agent-suffix.md +0 -23
- package/bundled/dev-pipeline-windows/templates/sections/phase-context-snapshot-base.md +0 -14
- package/bundled/dev-pipeline-windows/templates/sections/phase-context-snapshot-lite-suffix.md +0 -19
- package/bundled/dev-pipeline-windows/templates/sections/phase-critic-plan-full.md +0 -63
- package/bundled/dev-pipeline-windows/templates/sections/phase-critic-plan.md +0 -42
- package/bundled/dev-pipeline-windows/templates/sections/phase-implement-agent.md +0 -44
- package/bundled/dev-pipeline-windows/templates/sections/phase-implement-full.md +0 -59
- package/bundled/dev-pipeline-windows/templates/sections/phase-implement-lite.md +0 -39
- package/bundled/dev-pipeline-windows/templates/sections/phase-plan-agent.md +0 -27
- package/bundled/dev-pipeline-windows/templates/sections/phase-plan-lite.md +0 -27
- package/bundled/dev-pipeline-windows/templates/sections/phase-prizmkit-test.md +0 -39
- package/bundled/dev-pipeline-windows/templates/sections/phase-review-agent.md +0 -35
- package/bundled/dev-pipeline-windows/templates/sections/phase-review-full.md +0 -35
- package/bundled/dev-pipeline-windows/templates/sections/phase-specify-plan-full.md +0 -73
- package/bundled/dev-pipeline-windows/templates/sections/phase0-init.md +0 -13
- package/bundled/dev-pipeline-windows/templates/sections/phase0-test-baseline.md +0 -21
- package/bundled/dev-pipeline-windows/templates/sections/session-context.md +0 -5
- package/bundled/dev-pipeline-windows/templates/sections/subagent-timeout-recovery.md +0 -6
- package/bundled/dev-pipeline-windows/templates/sections/task-contract.md +0 -34
- package/bundled/dev-pipeline-windows/templates/sections/test-failure-recovery-agent.md +0 -48
- package/bundled/dev-pipeline-windows/templates/sections/test-failure-recovery-lite.md +0 -48
- package/bundled/dev-pipeline-windows/templates/session-status-schema.json +0 -83
- package/bundled/skills-windows/app-planner/SKILL.md +0 -296
- package/bundled/skills-windows/app-planner/assets/app-design-guide.md +0 -101
- package/bundled/skills-windows/app-planner/references/architecture-decisions.md +0 -52
- package/bundled/skills-windows/app-planner/references/brainstorm-guide.md +0 -101
- package/bundled/skills-windows/app-planner/references/frontend-design-guide.md +0 -71
- package/bundled/skills-windows/app-planner/references/infrastructure-convention-discovery.md +0 -108
- package/bundled/skills-windows/app-planner/references/project-brief-guide.md +0 -82
- package/bundled/skills-windows/app-planner/references/project-conventions-discovery.md +0 -59
- package/bundled/skills-windows/app-planner/references/project-state-detection.md +0 -90
- package/bundled/skills-windows/app-planner/references/red-team-checklist.md +0 -40
- package/bundled/skills-windows/app-planner/references/rules/backend/derivation-rules.md +0 -619
- package/bundled/skills-windows/app-planner/references/rules/backend/fixed-rules.md +0 -285
- package/bundled/skills-windows/app-planner/references/rules/backend/question-bank.md +0 -249
- package/bundled/skills-windows/app-planner/references/rules/backend/question-manifest.json +0 -46
- package/bundled/skills-windows/app-planner/references/rules/backend/template.md +0 -173
- package/bundled/skills-windows/app-planner/references/rules/database/derivation-rules.md +0 -382
- package/bundled/skills-windows/app-planner/references/rules/database/fixed-rules.md +0 -211
- package/bundled/skills-windows/app-planner/references/rules/database/question-bank.md +0 -184
- package/bundled/skills-windows/app-planner/references/rules/database/question-manifest.json +0 -39
- package/bundled/skills-windows/app-planner/references/rules/database/template.md +0 -158
- package/bundled/skills-windows/app-planner/references/rules/frontend/derivation-rules.md +0 -820
- package/bundled/skills-windows/app-planner/references/rules/frontend/fixed-rules.md +0 -188
- package/bundled/skills-windows/app-planner/references/rules/frontend/question-bank.md +0 -319
- package/bundled/skills-windows/app-planner/references/rules/frontend/question-manifest.json +0 -51
- package/bundled/skills-windows/app-planner/references/rules/frontend/template.md +0 -339
- package/bundled/skills-windows/app-planner/references/rules/mobile/derivation-rules.md +0 -649
- package/bundled/skills-windows/app-planner/references/rules/mobile/fixed-rules.md +0 -290
- package/bundled/skills-windows/app-planner/references/rules/mobile/question-bank.md +0 -232
- package/bundled/skills-windows/app-planner/references/rules/mobile/question-manifest.json +0 -47
- package/bundled/skills-windows/app-planner/references/rules/mobile/template.md +0 -175
- package/bundled/skills-windows/app-planner/references/rules-configuration.md +0 -46
- package/bundled/skills-windows/bug-fix-workflow/SKILL.md +0 -379
- package/bundled/skills-windows/bug-fix-workflow/references/bug-diagnosis.md +0 -41
- package/bundled/skills-windows/bug-planner/SKILL.md +0 -402
- package/bundled/skills-windows/bug-planner/assets/bug-confirmation-template.md +0 -43
- package/bundled/skills-windows/bug-planner/references/critic-and-verification.md +0 -44
- package/bundled/skills-windows/bug-planner/references/error-recovery.md +0 -73
- package/bundled/skills-windows/bug-planner/references/input-formats.md +0 -53
- package/bundled/skills-windows/bug-planner/references/schema-validation.md +0 -25
- package/bundled/skills-windows/bug-planner/references/severity-rules.md +0 -16
- package/bundled/skills-windows/bug-planner/scripts/validate-bug-list.py +0 -322
- package/bundled/skills-windows/bugfix-pipeline-launcher/SKILL.md +0 -304
- package/bundled/skills-windows/bugfix-pipeline-launcher/references/configuration.md +0 -84
- package/bundled/skills-windows/feature-pipeline-launcher/SKILL.md +0 -381
- package/bundled/skills-windows/feature-pipeline-launcher/references/configuration.md +0 -67
- package/bundled/skills-windows/feature-pipeline-launcher/scripts/preflight-check.py +0 -462
- package/bundled/skills-windows/feature-planner/SKILL.md +0 -397
- package/bundled/skills-windows/feature-planner/assets/evaluation-guide.md +0 -64
- package/bundled/skills-windows/feature-planner/assets/planning-guide.md +0 -214
- package/bundled/skills-windows/feature-planner/references/browser-interaction.md +0 -59
- package/bundled/skills-windows/feature-planner/references/completeness-review.md +0 -57
- package/bundled/skills-windows/feature-planner/references/decomposition-patterns.md +0 -75
- package/bundled/skills-windows/feature-planner/references/error-recovery.md +0 -90
- package/bundled/skills-windows/feature-planner/references/incremental-feature-planning.md +0 -112
- package/bundled/skills-windows/feature-planner/references/new-project-planning.md +0 -85
- package/bundled/skills-windows/feature-planner/scripts/validate-and-generate.py +0 -1020
- package/bundled/skills-windows/feature-workflow/SKILL.md +0 -374
- package/bundled/skills-windows/feature-workflow/references/brainstorm-guide.md +0 -137
- package/bundled/skills-windows/prizm-kit/SKILL.md +0 -93
- package/bundled/skills-windows/prizmkit-code-review/SKILL.md +0 -161
- package/bundled/skills-windows/prizmkit-code-review/references/dev-agent-prompt.md +0 -30
- package/bundled/skills-windows/prizmkit-code-review/references/review-report-template.md +0 -31
- package/bundled/skills-windows/prizmkit-code-review/references/reviewer-agent-prompt.md +0 -66
- package/bundled/skills-windows/prizmkit-code-review/scripts/check_loop.py +0 -186
- package/bundled/skills-windows/prizmkit-committer/SKILL.md +0 -89
- package/bundled/skills-windows/prizmkit-deploy/SKILL.md +0 -444
- package/bundled/skills-windows/prizmkit-deploy/references/ci-cd-workflows.md +0 -115
- package/bundled/skills-windows/prizmkit-deploy/references/cloud-platform-deploy.md +0 -93
- package/bundled/skills-windows/prizmkit-deploy/references/data-safety-examples.md +0 -120
- package/bundled/skills-windows/prizmkit-deploy/references/database-setup.md +0 -46
- package/bundled/skills-windows/prizmkit-deploy/references/deploy-config-schema.md +0 -148
- package/bundled/skills-windows/prizmkit-deploy/references/deploy-history-schema.md +0 -62
- package/bundled/skills-windows/prizmkit-deploy/references/deployment-modes.md +0 -50
- package/bundled/skills-windows/prizmkit-deploy/references/direct-upload.md +0 -26
- package/bundled/skills-windows/prizmkit-deploy/references/dns-setup.md +0 -42
- package/bundled/skills-windows/prizmkit-deploy/references/docker-deploy.md +0 -31
- package/bundled/skills-windows/prizmkit-deploy/references/firewall-setup.md +0 -37
- package/bundled/skills-windows/prizmkit-deploy/references/live-validation-notes.md +0 -21
- package/bundled/skills-windows/prizmkit-deploy/references/nginx-blue-green.md +0 -59
- package/bundled/skills-windows/prizmkit-deploy/references/ssh-bootstrap-flow.md +0 -49
- package/bundled/skills-windows/prizmkit-deploy/references/ssh-execution-flow.md +0 -41
- package/bundled/skills-windows/prizmkit-deploy/references/ssh-takeover.md +0 -20
- package/bundled/skills-windows/prizmkit-deploy/references/ssl-setup.md +0 -56
- package/bundled/skills-windows/prizmkit-implement/SKILL.md +0 -71
- package/bundled/skills-windows/prizmkit-init/SKILL.md +0 -356
- package/bundled/skills-windows/prizmkit-init/assets/project-brief-template.md +0 -82
- package/bundled/skills-windows/prizmkit-init/references/config-schema.md +0 -70
- package/bundled/skills-windows/prizmkit-init/references/rules/layer-detection.md +0 -41
- package/bundled/skills-windows/prizmkit-init/references/tech-stack-catalog.md +0 -13
- package/bundled/skills-windows/prizmkit-init/references/update-supplement.md +0 -9
- package/bundled/skills-windows/prizmkit-plan/SKILL.md +0 -102
- package/bundled/skills-windows/prizmkit-plan/assets/plan-template.md +0 -115
- package/bundled/skills-windows/prizmkit-plan/assets/spec-template.md +0 -73
- package/bundled/skills-windows/prizmkit-plan/references/clarify-guide.md +0 -67
- package/bundled/skills-windows/prizmkit-plan/references/examples.md +0 -85
- package/bundled/skills-windows/prizmkit-plan/references/verification-checklist.md +0 -60
- package/bundled/skills-windows/prizmkit-prizm-docs/SKILL.md +0 -129
- package/bundled/skills-windows/prizmkit-prizm-docs/assets/prizm-docs-format.md +0 -613
- package/bundled/skills-windows/prizmkit-prizm-docs/references/op-init.md +0 -45
- package/bundled/skills-windows/prizmkit-prizm-docs/references/op-rebuild.md +0 -15
- package/bundled/skills-windows/prizmkit-prizm-docs/references/op-status.md +0 -14
- package/bundled/skills-windows/prizmkit-prizm-docs/references/op-update.md +0 -19
- package/bundled/skills-windows/prizmkit-prizm-docs/references/op-validate.md +0 -17
- package/bundled/skills-windows/prizmkit-retrospective/SKILL.md +0 -87
- package/bundled/skills-windows/prizmkit-retrospective/references/knowledge-injection-steps.md +0 -50
- package/bundled/skills-windows/prizmkit-retrospective/references/structural-sync-steps.md +0 -43
- package/bundled/skills-windows/prizmkit-test/SKILL.md +0 -227
- package/bundled/skills-windows/prizmkit-test/references/boundary-coverage-protocol.md +0 -220
- package/bundled/skills-windows/prizmkit-test/references/examples.md +0 -143
- package/bundled/skills-windows/prizmkit-test/references/service-boundary-test-catalog.md +0 -225
- package/bundled/skills-windows/prizmkit-test/references/test-generation-steps.md +0 -109
- package/bundled/skills-windows/prizmkit-test/references/test-report-template.md +0 -111
- package/bundled/skills-windows/prizmkit-test/scripts/validate_boundary_report.py +0 -347
- package/bundled/skills-windows/recovery-workflow/SKILL.md +0 -355
- package/bundled/skills-windows/recovery-workflow/evals/evals.json +0 -46
- package/bundled/skills-windows/recovery-workflow/references/detection.md +0 -58
- package/bundled/skills-windows/recovery-workflow/scripts/detect-recovery-state.py +0 -544
- package/bundled/skills-windows/refactor-pipeline-launcher/SKILL.md +0 -346
- package/bundled/skills-windows/refactor-pipeline-launcher/references/configuration.md +0 -72
- package/bundled/skills-windows/refactor-planner/SKILL.md +0 -398
- package/bundled/skills-windows/refactor-planner/assets/planning-guide.md +0 -292
- package/bundled/skills-windows/refactor-planner/references/behavior-preservation.md +0 -301
- package/bundled/skills-windows/refactor-planner/references/fast-path.md +0 -59
- package/bundled/skills-windows/refactor-planner/references/planning-phases.md +0 -135
- package/bundled/skills-windows/refactor-planner/references/refactor-scoping-guide.md +0 -221
- package/bundled/skills-windows/refactor-planner/scripts/validate-and-generate-refactor.py +0 -858
- package/bundled/skills-windows/refactor-workflow/SKILL.md +0 -343
- package/bundled/skills-windows/refactor-workflow/references/brainstorm-guide.md +0 -116
- package/bundled/templates/hooks/diff-prizm-docs.sh +0 -158
- package/bundled/templates/hooks/prizm-pre-commit.sh +0 -108
- package/bundled/templates/hooks/validate-prizm-docs.sh +0 -139
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
"""Manual reset commands for the unified Python runtime."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import re
|
|
7
|
+
import subprocess
|
|
8
|
+
import sys
|
|
9
|
+
from collections.abc import Sequence
|
|
10
|
+
from dataclasses import dataclass
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
from .commands import CommandResult # type: ignore # runtime boundary import
|
|
14
|
+
from .gitops import default_branch, list_reset_branches, reset_cleanup_branch
|
|
15
|
+
from .runner_models import RunnerFamily, family_for
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass(frozen=True)
|
|
19
|
+
class ResetOptions:
|
|
20
|
+
"""Parsed legacy reset arguments for one family."""
|
|
21
|
+
|
|
22
|
+
list_path: Path
|
|
23
|
+
item_id: str = ""
|
|
24
|
+
item_range: tuple[str, str] | None = None
|
|
25
|
+
filter_mode: str = ""
|
|
26
|
+
clean: bool = False
|
|
27
|
+
run_after: bool = False
|
|
28
|
+
help_requested: bool = False
|
|
29
|
+
unknown_args: tuple[str, ...] = ()
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@dataclass(frozen=True)
|
|
33
|
+
class ResetItem:
|
|
34
|
+
"""Resolved reset target from the plan list."""
|
|
35
|
+
|
|
36
|
+
item_id: str
|
|
37
|
+
title: str
|
|
38
|
+
slug: str
|
|
39
|
+
status: str
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
FAMILY_LABELS = {
|
|
43
|
+
"feature": "feature",
|
|
44
|
+
"bugfix": "bug",
|
|
45
|
+
"refactor": "refactor",
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
FILTER_FLAGS = {
|
|
49
|
+
"--auto-skipped": "auto_skipped",
|
|
50
|
+
"--failed": "failed",
|
|
51
|
+
"--stalled": "stalled",
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
ID_FIELD_BY_KIND = {
|
|
56
|
+
"feature": "id",
|
|
57
|
+
"bugfix": "id",
|
|
58
|
+
"refactor": "id",
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
TITLE_FIELD_BY_KIND = {
|
|
63
|
+
"feature": "title",
|
|
64
|
+
"bugfix": "title",
|
|
65
|
+
"refactor": "title",
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
BRANCH_PREFIX_BY_KIND = {
|
|
70
|
+
"feature": "dev",
|
|
71
|
+
"bugfix": "bugfix",
|
|
72
|
+
"refactor": "refactor",
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
STALLED_FILTER_STATUSES = {
|
|
76
|
+
"failed",
|
|
77
|
+
"auto_skipped",
|
|
78
|
+
"needs_info",
|
|
79
|
+
"stalled",
|
|
80
|
+
"stalled_context_continuation",
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def run_reset_command(kind: str, legacy_args: tuple[str, ...], paths) -> CommandResult:
|
|
85
|
+
"""Run a manual reset command for feature, bugfix, or refactor."""
|
|
86
|
+
family = family_for(kind, paths)
|
|
87
|
+
options = _parse_reset_args(family, legacy_args)
|
|
88
|
+
if options.help_requested:
|
|
89
|
+
return CommandResult(0, f"Python {kind} reset", _help_text(family), stdout=_help_text(family))
|
|
90
|
+
|
|
91
|
+
list_path = _resolve_list_path(options.list_path, paths.project_root)
|
|
92
|
+
if not list_path.is_file():
|
|
93
|
+
return CommandResult(1, f"Python {kind} reset", f"{kind} list not found: {list_path}")
|
|
94
|
+
if not (family.state_dir / "pipeline.json").is_file():
|
|
95
|
+
return CommandResult(1, f"Python {kind} reset", f"No pipeline state found. Run the {kind} pipeline first to initialize.")
|
|
96
|
+
|
|
97
|
+
options = ResetOptions(
|
|
98
|
+
list_path=list_path,
|
|
99
|
+
item_id=options.item_id,
|
|
100
|
+
item_range=options.item_range,
|
|
101
|
+
filter_mode=options.filter_mode,
|
|
102
|
+
clean=options.clean,
|
|
103
|
+
run_after=options.run_after,
|
|
104
|
+
help_requested=options.help_requested,
|
|
105
|
+
unknown_args=options.unknown_args,
|
|
106
|
+
)
|
|
107
|
+
try:
|
|
108
|
+
items = _resolve_items(family, options)
|
|
109
|
+
except ValueError as exc:
|
|
110
|
+
return CommandResult(1, f"Python {kind} reset", str(exc))
|
|
111
|
+
if not items:
|
|
112
|
+
return CommandResult(0, f"Python {kind} reset", f"No {FAMILY_LABELS[kind]}s found with status: {options.filter_mode}")
|
|
113
|
+
|
|
114
|
+
if options.run_after and len(items) > 1:
|
|
115
|
+
options = ResetOptions(
|
|
116
|
+
list_path=options.list_path,
|
|
117
|
+
item_id=options.item_id,
|
|
118
|
+
item_range=options.item_range,
|
|
119
|
+
filter_mode=options.filter_mode,
|
|
120
|
+
clean=options.clean,
|
|
121
|
+
run_after=False,
|
|
122
|
+
help_requested=False,
|
|
123
|
+
unknown_args=options.unknown_args,
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
lines: list[str] = []
|
|
127
|
+
success = 0
|
|
128
|
+
failed = 0
|
|
129
|
+
return_branch = default_branch(paths.project_root)
|
|
130
|
+
for item in items:
|
|
131
|
+
ok = _reset_one(family, item, options, paths.project_root, return_branch, lines)
|
|
132
|
+
if ok:
|
|
133
|
+
success += 1
|
|
134
|
+
else:
|
|
135
|
+
failed += 1
|
|
136
|
+
|
|
137
|
+
lines.append(f"Reset complete: {success} succeeded, {failed} failed")
|
|
138
|
+
if options.run_after and len(items) == 1 and failed == 0:
|
|
139
|
+
from .runners import run_pipeline_command
|
|
140
|
+
|
|
141
|
+
lines.append(f"Auto-retrying {items[0].item_id} via Python foreground runner...")
|
|
142
|
+
retry_result = run_pipeline_command(kind, "run", (items[0].item_id, str(options.list_path)), paths)
|
|
143
|
+
lines.append(retry_result.render())
|
|
144
|
+
return CommandResult(retry_result.exit_code, f"Python {kind} reset", "\n".join(lines), stdout="\n".join(lines))
|
|
145
|
+
|
|
146
|
+
return CommandResult(0 if failed == 0 else 1, f"Python {kind} reset", "\n".join(lines), stdout="\n".join(lines))
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def _parse_reset_args(family: RunnerFamily, legacy_args: Sequence[str]) -> ResetOptions:
|
|
150
|
+
args = tuple(str(arg) for arg in legacy_args)
|
|
151
|
+
list_path = family.plan_path
|
|
152
|
+
item_id = ""
|
|
153
|
+
item_range: tuple[str, str] | None = None
|
|
154
|
+
filter_mode = ""
|
|
155
|
+
clean = False
|
|
156
|
+
run_after = False
|
|
157
|
+
help_requested = False
|
|
158
|
+
unknown: list[str] = []
|
|
159
|
+
positional: list[str] = []
|
|
160
|
+
|
|
161
|
+
index = 0
|
|
162
|
+
while index < len(args):
|
|
163
|
+
arg = args[index]
|
|
164
|
+
if arg in {"--help", "-h", "help"}:
|
|
165
|
+
help_requested = True
|
|
166
|
+
elif arg == "--clean":
|
|
167
|
+
clean = True
|
|
168
|
+
elif arg == "--run":
|
|
169
|
+
run_after = True
|
|
170
|
+
elif arg in FILTER_FLAGS:
|
|
171
|
+
filter_mode = FILTER_FLAGS[arg]
|
|
172
|
+
elif arg.startswith("-"):
|
|
173
|
+
unknown.append(arg)
|
|
174
|
+
else:
|
|
175
|
+
positional.append(arg)
|
|
176
|
+
index += 1
|
|
177
|
+
|
|
178
|
+
for value in positional:
|
|
179
|
+
if _looks_like_range(value, family.id_prefix):
|
|
180
|
+
item_range = _normalize_range(value, family.id_prefix)
|
|
181
|
+
elif _looks_like_item_id(value, family.id_prefix) and not item_id:
|
|
182
|
+
item_id = _normalize_item_id(value, family.id_prefix)
|
|
183
|
+
elif list_path == family.plan_path:
|
|
184
|
+
list_path = Path(value).expanduser()
|
|
185
|
+
else:
|
|
186
|
+
unknown.append(value)
|
|
187
|
+
|
|
188
|
+
return ResetOptions(
|
|
189
|
+
list_path=list_path,
|
|
190
|
+
item_id=item_id,
|
|
191
|
+
item_range=item_range,
|
|
192
|
+
filter_mode=filter_mode,
|
|
193
|
+
clean=clean,
|
|
194
|
+
run_after=run_after,
|
|
195
|
+
help_requested=help_requested,
|
|
196
|
+
unknown_args=tuple(unknown),
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def _resolve_list_path(path: Path, project_root: Path) -> Path:
|
|
201
|
+
return path.resolve() if path.is_absolute() else (project_root / path).resolve()
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def _resolve_items(family: RunnerFamily, options: ResetOptions) -> tuple[ResetItem, ...]:
|
|
205
|
+
data = json.loads(options.list_path.read_text(encoding="utf-8"))
|
|
206
|
+
raw_items = data.get(family.list_key, [])
|
|
207
|
+
if not isinstance(raw_items, list):
|
|
208
|
+
raw_items = []
|
|
209
|
+
by_id = {_item_id(family, item): item for item in raw_items if isinstance(item, dict) and _item_id(family, item)}
|
|
210
|
+
|
|
211
|
+
ids: list[str]
|
|
212
|
+
if options.filter_mode:
|
|
213
|
+
ids = []
|
|
214
|
+
for item in raw_items:
|
|
215
|
+
if not isinstance(item, dict):
|
|
216
|
+
continue
|
|
217
|
+
status = str(item.get("status") or "")
|
|
218
|
+
if options.filter_mode == "auto_skipped" and status == "auto_skipped":
|
|
219
|
+
ids.append(_item_id(family, item))
|
|
220
|
+
elif options.filter_mode == "failed" and status == "failed":
|
|
221
|
+
ids.append(_item_id(family, item))
|
|
222
|
+
elif options.filter_mode == "stalled" and status in STALLED_FILTER_STATUSES:
|
|
223
|
+
ids.append(_item_id(family, item))
|
|
224
|
+
elif options.item_range:
|
|
225
|
+
start, end = options.item_range
|
|
226
|
+
start_num = _numeric_suffix(start, family.id_prefix)
|
|
227
|
+
end_num = _numeric_suffix(end, family.id_prefix)
|
|
228
|
+
if start_num <= 0 or end_num <= 0 or start_num > end_num:
|
|
229
|
+
raise ValueError(f"Invalid range: {start}:{end} (start must be <= end)")
|
|
230
|
+
ids = [f"{family.id_prefix}{number:03d}" for number in range(start_num, end_num + 1)]
|
|
231
|
+
elif options.item_id:
|
|
232
|
+
ids = [options.item_id]
|
|
233
|
+
else:
|
|
234
|
+
raise ValueError(_help_text(family))
|
|
235
|
+
|
|
236
|
+
resolved: list[ResetItem] = []
|
|
237
|
+
for item_id in ids:
|
|
238
|
+
item = by_id.get(item_id)
|
|
239
|
+
if not isinstance(item, dict):
|
|
240
|
+
continue
|
|
241
|
+
title = str(item.get(TITLE_FIELD_BY_KIND[family.kind]) or "")
|
|
242
|
+
resolved.append(ResetItem(item_id=item_id, title=title, slug=_slug_for_item(family, item_id, title), status=str(item.get("status") or "unknown")))
|
|
243
|
+
return tuple(resolved)
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def _reset_one(family: RunnerFamily, item: ResetItem, options: ResetOptions, project_root: Path, return_branch: str, lines: list[str]) -> bool:
|
|
247
|
+
label = FAMILY_LABELS[family.kind]
|
|
248
|
+
status_file = family.state_dir / item.item_id / "status.json"
|
|
249
|
+
lines.append(f"Reset: {item.item_id} — {item.title}")
|
|
250
|
+
status_data = _load_status(status_file)
|
|
251
|
+
if status_data:
|
|
252
|
+
lines.append(f"Current status: {item.status} (retry {status_data.get('retry_count', 0)}, {len(status_data.get('sessions') or [])} sessions)")
|
|
253
|
+
_append_continuation_warning(lines, status_data, item.item_id, label)
|
|
254
|
+
else:
|
|
255
|
+
lines.append(f"Current status: {item.status} (no runtime state file)")
|
|
256
|
+
|
|
257
|
+
for branch in list_reset_branches(project_root, BRANCH_PREFIX_BY_KIND[family.kind], item.item_id):
|
|
258
|
+
cleanup = reset_cleanup_branch(project_root, branch, return_branch=return_branch, delete=options.clean)
|
|
259
|
+
lines.append(f"Discarded uncommitted changes on dev branch: {cleanup.branch}")
|
|
260
|
+
if cleanup.deleted:
|
|
261
|
+
lines.append(f"Deleted dev branch: {cleanup.branch}")
|
|
262
|
+
elif not options.clean:
|
|
263
|
+
lines.append(f"Dev branch preserved for debugging: {cleanup.branch}")
|
|
264
|
+
lines.extend(f"WARN: {warning}" for warning in cleanup.warnings)
|
|
265
|
+
|
|
266
|
+
action = "clean" if options.clean else "reset"
|
|
267
|
+
lines.append(f"{'Cleaning' if options.clean else 'Resetting'} {item.item_id} status...")
|
|
268
|
+
result = _run_updater(family, action, options, item, project_root)
|
|
269
|
+
if result.returncode == 0 and _json_without_error(result.stdout):
|
|
270
|
+
lines.append(f"{item.item_id} {action} complete: status -> pending, retry count -> 0")
|
|
271
|
+
return True
|
|
272
|
+
error = _error_text(result.stdout) or result.stderr.strip() or "unknown"
|
|
273
|
+
lines.append(f"ERROR: Reset {item.item_id} failed: {error}")
|
|
274
|
+
return False
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
def _run_updater(family: RunnerFamily, action: str, options: ResetOptions, item: ResetItem, project_root: Path) -> subprocess.CompletedProcess[str]:
|
|
278
|
+
command = [
|
|
279
|
+
sys.executable,
|
|
280
|
+
str(family.updater_script),
|
|
281
|
+
family.list_arg,
|
|
282
|
+
str(options.list_path),
|
|
283
|
+
"--state-dir",
|
|
284
|
+
str(family.state_dir),
|
|
285
|
+
family.item_id_arg,
|
|
286
|
+
item.item_id,
|
|
287
|
+
"--action",
|
|
288
|
+
action,
|
|
289
|
+
"--max-retries",
|
|
290
|
+
"3",
|
|
291
|
+
"--max-infra-retries",
|
|
292
|
+
"3",
|
|
293
|
+
]
|
|
294
|
+
if action == "clean":
|
|
295
|
+
command.extend(["--project-root", str(project_root)])
|
|
296
|
+
if family.kind == "feature":
|
|
297
|
+
command.extend(["--feature-slug", item.slug])
|
|
298
|
+
return subprocess.run(command, cwd=str(project_root), stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, check=False)
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
def _append_continuation_warning(lines: list[str], status_data: dict[str, object], item_id: str, item_label: str) -> None:
|
|
302
|
+
if status_data.get("continuation_pending") is True:
|
|
303
|
+
reason = str(status_data.get("continuation_reason") or "context_overflow")
|
|
304
|
+
lines.append(
|
|
305
|
+
f"WARN: Continuation pending for {item_label} {item_id} ({reason}). Manual reset will abandon automatic continuation progress."
|
|
306
|
+
)
|
|
307
|
+
branch = str(status_data.get("active_dev_branch") or "")
|
|
308
|
+
if branch:
|
|
309
|
+
lines.append(f"WARN: Pending continuation branch: {branch}")
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
def _load_status(path: Path) -> dict[str, object]:
|
|
313
|
+
if not path.is_file():
|
|
314
|
+
return {}
|
|
315
|
+
try:
|
|
316
|
+
data = json.loads(path.read_text(encoding="utf-8"))
|
|
317
|
+
except (OSError, json.JSONDecodeError):
|
|
318
|
+
return {}
|
|
319
|
+
return data if isinstance(data, dict) else {}
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
def _json_without_error(text: str) -> bool:
|
|
323
|
+
try:
|
|
324
|
+
data = json.loads(text or "{}")
|
|
325
|
+
except json.JSONDecodeError:
|
|
326
|
+
return False
|
|
327
|
+
return isinstance(data, dict) and "error" not in data
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
def _error_text(text: str) -> str:
|
|
331
|
+
try:
|
|
332
|
+
data = json.loads(text or "{}")
|
|
333
|
+
except json.JSONDecodeError:
|
|
334
|
+
return text.strip()
|
|
335
|
+
return str(data.get("error") or "") if isinstance(data, dict) else ""
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
def _item_id(family: RunnerFamily, item: dict[str, object]) -> str:
|
|
339
|
+
return _normalize_item_id(str(item.get(ID_FIELD_BY_KIND[family.kind]) or ""), family.id_prefix)
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
def _slug_for_item(family: RunnerFamily, item_id: str, title: str) -> str:
|
|
343
|
+
if family.kind != "feature":
|
|
344
|
+
return item_id
|
|
345
|
+
numeric = item_id.replace("F-", "").replace("f-", "").zfill(3)
|
|
346
|
+
slug = re.sub(r"[^a-z0-9\s-]", "", title.lower())
|
|
347
|
+
slug = re.sub(r"[\s]+", "-", slug.strip())
|
|
348
|
+
slug = re.sub(r"-+", "-", slug).strip("-") or "feature"
|
|
349
|
+
return f"{numeric}-{slug}"
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
def _looks_like_item_id(value: str, prefix: str) -> bool:
|
|
353
|
+
return value.upper().startswith(prefix.upper())
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
def _looks_like_range(value: str, prefix: str) -> bool:
|
|
357
|
+
if ":" not in value:
|
|
358
|
+
return False
|
|
359
|
+
left, right = value.split(":", 1)
|
|
360
|
+
return _looks_like_item_id(left, prefix) and _looks_like_item_id(right, prefix)
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
def _normalize_range(value: str, prefix: str) -> tuple[str, str]:
|
|
364
|
+
left, right = value.split(":", 1)
|
|
365
|
+
return _normalize_item_id(left, prefix), _normalize_item_id(right, prefix)
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
def _normalize_item_id(value: str, prefix: str) -> str:
|
|
369
|
+
upper = value.upper()
|
|
370
|
+
if upper.startswith(prefix.upper()):
|
|
371
|
+
suffix = upper[len(prefix) :]
|
|
372
|
+
if suffix.isdigit():
|
|
373
|
+
return f"{prefix}{int(suffix):03d}"
|
|
374
|
+
return upper
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
def _numeric_suffix(value: str, prefix: str) -> int:
|
|
378
|
+
normalized = _normalize_item_id(value, prefix)
|
|
379
|
+
suffix = normalized[len(prefix) :]
|
|
380
|
+
return int(suffix) if suffix.isdigit() else 0
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
def _help_text(family: RunnerFamily) -> str:
|
|
384
|
+
label = FAMILY_LABELS[family.kind]
|
|
385
|
+
return (
|
|
386
|
+
f"Usage: prizmkit-runtime reset {family.kind} <{label}-id|range> [--clean] [--run] "
|
|
387
|
+
"[--auto-skipped|--failed|--stalled] [list-path]\n"
|
|
388
|
+
"Reset is a destructive manual operation and is not used for automatic context continuation."
|
|
389
|
+
)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""Bookkeeping git helpers for Python foreground runners.
|
|
2
|
+
|
|
3
|
+
These helpers model the shell runner bookkeeping boundaries without hiding git
|
|
4
|
+
failures. They are intentionally small wrappers so task runners can preserve the
|
|
5
|
+
legacy ordering around branch creation and final status updates.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from dataclasses import dataclass
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
from .gitops import GitCommandResult, git_status_safe, run_git_command
|
|
14
|
+
from .runner_models import RunnerFamily
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass(frozen=True)
|
|
18
|
+
class BookkeepingResult:
|
|
19
|
+
"""Result from an optional bookkeeping commit boundary."""
|
|
20
|
+
|
|
21
|
+
attempted: bool
|
|
22
|
+
committed: bool
|
|
23
|
+
result: GitCommandResult | None = None
|
|
24
|
+
|
|
25
|
+
@property
|
|
26
|
+
def ok(self) -> bool:
|
|
27
|
+
return self.result is None or self.result.return_code == 0
|
|
28
|
+
|
|
29
|
+
|
|
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())
|
|
33
|
+
|
|
34
|
+
|
|
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):
|
|
38
|
+
return BookkeepingResult(attempted=False, committed=False)
|
|
39
|
+
run_git_command(project_root, ("add", "-A", "--", "."))
|
|
40
|
+
result = run_git_command(project_root, ("commit", "--no-verify", "-m", message))
|
|
41
|
+
return BookkeepingResult(attempted=True, committed=result.return_code == 0, result=result)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
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")
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
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}")
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"""Session classification and continuation helpers for Python runners."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import hashlib
|
|
6
|
+
import json
|
|
7
|
+
import subprocess
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
from .gitops import HIDDEN_TOOL_WORKTREE_EXCLUDES, git_status_safe, run_git_command
|
|
11
|
+
from .runner_models import PromptGenerationResult, SessionClassification
|
|
12
|
+
from .sessions import AISessionResult
|
|
13
|
+
|
|
14
|
+
CONTEXT_OVERFLOW = "context_overflow"
|
|
15
|
+
STALL_REASON = "context_overflow_without_git_checkpoint_or_artifact_progress"
|
|
16
|
+
CONTEXT_MARKERS = (
|
|
17
|
+
"context_overflow",
|
|
18
|
+
"input exceeds the context window",
|
|
19
|
+
"context_length_exceeded",
|
|
20
|
+
"maximum context length exceeded",
|
|
21
|
+
"prompt is too long",
|
|
22
|
+
"too many tokens",
|
|
23
|
+
"input token count exceeds",
|
|
24
|
+
)
|
|
25
|
+
INFRA_MARKERS = (
|
|
26
|
+
"rate limit",
|
|
27
|
+
"overloaded",
|
|
28
|
+
"gateway",
|
|
29
|
+
"authentication",
|
|
30
|
+
"unauthorized",
|
|
31
|
+
"api error",
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def classify_session(
|
|
36
|
+
result: AISessionResult,
|
|
37
|
+
*,
|
|
38
|
+
project_root: Path,
|
|
39
|
+
base_head: str,
|
|
40
|
+
prompt: PromptGenerationResult | None = None,
|
|
41
|
+
previous_fingerprint: object | None = None,
|
|
42
|
+
previous_no_progress_count: int = 0,
|
|
43
|
+
) -> SessionClassification:
|
|
44
|
+
"""Classify raw AI session signals with durable success precedence."""
|
|
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)
|
|
48
|
+
|
|
49
|
+
if _is_context_overflow(result):
|
|
50
|
+
no_progress_count = _next_no_progress_count(previous_fingerprint, fingerprint, previous_no_progress_count)
|
|
51
|
+
if no_progress_count >= 2:
|
|
52
|
+
return SessionClassification(
|
|
53
|
+
"stalled_context_continuation",
|
|
54
|
+
reason=STALL_REASON,
|
|
55
|
+
fatal_error_code=result.fatal_error_code or CONTEXT_OVERFLOW,
|
|
56
|
+
progress_fingerprint=fingerprint,
|
|
57
|
+
no_progress_count=no_progress_count,
|
|
58
|
+
)
|
|
59
|
+
return SessionClassification(
|
|
60
|
+
CONTEXT_OVERFLOW,
|
|
61
|
+
reason=CONTEXT_OVERFLOW,
|
|
62
|
+
fatal_error_code=result.fatal_error_code or CONTEXT_OVERFLOW,
|
|
63
|
+
progress_fingerprint=fingerprint,
|
|
64
|
+
no_progress_count=no_progress_count,
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
if _is_infra_error(result):
|
|
68
|
+
return SessionClassification("infra_error", reason="ai_runtime_or_provider_error", progress_fingerprint=fingerprint)
|
|
69
|
+
if result.termination_reason == "stale_session":
|
|
70
|
+
return SessionClassification("crashed", reason="stale_session", progress_fingerprint=fingerprint)
|
|
71
|
+
if result.timed_out or result.termination_reason == "timeout":
|
|
72
|
+
return SessionClassification("timed_out", reason="timeout", progress_fingerprint=fingerprint)
|
|
73
|
+
if result.exit_code not in (0, None):
|
|
74
|
+
return SessionClassification("crashed", reason=f"exit_code={result.exit_code}", progress_fingerprint=fingerprint)
|
|
75
|
+
if _has_workspace_changes(project_root):
|
|
76
|
+
_auto_commit_workspace(project_root)
|
|
77
|
+
return SessionClassification("success", reason="auto_commit_uncommitted_changes", progress_fingerprint=fingerprint)
|
|
78
|
+
return SessionClassification("crashed", reason="no_durable_success", progress_fingerprint=fingerprint)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def progress_fingerprint(project_root: Path, prompt: PromptGenerationResult | None = None) -> dict[str, object]:
|
|
82
|
+
"""Build the no-progress continuation fingerprint used by runner status metadata."""
|
|
83
|
+
status_text = git_status_safe(project_root)
|
|
84
|
+
head = run_git_command(project_root, ("rev-parse", "HEAD")).stdout.strip()
|
|
85
|
+
artifact_hash = ""
|
|
86
|
+
checkpoint_cursor = ""
|
|
87
|
+
if prompt and prompt.artifact_path and prompt.artifact_path.exists():
|
|
88
|
+
artifact_hash = _hash_tree(prompt.artifact_path)
|
|
89
|
+
if prompt and prompt.checkpoint_path and prompt.checkpoint_path.is_file():
|
|
90
|
+
try:
|
|
91
|
+
data = json.loads(prompt.checkpoint_path.read_text(encoding="utf-8"))
|
|
92
|
+
checkpoint_cursor = _checkpoint_cursor(data)
|
|
93
|
+
except (OSError, json.JSONDecodeError):
|
|
94
|
+
checkpoint_cursor = "unreadable"
|
|
95
|
+
return {
|
|
96
|
+
"git_diff_fingerprint": hashlib.sha256(status_text.encode()).hexdigest(),
|
|
97
|
+
"checkpoint_cursor": checkpoint_cursor,
|
|
98
|
+
"artifact_fingerprint": artifact_hash,
|
|
99
|
+
"head_commit": head,
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _next_no_progress_count(previous: object | None, current: object, count: int) -> int:
|
|
104
|
+
if previous and previous == current:
|
|
105
|
+
return max(0, count) + 1
|
|
106
|
+
return 0
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def _is_context_overflow(result: AISessionResult) -> bool:
|
|
110
|
+
if (result.fatal_error_code or "").lower() == CONTEXT_OVERFLOW:
|
|
111
|
+
return True
|
|
112
|
+
text = "\n".join(
|
|
113
|
+
[
|
|
114
|
+
result.progress_summary.fatal_error_code,
|
|
115
|
+
result.progress_summary.terminal_result_text,
|
|
116
|
+
*result.progress_summary.errors,
|
|
117
|
+
_tail(result.session_log),
|
|
118
|
+
]
|
|
119
|
+
).lower()
|
|
120
|
+
return any(marker in text for marker in CONTEXT_MARKERS)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def _is_infra_error(result: AISessionResult) -> bool:
|
|
124
|
+
text = "\n".join([result.progress_summary.terminal_result_text, *result.progress_summary.errors, _tail(result.session_log)]).lower()
|
|
125
|
+
return bool(result.fatal_error_code and result.fatal_error_code != CONTEXT_OVERFLOW) or any(marker in text for marker in INFRA_MARKERS)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def _has_commit_since(project_root: Path, base_head: str) -> bool:
|
|
129
|
+
if not base_head:
|
|
130
|
+
return False
|
|
131
|
+
current = run_git_command(project_root, ("rev-parse", "HEAD")).stdout.strip()
|
|
132
|
+
return bool(current and current != base_head)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def _has_workspace_changes(project_root: Path) -> bool:
|
|
136
|
+
return bool(git_status_safe(project_root).strip())
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def _auto_commit_workspace(project_root: Path) -> None:
|
|
140
|
+
run_git_command(project_root, ("add", "-A", "--", ".", *HIDDEN_TOOL_WORKTREE_EXCLUDES))
|
|
141
|
+
run_git_command(project_root, ("commit", "--no-verify", "-m", "chore: save runner session changes"))
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def _tail(path: Path, max_bytes: int = 8192) -> str:
|
|
145
|
+
try:
|
|
146
|
+
data = path.read_bytes()
|
|
147
|
+
except OSError:
|
|
148
|
+
return ""
|
|
149
|
+
return data[-max_bytes:].decode("utf-8", errors="ignore")
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def _hash_tree(path: Path) -> str:
|
|
153
|
+
digest = hashlib.sha256()
|
|
154
|
+
if path.is_file():
|
|
155
|
+
digest.update(path.name.encode())
|
|
156
|
+
digest.update(path.read_bytes())
|
|
157
|
+
return digest.hexdigest()
|
|
158
|
+
for child in sorted(path.rglob("*")):
|
|
159
|
+
if child.is_file():
|
|
160
|
+
try:
|
|
161
|
+
rel = child.relative_to(path).as_posix()
|
|
162
|
+
digest.update(rel.encode())
|
|
163
|
+
digest.update(child.read_bytes())
|
|
164
|
+
except OSError:
|
|
165
|
+
continue
|
|
166
|
+
return digest.hexdigest()
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def _checkpoint_cursor(data: dict[str, object]) -> str:
|
|
170
|
+
steps = data.get("steps")
|
|
171
|
+
if not isinstance(steps, list):
|
|
172
|
+
return ""
|
|
173
|
+
for step in steps:
|
|
174
|
+
if not isinstance(step, dict):
|
|
175
|
+
continue
|
|
176
|
+
status = step.get("status", "pending")
|
|
177
|
+
if status not in {"completed", "skipped"}:
|
|
178
|
+
return f"{step.get('id', '?')}:{step.get('skill', 'unknown')}:{status}"
|
|
179
|
+
return "complete"
|