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.
- package/CHANGELOG.md +11 -185
- package/LIESMICH.txt +51 -13
- package/README.md +44 -47
- package/agent-spine-plugin/.codex-plugin/plugin.json +16 -4
- package/agent-spine-plugin/CHANGELOG.md +37 -5
- package/agent-spine-plugin/README.md +3 -3
- package/agent-spine-plugin/blun.plugin.json +45 -10
- package/agent-spine-plugin/docs/artifact-evaluation.md +93 -0
- package/agent-spine-plugin/docs/host-integration.md +42 -27
- package/agent-spine-plugin/docs/preflight-recall.md +4 -2
- package/agent-spine-plugin/docs/session-timeline.md +97 -236
- package/agent-spine-plugin/docs/world-model.md +25 -0
- package/agent-spine-plugin/hooks/codex.json +1 -1
- package/agent-spine-plugin/hooks/hooks.json +1 -1
- package/agent-spine-plugin/package.json +1 -3
- package/agent-spine-plugin/scripts/check-hosts.js +3 -3
- package/agent-spine-plugin/scripts/release-check.js +10 -5
- package/agent-spine-plugin/scripts/run-checks.js +4 -1
- package/agent-spine-plugin/scripts/run-tests-hermetic.js +32 -6
- package/agent-spine-plugin/src/cli-learning.js +15 -0
- package/agent-spine-plugin/src/cli.js +2 -0
- package/agent-spine-plugin/src/hook.js +32 -32
- package/agent-spine-plugin/src/lib/action-lesson-recall.js +73 -8
- package/agent-spine-plugin/src/lib/briefing.js +146 -36
- package/agent-spine-plugin/src/lib/channel-continuity.js +19 -0
- package/agent-spine-plugin/src/lib/delivery-agent-usage.js +14 -7
- package/agent-spine-plugin/src/lib/gateway-group-response.js +128 -0
- package/agent-spine-plugin/src/lib/gateway-runs.js +24 -15
- package/agent-spine-plugin/src/lib/hook-briefing-use.js +13 -3
- package/agent-spine-plugin/src/lib/hook-context.js +16 -3
- package/agent-spine-plugin/src/lib/hook-output.js +129 -5
- package/agent-spine-plugin/src/lib/hook-timeline.js +5 -3
- package/agent-spine-plugin/src/lib/indexed-memory.js +2 -2
- package/agent-spine-plugin/src/lib/learning-artifact-evaluator.js +114 -0
- package/agent-spine-plugin/src/lib/learning-context.js +11 -4
- package/agent-spine-plugin/src/lib/learning-measurements.js +2 -2
- package/agent-spine-plugin/src/lib/mcp-runtime.js +89 -3
- package/agent-spine-plugin/src/lib/mcp-source-context.js +12 -2
- package/agent-spine-plugin/src/lib/mcp-timeline-tools.js +91 -8
- package/agent-spine-plugin/src/lib/mcp-world-tools.js +2 -2
- package/agent-spine-plugin/src/lib/owned-file-lock.js +20 -1
- package/agent-spine-plugin/src/lib/persona-runtime.js +2 -2
- package/agent-spine-plugin/src/lib/preflight-delivery-id.js +27 -0
- package/agent-spine-plugin/src/lib/preflight.js +4 -4
- package/agent-spine-plugin/src/lib/session-timeline-codex.js +15 -0
- package/agent-spine-plugin/src/lib/session-timeline-contract.js +12 -4
- package/agent-spine-plugin/src/lib/session-timeline-event-extract.js +36 -7
- package/agent-spine-plugin/src/lib/session-timeline-host-origin.js +13 -10
- package/agent-spine-plugin/src/lib/session-timeline-invocation.js +1 -1
- package/agent-spine-plugin/src/lib/session-timeline-king.js +14 -0
- package/agent-spine-plugin/src/lib/session-timeline-prior.js +18 -12
- package/agent-spine-plugin/src/lib/session-timeline-provider.js +5 -0
- package/agent-spine-plugin/src/lib/session-timeline-query.js +2 -0
- package/agent-spine-plugin/src/lib/session-timeline-results.js +35 -10
- package/agent-spine-plugin/src/lib/session-timeline-source-open.js +30 -0
- package/agent-spine-plugin/src/lib/session-timeline.js +122 -75
- package/agent-spine-plugin/src/lib/source-roots.js +3 -2
- package/agent-spine-plugin/src/lib/task-knowledge-context.js +22 -1
- package/agent-spine-plugin/src/lib/timeline-continuation-update.js +100 -0
- package/agent-spine-plugin/src/lib/timeline-tool-guard.js +30 -7
- package/agent-spine-plugin/src/lib/timeline-user-feedback.js +217 -0
- package/agent-spine-plugin/src/lib/timeline-world-capture.js +233 -0
- package/agent-spine-plugin/src/lib/world-knowledge.js +59 -2
- package/agent-spine-plugin/src/lib/world-model.js +64 -9
- package/agent-spine-plugin/src/worker.js +13 -1
- package/bin/blun.js +43 -28
- package/bin/core-bootstrap.js +5 -4
- package/bin/king.js +43 -28
- package/bin/launcher-mode.js +1 -10
- package/bin/launcher-runtime.js +128 -295
- package/bin/managed-node.js +0 -0
- package/bin/managed-plugin-selection.cjs +0 -1
- package/bin/native-module-repair.js +0 -0
- package/bin/node-runtime.js +0 -0
- package/bin/node-version.js +0 -0
- package/bin/plugin-bootstrap.js +56 -120
- package/bin/private-paths.js +11 -34
- package/bin/standard-tools-bootstrap.js +34 -114
- package/bin/turn-thinking-policy.cjs +3 -11
- package/bin/update-copy.js +200 -0
- package/bin/update-lease.js +0 -0
- package/bin/update-notice.js +136 -289
- package/bin/verify-agent-behavior.cjs +122 -0
- package/bin/verify-agent-components.cjs +104 -0
- package/bin/verify-bundled-agent-sources.cjs +57 -0
- package/blun.mjs +143076 -135288
- package/bundled-agent-sources.json +701 -0
- package/package.json +12 -15
- package/standard-skills/translate-native/README.md +1293 -0
- package/standard-skills/translate-native/SKILL.md +172 -22
- package/standard-skills/translate-native/VERSION +1 -1
- package/standard-skills/translate-native/agents/openai.yaml +18 -0
- package/standard-skills/translate-native/assets/icon.svg +8 -0
- package/standard-skills/translate-native/docs/BLUN_CODE_INTEGRATION.md +76 -0
- package/standard-skills/translate-native/docs/PREMORTEM.md +489 -0
- package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION.md +2035 -0
- package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_API.md +1302 -0
- package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_EVIDENCE_HTTP.md +136 -0
- package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_HEALTH_HTTP.md +130 -0
- package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_HTTP_PROVIDER.md +175 -0
- package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_RECEIPT_VERIFIER_HTTP.md +86 -0
- package/standard-skills/translate-native/integrations/AGENT_RULES.md +32 -0
- package/standard-skills/translate-native/integrations/adapters/blun-code-language-guard.js +514 -0
- package/standard-skills/translate-native/integrations/adapters/node-language-guard.js +230 -0
- package/standard-skills/translate-native/integrations/audit_log.py +327 -0
- package/standard-skills/translate-native/integrations/claude_language_hook.js +1536 -0
- package/standard-skills/translate-native/integrations/commercial_localization_profile.py +42 -0
- package/standard-skills/translate-native/integrations/delivery-policy.example.json +28 -0
- package/standard-skills/translate-native/integrations/enforced_delivery.py +543 -0
- package/standard-skills/translate-native/integrations/guard_service.py +435 -0
- package/standard-skills/translate-native/integrations/language_gateway.py +67 -0
- package/standard-skills/translate-native/integrations/mcp_auth_headers.py +198 -0
- package/standard-skills/translate-native/integrations/mcp_http_gateway.py +429 -0
- package/standard-skills/translate-native/integrations/non_language_html_entities.js +1485 -0
- package/standard-skills/translate-native/integrations/pre_output_guard.py +65 -0
- package/standard-skills/translate-native/integrations/task_router.py +101 -0
- package/standard-skills/translate-native/integrations/website_localization.py +401 -0
- package/standard-skills/translate-native/integrations/website_localization_api.py +581 -0
- package/standard-skills/translate-native/integrations/website_localization_benchmark.py +1885 -0
- package/standard-skills/translate-native/integrations/website_localization_benchmark_campaign.py +1772 -0
- package/standard-skills/translate-native/integrations/website_localization_benchmark_candidate.py +506 -0
- package/standard-skills/translate-native/integrations/website_localization_benchmark_http.py +400 -0
- package/standard-skills/translate-native/integrations/website_localization_benchmark_review_store.py +781 -0
- package/standard-skills/translate-native/integrations/website_localization_benchmark_reviewer_http.py +500 -0
- package/standard-skills/translate-native/integrations/website_localization_benchmark_runtime.py +1107 -0
- package/standard-skills/translate-native/integrations/website_localization_benchmark_suite.py +463 -0
- package/standard-skills/translate-native/integrations/website_localization_cms.py +2835 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_client.py +875 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_dispatch.py +805 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_http.py +588 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_lifecycle_monitor.py +991 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_receiver.py +1441 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_receiver_runtime.py +414 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_receiver_store.py +1073 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_removal_dispatch.py +865 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_client.py +583 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery.py +964 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_runtime.py +665 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_http.py +1153 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_runtime.py +675 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_service.py +1125 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_terminal_notification.py +674 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_terminal_notification_http.py +444 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_terminal_notification_receiver.py +1469 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_terminal_notification_receiver_runtime.py +1142 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_terminal_processing_monitor.py +634 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_terminal_receiver_client.py +804 -0
- package/standard-skills/translate-native/integrations/website_localization_deepl_baseline.py +922 -0
- package/standard-skills/translate-native/integrations/website_localization_evidence_http.py +482 -0
- package/standard-skills/translate-native/integrations/website_localization_health.py +1541 -0
- package/standard-skills/translate-native/integrations/website_localization_health_http.py +372 -0
- package/standard-skills/translate-native/integrations/website_localization_http_provider.py +297 -0
- package/standard-skills/translate-native/integrations/website_localization_native_reference_http.py +479 -0
- package/standard-skills/translate-native/integrations/website_localization_native_reference_intake.py +363 -0
- package/standard-skills/translate-native/integrations/website_localization_native_reference_queue.py +1449 -0
- package/standard-skills/translate-native/integrations/website_localization_native_reference_store.py +420 -0
- package/standard-skills/translate-native/integrations/website_localization_quality_profiles.py +235 -0
- package/standard-skills/translate-native/integrations/website_localization_queue.py +671 -0
- package/standard-skills/translate-native/integrations/website_localization_receipt_verifier_http.py +516 -0
- package/standard-skills/translate-native/integrations/website_localization_release.py +928 -0
- package/standard-skills/translate-native/integrations/website_localization_release_coordinator.py +1008 -0
- package/standard-skills/translate-native/integrations/website_localization_runner.py +276 -0
- package/standard-skills/translate-native/integrations/website_localization_runtime.py +862 -0
- package/standard-skills/translate-native/integrations/website_localization_service.py +350 -0
- package/standard-skills/translate-native/integrations/website_localization_supervisor.py +511 -0
- package/standard-skills/translate-native/integrations/website_localization_worker.py +663 -0
- package/standard-skills/translate-native/provenance.json +3 -4
- package/standard-skills/translate-native/references/commercial-localization.md +177 -0
- package/standard-skills/translate-native/scripts/blun_language_guard.py +7 -1
- package/standard-skills/translate-native/scripts/check_commercial_review.py +80 -0
- package/standard-skills/translate-native/scripts/commercial_localization_profile.py +333 -0
- package/standard-tools/language-guard/LICENSE +21 -0
- package/standard-tools/language-guard/VERSION +1 -0
- package/standard-tools/language-guard/blun_language_guard.py +7 -1
- package/standard-tools/language-guard/check_commercial_review.py +80 -0
- package/standard-tools/language-guard/commercial_localization_profile.py +333 -0
- package/standard-tools/language-guard/language_gateway.py +62 -0
- package/standard-tools/language-guard/pre_output_guard.py +64 -0
- package/standard-tools/language-guard/provenance.json +4 -11
- package/standard-tools/manifest.json +34 -11
- package/telegram-plugin/commands/access.md +2 -10
- package/telegram-plugin/dist/bridge.mjs +64041 -687
- package/telegram-plugin/dist/mcp-server.mjs +72810 -9027
- package/telegram-plugin/dist/noise.mjs +28 -63511
- package/agent-spine-plugin/CONTRIBUTING.md +0 -52
- package/agent-spine-plugin/SECURITY.md +0 -47
- package/agent-spine-plugin/docs/assignment-continuation.md +0 -48
- package/agent-spine-plugin/docs/releasing.md +0 -85
- package/agent-spine-plugin/docs/structured-completion.md +0 -67
- package/bin/abort-listener-policy.cjs +0 -43
- package/bin/active-steer-priority-policy.cjs +0 -24
- package/bin/agent-api-http-adapter.mjs +0 -446
- package/bin/agent-api-private-http-server.mjs +0 -288
- package/bin/agent-api-runtime.mjs +0 -252
- package/bin/agent-api-service-environment.mjs +0 -236
- package/bin/agent-api-service-host.mjs +0 -209
- package/bin/agent-api-service-process.mjs +0 -171
- package/bin/agent-api-session-registry.mjs +0 -428
- package/bin/agent-api-tool-broker.cjs +0 -248
- package/bin/agent-api-turn-controller.mjs +0 -461
- package/bin/agent-api-usage-journal.cjs +0 -259
- package/bin/agent-resume-snapshot.cjs +0 -241
- package/bin/agentspine-king-goal-inbox.mjs +0 -111
- package/bin/agentspine-king-goal-intake.mjs +0 -106
- package/bin/approval-rejection-stop.cjs +0 -15
- package/bin/assistant-message-offload-policy.cjs +0 -284
- package/bin/baseline-skill-performance-policy.cjs +0 -39
- package/bin/bash-search-scope-policy.cjs +0 -49
- package/bin/codebase-search-runtime.cjs +0 -23
- package/bin/cognitive-action-checkpoint.cjs +0 -1104
- package/bin/cognitive-attention-delivery.cjs +0 -76
- package/bin/cognitive-attention-policy.cjs +0 -143
- package/bin/cognitive-attention-runtime.cjs +0 -91
- package/bin/cognitive-context-projection.cjs +0 -73
- package/bin/cognitive-cross-portal-acceptance.cjs +0 -443
- package/bin/cognitive-effective-view.cjs +0 -77
- package/bin/cognitive-focus-projection.cjs +0 -206
- package/bin/cognitive-focus-scope.cjs +0 -37
- package/bin/cognitive-goal-autostart-policy.cjs +0 -72
- package/bin/cognitive-goal-time-trigger-controller.cjs +0 -146
- package/bin/cognitive-memory-adapter.cjs +0 -282
- package/bin/cognitive-memory-command.cjs +0 -293
- package/bin/cognitive-memory-provider.cjs +0 -92
- package/bin/cognitive-salience-policy.cjs +0 -159
- package/bin/cognitive-state-store.cjs +0 -508
- package/bin/cognitive-turn-lifecycle.cjs +0 -624
- package/bin/cognitive-work-focus.cjs +0 -180
- package/bin/compaction-history-archive.cjs +0 -166
- package/bin/compaction-history-startup.cjs +0 -50
- package/bin/compaction-model-policy.cjs +0 -31
- package/bin/compaction-stage-policy.cjs +0 -21
- package/bin/compaction-transaction-policy.cjs +0 -122
- package/bin/config-write-dedup-policy.cjs +0 -27
- package/bin/context-budget-ledger.cjs +0 -31
- package/bin/context-doctor-policy.cjs +0 -70
- package/bin/context-insight-policy.cjs +0 -36
- package/bin/context-performance-policy.cjs +0 -19
- package/bin/context-pressure-policy.cjs +0 -20
- package/bin/cron-run-output.cjs +0 -45
- package/bin/cron-run-store.cjs +0 -145
- package/bin/curiosity-scout-policy.cjs +0 -49
- package/bin/default-model-output-budget-policy.cjs +0 -28
- package/bin/durable-task-resume-policy.cjs +0 -130
- package/bin/durable-task-resume-runtime.cjs +0 -117
- package/bin/durable-task-resume-store.cjs +0 -88
- package/bin/editable-tool-approval-policy.cjs +0 -540
- package/bin/editable-tool-approval-runtime.cjs +0 -99
- package/bin/effective-system-prompt-cache-policy.cjs +0 -33
- package/bin/error-memory-performance-policy.cjs +0 -113
- package/bin/file-observation-policy.cjs +0 -133
- package/bin/foreground-output-capture-policy.cjs +0 -41
- package/bin/generated-source-health.cjs +0 -142
- package/bin/glob-pattern-policy.cjs +0 -13
- package/bin/goal-completion-evidence-policy.cjs +0 -120
- package/bin/grep-output-limit-policy.cjs +0 -39
- package/bin/historical-media-projection-policy.cjs +0 -48
- package/bin/history-offload-pressure-policy.cjs +0 -33
- package/bin/html-to-research-markdown.cjs +0 -147
- package/bin/identity-context-policy.cjs +0 -764
- package/bin/identity-journal-policy.cjs +0 -107
- package/bin/input-draft-persistence.cjs +0 -77
- package/bin/king-tui-function-contract.json +0 -33
- package/bin/launcher-restart-policy.cjs +0 -150
- package/bin/live-response-repetition-guard.cjs +0 -196
- package/bin/llm-config-log-dedup-policy.cjs +0 -76
- package/bin/loop-event-record-policy.cjs +0 -174
- package/bin/managed-context-startup-policy.cjs +0 -27
- package/bin/media-activity-layout-policy.cjs +0 -34
- package/bin/media-auto-retrieval-policy.cjs +0 -90
- package/bin/media-result-policy.cjs +0 -59
- package/bin/micro-compaction-policy.cjs +0 -145
- package/bin/mistake-relevance-policy.cjs +0 -319
- package/bin/model-retry-progress-policy.cjs +0 -46
- package/bin/native-large-file-io.cjs +0 -42
- package/bin/native-runtime-cache.cjs +0 -76
- package/bin/natural-presence-policy.cjs +0 -28
- package/bin/noninteractive-shell-env-policy.cjs +0 -19
- package/bin/observer-hooks.cjs +0 -14
- package/bin/outbound-claim-provenance.cjs +0 -150
- package/bin/oversized-context-offload-policy.cjs +0 -86
- package/bin/pending-media-policy.cjs +0 -182
- package/bin/pending-token-estimate-policy.cjs +0 -41
- package/bin/personal-memory-consent-policy.cjs +0 -72
- package/bin/personal-memory-performance-policy.cjs +0 -12
- package/bin/personality-choice-policy.cjs +0 -101
- package/bin/personality-memory-adapter.cjs +0 -379
- package/bin/personality-mode.cjs +0 -46
- package/bin/personality-setup-policy.cjs +0 -197
- package/bin/proactive-compaction-policy.cjs +0 -25
- package/bin/profile-identity-resolution.cjs +0 -136
- package/bin/profile-runtime.cjs +0 -318
- package/bin/profile-tool-exclusion-policy.cjs +0 -37
- package/bin/programmatic-context-isolation.cjs +0 -25
- package/bin/programmatic-tool-runtime.mjs +0 -627
- package/bin/provider-idle-timeout-policy.cjs +0 -14
- package/bin/provider-model-refresh-deadline.cjs +0 -53
- package/bin/provider-model-refresh-policy.cjs +0 -107
- package/bin/rate-limit-recovery-policy.cjs +0 -47
- package/bin/read-batch-policy.cjs +0 -32
- package/bin/read-continuation-policy.cjs +0 -59
- package/bin/recurring-cron-history-policy.cjs +0 -124
- package/bin/relationship-continuity-policy.cjs +0 -143
- package/bin/relationship-curiosity-policy.cjs +0 -107
- package/bin/relationship-learning-policy.cjs +0 -168
- package/bin/release-artifact-freeze-policy.cjs +0 -30
- package/bin/reload-plugin-bootstrap.cjs +0 -18
- package/bin/reload-queue-policy.cjs +0 -38
- package/bin/repeated-assistant-response-policy.cjs +0 -232
- package/bin/repeated-injection-projection.cjs +0 -107
- package/bin/repeated-user-message-projection.cjs +0 -8
- package/bin/research-page-result.cjs +0 -74
- package/bin/retry-checkpoint-policy.cjs +0 -13
- package/bin/runtime-exit-ledger.cjs +0 -144
- package/bin/scoped-cron-run-policy.cjs +0 -358
- package/bin/session-checkpoint-policy.cjs +0 -25
- package/bin/session-compaction-policy.cjs +0 -84
- package/bin/session-replay-policy.cjs +0 -20
- package/bin/session-replay-window-policy.cjs +0 -40
- package/bin/session-resume-checkpoint.cjs +0 -254
- package/bin/session-scrollback-archive.cjs +0 -229
- package/bin/skill-activation-performance-policy.cjs +0 -69
- package/bin/skill-listing-performance-policy.cjs +0 -92
- package/bin/soul-organization-policy.cjs +0 -78
- package/bin/soul-preservation-policy.cjs +0 -20
- package/bin/startup-preferences.cjs +0 -131
- package/bin/streaming-flush-performance-policy.cjs +0 -28
- package/bin/structured-agent-swarm-output.cjs +0 -325
- package/bin/structured-subagent-output.cjs +0 -252
- package/bin/subagent-context-fork-policy.cjs +0 -155
- package/bin/subagent-max-tokens-handoff-policy.cjs +0 -69
- package/bin/subagent-parent-responsiveness.cjs +0 -19
- package/bin/subagent-skill-policy.cjs +0 -206
- package/bin/subagent-timeout-policy.cjs +0 -182
- package/bin/subagent-tool-policy.cjs +0 -60
- package/bin/subagent-usage-rollup-policy.cjs +0 -29
- package/bin/system-prompt-context-policy.cjs +0 -124
- package/bin/system-prompt-token-cache-policy.cjs +0 -60
- package/bin/telegram-addressed-focus.cjs +0 -55
- package/bin/telegram-addressed-priority.cjs +0 -12
- package/bin/telegram-approval-relay.cjs +0 -290
- package/bin/telegram-bot-priority.cjs +0 -17
- package/bin/telegram-console-status-policy.cjs +0 -174
- package/bin/telegram-context-projection-policy.cjs +0 -141
- package/bin/telegram-delivery-lifecycle.cjs +0 -125
- package/bin/telegram-direct-focus-policy.cjs +0 -273
- package/bin/telegram-mcp-compatibility.cjs +0 -49
- package/bin/telegram-media-delivery-policy.cjs +0 -42
- package/bin/telegram-private-conversation-policy.cjs +0 -185
- package/bin/telegram-queue-handoff-policy.cjs +0 -73
- package/bin/telegram-remote-status-policy.cjs +0 -120
- package/bin/telegram-session-queue-runtime.mjs +0 -306
- package/bin/telegram-text-chunk-policy.cjs +0 -63
- package/bin/telegram-truncated-reply-policy.cjs +0 -37
- package/bin/telegram-urgent-policy.cjs +0 -45
- package/bin/telemetry-spool-policy.cjs +0 -57
- package/bin/thinking-activity-status-policy.cjs +0 -132
- package/bin/thinking-only-guard.cjs +0 -80
- package/bin/todo-list-turn-policy.cjs +0 -131
- package/bin/tool-call-loop-policy.cjs +0 -51
- package/bin/tool-file-persistence.cjs +0 -141
- package/bin/tool-result-offload-policy.cjs +0 -359
- package/bin/tool-result-offload-telemetry.cjs +0 -12
- package/bin/tool-schema-token-cache-policy.cjs +0 -41
- package/bin/tool-stream-preview-policy.cjs +0 -9
- package/bin/tui-functional-contract.cjs +0 -55
- package/bin/turn-tool-performance-policy.cjs +0 -486
- package/bin/usage-cache-efficiency-policy.cjs +0 -26
- package/bin/user-home-path-policy.cjs +0 -13
- package/bin/user-message-offload-policy.cjs +0 -103
- package/bin/user-prompt-hook-origin-policy.cjs +0 -34
- package/bin/user-tool-record-policy.cjs +0 -7
- package/bin/validated-learning-insight-policy.cjs +0 -58
- package/bin/validated-learning-outcome-trace.cjs +0 -107
- package/bin/validated-learning-performance-policy.cjs +0 -53
- package/bin/validated-learning-signal.cjs +0 -463
- package/bin/windows-bash-dialect-policy.cjs +0 -25
- package/bin/windows-node-crash-dump.cjs +0 -110
- package/bin/write-continuation-policy.cjs +0 -69
- package/codebase-index/README.md +0 -82
- package/codebase-index/codebase_index.py +0 -470
- package/standard-skills/agent-browser/SKILL.md +0 -19
- package/standard-skills/agent-browser/references/runtime.md +0 -8
- package/standard-skills/blun-session-inspector/SKILL.md +0 -41
- package/standard-skills/blun-session-inspector/scripts/inspect-session.cjs +0 -437
- package/standard-skills/design-taste-frontend/SKILL.md +0 -1206
- package/standard-skills/full-output-enforcement/SKILL.md +0 -49
- package/standard-skills/high-end-visual-design/SKILL.md +0 -98
- package/standard-skills/image-to-code/SKILL.md +0 -1228
- package/standard-skills/industrial-brutalist-ui/SKILL.md +0 -92
- package/standard-skills/minimalist-ui/SKILL.md +0 -85
- package/standard-skills/motion-design-taste/SKILL.md +0 -74
- package/standard-skills/playwright-testing/SKILL.md +0 -19
- package/standard-skills/playwright-testing/references/runtime.md +0 -7
- package/standard-skills/premortem/SKILL.md +0 -148
- package/standard-skills/redesign-existing-projects/SKILL.md +0 -178
- package/standard-skills/research-evidence/SKILL.md +0 -39
- package/standard-skills/research-evidence/references/evidence-format.md +0 -104
- package/standard-skills/research-evidence/scripts/evidence-collection.cjs +0 -260
- package/standard-skills/research-evidence/scripts/score-report.cjs +0 -130
- package/standard-skills/screenshot-lesen/SKILL.md +0 -52
- package/standard-skills/stitch-design-taste/DESIGN.md +0 -121
- package/standard-skills/stitch-design-taste/SKILL.md +0 -184
- package/standard-skills/telegram-channel/SKILL.md +0 -18
- package/standard-skills/telegram-channel/references/runtime.md +0 -7
- package/standard-skills/venture-flywheel/SKILL.md +0 -32
- package/standard-skills/venture-flywheel/identity/project-identity.cjs +0 -146
- package/standard-skills/venture-flywheel/policy/capability-engine.cjs +0 -114
- package/standard-skills/venture-flywheel/policy/repository-trust.cjs +0 -229
- package/standard-skills/venture-flywheel/references/BEISPIELE-phase0.md +0 -146
- package/standard-skills/venture-flywheel/references/CAPABILITY-MAP.md +0 -34
- package/standard-skills/venture-flywheel/references/SPEC-phase0-identity-trust.md +0 -77
- package/standard-skills/venture-flywheel/references/SPEC-phase0-state-events.md +0 -93
- package/standard-skills/venture-flywheel/schemas/capability-decision.schema.json +0 -13
- package/standard-skills/venture-flywheel/schemas/execution-event.schema.json +0 -44
- package/standard-skills/venture-flywheel/schemas/project-identity.schema.json +0 -32
- package/standard-skills/venture-flywheel/schemas/repository-trust.schema.json +0 -57
- package/standard-skills/venture-flywheel/schemas/run-transition.schema.json +0 -59
- package/standard-skills/venture-flywheel/state/execution-event.cjs +0 -191
- package/standard-skills/venture-flywheel/state/task-state-machine.cjs +0 -190
- package/standard-skills/web-lesen/SKILL.md +0 -73
- package/standard-skills/web-lesen/scripts/crawl_public.py +0 -379
- package/standard-skills/windows-mcp/SKILL.md +0 -19
- package/standard-skills/windows-mcp/references/runtime.md +0 -9
- package/telegram-plugin/DELIVERY.md +0 -36
- package/telegram-plugin/bin/telegram-approval-relay.cjs +0 -290
- package/telegram-plugin/bin/telegram-console-status-policy.cjs +0 -175
- package/telegram-plugin/bin/telegram-delivery-lifecycle.cjs +0 -125
- package/telegram-plugin/bin/telegram-direct-reply-policy.cjs +0 -48
- package/telegram-plugin/bin/telegram-launcher-status-queue.cjs +0 -122
- package/telegram-plugin/bin/telegram-private-conversation-policy.cjs +0 -186
- package/telegram-plugin/bin/telegram-remote-status-policy.cjs +0 -121
- package/telegram-plugin/bin/telegram-reply-parts.cjs +0 -149
- package/telegram-plugin/bin/telegram-text-chunk-policy.cjs +0 -63
- package/telegram-plugin/bin/telegram-typing-keepalive.cjs +0 -89
- package/telegram-plugin/compat/mcp-server-fa511cd1.mjs +0 -73825
- /package/{bin → scripts}/fix-node-pty-perms.js +0 -0
|
@@ -0,0 +1,514 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const fs = require("node:fs");
|
|
4
|
+
const os = require("node:os");
|
|
5
|
+
const path = require("node:path");
|
|
6
|
+
const {
|
|
7
|
+
LanguageGuardBlocked,
|
|
8
|
+
routeHostContext,
|
|
9
|
+
verifyForDelivery,
|
|
10
|
+
} = require("./node-language-guard");
|
|
11
|
+
|
|
12
|
+
const SERVER_NAME = "blun-language-guard";
|
|
13
|
+
const MAX_SERVICE_TOKEN_BYTES = 64 * 1024;
|
|
14
|
+
const MAX_BLUN_MCP_CONFIG_BYTES = 1024 * 1024;
|
|
15
|
+
|
|
16
|
+
function protectedFileIdentity(stats) {
|
|
17
|
+
return {
|
|
18
|
+
dev: stats.dev,
|
|
19
|
+
ino: stats.ino,
|
|
20
|
+
size: stats.size,
|
|
21
|
+
ctimeMs: stats.ctimeMs,
|
|
22
|
+
mtimeMs: stats.mtimeMs,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function sameProtectedFile(stats, expected) {
|
|
27
|
+
return stats.dev === expected.dev && stats.ino === expected.ino
|
|
28
|
+
&& stats.size === expected.size && stats.ctimeMs === expected.ctimeMs
|
|
29
|
+
&& stats.mtimeMs === expected.mtimeMs;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function validateServiceTokenStats(stats) {
|
|
33
|
+
if (!stats.isFile() || stats.isSymbolicLink()) throw new Error("service token must be a regular file");
|
|
34
|
+
if (stats.nlink !== 1) throw new Error("service token must not have additional hard links");
|
|
35
|
+
if (stats.size < 32 || stats.size > MAX_SERVICE_TOKEN_BYTES) throw new Error("service token has an invalid size");
|
|
36
|
+
if (process.platform !== "win32" && (stats.mode & 0o077) !== 0) throw new Error("service token permissions are too broad");
|
|
37
|
+
if (typeof process.getuid === "function" && stats.uid !== process.getuid()) throw new Error("service token has the wrong owner");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function protectedDirectoryIdentity(stats) {
|
|
41
|
+
return {
|
|
42
|
+
dev: stats.dev,
|
|
43
|
+
ino: stats.ino,
|
|
44
|
+
mode: stats.mode,
|
|
45
|
+
uid: stats.uid,
|
|
46
|
+
gid: stats.gid,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function sameProtectedDirectory(stats, expected) {
|
|
51
|
+
return stats.dev === expected.dev && stats.ino === expected.ino
|
|
52
|
+
&& stats.mode === expected.mode && stats.uid === expected.uid
|
|
53
|
+
&& stats.gid === expected.gid;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function validateProtectedDirectoryStats(stats, directory, label) {
|
|
57
|
+
if (!stats.isDirectory() || stats.isSymbolicLink()) {
|
|
58
|
+
throw new Error(`${label} directory must be a directory: ${directory}`);
|
|
59
|
+
}
|
|
60
|
+
if (process.platform !== "win32" && (stats.mode & 0o022) !== 0) {
|
|
61
|
+
throw new Error(`${label} directory is writable outside its owner: ${directory}`);
|
|
62
|
+
}
|
|
63
|
+
if (typeof process.getuid === "function" && stats.uid !== process.getuid()) {
|
|
64
|
+
throw new Error(`${label} directory has the wrong owner: ${directory}`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function existingProtectedDirectoryAnchor(directory, label) {
|
|
69
|
+
let candidate = directory;
|
|
70
|
+
while (true) {
|
|
71
|
+
try {
|
|
72
|
+
fs.lstatSync(candidate);
|
|
73
|
+
return candidate;
|
|
74
|
+
} catch (error) {
|
|
75
|
+
if (!error || error.code !== "ENOENT") throw error;
|
|
76
|
+
const parent = path.dirname(candidate);
|
|
77
|
+
if (parent === candidate) {
|
|
78
|
+
throw new Error(`${label} directory has no existing anchor: ${directory}`);
|
|
79
|
+
}
|
|
80
|
+
candidate = parent;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function openProtectedDirectory(destination, label, { allowMissing = false } = {}) {
|
|
86
|
+
const absoluteFile = path.resolve(destination);
|
|
87
|
+
const directory = path.dirname(absoluteFile);
|
|
88
|
+
if (process.platform === "win32") {
|
|
89
|
+
let details;
|
|
90
|
+
try {
|
|
91
|
+
details = fs.lstatSync(directory);
|
|
92
|
+
} catch (error) {
|
|
93
|
+
if (allowMissing && error && error.code === "ENOENT") return null;
|
|
94
|
+
throw error;
|
|
95
|
+
}
|
|
96
|
+
validateProtectedDirectoryStats(details, directory, label);
|
|
97
|
+
return {
|
|
98
|
+
accessPath: absoluteFile,
|
|
99
|
+
descriptor: null,
|
|
100
|
+
directory,
|
|
101
|
+
identity: protectedDirectoryIdentity(details),
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
const home = path.resolve(os.homedir());
|
|
105
|
+
const underHome = directory === home || directory.startsWith(`${home}${path.sep}`);
|
|
106
|
+
const anchor = underHome ? home : existingProtectedDirectoryAnchor(directory, label);
|
|
107
|
+
const relative = path.relative(anchor, directory);
|
|
108
|
+
const components = relative ? relative.split(path.sep) : [];
|
|
109
|
+
const noFollow = typeof fs.constants.O_NOFOLLOW === "number" ? fs.constants.O_NOFOLLOW : 0;
|
|
110
|
+
const directoryOnly = typeof fs.constants.O_DIRECTORY === "number" ? fs.constants.O_DIRECTORY : 0;
|
|
111
|
+
const flags = fs.constants.O_RDONLY | noFollow | directoryOnly;
|
|
112
|
+
const descriptorRoot = process.platform === "linux" ? "/proc/self/fd" : "/dev/fd";
|
|
113
|
+
let descriptor = null;
|
|
114
|
+
let current = anchor;
|
|
115
|
+
try {
|
|
116
|
+
descriptor = fs.openSync(anchor, flags);
|
|
117
|
+
validateProtectedDirectoryStats(fs.fstatSync(descriptor), anchor, label);
|
|
118
|
+
for (const component of components) {
|
|
119
|
+
current = path.join(current, component);
|
|
120
|
+
let child;
|
|
121
|
+
try {
|
|
122
|
+
child = fs.openSync(path.join(descriptorRoot, String(descriptor), component), flags);
|
|
123
|
+
} catch (error) {
|
|
124
|
+
if (allowMissing && error && error.code === "ENOENT") {
|
|
125
|
+
fs.closeSync(descriptor);
|
|
126
|
+
descriptor = null;
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
throw error;
|
|
130
|
+
}
|
|
131
|
+
try {
|
|
132
|
+
validateProtectedDirectoryStats(fs.fstatSync(child), current, label);
|
|
133
|
+
} catch (error) {
|
|
134
|
+
fs.closeSync(child);
|
|
135
|
+
throw error;
|
|
136
|
+
}
|
|
137
|
+
fs.closeSync(descriptor);
|
|
138
|
+
descriptor = child;
|
|
139
|
+
}
|
|
140
|
+
const identity = protectedDirectoryIdentity(fs.fstatSync(descriptor));
|
|
141
|
+
const accessPath = path.join(descriptorRoot, String(descriptor), path.basename(absoluteFile));
|
|
142
|
+
return { accessPath, descriptor, directory, identity };
|
|
143
|
+
} catch (error) {
|
|
144
|
+
if (descriptor !== null) fs.closeSync(descriptor);
|
|
145
|
+
if (error && String(error.message || "").startsWith(`${label} directory`)) throw error;
|
|
146
|
+
throw new Error(`${label} directory cannot be opened safely: ${current}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function closeProtectedDirectory(protectedDirectory, label) {
|
|
151
|
+
if (protectedDirectory.descriptor === null) {
|
|
152
|
+
const current = fs.lstatSync(protectedDirectory.directory);
|
|
153
|
+
validateProtectedDirectoryStats(current, protectedDirectory.directory, label);
|
|
154
|
+
if (!sameProtectedDirectory(current, protectedDirectory.identity)) {
|
|
155
|
+
throw new Error(`${label} directory changed while reading: ${protectedDirectory.directory}`);
|
|
156
|
+
}
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
try {
|
|
160
|
+
const held = fs.fstatSync(protectedDirectory.descriptor);
|
|
161
|
+
const current = fs.lstatSync(protectedDirectory.directory);
|
|
162
|
+
validateProtectedDirectoryStats(current, protectedDirectory.directory, label);
|
|
163
|
+
if (!sameProtectedDirectory(held, protectedDirectory.identity)
|
|
164
|
+
|| !sameProtectedDirectory(current, protectedDirectory.identity)) {
|
|
165
|
+
throw new Error(`${label} directory changed while reading: ${protectedDirectory.directory}`);
|
|
166
|
+
}
|
|
167
|
+
} finally {
|
|
168
|
+
fs.closeSync(protectedDirectory.descriptor);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function readProtectedServiceToken(destination) {
|
|
173
|
+
const protectedDirectory = openProtectedDirectory(destination, "service token");
|
|
174
|
+
const tokenFile = protectedDirectory.accessPath;
|
|
175
|
+
try {
|
|
176
|
+
const before = fs.lstatSync(tokenFile);
|
|
177
|
+
validateServiceTokenStats(before);
|
|
178
|
+
const noFollow = typeof fs.constants.O_NOFOLLOW === "number" ? fs.constants.O_NOFOLLOW : 0;
|
|
179
|
+
const descriptor = fs.openSync(tokenFile, fs.constants.O_RDONLY | noFollow);
|
|
180
|
+
try {
|
|
181
|
+
const opened = fs.fstatSync(descriptor);
|
|
182
|
+
validateServiceTokenStats(opened);
|
|
183
|
+
if (!sameProtectedFile(opened, protectedFileIdentity(before)) || opened.nlink !== before.nlink) {
|
|
184
|
+
throw new Error("service token changed while opening");
|
|
185
|
+
}
|
|
186
|
+
const buffer = Buffer.alloc(MAX_SERVICE_TOKEN_BYTES + 1);
|
|
187
|
+
let size = 0;
|
|
188
|
+
while (size < buffer.length) {
|
|
189
|
+
const count = fs.readSync(descriptor, buffer, size, buffer.length - size, null);
|
|
190
|
+
if (count === 0) break;
|
|
191
|
+
size += count;
|
|
192
|
+
}
|
|
193
|
+
const after = fs.fstatSync(descriptor);
|
|
194
|
+
const afterPath = fs.lstatSync(tokenFile);
|
|
195
|
+
if (!sameProtectedFile(after, protectedFileIdentity(opened)) || after.nlink !== opened.nlink
|
|
196
|
+
|| !sameProtectedFile(afterPath, protectedFileIdentity(opened)) || afterPath.nlink !== opened.nlink) {
|
|
197
|
+
throw new Error("service token changed while reading");
|
|
198
|
+
}
|
|
199
|
+
if (size > MAX_SERVICE_TOKEN_BYTES) throw new Error("service token has an invalid size");
|
|
200
|
+
const token = new TextDecoder("utf-8", { fatal: true }).decode(buffer.subarray(0, size)).replace(/^\uFEFF/, "").trim();
|
|
201
|
+
if (token.length < 32) throw new Error("service token is invalid");
|
|
202
|
+
return token;
|
|
203
|
+
} finally {
|
|
204
|
+
fs.closeSync(descriptor);
|
|
205
|
+
}
|
|
206
|
+
} finally {
|
|
207
|
+
closeProtectedDirectory(protectedDirectory, "service token");
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function validateLegacyConfigStats(stats) {
|
|
212
|
+
if (!stats.isFile() || stats.isSymbolicLink()) throw new Error("BLUN MCP configuration must be a regular file");
|
|
213
|
+
if (stats.nlink !== 1) throw new Error("BLUN MCP configuration must not have additional hard links");
|
|
214
|
+
if (stats.size > MAX_BLUN_MCP_CONFIG_BYTES) throw new Error("BLUN MCP configuration exceeds the size limit");
|
|
215
|
+
if (process.platform !== "win32" && (stats.mode & 0o022) !== 0) {
|
|
216
|
+
throw new Error("BLUN MCP configuration is writable outside its owner");
|
|
217
|
+
}
|
|
218
|
+
if (typeof process.getuid === "function" && stats.uid !== process.getuid()) {
|
|
219
|
+
throw new Error("BLUN MCP configuration has the wrong owner");
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function readProtectedLegacyConfig(destination) {
|
|
224
|
+
const protectedDirectory = openProtectedDirectory(
|
|
225
|
+
destination,
|
|
226
|
+
"BLUN MCP configuration",
|
|
227
|
+
{ allowMissing: true },
|
|
228
|
+
);
|
|
229
|
+
if (protectedDirectory === null) return null;
|
|
230
|
+
const configFile = protectedDirectory.accessPath;
|
|
231
|
+
try {
|
|
232
|
+
let before;
|
|
233
|
+
try { before = fs.lstatSync(configFile); }
|
|
234
|
+
catch (error) {
|
|
235
|
+
if (error?.code === "ENOENT") return null;
|
|
236
|
+
throw error;
|
|
237
|
+
}
|
|
238
|
+
validateLegacyConfigStats(before);
|
|
239
|
+
const expected = protectedFileIdentity(before);
|
|
240
|
+
const noFollow = typeof fs.constants.O_NOFOLLOW === "number" ? fs.constants.O_NOFOLLOW : 0;
|
|
241
|
+
const descriptor = fs.openSync(configFile, fs.constants.O_RDONLY | noFollow);
|
|
242
|
+
try {
|
|
243
|
+
const opened = fs.fstatSync(descriptor);
|
|
244
|
+
validateLegacyConfigStats(opened);
|
|
245
|
+
if (!sameProtectedFile(opened, expected) || opened.nlink !== before.nlink) {
|
|
246
|
+
throw new Error("BLUN MCP configuration changed while opening");
|
|
247
|
+
}
|
|
248
|
+
const buffer = Buffer.alloc(MAX_BLUN_MCP_CONFIG_BYTES + 1);
|
|
249
|
+
let size = 0;
|
|
250
|
+
while (size < buffer.length) {
|
|
251
|
+
const count = fs.readSync(descriptor, buffer, size, buffer.length - size, null);
|
|
252
|
+
if (count === 0) break;
|
|
253
|
+
size += count;
|
|
254
|
+
}
|
|
255
|
+
const after = fs.fstatSync(descriptor);
|
|
256
|
+
const afterPath = fs.lstatSync(configFile);
|
|
257
|
+
if (
|
|
258
|
+
!sameProtectedFile(after, expected) || after.nlink !== before.nlink
|
|
259
|
+
|| !sameProtectedFile(afterPath, expected) || afterPath.nlink !== before.nlink
|
|
260
|
+
) throw new Error("BLUN MCP configuration changed while reading");
|
|
261
|
+
if (size > MAX_BLUN_MCP_CONFIG_BYTES) throw new Error("BLUN MCP configuration exceeds the size limit");
|
|
262
|
+
return new TextDecoder("utf-8", { fatal: true })
|
|
263
|
+
.decode(buffer.subarray(0, size)).replace(/^\uFEFF/, "");
|
|
264
|
+
} finally {
|
|
265
|
+
fs.closeSync(descriptor);
|
|
266
|
+
}
|
|
267
|
+
} finally {
|
|
268
|
+
closeProtectedDirectory(protectedDirectory, "BLUN MCP configuration");
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function loadLegacyGuardConfig(userHome) {
|
|
273
|
+
const file = path.join(userHome, ".blun", "mcp.json");
|
|
274
|
+
const raw = readProtectedLegacyConfig(file);
|
|
275
|
+
if (raw === null) return null;
|
|
276
|
+
let parsed;
|
|
277
|
+
try {
|
|
278
|
+
parsed = JSON.parse(raw);
|
|
279
|
+
} catch {
|
|
280
|
+
throw new Error("BLUN MCP configuration is not valid JSON");
|
|
281
|
+
}
|
|
282
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
283
|
+
throw new Error("BLUN MCP configuration root must be an object");
|
|
284
|
+
}
|
|
285
|
+
if (parsed.mcpServers !== undefined && (
|
|
286
|
+
!parsed.mcpServers || typeof parsed.mcpServers !== "object" || Array.isArray(parsed.mcpServers)
|
|
287
|
+
)) throw new Error("BLUN mcpServers must be an object");
|
|
288
|
+
const server = parsed?.mcpServers?.[SERVER_NAME];
|
|
289
|
+
if (server === undefined) return null;
|
|
290
|
+
if (!server || typeof server !== "object" || Array.isArray(server)) {
|
|
291
|
+
throw new Error("BLUN language-guard MCP entry must be an object");
|
|
292
|
+
}
|
|
293
|
+
if (server.env !== undefined && (
|
|
294
|
+
!server.env || typeof server.env !== "object" || Array.isArray(server.env)
|
|
295
|
+
)) throw new Error("BLUN language-guard MCP environment must be an object");
|
|
296
|
+
if (server.args !== undefined && !Array.isArray(server.args)) {
|
|
297
|
+
throw new Error("BLUN language-guard MCP arguments must be an array");
|
|
298
|
+
}
|
|
299
|
+
const env = server.env || {};
|
|
300
|
+
const values = {
|
|
301
|
+
command: String(server.command || ""),
|
|
302
|
+
args: Array.isArray(server.args) ? server.args.map(String) : [],
|
|
303
|
+
cwd: String(server.cwd || ""),
|
|
304
|
+
endpoint: String(env.BLUN_LANGUAGE_GUARD_SERVICE_ENDPOINT || ""),
|
|
305
|
+
tokenFile: String(env.BLUN_LANGUAGE_GUARD_SERVICE_TOKEN_FILE || ""),
|
|
306
|
+
};
|
|
307
|
+
if (
|
|
308
|
+
!values.command || !values.endpoint || !values.tokenFile
|
|
309
|
+
|| values.command.length > 4096 || values.cwd.length > 4096
|
|
310
|
+
|| values.endpoint.length > 4096 || values.tokenFile.length > 4096
|
|
311
|
+
|| values.args.length > 128 || values.args.some(value => value.length > 4096)
|
|
312
|
+
) throw new Error("BLUN language-guard MCP entry is invalid");
|
|
313
|
+
return {
|
|
314
|
+
name: SERVER_NAME,
|
|
315
|
+
...values,
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
function bootstrapLanguageGuardMcp({ userHome, store }) {
|
|
320
|
+
const current = store.getAllInternal().find(item => String(item.name || "").toLowerCase() === SERVER_NAME);
|
|
321
|
+
if (current) return { installed: false, id: current.id, reason: "already-installed" };
|
|
322
|
+
let legacy;
|
|
323
|
+
try { legacy = loadLegacyGuardConfig(userHome); }
|
|
324
|
+
catch {
|
|
325
|
+
throw new LanguageGuardBlocked("legacy BLUN MCP configuration is unsafe", "guard_unavailable");
|
|
326
|
+
}
|
|
327
|
+
if (!legacy?.command || !legacy.endpoint || !legacy.tokenFile) {
|
|
328
|
+
return { installed: false, reason: "legacy-config-missing" };
|
|
329
|
+
}
|
|
330
|
+
const saved = store.save({
|
|
331
|
+
name: SERVER_NAME,
|
|
332
|
+
transport: "stdio",
|
|
333
|
+
command: legacy.command,
|
|
334
|
+
args: legacy.args,
|
|
335
|
+
cwd: legacy.cwd,
|
|
336
|
+
enabled: true,
|
|
337
|
+
secretText: [
|
|
338
|
+
`BLUN_LANGUAGE_GUARD_SERVICE_ENDPOINT=${legacy.endpoint}`,
|
|
339
|
+
`BLUN_LANGUAGE_GUARD_SERVICE_TOKEN_FILE=${legacy.tokenFile}`,
|
|
340
|
+
].join("\n"),
|
|
341
|
+
});
|
|
342
|
+
if (!saved?.ok || !saved.savedId) throw new LanguageGuardBlocked("language guard MCP bootstrap failed", "guard_unavailable");
|
|
343
|
+
return { installed: true, id: saved.savedId };
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
function resolveGuardConnection({ store, environment = process.env }) {
|
|
347
|
+
const server = store.getAllInternal().find(item => String(item.name || "").toLowerCase() === SERVER_NAME);
|
|
348
|
+
let secrets = {};
|
|
349
|
+
if (server) {
|
|
350
|
+
try { secrets = store.getSecrets(server.id) || {}; }
|
|
351
|
+
catch { secrets = {}; }
|
|
352
|
+
}
|
|
353
|
+
const endpoint = String(
|
|
354
|
+
environment.BLUN_LANGUAGE_GUARD_SERVICE_ENDPOINT
|
|
355
|
+
|| secrets.BLUN_LANGUAGE_GUARD_SERVICE_ENDPOINT
|
|
356
|
+
|| "",
|
|
357
|
+
).trim();
|
|
358
|
+
const tokenFile = String(
|
|
359
|
+
environment.BLUN_LANGUAGE_GUARD_SERVICE_TOKEN_FILE
|
|
360
|
+
|| secrets.BLUN_LANGUAGE_GUARD_SERVICE_TOKEN_FILE
|
|
361
|
+
|| "",
|
|
362
|
+
).trim();
|
|
363
|
+
if (!server || server.enabled === false || !endpoint || !tokenFile) {
|
|
364
|
+
throw new LanguageGuardBlocked("mandatory language guard is not configured", "guard_unavailable");
|
|
365
|
+
}
|
|
366
|
+
let serviceToken;
|
|
367
|
+
try { serviceToken = readProtectedServiceToken(tokenFile); }
|
|
368
|
+
catch { throw new LanguageGuardBlocked("mandatory language guard token is unavailable", "guard_unavailable"); }
|
|
369
|
+
if (serviceToken.length < 32) {
|
|
370
|
+
throw new LanguageGuardBlocked("mandatory language guard token is invalid", "guard_unavailable");
|
|
371
|
+
}
|
|
372
|
+
return { endpoint, serviceToken };
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
function resolveLanguage(meta, config) {
|
|
376
|
+
const candidates = [
|
|
377
|
+
[meta?.languageGuardLanguage, "meta.languageGuardLanguage"],
|
|
378
|
+
[config?.languageGuardLanguage, "config.languageGuardLanguage"],
|
|
379
|
+
[config?.responseLanguage, "config.responseLanguage"],
|
|
380
|
+
[config?.language, "config.language"],
|
|
381
|
+
[meta?.telegram?.conversationLanguage, "meta.telegram.conversationLanguage"],
|
|
382
|
+
// Telegram's senderLanguageCode describes the sender's client/interface
|
|
383
|
+
// language. It is not reliable evidence for the language of this message,
|
|
384
|
+
// so retain it only as a backwards-compatible last resort.
|
|
385
|
+
[meta?.telegram?.senderLanguageCode, "meta.telegram.senderLanguageCode"],
|
|
386
|
+
];
|
|
387
|
+
for (const [value, source] of candidates) {
|
|
388
|
+
const language = String(value || "").trim();
|
|
389
|
+
if (language) return { language, source };
|
|
390
|
+
}
|
|
391
|
+
return { language: "", source: "missing" };
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
function languageFromMeta(meta, config) {
|
|
395
|
+
return resolveLanguage(meta, config).language;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
function createBlunLanguageGuard({ store, getConfig, environment = process.env }) {
|
|
399
|
+
function context({ messages, meta = {}, channel = "desktop" }) {
|
|
400
|
+
const prompt = String(messages?.[messages.length - 1]?.content || "");
|
|
401
|
+
const languageResolution = resolveLanguage(meta, getConfig?.() || {});
|
|
402
|
+
const language = languageResolution.language;
|
|
403
|
+
const route = routeHostContext({
|
|
404
|
+
// Keep host evidence and types intact. The shared router infers a
|
|
405
|
+
// translation from source text and rejects an explicit downgrade.
|
|
406
|
+
task_kind: meta.languageGuardTaskKind,
|
|
407
|
+
source_text: meta.languageGuardSourceText,
|
|
408
|
+
target_language: language,
|
|
409
|
+
response_language: language,
|
|
410
|
+
content_type: meta.languageGuardContentType || "prose",
|
|
411
|
+
});
|
|
412
|
+
const connection = resolveGuardConnection({ store, environment });
|
|
413
|
+
return {
|
|
414
|
+
hostContext: {
|
|
415
|
+
task_kind: route.taskKind,
|
|
416
|
+
operation: route.taskKind === "translation" ? "translation" : "chat",
|
|
417
|
+
source_text: route.sourceText,
|
|
418
|
+
target_language: route.taskKind === "translation" ? route.language : undefined,
|
|
419
|
+
response_language: route.taskKind === "response" ? route.language : undefined,
|
|
420
|
+
content_type: route.contentType,
|
|
421
|
+
},
|
|
422
|
+
endpoint: connection.endpoint,
|
|
423
|
+
serviceToken: connection.serviceToken,
|
|
424
|
+
agentId: String(meta.agentName || meta.agentId || "blun-code"),
|
|
425
|
+
channel: String(channel || "desktop"),
|
|
426
|
+
prompt,
|
|
427
|
+
route,
|
|
428
|
+
languageSource: languageResolution.source,
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
function mandatoryInstruction(guardContext) {
|
|
433
|
+
const tool = guardContext.route.taskKind === "translation" ? "release_translation" : "release_response";
|
|
434
|
+
const translationRule = guardContext.route.taskKind === "translation"
|
|
435
|
+
? "Load and apply the installed translate-native skill/plugin before drafting. Use the complete trusted source supplied by the host."
|
|
436
|
+
: "If the request is actually a translation but the host did not mark it as translation, do not translate; explain that trusted translation routing is required.";
|
|
437
|
+
return [
|
|
438
|
+
"[BLUN LANGUAGE GUARD — MANDATORY]",
|
|
439
|
+
`The host classified this output as ${guardContext.route.taskKind} in ${guardContext.route.language}.`,
|
|
440
|
+
`Pass language exactly as ${JSON.stringify(guardContext.route.language)} to ${tool}; do not substitute a base language or another locale.`,
|
|
441
|
+
translationRule,
|
|
442
|
+
`Before final output, call ${tool} for the complete final candidate with truthful attestations.`,
|
|
443
|
+
"Final output must be exactly one JSON object with only target_text and release_token.",
|
|
444
|
+
"Do not stream, print, or send the candidate through another channel.",
|
|
445
|
+
"[/BLUN LANGUAGE GUARD]",
|
|
446
|
+
].join("\n");
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
function decorateMessages(messages, guardContext) {
|
|
450
|
+
const copy = Array.isArray(messages) ? messages.map(item => ({ ...item })) : [];
|
|
451
|
+
if (!copy.length) return copy;
|
|
452
|
+
const index = copy.length - 1;
|
|
453
|
+
copy[index].content = `${String(copy[index].content || "")}\n\n${mandatoryInstruction(guardContext)}`;
|
|
454
|
+
return copy;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
function bufferedEmitter(emit) {
|
|
458
|
+
if (typeof emit !== "function") return undefined;
|
|
459
|
+
return event => {
|
|
460
|
+
if (event?.type === "text-delta" || event?.type === "done") return;
|
|
461
|
+
emit(event);
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
async function releaseResult(result, guardContext, emit) {
|
|
466
|
+
if (result?.error || result?.cancelled) return result;
|
|
467
|
+
const rawEnvelope = result?.answer || result?.reply || "";
|
|
468
|
+
const verified = await verifyForDelivery({
|
|
469
|
+
rawEnvelope,
|
|
470
|
+
hostContext: guardContext.hostContext,
|
|
471
|
+
endpoint: guardContext.endpoint,
|
|
472
|
+
serviceToken: guardContext.serviceToken,
|
|
473
|
+
agentId: guardContext.agentId,
|
|
474
|
+
channel: guardContext.channel,
|
|
475
|
+
});
|
|
476
|
+
if (typeof emit === "function") {
|
|
477
|
+
emit({ type: "text-delta", delta: verified.text, languageGuardVerified: true });
|
|
478
|
+
emit({ type: "done", answer: verified.text, languageGuardVerified: true });
|
|
479
|
+
}
|
|
480
|
+
return {
|
|
481
|
+
...result,
|
|
482
|
+
answer: verified.text,
|
|
483
|
+
reply: verified.text,
|
|
484
|
+
languageGuardVerified: true,
|
|
485
|
+
languageGuard: {
|
|
486
|
+
taskKind: verified.route.taskKind,
|
|
487
|
+
language: verified.route.language,
|
|
488
|
+
languageSource: guardContext.languageSource,
|
|
489
|
+
version: verified.verification?.version || "",
|
|
490
|
+
},
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
return {
|
|
495
|
+
mandatory: true,
|
|
496
|
+
context,
|
|
497
|
+
mandatoryInstruction,
|
|
498
|
+
decorateMessages,
|
|
499
|
+
bufferedEmitter,
|
|
500
|
+
releaseResult,
|
|
501
|
+
};
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
module.exports = {
|
|
505
|
+
SERVER_NAME,
|
|
506
|
+
loadLegacyGuardConfig,
|
|
507
|
+
readProtectedLegacyConfig,
|
|
508
|
+
readProtectedServiceToken,
|
|
509
|
+
bootstrapLanguageGuardMcp,
|
|
510
|
+
resolveGuardConnection,
|
|
511
|
+
resolveLanguage,
|
|
512
|
+
languageFromMeta,
|
|
513
|
+
createBlunLanguageGuard,
|
|
514
|
+
};
|