blun-king-cli 9.1.587 → 9.1.588

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 (436) hide show
  1. package/CHANGELOG.md +11 -185
  2. package/LIESMICH.txt +51 -13
  3. package/README.md +44 -47
  4. package/agent-spine-plugin/.codex-plugin/plugin.json +16 -4
  5. package/agent-spine-plugin/CHANGELOG.md +37 -5
  6. package/agent-spine-plugin/README.md +3 -3
  7. package/agent-spine-plugin/blun.plugin.json +45 -10
  8. package/agent-spine-plugin/docs/artifact-evaluation.md +93 -0
  9. package/agent-spine-plugin/docs/host-integration.md +42 -27
  10. package/agent-spine-plugin/docs/preflight-recall.md +4 -2
  11. package/agent-spine-plugin/docs/session-timeline.md +97 -236
  12. package/agent-spine-plugin/docs/world-model.md +25 -0
  13. package/agent-spine-plugin/hooks/codex.json +1 -1
  14. package/agent-spine-plugin/hooks/hooks.json +1 -1
  15. package/agent-spine-plugin/package.json +1 -3
  16. package/agent-spine-plugin/scripts/check-hosts.js +3 -3
  17. package/agent-spine-plugin/scripts/release-check.js +10 -5
  18. package/agent-spine-plugin/scripts/run-checks.js +4 -1
  19. package/agent-spine-plugin/scripts/run-tests-hermetic.js +32 -6
  20. package/agent-spine-plugin/src/cli-learning.js +15 -0
  21. package/agent-spine-plugin/src/cli.js +2 -0
  22. package/agent-spine-plugin/src/hook.js +32 -32
  23. package/agent-spine-plugin/src/lib/action-lesson-recall.js +73 -8
  24. package/agent-spine-plugin/src/lib/briefing.js +146 -36
  25. package/agent-spine-plugin/src/lib/channel-continuity.js +19 -0
  26. package/agent-spine-plugin/src/lib/delivery-agent-usage.js +14 -7
  27. package/agent-spine-plugin/src/lib/gateway-group-response.js +128 -0
  28. package/agent-spine-plugin/src/lib/gateway-runs.js +24 -15
  29. package/agent-spine-plugin/src/lib/hook-briefing-use.js +13 -3
  30. package/agent-spine-plugin/src/lib/hook-context.js +16 -3
  31. package/agent-spine-plugin/src/lib/hook-output.js +129 -5
  32. package/agent-spine-plugin/src/lib/hook-timeline.js +5 -3
  33. package/agent-spine-plugin/src/lib/indexed-memory.js +2 -2
  34. package/agent-spine-plugin/src/lib/learning-artifact-evaluator.js +114 -0
  35. package/agent-spine-plugin/src/lib/learning-context.js +11 -4
  36. package/agent-spine-plugin/src/lib/learning-measurements.js +2 -2
  37. package/agent-spine-plugin/src/lib/mcp-runtime.js +89 -3
  38. package/agent-spine-plugin/src/lib/mcp-source-context.js +12 -2
  39. package/agent-spine-plugin/src/lib/mcp-timeline-tools.js +91 -8
  40. package/agent-spine-plugin/src/lib/mcp-world-tools.js +2 -2
  41. package/agent-spine-plugin/src/lib/owned-file-lock.js +20 -1
  42. package/agent-spine-plugin/src/lib/persona-runtime.js +2 -2
  43. package/agent-spine-plugin/src/lib/preflight-delivery-id.js +27 -0
  44. package/agent-spine-plugin/src/lib/preflight.js +4 -4
  45. package/agent-spine-plugin/src/lib/session-timeline-codex.js +15 -0
  46. package/agent-spine-plugin/src/lib/session-timeline-contract.js +12 -4
  47. package/agent-spine-plugin/src/lib/session-timeline-event-extract.js +36 -7
  48. package/agent-spine-plugin/src/lib/session-timeline-host-origin.js +13 -10
  49. package/agent-spine-plugin/src/lib/session-timeline-invocation.js +1 -1
  50. package/agent-spine-plugin/src/lib/session-timeline-king.js +14 -0
  51. package/agent-spine-plugin/src/lib/session-timeline-prior.js +18 -12
  52. package/agent-spine-plugin/src/lib/session-timeline-provider.js +5 -0
  53. package/agent-spine-plugin/src/lib/session-timeline-query.js +2 -0
  54. package/agent-spine-plugin/src/lib/session-timeline-results.js +35 -10
  55. package/agent-spine-plugin/src/lib/session-timeline-source-open.js +30 -0
  56. package/agent-spine-plugin/src/lib/session-timeline.js +122 -75
  57. package/agent-spine-plugin/src/lib/source-roots.js +3 -2
  58. package/agent-spine-plugin/src/lib/task-knowledge-context.js +22 -1
  59. package/agent-spine-plugin/src/lib/timeline-continuation-update.js +100 -0
  60. package/agent-spine-plugin/src/lib/timeline-tool-guard.js +30 -7
  61. package/agent-spine-plugin/src/lib/timeline-user-feedback.js +217 -0
  62. package/agent-spine-plugin/src/lib/timeline-world-capture.js +233 -0
  63. package/agent-spine-plugin/src/lib/world-knowledge.js +59 -2
  64. package/agent-spine-plugin/src/lib/world-model.js +64 -9
  65. package/agent-spine-plugin/src/worker.js +13 -1
  66. package/bin/blun.js +43 -28
  67. package/bin/core-bootstrap.js +5 -4
  68. package/bin/king.js +43 -28
  69. package/bin/launcher-mode.js +1 -10
  70. package/bin/launcher-runtime.js +128 -295
  71. package/bin/managed-node.js +0 -0
  72. package/bin/managed-plugin-selection.cjs +0 -1
  73. package/bin/native-module-repair.js +0 -0
  74. package/bin/node-runtime.js +0 -0
  75. package/bin/node-version.js +0 -0
  76. package/bin/plugin-bootstrap.js +56 -120
  77. package/bin/private-paths.js +11 -34
  78. package/bin/standard-tools-bootstrap.js +34 -114
  79. package/bin/turn-thinking-policy.cjs +3 -11
  80. package/bin/update-copy.js +200 -0
  81. package/bin/update-lease.js +0 -0
  82. package/bin/update-notice.js +136 -289
  83. package/bin/verify-agent-behavior.cjs +122 -0
  84. package/bin/verify-agent-components.cjs +104 -0
  85. package/bin/verify-bundled-agent-sources.cjs +57 -0
  86. package/blun.mjs +143076 -135288
  87. package/bundled-agent-sources.json +701 -0
  88. package/package.json +12 -15
  89. package/standard-skills/translate-native/README.md +1293 -0
  90. package/standard-skills/translate-native/SKILL.md +172 -22
  91. package/standard-skills/translate-native/VERSION +1 -1
  92. package/standard-skills/translate-native/agents/openai.yaml +18 -0
  93. package/standard-skills/translate-native/assets/icon.svg +8 -0
  94. package/standard-skills/translate-native/docs/BLUN_CODE_INTEGRATION.md +76 -0
  95. package/standard-skills/translate-native/docs/PREMORTEM.md +489 -0
  96. package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION.md +2035 -0
  97. package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_API.md +1302 -0
  98. package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_EVIDENCE_HTTP.md +136 -0
  99. package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_HEALTH_HTTP.md +130 -0
  100. package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_HTTP_PROVIDER.md +175 -0
  101. package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_RECEIPT_VERIFIER_HTTP.md +86 -0
  102. package/standard-skills/translate-native/integrations/AGENT_RULES.md +32 -0
  103. package/standard-skills/translate-native/integrations/adapters/blun-code-language-guard.js +514 -0
  104. package/standard-skills/translate-native/integrations/adapters/node-language-guard.js +230 -0
  105. package/standard-skills/translate-native/integrations/audit_log.py +327 -0
  106. package/standard-skills/translate-native/integrations/claude_language_hook.js +1536 -0
  107. package/standard-skills/translate-native/integrations/commercial_localization_profile.py +42 -0
  108. package/standard-skills/translate-native/integrations/delivery-policy.example.json +28 -0
  109. package/standard-skills/translate-native/integrations/enforced_delivery.py +543 -0
  110. package/standard-skills/translate-native/integrations/guard_service.py +435 -0
  111. package/standard-skills/translate-native/integrations/language_gateway.py +67 -0
  112. package/standard-skills/translate-native/integrations/mcp_auth_headers.py +198 -0
  113. package/standard-skills/translate-native/integrations/mcp_http_gateway.py +429 -0
  114. package/standard-skills/translate-native/integrations/non_language_html_entities.js +1485 -0
  115. package/standard-skills/translate-native/integrations/pre_output_guard.py +65 -0
  116. package/standard-skills/translate-native/integrations/task_router.py +101 -0
  117. package/standard-skills/translate-native/integrations/website_localization.py +401 -0
  118. package/standard-skills/translate-native/integrations/website_localization_api.py +581 -0
  119. package/standard-skills/translate-native/integrations/website_localization_benchmark.py +1885 -0
  120. package/standard-skills/translate-native/integrations/website_localization_benchmark_campaign.py +1772 -0
  121. package/standard-skills/translate-native/integrations/website_localization_benchmark_candidate.py +506 -0
  122. package/standard-skills/translate-native/integrations/website_localization_benchmark_http.py +400 -0
  123. package/standard-skills/translate-native/integrations/website_localization_benchmark_review_store.py +781 -0
  124. package/standard-skills/translate-native/integrations/website_localization_benchmark_reviewer_http.py +500 -0
  125. package/standard-skills/translate-native/integrations/website_localization_benchmark_runtime.py +1107 -0
  126. package/standard-skills/translate-native/integrations/website_localization_benchmark_suite.py +463 -0
  127. package/standard-skills/translate-native/integrations/website_localization_cms.py +2835 -0
  128. package/standard-skills/translate-native/integrations/website_localization_cms_client.py +875 -0
  129. package/standard-skills/translate-native/integrations/website_localization_cms_dispatch.py +805 -0
  130. package/standard-skills/translate-native/integrations/website_localization_cms_http.py +588 -0
  131. package/standard-skills/translate-native/integrations/website_localization_cms_lifecycle_monitor.py +991 -0
  132. package/standard-skills/translate-native/integrations/website_localization_cms_receiver.py +1441 -0
  133. package/standard-skills/translate-native/integrations/website_localization_cms_receiver_runtime.py +414 -0
  134. package/standard-skills/translate-native/integrations/website_localization_cms_receiver_store.py +1073 -0
  135. package/standard-skills/translate-native/integrations/website_localization_cms_removal_dispatch.py +865 -0
  136. package/standard-skills/translate-native/integrations/website_localization_cms_source_client.py +583 -0
  137. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery.py +964 -0
  138. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_runtime.py +665 -0
  139. package/standard-skills/translate-native/integrations/website_localization_cms_source_http.py +1153 -0
  140. package/standard-skills/translate-native/integrations/website_localization_cms_source_runtime.py +675 -0
  141. package/standard-skills/translate-native/integrations/website_localization_cms_source_service.py +1125 -0
  142. package/standard-skills/translate-native/integrations/website_localization_cms_terminal_notification.py +674 -0
  143. package/standard-skills/translate-native/integrations/website_localization_cms_terminal_notification_http.py +444 -0
  144. package/standard-skills/translate-native/integrations/website_localization_cms_terminal_notification_receiver.py +1469 -0
  145. package/standard-skills/translate-native/integrations/website_localization_cms_terminal_notification_receiver_runtime.py +1142 -0
  146. package/standard-skills/translate-native/integrations/website_localization_cms_terminal_processing_monitor.py +634 -0
  147. package/standard-skills/translate-native/integrations/website_localization_cms_terminal_receiver_client.py +804 -0
  148. package/standard-skills/translate-native/integrations/website_localization_deepl_baseline.py +922 -0
  149. package/standard-skills/translate-native/integrations/website_localization_evidence_http.py +482 -0
  150. package/standard-skills/translate-native/integrations/website_localization_health.py +1541 -0
  151. package/standard-skills/translate-native/integrations/website_localization_health_http.py +372 -0
  152. package/standard-skills/translate-native/integrations/website_localization_http_provider.py +297 -0
  153. package/standard-skills/translate-native/integrations/website_localization_native_reference_http.py +479 -0
  154. package/standard-skills/translate-native/integrations/website_localization_native_reference_intake.py +363 -0
  155. package/standard-skills/translate-native/integrations/website_localization_native_reference_queue.py +1449 -0
  156. package/standard-skills/translate-native/integrations/website_localization_native_reference_store.py +420 -0
  157. package/standard-skills/translate-native/integrations/website_localization_quality_profiles.py +235 -0
  158. package/standard-skills/translate-native/integrations/website_localization_queue.py +671 -0
  159. package/standard-skills/translate-native/integrations/website_localization_receipt_verifier_http.py +516 -0
  160. package/standard-skills/translate-native/integrations/website_localization_release.py +928 -0
  161. package/standard-skills/translate-native/integrations/website_localization_release_coordinator.py +1008 -0
  162. package/standard-skills/translate-native/integrations/website_localization_runner.py +276 -0
  163. package/standard-skills/translate-native/integrations/website_localization_runtime.py +862 -0
  164. package/standard-skills/translate-native/integrations/website_localization_service.py +350 -0
  165. package/standard-skills/translate-native/integrations/website_localization_supervisor.py +511 -0
  166. package/standard-skills/translate-native/integrations/website_localization_worker.py +663 -0
  167. package/standard-skills/translate-native/provenance.json +3 -4
  168. package/standard-skills/translate-native/references/commercial-localization.md +177 -0
  169. package/standard-skills/translate-native/scripts/blun_language_guard.py +7 -1
  170. package/standard-skills/translate-native/scripts/check_commercial_review.py +80 -0
  171. package/standard-skills/translate-native/scripts/commercial_localization_profile.py +333 -0
  172. package/standard-tools/language-guard/LICENSE +21 -0
  173. package/standard-tools/language-guard/VERSION +1 -0
  174. package/standard-tools/language-guard/blun_language_guard.py +7 -1
  175. package/standard-tools/language-guard/check_commercial_review.py +80 -0
  176. package/standard-tools/language-guard/commercial_localization_profile.py +333 -0
  177. package/standard-tools/language-guard/language_gateway.py +62 -0
  178. package/standard-tools/language-guard/pre_output_guard.py +64 -0
  179. package/standard-tools/language-guard/provenance.json +4 -11
  180. package/standard-tools/manifest.json +34 -11
  181. package/telegram-plugin/commands/access.md +2 -10
  182. package/telegram-plugin/dist/bridge.mjs +64041 -687
  183. package/telegram-plugin/dist/mcp-server.mjs +72810 -9027
  184. package/telegram-plugin/dist/noise.mjs +28 -63511
  185. package/agent-spine-plugin/CONTRIBUTING.md +0 -52
  186. package/agent-spine-plugin/SECURITY.md +0 -47
  187. package/agent-spine-plugin/docs/assignment-continuation.md +0 -48
  188. package/agent-spine-plugin/docs/releasing.md +0 -85
  189. package/agent-spine-plugin/docs/structured-completion.md +0 -67
  190. package/bin/abort-listener-policy.cjs +0 -43
  191. package/bin/active-steer-priority-policy.cjs +0 -24
  192. package/bin/agent-api-http-adapter.mjs +0 -446
  193. package/bin/agent-api-private-http-server.mjs +0 -288
  194. package/bin/agent-api-runtime.mjs +0 -252
  195. package/bin/agent-api-service-environment.mjs +0 -236
  196. package/bin/agent-api-service-host.mjs +0 -209
  197. package/bin/agent-api-service-process.mjs +0 -171
  198. package/bin/agent-api-session-registry.mjs +0 -428
  199. package/bin/agent-api-tool-broker.cjs +0 -248
  200. package/bin/agent-api-turn-controller.mjs +0 -461
  201. package/bin/agent-api-usage-journal.cjs +0 -259
  202. package/bin/agent-resume-snapshot.cjs +0 -241
  203. package/bin/agentspine-king-goal-inbox.mjs +0 -111
  204. package/bin/agentspine-king-goal-intake.mjs +0 -106
  205. package/bin/approval-rejection-stop.cjs +0 -15
  206. package/bin/assistant-message-offload-policy.cjs +0 -284
  207. package/bin/baseline-skill-performance-policy.cjs +0 -39
  208. package/bin/bash-search-scope-policy.cjs +0 -49
  209. package/bin/codebase-search-runtime.cjs +0 -23
  210. package/bin/cognitive-action-checkpoint.cjs +0 -1104
  211. package/bin/cognitive-attention-delivery.cjs +0 -76
  212. package/bin/cognitive-attention-policy.cjs +0 -143
  213. package/bin/cognitive-attention-runtime.cjs +0 -91
  214. package/bin/cognitive-context-projection.cjs +0 -73
  215. package/bin/cognitive-cross-portal-acceptance.cjs +0 -443
  216. package/bin/cognitive-effective-view.cjs +0 -77
  217. package/bin/cognitive-focus-projection.cjs +0 -206
  218. package/bin/cognitive-focus-scope.cjs +0 -37
  219. package/bin/cognitive-goal-autostart-policy.cjs +0 -72
  220. package/bin/cognitive-goal-time-trigger-controller.cjs +0 -146
  221. package/bin/cognitive-memory-adapter.cjs +0 -282
  222. package/bin/cognitive-memory-command.cjs +0 -293
  223. package/bin/cognitive-memory-provider.cjs +0 -92
  224. package/bin/cognitive-salience-policy.cjs +0 -159
  225. package/bin/cognitive-state-store.cjs +0 -508
  226. package/bin/cognitive-turn-lifecycle.cjs +0 -624
  227. package/bin/cognitive-work-focus.cjs +0 -180
  228. package/bin/compaction-history-archive.cjs +0 -166
  229. package/bin/compaction-history-startup.cjs +0 -50
  230. package/bin/compaction-model-policy.cjs +0 -31
  231. package/bin/compaction-stage-policy.cjs +0 -21
  232. package/bin/compaction-transaction-policy.cjs +0 -122
  233. package/bin/config-write-dedup-policy.cjs +0 -27
  234. package/bin/context-budget-ledger.cjs +0 -31
  235. package/bin/context-doctor-policy.cjs +0 -70
  236. package/bin/context-insight-policy.cjs +0 -36
  237. package/bin/context-performance-policy.cjs +0 -19
  238. package/bin/context-pressure-policy.cjs +0 -20
  239. package/bin/cron-run-output.cjs +0 -45
  240. package/bin/cron-run-store.cjs +0 -145
  241. package/bin/curiosity-scout-policy.cjs +0 -49
  242. package/bin/default-model-output-budget-policy.cjs +0 -28
  243. package/bin/durable-task-resume-policy.cjs +0 -130
  244. package/bin/durable-task-resume-runtime.cjs +0 -117
  245. package/bin/durable-task-resume-store.cjs +0 -88
  246. package/bin/editable-tool-approval-policy.cjs +0 -540
  247. package/bin/editable-tool-approval-runtime.cjs +0 -99
  248. package/bin/effective-system-prompt-cache-policy.cjs +0 -33
  249. package/bin/error-memory-performance-policy.cjs +0 -113
  250. package/bin/file-observation-policy.cjs +0 -133
  251. package/bin/foreground-output-capture-policy.cjs +0 -41
  252. package/bin/generated-source-health.cjs +0 -142
  253. package/bin/glob-pattern-policy.cjs +0 -13
  254. package/bin/goal-completion-evidence-policy.cjs +0 -120
  255. package/bin/grep-output-limit-policy.cjs +0 -39
  256. package/bin/historical-media-projection-policy.cjs +0 -48
  257. package/bin/history-offload-pressure-policy.cjs +0 -33
  258. package/bin/html-to-research-markdown.cjs +0 -147
  259. package/bin/identity-context-policy.cjs +0 -764
  260. package/bin/identity-journal-policy.cjs +0 -107
  261. package/bin/input-draft-persistence.cjs +0 -77
  262. package/bin/king-tui-function-contract.json +0 -33
  263. package/bin/launcher-restart-policy.cjs +0 -150
  264. package/bin/live-response-repetition-guard.cjs +0 -196
  265. package/bin/llm-config-log-dedup-policy.cjs +0 -76
  266. package/bin/loop-event-record-policy.cjs +0 -174
  267. package/bin/managed-context-startup-policy.cjs +0 -27
  268. package/bin/media-activity-layout-policy.cjs +0 -34
  269. package/bin/media-auto-retrieval-policy.cjs +0 -90
  270. package/bin/media-result-policy.cjs +0 -59
  271. package/bin/micro-compaction-policy.cjs +0 -145
  272. package/bin/mistake-relevance-policy.cjs +0 -319
  273. package/bin/model-retry-progress-policy.cjs +0 -46
  274. package/bin/native-large-file-io.cjs +0 -42
  275. package/bin/native-runtime-cache.cjs +0 -76
  276. package/bin/natural-presence-policy.cjs +0 -28
  277. package/bin/noninteractive-shell-env-policy.cjs +0 -19
  278. package/bin/observer-hooks.cjs +0 -14
  279. package/bin/outbound-claim-provenance.cjs +0 -150
  280. package/bin/oversized-context-offload-policy.cjs +0 -86
  281. package/bin/pending-media-policy.cjs +0 -182
  282. package/bin/pending-token-estimate-policy.cjs +0 -41
  283. package/bin/personal-memory-consent-policy.cjs +0 -72
  284. package/bin/personal-memory-performance-policy.cjs +0 -12
  285. package/bin/personality-choice-policy.cjs +0 -101
  286. package/bin/personality-memory-adapter.cjs +0 -379
  287. package/bin/personality-mode.cjs +0 -46
  288. package/bin/personality-setup-policy.cjs +0 -197
  289. package/bin/proactive-compaction-policy.cjs +0 -25
  290. package/bin/profile-identity-resolution.cjs +0 -136
  291. package/bin/profile-runtime.cjs +0 -318
  292. package/bin/profile-tool-exclusion-policy.cjs +0 -37
  293. package/bin/programmatic-context-isolation.cjs +0 -25
  294. package/bin/programmatic-tool-runtime.mjs +0 -627
  295. package/bin/provider-idle-timeout-policy.cjs +0 -14
  296. package/bin/provider-model-refresh-deadline.cjs +0 -53
  297. package/bin/provider-model-refresh-policy.cjs +0 -107
  298. package/bin/rate-limit-recovery-policy.cjs +0 -47
  299. package/bin/read-batch-policy.cjs +0 -32
  300. package/bin/read-continuation-policy.cjs +0 -59
  301. package/bin/recurring-cron-history-policy.cjs +0 -124
  302. package/bin/relationship-continuity-policy.cjs +0 -143
  303. package/bin/relationship-curiosity-policy.cjs +0 -107
  304. package/bin/relationship-learning-policy.cjs +0 -168
  305. package/bin/release-artifact-freeze-policy.cjs +0 -30
  306. package/bin/reload-plugin-bootstrap.cjs +0 -18
  307. package/bin/reload-queue-policy.cjs +0 -38
  308. package/bin/repeated-assistant-response-policy.cjs +0 -232
  309. package/bin/repeated-injection-projection.cjs +0 -107
  310. package/bin/repeated-user-message-projection.cjs +0 -8
  311. package/bin/research-page-result.cjs +0 -74
  312. package/bin/retry-checkpoint-policy.cjs +0 -13
  313. package/bin/runtime-exit-ledger.cjs +0 -144
  314. package/bin/scoped-cron-run-policy.cjs +0 -358
  315. package/bin/session-checkpoint-policy.cjs +0 -25
  316. package/bin/session-compaction-policy.cjs +0 -84
  317. package/bin/session-replay-policy.cjs +0 -20
  318. package/bin/session-replay-window-policy.cjs +0 -40
  319. package/bin/session-resume-checkpoint.cjs +0 -254
  320. package/bin/session-scrollback-archive.cjs +0 -229
  321. package/bin/skill-activation-performance-policy.cjs +0 -69
  322. package/bin/skill-listing-performance-policy.cjs +0 -92
  323. package/bin/soul-organization-policy.cjs +0 -78
  324. package/bin/soul-preservation-policy.cjs +0 -20
  325. package/bin/startup-preferences.cjs +0 -131
  326. package/bin/streaming-flush-performance-policy.cjs +0 -28
  327. package/bin/structured-agent-swarm-output.cjs +0 -325
  328. package/bin/structured-subagent-output.cjs +0 -252
  329. package/bin/subagent-context-fork-policy.cjs +0 -155
  330. package/bin/subagent-max-tokens-handoff-policy.cjs +0 -69
  331. package/bin/subagent-parent-responsiveness.cjs +0 -19
  332. package/bin/subagent-skill-policy.cjs +0 -206
  333. package/bin/subagent-timeout-policy.cjs +0 -182
  334. package/bin/subagent-tool-policy.cjs +0 -60
  335. package/bin/subagent-usage-rollup-policy.cjs +0 -29
  336. package/bin/system-prompt-context-policy.cjs +0 -124
  337. package/bin/system-prompt-token-cache-policy.cjs +0 -60
  338. package/bin/telegram-addressed-focus.cjs +0 -55
  339. package/bin/telegram-addressed-priority.cjs +0 -12
  340. package/bin/telegram-approval-relay.cjs +0 -290
  341. package/bin/telegram-bot-priority.cjs +0 -17
  342. package/bin/telegram-console-status-policy.cjs +0 -174
  343. package/bin/telegram-context-projection-policy.cjs +0 -141
  344. package/bin/telegram-delivery-lifecycle.cjs +0 -125
  345. package/bin/telegram-direct-focus-policy.cjs +0 -273
  346. package/bin/telegram-mcp-compatibility.cjs +0 -49
  347. package/bin/telegram-media-delivery-policy.cjs +0 -42
  348. package/bin/telegram-private-conversation-policy.cjs +0 -185
  349. package/bin/telegram-queue-handoff-policy.cjs +0 -73
  350. package/bin/telegram-remote-status-policy.cjs +0 -120
  351. package/bin/telegram-session-queue-runtime.mjs +0 -306
  352. package/bin/telegram-text-chunk-policy.cjs +0 -63
  353. package/bin/telegram-truncated-reply-policy.cjs +0 -37
  354. package/bin/telegram-urgent-policy.cjs +0 -45
  355. package/bin/telemetry-spool-policy.cjs +0 -57
  356. package/bin/thinking-activity-status-policy.cjs +0 -132
  357. package/bin/thinking-only-guard.cjs +0 -80
  358. package/bin/todo-list-turn-policy.cjs +0 -131
  359. package/bin/tool-call-loop-policy.cjs +0 -51
  360. package/bin/tool-file-persistence.cjs +0 -141
  361. package/bin/tool-result-offload-policy.cjs +0 -359
  362. package/bin/tool-result-offload-telemetry.cjs +0 -12
  363. package/bin/tool-schema-token-cache-policy.cjs +0 -41
  364. package/bin/tool-stream-preview-policy.cjs +0 -9
  365. package/bin/tui-functional-contract.cjs +0 -55
  366. package/bin/turn-tool-performance-policy.cjs +0 -486
  367. package/bin/usage-cache-efficiency-policy.cjs +0 -26
  368. package/bin/user-home-path-policy.cjs +0 -13
  369. package/bin/user-message-offload-policy.cjs +0 -103
  370. package/bin/user-prompt-hook-origin-policy.cjs +0 -34
  371. package/bin/user-tool-record-policy.cjs +0 -7
  372. package/bin/validated-learning-insight-policy.cjs +0 -58
  373. package/bin/validated-learning-outcome-trace.cjs +0 -107
  374. package/bin/validated-learning-performance-policy.cjs +0 -53
  375. package/bin/validated-learning-signal.cjs +0 -463
  376. package/bin/windows-bash-dialect-policy.cjs +0 -25
  377. package/bin/windows-node-crash-dump.cjs +0 -110
  378. package/bin/write-continuation-policy.cjs +0 -69
  379. package/codebase-index/README.md +0 -82
  380. package/codebase-index/codebase_index.py +0 -470
  381. package/standard-skills/agent-browser/SKILL.md +0 -19
  382. package/standard-skills/agent-browser/references/runtime.md +0 -8
  383. package/standard-skills/blun-session-inspector/SKILL.md +0 -41
  384. package/standard-skills/blun-session-inspector/scripts/inspect-session.cjs +0 -437
  385. package/standard-skills/design-taste-frontend/SKILL.md +0 -1206
  386. package/standard-skills/full-output-enforcement/SKILL.md +0 -49
  387. package/standard-skills/high-end-visual-design/SKILL.md +0 -98
  388. package/standard-skills/image-to-code/SKILL.md +0 -1228
  389. package/standard-skills/industrial-brutalist-ui/SKILL.md +0 -92
  390. package/standard-skills/minimalist-ui/SKILL.md +0 -85
  391. package/standard-skills/motion-design-taste/SKILL.md +0 -74
  392. package/standard-skills/playwright-testing/SKILL.md +0 -19
  393. package/standard-skills/playwright-testing/references/runtime.md +0 -7
  394. package/standard-skills/premortem/SKILL.md +0 -148
  395. package/standard-skills/redesign-existing-projects/SKILL.md +0 -178
  396. package/standard-skills/research-evidence/SKILL.md +0 -39
  397. package/standard-skills/research-evidence/references/evidence-format.md +0 -104
  398. package/standard-skills/research-evidence/scripts/evidence-collection.cjs +0 -260
  399. package/standard-skills/research-evidence/scripts/score-report.cjs +0 -130
  400. package/standard-skills/screenshot-lesen/SKILL.md +0 -52
  401. package/standard-skills/stitch-design-taste/DESIGN.md +0 -121
  402. package/standard-skills/stitch-design-taste/SKILL.md +0 -184
  403. package/standard-skills/telegram-channel/SKILL.md +0 -18
  404. package/standard-skills/telegram-channel/references/runtime.md +0 -7
  405. package/standard-skills/venture-flywheel/SKILL.md +0 -32
  406. package/standard-skills/venture-flywheel/identity/project-identity.cjs +0 -146
  407. package/standard-skills/venture-flywheel/policy/capability-engine.cjs +0 -114
  408. package/standard-skills/venture-flywheel/policy/repository-trust.cjs +0 -229
  409. package/standard-skills/venture-flywheel/references/BEISPIELE-phase0.md +0 -146
  410. package/standard-skills/venture-flywheel/references/CAPABILITY-MAP.md +0 -34
  411. package/standard-skills/venture-flywheel/references/SPEC-phase0-identity-trust.md +0 -77
  412. package/standard-skills/venture-flywheel/references/SPEC-phase0-state-events.md +0 -93
  413. package/standard-skills/venture-flywheel/schemas/capability-decision.schema.json +0 -13
  414. package/standard-skills/venture-flywheel/schemas/execution-event.schema.json +0 -44
  415. package/standard-skills/venture-flywheel/schemas/project-identity.schema.json +0 -32
  416. package/standard-skills/venture-flywheel/schemas/repository-trust.schema.json +0 -57
  417. package/standard-skills/venture-flywheel/schemas/run-transition.schema.json +0 -59
  418. package/standard-skills/venture-flywheel/state/execution-event.cjs +0 -191
  419. package/standard-skills/venture-flywheel/state/task-state-machine.cjs +0 -190
  420. package/standard-skills/web-lesen/SKILL.md +0 -73
  421. package/standard-skills/web-lesen/scripts/crawl_public.py +0 -379
  422. package/standard-skills/windows-mcp/SKILL.md +0 -19
  423. package/standard-skills/windows-mcp/references/runtime.md +0 -9
  424. package/telegram-plugin/DELIVERY.md +0 -36
  425. package/telegram-plugin/bin/telegram-approval-relay.cjs +0 -290
  426. package/telegram-plugin/bin/telegram-console-status-policy.cjs +0 -175
  427. package/telegram-plugin/bin/telegram-delivery-lifecycle.cjs +0 -125
  428. package/telegram-plugin/bin/telegram-direct-reply-policy.cjs +0 -48
  429. package/telegram-plugin/bin/telegram-launcher-status-queue.cjs +0 -122
  430. package/telegram-plugin/bin/telegram-private-conversation-policy.cjs +0 -186
  431. package/telegram-plugin/bin/telegram-remote-status-policy.cjs +0 -121
  432. package/telegram-plugin/bin/telegram-reply-parts.cjs +0 -149
  433. package/telegram-plugin/bin/telegram-text-chunk-policy.cjs +0 -63
  434. package/telegram-plugin/bin/telegram-typing-keepalive.cjs +0 -89
  435. package/telegram-plugin/compat/mcp-server-fa511cd1.mjs +0 -73825
  436. /package/{bin → scripts}/fix-node-pty-perms.js +0 -0
@@ -0,0 +1,665 @@
1
+ #!/usr/bin/env python3
2
+ """Protected production runtime for durable website-source delivery.
3
+
4
+ The composition root validates the complete worker in memory before creating
5
+ one private SQLite database. A runtime belongs to one process, serializes all
6
+ connection access, guards the database identity around every operation, and
7
+ can own one supervised non-daemon delivery worker.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import importlib.util
13
+ import math
14
+ import os
15
+ import sqlite3
16
+ import stat
17
+ import sys
18
+ import threading
19
+ import time
20
+ from pathlib import Path
21
+ from typing import Any, Callable, Mapping
22
+
23
+
24
+ def _load_module(name: str, path: Path):
25
+ spec = importlib.util.spec_from_file_location(name, path)
26
+ if spec is None or spec.loader is None:
27
+ raise RuntimeError(
28
+ f"cannot load source delivery runtime dependency: {path.name}"
29
+ )
30
+ module = importlib.util.module_from_spec(spec)
31
+ sys.modules[spec.name] = module
32
+ spec.loader.exec_module(module)
33
+ return module
34
+
35
+
36
+ _ROOT = Path(__file__).resolve().parents[1]
37
+ _DELIVERY = _load_module(
38
+ "blun_website_localization_composed_cms_source_delivery",
39
+ _ROOT / "integrations" / "website_localization_cms_source_delivery.py",
40
+ )
41
+
42
+
43
+ class DurableCMSSourceDeliveryRuntimeBlocked(RuntimeError):
44
+ """Stable runtime failure without paths, content, or private exceptions."""
45
+
46
+ def __init__(self, code: str):
47
+ super().__init__(code)
48
+ self.code = code
49
+
50
+
51
+ def _blocked(code: str) -> DurableCMSSourceDeliveryRuntimeBlocked:
52
+ return DurableCMSSourceDeliveryRuntimeBlocked(code)
53
+
54
+
55
+ def _delivery_failure(error: Exception) -> DurableCMSSourceDeliveryRuntimeBlocked:
56
+ code = getattr(error, "code", None)
57
+ if code in {
58
+ "source_delivery.request_invalid",
59
+ "source_delivery.source_attempts_invalid",
60
+ "source_delivery.attempts_invalid",
61
+ "source_delivery.status_invalid",
62
+ "source_delivery.worker_invalid",
63
+ "source_delivery.lease_invalid",
64
+ "source_delivery.lease_too_short",
65
+ }:
66
+ return _blocked("source_delivery_runtime.request_invalid")
67
+ if code == "source_delivery.idempotency_collision":
68
+ return _blocked("source_delivery_runtime.idempotency_collision")
69
+ if code == "source_delivery.status_not_found":
70
+ return _blocked("source_delivery_runtime.status_not_found")
71
+ return _blocked("source_delivery_runtime.outbox_blocked")
72
+
73
+
74
+ def _database_path(value: Any) -> str:
75
+ try:
76
+ result = os.fspath(value)
77
+ except TypeError:
78
+ raise _blocked("source_delivery_runtime.database_path_invalid") from None
79
+ if isinstance(result, bytes):
80
+ raise _blocked("source_delivery_runtime.database_path_invalid")
81
+ if (
82
+ not isinstance(result, str)
83
+ or not result
84
+ or "\x00" in result
85
+ or result.startswith("file:")
86
+ ):
87
+ raise _blocked("source_delivery_runtime.database_path_invalid")
88
+ if result == ":memory:":
89
+ return result
90
+ if (
91
+ os.name != "posix"
92
+ or not os.path.isabs(result)
93
+ or os.path.normpath(result) != result
94
+ ):
95
+ raise _blocked("source_delivery_runtime.database_path_invalid")
96
+ return result
97
+
98
+
99
+ def _validate_database_parent(database_path: str) -> None:
100
+ current = os.path.dirname(database_path)
101
+ first = True
102
+ while True:
103
+ try:
104
+ current_stat = os.lstat(current)
105
+ except OSError:
106
+ raise _blocked(
107
+ "source_delivery_runtime.database_parent_unavailable"
108
+ ) from None
109
+ mode = stat.S_IMODE(current_stat.st_mode)
110
+ sticky_root_directory = (
111
+ current_stat.st_uid == 0
112
+ and bool(mode & stat.S_ISVTX)
113
+ and bool(mode & 0o002)
114
+ )
115
+ if (
116
+ not stat.S_ISDIR(current_stat.st_mode)
117
+ or current_stat.st_uid not in {0, os.geteuid()}
118
+ or (first and current_stat.st_uid != os.geteuid())
119
+ or (mode & 0o022 and not sticky_root_directory)
120
+ ):
121
+ raise _blocked("source_delivery_runtime.database_parent_unsafe")
122
+ parent = os.path.dirname(current)
123
+ if parent == current:
124
+ break
125
+ current = parent
126
+ first = False
127
+
128
+
129
+ def _validate_database_file(
130
+ database_path: str,
131
+ expected_identity: tuple[int, int] | None = None,
132
+ ) -> tuple[int, int]:
133
+ try:
134
+ database_stat = os.lstat(database_path)
135
+ except FileNotFoundError:
136
+ raise
137
+ except OSError:
138
+ raise _blocked("source_delivery_runtime.database_unavailable") from None
139
+ identity = (database_stat.st_dev, database_stat.st_ino)
140
+ if (
141
+ not stat.S_ISREG(database_stat.st_mode)
142
+ or database_stat.st_uid != os.geteuid()
143
+ or database_stat.st_nlink != 1
144
+ or stat.S_IMODE(database_stat.st_mode) != 0o600
145
+ or (expected_identity is not None and identity != expected_identity)
146
+ ):
147
+ raise _blocked("source_delivery_runtime.database_unsafe")
148
+ return identity
149
+
150
+
151
+ def _sqlite_timeout(value: Any) -> float:
152
+ if (
153
+ isinstance(value, bool)
154
+ or not isinstance(value, (int, float))
155
+ or not math.isfinite(float(value))
156
+ or not 0 < float(value) <= 60
157
+ ):
158
+ raise _blocked("source_delivery_runtime.sqlite_timeout_invalid")
159
+ return float(value)
160
+
161
+
162
+ def _prepare_database_file(database_path: str) -> Callable[[], None]:
163
+ if database_path == ":memory:":
164
+ return lambda: None
165
+ _validate_database_parent(database_path)
166
+ try:
167
+ identity = _validate_database_file(database_path)
168
+ except FileNotFoundError:
169
+ flags = os.O_CREAT | os.O_EXCL | os.O_RDWR
170
+ flags |= getattr(os, "O_CLOEXEC", 0)
171
+ flags |= getattr(os, "O_NOFOLLOW", 0)
172
+ try:
173
+ descriptor = os.open(database_path, flags, 0o600)
174
+ except FileExistsError:
175
+ identity = _validate_database_file(database_path)
176
+ except OSError:
177
+ raise _blocked(
178
+ "source_delivery_runtime.database_create_failed"
179
+ ) from None
180
+ else:
181
+ try:
182
+ os.fchmod(descriptor, 0o600)
183
+ created_stat = os.fstat(descriptor)
184
+ identity = (created_stat.st_dev, created_stat.st_ino)
185
+ if (
186
+ not stat.S_ISREG(created_stat.st_mode)
187
+ or created_stat.st_uid != os.geteuid()
188
+ or created_stat.st_nlink != 1
189
+ or stat.S_IMODE(created_stat.st_mode) != 0o600
190
+ ):
191
+ raise _blocked(
192
+ "source_delivery_runtime.database_create_failed"
193
+ )
194
+ finally:
195
+ os.close(descriptor)
196
+
197
+ def guard() -> None:
198
+ _validate_database_parent(database_path)
199
+ try:
200
+ _validate_database_file(database_path, identity)
201
+ except FileNotFoundError:
202
+ raise _blocked(
203
+ "source_delivery_runtime.database_unavailable"
204
+ ) from None
205
+
206
+ guard()
207
+ return guard
208
+
209
+
210
+ def _duration(value: Any, code: str, *, maximum: float = 86_400) -> float:
211
+ if (
212
+ isinstance(value, bool)
213
+ or not isinstance(value, (int, float))
214
+ or not math.isfinite(float(value))
215
+ or not 0 < float(value) <= maximum
216
+ ):
217
+ raise _blocked(code)
218
+ return float(value)
219
+
220
+
221
+ def _preflight(
222
+ client: Any,
223
+ worker_id: str,
224
+ lease_seconds: float | int,
225
+ outbox_options: Mapping[str, Any],
226
+ ) -> float:
227
+ connection = sqlite3.connect(":memory:")
228
+ try:
229
+ outbox = _DELIVERY.DurableCMSSourceDeliveryOutbox(
230
+ connection, client, **dict(outbox_options),
231
+ )
232
+ lease = _duration(
233
+ lease_seconds, "source_delivery_runtime.lease_invalid",
234
+ )
235
+ outbox.claim(worker_id, lease_seconds=lease)
236
+ return lease
237
+ except DurableCMSSourceDeliveryRuntimeBlocked:
238
+ raise
239
+ except Exception as error:
240
+ raise _blocked("source_delivery_runtime.configuration_invalid") from error
241
+ finally:
242
+ connection.close()
243
+
244
+
245
+ class DurableCMSSourceDeliveryRuntime:
246
+ """One process-owned, guarded, thread-safe source-delivery runtime."""
247
+
248
+ def __init__(
249
+ self,
250
+ connection: sqlite3.Connection,
251
+ guard: Callable[[], None],
252
+ outbox: Any,
253
+ *,
254
+ worker_id: str,
255
+ lease_seconds: float,
256
+ ):
257
+ self._connection = connection
258
+ self._guard = guard
259
+ self._outbox = outbox
260
+ self._worker_id = worker_id
261
+ self._lease_seconds = lease_seconds
262
+ self._lock = threading.RLock()
263
+ self._closed = False
264
+ self._owner_pid = os.getpid()
265
+ self._worker_stop = threading.Event()
266
+ self._worker_thread: threading.Thread | None = None
267
+ self._worker_state = "unmanaged"
268
+ self._worker_error_code: str | None = None
269
+
270
+ def __repr__(self) -> str:
271
+ return f"DurableCMSSourceDeliveryRuntime(state={self.state!r})"
272
+
273
+ def __enter__(self) -> "DurableCMSSourceDeliveryRuntime":
274
+ self._assert_owner()
275
+ if self._closed:
276
+ raise _blocked("source_delivery_runtime.closed")
277
+ return self
278
+
279
+ def __exit__(self, *_exc: Any) -> None:
280
+ self.close()
281
+
282
+ def _assert_owner(self) -> None:
283
+ # Check before the lock: a child must never wait on a lock inherited
284
+ # from a vanished parent thread.
285
+ if os.getpid() != self._owner_pid:
286
+ raise _blocked("source_delivery_runtime.foreign_process")
287
+
288
+ def _guard_database(self) -> None:
289
+ self._guard()
290
+
291
+ def _call(self, name: str, *args: Any, **kwargs: Any) -> Any:
292
+ self._assert_owner()
293
+ with self._lock:
294
+ if self._closed:
295
+ raise _blocked("source_delivery_runtime.closed")
296
+ self._guard_database()
297
+ try:
298
+ result = getattr(self._outbox, name)(*args, **kwargs)
299
+ except Exception as error:
300
+ raise _delivery_failure(error) from error
301
+ finally:
302
+ self._guard_database()
303
+ return result
304
+
305
+ def _require_worker_locked(self) -> None:
306
+ if self._worker_state == "unmanaged":
307
+ return
308
+ if (
309
+ self._worker_state != "running"
310
+ or self._worker_error_code is not None
311
+ or self._worker_thread is None
312
+ or not self._worker_thread.is_alive()
313
+ ):
314
+ raise _blocked("source_delivery_runtime.worker_not_ready")
315
+
316
+ def enqueue_change(
317
+ self,
318
+ change: Mapping[str, Any],
319
+ *,
320
+ source_max_attempts: int = 5,
321
+ delivery_max_attempts: int = 5,
322
+ ) -> Any:
323
+ self._assert_owner()
324
+ with self._lock:
325
+ self._require_worker_locked()
326
+ return self._call(
327
+ "enqueue_change",
328
+ change,
329
+ source_max_attempts=source_max_attempts,
330
+ delivery_max_attempts=delivery_max_attempts,
331
+ )
332
+
333
+ def enqueue_removal(
334
+ self,
335
+ removal: Mapping[str, Any],
336
+ *,
337
+ source_max_attempts: int = 5,
338
+ delivery_max_attempts: int = 5,
339
+ ) -> Any:
340
+ self._assert_owner()
341
+ with self._lock:
342
+ self._require_worker_locked()
343
+ return self._call(
344
+ "enqueue_removal",
345
+ removal,
346
+ source_max_attempts=source_max_attempts,
347
+ delivery_max_attempts=delivery_max_attempts,
348
+ )
349
+
350
+ def status(self, operation: str, request_id: str) -> Any:
351
+ return self._call("status", operation, request_id)
352
+
353
+ def health(self) -> Any:
354
+ return self._call("health")
355
+
356
+ def run_once(self) -> Any:
357
+ return self._call(
358
+ "run_once",
359
+ self._worker_id,
360
+ lease_seconds=self._lease_seconds,
361
+ )
362
+
363
+ @staticmethod
364
+ def _loop_delays(
365
+ active_delay_seconds: float | int,
366
+ idle_delay_seconds: float | int,
367
+ blocked_delay_seconds: float | int,
368
+ ) -> tuple[float, float, float]:
369
+ return (
370
+ _duration(
371
+ active_delay_seconds,
372
+ "source_delivery_runtime.loop_invalid",
373
+ maximum=300,
374
+ ),
375
+ _duration(
376
+ idle_delay_seconds,
377
+ "source_delivery_runtime.loop_invalid",
378
+ maximum=300,
379
+ ),
380
+ _duration(
381
+ blocked_delay_seconds,
382
+ "source_delivery_runtime.loop_invalid",
383
+ maximum=300,
384
+ ),
385
+ )
386
+
387
+ @staticmethod
388
+ def _join_timeout(value: float | int) -> float:
389
+ return _duration(
390
+ value, "source_delivery_runtime.worker_timeout_invalid",
391
+ maximum=300,
392
+ )
393
+
394
+ def _managed_worker(
395
+ self,
396
+ stop: threading.Event,
397
+ delays: tuple[float, float, float],
398
+ ) -> None:
399
+ try:
400
+ active, idle, blocked = delays
401
+ while not stop.is_set():
402
+ outcome = self.run_once()
403
+ if outcome is None:
404
+ delay = idle
405
+ elif outcome.status in {"retry_wait", "failed"}:
406
+ delay = blocked
407
+ else:
408
+ delay = active
409
+ stop.wait(delay)
410
+ except Exception:
411
+ with self._lock:
412
+ self._worker_error_code = (
413
+ "source_delivery_runtime.worker_blocked"
414
+ )
415
+ self._worker_state = "failed"
416
+ return
417
+ with self._lock:
418
+ if self._worker_state in {"running", "stopping"}:
419
+ self._worker_state = "stopped"
420
+
421
+ def start_worker(
422
+ self,
423
+ *,
424
+ active_delay_seconds: float | int = 0.05,
425
+ idle_delay_seconds: float | int = 1,
426
+ blocked_delay_seconds: float | int = 5,
427
+ ) -> None:
428
+ """Start one interruptible process-owned background worker."""
429
+
430
+ delays = self._loop_delays(
431
+ active_delay_seconds,
432
+ idle_delay_seconds,
433
+ blocked_delay_seconds,
434
+ )
435
+ self._assert_owner()
436
+ with self._lock:
437
+ if self._closed:
438
+ raise _blocked("source_delivery_runtime.closed")
439
+ if self._worker_state == "running":
440
+ return
441
+ if self._worker_state in {"stopping", "failed"}:
442
+ raise _blocked("source_delivery_runtime.worker_blocked")
443
+ self._guard_database()
444
+ stop = threading.Event()
445
+ thread = threading.Thread(
446
+ target=self._managed_worker,
447
+ args=(stop, delays),
448
+ name="cms-source-delivery-worker",
449
+ daemon=False,
450
+ )
451
+ self._worker_stop = stop
452
+ self._worker_thread = thread
453
+ self._worker_error_code = None
454
+ self._worker_state = "running"
455
+ try:
456
+ thread.start()
457
+ except Exception as error:
458
+ self._worker_thread = None
459
+ self._worker_state = "failed"
460
+ self._worker_error_code = (
461
+ "source_delivery_runtime.worker_blocked"
462
+ )
463
+ raise _blocked(
464
+ "source_delivery_runtime.worker_blocked"
465
+ ) from error
466
+
467
+ def stop_worker(self, *, timeout_seconds: float | int = 30) -> None:
468
+ """Signal and join the worker without closing durable state."""
469
+
470
+ timeout = self._join_timeout(timeout_seconds)
471
+ self._assert_owner()
472
+ thread = self._worker_thread
473
+ state = self._worker_state
474
+ if thread is None or state in {"unmanaged", "stopped"}:
475
+ return
476
+ if thread is threading.current_thread():
477
+ raise _blocked("source_delivery_runtime.worker_stop_invalid")
478
+ if state != "failed":
479
+ self._worker_state = "stopping"
480
+ self._worker_stop.set()
481
+ thread.join(timeout)
482
+ if thread.is_alive():
483
+ raise _blocked("source_delivery_runtime.worker_stop_timeout")
484
+ with self._lock:
485
+ if self._worker_state == "stopping":
486
+ self._worker_state = "stopped"
487
+
488
+ def require_worker_ready(self) -> None:
489
+ """Block managed intake unless its worker is alive and healthy."""
490
+
491
+ self._assert_owner()
492
+ with self._lock:
493
+ if self._closed:
494
+ raise _blocked("source_delivery_runtime.closed")
495
+ self._require_worker_locked()
496
+
497
+ def worker_readiness(self) -> dict[str, Any]:
498
+ """Return a content-free worker and durable-outbox snapshot."""
499
+
500
+ self._assert_owner()
501
+ with self._lock:
502
+ state = "closed" if self._closed else self._worker_state
503
+ error_code = self._worker_error_code
504
+ thread = self._worker_thread
505
+ alive = thread is not None and thread.is_alive()
506
+ if state != "running" or not alive:
507
+ return {
508
+ "schema": "blun.cms-source-delivery-worker-readiness.v1",
509
+ "status": "not_ready",
510
+ "worker_state": state,
511
+ "outbox_status": None,
512
+ "error_code": error_code
513
+ or "source_delivery_runtime.worker_not_ready",
514
+ }
515
+ health = self.health()
516
+ outbox_status = getattr(health, "status", None)
517
+ if outbox_status not in {"ok", "blocked"}:
518
+ raise _blocked("source_delivery_runtime.outbox_blocked")
519
+ ready = outbox_status == "ok"
520
+ return {
521
+ "schema": "blun.cms-source-delivery-worker-readiness.v1",
522
+ "status": "ready" if ready else "not_ready",
523
+ "worker_state": "running",
524
+ "outbox_status": outbox_status,
525
+ "error_code": (
526
+ None
527
+ if ready
528
+ else getattr(health, "error_code", None)
529
+ or "source_delivery_runtime.outbox_blocked"
530
+ ),
531
+ }
532
+
533
+ def run_forever(
534
+ self,
535
+ stop: Callable[[], bool],
536
+ *,
537
+ sleeper: Callable[[float], Any] = time.sleep,
538
+ active_delay_seconds: float | int = 0.05,
539
+ idle_delay_seconds: float | int = 1,
540
+ blocked_delay_seconds: float | int = 5,
541
+ ) -> None:
542
+ if not callable(stop) or not callable(sleeper):
543
+ raise _blocked("source_delivery_runtime.loop_invalid")
544
+ active, idle, blocked = self._loop_delays(
545
+ active_delay_seconds,
546
+ idle_delay_seconds,
547
+ blocked_delay_seconds,
548
+ )
549
+ while not stop():
550
+ outcome = self.run_once()
551
+ if outcome is None:
552
+ delay = idle
553
+ elif outcome.status in {"retry_wait", "failed"}:
554
+ delay = blocked
555
+ else:
556
+ delay = active
557
+ sleeper(delay)
558
+
559
+ def close(self, *, worker_timeout_seconds: float | int = 30) -> None:
560
+ self._assert_owner()
561
+ self.stop_worker(timeout_seconds=worker_timeout_seconds)
562
+ with self._lock:
563
+ if self._closed:
564
+ return
565
+ try:
566
+ self._connection.close()
567
+ except sqlite3.Error as error:
568
+ raise _blocked("source_delivery_runtime.close_failed") from error
569
+ self._closed = True
570
+
571
+ @property
572
+ def state(self) -> str:
573
+ if os.getpid() != self._owner_pid:
574
+ return "foreign-process"
575
+ with self._lock:
576
+ return "closed" if self._closed else "open"
577
+
578
+ @property
579
+ def worker_state(self) -> str:
580
+ if os.getpid() != self._owner_pid:
581
+ return "foreign-process"
582
+ with self._lock:
583
+ return "closed" if self._closed else self._worker_state
584
+
585
+
586
+ def open_durable_cms_source_delivery(
587
+ database: str | os.PathLike[str],
588
+ client: Any,
589
+ *,
590
+ worker_id: str,
591
+ clock: Callable[[], float | int] = time.time,
592
+ sqlite_timeout_seconds: float | int = 5,
593
+ lease_seconds: float | int = 600,
594
+ base_delay_seconds: float | int = 5,
595
+ max_delay_seconds: float | int = 300,
596
+ ) -> DurableCMSSourceDeliveryRuntime:
597
+ """Validate configuration, then open one guarded durable outbox."""
598
+
599
+ path = _database_path(database)
600
+ timeout = _sqlite_timeout(sqlite_timeout_seconds)
601
+ outbox_options = {
602
+ "clock": clock,
603
+ "base_delay_seconds": base_delay_seconds,
604
+ "max_delay_seconds": max_delay_seconds,
605
+ }
606
+ lease = _preflight(client, worker_id, lease_seconds, outbox_options)
607
+ guard = _prepare_database_file(path)
608
+ connection = None
609
+ try:
610
+ connection = sqlite3.connect(
611
+ path,
612
+ timeout=timeout,
613
+ isolation_level=None,
614
+ check_same_thread=False,
615
+ )
616
+ guard()
617
+ outbox = _DELIVERY.DurableCMSSourceDeliveryOutbox(
618
+ connection, client, **outbox_options,
619
+ )
620
+ guard()
621
+ except Exception as error:
622
+ if connection is not None:
623
+ try:
624
+ connection.close()
625
+ except sqlite3.Error:
626
+ pass
627
+ if isinstance(error, DurableCMSSourceDeliveryRuntimeBlocked):
628
+ raise
629
+ if isinstance(error, _DELIVERY.CMSSourceDeliveryBlocked):
630
+ raise _delivery_failure(error) from error
631
+ raise _blocked("source_delivery_runtime.initialization_failed") from error
632
+ return DurableCMSSourceDeliveryRuntime(
633
+ connection,
634
+ guard,
635
+ outbox,
636
+ worker_id=worker_id,
637
+ lease_seconds=lease,
638
+ )
639
+
640
+
641
+ def open_hosted_cms_source_delivery(
642
+ *args: Any,
643
+ active_delay_seconds: float | int = 0.05,
644
+ idle_delay_seconds: float | int = 1,
645
+ blocked_delay_seconds: float | int = 5,
646
+ **kwargs: Any,
647
+ ) -> DurableCMSSourceDeliveryRuntime:
648
+ """Open the guarded outbox and start its supervised worker."""
649
+
650
+ delays = DurableCMSSourceDeliveryRuntime._loop_delays(
651
+ active_delay_seconds,
652
+ idle_delay_seconds,
653
+ blocked_delay_seconds,
654
+ )
655
+ runtime = open_durable_cms_source_delivery(*args, **kwargs)
656
+ try:
657
+ runtime.start_worker(
658
+ active_delay_seconds=delays[0],
659
+ idle_delay_seconds=delays[1],
660
+ blocked_delay_seconds=delays[2],
661
+ )
662
+ except Exception:
663
+ runtime.close()
664
+ raise
665
+ return runtime