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,435 @@
1
+ #!/usr/bin/env python3
2
+ """Isolated signer/verifier service for mandatory language-gated delivery."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import argparse
7
+ import hashlib
8
+ import hmac
9
+ import importlib.util
10
+ import json
11
+ import os
12
+ import re
13
+ import signal
14
+ import socket
15
+ import socketserver
16
+ import stat
17
+ import sys
18
+ import threading
19
+ import time
20
+ from pathlib import Path
21
+ from typing import Any
22
+
23
+
24
+ ROOT = Path(__file__).resolve().parents[1]
25
+ GATEWAY_PATH = ROOT / "integrations" / "language_gateway.py"
26
+ AUDIT_PATH = ROOT / "integrations" / "audit_log.py"
27
+ CLIENT_PATH = ROOT / "translate-native" / "scripts" / "guard_service_client.py"
28
+
29
+
30
+ def _load(name: str, path: Path):
31
+ spec = importlib.util.spec_from_file_location(name, path)
32
+ if not spec or not spec.loader:
33
+ raise RuntimeError(f"Cannot load {path.name}")
34
+ module = importlib.util.module_from_spec(spec)
35
+ sys.modules[name] = module
36
+ spec.loader.exec_module(module)
37
+ return module
38
+
39
+
40
+ GATEWAY = _load("blun_isolated_gateway", GATEWAY_PATH)
41
+ AUDIT = _load("blun_isolated_audit", AUDIT_PATH)
42
+ CLIENT = _load("blun_isolated_client", CLIENT_PATH)
43
+ QUALITY = GATEWAY.GUARD.QUALITY
44
+ MAX_REQUEST_BYTES = 8 * 1024 * 1024
45
+
46
+
47
+ class GuardProtocolError(ValueError):
48
+ """Raised for malformed or unauthorized local service requests."""
49
+
50
+
51
+ def _exact_string(payload: dict[str, Any], name: str, *, required: bool = True) -> str:
52
+ value = payload.get(name, "")
53
+ if not isinstance(value, str) or (required and not value.strip()):
54
+ raise GuardProtocolError(f"{name} must be a string")
55
+ return value
56
+
57
+
58
+ def _content_type(payload: dict[str, Any]) -> str:
59
+ value = payload.get("content_type", "prose")
60
+ if not isinstance(value, str) or not value.strip():
61
+ raise GuardProtocolError("content_type must be a string")
62
+ return value
63
+
64
+
65
+ def _exact_hash(payload: dict[str, Any], name: str) -> str:
66
+ value = _exact_string(payload, name)
67
+ if re.fullmatch(r"[0-9a-f]{64}", value) is None:
68
+ raise GuardProtocolError(f"{name} must be a lowercase SHA-256 hash")
69
+ return value
70
+
71
+
72
+ def _decision_audit(request: dict[str, Any], result: dict[str, Any], event: str) -> dict[str, Any]:
73
+ source = request.get("source_text", "") if isinstance(request.get("source_text", ""), str) else ""
74
+ target = request.get("target_text", "") if isinstance(request.get("target_text", ""), str) else ""
75
+ return {
76
+ "event": event,
77
+ "allowed": result.get("release_allowed") is True or result.get("valid") is True,
78
+ "task_kind": request.get("task_kind"),
79
+ "language": request.get("language"),
80
+ "agent_id": request.get("agent_id"),
81
+ "channel": request.get("channel"),
82
+ "source_sha256": QUALITY.canonical_hash(source) if source else "",
83
+ "target_sha256": QUALITY.canonical_hash(target) if target else "",
84
+ "guard_version": QUALITY.VERSION,
85
+ "codes": AUDIT.finding_codes(result),
86
+ }
87
+
88
+
89
+ class GuardService:
90
+ def __init__(self, key_path: Path, audit_path: Path, service_token: str = "") -> None:
91
+ self.key_path = key_path
92
+ self.audit_path = audit_path
93
+ self.service_token = service_token
94
+ self.key = QUALITY.load_or_create_key(key_path)
95
+ self.boot_id = QUALITY._b64encode(os.urandom(12))
96
+ self.consumed_delivery_nonces: dict[str, int] = {}
97
+ self.session_epochs: dict[str, str] = {}
98
+ self.session_epoch_history: dict[str, set[str]] = {}
99
+ self.delivery_lock = threading.Lock()
100
+ if os.name != "nt" and key_path.stat().st_mode & 0o077:
101
+ raise RuntimeError("guard signing key permissions must be owner-only")
102
+ GATEWAY.GUARD.KEY_PATH = key_path
103
+ GATEWAY.GUARD.SERVICE_ENDPOINT = ""
104
+
105
+ def _health_self_test(self) -> dict[str, bool]:
106
+ """Exercise the real response gate and signer without writing a canary audit record."""
107
+ target = "Hälsokontrollen är aktiv."
108
+ audit_paths = AUDIT.audit_paths_healthy(self.audit_path)
109
+ try:
110
+ released = GATEWAY.gate({
111
+ "task_kind": "response",
112
+ "source_text": "",
113
+ "target_text": target,
114
+ "language": "sv-SE",
115
+ "attestations": {"nativeness": True, "orthography": True},
116
+ })
117
+ release_ok = released.get("release_allowed") is True
118
+ token = released.get("release_token", "") if release_ok else ""
119
+ verified = QUALITY.verify_receipt(
120
+ token, "", target, "sv-SE", self.key, purpose="response"
121
+ )
122
+ tampered = QUALITY.verify_receipt(
123
+ token, "", target + " Ändrad.", "sv-SE", self.key, purpose="response"
124
+ )
125
+ return {
126
+ "release": release_ok,
127
+ "signature": verified.get("valid") is True,
128
+ "tamper_blocked": tampered.get("valid") is False,
129
+ "audit_paths": audit_paths,
130
+ }
131
+ except Exception:
132
+ return {
133
+ "release": False,
134
+ "signature": False,
135
+ "tamper_blocked": False,
136
+ "audit_paths": audit_paths,
137
+ }
138
+
139
+ @staticmethod
140
+ def _identity_hash(value: str) -> str:
141
+ return hashlib.sha256(value.encode("utf-8")).hexdigest()
142
+
143
+ def _verify_release(self, request: dict[str, Any]) -> tuple[str, str, dict[str, Any]]:
144
+ task_kind = _exact_string(request, "task_kind")
145
+ if task_kind not in {"response", "translation"}:
146
+ raise GuardProtocolError("invalid task_kind")
147
+ source = _exact_string(request, "source_text", required=False)
148
+ if task_kind == "translation" and not source.strip():
149
+ raise GuardProtocolError("translation verification requires source_text")
150
+ if task_kind == "response" and source:
151
+ raise GuardProtocolError("response verification cannot contain source_text")
152
+ result = QUALITY.verify_receipt(
153
+ _exact_string(request, "release_token"),
154
+ source,
155
+ _exact_string(request, "target_text"),
156
+ _exact_string(request, "language"),
157
+ self.key,
158
+ _content_type(request),
159
+ request.get("short_text_reviewed") is True,
160
+ purpose=task_kind,
161
+ )
162
+ return task_kind, source, result
163
+
164
+ def _issue_delivery_grant(self, request: dict[str, Any], task_kind: str) -> str:
165
+ now = int(time.time())
166
+ payload = {
167
+ "v": QUALITY.VERSION,
168
+ "boot": self.boot_id,
169
+ "source_sha256": QUALITY.canonical_hash(_exact_string(request, "source_text", required=False)),
170
+ "target_sha256": QUALITY.canonical_hash(_exact_string(request, "target_text")),
171
+ "session_sha256": self._identity_hash(_exact_string(request, "session_id")),
172
+ "session_epoch_sha256": self._identity_hash(_exact_string(request, "session_epoch")),
173
+ "agent_sha256": self._identity_hash(_exact_string(request, "agent_id")),
174
+ "language": _exact_string(request, "language"),
175
+ "purpose": task_kind,
176
+ "content_type": _content_type(request),
177
+ "short_text_reviewed": request.get("short_text_reviewed") is True,
178
+ "channel": _exact_string(request, "channel"),
179
+ "iat": now,
180
+ "exp": now + 600,
181
+ "nonce": QUALITY._b64encode(os.urandom(16)),
182
+ }
183
+ encoded = QUALITY._b64encode(
184
+ json.dumps(payload, sort_keys=True, separators=(",", ":")).encode("utf-8")
185
+ )
186
+ signature = QUALITY._b64encode(hmac.new(self.key, encoded.encode("ascii"), hashlib.sha256).digest())
187
+ return f"blgd2.{encoded}.{signature}"
188
+
189
+ def _register_session_epoch(self, request: dict[str, Any]) -> dict[str, Any]:
190
+ session_hash = self._identity_hash(_exact_string(request, "session_id"))
191
+ epoch = _exact_string(request, "session_epoch")
192
+ if re.fullmatch(r"[0-9a-f]{64}", epoch) is None:
193
+ raise GuardProtocolError("session_epoch must be 64 lowercase hexadecimal characters")
194
+ epoch_hash = self._identity_hash(epoch)
195
+ with self.delivery_lock:
196
+ history = self.session_epoch_history.setdefault(session_hash, set())
197
+ if epoch_hash in history:
198
+ return {"status": "BLOCK", "registered": False}
199
+ history.add(epoch_hash)
200
+ self.session_epochs[session_hash] = epoch_hash
201
+ return {"status": "PASS", "registered": True}
202
+
203
+ def _retire_session_epoch(self, request: dict[str, Any]) -> dict[str, Any]:
204
+ session_hash = self._identity_hash(_exact_string(request, "session_id"))
205
+ epoch = _exact_string(request, "session_epoch")
206
+ if re.fullmatch(r"[0-9a-f]{64}", epoch) is None:
207
+ raise GuardProtocolError("session_epoch must be 64 lowercase hexadecimal characters")
208
+ expected_epoch_hash = self._identity_hash(epoch)
209
+ tombstone_hash = self._identity_hash(os.urandom(32).hex())
210
+ with self.delivery_lock:
211
+ if self.session_epochs.get(session_hash) != expected_epoch_hash:
212
+ return {"status": "BLOCK", "retired": False}
213
+ history = self.session_epoch_history.setdefault(session_hash, set())
214
+ history.add(tombstone_hash)
215
+ self.session_epochs[session_hash] = tombstone_hash
216
+ return {"status": "PASS", "retired": True}
217
+
218
+ def _authorize_delivery(self, request: dict[str, Any], task_kind: str) -> dict[str, Any]:
219
+ session_hash = self._identity_hash(_exact_string(request, "session_id"))
220
+ epoch = _exact_string(request, "session_epoch")
221
+ if re.fullmatch(r"[0-9a-f]{64}", epoch) is None:
222
+ raise GuardProtocolError("session_epoch must be 64 lowercase hexadecimal characters")
223
+ epoch_hash = self._identity_hash(epoch)
224
+ with self.delivery_lock:
225
+ current_epoch = self.session_epochs.get(session_hash)
226
+ history = self.session_epoch_history.setdefault(session_hash, set())
227
+ if current_epoch is None and epoch_hash not in history:
228
+ history.add(epoch_hash)
229
+ self.session_epochs[session_hash] = epoch_hash
230
+ current_epoch = epoch_hash
231
+ if current_epoch != epoch_hash:
232
+ return {
233
+ "valid": False,
234
+ "status": "BLOCK",
235
+ "checks": {"session_epoch_current": False},
236
+ }
237
+ return {
238
+ "valid": True,
239
+ "status": "PASS",
240
+ "delivery_grant": self._issue_delivery_grant(request, task_kind),
241
+ "expires_in": 600,
242
+ }
243
+
244
+ def _consume_delivery_grant(self, request: dict[str, Any]) -> dict[str, Any]:
245
+ try:
246
+ prefix, encoded, signature = _exact_string(request, "delivery_grant").split(".")
247
+ expected = QUALITY._b64encode(hmac.new(self.key, encoded.encode("ascii"), hashlib.sha256).digest())
248
+ if prefix != "blgd2" or not hmac.compare_digest(signature, expected):
249
+ raise ValueError("invalid delivery grant signature")
250
+ payload = json.loads(QUALITY._b64decode(encoded))
251
+ if not isinstance(payload, dict):
252
+ raise ValueError("invalid delivery grant payload")
253
+ nonce = payload.get("nonce")
254
+ if not isinstance(nonce, str) or not nonce:
255
+ raise ValueError("invalid delivery grant nonce")
256
+ now = int(time.time())
257
+ session_hash = self._identity_hash(_exact_string(request, "session_id"))
258
+ epoch_hash = self._identity_hash(_exact_string(request, "session_epoch"))
259
+ checks = {
260
+ "target": payload.get("target_sha256") == QUALITY.canonical_hash(_exact_string(request, "target_text")),
261
+ "source": payload.get("source_sha256") == _exact_hash(request, "source_sha256"),
262
+ "session": payload.get("session_sha256") == session_hash,
263
+ "session_epoch": payload.get("session_epoch_sha256") == epoch_hash,
264
+ "agent": payload.get("agent_sha256") == self._identity_hash(_exact_string(request, "agent_id")),
265
+ "language": payload.get("language") == _exact_string(request, "language"),
266
+ "purpose": payload.get("purpose") == _exact_string(request, "task_kind"),
267
+ "content_type": payload.get("content_type") == _content_type(request),
268
+ "short_text_reviewed": payload.get("short_text_reviewed") is (request.get("short_text_reviewed") is True),
269
+ "channel": payload.get("channel") == _exact_string(request, "channel"),
270
+ "version": payload.get("v") == QUALITY.VERSION,
271
+ "service_boot": payload.get("boot") == self.boot_id,
272
+ "not_expired": int(payload.get("exp", 0)) >= now,
273
+ }
274
+ with self.delivery_lock:
275
+ checks["session_epoch_current"] = self.session_epochs.get(session_hash) == epoch_hash
276
+ self.consumed_delivery_nonces = {
277
+ used_nonce: expiry
278
+ for used_nonce, expiry in self.consumed_delivery_nonces.items()
279
+ if expiry >= now
280
+ }
281
+ checks["one_time"] = nonce not in self.consumed_delivery_nonces
282
+ identity_valid = all(
283
+ checks[name]
284
+ for name in ("session", "session_epoch", "session_epoch_current", "agent", "version", "service_boot", "not_expired", "one_time")
285
+ )
286
+ valid = all(checks.values())
287
+ if identity_valid:
288
+ self.consumed_delivery_nonces[nonce] = int(payload["exp"])
289
+ return {"valid": valid, "status": "PASS" if valid else "BLOCK", "checks": checks}
290
+ except (ValueError, TypeError, KeyError, json.JSONDecodeError, UnicodeDecodeError) as error:
291
+ return {"valid": False, "status": "BLOCK", "error": str(error)}
292
+
293
+ def _authorize(self, request: dict[str, Any]) -> None:
294
+ supplied = request.pop("service_token", "")
295
+ if self.service_token and (
296
+ not isinstance(supplied, str)
297
+ or not hmac.compare_digest(supplied, self.service_token)
298
+ ):
299
+ raise GuardProtocolError("unauthorized")
300
+
301
+ def handle(self, raw_request: dict[str, Any]) -> dict[str, Any]:
302
+ if not isinstance(raw_request, dict):
303
+ raise GuardProtocolError("request must be an object")
304
+ request = dict(raw_request)
305
+ self._authorize(request)
306
+ operation = request.pop("operation", "")
307
+ if operation == "health":
308
+ self_test = self._health_self_test()
309
+ healthy = all(self_test.values())
310
+ return {
311
+ "status": "ok" if healthy else "BLOCK",
312
+ "service": "blun-language-guard",
313
+ "version": QUALITY.VERSION,
314
+ "isolated_key": healthy,
315
+ "self_test": self_test,
316
+ }
317
+ if operation == "release":
318
+ result = GATEWAY.gate(request)
319
+ AUDIT.append_audit(self.audit_path, _decision_audit(request, result, "release"))
320
+ return result
321
+ if operation == "verify":
322
+ _, _, result = self._verify_release(request)
323
+ result["status"] = "PASS" if result.get("valid") else "BLOCK"
324
+ AUDIT.append_audit(self.audit_path, _decision_audit(request, result, "verify"))
325
+ return result
326
+ if operation == "register_session_epoch":
327
+ return self._register_session_epoch(request)
328
+ if operation == "retire_session_epoch":
329
+ return self._retire_session_epoch(request)
330
+ if operation == "authorize_delivery":
331
+ task_kind, _, result = self._verify_release(request)
332
+ if result.get("valid"):
333
+ result = self._authorize_delivery(request, task_kind)
334
+ else:
335
+ result["status"] = "BLOCK"
336
+ AUDIT.append_audit(self.audit_path, _decision_audit(request, result, "authorize-delivery"))
337
+ return result
338
+ if operation == "consume_delivery":
339
+ result = self._consume_delivery_grant(request)
340
+ AUDIT.append_audit(self.audit_path, _decision_audit(request, result, "consume-delivery"))
341
+ return result
342
+ raise GuardProtocolError("unknown operation")
343
+
344
+
345
+ class _RequestHandler(socketserver.StreamRequestHandler):
346
+ def handle(self) -> None:
347
+ try:
348
+ raw = self.rfile.readline(MAX_REQUEST_BYTES + 1)
349
+ if len(raw) > MAX_REQUEST_BYTES:
350
+ raise GuardProtocolError("request too large")
351
+ request = json.loads(raw.decode("utf-8-sig"))
352
+ response = self.server.guard_service.handle(request) # type: ignore[attr-defined]
353
+ except (GuardProtocolError, UnicodeDecodeError, json.JSONDecodeError) as error:
354
+ response = {"status": "BLOCK", "release_allowed": False, "error": str(error)}
355
+ except Exception:
356
+ response = {"status": "BLOCK", "release_allowed": False, "error": "internal guard failure"}
357
+ encoded = (json.dumps(response, ensure_ascii=False, separators=(",", ":")) + "\n").encode("utf-8")
358
+ self.wfile.write(encoded)
359
+
360
+
361
+ class _ThreadingTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
362
+ allow_reuse_address = True
363
+ daemon_threads = True
364
+
365
+
366
+ if hasattr(socketserver, "UnixStreamServer"):
367
+ class _ThreadingUnixServer(socketserver.ThreadingMixIn, socketserver.UnixStreamServer): # type: ignore[misc]
368
+ daemon_threads = True
369
+
370
+
371
+ def _token_from_file(path: Path | None) -> str:
372
+ if path is None:
373
+ return ""
374
+ return CLIENT.load_service_token(path)
375
+
376
+
377
+ def build_server(endpoint: str, service: GuardService):
378
+ transport, address = CLIENT.parse_endpoint(endpoint)
379
+ if transport == "unix":
380
+ if not hasattr(socketserver, "UnixStreamServer"):
381
+ raise RuntimeError("Unix sockets are unavailable")
382
+ socket_path = Path(str(address))
383
+ socket_path.parent.mkdir(parents=True, exist_ok=True)
384
+ if socket_path.exists() or socket_path.is_symlink():
385
+ mode = socket_path.lstat().st_mode
386
+ if not stat.S_ISSOCK(mode):
387
+ raise RuntimeError(f"refusing to replace non-socket path: {socket_path}")
388
+ socket_path.unlink()
389
+ server = _ThreadingUnixServer(str(socket_path), _RequestHandler) # type: ignore[name-defined]
390
+ os.chmod(socket_path, 0o660)
391
+ server.socket_path = socket_path
392
+ else:
393
+ server = _ThreadingTCPServer(address, _RequestHandler)
394
+ server.socket_path = None
395
+ server.guard_service = service
396
+ return server
397
+
398
+
399
+ def main() -> int:
400
+ parser = argparse.ArgumentParser(description="Run the isolated BLUN Language Guard signer")
401
+ default_runtime = Path.home() / ".config" / "blun-language-guard"
402
+ parser.add_argument("--endpoint", default=f"unix:{default_runtime / 'guard.sock'}" if os.name != "nt" else "tcp:127.0.0.1:47631")
403
+ parser.add_argument("--key-file", type=Path, default=default_runtime / "signing.key")
404
+ parser.add_argument("--token-file", type=Path)
405
+ parser.add_argument("--audit-file", type=Path, default=default_runtime / "audit.jsonl")
406
+ args = parser.parse_args()
407
+ try:
408
+ service = GuardService(args.key_file, args.audit_file, _token_from_file(args.token_file))
409
+ server = build_server(args.endpoint, service)
410
+ except (OSError, RuntimeError, ValueError) as error:
411
+ print(f"BLOCK: {error}", file=sys.stderr)
412
+ return 1
413
+
414
+ def stop(_signum=None, _frame=None) -> None:
415
+ # BaseServer.shutdown() must run outside the serve_forever() thread.
416
+ threading.Thread(target=server.shutdown, daemon=True).start()
417
+
418
+ for signum in (signal.SIGINT, signal.SIGTERM):
419
+ signal.signal(signum, stop)
420
+ try:
421
+ server.serve_forever(poll_interval=0.25)
422
+ finally:
423
+ server.server_close()
424
+ socket_path = getattr(server, "socket_path", None)
425
+ if socket_path:
426
+ try:
427
+ if socket_path.exists() and stat.S_ISSOCK(socket_path.lstat().st_mode):
428
+ socket_path.unlink()
429
+ except OSError:
430
+ pass
431
+ return 0
432
+
433
+
434
+ if __name__ == "__main__":
435
+ raise SystemExit(main())
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/env python3
2
+ """Fail-closed release gateway for agent, API, hook, and CI adapters."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import argparse
7
+ import importlib.util
8
+ import json
9
+ import sys
10
+ from pathlib import Path
11
+
12
+
13
+ ROOT = Path(__file__).resolve().parents[1]
14
+ SERVER = ROOT / "translate-native" / "scripts" / "blun_language_guard.py"
15
+ SPEC = importlib.util.spec_from_file_location("blun_gateway_guard", SERVER)
16
+ assert SPEC and SPEC.loader
17
+ GUARD = importlib.util.module_from_spec(SPEC)
18
+ sys.modules[SPEC.name] = GUARD
19
+ SPEC.loader.exec_module(GUARD)
20
+
21
+
22
+ def gate(request: dict) -> dict:
23
+ required = ("task_kind", "target_text", "language")
24
+ missing = [
25
+ key for key in required
26
+ if not isinstance(request.get(key), str) or not request[key].strip()
27
+ ]
28
+ if missing:
29
+ return {"status": "BLOCK", "release_allowed": False, "reason": "missing-fields", "fields": missing}
30
+ task_kind = request["task_kind"]
31
+ source = request.get("source_text", "")
32
+ if not isinstance(source, str):
33
+ return {"status": "BLOCK", "release_allowed": False, "reason": "invalid-source-type"}
34
+ if task_kind == "translation":
35
+ if not source.strip():
36
+ return {"status": "BLOCK", "release_allowed": False, "reason": "translation-source-required"}
37
+ result = GUARD.release_translation(request)
38
+ elif task_kind == "response":
39
+ if source.strip():
40
+ return {"status": "BLOCK", "release_allowed": False, "reason": "response-cannot-carry-source"}
41
+ result = GUARD.release_response(request)
42
+ else:
43
+ return {"status": "BLOCK", "release_allowed": False, "reason": "invalid-task-kind"}
44
+ result["gateway"] = f"blun-language-gateway/{GUARD.VERSION}"
45
+ result["task_kind"] = task_kind
46
+ return result
47
+
48
+
49
+ def main() -> int:
50
+ parser = argparse.ArgumentParser(description="BLUN fail-closed language output gateway")
51
+ parser.add_argument("--input", type=Path, help="JSON request file; defaults to stdin")
52
+ parser.add_argument("--receipt-only", action="store_true", help="Print only a valid release receipt")
53
+ args = parser.parse_args()
54
+ try:
55
+ request = json.loads(args.input.read_text(encoding="utf-8-sig") if args.input else sys.stdin.read().lstrip("\ufeff"))
56
+ result = gate(request)
57
+ except (OSError, json.JSONDecodeError) as error:
58
+ result = {"status": "BLOCK", "release_allowed": False, "reason": "invalid-input", "error": str(error)}
59
+ if args.receipt_only and result.get("release_allowed"):
60
+ print(result.get("release_token", ""))
61
+ else:
62
+ print(json.dumps(result, ensure_ascii=False, indent=2))
63
+ return 0 if result.get("release_allowed") else 1
64
+
65
+
66
+ if __name__ == "__main__":
67
+ raise SystemExit(main())