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.
Files changed (317) hide show
  1. package/bin/create-prizmkit.js +4 -4
  2. package/bundled/VERSION.json +3 -3
  3. package/bundled/dev-pipeline/.env.example +3 -3
  4. package/bundled/dev-pipeline/README.md +110 -90
  5. package/bundled/dev-pipeline/assets/prizm-dev-team-integration.md +1 -1
  6. package/bundled/dev-pipeline/cli.py +27 -0
  7. package/bundled/dev-pipeline/prizmkit_runtime/__init__.py +13 -0
  8. package/bundled/dev-pipeline/prizmkit_runtime/__main__.py +9 -0
  9. package/bundled/dev-pipeline/prizmkit_runtime/cli.py +193 -0
  10. package/bundled/dev-pipeline/prizmkit_runtime/commands.py +313 -0
  11. package/bundled/dev-pipeline/prizmkit_runtime/compat.py +32 -0
  12. package/bundled/dev-pipeline/prizmkit_runtime/config.py +410 -0
  13. package/bundled/dev-pipeline/prizmkit_runtime/daemon.py +478 -0
  14. package/bundled/dev-pipeline/prizmkit_runtime/gitops.py +734 -0
  15. package/bundled/dev-pipeline/prizmkit_runtime/heartbeat.py +256 -0
  16. package/bundled/dev-pipeline/prizmkit_runtime/interoperability.py +109 -0
  17. package/bundled/dev-pipeline/prizmkit_runtime/paths.py +110 -0
  18. package/bundled/dev-pipeline/prizmkit_runtime/processes.py +373 -0
  19. package/bundled/dev-pipeline/prizmkit_runtime/reset.py +389 -0
  20. package/bundled/dev-pipeline/prizmkit_runtime/runner_bookkeeping.py +51 -0
  21. package/bundled/dev-pipeline/prizmkit_runtime/runner_classification.py +179 -0
  22. package/bundled/dev-pipeline/prizmkit_runtime/runner_models.py +355 -0
  23. package/bundled/dev-pipeline/prizmkit_runtime/runner_prompts.py +118 -0
  24. package/bundled/dev-pipeline/prizmkit_runtime/runner_recovery.py +187 -0
  25. package/bundled/dev-pipeline/prizmkit_runtime/runner_status.py +153 -0
  26. package/bundled/dev-pipeline/prizmkit_runtime/runners.py +425 -0
  27. package/bundled/dev-pipeline/prizmkit_runtime/sessions.py +560 -0
  28. package/bundled/dev-pipeline/prizmkit_runtime/status.py +71 -0
  29. package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +51 -36
  30. package/bundled/dev-pipeline/scripts/generate-bugfix-prompt.py +20 -5
  31. package/bundled/dev-pipeline/scripts/generate-recovery-prompt.py +2 -2
  32. package/bundled/dev-pipeline/scripts/parse-stream-progress.py +39 -0
  33. package/bundled/dev-pipeline/templates/agent-prompts/dev-implement.md +8 -2
  34. package/bundled/dev-pipeline/templates/agent-prompts/reviewer-review.md +1 -1
  35. package/bundled/dev-pipeline/templates/bootstrap-prompt.md +6 -2
  36. package/bundled/dev-pipeline/templates/bootstrap-tier1.md +14 -6
  37. package/bundled/dev-pipeline/templates/bootstrap-tier2.md +14 -4
  38. package/bundled/dev-pipeline/templates/bootstrap-tier3.md +14 -4
  39. package/bundled/dev-pipeline/templates/sections/context-budget-rules.md +2 -0
  40. package/bundled/dev-pipeline/templates/sections/log-size-awareness.md +9 -30
  41. package/bundled/dev-pipeline/templates/sections/phase-context-snapshot-agent-suffix.md +15 -7
  42. package/bundled/dev-pipeline/templates/sections/phase-implement-agent.md +42 -29
  43. package/bundled/dev-pipeline/templates/sections/phase-implement-full.md +41 -39
  44. package/bundled/dev-pipeline/templates/sections/phase-implement-lite.md +8 -17
  45. package/bundled/dev-pipeline/templates/sections/phase-prizmkit-test.md +2 -2
  46. package/bundled/dev-pipeline/templates/sections/phase-review-agent.md +1 -3
  47. package/bundled/dev-pipeline/templates/sections/phase-review-full.md +1 -3
  48. package/bundled/dev-pipeline/templates/sections/phase0-test-baseline.md +3 -8
  49. package/bundled/dev-pipeline/templates/sections/test-failure-recovery-agent.md +6 -2
  50. package/bundled/dev-pipeline/templates/sections/test-failure-recovery-lite.md +5 -1
  51. package/bundled/dev-pipeline/tests/test_auto_skip.py +436 -14
  52. package/bundled/dev-pipeline/tests/test_generate_bootstrap_prompt.py +115 -7
  53. package/bundled/dev-pipeline/tests/test_generate_bugfix_prompt.py +40 -0
  54. package/bundled/dev-pipeline/tests/test_python_runner_parity.py +1226 -0
  55. package/bundled/dev-pipeline/tests/test_unified_cli.py +1045 -0
  56. package/bundled/skills/_metadata.json +1 -1
  57. package/bundled/skills/bugfix-pipeline-launcher/SKILL.md +29 -34
  58. package/bundled/skills/bugfix-pipeline-launcher/references/configuration.md +6 -5
  59. package/bundled/skills/feature-pipeline-launcher/SKILL.md +29 -35
  60. package/bundled/skills/feature-pipeline-launcher/references/configuration.md +7 -6
  61. package/bundled/skills/feature-workflow/SKILL.md +3 -6
  62. package/bundled/skills/recovery-workflow/SKILL.md +23 -32
  63. package/bundled/skills/refactor-pipeline-launcher/SKILL.md +29 -35
  64. package/bundled/skills/refactor-pipeline-launcher/references/configuration.md +7 -6
  65. package/bundled/skills/refactor-workflow/SKILL.md +3 -6
  66. package/bundled/templates/hooks/commit-intent.json +2 -2
  67. package/bundled/templates/hooks/diff-prizm-docs.py +226 -0
  68. package/bundled/templates/hooks/prizm-pre-commit.py +45 -0
  69. package/bundled/templates/hooks/validate-prizm-docs.py +240 -0
  70. package/package.json +1 -1
  71. package/src/config.js +42 -19
  72. package/src/external-skills.js +14 -14
  73. package/src/index.js +3 -6
  74. package/src/manifest.js +11 -5
  75. package/src/metadata.js +7 -18
  76. package/src/platforms.js +25 -0
  77. package/src/prompts.js +0 -12
  78. package/src/runtimes.js +18 -11
  79. package/src/scaffold.js +144 -122
  80. package/src/upgrade.js +12 -3
  81. package/bundled/dev-pipeline/launch-bugfix-daemon.sh +0 -500
  82. package/bundled/dev-pipeline/launch-feature-daemon.sh +0 -657
  83. package/bundled/dev-pipeline/launch-refactor-daemon.sh +0 -502
  84. package/bundled/dev-pipeline/lib/branch.sh +0 -326
  85. package/bundled/dev-pipeline/lib/common.sh +0 -1476
  86. package/bundled/dev-pipeline/lib/heartbeat.sh +0 -469
  87. package/bundled/dev-pipeline/reset-bug.sh +0 -425
  88. package/bundled/dev-pipeline/reset-feature.sh +0 -436
  89. package/bundled/dev-pipeline/reset-refactor.sh +0 -423
  90. package/bundled/dev-pipeline/run-bugfix.sh +0 -1430
  91. package/bundled/dev-pipeline/run-feature.sh +0 -1718
  92. package/bundled/dev-pipeline/run-recovery.sh +0 -648
  93. package/bundled/dev-pipeline/run-refactor.sh +0 -1463
  94. package/bundled/dev-pipeline/tests/test-path-resolution.sh +0 -100
  95. package/bundled/dev-pipeline-windows/.env.example +0 -36
  96. package/bundled/dev-pipeline-windows/README.md +0 -30
  97. package/bundled/dev-pipeline-windows/SCHEMA_ANALYSIS.md +0 -533
  98. package/bundled/dev-pipeline-windows/assets/feature-list-example.json +0 -146
  99. package/bundled/dev-pipeline-windows/assets/prizm-dev-team-integration.md +0 -137
  100. package/bundled/dev-pipeline-windows/launch-bugfix-daemon.ps1 +0 -9
  101. package/bundled/dev-pipeline-windows/launch-feature-daemon.ps1 +0 -9
  102. package/bundled/dev-pipeline-windows/launch-refactor-daemon.ps1 +0 -9
  103. package/bundled/dev-pipeline-windows/lib/branch.ps1 +0 -235
  104. package/bundled/dev-pipeline-windows/lib/common.ps1 +0 -991
  105. package/bundled/dev-pipeline-windows/lib/daemon.ps1 +0 -140
  106. package/bundled/dev-pipeline-windows/lib/pipeline.ps1 +0 -1051
  107. package/bundled/dev-pipeline-windows/lib/reset.ps1 +0 -121
  108. package/bundled/dev-pipeline-windows/reset-bug.ps1 +0 -10
  109. package/bundled/dev-pipeline-windows/reset-feature.ps1 +0 -10
  110. package/bundled/dev-pipeline-windows/reset-refactor.ps1 +0 -10
  111. package/bundled/dev-pipeline-windows/run-bugfix.ps1 +0 -9
  112. package/bundled/dev-pipeline-windows/run-feature.ps1 +0 -9
  113. package/bundled/dev-pipeline-windows/run-recovery.ps1 +0 -179
  114. package/bundled/dev-pipeline-windows/run-refactor.ps1 +0 -9
  115. package/bundled/dev-pipeline-windows/scripts/check-session-status.py +0 -301
  116. package/bundled/dev-pipeline-windows/scripts/continuation.py +0 -374
  117. package/bundled/dev-pipeline-windows/scripts/detect-stuck.py +0 -530
  118. package/bundled/dev-pipeline-windows/scripts/generate-bootstrap-prompt.py +0 -2279
  119. package/bundled/dev-pipeline-windows/scripts/generate-bugfix-prompt.py +0 -763
  120. package/bundled/dev-pipeline-windows/scripts/generate-recovery-prompt.py +0 -805
  121. package/bundled/dev-pipeline-windows/scripts/generate-refactor-prompt.py +0 -841
  122. package/bundled/dev-pipeline-windows/scripts/init-bugfix-pipeline.py +0 -316
  123. package/bundled/dev-pipeline-windows/scripts/init-dev-team.py +0 -134
  124. package/bundled/dev-pipeline-windows/scripts/init-pipeline.py +0 -382
  125. package/bundled/dev-pipeline-windows/scripts/init-refactor-pipeline.py +0 -399
  126. package/bundled/dev-pipeline-windows/scripts/parse-stream-progress.py +0 -1362
  127. package/bundled/dev-pipeline-windows/scripts/patch-completion-notes.py +0 -191
  128. package/bundled/dev-pipeline-windows/scripts/prizmkit-test-gate.py +0 -446
  129. package/bundled/dev-pipeline-windows/scripts/update-bug-status.py +0 -1121
  130. package/bundled/dev-pipeline-windows/scripts/update-checkpoint.py +0 -173
  131. package/bundled/dev-pipeline-windows/scripts/update-feature-status.py +0 -1789
  132. package/bundled/dev-pipeline-windows/scripts/update-refactor-status.py +0 -1327
  133. package/bundled/dev-pipeline-windows/scripts/utils.py +0 -542
  134. package/bundled/dev-pipeline-windows/templates/agent-prompts/critic-plan-challenge.md +0 -7
  135. package/bundled/dev-pipeline-windows/templates/agent-prompts/dev-fix.md +0 -7
  136. package/bundled/dev-pipeline-windows/templates/agent-prompts/dev-implement.md +0 -65
  137. package/bundled/dev-pipeline-windows/templates/agent-prompts/dev-resume.md +0 -5
  138. package/bundled/dev-pipeline-windows/templates/agent-prompts/reviewer-review.md +0 -7
  139. package/bundled/dev-pipeline-windows/templates/bootstrap-prompt.md +0 -73
  140. package/bundled/dev-pipeline-windows/templates/bootstrap-tier1.md +0 -589
  141. package/bundled/dev-pipeline-windows/templates/bootstrap-tier2.md +0 -710
  142. package/bundled/dev-pipeline-windows/templates/bootstrap-tier3.md +0 -791
  143. package/bundled/dev-pipeline-windows/templates/bug-fix-list-schema.json +0 -263
  144. package/bundled/dev-pipeline-windows/templates/bugfix-bootstrap-prompt.md +0 -326
  145. package/bundled/dev-pipeline-windows/templates/feature-list-schema.json +0 -237
  146. package/bundled/dev-pipeline-windows/templates/refactor-bootstrap-prompt.md +0 -340
  147. package/bundled/dev-pipeline-windows/templates/refactor-list-schema.json +0 -270
  148. package/bundled/dev-pipeline-windows/templates/sections/ac-verification-checklist.md +0 -7
  149. package/bundled/dev-pipeline-windows/templates/sections/checkpoint-system.md +0 -91
  150. package/bundled/dev-pipeline-windows/templates/sections/context-budget-rules.md +0 -34
  151. package/bundled/dev-pipeline-windows/templates/sections/critical-paths-agent.md +0 -10
  152. package/bundled/dev-pipeline-windows/templates/sections/critical-paths-full.md +0 -12
  153. package/bundled/dev-pipeline-windows/templates/sections/critical-paths-lite.md +0 -7
  154. package/bundled/dev-pipeline-windows/templates/sections/directory-convention-agent.md +0 -8
  155. package/bundled/dev-pipeline-windows/templates/sections/directory-convention-full.md +0 -9
  156. package/bundled/dev-pipeline-windows/templates/sections/directory-convention-lite.md +0 -6
  157. package/bundled/dev-pipeline-windows/templates/sections/failure-capture.md +0 -21
  158. package/bundled/dev-pipeline-windows/templates/sections/feature-context.md +0 -21
  159. package/bundled/dev-pipeline-windows/templates/sections/log-size-awareness.md +0 -41
  160. package/bundled/dev-pipeline-windows/templates/sections/phase-browser-verification-auto.md +0 -283
  161. package/bundled/dev-pipeline-windows/templates/sections/phase-browser-verification-opencli.md +0 -112
  162. package/bundled/dev-pipeline-windows/templates/sections/phase-browser-verification.md +0 -168
  163. package/bundled/dev-pipeline-windows/templates/sections/phase-commit-full.md +0 -82
  164. package/bundled/dev-pipeline-windows/templates/sections/phase-commit.md +0 -75
  165. package/bundled/dev-pipeline-windows/templates/sections/phase-context-snapshot-agent-suffix.md +0 -23
  166. package/bundled/dev-pipeline-windows/templates/sections/phase-context-snapshot-base.md +0 -14
  167. package/bundled/dev-pipeline-windows/templates/sections/phase-context-snapshot-lite-suffix.md +0 -19
  168. package/bundled/dev-pipeline-windows/templates/sections/phase-critic-plan-full.md +0 -63
  169. package/bundled/dev-pipeline-windows/templates/sections/phase-critic-plan.md +0 -42
  170. package/bundled/dev-pipeline-windows/templates/sections/phase-implement-agent.md +0 -44
  171. package/bundled/dev-pipeline-windows/templates/sections/phase-implement-full.md +0 -59
  172. package/bundled/dev-pipeline-windows/templates/sections/phase-implement-lite.md +0 -39
  173. package/bundled/dev-pipeline-windows/templates/sections/phase-plan-agent.md +0 -27
  174. package/bundled/dev-pipeline-windows/templates/sections/phase-plan-lite.md +0 -27
  175. package/bundled/dev-pipeline-windows/templates/sections/phase-prizmkit-test.md +0 -39
  176. package/bundled/dev-pipeline-windows/templates/sections/phase-review-agent.md +0 -35
  177. package/bundled/dev-pipeline-windows/templates/sections/phase-review-full.md +0 -35
  178. package/bundled/dev-pipeline-windows/templates/sections/phase-specify-plan-full.md +0 -73
  179. package/bundled/dev-pipeline-windows/templates/sections/phase0-init.md +0 -13
  180. package/bundled/dev-pipeline-windows/templates/sections/phase0-test-baseline.md +0 -21
  181. package/bundled/dev-pipeline-windows/templates/sections/session-context.md +0 -5
  182. package/bundled/dev-pipeline-windows/templates/sections/subagent-timeout-recovery.md +0 -6
  183. package/bundled/dev-pipeline-windows/templates/sections/task-contract.md +0 -34
  184. package/bundled/dev-pipeline-windows/templates/sections/test-failure-recovery-agent.md +0 -48
  185. package/bundled/dev-pipeline-windows/templates/sections/test-failure-recovery-lite.md +0 -48
  186. package/bundled/dev-pipeline-windows/templates/session-status-schema.json +0 -83
  187. package/bundled/skills-windows/app-planner/SKILL.md +0 -296
  188. package/bundled/skills-windows/app-planner/assets/app-design-guide.md +0 -101
  189. package/bundled/skills-windows/app-planner/references/architecture-decisions.md +0 -52
  190. package/bundled/skills-windows/app-planner/references/brainstorm-guide.md +0 -101
  191. package/bundled/skills-windows/app-planner/references/frontend-design-guide.md +0 -71
  192. package/bundled/skills-windows/app-planner/references/infrastructure-convention-discovery.md +0 -108
  193. package/bundled/skills-windows/app-planner/references/project-brief-guide.md +0 -82
  194. package/bundled/skills-windows/app-planner/references/project-conventions-discovery.md +0 -59
  195. package/bundled/skills-windows/app-planner/references/project-state-detection.md +0 -90
  196. package/bundled/skills-windows/app-planner/references/red-team-checklist.md +0 -40
  197. package/bundled/skills-windows/app-planner/references/rules/backend/derivation-rules.md +0 -619
  198. package/bundled/skills-windows/app-planner/references/rules/backend/fixed-rules.md +0 -285
  199. package/bundled/skills-windows/app-planner/references/rules/backend/question-bank.md +0 -249
  200. package/bundled/skills-windows/app-planner/references/rules/backend/question-manifest.json +0 -46
  201. package/bundled/skills-windows/app-planner/references/rules/backend/template.md +0 -173
  202. package/bundled/skills-windows/app-planner/references/rules/database/derivation-rules.md +0 -382
  203. package/bundled/skills-windows/app-planner/references/rules/database/fixed-rules.md +0 -211
  204. package/bundled/skills-windows/app-planner/references/rules/database/question-bank.md +0 -184
  205. package/bundled/skills-windows/app-planner/references/rules/database/question-manifest.json +0 -39
  206. package/bundled/skills-windows/app-planner/references/rules/database/template.md +0 -158
  207. package/bundled/skills-windows/app-planner/references/rules/frontend/derivation-rules.md +0 -820
  208. package/bundled/skills-windows/app-planner/references/rules/frontend/fixed-rules.md +0 -188
  209. package/bundled/skills-windows/app-planner/references/rules/frontend/question-bank.md +0 -319
  210. package/bundled/skills-windows/app-planner/references/rules/frontend/question-manifest.json +0 -51
  211. package/bundled/skills-windows/app-planner/references/rules/frontend/template.md +0 -339
  212. package/bundled/skills-windows/app-planner/references/rules/mobile/derivation-rules.md +0 -649
  213. package/bundled/skills-windows/app-planner/references/rules/mobile/fixed-rules.md +0 -290
  214. package/bundled/skills-windows/app-planner/references/rules/mobile/question-bank.md +0 -232
  215. package/bundled/skills-windows/app-planner/references/rules/mobile/question-manifest.json +0 -47
  216. package/bundled/skills-windows/app-planner/references/rules/mobile/template.md +0 -175
  217. package/bundled/skills-windows/app-planner/references/rules-configuration.md +0 -46
  218. package/bundled/skills-windows/bug-fix-workflow/SKILL.md +0 -379
  219. package/bundled/skills-windows/bug-fix-workflow/references/bug-diagnosis.md +0 -41
  220. package/bundled/skills-windows/bug-planner/SKILL.md +0 -402
  221. package/bundled/skills-windows/bug-planner/assets/bug-confirmation-template.md +0 -43
  222. package/bundled/skills-windows/bug-planner/references/critic-and-verification.md +0 -44
  223. package/bundled/skills-windows/bug-planner/references/error-recovery.md +0 -73
  224. package/bundled/skills-windows/bug-planner/references/input-formats.md +0 -53
  225. package/bundled/skills-windows/bug-planner/references/schema-validation.md +0 -25
  226. package/bundled/skills-windows/bug-planner/references/severity-rules.md +0 -16
  227. package/bundled/skills-windows/bug-planner/scripts/validate-bug-list.py +0 -322
  228. package/bundled/skills-windows/bugfix-pipeline-launcher/SKILL.md +0 -304
  229. package/bundled/skills-windows/bugfix-pipeline-launcher/references/configuration.md +0 -84
  230. package/bundled/skills-windows/feature-pipeline-launcher/SKILL.md +0 -381
  231. package/bundled/skills-windows/feature-pipeline-launcher/references/configuration.md +0 -67
  232. package/bundled/skills-windows/feature-pipeline-launcher/scripts/preflight-check.py +0 -462
  233. package/bundled/skills-windows/feature-planner/SKILL.md +0 -397
  234. package/bundled/skills-windows/feature-planner/assets/evaluation-guide.md +0 -64
  235. package/bundled/skills-windows/feature-planner/assets/planning-guide.md +0 -214
  236. package/bundled/skills-windows/feature-planner/references/browser-interaction.md +0 -59
  237. package/bundled/skills-windows/feature-planner/references/completeness-review.md +0 -57
  238. package/bundled/skills-windows/feature-planner/references/decomposition-patterns.md +0 -75
  239. package/bundled/skills-windows/feature-planner/references/error-recovery.md +0 -90
  240. package/bundled/skills-windows/feature-planner/references/incremental-feature-planning.md +0 -112
  241. package/bundled/skills-windows/feature-planner/references/new-project-planning.md +0 -85
  242. package/bundled/skills-windows/feature-planner/scripts/validate-and-generate.py +0 -1020
  243. package/bundled/skills-windows/feature-workflow/SKILL.md +0 -374
  244. package/bundled/skills-windows/feature-workflow/references/brainstorm-guide.md +0 -137
  245. package/bundled/skills-windows/prizm-kit/SKILL.md +0 -93
  246. package/bundled/skills-windows/prizmkit-code-review/SKILL.md +0 -161
  247. package/bundled/skills-windows/prizmkit-code-review/references/dev-agent-prompt.md +0 -30
  248. package/bundled/skills-windows/prizmkit-code-review/references/review-report-template.md +0 -31
  249. package/bundled/skills-windows/prizmkit-code-review/references/reviewer-agent-prompt.md +0 -66
  250. package/bundled/skills-windows/prizmkit-code-review/scripts/check_loop.py +0 -186
  251. package/bundled/skills-windows/prizmkit-committer/SKILL.md +0 -89
  252. package/bundled/skills-windows/prizmkit-deploy/SKILL.md +0 -444
  253. package/bundled/skills-windows/prizmkit-deploy/references/ci-cd-workflows.md +0 -115
  254. package/bundled/skills-windows/prizmkit-deploy/references/cloud-platform-deploy.md +0 -93
  255. package/bundled/skills-windows/prizmkit-deploy/references/data-safety-examples.md +0 -120
  256. package/bundled/skills-windows/prizmkit-deploy/references/database-setup.md +0 -46
  257. package/bundled/skills-windows/prizmkit-deploy/references/deploy-config-schema.md +0 -148
  258. package/bundled/skills-windows/prizmkit-deploy/references/deploy-history-schema.md +0 -62
  259. package/bundled/skills-windows/prizmkit-deploy/references/deployment-modes.md +0 -50
  260. package/bundled/skills-windows/prizmkit-deploy/references/direct-upload.md +0 -26
  261. package/bundled/skills-windows/prizmkit-deploy/references/dns-setup.md +0 -42
  262. package/bundled/skills-windows/prizmkit-deploy/references/docker-deploy.md +0 -31
  263. package/bundled/skills-windows/prizmkit-deploy/references/firewall-setup.md +0 -37
  264. package/bundled/skills-windows/prizmkit-deploy/references/live-validation-notes.md +0 -21
  265. package/bundled/skills-windows/prizmkit-deploy/references/nginx-blue-green.md +0 -59
  266. package/bundled/skills-windows/prizmkit-deploy/references/ssh-bootstrap-flow.md +0 -49
  267. package/bundled/skills-windows/prizmkit-deploy/references/ssh-execution-flow.md +0 -41
  268. package/bundled/skills-windows/prizmkit-deploy/references/ssh-takeover.md +0 -20
  269. package/bundled/skills-windows/prizmkit-deploy/references/ssl-setup.md +0 -56
  270. package/bundled/skills-windows/prizmkit-implement/SKILL.md +0 -71
  271. package/bundled/skills-windows/prizmkit-init/SKILL.md +0 -356
  272. package/bundled/skills-windows/prizmkit-init/assets/project-brief-template.md +0 -82
  273. package/bundled/skills-windows/prizmkit-init/references/config-schema.md +0 -70
  274. package/bundled/skills-windows/prizmkit-init/references/rules/layer-detection.md +0 -41
  275. package/bundled/skills-windows/prizmkit-init/references/tech-stack-catalog.md +0 -13
  276. package/bundled/skills-windows/prizmkit-init/references/update-supplement.md +0 -9
  277. package/bundled/skills-windows/prizmkit-plan/SKILL.md +0 -102
  278. package/bundled/skills-windows/prizmkit-plan/assets/plan-template.md +0 -115
  279. package/bundled/skills-windows/prizmkit-plan/assets/spec-template.md +0 -73
  280. package/bundled/skills-windows/prizmkit-plan/references/clarify-guide.md +0 -67
  281. package/bundled/skills-windows/prizmkit-plan/references/examples.md +0 -85
  282. package/bundled/skills-windows/prizmkit-plan/references/verification-checklist.md +0 -60
  283. package/bundled/skills-windows/prizmkit-prizm-docs/SKILL.md +0 -129
  284. package/bundled/skills-windows/prizmkit-prizm-docs/assets/prizm-docs-format.md +0 -613
  285. package/bundled/skills-windows/prizmkit-prizm-docs/references/op-init.md +0 -45
  286. package/bundled/skills-windows/prizmkit-prizm-docs/references/op-rebuild.md +0 -15
  287. package/bundled/skills-windows/prizmkit-prizm-docs/references/op-status.md +0 -14
  288. package/bundled/skills-windows/prizmkit-prizm-docs/references/op-update.md +0 -19
  289. package/bundled/skills-windows/prizmkit-prizm-docs/references/op-validate.md +0 -17
  290. package/bundled/skills-windows/prizmkit-retrospective/SKILL.md +0 -87
  291. package/bundled/skills-windows/prizmkit-retrospective/references/knowledge-injection-steps.md +0 -50
  292. package/bundled/skills-windows/prizmkit-retrospective/references/structural-sync-steps.md +0 -43
  293. package/bundled/skills-windows/prizmkit-test/SKILL.md +0 -227
  294. package/bundled/skills-windows/prizmkit-test/references/boundary-coverage-protocol.md +0 -220
  295. package/bundled/skills-windows/prizmkit-test/references/examples.md +0 -143
  296. package/bundled/skills-windows/prizmkit-test/references/service-boundary-test-catalog.md +0 -225
  297. package/bundled/skills-windows/prizmkit-test/references/test-generation-steps.md +0 -109
  298. package/bundled/skills-windows/prizmkit-test/references/test-report-template.md +0 -111
  299. package/bundled/skills-windows/prizmkit-test/scripts/validate_boundary_report.py +0 -347
  300. package/bundled/skills-windows/recovery-workflow/SKILL.md +0 -355
  301. package/bundled/skills-windows/recovery-workflow/evals/evals.json +0 -46
  302. package/bundled/skills-windows/recovery-workflow/references/detection.md +0 -58
  303. package/bundled/skills-windows/recovery-workflow/scripts/detect-recovery-state.py +0 -544
  304. package/bundled/skills-windows/refactor-pipeline-launcher/SKILL.md +0 -346
  305. package/bundled/skills-windows/refactor-pipeline-launcher/references/configuration.md +0 -72
  306. package/bundled/skills-windows/refactor-planner/SKILL.md +0 -398
  307. package/bundled/skills-windows/refactor-planner/assets/planning-guide.md +0 -292
  308. package/bundled/skills-windows/refactor-planner/references/behavior-preservation.md +0 -301
  309. package/bundled/skills-windows/refactor-planner/references/fast-path.md +0 -59
  310. package/bundled/skills-windows/refactor-planner/references/planning-phases.md +0 -135
  311. package/bundled/skills-windows/refactor-planner/references/refactor-scoping-guide.md +0 -221
  312. package/bundled/skills-windows/refactor-planner/scripts/validate-and-generate-refactor.py +0 -858
  313. package/bundled/skills-windows/refactor-workflow/SKILL.md +0 -343
  314. package/bundled/skills-windows/refactor-workflow/references/brainstorm-guide.md +0 -116
  315. package/bundled/templates/hooks/diff-prizm-docs.sh +0 -158
  316. package/bundled/templates/hooks/prizm-pre-commit.sh +0 -108
  317. package/bundled/templates/hooks/validate-prizm-docs.sh +0 -139
@@ -0,0 +1,478 @@
1
+ """Daemon lifecycle commands for the unified Python runtime."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ import os
7
+ import shlex
8
+ import subprocess
9
+ import sys
10
+ import time
11
+ from dataclasses import dataclass
12
+ from datetime import datetime, timezone
13
+ from pathlib import Path
14
+
15
+ from .commands import CommandResult # type: ignore # runtime boundary import
16
+ from .processes import ProcessSpec, is_pid_running, launch_process, terminate_pid_tree
17
+ from .runner_models import RunnerFamily, family_for
18
+
19
+
20
+ LOG_ROTATE_BYTES = 50 * 1024 * 1024
21
+ START_VERIFY_SECONDS = 2.0
22
+
23
+
24
+ @dataclass(frozen=True)
25
+ class DaemonPaths:
26
+ """Filesystem contract for one pipeline daemon."""
27
+
28
+ state_dir: Path
29
+ pid_file: Path
30
+ log_file: Path
31
+ meta_file: Path
32
+
33
+
34
+ @dataclass(frozen=True)
35
+ class DaemonStartOptions:
36
+ """Parsed daemon start/restart arguments."""
37
+
38
+ list_path: Path
39
+ env_overrides: str = ""
40
+ mode: str = ""
41
+ features_filter: str = ""
42
+ critic: bool | None = None
43
+ help_requested: bool = False
44
+
45
+
46
+ @dataclass(frozen=True)
47
+ class DaemonLogOptions:
48
+ """Parsed daemon log arguments."""
49
+
50
+ lines: int = 50
51
+ follow: bool = False
52
+
53
+
54
+ LIST_META_KEY_BY_KIND = {
55
+ "feature": "feature_list",
56
+ "bugfix": "bug_list",
57
+ "refactor": "refactor_list",
58
+ }
59
+
60
+ ITEMS_KEY_BY_KIND = {
61
+ "feature": "features",
62
+ "bugfix": "bugs",
63
+ "refactor": "refactors",
64
+ }
65
+
66
+ ID_KEY_BY_KIND = {
67
+ "feature": "id",
68
+ "bugfix": "id",
69
+ "refactor": "id",
70
+ }
71
+
72
+ PROGRESS_COUNTS_BY_KIND = {
73
+ "feature": ("completed", "in_progress", "failed", "pending", "skipped", "auto_skipped"),
74
+ "bugfix": ("completed", "in_progress", "failed", "pending", "needs_info", "skipped"),
75
+ "refactor": ("completed", "in_progress", "failed", "pending", "skipped", "auto_skipped"),
76
+ }
77
+
78
+
79
+ def run_daemon_command(kind: str, action: str, legacy_args: tuple[str, ...], paths) -> CommandResult:
80
+ """Run a daemon lifecycle command for feature, bugfix, or refactor."""
81
+ family = family_for(kind, paths)
82
+ daemon_paths = _daemon_paths(family)
83
+ if action == "describe":
84
+ return CommandResult(0, f"Python {kind} daemon", _help_text(family))
85
+ if action == "start":
86
+ return _start(family, daemon_paths, legacy_args, paths)
87
+ if action == "status":
88
+ return _status(family, daemon_paths)
89
+ if action == "stop":
90
+ return _stop(family, daemon_paths)
91
+ if action in {"logs", "log"}:
92
+ return _logs(family, daemon_paths, legacy_args)
93
+ if action == "restart":
94
+ stop_result = _stop(family, daemon_paths)
95
+ start_result = _start(family, daemon_paths, legacy_args, paths)
96
+ stderr = "\n".join(part for part in (stop_result.stderr, start_result.stderr) if part)
97
+ return CommandResult(start_result.exit_code, start_result.title, start_result.message, stdout=start_result.render(), stderr=stderr)
98
+ return CommandResult(1, f"Python {kind} daemon", f"Unsupported daemon action: {action}")
99
+
100
+
101
+ def _daemon_paths(family: RunnerFamily) -> DaemonPaths:
102
+ return DaemonPaths(
103
+ state_dir=family.state_dir,
104
+ pid_file=family.state_dir / ".pipeline.pid",
105
+ log_file=family.state_dir / "pipeline-daemon.log",
106
+ meta_file=family.state_dir / ".pipeline-meta.json",
107
+ )
108
+
109
+
110
+ def _start(family: RunnerFamily, daemon_paths: DaemonPaths, legacy_args: tuple[str, ...], paths) -> CommandResult:
111
+ options = _parse_start_args(family, legacy_args)
112
+ if options.help_requested:
113
+ return CommandResult(0, f"Python {family.kind} daemon", _help_text(family))
114
+ list_path = options.list_path if options.list_path.is_absolute() else (paths.project_root / options.list_path).resolve()
115
+ if not list_path.is_file():
116
+ stderr = f"{family.kind} list not found: {list_path}"
117
+ return CommandResult(2, f"Python {family.kind} daemon", stderr, stdout="", stderr=stderr)
118
+
119
+ daemon_paths.state_dir.mkdir(parents=True, exist_ok=True)
120
+ stale_warning = _clean_stale_pid(daemon_paths)
121
+ stderr_lines = [stale_warning] if stale_warning else []
122
+ running_pid = _read_pid(daemon_paths.pid_file)
123
+ if is_pid_running(running_pid):
124
+ message = f"Pipeline is already running (PID: {running_pid})"
125
+ return CommandResult(1, f"Python {family.kind} daemon", message, stdout="", stderr=message)
126
+
127
+ rotated = _rotate_log_if_needed(daemon_paths.log_file)
128
+ if rotated:
129
+ stderr_lines.append(f"Log rotated: {rotated}")
130
+
131
+ started_at = _utc_iso()
132
+ _write_log_separator(family, daemon_paths.log_file, list_path, started_at, options)
133
+ command = _payload_command(family, paths, list_path, options)
134
+ env = _daemon_env(options)
135
+ spec = ProcessSpec(
136
+ command=tuple(command),
137
+ cwd=paths.project_root,
138
+ environment_overrides=env,
139
+ environment_unsets=("CLAUDECODE",),
140
+ pid_file=daemon_paths.pid_file,
141
+ )
142
+ log_handle = daemon_paths.log_file.open("a", encoding="utf-8")
143
+ try:
144
+ handle = launch_process(spec, stdout=log_handle, stderr=subprocess.STDOUT, stdin=subprocess.DEVNULL, text=True)
145
+ finally:
146
+ log_handle.close()
147
+
148
+ pid = int(handle.pid or 0)
149
+ _write_meta(family, daemon_paths.meta_file, pid, started_at, list_path, options, daemon_paths.log_file)
150
+ time.sleep(_start_verify_seconds())
151
+ if not is_pid_running(pid):
152
+ daemon_paths.pid_file.unlink(missing_ok=True)
153
+ message = f"Pipeline process died immediately after launch. Check log for errors: {daemon_paths.log_file}"
154
+ return CommandResult(1, f"Python {family.kind} daemon", message, stdout="", stderr="\n".join([*stderr_lines, message]))
155
+
156
+ stderr_lines.extend(
157
+ [
158
+ f"Launching {family.kind} pipeline...",
159
+ f"{family.kind} list: {list_path}",
160
+ f"Log file: {daemon_paths.log_file}",
161
+ f"Pipeline started successfully (PID: {pid})",
162
+ ]
163
+ )
164
+ payload = {"success": True, "pid": pid, "log_file": str(daemon_paths.log_file), "started_at": started_at}
165
+ return CommandResult(0, f"Python {family.kind} daemon", "started", stdout=json.dumps(payload), stderr="\n".join(stderr_lines))
166
+
167
+
168
+ def _status(family: RunnerFamily, daemon_paths: DaemonPaths) -> CommandResult:
169
+ daemon_paths.state_dir.mkdir(parents=True, exist_ok=True)
170
+ stderr_lines: list[str] = []
171
+ stale_warning = _clean_stale_pid(daemon_paths)
172
+ if stale_warning:
173
+ stderr_lines.append(stale_warning)
174
+
175
+ pid = _read_pid(daemon_paths.pid_file)
176
+ meta = _read_meta(daemon_paths.meta_file)
177
+ if not is_pid_running(pid):
178
+ stderr_lines.append("Pipeline is not running")
179
+ if daemon_paths.log_file.is_file():
180
+ stderr_lines.append(f"Last log: {daemon_paths.log_file} ({daemon_paths.log_file.stat().st_size // 1024}KB)")
181
+ return CommandResult(1, f"Python {family.kind} daemon status", "not running", stdout=json.dumps({"running": False}), stderr="\n".join(stderr_lines))
182
+
183
+ list_key = LIST_META_KEY_BY_KIND[family.kind]
184
+ list_path = str(meta.get(list_key) or "")
185
+ log_size_kb = daemon_paths.log_file.stat().st_size // 1024 if daemon_paths.log_file.is_file() else 0
186
+ started_at = str(meta.get("started_at") or "")
187
+ payload: dict[str, object] = {
188
+ "running": True,
189
+ "pid": pid,
190
+ "log_file": str(daemon_paths.log_file),
191
+ "log_size_kb": log_size_kb,
192
+ "started_at": started_at,
193
+ list_key: list_path,
194
+ }
195
+ if family.kind != "feature":
196
+ payload["pipeline_type"] = family.kind
197
+ progress = _progress_summary(family, Path(list_path) if list_path else None)
198
+ if progress:
199
+ payload["progress"] = progress
200
+
201
+ stderr_lines.append(f"Pipeline is running (PID: {pid})")
202
+ if started_at:
203
+ stderr_lines.append(f"Started at: {started_at}")
204
+ stderr_lines.append(f"Log file: {daemon_paths.log_file} ({log_size_kb}KB)")
205
+ tail = _tail_lines(daemon_paths.log_file, 5)
206
+ if tail:
207
+ stderr_lines.append("--- Last 5 log lines ---")
208
+ stderr_lines.extend(tail)
209
+ return CommandResult(0, f"Python {family.kind} daemon status", "running", stdout=json.dumps(payload), stderr="\n".join(stderr_lines))
210
+
211
+
212
+ def _stop(family: RunnerFamily, daemon_paths: DaemonPaths) -> CommandResult:
213
+ if not daemon_paths.pid_file.is_file():
214
+ message = "Pipeline is not running (no PID file)"
215
+ return CommandResult(0, f"Python {family.kind} daemon stop", message, stdout=json.dumps({"success": True, "message": "not running"}), stderr=message)
216
+ pid = _read_pid(daemon_paths.pid_file)
217
+ if pid is None:
218
+ daemon_paths.pid_file.unlink(missing_ok=True)
219
+ message = "Pipeline is not running (empty PID file)"
220
+ return CommandResult(0, f"Python {family.kind} daemon stop", message, stdout=json.dumps({"success": True, "message": "not running"}), stderr=message)
221
+ if not is_pid_running(pid):
222
+ daemon_paths.pid_file.unlink(missing_ok=True)
223
+ message = f"Pipeline is not running (process {pid} already exited)"
224
+ return CommandResult(0, f"Python {family.kind} daemon stop", message, stdout=json.dumps({"success": True, "message": "already exited"}), stderr=message)
225
+
226
+ termination = terminate_pid_tree(pid, "daemon_stop", grace_seconds=30.0)
227
+ if termination.terminated:
228
+ daemon_paths.pid_file.unlink(missing_ok=True)
229
+ payload = {"success": True, "pid": pid, "message": "stopped"}
230
+ return CommandResult(0, f"Python {family.kind} daemon stop", "stopped", stdout=json.dumps(payload), stderr=f"Pipeline stopped (PID: {pid})")
231
+ payload = {"success": False, "pid": pid, "message": "failed to stop"}
232
+ return CommandResult(1, f"Python {family.kind} daemon stop", "failed", stdout=json.dumps(payload), stderr=f"Failed to stop pipeline (PID: {pid})")
233
+
234
+
235
+ def _logs(family: RunnerFamily, daemon_paths: DaemonPaths, legacy_args: tuple[str, ...]) -> CommandResult:
236
+ options = _parse_log_args(legacy_args)
237
+ if not daemon_paths.log_file.is_file():
238
+ message = f"No log file found at {daemon_paths.log_file}\nPipeline has not been started yet"
239
+ return CommandResult(0, f"Python {family.kind} daemon logs", message, stdout="", stderr=message)
240
+ if options.follow:
241
+ return _follow_log(family, daemon_paths.log_file)
242
+ return CommandResult(0, f"Python {family.kind} daemon logs", "logs", stdout="\n".join(_tail_lines(daemon_paths.log_file, options.lines)))
243
+
244
+
245
+ def _parse_start_args(family: RunnerFamily, legacy_args: tuple[str, ...]) -> DaemonStartOptions:
246
+ list_path = family.plan_path
247
+ env_overrides = ""
248
+ mode = ""
249
+ features_filter = ""
250
+ critic: bool | None = None
251
+ help_requested = False
252
+ positional: list[str] = []
253
+ index = 0
254
+ while index < len(legacy_args):
255
+ arg = legacy_args[index]
256
+ if arg in {"--help", "-h", "help"}:
257
+ help_requested = True
258
+ elif arg == "--env" and index + 1 < len(legacy_args):
259
+ index += 1
260
+ env_overrides = legacy_args[index]
261
+ elif arg == "--mode" and index + 1 < len(legacy_args):
262
+ index += 1
263
+ mode = legacy_args[index]
264
+ if mode not in {"lite", "standard", "full"}:
265
+ raise ValueError(f"Invalid mode: {mode} (must be lite, standard, or full)")
266
+ elif arg == "--features" and index + 1 < len(legacy_args):
267
+ index += 1
268
+ features_filter = legacy_args[index]
269
+ elif arg == "--critic":
270
+ critic = True
271
+ elif arg == "--no-critic":
272
+ critic = False
273
+ else:
274
+ positional.append(arg)
275
+ index += 1
276
+ if positional:
277
+ list_path = Path(positional[0]).expanduser()
278
+ return DaemonStartOptions(list_path=list_path, env_overrides=env_overrides, mode=mode, features_filter=features_filter, critic=critic, help_requested=help_requested)
279
+
280
+
281
+ def _parse_log_args(legacy_args: tuple[str, ...]) -> DaemonLogOptions:
282
+ lines = 50
283
+ follow = False
284
+ index = 0
285
+ while index < len(legacy_args):
286
+ arg = legacy_args[index]
287
+ if arg in {"--follow", "-f"}:
288
+ follow = True
289
+ elif arg in {"--lines", "-n"} and index + 1 < len(legacy_args):
290
+ index += 1
291
+ try:
292
+ lines = max(0, int(legacy_args[index]))
293
+ except ValueError:
294
+ lines = 50
295
+ index += 1
296
+ return DaemonLogOptions(lines=lines, follow=follow)
297
+
298
+
299
+ def _payload_command(family: RunnerFamily, paths, list_path: Path, options: DaemonStartOptions) -> list[str]:
300
+ command = [
301
+ sys.executable,
302
+ str(paths.pipeline_root / "cli.py"),
303
+ "--project-root",
304
+ str(paths.project_root),
305
+ "--pipeline-root",
306
+ str(paths.pipeline_root),
307
+ family.kind,
308
+ "run",
309
+ str(list_path),
310
+ ]
311
+ if family.kind == "feature" and options.features_filter:
312
+ command.extend(["--features", options.features_filter])
313
+ if options.mode:
314
+ command.extend(["--mode", options.mode])
315
+ if options.critic is True:
316
+ command.append("--critic")
317
+ elif options.critic is False:
318
+ command.append("--no-critic")
319
+ return command
320
+
321
+
322
+ def _daemon_env(options: DaemonStartOptions) -> dict[str, str]:
323
+ env: dict[str, str] = {}
324
+ for token in shlex.split(options.env_overrides):
325
+ if "=" in token:
326
+ key, value = token.split("=", 1)
327
+ if key:
328
+ env[key] = value
329
+ if options.mode:
330
+ env["PIPELINE_MODE"] = options.mode
331
+ if options.critic is not None:
332
+ env["ENABLE_CRITIC"] = "true" if options.critic else "false"
333
+ return env
334
+
335
+
336
+ def _clean_stale_pid(daemon_paths: DaemonPaths) -> str:
337
+ if not daemon_paths.pid_file.is_file():
338
+ return ""
339
+ pid = _read_pid(daemon_paths.pid_file)
340
+ if pid is not None and not is_pid_running(pid):
341
+ daemon_paths.pid_file.unlink(missing_ok=True)
342
+ return f"Cleaned stale PID file (process {pid} no longer running)"
343
+ return ""
344
+
345
+
346
+ def _read_pid(path: Path) -> int | None:
347
+ if not path.is_file():
348
+ return None
349
+ try:
350
+ raw = path.read_text(encoding="utf-8").strip()
351
+ return int(raw) if raw else None
352
+ except (OSError, ValueError):
353
+ return None
354
+
355
+
356
+ def _write_meta(family: RunnerFamily, path: Path, pid: int, started_at: str, list_path: Path, options: DaemonStartOptions, log_file: Path) -> None:
357
+ data: dict[str, object] = {
358
+ "pid": pid,
359
+ "pipeline_type": family.kind,
360
+ "started_at": started_at,
361
+ LIST_META_KEY_BY_KIND[family.kind]: str(list_path),
362
+ "env_overrides": options.env_overrides,
363
+ "mode": options.mode,
364
+ "log_file": str(log_file),
365
+ }
366
+ tmp = path.with_suffix(path.suffix + ".tmp")
367
+ tmp.write_text(json.dumps(data, indent=2), encoding="utf-8")
368
+ tmp.replace(path)
369
+
370
+
371
+ def _read_meta(path: Path) -> dict[str, object]:
372
+ if not path.is_file():
373
+ return {}
374
+ try:
375
+ data = json.loads(path.read_text(encoding="utf-8"))
376
+ except (OSError, json.JSONDecodeError):
377
+ return {}
378
+ return data if isinstance(data, dict) else {}
379
+
380
+
381
+ def _progress_summary(family: RunnerFamily, list_path: Path | None) -> dict[str, object]:
382
+ if list_path is None or not list_path.is_file():
383
+ return {}
384
+ try:
385
+ data = json.loads(list_path.read_text(encoding="utf-8"))
386
+ except (OSError, json.JSONDecodeError):
387
+ return {}
388
+ items = data.get(ITEMS_KEY_BY_KIND[family.kind], [])
389
+ if not isinstance(items, list):
390
+ items = []
391
+ counts = {key: 0 for key in PROGRESS_COUNTS_BY_KIND[family.kind]}
392
+ for item in items:
393
+ if not isinstance(item, dict):
394
+ continue
395
+ item_id = str(item.get(ID_KEY_BY_KIND[family.kind]) or "")
396
+ status = str(item.get("status") or "pending")
397
+ status_file = family.state_dir / item_id / "status.json"
398
+ if status_file.is_file():
399
+ try:
400
+ status_data = json.loads(status_file.read_text(encoding="utf-8"))
401
+ status = str(status_data.get("status") or status)
402
+ except (OSError, json.JSONDecodeError):
403
+ pass
404
+ counts[status if status in counts else "pending"] += 1
405
+ total = len(items)
406
+ percent = round(counts.get("completed", 0) / total * 100, 1) if total else 0
407
+ return {"total": total, **counts, "percent": percent}
408
+
409
+
410
+ def _write_log_separator(family: RunnerFamily, log_file: Path, list_path: Path, started_at: str, options: DaemonStartOptions) -> None:
411
+ log_file.parent.mkdir(parents=True, exist_ok=True)
412
+ lines = [
413
+ "",
414
+ "================================================================",
415
+ f" {family.kind.title()} Pipeline Daemon Started: {started_at}",
416
+ f" {family.kind.title()} list: {list_path}",
417
+ ]
418
+ if options.features_filter:
419
+ lines.append(f" Features filter: {options.features_filter}")
420
+ if options.mode:
421
+ lines.append(f" Mode: {options.mode}")
422
+ if options.env_overrides:
423
+ lines.append(f" Environment: {options.env_overrides}")
424
+ lines.extend(["================================================================", ""])
425
+ with log_file.open("a", encoding="utf-8") as handle:
426
+ handle.write("\n".join(lines) + "\n")
427
+
428
+
429
+ def _rotate_log_if_needed(log_file: Path) -> Path | None:
430
+ if not log_file.is_file() or log_file.stat().st_size <= LOG_ROTATE_BYTES:
431
+ return None
432
+ rotated = log_file.with_name(f"{log_file.name}.{datetime.now(timezone.utc).strftime('%Y%m%dT%H%M%S')}.bak")
433
+ log_file.replace(rotated)
434
+ return rotated
435
+
436
+
437
+ def _tail_lines(path: Path, count: int) -> list[str]:
438
+ if count <= 0 or not path.is_file():
439
+ return []
440
+ try:
441
+ return path.read_text(encoding="utf-8", errors="replace").splitlines()[-count:]
442
+ except OSError:
443
+ return []
444
+
445
+
446
+ def _follow_log(family: RunnerFamily, log_file: Path) -> CommandResult:
447
+ try:
448
+ with log_file.open("r", encoding="utf-8", errors="replace") as handle:
449
+ handle.seek(0, os.SEEK_END)
450
+ while True:
451
+ line = handle.readline()
452
+ if line:
453
+ print(line, end="")
454
+ else:
455
+ time.sleep(0.5)
456
+ except KeyboardInterrupt:
457
+ return CommandResult(0, f"Python {family.kind} daemon logs", "follow stopped", stdout="")
458
+
459
+
460
+ def _utc_iso() -> str:
461
+ return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
462
+
463
+
464
+ def _start_verify_seconds() -> float:
465
+ raw = os.environ.get("PRIZMKIT_DAEMON_VERIFY_SECONDS")
466
+ if raw is None:
467
+ return START_VERIFY_SECONDS
468
+ try:
469
+ return max(0.0, float(raw))
470
+ except ValueError:
471
+ return START_VERIFY_SECONDS
472
+
473
+
474
+ def _help_text(family: RunnerFamily) -> str:
475
+ return (
476
+ f"Usage: prizmkit-runtime daemon {family.kind} <start|stop|status|logs|restart> [options]\n"
477
+ "Commands preserve .pipeline.pid, pipeline-daemon.log, and .pipeline-meta.json contracts."
478
+ )