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,588 @@
1
+ #!/usr/bin/env python3
2
+ """Secure provider-neutral HTTP publisher for signed CMS localization bundles."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import hashlib
7
+ import importlib.util
8
+ import json
9
+ import re
10
+ import secrets
11
+ import socket
12
+ import sys
13
+ import urllib.error
14
+ import urllib.parse
15
+ import urllib.request
16
+ from dataclasses import dataclass
17
+ from pathlib import Path
18
+ from typing import Any, Callable, Mapping, Protocol
19
+
20
+
21
+ MAX_ENDPOINT_LENGTH = 2048
22
+ MAX_HEADER_VALUE_LENGTH = 4096
23
+ MAX_RESPONSE_BYTES = 65_536
24
+ MAX_REQUEST_BYTES = 4_000_000
25
+ HEADER_NAME = re.compile(r"^[!#$%&'*+.^_`|~0-9A-Za-z-]{1,128}$")
26
+ TOKEN = re.compile(r"^[A-Za-z0-9_.:-]{1,256}$")
27
+ SIGNATURE_VALUE = re.compile(r"^[A-Za-z0-9_.:/+=-]{1,4096}$")
28
+ ERROR_CODE = re.compile(r"^[a-z][a-z0-9_.-]{0,127}$")
29
+ RESERVED_HEADERS = {
30
+ "accept", "accept-encoding", "connection", "content-length", "content-type",
31
+ "host", "idempotency-key", "transfer-encoding", "x-localization-delivery-id",
32
+ "x-localization-payload-sha256",
33
+ }
34
+ PUBLICATION_FIELDS = {
35
+ "schema", "delivery_id", "event_id", "site_id", "website_version", "plan_id",
36
+ "source_id", "source_revision", "source_sequence", "source_sha256", "localizations",
37
+ }
38
+ TOMBSTONE_FIELDS = {
39
+ "schema", "delivery_id", "tombstone_id", "event_id", "site_id",
40
+ "website_version", "plan_id", "source_id", "source_sequence",
41
+ "publication_delivery_id", "publication_payload_sha256", "locales",
42
+ }
43
+
44
+
45
+ def _load_module(name: str, path: Path):
46
+ spec = importlib.util.spec_from_file_location(name, path)
47
+ if spec is None or spec.loader is None:
48
+ raise RuntimeError(f"cannot load required HTTP publisher dependency: {path.name}")
49
+ module = importlib.util.module_from_spec(spec)
50
+ sys.modules[spec.name] = module
51
+ spec.loader.exec_module(module)
52
+ return module
53
+
54
+
55
+ _ROOT = Path(__file__).resolve().parents[1]
56
+ _CMS = _load_module(
57
+ "blun_website_localization_http_publisher_cms",
58
+ _ROOT / "integrations" / "website_localization_cms.py",
59
+ )
60
+ REQUEST_SCHEMA = _CMS.PUBLICATION_HTTP_REQUEST_SCHEMA
61
+ RESPONSE_SCHEMA = _CMS.PUBLICATION_HTTP_RESPONSE_SCHEMA
62
+ TOMBSTONE_REQUEST_SCHEMA = _CMS.TOMBSTONE_HTTP_REQUEST_SCHEMA
63
+ TOMBSTONE_RESPONSE_SCHEMA = _CMS.TOMBSTONE_HTTP_RESPONSE_SCHEMA
64
+ HEALTH_SCHEMA = _CMS.PUBLICATION_HEALTH_SCHEMA
65
+ HEALTH_ACK_SCHEMA = _CMS.PUBLICATION_HEALTH_ACK_SCHEMA
66
+ HEALTH_REQUEST_SCHEMA = _CMS.PUBLICATION_HEALTH_HTTP_REQUEST_SCHEMA
67
+ HEALTH_RESPONSE_SCHEMA = _CMS.PUBLICATION_HEALTH_HTTP_RESPONSE_SCHEMA
68
+ RESERVED_HEADERS.update(
69
+ name.lower() for name, _ in _CMS.PUBLICATION_HTTP_BINDING_HEADERS
70
+ )
71
+ RESERVED_HEADERS.update(
72
+ name.lower() for name, _ in _CMS.PUBLICATION_HEALTH_HTTP_BINDING_HEADERS
73
+ )
74
+
75
+
76
+ class HTTPPublisherFailed(RuntimeError):
77
+ """Content-free failure understood by the durable CMS outbox."""
78
+
79
+ cms_publish_failure = True
80
+
81
+ def __init__(self, code: str, *, retryable: bool):
82
+ if not isinstance(code, str) or ERROR_CODE.fullmatch(code) is None:
83
+ raise ValueError("HTTP publisher error code is invalid")
84
+ if not isinstance(retryable, bool):
85
+ raise ValueError("HTTP publisher retryability must be boolean")
86
+ super().__init__(code)
87
+ self.code = code
88
+ self.retryable = retryable
89
+
90
+
91
+ @dataclass(frozen=True)
92
+ class HTTPResult:
93
+ status: int
94
+ headers: tuple[tuple[str, str], ...]
95
+ body: bytes
96
+
97
+
98
+ class HTTPTransport(Protocol):
99
+ def post(
100
+ self,
101
+ url: str,
102
+ headers: Mapping[str, str],
103
+ body: bytes,
104
+ *,
105
+ timeout: float,
106
+ ) -> HTTPResult: ...
107
+
108
+
109
+ class _NoRedirect(urllib.request.HTTPRedirectHandler):
110
+ def redirect_request(self, req, fp, code, msg, headers, newurl):
111
+ return None
112
+
113
+
114
+ class URLTransport:
115
+ """One bounded stdlib HTTP attempt with redirects disabled."""
116
+
117
+ def __init__(self):
118
+ self._opener = urllib.request.build_opener(_NoRedirect)
119
+
120
+ def post(
121
+ self,
122
+ url: str,
123
+ headers: Mapping[str, str],
124
+ body: bytes,
125
+ *,
126
+ timeout: float,
127
+ ) -> HTTPResult:
128
+ request = urllib.request.Request(
129
+ url,
130
+ data=body,
131
+ headers=dict(headers),
132
+ method="POST",
133
+ )
134
+ try:
135
+ response = self._opener.open(request, timeout=timeout)
136
+ except urllib.error.HTTPError as error:
137
+ response_headers = tuple(error.headers.items()) if error.headers is not None else ()
138
+ return HTTPResult(int(error.code), response_headers, b"")
139
+ except (urllib.error.URLError, TimeoutError, socket.timeout, OSError):
140
+ raise HTTPPublisherFailed("network", retryable=True) from None
141
+ try:
142
+ body = response.read(MAX_RESPONSE_BYTES + 1)
143
+ return HTTPResult(int(response.status), tuple(response.headers.items()), body)
144
+ except (TimeoutError, socket.timeout, OSError):
145
+ raise HTTPPublisherFailed("network", retryable=True) from None
146
+ finally:
147
+ response.close()
148
+
149
+
150
+ def _canonical_json(value: Any, *, code: str, maximum: int) -> bytes:
151
+ try:
152
+ encoded = json.dumps(
153
+ value,
154
+ ensure_ascii=False,
155
+ allow_nan=False,
156
+ sort_keys=True,
157
+ separators=(",", ":"),
158
+ ).encode("utf-8")
159
+ except (TypeError, ValueError, RecursionError):
160
+ raise HTTPPublisherFailed(code, retryable=False) from None
161
+ if not encoded or len(encoded) > maximum:
162
+ raise HTTPPublisherFailed(code, retryable=False)
163
+ return encoded
164
+
165
+
166
+ def _pairs(items):
167
+ result = {}
168
+ for key, value in items:
169
+ if key in result:
170
+ raise ValueError("duplicate JSON key")
171
+ result[key] = value
172
+ return result
173
+
174
+
175
+ def _constant(value):
176
+ raise ValueError("non-finite JSON number")
177
+
178
+
179
+ def _endpoint(value: Any, allow_loopback_http: bool) -> str:
180
+ if (
181
+ not isinstance(value, str)
182
+ or value != value.strip()
183
+ or not value
184
+ or not value.isascii()
185
+ or len(value) > MAX_ENDPOINT_LENGTH
186
+ or any(ord(character) <= 32 or ord(character) == 127 for character in value)
187
+ ):
188
+ raise ValueError("endpoint is invalid")
189
+ try:
190
+ parsed = urllib.parse.urlsplit(value)
191
+ hostname = parsed.hostname
192
+ port = parsed.port
193
+ except ValueError:
194
+ raise ValueError("endpoint is invalid") from None
195
+ if (
196
+ not hostname
197
+ or not hostname.isascii()
198
+ or parsed.username is not None
199
+ or parsed.password is not None
200
+ or parsed.query
201
+ or parsed.fragment
202
+ or not parsed.path.startswith("/")
203
+ or parsed.path.startswith("//")
204
+ ):
205
+ raise ValueError("endpoint is invalid")
206
+ if parsed.scheme == "https":
207
+ pass
208
+ elif (
209
+ parsed.scheme == "http"
210
+ and allow_loopback_http
211
+ and hostname.lower() in {"localhost", "127.0.0.1", "::1"}
212
+ ):
213
+ pass
214
+ else:
215
+ raise ValueError("endpoint must use HTTPS")
216
+ if port is not None and not 1 <= port <= 65535:
217
+ raise ValueError("endpoint is invalid")
218
+ return value
219
+
220
+
221
+ def _authentication_headers(provider: Callable[[], Mapping[str, str]]) -> dict[str, str]:
222
+ try:
223
+ supplied = provider()
224
+ except Exception:
225
+ raise HTTPPublisherFailed("authentication", retryable=False) from None
226
+ if not isinstance(supplied, Mapping) or not supplied:
227
+ raise HTTPPublisherFailed("authentication", retryable=False)
228
+ result: dict[str, str] = {}
229
+ normalized_names: set[str] = set()
230
+ for name, value in supplied.items():
231
+ normalized = name.lower() if isinstance(name, str) else ""
232
+ if (
233
+ not isinstance(name, str)
234
+ or HEADER_NAME.fullmatch(name) is None
235
+ or normalized in RESERVED_HEADERS
236
+ or normalized in normalized_names
237
+ ):
238
+ raise HTTPPublisherFailed("authentication", retryable=False)
239
+ if (
240
+ not isinstance(value, str)
241
+ or not value
242
+ or not value.isascii()
243
+ or len(value) > MAX_HEADER_VALUE_LENGTH
244
+ or "\r" in value
245
+ or "\n" in value
246
+ or any(ord(character) < 32 or ord(character) == 127 for character in value)
247
+ ):
248
+ raise HTTPPublisherFailed("authentication", retryable=False)
249
+ normalized_names.add(normalized)
250
+ result[name] = value
251
+ return result
252
+
253
+
254
+ def _signature(value: Any) -> tuple[_CMS.CMSMessageSignature, dict[str, str]]:
255
+ try:
256
+ algorithm = value.algorithm
257
+ key_id = value.key_id
258
+ signature = value.signature
259
+ except Exception:
260
+ raise HTTPPublisherFailed("request_invalid", retryable=False) from None
261
+ if (
262
+ not isinstance(algorithm, str)
263
+ or TOKEN.fullmatch(algorithm) is None
264
+ or not isinstance(key_id, str)
265
+ or TOKEN.fullmatch(key_id) is None
266
+ or not isinstance(signature, str)
267
+ or SIGNATURE_VALUE.fullmatch(signature) is None
268
+ ):
269
+ raise HTTPPublisherFailed("request_invalid", retryable=False)
270
+ return (
271
+ _CMS.CMSMessageSignature(algorithm, key_id, signature),
272
+ {"algorithm": algorithm, "key_id": key_id, "signature": signature},
273
+ )
274
+
275
+
276
+ def _response_headers(value: Any) -> dict[str, str]:
277
+ if not isinstance(value, tuple):
278
+ raise HTTPPublisherFailed("transport_invalid", retryable=True)
279
+ result: dict[str, str] = {}
280
+ for item in value:
281
+ if (
282
+ not isinstance(item, tuple)
283
+ or len(item) != 2
284
+ or not all(isinstance(part, str) for part in item)
285
+ ):
286
+ raise HTTPPublisherFailed("transport_invalid", retryable=True)
287
+ name, content = item[0].lower(), item[1].strip()
288
+ if name in {"content-type", "content-length"}:
289
+ if name in result:
290
+ raise HTTPPublisherFailed("response_headers", retryable=True)
291
+ result[name] = content
292
+ return result
293
+
294
+
295
+ class HTTPPublisherAdapter:
296
+ """Publish one exact signed outbox bundle and verify one signed CMS acknowledgement."""
297
+
298
+ def __init__(
299
+ self,
300
+ endpoint: str,
301
+ authentication_headers: Callable[[], Mapping[str, str]],
302
+ acknowledgement_verifier: Any,
303
+ *,
304
+ transport: HTTPTransport | None = None,
305
+ timeout: float = 30.0,
306
+ allow_loopback_http: bool = False,
307
+ probe_id_factory: Callable[[], str] | None = None,
308
+ ):
309
+ if not isinstance(allow_loopback_http, bool):
310
+ raise TypeError("allow_loopback_http must be boolean")
311
+ self.endpoint = _endpoint(endpoint, allow_loopback_http)
312
+ if not callable(authentication_headers):
313
+ raise TypeError("authentication_headers must be callable")
314
+ if not callable(getattr(acknowledgement_verifier, "verify", None)):
315
+ raise TypeError("acknowledgement_verifier must provide verify")
316
+ if (
317
+ isinstance(timeout, bool)
318
+ or not isinstance(timeout, (int, float))
319
+ or not 0 < timeout <= 300
320
+ ):
321
+ raise ValueError("timeout is outside the supported range")
322
+ self.authentication_headers = authentication_headers
323
+ self.acknowledgement_verifier = acknowledgement_verifier
324
+ self.transport = URLTransport() if transport is None else transport
325
+ if not callable(getattr(self.transport, "post", None)):
326
+ raise TypeError("transport must provide post")
327
+ self.timeout = float(timeout)
328
+ self.probe_id_factory = (
329
+ secrets.token_hex if probe_id_factory is None else probe_id_factory
330
+ )
331
+ if not callable(self.probe_id_factory):
332
+ raise TypeError("probe_id_factory must be callable")
333
+
334
+ def publish(self, request: Any) -> Mapping[str, Any]:
335
+ try:
336
+ delivery_id = request.delivery_id
337
+ payload = request.payload
338
+ payload_sha256 = request.payload_sha256
339
+ raw_signature = request.signature
340
+ except Exception:
341
+ raise HTTPPublisherFailed("request_invalid", retryable=False) from None
342
+ tombstone = isinstance(payload, dict) and payload.get("schema") == _CMS.TOMBSTONE_DELIVERY_SCHEMA
343
+ expected_fields = TOMBSTONE_FIELDS if tombstone else PUBLICATION_FIELDS
344
+ if (
345
+ not isinstance(delivery_id, str)
346
+ or TOKEN.fullmatch(delivery_id) is None
347
+ or not isinstance(payload_sha256, str)
348
+ or re.fullmatch(r"[a-f0-9]{64}", payload_sha256) is None
349
+ or not isinstance(payload, dict)
350
+ or set(payload) != expected_fields
351
+ or payload.get("schema") not in {
352
+ _CMS.PUBLICATION_SCHEMA, _CMS.TOMBSTONE_DELIVERY_SCHEMA,
353
+ }
354
+ or payload.get("delivery_id") != delivery_id
355
+ or isinstance(payload.get("source_sequence"), bool)
356
+ or not isinstance(payload.get("source_sequence"), int)
357
+ or payload["source_sequence"] <= 0
358
+ or not isinstance(
359
+ payload.get("locales") if tombstone else payload.get("localizations"),
360
+ list,
361
+ )
362
+ or not (payload.get("locales") if tombstone else payload.get("localizations"))
363
+ ):
364
+ raise HTTPPublisherFailed("request_invalid", retryable=False)
365
+ if tombstone and (
366
+ payload["locales"] != sorted(set(payload["locales"]))
367
+ or any(
368
+ not isinstance(locale, str) or TOKEN.fullmatch(locale) is None
369
+ for locale in payload["locales"]
370
+ )
371
+ or not isinstance(payload.get("publication_payload_sha256"), str)
372
+ or re.fullmatch(
373
+ r"[a-f0-9]{64}", payload["publication_payload_sha256"],
374
+ ) is None
375
+ ):
376
+ raise HTTPPublisherFailed("request_invalid", retryable=False)
377
+ payload_bytes = _canonical_json(
378
+ payload,
379
+ code="request_invalid",
380
+ maximum=MAX_REQUEST_BYTES,
381
+ )
382
+ if hashlib.sha256(payload_bytes).hexdigest() != payload_sha256:
383
+ raise HTTPPublisherFailed("request_binding", retryable=False)
384
+ _, signature_payload = _signature(raw_signature)
385
+ body = _canonical_json(
386
+ {
387
+ "schema": TOMBSTONE_REQUEST_SCHEMA if tombstone else REQUEST_SCHEMA,
388
+ "payload_sha256": payload_sha256,
389
+ "tombstone" if tombstone else "publication": payload,
390
+ "signature": signature_payload,
391
+ },
392
+ code="request_invalid",
393
+ maximum=MAX_REQUEST_BYTES,
394
+ )
395
+ headers = _authentication_headers(self.authentication_headers)
396
+ binding_values = {
397
+ "delivery_id": delivery_id,
398
+ "payload_sha256": payload_sha256,
399
+ }
400
+ try:
401
+ protocol_headers = {
402
+ name: binding_values[binding]
403
+ for name, binding in _CMS.PUBLICATION_HTTP_BINDING_HEADERS
404
+ }
405
+ except (KeyError, TypeError, ValueError):
406
+ raise HTTPPublisherFailed("request_invalid", retryable=False) from None
407
+ headers.update({
408
+ "Accept": "application/json",
409
+ "Accept-Encoding": "identity",
410
+ "Content-Type": "application/json; charset=utf-8",
411
+ **protocol_headers,
412
+ })
413
+ envelope = self._post_json(headers, body)
414
+ if not isinstance(envelope, dict) or set(envelope) != {
415
+ "schema", "acknowledgement", "signature",
416
+ }:
417
+ raise HTTPPublisherFailed("acknowledgement_invalid", retryable=False)
418
+ acknowledgement = envelope["acknowledgement"]
419
+ expected = {
420
+ "schema": _CMS.TOMBSTONE_ACK_SCHEMA if tombstone else _CMS.ACK_SCHEMA,
421
+ "delivery_id": delivery_id,
422
+ "payload_sha256": payload_sha256,
423
+ "status": "deleted" if tombstone else "accepted",
424
+ }
425
+ expected_response_schema = (
426
+ TOMBSTONE_RESPONSE_SCHEMA if tombstone else RESPONSE_SCHEMA
427
+ )
428
+ if envelope["schema"] != expected_response_schema or acknowledgement != expected:
429
+ raise HTTPPublisherFailed("acknowledgement_binding", retryable=False)
430
+ signature_mapping = envelope["signature"]
431
+ if not isinstance(signature_mapping, dict) or set(signature_mapping) != {
432
+ "algorithm", "key_id", "signature",
433
+ }:
434
+ raise HTTPPublisherFailed("acknowledgement_invalid", retryable=False)
435
+ try:
436
+ acknowledgement_signature, _ = _signature(type("Signature", (), signature_mapping)())
437
+ except HTTPPublisherFailed:
438
+ raise HTTPPublisherFailed("acknowledgement_invalid", retryable=False) from None
439
+ acknowledgement_bytes = _canonical_json(
440
+ acknowledgement,
441
+ code="acknowledgement_invalid",
442
+ maximum=MAX_RESPONSE_BYTES,
443
+ )
444
+ try:
445
+ verified = self.acknowledgement_verifier.verify(
446
+ acknowledgement_bytes,
447
+ acknowledgement_signature,
448
+ ) is True
449
+ except Exception:
450
+ verified = False
451
+ if not verified:
452
+ raise HTTPPublisherFailed("acknowledgement_signature", retryable=False)
453
+ return acknowledgement
454
+
455
+ def check(self, *, contract_sha256: str) -> Mapping[str, Any]:
456
+ """Challenge the configured receiver without sending localized content."""
457
+ if (
458
+ not isinstance(contract_sha256, str)
459
+ or re.fullmatch(r"[a-f0-9]{64}", contract_sha256) is None
460
+ ):
461
+ raise HTTPPublisherFailed("health_request_invalid", retryable=False)
462
+ try:
463
+ probe_id = self.probe_id_factory()
464
+ except Exception:
465
+ raise HTTPPublisherFailed("health_request_invalid", retryable=False) from None
466
+ if (
467
+ not isinstance(probe_id, str)
468
+ or not 16 <= len(probe_id) <= 256
469
+ or TOKEN.fullmatch(probe_id) is None
470
+ ):
471
+ raise HTTPPublisherFailed("health_request_invalid", retryable=False)
472
+ probe = {
473
+ "schema": HEALTH_SCHEMA,
474
+ "probe_id": probe_id,
475
+ "contract_sha256": contract_sha256,
476
+ }
477
+ body = _canonical_json(
478
+ {"schema": HEALTH_REQUEST_SCHEMA, "probe": probe},
479
+ code="health_request_invalid",
480
+ maximum=MAX_REQUEST_BYTES,
481
+ )
482
+ headers = _authentication_headers(self.authentication_headers)
483
+ bindings = {"probe_id": probe_id, "contract_sha256": contract_sha256}
484
+ try:
485
+ protocol_headers = {
486
+ name: bindings[binding]
487
+ for name, binding in _CMS.PUBLICATION_HEALTH_HTTP_BINDING_HEADERS
488
+ }
489
+ except (KeyError, TypeError, ValueError):
490
+ raise HTTPPublisherFailed("health_request_invalid", retryable=False) from None
491
+ headers.update({
492
+ "Accept": "application/json",
493
+ "Accept-Encoding": "identity",
494
+ "Content-Type": "application/json; charset=utf-8",
495
+ **protocol_headers,
496
+ })
497
+ envelope = self._post_json(headers, body)
498
+ if not isinstance(envelope, dict) or set(envelope) != {
499
+ "schema", "acknowledgement", "signature",
500
+ }:
501
+ raise HTTPPublisherFailed(
502
+ "health_acknowledgement_invalid", retryable=False,
503
+ )
504
+ acknowledgement = envelope["acknowledgement"]
505
+ expected = {
506
+ "schema": HEALTH_ACK_SCHEMA,
507
+ "probe_id": probe_id,
508
+ "contract_sha256": contract_sha256,
509
+ "status": "healthy",
510
+ }
511
+ if envelope["schema"] != HEALTH_RESPONSE_SCHEMA or acknowledgement != expected:
512
+ raise HTTPPublisherFailed(
513
+ "health_acknowledgement_binding", retryable=False,
514
+ )
515
+ signature_mapping = envelope["signature"]
516
+ if not isinstance(signature_mapping, dict) or set(signature_mapping) != {
517
+ "algorithm", "key_id", "signature",
518
+ }:
519
+ raise HTTPPublisherFailed(
520
+ "health_acknowledgement_invalid", retryable=False,
521
+ )
522
+ try:
523
+ signature, _ = _signature(type("Signature", (), signature_mapping)())
524
+ acknowledgement_bytes = _canonical_json(
525
+ acknowledgement,
526
+ code="health_acknowledgement_invalid",
527
+ maximum=MAX_RESPONSE_BYTES,
528
+ )
529
+ verified = self.acknowledgement_verifier.verify(
530
+ acknowledgement_bytes, signature,
531
+ ) is True
532
+ except Exception:
533
+ verified = False
534
+ if not verified:
535
+ raise HTTPPublisherFailed(
536
+ "health_acknowledgement_signature", retryable=False,
537
+ )
538
+ return acknowledgement
539
+
540
+ def _post_json(self, headers: Mapping[str, str], body: bytes) -> Any:
541
+ try:
542
+ result = self.transport.post(
543
+ self.endpoint, headers, body, timeout=self.timeout,
544
+ )
545
+ except HTTPPublisherFailed:
546
+ raise
547
+ except Exception:
548
+ raise HTTPPublisherFailed("network", retryable=True) from None
549
+ if (
550
+ not isinstance(result, HTTPResult)
551
+ or isinstance(result.status, bool)
552
+ or not isinstance(result.status, int)
553
+ or not 100 <= result.status <= 599
554
+ ):
555
+ raise HTTPPublisherFailed("transport_invalid", retryable=True)
556
+ if result.status != 200:
557
+ if 300 <= result.status <= 399:
558
+ raise HTTPPublisherFailed("redirect", retryable=False)
559
+ retryable = result.status in {408, 425, 429} or 500 <= result.status <= 599
560
+ raise HTTPPublisherFailed("http_status", retryable=retryable)
561
+ response_headers = _response_headers(result.headers)
562
+ content_type = (
563
+ response_headers.get("content-type", "").lower().replace(" ", "")
564
+ )
565
+ if content_type not in {"application/json", "application/json;charset=utf-8"}:
566
+ raise HTTPPublisherFailed("response_content_type", retryable=True)
567
+ if (
568
+ not isinstance(result.body, bytes)
569
+ or not result.body
570
+ or len(result.body) > MAX_RESPONSE_BYTES
571
+ ):
572
+ raise HTTPPublisherFailed("response_size", retryable=True)
573
+ declared = response_headers.get("content-length")
574
+ if declared is not None and (
575
+ not declared.isascii()
576
+ or not declared.isdecimal()
577
+ or int(declared) != len(result.body)
578
+ ):
579
+ raise HTTPPublisherFailed("response_size", retryable=True)
580
+ try:
581
+ text = result.body.decode("utf-8")
582
+ if text.startswith("\ufeff"):
583
+ raise ValueError("BOM rejected")
584
+ return json.loads(
585
+ text, object_pairs_hook=_pairs, parse_constant=_constant,
586
+ )
587
+ except (UnicodeDecodeError, json.JSONDecodeError, ValueError, RecursionError):
588
+ raise HTTPPublisherFailed("response_json", retryable=True) from None