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