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,964 @@
1
+ #!/usr/bin/env python3
2
+ """Durable website-side delivery outbox for the source-CMS HTTPS client.
3
+
4
+ The website host persists one immutable change, cancellation, or tombstone
5
+ before network access. One token-bound lease performs one client call. A crash
6
+ after remote acceptance safely replays the same identity after lease expiry;
7
+ the source runtime remains the idempotency authority.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import hashlib
13
+ import importlib.util
14
+ import json
15
+ import math
16
+ import re
17
+ import secrets
18
+ import sqlite3
19
+ import sys
20
+ import time
21
+ from contextlib import contextmanager
22
+ from dataclasses import dataclass, field
23
+ from pathlib import Path
24
+ from typing import Any, Callable, Iterator, Mapping
25
+
26
+
27
+ SCHEMA_VERSION = 1
28
+ MAX_ATTEMPTS = 20
29
+ MAX_LEASE_SECONDS = 86_400.0
30
+ MAX_DELAY_SECONDS = 86_400.0
31
+ STATUSES = ("pending", "leased", "retry_wait", "succeeded", "failed")
32
+ ACTIVE_STATUSES = {"pending", "leased", "retry_wait"}
33
+ OPERATIONS = ("change", "cancellation", "tombstone")
34
+ TOKEN = re.compile(r"^[A-Za-z0-9_.:-]{1,256}$")
35
+ SHA256 = re.compile(r"^[0-9a-f]{64}$")
36
+ ERROR_CODE = re.compile(r"^[a-z][a-z0-9_.-]{0,127}$")
37
+ _META_COLUMNS = ("singleton", "schema_version")
38
+ _COLUMNS = (
39
+ "operation", "request_id", "event_id", "site_id", "payload_json",
40
+ "payload_sha256", "capabilities_sha256", "status", "attempts",
41
+ "delivery_max_attempts", "source_max_attempts", "next_attempt_at",
42
+ "lease_owner", "lease_token", "lease_expires_at", "last_error_code",
43
+ "response_sha256", "created_at", "updated_at",
44
+ )
45
+
46
+
47
+ def _load_module(name: str, path: Path):
48
+ spec = importlib.util.spec_from_file_location(name, path)
49
+ if spec is None or spec.loader is None:
50
+ raise RuntimeError(f"cannot load source delivery dependency: {path.name}")
51
+ module = importlib.util.module_from_spec(spec)
52
+ sys.modules[spec.name] = module
53
+ spec.loader.exec_module(module)
54
+ return module
55
+
56
+
57
+ _ROOT = Path(__file__).resolve().parents[1]
58
+ _CLIENT = _load_module(
59
+ "blun_website_localization_cms_source_delivery_client",
60
+ _ROOT / "integrations" / "website_localization_cms_source_client.py",
61
+ )
62
+
63
+
64
+ class CMSSourceDeliveryBlocked(RuntimeError):
65
+ """Stable, content-free failure of the durable delivery outbox."""
66
+
67
+ def __init__(self, code: str):
68
+ if not isinstance(code, str) or ERROR_CODE.fullmatch(code) is None:
69
+ raise ValueError("source delivery failure is invalid")
70
+ super().__init__(code)
71
+ self.code = code
72
+
73
+
74
+ @dataclass(frozen=True)
75
+ class SourceDeliveryClaim:
76
+ operation: str
77
+ request_id: str
78
+ event_id: str
79
+ site_id: str
80
+ payload_sha256: str
81
+ capabilities_sha256: str
82
+ attempt: int
83
+ delivery_max_attempts: int
84
+ source_max_attempts: int
85
+ lease_owner: str
86
+ lease_token: str
87
+ lease_expires_at: float
88
+ payload_json: str = field(repr=False, compare=False)
89
+
90
+
91
+ @dataclass(frozen=True)
92
+ class SourceDeliveryStatus:
93
+ operation: str
94
+ request_id: str
95
+ event_id: str
96
+ site_id: str
97
+ payload_sha256: str
98
+ capabilities_sha256: str
99
+ status: str
100
+ attempts: int
101
+ delivery_max_attempts: int
102
+ source_max_attempts: int
103
+ next_attempt_at: float
104
+ lease_expires_at: float | None
105
+ lease_expired: bool
106
+ last_error_code: str | None
107
+ response_sha256: str | None
108
+
109
+
110
+ @dataclass(frozen=True)
111
+ class SourceDeliveryOutcome:
112
+ operation: str
113
+ request_id: str
114
+ event_id: str
115
+ status: str
116
+ attempt: int
117
+ delivery_max_attempts: int
118
+ next_attempt_at: float
119
+ error_code: str | None
120
+
121
+
122
+ @dataclass(frozen=True)
123
+ class SourceDeliveryHealth:
124
+ schema: str
125
+ status: str
126
+ counts: dict[str, int]
127
+ operations: dict[str, int]
128
+ due: int
129
+ expired_leases: int
130
+ failed: int
131
+ contract_mismatches: int
132
+ error_code: str | None
133
+
134
+ def as_payload(self) -> dict[str, Any]:
135
+ return {
136
+ "schema": self.schema,
137
+ "status": self.status,
138
+ "counts": dict(self.counts),
139
+ "operations": dict(self.operations),
140
+ "due": self.due,
141
+ "expired_leases": self.expired_leases,
142
+ "failed": self.failed,
143
+ "contract_mismatches": self.contract_mismatches,
144
+ "error_code": self.error_code,
145
+ }
146
+
147
+
148
+ def _token(value: Any, code: str, *, limit: int = 256) -> str:
149
+ if (
150
+ not isinstance(value, str)
151
+ or len(value) > limit
152
+ or TOKEN.fullmatch(value) is None
153
+ ):
154
+ raise CMSSourceDeliveryBlocked(code)
155
+ return value
156
+
157
+
158
+ def _sha256(value: Any, code: str) -> str:
159
+ if not isinstance(value, str) or SHA256.fullmatch(value) is None:
160
+ raise CMSSourceDeliveryBlocked(code)
161
+ return value
162
+
163
+
164
+ def _timestamp(value: Any, code: str) -> float:
165
+ if isinstance(value, bool) or not isinstance(value, (int, float)):
166
+ raise CMSSourceDeliveryBlocked(code)
167
+ result = float(value)
168
+ if result < 0 or not math.isfinite(result):
169
+ raise CMSSourceDeliveryBlocked(code)
170
+ return result
171
+
172
+
173
+ def _duration(value: Any, code: str, *, maximum: float) -> float:
174
+ result = _timestamp(value, code)
175
+ if result <= 0 or result > maximum:
176
+ raise CMSSourceDeliveryBlocked(code)
177
+ return result
178
+
179
+
180
+ def _attempts(value: Any, code: str) -> int:
181
+ if (
182
+ isinstance(value, bool)
183
+ or not isinstance(value, int)
184
+ or not 1 <= value <= MAX_ATTEMPTS
185
+ ):
186
+ raise CMSSourceDeliveryBlocked(code)
187
+ return value
188
+
189
+
190
+ def _canonical(value: Any, code: str) -> str:
191
+ try:
192
+ result = json.dumps(
193
+ value, ensure_ascii=False, allow_nan=False, sort_keys=True,
194
+ separators=(",", ":"),
195
+ )
196
+ except (TypeError, ValueError, RecursionError):
197
+ raise CMSSourceDeliveryBlocked(code) from None
198
+ if not result or len(result.encode("utf-8")) > _CLIENT._HTTP.MAX_BODY_BYTES:
199
+ raise CMSSourceDeliveryBlocked(code)
200
+ return result
201
+
202
+
203
+ def _hash(value: str) -> str:
204
+ return hashlib.sha256(value.encode("utf-8")).hexdigest()
205
+
206
+
207
+ def _payload(value: Any) -> tuple[str, str, str, str, str, str]:
208
+ if not isinstance(value, Mapping):
209
+ raise CMSSourceDeliveryBlocked("source_delivery.request_invalid")
210
+ try:
211
+ schema = value.get("schema")
212
+ if schema == _CLIENT._CMS.CHANGE_SCHEMA:
213
+ copied, raw = _CLIENT._copy_payload(value, "change")
214
+ operation = "change"
215
+ request_id = copied["event_id"]
216
+ else:
217
+ copied, raw = _CLIENT._copy_payload(value, "removal")
218
+ if copied["schema"] == _CLIENT._CMS.CANCELLATION_SCHEMA:
219
+ operation, identity = "cancellation", "cancellation_id"
220
+ else:
221
+ operation, identity = "tombstone", "tombstone_id"
222
+ request_id = copied[identity]
223
+ event_id = copied["event_id"]
224
+ site_id = copied["site_id"]
225
+ except Exception:
226
+ raise CMSSourceDeliveryBlocked(
227
+ "source_delivery.request_invalid",
228
+ ) from None
229
+ payload_json = raw.decode("utf-8")
230
+ return (
231
+ operation, request_id, event_id, site_id, payload_json,
232
+ hashlib.sha256(raw).hexdigest(),
233
+ )
234
+
235
+
236
+ def _error_code(error: Exception) -> tuple[str, bool]:
237
+ code = getattr(error, "code", None)
238
+ retryable = getattr(error, "retryable", None)
239
+ declared = getattr(error, "cms_source_client_failure", False) is True
240
+ if (
241
+ not declared
242
+ or not isinstance(code, str)
243
+ or ERROR_CODE.fullmatch(code) is None
244
+ or not isinstance(retryable, bool)
245
+ ):
246
+ return "source_delivery.client_failure", False
247
+ return code, retryable
248
+
249
+
250
+ @contextmanager
251
+ def _transaction(connection: sqlite3.Connection) -> Iterator[None]:
252
+ if connection.in_transaction:
253
+ raise CMSSourceDeliveryBlocked("source_delivery.transaction_nested")
254
+ try:
255
+ connection.execute("BEGIN IMMEDIATE")
256
+ yield
257
+ connection.commit()
258
+ except Exception:
259
+ if connection.in_transaction:
260
+ connection.rollback()
261
+ raise
262
+
263
+
264
+ class DurableCMSSourceDeliveryOutbox:
265
+ """Persist and deliver source events at least once through one pinned client."""
266
+
267
+ def __init__(
268
+ self,
269
+ connection: sqlite3.Connection,
270
+ client: Any,
271
+ *,
272
+ clock: Callable[[], float | int] = time.time,
273
+ base_delay_seconds: float | int = 5,
274
+ max_delay_seconds: float | int = 300,
275
+ ):
276
+ if not isinstance(connection, sqlite3.Connection):
277
+ raise TypeError("connection must be sqlite3.Connection")
278
+ if not callable(clock):
279
+ raise TypeError("clock must be callable")
280
+ digest = getattr(client, "expected_capabilities_sha256", None)
281
+ if (
282
+ not callable(getattr(client, "submit_change", None))
283
+ or not callable(getattr(client, "submit_removal", None))
284
+ or not isinstance(digest, str)
285
+ or SHA256.fullmatch(digest) is None
286
+ ):
287
+ raise TypeError("client must provide the pinned source operations")
288
+ timeout = getattr(client, "timeout", None)
289
+ if (
290
+ isinstance(timeout, bool)
291
+ or not isinstance(timeout, (int, float))
292
+ or not math.isfinite(float(timeout))
293
+ or not 0 < float(timeout) <= 300
294
+ ):
295
+ raise TypeError("client timeout is invalid")
296
+ self.connection = connection
297
+ self.connection.row_factory = sqlite3.Row
298
+ self.client = client
299
+ self.capabilities_sha256 = digest
300
+ self.timeout = float(timeout)
301
+ self.clock = clock
302
+ self.base_delay_seconds = _duration(
303
+ base_delay_seconds, "source_delivery.delay_invalid",
304
+ maximum=MAX_DELAY_SECONDS,
305
+ )
306
+ self.max_delay_seconds = _duration(
307
+ max_delay_seconds, "source_delivery.delay_invalid",
308
+ maximum=MAX_DELAY_SECONDS,
309
+ )
310
+ if self.base_delay_seconds > self.max_delay_seconds:
311
+ raise CMSSourceDeliveryBlocked("source_delivery.delay_invalid")
312
+ self._initialize()
313
+
314
+ def _now(self, value: float | int | None = None) -> float:
315
+ try:
316
+ supplied = self.clock() if value is None else value
317
+ except Exception:
318
+ raise CMSSourceDeliveryBlocked(
319
+ "source_delivery.time_invalid",
320
+ ) from None
321
+ return _timestamp(supplied, "source_delivery.time_invalid")
322
+
323
+ def _initialize(self) -> None:
324
+ with _transaction(self.connection):
325
+ self.connection.execute("""
326
+ CREATE TABLE IF NOT EXISTS cms_source_delivery_meta (
327
+ singleton INTEGER PRIMARY KEY CHECK (singleton = 1),
328
+ schema_version INTEGER NOT NULL CHECK (schema_version = 1)
329
+ )
330
+ """)
331
+ self.connection.execute("""
332
+ INSERT OR IGNORE INTO cms_source_delivery_meta VALUES (1, 1)
333
+ """)
334
+ self.connection.execute("""
335
+ CREATE TABLE IF NOT EXISTS cms_source_delivery_outbox (
336
+ operation TEXT NOT NULL CHECK (
337
+ operation IN ('change', 'cancellation', 'tombstone')
338
+ ),
339
+ request_id TEXT NOT NULL,
340
+ event_id TEXT NOT NULL,
341
+ site_id TEXT NOT NULL,
342
+ payload_json TEXT NOT NULL,
343
+ payload_sha256 TEXT NOT NULL,
344
+ capabilities_sha256 TEXT NOT NULL,
345
+ status TEXT NOT NULL CHECK (
346
+ status IN (
347
+ 'pending', 'leased', 'retry_wait',
348
+ 'succeeded', 'failed'
349
+ )
350
+ ),
351
+ attempts INTEGER NOT NULL CHECK (attempts >= 0),
352
+ delivery_max_attempts INTEGER NOT NULL CHECK (
353
+ delivery_max_attempts BETWEEN 1 AND 20
354
+ ),
355
+ source_max_attempts INTEGER NOT NULL CHECK (
356
+ source_max_attempts BETWEEN 1 AND 20
357
+ ),
358
+ next_attempt_at REAL NOT NULL,
359
+ lease_owner TEXT,
360
+ lease_token TEXT,
361
+ lease_expires_at REAL,
362
+ last_error_code TEXT,
363
+ response_sha256 TEXT,
364
+ created_at REAL NOT NULL,
365
+ updated_at REAL NOT NULL,
366
+ PRIMARY KEY (operation, request_id),
367
+ CHECK (
368
+ (status = 'leased' AND lease_owner IS NOT NULL
369
+ AND lease_token IS NOT NULL
370
+ AND lease_expires_at IS NOT NULL)
371
+ OR
372
+ (status <> 'leased' AND lease_owner IS NULL
373
+ AND lease_token IS NULL
374
+ AND lease_expires_at IS NULL)
375
+ )
376
+ )
377
+ """)
378
+ self.connection.execute("""
379
+ CREATE INDEX IF NOT EXISTS cms_source_delivery_due
380
+ ON cms_source_delivery_outbox (
381
+ status, next_attempt_at, created_at, operation, request_id
382
+ )
383
+ """)
384
+ self._validate_schema()
385
+
386
+ def _validate_schema(self) -> None:
387
+ meta_columns = tuple(
388
+ row["name"] for row in self.connection.execute(
389
+ "PRAGMA table_info(cms_source_delivery_meta)"
390
+ ).fetchall()
391
+ )
392
+ meta = self.connection.execute(
393
+ "SELECT singleton, schema_version FROM cms_source_delivery_meta"
394
+ ).fetchall()
395
+ columns = tuple(
396
+ row["name"] for row in self.connection.execute(
397
+ "PRAGMA table_info(cms_source_delivery_outbox)"
398
+ ).fetchall()
399
+ )
400
+ if (
401
+ meta_columns != _META_COLUMNS
402
+ or len(meta) != 1
403
+ or tuple(meta[0]) != (1, SCHEMA_VERSION)
404
+ or columns != _COLUMNS
405
+ ):
406
+ raise CMSSourceDeliveryBlocked("source_delivery.schema_altered")
407
+
408
+ def enqueue_change(
409
+ self,
410
+ change: Mapping[str, Any],
411
+ *,
412
+ source_max_attempts: int = 5,
413
+ delivery_max_attempts: int = 5,
414
+ now: float | int | None = None,
415
+ ) -> SourceDeliveryStatus:
416
+ return self._enqueue(
417
+ change,
418
+ source_max_attempts=source_max_attempts,
419
+ delivery_max_attempts=delivery_max_attempts,
420
+ now=now,
421
+ expected_operation="change",
422
+ )
423
+
424
+ def enqueue_removal(
425
+ self,
426
+ removal: Mapping[str, Any],
427
+ *,
428
+ source_max_attempts: int = 5,
429
+ delivery_max_attempts: int = 5,
430
+ now: float | int | None = None,
431
+ ) -> SourceDeliveryStatus:
432
+ return self._enqueue(
433
+ removal,
434
+ source_max_attempts=source_max_attempts,
435
+ delivery_max_attempts=delivery_max_attempts,
436
+ now=now,
437
+ expected_operation=None,
438
+ )
439
+
440
+ def _enqueue(
441
+ self,
442
+ value: Mapping[str, Any],
443
+ *,
444
+ source_max_attempts: int,
445
+ delivery_max_attempts: int,
446
+ now: float | int | None,
447
+ expected_operation: str | None,
448
+ ) -> SourceDeliveryStatus:
449
+ self._validate_schema()
450
+ source_max_attempts = _attempts(
451
+ source_max_attempts, "source_delivery.source_attempts_invalid",
452
+ )
453
+ delivery_max_attempts = _attempts(
454
+ delivery_max_attempts, "source_delivery.attempts_invalid",
455
+ )
456
+ current = self._now(now)
457
+ payload = _payload(value)
458
+ operation, request_id, event_id, site_id, payload_json, payload_hash = payload
459
+ if expected_operation is not None and operation != expected_operation:
460
+ raise CMSSourceDeliveryBlocked("source_delivery.request_invalid")
461
+ with _transaction(self.connection):
462
+ row = self.connection.execute("""
463
+ SELECT payload_sha256, capabilities_sha256,
464
+ delivery_max_attempts, source_max_attempts
465
+ FROM cms_source_delivery_outbox
466
+ WHERE operation = ? AND request_id = ?
467
+ """, (operation, request_id)).fetchone()
468
+ binding = (
469
+ payload_hash,
470
+ self.capabilities_sha256,
471
+ delivery_max_attempts,
472
+ source_max_attempts,
473
+ )
474
+ if row is not None and tuple(row) != binding:
475
+ raise CMSSourceDeliveryBlocked(
476
+ "source_delivery.idempotency_collision",
477
+ )
478
+ if row is None:
479
+ self.connection.execute("""
480
+ INSERT INTO cms_source_delivery_outbox (
481
+ operation, request_id, event_id, site_id, payload_json,
482
+ payload_sha256, capabilities_sha256, status, attempts,
483
+ delivery_max_attempts, source_max_attempts,
484
+ next_attempt_at, created_at, updated_at
485
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, 'pending', 0, ?, ?, ?, ?, ?)
486
+ """, (
487
+ operation, request_id, event_id, site_id, payload_json,
488
+ payload_hash, self.capabilities_sha256,
489
+ delivery_max_attempts, source_max_attempts,
490
+ current, current, current,
491
+ ))
492
+ return self.status(operation, request_id, now=current)
493
+
494
+ def _validated_row(self, row: sqlite3.Row) -> None:
495
+ try:
496
+ operation = row["operation"]
497
+ request_id = _token(
498
+ row["request_id"], "source_delivery.integrity",
499
+ )
500
+ event_id = _token(row["event_id"], "source_delivery.integrity")
501
+ site_id = _token(row["site_id"], "source_delivery.integrity")
502
+ payload_hash = _sha256(
503
+ row["payload_sha256"], "source_delivery.integrity",
504
+ )
505
+ _sha256(row["capabilities_sha256"], "source_delivery.integrity")
506
+ status = row["status"]
507
+ attempts = row["attempts"]
508
+ delivery_max = _attempts(
509
+ row["delivery_max_attempts"], "source_delivery.integrity",
510
+ )
511
+ _attempts(row["source_max_attempts"], "source_delivery.integrity")
512
+ next_attempt = _timestamp(
513
+ row["next_attempt_at"], "source_delivery.integrity",
514
+ )
515
+ created = _timestamp(row["created_at"], "source_delivery.integrity")
516
+ updated = _timestamp(row["updated_at"], "source_delivery.integrity")
517
+ parsed = json.loads(row["payload_json"])
518
+ normalized = _payload(parsed)
519
+ except CMSSourceDeliveryBlocked:
520
+ raise
521
+ except Exception:
522
+ raise CMSSourceDeliveryBlocked(
523
+ "source_delivery.integrity",
524
+ ) from None
525
+ if (
526
+ operation not in OPERATIONS
527
+ or status not in STATUSES
528
+ or isinstance(attempts, bool)
529
+ or not isinstance(attempts, int)
530
+ or not 0 <= attempts <= delivery_max
531
+ or not created <= updated
532
+ or next_attempt < created
533
+ or normalized != (
534
+ operation, request_id, event_id, site_id,
535
+ row["payload_json"], payload_hash,
536
+ )
537
+ ):
538
+ raise CMSSourceDeliveryBlocked("source_delivery.integrity")
539
+ leased = status == "leased"
540
+ lease_values = (
541
+ row["lease_owner"], row["lease_token"], row["lease_expires_at"],
542
+ )
543
+ if leased:
544
+ if (
545
+ not all(value is not None for value in lease_values)
546
+ or not _token(
547
+ row["lease_owner"], "source_delivery.integrity", limit=128,
548
+ )
549
+ or not _token(
550
+ row["lease_token"], "source_delivery.integrity", limit=256,
551
+ )
552
+ or _timestamp(
553
+ row["lease_expires_at"], "source_delivery.integrity",
554
+ ) <= updated
555
+ ):
556
+ raise CMSSourceDeliveryBlocked("source_delivery.integrity")
557
+ elif any(value is not None for value in lease_values):
558
+ raise CMSSourceDeliveryBlocked("source_delivery.integrity")
559
+ error = row["last_error_code"]
560
+ response_hash = row["response_sha256"]
561
+ if error is not None and (
562
+ not isinstance(error, str) or ERROR_CODE.fullmatch(error) is None
563
+ ):
564
+ raise CMSSourceDeliveryBlocked("source_delivery.integrity")
565
+ if response_hash is not None:
566
+ _sha256(response_hash, "source_delivery.integrity")
567
+ if (
568
+ (status in {"retry_wait", "failed"}) != (error is not None)
569
+ or (status == "succeeded") != (response_hash is not None)
570
+ ):
571
+ raise CMSSourceDeliveryBlocked("source_delivery.integrity")
572
+
573
+ def _validate_rows(self) -> list[sqlite3.Row]:
574
+ rows = self.connection.execute(
575
+ "SELECT * FROM cms_source_delivery_outbox"
576
+ ).fetchall()
577
+ for row in rows:
578
+ self._validated_row(row)
579
+ return rows
580
+
581
+ def status(
582
+ self,
583
+ operation: str,
584
+ request_id: str,
585
+ *,
586
+ now: float | int | None = None,
587
+ ) -> SourceDeliveryStatus:
588
+ self._validate_schema()
589
+ if operation not in OPERATIONS:
590
+ raise CMSSourceDeliveryBlocked("source_delivery.status_invalid")
591
+ request_id = _token(request_id, "source_delivery.status_invalid")
592
+ current = self._now(now)
593
+ row = self.connection.execute("""
594
+ SELECT * FROM cms_source_delivery_outbox
595
+ WHERE operation = ? AND request_id = ?
596
+ """, (operation, request_id)).fetchone()
597
+ if row is None:
598
+ raise CMSSourceDeliveryBlocked("source_delivery.status_not_found")
599
+ self._validated_row(row)
600
+ return SourceDeliveryStatus(
601
+ operation=row["operation"],
602
+ request_id=row["request_id"],
603
+ event_id=row["event_id"],
604
+ site_id=row["site_id"],
605
+ payload_sha256=row["payload_sha256"],
606
+ capabilities_sha256=row["capabilities_sha256"],
607
+ status=row["status"],
608
+ attempts=int(row["attempts"]),
609
+ delivery_max_attempts=int(row["delivery_max_attempts"]),
610
+ source_max_attempts=int(row["source_max_attempts"]),
611
+ next_attempt_at=float(row["next_attempt_at"]),
612
+ lease_expires_at=(
613
+ None
614
+ if row["lease_expires_at"] is None
615
+ else float(row["lease_expires_at"])
616
+ ),
617
+ lease_expired=(
618
+ row["status"] == "leased"
619
+ and float(row["lease_expires_at"]) <= current
620
+ ),
621
+ last_error_code=row["last_error_code"],
622
+ response_sha256=row["response_sha256"],
623
+ )
624
+
625
+ def claim(
626
+ self,
627
+ worker_id: str,
628
+ *,
629
+ lease_seconds: float | int = 600,
630
+ now: float | int | None = None,
631
+ ) -> SourceDeliveryClaim | None:
632
+ self._validate_schema()
633
+ worker_id = _token(
634
+ worker_id, "source_delivery.worker_invalid", limit=128,
635
+ )
636
+ lease_seconds = _duration(
637
+ lease_seconds, "source_delivery.lease_invalid",
638
+ maximum=MAX_LEASE_SECONDS,
639
+ )
640
+ if lease_seconds <= self.timeout:
641
+ raise CMSSourceDeliveryBlocked("source_delivery.lease_too_short")
642
+ current = self._now(now)
643
+ claim = None
644
+ with _transaction(self.connection):
645
+ self._validate_rows()
646
+ self.connection.execute("""
647
+ UPDATE cms_source_delivery_outbox
648
+ SET status = CASE
649
+ WHEN attempts >= delivery_max_attempts
650
+ THEN 'failed' ELSE 'retry_wait' END,
651
+ next_attempt_at = ?, lease_owner = NULL,
652
+ lease_token = NULL, lease_expires_at = NULL,
653
+ last_error_code = 'source_delivery.lease_expired',
654
+ updated_at = ?
655
+ WHERE status = 'leased' AND lease_expires_at <= ?
656
+ """, (current, current, current))
657
+ mismatch = self.connection.execute("""
658
+ SELECT 1 FROM cms_source_delivery_outbox
659
+ WHERE status IN ('pending', 'leased', 'retry_wait')
660
+ AND capabilities_sha256 <> ? LIMIT 1
661
+ """, (self.capabilities_sha256,)).fetchone()
662
+ if mismatch is not None:
663
+ raise CMSSourceDeliveryBlocked(
664
+ "source_delivery.contract_changed",
665
+ )
666
+ row = self.connection.execute("""
667
+ SELECT * FROM cms_source_delivery_outbox
668
+ WHERE status IN ('pending', 'retry_wait')
669
+ AND next_attempt_at <= ?
670
+ AND attempts < delivery_max_attempts
671
+ ORDER BY CASE operation WHEN 'change' THEN 1 ELSE 0 END,
672
+ created_at, operation, request_id
673
+ LIMIT 1
674
+ """, (current,)).fetchone()
675
+ if row is not None:
676
+ self._validated_row(row)
677
+ lease_token = secrets.token_urlsafe(32)
678
+ lease_expires_at = current + lease_seconds
679
+ updated = self.connection.execute("""
680
+ UPDATE cms_source_delivery_outbox
681
+ SET status = 'leased', attempts = attempts + 1,
682
+ lease_owner = ?, lease_token = ?, lease_expires_at = ?,
683
+ last_error_code = NULL, updated_at = ?
684
+ WHERE operation = ? AND request_id = ?
685
+ AND status IN ('pending', 'retry_wait')
686
+ """, (
687
+ worker_id, lease_token, lease_expires_at, current,
688
+ row["operation"], row["request_id"],
689
+ ))
690
+ if updated.rowcount != 1:
691
+ raise CMSSourceDeliveryBlocked(
692
+ "source_delivery.claim_lost",
693
+ )
694
+ claim = SourceDeliveryClaim(
695
+ operation=row["operation"],
696
+ request_id=row["request_id"],
697
+ event_id=row["event_id"],
698
+ site_id=row["site_id"],
699
+ payload_sha256=row["payload_sha256"],
700
+ capabilities_sha256=row["capabilities_sha256"],
701
+ attempt=int(row["attempts"]) + 1,
702
+ delivery_max_attempts=int(
703
+ row["delivery_max_attempts"]
704
+ ),
705
+ source_max_attempts=int(row["source_max_attempts"]),
706
+ lease_owner=worker_id,
707
+ lease_token=lease_token,
708
+ lease_expires_at=lease_expires_at,
709
+ payload_json=row["payload_json"],
710
+ )
711
+ return claim
712
+
713
+ @staticmethod
714
+ def _claim(value: Any) -> SourceDeliveryClaim:
715
+ if not isinstance(value, SourceDeliveryClaim):
716
+ raise CMSSourceDeliveryBlocked("source_delivery.claim_invalid")
717
+ for name in (
718
+ "request_id", "event_id", "site_id", "lease_owner", "lease_token",
719
+ ):
720
+ _token(getattr(value, name), "source_delivery.claim_invalid")
721
+ if (
722
+ value.operation not in OPERATIONS
723
+ or SHA256.fullmatch(value.payload_sha256) is None
724
+ or SHA256.fullmatch(value.capabilities_sha256) is None
725
+ or not 1 <= value.attempt <= value.delivery_max_attempts <= 20
726
+ or not 1 <= value.source_max_attempts <= 20
727
+ ):
728
+ raise CMSSourceDeliveryBlocked("source_delivery.claim_invalid")
729
+ _timestamp(
730
+ value.lease_expires_at, "source_delivery.claim_invalid",
731
+ )
732
+ return value
733
+
734
+ def _current_row(
735
+ self, claim: SourceDeliveryClaim, current: float,
736
+ ) -> sqlite3.Row:
737
+ row = self.connection.execute("""
738
+ SELECT * FROM cms_source_delivery_outbox
739
+ WHERE operation = ? AND request_id = ?
740
+ """, (claim.operation, claim.request_id)).fetchone()
741
+ if row is None:
742
+ raise CMSSourceDeliveryBlocked("source_delivery.claim_lost")
743
+ self._validated_row(row)
744
+ if (
745
+ row["status"] != "leased"
746
+ or row["lease_owner"] != claim.lease_owner
747
+ or row["lease_token"] != claim.lease_token
748
+ or float(row["lease_expires_at"]) != claim.lease_expires_at
749
+ or float(row["lease_expires_at"]) <= current
750
+ or int(row["attempts"]) != claim.attempt
751
+ or row["payload_sha256"] != claim.payload_sha256
752
+ or row["capabilities_sha256"] != claim.capabilities_sha256
753
+ ):
754
+ raise CMSSourceDeliveryBlocked("source_delivery.claim_lost")
755
+ return row
756
+
757
+ def _response(self, claim: SourceDeliveryClaim, value: Any) -> str:
758
+ if not isinstance(value, Mapping):
759
+ raise CMSSourceDeliveryBlocked("source_delivery.response_invalid")
760
+ response_json = _canonical(
761
+ dict(value), "source_delivery.response_invalid",
762
+ )
763
+ try:
764
+ response = json.loads(response_json)
765
+ except (json.JSONDecodeError, RecursionError):
766
+ raise CMSSourceDeliveryBlocked(
767
+ "source_delivery.response_invalid",
768
+ ) from None
769
+ expected_schema = (
770
+ _CLIENT._HTTP.CHANGE_RESPONSE_SCHEMA
771
+ if claim.operation == "change"
772
+ else _CLIENT._HTTP.REMOVAL_RESPONSE_SCHEMA
773
+ )
774
+ if (
775
+ set(response) != {
776
+ "schema", "operation", "request_id", "event_id",
777
+ "payload_sha256", "status", "attempts", "max_attempts",
778
+ "capabilities_sha256",
779
+ }
780
+ or response.get("schema") != expected_schema
781
+ or response.get("operation") != claim.operation
782
+ or response.get("request_id") != claim.request_id
783
+ or response.get("event_id") != claim.event_id
784
+ or response.get("payload_sha256") != claim.payload_sha256
785
+ or response.get("status") not in _CLIENT._HTTP.STATUSES
786
+ or response.get("capabilities_sha256")
787
+ != claim.capabilities_sha256
788
+ or isinstance(response.get("attempts"), bool)
789
+ or not isinstance(response.get("attempts"), int)
790
+ or not 0 <= response["attempts"] <= claim.source_max_attempts
791
+ or response.get("max_attempts") != claim.source_max_attempts
792
+ ):
793
+ raise CMSSourceDeliveryBlocked("source_delivery.response_invalid")
794
+ return response_json
795
+
796
+ def complete(
797
+ self,
798
+ claim: SourceDeliveryClaim,
799
+ response: Mapping[str, Any],
800
+ *,
801
+ now: float | int | None = None,
802
+ ) -> SourceDeliveryStatus:
803
+ self._validate_schema()
804
+ claim = self._claim(claim)
805
+ current = self._now(now)
806
+ response_hash = _hash(self._response(claim, response))
807
+ with _transaction(self.connection):
808
+ self._current_row(claim, current)
809
+ updated = self.connection.execute("""
810
+ UPDATE cms_source_delivery_outbox
811
+ SET status = 'succeeded', lease_owner = NULL,
812
+ lease_token = NULL, lease_expires_at = NULL,
813
+ last_error_code = NULL, response_sha256 = ?, updated_at = ?
814
+ WHERE operation = ? AND request_id = ?
815
+ AND status = 'leased' AND lease_token = ?
816
+ """, (
817
+ response_hash, current, claim.operation, claim.request_id,
818
+ claim.lease_token,
819
+ ))
820
+ if updated.rowcount != 1:
821
+ raise CMSSourceDeliveryBlocked("source_delivery.claim_lost")
822
+ return self.status(claim.operation, claim.request_id, now=current)
823
+
824
+ def _record_failure(
825
+ self,
826
+ claim: SourceDeliveryClaim,
827
+ code: str,
828
+ *,
829
+ retryable: bool,
830
+ now: float | int | None = None,
831
+ ) -> SourceDeliveryStatus:
832
+ self._validate_schema()
833
+ claim = self._claim(claim)
834
+ if not isinstance(code, str) or ERROR_CODE.fullmatch(code) is None:
835
+ code = "source_delivery.client_failure"
836
+ retryable = False
837
+ current = self._now(now)
838
+ with _transaction(self.connection):
839
+ self._current_row(claim, current)
840
+ retry = retryable and claim.attempt < claim.delivery_max_attempts
841
+ delay = min(
842
+ self.max_delay_seconds,
843
+ self.base_delay_seconds * (2 ** (claim.attempt - 1)),
844
+ )
845
+ status = "retry_wait" if retry else "failed"
846
+ next_attempt = current + delay if retry else current
847
+ updated = self.connection.execute("""
848
+ UPDATE cms_source_delivery_outbox
849
+ SET status = ?, next_attempt_at = ?, lease_owner = NULL,
850
+ lease_token = NULL, lease_expires_at = NULL,
851
+ last_error_code = ?, response_sha256 = NULL, updated_at = ?
852
+ WHERE operation = ? AND request_id = ?
853
+ AND status = 'leased' AND lease_token = ?
854
+ """, (
855
+ status, next_attempt, code, current, claim.operation,
856
+ claim.request_id, claim.lease_token,
857
+ ))
858
+ if updated.rowcount != 1:
859
+ raise CMSSourceDeliveryBlocked("source_delivery.claim_lost")
860
+ return self.status(claim.operation, claim.request_id, now=current)
861
+
862
+ def run_once(
863
+ self,
864
+ worker_id: str,
865
+ *,
866
+ lease_seconds: float | int = 600,
867
+ now: float | int | None = None,
868
+ ) -> SourceDeliveryOutcome | None:
869
+ claim = self.claim(
870
+ worker_id, lease_seconds=lease_seconds, now=now,
871
+ )
872
+ if claim is None:
873
+ return None
874
+ try:
875
+ payload = json.loads(claim.payload_json)
876
+ if claim.operation == "change":
877
+ response = self.client.submit_change(
878
+ payload, max_attempts=claim.source_max_attempts,
879
+ )
880
+ else:
881
+ response = self.client.submit_removal(
882
+ payload, max_attempts=claim.source_max_attempts,
883
+ )
884
+ status = self.complete(claim, response)
885
+ except CMSSourceDeliveryBlocked as error:
886
+ if error.code != "source_delivery.response_invalid":
887
+ raise
888
+ status = self._record_failure(
889
+ claim, error.code, retryable=False,
890
+ )
891
+ except Exception as error:
892
+ code, retryable = _error_code(error)
893
+ status = self._record_failure(
894
+ claim, code, retryable=retryable,
895
+ )
896
+ return SourceDeliveryOutcome(
897
+ operation=status.operation,
898
+ request_id=status.request_id,
899
+ event_id=status.event_id,
900
+ status=status.status,
901
+ attempt=status.attempts,
902
+ delivery_max_attempts=status.delivery_max_attempts,
903
+ next_attempt_at=status.next_attempt_at,
904
+ error_code=status.last_error_code,
905
+ )
906
+
907
+ def health(
908
+ self, *, now: float | int | None = None,
909
+ ) -> SourceDeliveryHealth:
910
+ self._validate_schema()
911
+ current = self._now(now)
912
+ try:
913
+ rows = self._validate_rows()
914
+ except CMSSourceDeliveryBlocked:
915
+ return SourceDeliveryHealth(
916
+ schema="blun.cms-source-delivery-health.v1",
917
+ status="blocked",
918
+ counts={}, operations={}, due=0, expired_leases=0,
919
+ failed=0, contract_mismatches=0,
920
+ error_code="source_delivery.integrity",
921
+ )
922
+ counts = {name: 0 for name in STATUSES}
923
+ operations = {name: 0 for name in OPERATIONS}
924
+ due = expired = failed = mismatches = 0
925
+ for row in rows:
926
+ counts[row["status"]] += 1
927
+ operations[row["operation"]] += 1
928
+ if (
929
+ row["status"] in {"pending", "retry_wait"}
930
+ and float(row["next_attempt_at"]) <= current
931
+ ):
932
+ due += 1
933
+ if (
934
+ row["status"] == "leased"
935
+ and float(row["lease_expires_at"]) <= current
936
+ ):
937
+ expired += 1
938
+ if row["status"] == "failed":
939
+ failed += 1
940
+ if (
941
+ row["status"] in ACTIVE_STATUSES
942
+ and row["capabilities_sha256"] != self.capabilities_sha256
943
+ ):
944
+ mismatches += 1
945
+ blocked = failed > 0 or expired > 0 or mismatches > 0
946
+ if failed:
947
+ error = "source_delivery.failed"
948
+ elif expired:
949
+ error = "source_delivery.lease_expired"
950
+ elif mismatches:
951
+ error = "source_delivery.contract_changed"
952
+ else:
953
+ error = None
954
+ return SourceDeliveryHealth(
955
+ schema="blun.cms-source-delivery-health.v1",
956
+ status="blocked" if blocked else "ok",
957
+ counts=counts,
958
+ operations=operations,
959
+ due=due,
960
+ expired_leases=expired,
961
+ failed=failed,
962
+ contract_mismatches=mismatches,
963
+ error_code=error,
964
+ )