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,675 @@
1
+ #!/usr/bin/env python3
2
+ """Owned, durable runtime for the source side of the CMS localization API.
3
+
4
+ The composition root validates the complete service configuration before it
5
+ opens three private SQLite databases. One runtime belongs to one process and
6
+ serializes every local state transition. Separate processes may safely open
7
+ the same files because the underlying outboxes and monitor use durable leases.
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(f"cannot load source runtime dependency: {path.name}")
28
+ module = importlib.util.module_from_spec(spec)
29
+ sys.modules[spec.name] = module
30
+ spec.loader.exec_module(module)
31
+ return module
32
+
33
+
34
+ _ROOT = Path(__file__).resolve().parents[1]
35
+ _SERVICE = _load_module(
36
+ "blun_website_localization_composed_cms_source_service",
37
+ _ROOT / "integrations" / "website_localization_cms_source_service.py",
38
+ )
39
+ _HTTP = _load_module(
40
+ "blun_website_localization_composed_cms_source_http",
41
+ _ROOT / "integrations" / "website_localization_cms_source_http.py",
42
+ )
43
+
44
+
45
+ class DurableCMSSourceRuntimeBlocked(RuntimeError):
46
+ """Stable runtime failure that contains no path, credential, or content."""
47
+
48
+ def __init__(self, code: str):
49
+ super().__init__(code)
50
+ self.code = code
51
+
52
+
53
+ def _blocked(code: str) -> DurableCMSSourceRuntimeBlocked:
54
+ return DurableCMSSourceRuntimeBlocked(code)
55
+
56
+
57
+ def _service_failure(error: Exception) -> DurableCMSSourceRuntimeBlocked:
58
+ code = getattr(error, "code", None)
59
+ if code in {
60
+ "dispatch.change_invalid",
61
+ "dispatch.max_attempts_invalid",
62
+ "removal.request_invalid",
63
+ "removal.max_attempts_invalid",
64
+ "source_service.status_invalid",
65
+ }:
66
+ return _blocked("source_runtime.request_invalid")
67
+ if code in {
68
+ "dispatch.idempotency_collision",
69
+ "removal.idempotency_collision",
70
+ }:
71
+ return _blocked("source_runtime.idempotency_collision")
72
+ if code == "source_service.status_not_found":
73
+ return _blocked("source_runtime.status_not_found")
74
+ return _blocked("source_runtime.service_blocked")
75
+
76
+
77
+ def _database_path(value: Any) -> str:
78
+ try:
79
+ result = os.fspath(value)
80
+ except TypeError:
81
+ raise _blocked("source_runtime.database_path_invalid") from None
82
+ if isinstance(result, bytes):
83
+ raise _blocked("source_runtime.database_path_invalid")
84
+ if (
85
+ not isinstance(result, str)
86
+ or not result
87
+ or "\x00" in result
88
+ or result.startswith("file:")
89
+ ):
90
+ raise _blocked("source_runtime.database_path_invalid")
91
+ if result == ":memory:":
92
+ return result
93
+ if (
94
+ os.name != "posix"
95
+ or not os.path.isabs(result)
96
+ or os.path.normpath(result) != result
97
+ ):
98
+ raise _blocked("source_runtime.database_path_invalid")
99
+ return result
100
+
101
+
102
+ def _validate_database_parent(database_path: str) -> None:
103
+ current = os.path.dirname(database_path)
104
+ first = True
105
+ while True:
106
+ try:
107
+ current_stat = os.lstat(current)
108
+ except OSError:
109
+ raise _blocked("source_runtime.database_parent_unavailable") from None
110
+ mode = stat.S_IMODE(current_stat.st_mode)
111
+ sticky_root_directory = (
112
+ current_stat.st_uid == 0
113
+ and bool(mode & stat.S_ISVTX)
114
+ and bool(mode & 0o002)
115
+ )
116
+ if (
117
+ not stat.S_ISDIR(current_stat.st_mode)
118
+ or current_stat.st_uid not in {0, os.geteuid()}
119
+ or (first and current_stat.st_uid != os.geteuid())
120
+ or (mode & 0o022 and not sticky_root_directory)
121
+ ):
122
+ raise _blocked("source_runtime.database_parent_unsafe")
123
+ parent = os.path.dirname(current)
124
+ if parent == current:
125
+ break
126
+ current = parent
127
+ first = False
128
+
129
+
130
+ def _validate_database_file(
131
+ database_path: str,
132
+ expected_identity: tuple[int, int] | None = None,
133
+ ) -> tuple[int, int]:
134
+ try:
135
+ database_stat = os.lstat(database_path)
136
+ except FileNotFoundError:
137
+ raise
138
+ except OSError:
139
+ raise _blocked("source_runtime.database_unavailable") from None
140
+ identity = (database_stat.st_dev, database_stat.st_ino)
141
+ if (
142
+ not stat.S_ISREG(database_stat.st_mode)
143
+ or database_stat.st_uid != os.geteuid()
144
+ or database_stat.st_nlink != 1
145
+ or stat.S_IMODE(database_stat.st_mode) != 0o600
146
+ or (expected_identity is not None and identity != expected_identity)
147
+ ):
148
+ raise _blocked("source_runtime.database_unsafe")
149
+ return identity
150
+
151
+
152
+ def _prepare_database_file(database_path: str) -> Callable[[], None]:
153
+ if database_path == ":memory:":
154
+ return lambda: None
155
+ _validate_database_parent(database_path)
156
+ try:
157
+ identity = _validate_database_file(database_path)
158
+ except FileNotFoundError:
159
+ flags = os.O_CREAT | os.O_EXCL | os.O_RDWR
160
+ flags |= getattr(os, "O_CLOEXEC", 0)
161
+ flags |= getattr(os, "O_NOFOLLOW", 0)
162
+ try:
163
+ descriptor = os.open(database_path, flags, 0o600)
164
+ except FileExistsError:
165
+ identity = _validate_database_file(database_path)
166
+ except OSError:
167
+ raise _blocked("source_runtime.database_create_failed") from None
168
+ else:
169
+ try:
170
+ os.fchmod(descriptor, 0o600)
171
+ created_stat = os.fstat(descriptor)
172
+ identity = (created_stat.st_dev, created_stat.st_ino)
173
+ if (
174
+ not stat.S_ISREG(created_stat.st_mode)
175
+ or created_stat.st_uid != os.geteuid()
176
+ or created_stat.st_nlink != 1
177
+ or stat.S_IMODE(created_stat.st_mode) != 0o600
178
+ ):
179
+ raise _blocked("source_runtime.database_create_failed")
180
+ finally:
181
+ os.close(descriptor)
182
+
183
+ def guard() -> None:
184
+ _validate_database_parent(database_path)
185
+ try:
186
+ _validate_database_file(database_path, identity)
187
+ except FileNotFoundError:
188
+ raise _blocked("source_runtime.database_unavailable") from None
189
+
190
+ guard()
191
+ return guard
192
+
193
+
194
+ def _validate_paths(paths: tuple[str, str, str]) -> None:
195
+ filesystem_paths = [path for path in paths if path != ":memory:"]
196
+ if len(set(filesystem_paths)) != len(filesystem_paths):
197
+ raise _blocked("source_runtime.database_path_reused")
198
+ identities: set[tuple[int, int]] = set()
199
+ for path in filesystem_paths:
200
+ _validate_database_parent(path)
201
+ try:
202
+ identity = _validate_database_file(path)
203
+ except FileNotFoundError:
204
+ continue
205
+ if identity in identities:
206
+ raise _blocked("source_runtime.database_identity_reused")
207
+ identities.add(identity)
208
+
209
+
210
+ def _sqlite_timeout(value: Any) -> 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) <= 60
216
+ ):
217
+ raise _blocked("source_runtime.sqlite_timeout_invalid")
218
+ return float(value)
219
+
220
+
221
+ def _preflight_service(
222
+ client: Any,
223
+ service_options: Mapping[str, Any],
224
+ ) -> None:
225
+ connections = [sqlite3.connect(":memory:") for _ in range(3)]
226
+ try:
227
+ _SERVICE.CMSLocalizationSourceService(
228
+ *connections,
229
+ client,
230
+ **dict(service_options),
231
+ )
232
+ except _SERVICE.CMSSourceServiceBlocked as error:
233
+ raise _blocked("source_runtime.configuration_invalid") from error
234
+ except (TypeError, ValueError, sqlite3.Error) as error:
235
+ raise _blocked("source_runtime.configuration_invalid") from error
236
+ except Exception as error:
237
+ raise _blocked("source_runtime.configuration_invalid") from error
238
+ finally:
239
+ for connection in connections:
240
+ connection.close()
241
+
242
+
243
+ class DurableCMSSourceRuntime:
244
+ """One process-owned and thread-safe source-CMS service runtime."""
245
+
246
+ def __init__(
247
+ self,
248
+ connections: tuple[sqlite3.Connection, sqlite3.Connection, sqlite3.Connection],
249
+ guards: tuple[Callable[[], None], Callable[[], None], Callable[[], None]],
250
+ service: Any,
251
+ http_authenticator: Callable[[dict[str, Any]], Any] | None,
252
+ ):
253
+ self._connections = connections
254
+ self._guards = guards
255
+ self._service = service
256
+ self._lock = threading.RLock()
257
+ self._closed = False
258
+ self._owner_pid = os.getpid()
259
+ self._worker_stop = threading.Event()
260
+ self._worker_thread: threading.Thread | None = None
261
+ self._worker_state = "unmanaged"
262
+ self._worker_error_code: str | None = None
263
+ self.http = (
264
+ None
265
+ if http_authenticator is None
266
+ else _HTTP.CMSSourceHTTPApplication(self, http_authenticator)
267
+ )
268
+
269
+ def __repr__(self) -> str:
270
+ return f"DurableCMSSourceRuntime(state={self.state!r})"
271
+
272
+ def __enter__(self) -> "DurableCMSSourceRuntime":
273
+ self._assert_owner()
274
+ if self._closed:
275
+ raise _blocked("source_runtime.closed")
276
+ return self
277
+
278
+ def __exit__(self, *_exc: Any) -> None:
279
+ self.close()
280
+
281
+ def _assert_owner(self) -> None:
282
+ # This must precede lock acquisition: a lock held by a vanished parent
283
+ # thread after fork cannot safely be acquired by the child process.
284
+ if os.getpid() != self._owner_pid:
285
+ raise _blocked("source_runtime.foreign_process")
286
+
287
+ def _guard_databases(self) -> None:
288
+ for guard in self._guards:
289
+ 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_runtime.closed")
296
+ self._guard_databases()
297
+ try:
298
+ result = getattr(self._service, name)(*args, **kwargs)
299
+ except Exception as error:
300
+ raise _service_failure(error) from error
301
+ finally:
302
+ self._guard_databases()
303
+ return result
304
+
305
+ def enqueue_change(
306
+ self, change: Mapping[str, Any], *, max_attempts: int = 5,
307
+ ) -> Any:
308
+ return self._call("enqueue_change", change, max_attempts=max_attempts)
309
+
310
+ def enqueue_removal(
311
+ self, request: Mapping[str, Any], *, max_attempts: int = 5,
312
+ ) -> Any:
313
+ return self._call("enqueue_removal", request, max_attempts=max_attempts)
314
+
315
+ def status(self, event_id: str, site_id: str) -> Any:
316
+ return self._call("status", event_id, site_id)
317
+
318
+ def run_once(self) -> Any:
319
+ return self._call("run_once")
320
+
321
+ def health(self) -> Any:
322
+ return self._call("health")
323
+
324
+ @staticmethod
325
+ def _loop_delays(
326
+ active_delay_seconds: float | int,
327
+ idle_delay_seconds: float | int,
328
+ blocked_delay_seconds: float | int,
329
+ ) -> tuple[float, float, float]:
330
+ try:
331
+ return tuple(
332
+ _SERVICE._positive_duration(
333
+ value, "source_service.delay_invalid",
334
+ )
335
+ for value in (
336
+ active_delay_seconds,
337
+ idle_delay_seconds,
338
+ blocked_delay_seconds,
339
+ )
340
+ )
341
+ except Exception as error:
342
+ raise _blocked("source_runtime.loop_invalid") from error
343
+
344
+ @staticmethod
345
+ def _join_timeout(value: float | int) -> float:
346
+ if (
347
+ isinstance(value, bool)
348
+ or not isinstance(value, (int, float))
349
+ or not math.isfinite(float(value))
350
+ or not 0 < float(value) <= 300
351
+ ):
352
+ raise _blocked("source_runtime.worker_timeout_invalid")
353
+ return float(value)
354
+
355
+ def _managed_worker(
356
+ self,
357
+ stop: threading.Event,
358
+ delays: tuple[float, float, float],
359
+ ) -> None:
360
+ try:
361
+ with self._lock:
362
+ if self._worker_state != "starting" or self._worker_stop is not stop:
363
+ return
364
+ self._worker_state = "running"
365
+ active, idle, blocked = delays
366
+ while not stop.is_set():
367
+ outcome = self.run_once()
368
+ delay = (
369
+ blocked
370
+ if outcome.status in {"blocked", "failed", "retry_wait"}
371
+ else idle if outcome.status == "idle" else active
372
+ )
373
+ stop.wait(delay)
374
+ except Exception:
375
+ with self._lock:
376
+ self._worker_error_code = "source_runtime.worker_blocked"
377
+ self._worker_state = "failed"
378
+ return
379
+ with self._lock:
380
+ if self._worker_state in {"running", "stopping"}:
381
+ self._worker_state = "stopped"
382
+
383
+ def start_worker(
384
+ self,
385
+ *,
386
+ active_delay_seconds: float | int = 0.05,
387
+ idle_delay_seconds: float | int = 1,
388
+ blocked_delay_seconds: float | int = 5,
389
+ ) -> None:
390
+ """Start one interruptible, process-owned background worker."""
391
+
392
+ delays = self._loop_delays(
393
+ active_delay_seconds,
394
+ idle_delay_seconds,
395
+ blocked_delay_seconds,
396
+ )
397
+ self._assert_owner()
398
+ with self._lock:
399
+ if self._closed:
400
+ raise _blocked("source_runtime.closed")
401
+ if self._worker_state in {"starting", "running"}:
402
+ return
403
+ if self._worker_state in {"stopping", "failed"}:
404
+ raise _blocked("source_runtime.worker_blocked")
405
+ self._guard_databases()
406
+ stop = threading.Event()
407
+ thread = threading.Thread(
408
+ target=self._managed_worker,
409
+ args=(stop, delays),
410
+ name="cms-source-worker",
411
+ daemon=False,
412
+ )
413
+ self._worker_stop = stop
414
+ self._worker_thread = thread
415
+ self._worker_error_code = None
416
+ self._worker_state = "starting"
417
+ try:
418
+ thread.start()
419
+ except Exception as error:
420
+ self._worker_thread = None
421
+ self._worker_state = "failed"
422
+ self._worker_error_code = "source_runtime.worker_blocked"
423
+ raise _blocked("source_runtime.worker_blocked") from error
424
+
425
+ def stop_worker(self, *, timeout_seconds: float | int = 30) -> None:
426
+ """Stop and join the managed worker without closing durable state."""
427
+
428
+ timeout = self._join_timeout(timeout_seconds)
429
+ self._assert_owner()
430
+ # Signal before taking the runtime lock. A provider call may currently
431
+ # hold that lock, and shutdown still needs a real upper time bound.
432
+ thread = self._worker_thread
433
+ state = self._worker_state
434
+ if thread is None or state in {"unmanaged", "stopped"}:
435
+ return
436
+ if thread is threading.current_thread():
437
+ raise _blocked("source_runtime.worker_stop_invalid")
438
+ if state != "failed":
439
+ self._worker_state = "stopping"
440
+ self._worker_stop.set()
441
+ thread.join(timeout)
442
+ if thread.is_alive():
443
+ raise _blocked("source_runtime.worker_stop_timeout")
444
+ with self._lock:
445
+ if self._worker_state == "stopping":
446
+ self._worker_state = "stopped"
447
+
448
+ def require_worker_ready(self) -> None:
449
+ """Block hosted HTTP writes unless their managed worker is running."""
450
+
451
+ self._assert_owner()
452
+ with self._lock:
453
+ if self._closed:
454
+ raise _blocked("source_runtime.closed")
455
+ if self._worker_state == "unmanaged":
456
+ return
457
+ if self._worker_state != "running" or self._worker_error_code is not None:
458
+ raise _blocked("source_runtime.worker_not_ready")
459
+
460
+ def worker_readiness(self) -> dict[str, Any]:
461
+ """Return a content-free readiness snapshot for supervised hosts."""
462
+
463
+ self._assert_owner()
464
+ with self._lock:
465
+ state = "closed" if self._closed else self._worker_state
466
+ error_code = self._worker_error_code
467
+ if state != "running":
468
+ return {
469
+ "schema": "blun.cms-source-worker-readiness.v1",
470
+ "status": "not_ready",
471
+ "worker_state": state,
472
+ "service_status": None,
473
+ "error_code": error_code or "source_runtime.worker_not_ready",
474
+ }
475
+ health = self.health()
476
+ service_status = getattr(health, "status", None)
477
+ if service_status not in {"ok", "degraded", "blocked"}:
478
+ raise _blocked("source_runtime.service_blocked")
479
+ ready = service_status != "blocked"
480
+ return {
481
+ "schema": "blun.cms-source-worker-readiness.v1",
482
+ "status": "ready" if ready else "not_ready",
483
+ "worker_state": "running",
484
+ "service_status": service_status,
485
+ "error_code": (
486
+ None if ready else "source_runtime.service_blocked"
487
+ ),
488
+ }
489
+
490
+ def run_forever(
491
+ self,
492
+ stop: Callable[[], bool],
493
+ *,
494
+ sleeper: Callable[[float], Any] = time.sleep,
495
+ active_delay_seconds: float | int = 0.05,
496
+ idle_delay_seconds: float | int = 1,
497
+ blocked_delay_seconds: float | int = 5,
498
+ ) -> None:
499
+ if not callable(stop) or not callable(sleeper):
500
+ raise _blocked("source_runtime.loop_invalid")
501
+ active, idle, blocked = self._loop_delays(
502
+ active_delay_seconds,
503
+ idle_delay_seconds,
504
+ blocked_delay_seconds,
505
+ )
506
+ while not stop():
507
+ outcome = self.run_once()
508
+ delay = (
509
+ blocked if outcome.status in {"blocked", "failed", "retry_wait"}
510
+ else idle if outcome.status == "idle"
511
+ else active
512
+ )
513
+ sleeper(delay)
514
+
515
+ def close(self, *, worker_timeout_seconds: float | int = 30) -> None:
516
+ self._assert_owner()
517
+ self.stop_worker(timeout_seconds=worker_timeout_seconds)
518
+ with self._lock:
519
+ if self._closed:
520
+ return
521
+ failed = False
522
+ for connection in self._connections:
523
+ try:
524
+ connection.close()
525
+ except sqlite3.Error:
526
+ failed = True
527
+ self._closed = True
528
+ if failed:
529
+ raise _blocked("source_runtime.close_failed")
530
+
531
+ @property
532
+ def state(self) -> str:
533
+ if os.getpid() != self._owner_pid:
534
+ return "foreign-process"
535
+ with self._lock:
536
+ return "closed" if self._closed else "open"
537
+
538
+ @property
539
+ def worker_state(self) -> str:
540
+ if os.getpid() != self._owner_pid:
541
+ return "foreign-process"
542
+ with self._lock:
543
+ return "closed" if self._closed else self._worker_state
544
+
545
+
546
+ def open_durable_cms_source(
547
+ change_database: str | os.PathLike[str],
548
+ removal_database: str | os.PathLike[str],
549
+ lifecycle_database: str | os.PathLike[str],
550
+ client: Any,
551
+ *,
552
+ change_worker_id: str,
553
+ removal_worker_id: str,
554
+ lifecycle_worker_id: str,
555
+ terminal_notifier: Callable[[Mapping[str, Any]], Any] | None = None,
556
+ terminal_status_reader: Callable[[str, str], Any] | None = None,
557
+ notification_worker_id: str | None = None,
558
+ http_authenticator: Callable[[dict[str, Any]], Any] | None = None,
559
+ clock: Callable[[], float | int] = time.time,
560
+ sqlite_timeout_seconds: float | int = 5,
561
+ change_lease_seconds: float | int = 600,
562
+ removal_lease_seconds: float | int = 600,
563
+ lifecycle_lease_seconds: float | int = 600,
564
+ notification_lease_seconds: float | int = 600,
565
+ terminal_processing_lease_seconds: float | int = 600,
566
+ max_lifecycle_failures: int = 5,
567
+ max_notification_attempts: int = 5,
568
+ max_terminal_processing_failures: int = 5,
569
+ dispatch_base_delay_seconds: float | int = 5,
570
+ dispatch_max_delay_seconds: float | int = 300,
571
+ lifecycle_poll_interval_seconds: float | int = 30,
572
+ lifecycle_base_delay_seconds: float | int = 5,
573
+ lifecycle_max_delay_seconds: float | int = 300,
574
+ notification_base_delay_seconds: float | int = 5,
575
+ notification_max_delay_seconds: float | int = 300,
576
+ terminal_processing_poll_interval_seconds: float | int = 30,
577
+ terminal_processing_base_delay_seconds: float | int = 5,
578
+ terminal_processing_max_delay_seconds: float | int = 300,
579
+ ) -> DurableCMSSourceRuntime:
580
+ """Validate and open the complete durable source-side CMS worker."""
581
+
582
+ paths = tuple(_database_path(value) for value in (
583
+ change_database, removal_database, lifecycle_database,
584
+ ))
585
+ timeout = _sqlite_timeout(sqlite_timeout_seconds)
586
+ if http_authenticator is not None and not callable(http_authenticator):
587
+ raise _blocked("source_runtime.http_authenticator_invalid")
588
+ service_options = {
589
+ "change_worker_id": change_worker_id,
590
+ "removal_worker_id": removal_worker_id,
591
+ "lifecycle_worker_id": lifecycle_worker_id,
592
+ "terminal_notifier": terminal_notifier,
593
+ "terminal_status_reader": terminal_status_reader,
594
+ "notification_worker_id": notification_worker_id,
595
+ "clock": clock,
596
+ "change_lease_seconds": change_lease_seconds,
597
+ "removal_lease_seconds": removal_lease_seconds,
598
+ "lifecycle_lease_seconds": lifecycle_lease_seconds,
599
+ "notification_lease_seconds": notification_lease_seconds,
600
+ "terminal_processing_lease_seconds": terminal_processing_lease_seconds,
601
+ "max_lifecycle_failures": max_lifecycle_failures,
602
+ "max_notification_attempts": max_notification_attempts,
603
+ "max_terminal_processing_failures": max_terminal_processing_failures,
604
+ "dispatch_base_delay_seconds": dispatch_base_delay_seconds,
605
+ "dispatch_max_delay_seconds": dispatch_max_delay_seconds,
606
+ "lifecycle_poll_interval_seconds": lifecycle_poll_interval_seconds,
607
+ "lifecycle_base_delay_seconds": lifecycle_base_delay_seconds,
608
+ "lifecycle_max_delay_seconds": lifecycle_max_delay_seconds,
609
+ "notification_base_delay_seconds": notification_base_delay_seconds,
610
+ "notification_max_delay_seconds": notification_max_delay_seconds,
611
+ "terminal_processing_poll_interval_seconds": (
612
+ terminal_processing_poll_interval_seconds
613
+ ),
614
+ "terminal_processing_base_delay_seconds": (
615
+ terminal_processing_base_delay_seconds
616
+ ),
617
+ "terminal_processing_max_delay_seconds": (
618
+ terminal_processing_max_delay_seconds
619
+ ),
620
+ }
621
+ _preflight_service(client, service_options)
622
+ _validate_paths(paths)
623
+ guards = tuple(_prepare_database_file(path) for path in paths)
624
+ connections: list[sqlite3.Connection] = []
625
+ try:
626
+ for path in paths:
627
+ connections.append(sqlite3.connect(
628
+ path,
629
+ timeout=timeout,
630
+ isolation_level=None,
631
+ check_same_thread=False,
632
+ ))
633
+ for guard in guards:
634
+ guard()
635
+ service = _SERVICE.CMSLocalizationSourceService(
636
+ *connections,
637
+ client,
638
+ **service_options,
639
+ )
640
+ for guard in guards:
641
+ guard()
642
+ except Exception as error:
643
+ for connection in connections:
644
+ try:
645
+ connection.close()
646
+ except sqlite3.Error:
647
+ pass
648
+ if isinstance(error, DurableCMSSourceRuntimeBlocked):
649
+ raise
650
+ raise _blocked("source_runtime.initialization_failed") from error
651
+ return DurableCMSSourceRuntime(
652
+ tuple(connections), guards, service, http_authenticator,
653
+ )
654
+
655
+
656
+ def open_hosted_cms_source(
657
+ *args: Any,
658
+ active_delay_seconds: float | int = 0.05,
659
+ idle_delay_seconds: float | int = 1,
660
+ blocked_delay_seconds: float | int = 5,
661
+ **kwargs: Any,
662
+ ) -> DurableCMSSourceRuntime:
663
+ """Open a durable runtime and start its supervised background worker."""
664
+
665
+ runtime = open_durable_cms_source(*args, **kwargs)
666
+ try:
667
+ runtime.start_worker(
668
+ active_delay_seconds=active_delay_seconds,
669
+ idle_delay_seconds=idle_delay_seconds,
670
+ blocked_delay_seconds=blocked_delay_seconds,
671
+ )
672
+ except Exception:
673
+ runtime.close()
674
+ raise
675
+ return runtime