prizmkit 1.1.99 → 1.1.101

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 (321) 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 +345 -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 +147 -0
  26. package/bundled/dev-pipeline/prizmkit_runtime/runners.py +422 -0
  27. package/bundled/dev-pipeline/prizmkit_runtime/sessions.py +552 -0
  28. package/bundled/dev-pipeline/prizmkit_runtime/status.py +71 -0
  29. package/bundled/dev-pipeline/scripts/check-session-status.py +74 -1
  30. package/bundled/dev-pipeline/scripts/continuation.py +374 -0
  31. package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +64 -52
  32. package/bundled/dev-pipeline/scripts/generate-bugfix-prompt.py +35 -25
  33. package/bundled/dev-pipeline/scripts/generate-recovery-prompt.py +2 -2
  34. package/bundled/dev-pipeline/scripts/generate-refactor-prompt.py +15 -20
  35. package/bundled/dev-pipeline/scripts/parse-stream-progress.py +185 -16
  36. package/bundled/dev-pipeline/scripts/update-bug-status.py +214 -6
  37. package/bundled/dev-pipeline/scripts/update-feature-status.py +237 -6
  38. package/bundled/dev-pipeline/scripts/update-refactor-status.py +214 -6
  39. package/bundled/dev-pipeline/templates/agent-prompts/dev-implement.md +8 -2
  40. package/bundled/dev-pipeline/templates/bootstrap-prompt.md +4 -0
  41. package/bundled/dev-pipeline/templates/bootstrap-tier1.md +14 -5
  42. package/bundled/dev-pipeline/templates/bootstrap-tier2.md +16 -6
  43. package/bundled/dev-pipeline/templates/bootstrap-tier3.md +16 -6
  44. package/bundled/dev-pipeline/templates/bugfix-bootstrap-prompt.md +1 -1
  45. package/bundled/dev-pipeline/templates/refactor-bootstrap-prompt.md +3 -3
  46. package/bundled/dev-pipeline/templates/sections/context-budget-rules.md +2 -0
  47. package/bundled/dev-pipeline/templates/sections/log-size-awareness.md +13 -69
  48. package/bundled/dev-pipeline/templates/sections/phase-context-snapshot-agent-suffix.md +15 -7
  49. package/bundled/dev-pipeline/templates/sections/phase-implement-agent.md +42 -29
  50. package/bundled/dev-pipeline/templates/sections/phase-implement-full.md +41 -39
  51. package/bundled/dev-pipeline/templates/sections/test-failure-recovery-agent.md +4 -0
  52. package/bundled/dev-pipeline/templates/sections/test-failure-recovery-lite.md +4 -0
  53. package/bundled/dev-pipeline/templates/session-status-schema.json +1 -1
  54. package/bundled/dev-pipeline/tests/conftest.py +1 -0
  55. package/bundled/dev-pipeline/tests/test_auto_skip.py +932 -0
  56. package/bundled/dev-pipeline/tests/test_generate_bootstrap_prompt.py +207 -0
  57. package/bundled/dev-pipeline/tests/test_generate_bugfix_prompt.py +100 -0
  58. package/bundled/dev-pipeline/tests/test_generate_refactor_prompt.py +43 -0
  59. package/bundled/dev-pipeline/tests/test_python_runner_parity.py +1138 -0
  60. package/bundled/dev-pipeline/tests/test_unified_cli.py +1045 -0
  61. package/bundled/skills/_metadata.json +1 -1
  62. package/bundled/skills/bugfix-pipeline-launcher/SKILL.md +29 -34
  63. package/bundled/skills/bugfix-pipeline-launcher/references/configuration.md +6 -5
  64. package/bundled/skills/feature-pipeline-launcher/SKILL.md +29 -35
  65. package/bundled/skills/feature-pipeline-launcher/references/configuration.md +7 -6
  66. package/bundled/skills/feature-workflow/SKILL.md +3 -6
  67. package/bundled/skills/recovery-workflow/SKILL.md +23 -32
  68. package/bundled/skills/refactor-pipeline-launcher/SKILL.md +29 -35
  69. package/bundled/skills/refactor-pipeline-launcher/references/configuration.md +7 -6
  70. package/bundled/skills/refactor-workflow/SKILL.md +3 -6
  71. package/bundled/templates/hooks/commit-intent.json +2 -2
  72. package/bundled/templates/hooks/diff-prizm-docs.py +226 -0
  73. package/bundled/templates/hooks/prizm-pre-commit.py +45 -0
  74. package/bundled/templates/hooks/validate-prizm-docs.py +240 -0
  75. package/package.json +1 -1
  76. package/src/config.js +33 -12
  77. package/src/index.js +3 -6
  78. package/src/manifest.js +3 -2
  79. package/src/metadata.js +7 -18
  80. package/src/prompts.js +0 -12
  81. package/src/runtimes.js +18 -11
  82. package/src/scaffold.js +133 -116
  83. package/src/upgrade.js +1 -1
  84. package/bundled/dev-pipeline/launch-bugfix-daemon.sh +0 -500
  85. package/bundled/dev-pipeline/launch-feature-daemon.sh +0 -657
  86. package/bundled/dev-pipeline/launch-refactor-daemon.sh +0 -502
  87. package/bundled/dev-pipeline/lib/branch.sh +0 -326
  88. package/bundled/dev-pipeline/lib/common.sh +0 -1257
  89. package/bundled/dev-pipeline/lib/heartbeat.sh +0 -469
  90. package/bundled/dev-pipeline/reset-bug.sh +0 -395
  91. package/bundled/dev-pipeline/reset-feature.sh +0 -406
  92. package/bundled/dev-pipeline/reset-refactor.sh +0 -393
  93. package/bundled/dev-pipeline/run-bugfix.sh +0 -1315
  94. package/bundled/dev-pipeline/run-feature.sh +0 -1602
  95. package/bundled/dev-pipeline/run-recovery.sh +0 -648
  96. package/bundled/dev-pipeline/run-refactor.sh +0 -1348
  97. package/bundled/dev-pipeline/scripts/monitor-log.sh +0 -104
  98. package/bundled/dev-pipeline/tests/test-path-resolution.sh +0 -100
  99. package/bundled/dev-pipeline-windows/.env.example +0 -36
  100. package/bundled/dev-pipeline-windows/README.md +0 -30
  101. package/bundled/dev-pipeline-windows/SCHEMA_ANALYSIS.md +0 -533
  102. package/bundled/dev-pipeline-windows/assets/feature-list-example.json +0 -146
  103. package/bundled/dev-pipeline-windows/assets/prizm-dev-team-integration.md +0 -137
  104. package/bundled/dev-pipeline-windows/launch-bugfix-daemon.ps1 +0 -9
  105. package/bundled/dev-pipeline-windows/launch-feature-daemon.ps1 +0 -9
  106. package/bundled/dev-pipeline-windows/launch-refactor-daemon.ps1 +0 -9
  107. package/bundled/dev-pipeline-windows/lib/branch.ps1 +0 -235
  108. package/bundled/dev-pipeline-windows/lib/common.ps1 +0 -829
  109. package/bundled/dev-pipeline-windows/lib/daemon.ps1 +0 -140
  110. package/bundled/dev-pipeline-windows/lib/pipeline.ps1 +0 -967
  111. package/bundled/dev-pipeline-windows/lib/reset.ps1 +0 -87
  112. package/bundled/dev-pipeline-windows/reset-bug.ps1 +0 -9
  113. package/bundled/dev-pipeline-windows/reset-feature.ps1 +0 -9
  114. package/bundled/dev-pipeline-windows/reset-refactor.ps1 +0 -9
  115. package/bundled/dev-pipeline-windows/run-bugfix.ps1 +0 -9
  116. package/bundled/dev-pipeline-windows/run-feature.ps1 +0 -9
  117. package/bundled/dev-pipeline-windows/run-recovery.ps1 +0 -179
  118. package/bundled/dev-pipeline-windows/run-refactor.ps1 +0 -9
  119. package/bundled/dev-pipeline-windows/scripts/check-session-status.py +0 -228
  120. package/bundled/dev-pipeline-windows/scripts/detect-stuck.py +0 -530
  121. package/bundled/dev-pipeline-windows/scripts/generate-bootstrap-prompt.py +0 -2282
  122. package/bundled/dev-pipeline-windows/scripts/generate-bugfix-prompt.py +0 -767
  123. package/bundled/dev-pipeline-windows/scripts/generate-recovery-prompt.py +0 -805
  124. package/bundled/dev-pipeline-windows/scripts/generate-refactor-prompt.py +0 -845
  125. package/bundled/dev-pipeline-windows/scripts/init-bugfix-pipeline.py +0 -316
  126. package/bundled/dev-pipeline-windows/scripts/init-dev-team.py +0 -134
  127. package/bundled/dev-pipeline-windows/scripts/init-pipeline.py +0 -382
  128. package/bundled/dev-pipeline-windows/scripts/init-refactor-pipeline.py +0 -399
  129. package/bundled/dev-pipeline-windows/scripts/monitor-log.ps1 +0 -102
  130. package/bundled/dev-pipeline-windows/scripts/parse-stream-progress.py +0 -1232
  131. package/bundled/dev-pipeline-windows/scripts/patch-completion-notes.py +0 -191
  132. package/bundled/dev-pipeline-windows/scripts/prizmkit-test-gate.py +0 -446
  133. package/bundled/dev-pipeline-windows/scripts/update-bug-status.py +0 -913
  134. package/bundled/dev-pipeline-windows/scripts/update-checkpoint.py +0 -173
  135. package/bundled/dev-pipeline-windows/scripts/update-feature-status.py +0 -1558
  136. package/bundled/dev-pipeline-windows/scripts/update-refactor-status.py +0 -1119
  137. package/bundled/dev-pipeline-windows/scripts/utils.py +0 -542
  138. package/bundled/dev-pipeline-windows/templates/agent-prompts/critic-plan-challenge.md +0 -7
  139. package/bundled/dev-pipeline-windows/templates/agent-prompts/dev-fix.md +0 -7
  140. package/bundled/dev-pipeline-windows/templates/agent-prompts/dev-implement.md +0 -65
  141. package/bundled/dev-pipeline-windows/templates/agent-prompts/dev-resume.md +0 -5
  142. package/bundled/dev-pipeline-windows/templates/agent-prompts/reviewer-review.md +0 -7
  143. package/bundled/dev-pipeline-windows/templates/bootstrap-prompt.md +0 -73
  144. package/bundled/dev-pipeline-windows/templates/bootstrap-tier1.md +0 -589
  145. package/bundled/dev-pipeline-windows/templates/bootstrap-tier2.md +0 -710
  146. package/bundled/dev-pipeline-windows/templates/bootstrap-tier3.md +0 -791
  147. package/bundled/dev-pipeline-windows/templates/bug-fix-list-schema.json +0 -263
  148. package/bundled/dev-pipeline-windows/templates/bugfix-bootstrap-prompt.md +0 -326
  149. package/bundled/dev-pipeline-windows/templates/feature-list-schema.json +0 -237
  150. package/bundled/dev-pipeline-windows/templates/refactor-bootstrap-prompt.md +0 -340
  151. package/bundled/dev-pipeline-windows/templates/refactor-list-schema.json +0 -270
  152. package/bundled/dev-pipeline-windows/templates/sections/ac-verification-checklist.md +0 -7
  153. package/bundled/dev-pipeline-windows/templates/sections/checkpoint-system.md +0 -91
  154. package/bundled/dev-pipeline-windows/templates/sections/context-budget-rules.md +0 -34
  155. package/bundled/dev-pipeline-windows/templates/sections/critical-paths-agent.md +0 -10
  156. package/bundled/dev-pipeline-windows/templates/sections/critical-paths-full.md +0 -12
  157. package/bundled/dev-pipeline-windows/templates/sections/critical-paths-lite.md +0 -7
  158. package/bundled/dev-pipeline-windows/templates/sections/directory-convention-agent.md +0 -8
  159. package/bundled/dev-pipeline-windows/templates/sections/directory-convention-full.md +0 -9
  160. package/bundled/dev-pipeline-windows/templates/sections/directory-convention-lite.md +0 -6
  161. package/bundled/dev-pipeline-windows/templates/sections/failure-capture.md +0 -21
  162. package/bundled/dev-pipeline-windows/templates/sections/feature-context.md +0 -21
  163. package/bundled/dev-pipeline-windows/templates/sections/log-size-awareness.md +0 -78
  164. package/bundled/dev-pipeline-windows/templates/sections/phase-browser-verification-auto.md +0 -283
  165. package/bundled/dev-pipeline-windows/templates/sections/phase-browser-verification-opencli.md +0 -112
  166. package/bundled/dev-pipeline-windows/templates/sections/phase-browser-verification.md +0 -168
  167. package/bundled/dev-pipeline-windows/templates/sections/phase-commit-full.md +0 -82
  168. package/bundled/dev-pipeline-windows/templates/sections/phase-commit.md +0 -75
  169. package/bundled/dev-pipeline-windows/templates/sections/phase-context-snapshot-agent-suffix.md +0 -23
  170. package/bundled/dev-pipeline-windows/templates/sections/phase-context-snapshot-base.md +0 -14
  171. package/bundled/dev-pipeline-windows/templates/sections/phase-context-snapshot-lite-suffix.md +0 -19
  172. package/bundled/dev-pipeline-windows/templates/sections/phase-critic-plan-full.md +0 -63
  173. package/bundled/dev-pipeline-windows/templates/sections/phase-critic-plan.md +0 -42
  174. package/bundled/dev-pipeline-windows/templates/sections/phase-implement-agent.md +0 -44
  175. package/bundled/dev-pipeline-windows/templates/sections/phase-implement-full.md +0 -59
  176. package/bundled/dev-pipeline-windows/templates/sections/phase-implement-lite.md +0 -39
  177. package/bundled/dev-pipeline-windows/templates/sections/phase-plan-agent.md +0 -27
  178. package/bundled/dev-pipeline-windows/templates/sections/phase-plan-lite.md +0 -27
  179. package/bundled/dev-pipeline-windows/templates/sections/phase-prizmkit-test.md +0 -39
  180. package/bundled/dev-pipeline-windows/templates/sections/phase-review-agent.md +0 -35
  181. package/bundled/dev-pipeline-windows/templates/sections/phase-review-full.md +0 -35
  182. package/bundled/dev-pipeline-windows/templates/sections/phase-specify-plan-full.md +0 -73
  183. package/bundled/dev-pipeline-windows/templates/sections/phase0-init.md +0 -13
  184. package/bundled/dev-pipeline-windows/templates/sections/phase0-test-baseline.md +0 -21
  185. package/bundled/dev-pipeline-windows/templates/sections/session-context.md +0 -5
  186. package/bundled/dev-pipeline-windows/templates/sections/subagent-timeout-recovery.md +0 -6
  187. package/bundled/dev-pipeline-windows/templates/sections/task-contract.md +0 -34
  188. package/bundled/dev-pipeline-windows/templates/sections/test-failure-recovery-agent.md +0 -48
  189. package/bundled/dev-pipeline-windows/templates/sections/test-failure-recovery-lite.md +0 -48
  190. package/bundled/dev-pipeline-windows/templates/session-status-schema.json +0 -83
  191. package/bundled/skills-windows/app-planner/SKILL.md +0 -296
  192. package/bundled/skills-windows/app-planner/assets/app-design-guide.md +0 -101
  193. package/bundled/skills-windows/app-planner/references/architecture-decisions.md +0 -52
  194. package/bundled/skills-windows/app-planner/references/brainstorm-guide.md +0 -101
  195. package/bundled/skills-windows/app-planner/references/frontend-design-guide.md +0 -71
  196. package/bundled/skills-windows/app-planner/references/infrastructure-convention-discovery.md +0 -108
  197. package/bundled/skills-windows/app-planner/references/project-brief-guide.md +0 -82
  198. package/bundled/skills-windows/app-planner/references/project-conventions-discovery.md +0 -59
  199. package/bundled/skills-windows/app-planner/references/project-state-detection.md +0 -90
  200. package/bundled/skills-windows/app-planner/references/red-team-checklist.md +0 -40
  201. package/bundled/skills-windows/app-planner/references/rules/backend/derivation-rules.md +0 -619
  202. package/bundled/skills-windows/app-planner/references/rules/backend/fixed-rules.md +0 -285
  203. package/bundled/skills-windows/app-planner/references/rules/backend/question-bank.md +0 -249
  204. package/bundled/skills-windows/app-planner/references/rules/backend/question-manifest.json +0 -46
  205. package/bundled/skills-windows/app-planner/references/rules/backend/template.md +0 -173
  206. package/bundled/skills-windows/app-planner/references/rules/database/derivation-rules.md +0 -382
  207. package/bundled/skills-windows/app-planner/references/rules/database/fixed-rules.md +0 -211
  208. package/bundled/skills-windows/app-planner/references/rules/database/question-bank.md +0 -184
  209. package/bundled/skills-windows/app-planner/references/rules/database/question-manifest.json +0 -39
  210. package/bundled/skills-windows/app-planner/references/rules/database/template.md +0 -158
  211. package/bundled/skills-windows/app-planner/references/rules/frontend/derivation-rules.md +0 -820
  212. package/bundled/skills-windows/app-planner/references/rules/frontend/fixed-rules.md +0 -188
  213. package/bundled/skills-windows/app-planner/references/rules/frontend/question-bank.md +0 -319
  214. package/bundled/skills-windows/app-planner/references/rules/frontend/question-manifest.json +0 -51
  215. package/bundled/skills-windows/app-planner/references/rules/frontend/template.md +0 -339
  216. package/bundled/skills-windows/app-planner/references/rules/mobile/derivation-rules.md +0 -649
  217. package/bundled/skills-windows/app-planner/references/rules/mobile/fixed-rules.md +0 -290
  218. package/bundled/skills-windows/app-planner/references/rules/mobile/question-bank.md +0 -232
  219. package/bundled/skills-windows/app-planner/references/rules/mobile/question-manifest.json +0 -47
  220. package/bundled/skills-windows/app-planner/references/rules/mobile/template.md +0 -175
  221. package/bundled/skills-windows/app-planner/references/rules-configuration.md +0 -46
  222. package/bundled/skills-windows/bug-fix-workflow/SKILL.md +0 -379
  223. package/bundled/skills-windows/bug-fix-workflow/references/bug-diagnosis.md +0 -41
  224. package/bundled/skills-windows/bug-planner/SKILL.md +0 -402
  225. package/bundled/skills-windows/bug-planner/assets/bug-confirmation-template.md +0 -43
  226. package/bundled/skills-windows/bug-planner/references/critic-and-verification.md +0 -44
  227. package/bundled/skills-windows/bug-planner/references/error-recovery.md +0 -73
  228. package/bundled/skills-windows/bug-planner/references/input-formats.md +0 -53
  229. package/bundled/skills-windows/bug-planner/references/schema-validation.md +0 -25
  230. package/bundled/skills-windows/bug-planner/references/severity-rules.md +0 -16
  231. package/bundled/skills-windows/bug-planner/scripts/validate-bug-list.py +0 -322
  232. package/bundled/skills-windows/bugfix-pipeline-launcher/SKILL.md +0 -304
  233. package/bundled/skills-windows/bugfix-pipeline-launcher/references/configuration.md +0 -84
  234. package/bundled/skills-windows/feature-pipeline-launcher/SKILL.md +0 -381
  235. package/bundled/skills-windows/feature-pipeline-launcher/references/configuration.md +0 -67
  236. package/bundled/skills-windows/feature-pipeline-launcher/scripts/preflight-check.py +0 -462
  237. package/bundled/skills-windows/feature-planner/SKILL.md +0 -397
  238. package/bundled/skills-windows/feature-planner/assets/evaluation-guide.md +0 -64
  239. package/bundled/skills-windows/feature-planner/assets/planning-guide.md +0 -214
  240. package/bundled/skills-windows/feature-planner/references/browser-interaction.md +0 -59
  241. package/bundled/skills-windows/feature-planner/references/completeness-review.md +0 -57
  242. package/bundled/skills-windows/feature-planner/references/decomposition-patterns.md +0 -75
  243. package/bundled/skills-windows/feature-planner/references/error-recovery.md +0 -90
  244. package/bundled/skills-windows/feature-planner/references/incremental-feature-planning.md +0 -112
  245. package/bundled/skills-windows/feature-planner/references/new-project-planning.md +0 -85
  246. package/bundled/skills-windows/feature-planner/scripts/validate-and-generate.py +0 -1020
  247. package/bundled/skills-windows/feature-workflow/SKILL.md +0 -374
  248. package/bundled/skills-windows/feature-workflow/references/brainstorm-guide.md +0 -137
  249. package/bundled/skills-windows/prizm-kit/SKILL.md +0 -93
  250. package/bundled/skills-windows/prizmkit-code-review/SKILL.md +0 -161
  251. package/bundled/skills-windows/prizmkit-code-review/references/dev-agent-prompt.md +0 -30
  252. package/bundled/skills-windows/prizmkit-code-review/references/review-report-template.md +0 -31
  253. package/bundled/skills-windows/prizmkit-code-review/references/reviewer-agent-prompt.md +0 -66
  254. package/bundled/skills-windows/prizmkit-code-review/scripts/check_loop.py +0 -186
  255. package/bundled/skills-windows/prizmkit-committer/SKILL.md +0 -89
  256. package/bundled/skills-windows/prizmkit-deploy/SKILL.md +0 -444
  257. package/bundled/skills-windows/prizmkit-deploy/references/ci-cd-workflows.md +0 -115
  258. package/bundled/skills-windows/prizmkit-deploy/references/cloud-platform-deploy.md +0 -93
  259. package/bundled/skills-windows/prizmkit-deploy/references/data-safety-examples.md +0 -120
  260. package/bundled/skills-windows/prizmkit-deploy/references/database-setup.md +0 -46
  261. package/bundled/skills-windows/prizmkit-deploy/references/deploy-config-schema.md +0 -148
  262. package/bundled/skills-windows/prizmkit-deploy/references/deploy-history-schema.md +0 -62
  263. package/bundled/skills-windows/prizmkit-deploy/references/deployment-modes.md +0 -50
  264. package/bundled/skills-windows/prizmkit-deploy/references/direct-upload.md +0 -26
  265. package/bundled/skills-windows/prizmkit-deploy/references/dns-setup.md +0 -42
  266. package/bundled/skills-windows/prizmkit-deploy/references/docker-deploy.md +0 -31
  267. package/bundled/skills-windows/prizmkit-deploy/references/firewall-setup.md +0 -37
  268. package/bundled/skills-windows/prizmkit-deploy/references/live-validation-notes.md +0 -21
  269. package/bundled/skills-windows/prizmkit-deploy/references/nginx-blue-green.md +0 -59
  270. package/bundled/skills-windows/prizmkit-deploy/references/ssh-bootstrap-flow.md +0 -49
  271. package/bundled/skills-windows/prizmkit-deploy/references/ssh-execution-flow.md +0 -41
  272. package/bundled/skills-windows/prizmkit-deploy/references/ssh-takeover.md +0 -20
  273. package/bundled/skills-windows/prizmkit-deploy/references/ssl-setup.md +0 -56
  274. package/bundled/skills-windows/prizmkit-implement/SKILL.md +0 -71
  275. package/bundled/skills-windows/prizmkit-init/SKILL.md +0 -356
  276. package/bundled/skills-windows/prizmkit-init/assets/project-brief-template.md +0 -82
  277. package/bundled/skills-windows/prizmkit-init/references/config-schema.md +0 -70
  278. package/bundled/skills-windows/prizmkit-init/references/rules/layer-detection.md +0 -41
  279. package/bundled/skills-windows/prizmkit-init/references/tech-stack-catalog.md +0 -13
  280. package/bundled/skills-windows/prizmkit-init/references/update-supplement.md +0 -9
  281. package/bundled/skills-windows/prizmkit-plan/SKILL.md +0 -102
  282. package/bundled/skills-windows/prizmkit-plan/assets/plan-template.md +0 -115
  283. package/bundled/skills-windows/prizmkit-plan/assets/spec-template.md +0 -73
  284. package/bundled/skills-windows/prizmkit-plan/references/clarify-guide.md +0 -67
  285. package/bundled/skills-windows/prizmkit-plan/references/examples.md +0 -85
  286. package/bundled/skills-windows/prizmkit-plan/references/verification-checklist.md +0 -60
  287. package/bundled/skills-windows/prizmkit-prizm-docs/SKILL.md +0 -129
  288. package/bundled/skills-windows/prizmkit-prizm-docs/assets/prizm-docs-format.md +0 -613
  289. package/bundled/skills-windows/prizmkit-prizm-docs/references/op-init.md +0 -45
  290. package/bundled/skills-windows/prizmkit-prizm-docs/references/op-rebuild.md +0 -15
  291. package/bundled/skills-windows/prizmkit-prizm-docs/references/op-status.md +0 -14
  292. package/bundled/skills-windows/prizmkit-prizm-docs/references/op-update.md +0 -19
  293. package/bundled/skills-windows/prizmkit-prizm-docs/references/op-validate.md +0 -17
  294. package/bundled/skills-windows/prizmkit-retrospective/SKILL.md +0 -87
  295. package/bundled/skills-windows/prizmkit-retrospective/references/knowledge-injection-steps.md +0 -50
  296. package/bundled/skills-windows/prizmkit-retrospective/references/structural-sync-steps.md +0 -43
  297. package/bundled/skills-windows/prizmkit-test/SKILL.md +0 -227
  298. package/bundled/skills-windows/prizmkit-test/references/boundary-coverage-protocol.md +0 -220
  299. package/bundled/skills-windows/prizmkit-test/references/examples.md +0 -143
  300. package/bundled/skills-windows/prizmkit-test/references/service-boundary-test-catalog.md +0 -225
  301. package/bundled/skills-windows/prizmkit-test/references/test-generation-steps.md +0 -109
  302. package/bundled/skills-windows/prizmkit-test/references/test-report-template.md +0 -111
  303. package/bundled/skills-windows/prizmkit-test/scripts/validate_boundary_report.py +0 -347
  304. package/bundled/skills-windows/recovery-workflow/SKILL.md +0 -355
  305. package/bundled/skills-windows/recovery-workflow/evals/evals.json +0 -46
  306. package/bundled/skills-windows/recovery-workflow/references/detection.md +0 -58
  307. package/bundled/skills-windows/recovery-workflow/scripts/detect-recovery-state.py +0 -544
  308. package/bundled/skills-windows/refactor-pipeline-launcher/SKILL.md +0 -346
  309. package/bundled/skills-windows/refactor-pipeline-launcher/references/configuration.md +0 -72
  310. package/bundled/skills-windows/refactor-planner/SKILL.md +0 -398
  311. package/bundled/skills-windows/refactor-planner/assets/planning-guide.md +0 -292
  312. package/bundled/skills-windows/refactor-planner/references/behavior-preservation.md +0 -301
  313. package/bundled/skills-windows/refactor-planner/references/fast-path.md +0 -59
  314. package/bundled/skills-windows/refactor-planner/references/planning-phases.md +0 -135
  315. package/bundled/skills-windows/refactor-planner/references/refactor-scoping-guide.md +0 -221
  316. package/bundled/skills-windows/refactor-planner/scripts/validate-and-generate-refactor.py +0 -858
  317. package/bundled/skills-windows/refactor-workflow/SKILL.md +0 -343
  318. package/bundled/skills-windows/refactor-workflow/references/brainstorm-guide.md +0 -116
  319. package/bundled/templates/hooks/diff-prizm-docs.sh +0 -158
  320. package/bundled/templates/hooks/prizm-pre-commit.sh +0 -108
  321. 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
+ )