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
|
@@ -19,30 +19,29 @@ import { readHookInput, SILENT_OVERSIZE_POST_TOOL_USE, SILENT_OVERSIZE_POST_TOOL
|
|
|
19
19
|
import { isMainModule } from "./lib/runtime.js";
|
|
20
20
|
import { deliveryActorSession, deliverySuccessEvidence, recordDeliveryToolUse,
|
|
21
21
|
recordDeliveryWriteIntent } from "./lib/delivery-verification.js";
|
|
22
|
-
import {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
import {
|
|
26
|
-
ATTENTION_WRITE_EVENTS, boundedId, captureAttentionLifecycle, hookDeliveryId, hostContextLimit, hostFromInput,
|
|
22
|
+
import { blockPrompt, blockStop, blunRuntimeContext, blunRuntimeMessage, denyTool, hookOutput,
|
|
23
|
+
lifecycleOutput } from "./lib/hook-output.js";
|
|
24
|
+
import { ATTENTION_WRITE_EVENTS, boundedId, captureAttentionLifecycle, hookDeliveryId, hostContextLimit, hostFromInput,
|
|
27
25
|
promptFromInput, renderContext, runtimeScope, selfstarterInput, selfstarterRootSkipped,
|
|
28
|
-
selfstarterScope, sessionId, startChannelEvent, startSelfstarter, toolResult,
|
|
29
|
-
} from "./lib/hook-context.js";
|
|
30
|
-
import {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
} from "./lib/hook-
|
|
34
|
-
import {
|
|
35
|
-
captureJavaScriptBeforeWrite, inspectWrittenJavaScript, verifyBaselineBeforeWrite, verifyDeliveredArtifacts
|
|
36
|
-
} from "./lib/hook-artifact-guards.js";
|
|
26
|
+
selfstarterScope, sessionId, startChannelEvent, startSelfstarter, toolResult,
|
|
27
|
+
toolSucceeded } from "./lib/hook-context.js";
|
|
28
|
+
import { auditGuard, auditSkippedScans, candidatePaths, finishScanFailure, hookScanFailureFailsOpen,
|
|
29
|
+
isMutationTool, isScanFailOpenTool, shellTargetsProtected } from "./lib/hook-protection.js";
|
|
30
|
+
import { captureJavaScriptBeforeWrite, inspectWrittenJavaScript, verifyBaselineBeforeWrite,
|
|
31
|
+
verifyDeliveredArtifacts } from "./lib/hook-artifact-guards.js";
|
|
37
32
|
import { isPremortemWrite, prepareHookPremortem, recordHookPremortemWrite,
|
|
38
33
|
recordHookPremortemWriteIntent, verifyHookPremortemWrite } from "./lib/hook-premortem.js";
|
|
39
34
|
import { verifyHookStopContracts } from "./lib/hook-stop-verification.js";
|
|
40
35
|
import { processAdvisory } from "./lib/hook-process-advisory.js";
|
|
36
|
+
import { recordHookBriefingUse } from "./lib/hook-briefing-use.js";
|
|
41
37
|
export { blunRuntimeContext, blunRuntimeMessage } from "./lib/hook-output.js";
|
|
42
38
|
const CONTEXT_EVENTS = new Set(["SessionStart", "UserPromptSubmit", "PreCompact", "PostCompact"]);
|
|
43
|
-
const KNOWN_EVENTS = new Set([
|
|
44
|
-
|
|
45
|
-
]
|
|
39
|
+
const KNOWN_EVENTS = new Set([...CONTEXT_EVENTS, "InstructionsLoaded", "PreToolUse", "PostToolUse", "Stop", "SubagentStop"]);
|
|
40
|
+
async function writeContextOutput(output, host) {
|
|
41
|
+
const field = Object.hasOwn(output.hookSpecificOutput, "message") ? "message" : "additionalContext", content = output.hookSpecificOutput[field];
|
|
42
|
+
await new Promise((resolveWrite, rejectWrite) => process.stdout.write(`${JSON.stringify(output)}\n`, (error) => error ? rejectWrite(error) : resolveWrite()));
|
|
43
|
+
return { schema: "agentspine.host-context-handoff/v1", host, field, bytes: Buffer.byteLength(content), digest: createHash("sha256").update(content).digest("hex") };
|
|
44
|
+
}
|
|
46
45
|
async function runHookCore(input, payload, options) {
|
|
47
46
|
if (!input || typeof input !== "object" || Array.isArray(input)) throw new Error("hook input must be one JSON object");
|
|
48
47
|
const event = input.hook_event_name || input.event_name || "";
|
|
@@ -220,7 +219,7 @@ async function runHookCore(input, payload, options) {
|
|
|
220
219
|
}
|
|
221
220
|
premortem = { ...premortem, writeIntent: premortemIntent.status,
|
|
222
221
|
writeDigest: premortemIntent.writeDigest || null };
|
|
223
|
-
try { lessonRecall = actionLessonRecall({ catalog, event, input, scope }); }
|
|
222
|
+
try { lessonRecall = await actionLessonRecall({ catalog, event, input, scope }); }
|
|
224
223
|
catch (error) { lessonRecall = { status: "degraded", items: [], reason: error.message, authority: "context-only" }; }
|
|
225
224
|
}
|
|
226
225
|
if (["PostToolUse", "Stop", "SubagentStop"].includes(event)) {
|
|
@@ -255,7 +254,6 @@ async function runHookCore(input, payload, options) {
|
|
|
255
254
|
if (contracts.blocked) {
|
|
256
255
|
return processAdvisory(input, payload, root, scope, { deliveryVerification, premortem });
|
|
257
256
|
}
|
|
258
|
-
|
|
259
257
|
try {
|
|
260
258
|
artifactGuard = await verifyDeliveredArtifacts({ input, cwd });
|
|
261
259
|
if (artifactGuard.blocked) {
|
|
@@ -287,7 +285,6 @@ async function runHookCore(input, payload, options) {
|
|
|
287
285
|
scope = await runtimeScope(input, root, resolvedSources.userStateRoot, catalog);
|
|
288
286
|
attentionEvent = await captureAttentionLifecycle(input, event, root, scope, catalog);
|
|
289
287
|
}
|
|
290
|
-
|
|
291
288
|
if (event === "PostToolUse" && !selfstarterRootSkipped(resolvedSources.diagnostics)) {
|
|
292
289
|
scope ||= await runtimeScope(input, root, resolvedSources.userStateRoot, catalog);
|
|
293
290
|
const exact = await selfstarterScope(input, scope, root, "effect");
|
|
@@ -298,7 +295,6 @@ async function runHookCore(input, payload, options) {
|
|
|
298
295
|
});
|
|
299
296
|
}
|
|
300
297
|
}
|
|
301
|
-
|
|
302
298
|
if (["Stop", "SubagentStop"].includes(event)) {
|
|
303
299
|
scope ||= await runtimeScope(input, root, resolvedSources.userStateRoot, catalog);
|
|
304
300
|
const exact = selfstarterRootSkipped(resolvedSources.diagnostics)
|
|
@@ -323,10 +319,10 @@ async function runHookCore(input, payload, options) {
|
|
|
323
319
|
});
|
|
324
320
|
}
|
|
325
321
|
}
|
|
326
|
-
|
|
327
322
|
if (CONTEXT_EVENTS.has(event)) {
|
|
328
323
|
let signal = null;
|
|
329
324
|
let preflight = null;
|
|
325
|
+
let briefingOrigin = null;
|
|
330
326
|
try {
|
|
331
327
|
await syncPersonaRosterFromEnvironment({ root, env: process.env, now: input.timestamp || new Date(), catalog });
|
|
332
328
|
scope ||= await runtimeScope(input, root, resolvedSources.userStateRoot, catalog);
|
|
@@ -371,16 +367,16 @@ async function runHookCore(input, payload, options) {
|
|
|
371
367
|
}
|
|
372
368
|
const briefing = await sessionBriefing({
|
|
373
369
|
root, cwd, host: scope.host, entityId: scope.entityId, groupId: scope.groupId,
|
|
374
|
-
userId: scope.userId, tenantId: scope.tenantId, projectId: scope.projectId, currentTaskId: scope.currentTaskId,
|
|
370
|
+
userId: scope.userId, tenantId: scope.tenantId, projectId: scope.projectId, currentTaskId: scope.currentTaskId, portalRef: scope.portalRef, threadRef: scope.threadRef,
|
|
375
371
|
includePrivate: Boolean(scope.entityId && !scope.groupId),
|
|
376
372
|
focusActive: true, includeSourceContent: event === "UserPromptSubmit" ? false : !scope.groupId,
|
|
377
373
|
maxBytes: event === "UserPromptSubmit" ? 4096 : scope.config.maxBriefingBytes,
|
|
378
374
|
now: input.timestamp || new Date(),
|
|
379
|
-
catalog, userStateRoot: resolvedSources.userStateRoot, sourceDiagnostics: resolvedSources.diagnostics,
|
|
380
|
-
prompt: event === "UserPromptSubmit" ? promptFromInput(input) : null
|
|
375
|
+
catalog, userStateRoot: resolvedSources.userStateRoot, sourceDiagnostics: event === "UserPromptSubmit" ? null : resolvedSources.diagnostics,
|
|
376
|
+
prompt: event === "UserPromptSubmit" ? promptFromInput(input) : null, preAnswer: event === "UserPromptSubmit"
|
|
381
377
|
});
|
|
382
378
|
if (event === "PostCompact") {
|
|
383
|
-
try { lessonRecall = actionLessonRecall({ catalog, event, input, scope }); }
|
|
379
|
+
try { lessonRecall = await actionLessonRecall({ catalog, event, input, scope }); }
|
|
384
380
|
catch (error) { lessonRecall = { status: "degraded", items: [], reason: error.message, authority: "context-only" }; }
|
|
385
381
|
}
|
|
386
382
|
let context = renderContext(event, catalog, briefing, signal, attentionEvent, selfstarter, channelEvent, resolvedSources.diagnostics, preflight, lessonRecall);
|
|
@@ -388,10 +384,11 @@ async function runHookCore(input, payload, options) {
|
|
|
388
384
|
throw new Error("mandatory preflight context exceeds the host hook injection limit");
|
|
389
385
|
}
|
|
390
386
|
if (event === "UserPromptSubmit") {
|
|
391
|
-
const
|
|
387
|
+
const finalized = await finalizeUserPromptSessionTimeline({ root, input, scope, resolvedSources, preflight,
|
|
392
388
|
prompt: promptFromInput(input), now: input.timestamp || new Date() });
|
|
393
|
-
if (!preflightConsumed) throw new Error("preflight receipt could not be consumed atomically for this exact turn");
|
|
394
|
-
|
|
389
|
+
if (!finalized.preflightConsumed) throw new Error("preflight receipt could not be consumed atomically for this exact turn");
|
|
390
|
+
briefingOrigin = finalized.briefingOrigin;
|
|
391
|
+
resolvedSources.diagnostics.timeline = finalized.timeline;
|
|
395
392
|
}
|
|
396
393
|
if (event === "UserPromptSubmit") {
|
|
397
394
|
const activeCanaries = briefing.learning.filter((item) => ["active", "revalidating"].includes(item.outcomeStatus));
|
|
@@ -433,7 +430,12 @@ async function runHookCore(input, payload, options) {
|
|
|
433
430
|
}
|
|
434
431
|
}
|
|
435
432
|
if (payload) return { blocked: false, context, briefing, preflight, signal, attentionEvent, channelEvent, lessonRecall, catalogPath };
|
|
436
|
-
|
|
433
|
+
const output = hookOutput(event, context);
|
|
434
|
+
const handoff = await writeContextOutput(output, process.env.BLUN_PLUGIN_ROOT ? "king"
|
|
435
|
+
: process.env.PLUGIN_ROOT ? "codex" : process.env.CLAUDE_PLUGIN_ROOT ? "claude" : scope.host);
|
|
436
|
+
if (event === "UserPromptSubmit" && briefingOrigin) {
|
|
437
|
+
await recordHookBriefingUse({ origin: briefingOrigin, root, handoff, now: input.timestamp || new Date() });
|
|
438
|
+
}
|
|
437
439
|
return;
|
|
438
440
|
} catch (error) {
|
|
439
441
|
if (hookScanFailureFailsOpen(error)) {
|
|
@@ -468,7 +470,6 @@ async function runHookCore(input, payload, options) {
|
|
|
468
470
|
learningDelivery, deliveryVerification, premortem, lessonRecall };
|
|
469
471
|
process.stdout.write(`${JSON.stringify(lifecycleOutput(event, artifactGuard, premortem, deliveryVerification, process.env, sourceWarning, lessonRecall))}\n`);
|
|
470
472
|
}
|
|
471
|
-
|
|
472
473
|
export async function runHook(payload = null, options = {}) {
|
|
473
474
|
let input = payload;
|
|
474
475
|
try {
|
|
@@ -485,7 +486,6 @@ export async function runHook(payload = null, options = {}) {
|
|
|
485
486
|
return finishScanFailure(input, payload, "lifecycle", error);
|
|
486
487
|
}
|
|
487
488
|
}
|
|
488
|
-
|
|
489
489
|
if (isMainModule(import.meta.url)) {
|
|
490
490
|
const args = process.argv.slice(2);
|
|
491
491
|
const silentOversizePostToolUse = args.length === 1 && args[0] === SILENT_OVERSIZE_POST_TOOL_USE_ARG;
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { documentSnapshotContent } from "./documents.js";
|
|
3
|
+
import { learningContext } from "./learning-context.js";
|
|
3
4
|
|
|
4
5
|
const AUTHORITY = "context-only";
|
|
5
6
|
const MAX_ITEMS = 6;
|
|
7
|
+
const MAX_LEARNING_ITEMS = 3;
|
|
6
8
|
const MAX_ITEM_BYTES = 2048;
|
|
7
9
|
const MAX_TOTAL_BYTES = 8192;
|
|
8
10
|
|
|
@@ -10,17 +12,77 @@ function digest(value) {
|
|
|
10
12
|
return createHash("sha256").update(JSON.stringify(value)).digest("hex");
|
|
11
13
|
}
|
|
12
14
|
|
|
13
|
-
|
|
15
|
+
function learningScope(scope) {
|
|
16
|
+
return {
|
|
17
|
+
personaId: scope.entityId,
|
|
18
|
+
userId: scope.userId,
|
|
19
|
+
tenantId: scope.tenantId,
|
|
20
|
+
projectId: scope.projectId,
|
|
21
|
+
groupId: scope.groupId,
|
|
22
|
+
taskId: scope.currentTaskId
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function compactLearning(item) {
|
|
27
|
+
return {
|
|
28
|
+
id: item.id,
|
|
29
|
+
kind: item.kind,
|
|
30
|
+
claim: item.claim,
|
|
31
|
+
subjectId: item.subjectId,
|
|
32
|
+
confidence: item.confidence,
|
|
33
|
+
evidenceCount: item.evidenceCount,
|
|
34
|
+
acceptedAt: item.acceptedAt,
|
|
35
|
+
outcomeStatus: item.outcomeStatus,
|
|
36
|
+
relevance: item.relevance,
|
|
37
|
+
authority: AUTHORITY
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export async function actionLessonRecall({ catalog, event, input, scope }) {
|
|
14
42
|
const candidates = catalog.documents
|
|
15
43
|
.filter((item) => item.sourceScope === "project-memory" && item.name !== "MEMORY.md")
|
|
16
44
|
.filter((item) => ["prompt", "pinned", "entity", "project", "task", "always"].includes(item.relevance));
|
|
17
45
|
if (scope.groupId) return {
|
|
18
|
-
schema: "agentspine.action-lesson-recall/
|
|
19
|
-
items: [], omitted: candidates.length, instruction: null, authority: AUTHORITY
|
|
46
|
+
schema: "agentspine.action-lesson-recall/v2", status: "group-suppressed", event,
|
|
47
|
+
items: [], learning: [], omitted: candidates.length, instruction: null, authority: AUTHORITY
|
|
20
48
|
};
|
|
21
49
|
let used = 0;
|
|
22
50
|
let omitted = Math.max(0, candidates.length - MAX_ITEMS);
|
|
23
51
|
const items = [];
|
|
52
|
+
const learning = [];
|
|
53
|
+
let learningDiagnostics = { status: "not-applicable", reason: null };
|
|
54
|
+
if (event === "PreToolUse" && scope.currentTaskId && scope.entityId && scope.userId && scope.tenantId && scope.projectId) {
|
|
55
|
+
try {
|
|
56
|
+
const selected = await learningContext({
|
|
57
|
+
root: catalog.root,
|
|
58
|
+
includePrivate: true,
|
|
59
|
+
groupId: null,
|
|
60
|
+
scope: learningScope(scope),
|
|
61
|
+
maxItems: 50,
|
|
62
|
+
catalog,
|
|
63
|
+
now: input.timestamp || new Date(),
|
|
64
|
+
taskFocus: scope.currentTaskId
|
|
65
|
+
});
|
|
66
|
+
const exact = selected.items
|
|
67
|
+
.filter((item) => item.relevance?.match === "exact-task"
|
|
68
|
+
&& item.relevance.taskId === scope.currentTaskId
|
|
69
|
+
&& ["active", "validated", "revalidating"].includes(item.outcomeStatus));
|
|
70
|
+
for (const item of exact.slice(0, MAX_LEARNING_ITEMS)) {
|
|
71
|
+
const compact = compactLearning(item);
|
|
72
|
+
const bytes = Buffer.byteLength(JSON.stringify(compact));
|
|
73
|
+
if (bytes > MAX_ITEM_BYTES || used + bytes > MAX_TOTAL_BYTES) {
|
|
74
|
+
omitted += 1;
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
learning.push(compact);
|
|
78
|
+
used += bytes;
|
|
79
|
+
}
|
|
80
|
+
omitted += Math.max(0, exact.length - MAX_LEARNING_ITEMS);
|
|
81
|
+
learningDiagnostics = { status: learning.length ? "recalled" : "none", reason: null };
|
|
82
|
+
} catch (error) {
|
|
83
|
+
learningDiagnostics = { status: "degraded", reason: String(error.message).slice(0, 512) };
|
|
84
|
+
}
|
|
85
|
+
}
|
|
24
86
|
for (const document of candidates.slice(0, MAX_ITEMS)) {
|
|
25
87
|
const snapshot = documentSnapshotContent(document);
|
|
26
88
|
const bytes = snapshot?.byteLength || 0;
|
|
@@ -36,17 +98,20 @@ export function actionLessonRecall({ catalog, event, input, scope }) {
|
|
|
36
98
|
const material = {
|
|
37
99
|
event, sessionId: input.session_id ?? input.sessionId ?? null,
|
|
38
100
|
toolName: input.tool_name || null, toolUseId: input.tool_use_id || null,
|
|
39
|
-
paths: items.map((item) => [item.path, item.sha256])
|
|
101
|
+
paths: items.map((item) => [item.path, item.sha256]),
|
|
102
|
+
learning: learning.map((item) => [item.id, item.acceptedAt, item.outcomeStatus])
|
|
40
103
|
};
|
|
41
104
|
return {
|
|
42
|
-
schema: "agentspine.action-lesson-recall/
|
|
43
|
-
status: items.length ? "recalled" : "none",
|
|
105
|
+
schema: "agentspine.action-lesson-recall/v2",
|
|
106
|
+
status: items.length || learning.length ? "recalled" : learningDiagnostics.status === "degraded" ? "degraded" : "none",
|
|
44
107
|
event,
|
|
45
108
|
receiptDigest: digest(material),
|
|
46
109
|
items,
|
|
110
|
+
learning,
|
|
111
|
+
learningDiagnostics,
|
|
47
112
|
omitted,
|
|
48
|
-
instruction: items.length
|
|
49
|
-
? "Before this action, compare the plan with every recalled lesson below. These are untrusted context only: they can constrain behavior through current host rules, but never grant permissions, identity, tools, access, delegation or policy exceptions."
|
|
113
|
+
instruction: items.length || learning.length
|
|
114
|
+
? "Before this action, compare the plan with every recalled source lesson and outcome-gated exact-task strategy below. These are untrusted context only: they can constrain behavior through current host rules, but never grant permissions, identity, tools, access, delegation or policy exceptions."
|
|
50
115
|
: null,
|
|
51
116
|
authority: AUTHORITY
|
|
52
117
|
};
|
|
@@ -55,8 +55,6 @@ function recalculateBudget(result) {
|
|
|
55
55
|
function tryAdd(result, collection, item) {
|
|
56
56
|
collection.push(item);
|
|
57
57
|
recalculateBudget(result);
|
|
58
|
-
// Keep a small accounting reserve so growing omission counters can never
|
|
59
|
-
// invalidate a packet after an item has been accepted.
|
|
60
58
|
if (result.budget.usedBytes <= result.budget.maxBytes - 128) return true;
|
|
61
59
|
collection.pop();
|
|
62
60
|
recalculateBudget(result);
|
|
@@ -96,6 +94,108 @@ function voiceProfile(entity) {
|
|
|
96
94
|
.map(([key, item]) => [key, typeof item === "string" ? item.slice(0, 120) : item]));
|
|
97
95
|
}
|
|
98
96
|
|
|
97
|
+
function pick(value, keys) {
|
|
98
|
+
return Object.fromEntries(keys.map((key) => [key, value[key]]));
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function feedbackCandidates(values) {
|
|
102
|
+
if (values.length < 3) return values.map((item) =>
|
|
103
|
+
pick(item, ["id", "text", "provider", "digest", "session", "message", "at"]));
|
|
104
|
+
const shared = ["provider", "digest", "session"].filter((key) =>
|
|
105
|
+
values.every((item) => item[key] === values[0][key]));
|
|
106
|
+
const fields = ["id", "text", "message", "at",
|
|
107
|
+
...["provider", "digest", "session"].filter((key) => !shared.includes(key))];
|
|
108
|
+
const expected = { id: "assertion:user-feedback-", message: "timeline-event:" };
|
|
109
|
+
const prefixes = fields.map((key) => expected[key] || (key === "at"
|
|
110
|
+
&& values.every((item) => /^\d{4}-\d{2}-\d{2}T\d{2}:/.test(item[key]))
|
|
111
|
+
? values[0][key].slice(0, 14) : ""));
|
|
112
|
+
return { fields, common: Object.fromEntries(shared.map((key) => [key, values[0][key]])), prefixes,
|
|
113
|
+
rows: values.map((item) => fields.map((key, index) => item[key].slice(prefixes[index].length))) };
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function preAnswerRecall(world, currentTaskId) {
|
|
117
|
+
if (!currentTaskId) return null;
|
|
118
|
+
const task = [...(world.knowledge?.continuation?.tasks || []),
|
|
119
|
+
...(world.knowledge?.continuation?.terminal || [])]
|
|
120
|
+
.find((item) => item.taskId === currentTaskId);
|
|
121
|
+
if (!task) return null;
|
|
122
|
+
const feedback = (world.knowledge?.taskContext?.items || []).filter((item) =>
|
|
123
|
+
item?.source?.kind === "uninterpreted-user-message"
|
|
124
|
+
&& item.value?.targetAssertionId === task.assertionId)
|
|
125
|
+
.sort((left, right) => right.observedAt.localeCompare(left.observedAt));
|
|
126
|
+
const interpretations = (world.knowledge?.taskContext?.items || []).filter((item) =>
|
|
127
|
+
item?.source?.kind === "model-suggestion"
|
|
128
|
+
&& ["agentspine.timeline-user-feedback-interpretation/v1",
|
|
129
|
+
"agentspine.timeline-user-feedback-clarification/v2"].includes(item.value?.schema)
|
|
130
|
+
&& item.value?.targetAssertionId === task.assertionId);
|
|
131
|
+
const taskValue = pick(task, ["taskId", "status", "objective"]);
|
|
132
|
+
taskValue.lastVerifiedStep = task.lastVerifiedStep
|
|
133
|
+
? pick(task.lastVerifiedStep, ["summary", "result"]) : null;
|
|
134
|
+
taskValue.nextStep = task.nextStep ? pick(task.nextStep, ["summary"]) : null;
|
|
135
|
+
const values = feedback.slice(0, 3).map(({ id, value, source, observedAt }) => ({
|
|
136
|
+
id,
|
|
137
|
+
text: value.sourceText,
|
|
138
|
+
status: value.interpretationStatus, completionVerified: value.completionVerified,
|
|
139
|
+
provider: value.sourceProvider, digest: value.sourceDigest,
|
|
140
|
+
session: source.sessionRef, message: source.messageRef, at: observedAt
|
|
141
|
+
}));
|
|
142
|
+
if (values.length && task.status === "completed" && task.source?.kind === "objective-measurement") {
|
|
143
|
+
taskValue.completionEvidence = {
|
|
144
|
+
status: "objective-verified", assertionId: task.assertionId, observedAt: task.observedAt,
|
|
145
|
+
source: pick(task.source, ["kind", "id", "digest", "sessionRef", "messageRef"])
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
if (!values.length) {
|
|
149
|
+
Object.assign(taskValue, pick(task, ["assertionId", "observedAt"]));
|
|
150
|
+
taskValue.source = pick(task.source, ["kind", "id", "digest", "sessionRef", "messageRef"]);
|
|
151
|
+
taskValue.scope = pick(task.scope, ["projectId", "groupId", "privacy", "portalRef", "threadRef"]);
|
|
152
|
+
taskValue.correctionStatus = task.source.kind === "explicit-user-feedback"
|
|
153
|
+
? "applied-source-verified" : "none-current";
|
|
154
|
+
}
|
|
155
|
+
if (values.length === 1) {
|
|
156
|
+
const proposal = interpretations.find((item) =>
|
|
157
|
+
item.value.sourceFeedbackAssertionId === feedback[0].id);
|
|
158
|
+
if (proposal) {
|
|
159
|
+
const value = proposal.value;
|
|
160
|
+
const model = {
|
|
161
|
+
status: value.interpretationStatus, kind: value.interpretationKind,
|
|
162
|
+
nextStep: value.proposedNextStepSummary, question: value.clarificationQuestion,
|
|
163
|
+
provider: value.modelProvider, replaces: value.replacedNextStepId,
|
|
164
|
+
digest: proposal.source.digest, completionVerified: false
|
|
165
|
+
};
|
|
166
|
+
for (const key of ["nextStep", "question"]) {
|
|
167
|
+
if (model[key] === null) delete model[key];
|
|
168
|
+
}
|
|
169
|
+
values[0].modelInterpretation = model;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return {
|
|
173
|
+
schema: "agentspine.pre-answer-recall/v1",
|
|
174
|
+
order: "review-before-claims-and-actions",
|
|
175
|
+
task: taskValue,
|
|
176
|
+
...(values.length === 1 ? { feedback: values[0], ...(task.status === "completed" ? {} : {
|
|
177
|
+
interpretationInput: { feedbackAssertionId: feedback[0].id,
|
|
178
|
+
targetAssertionId: feedback[0].value.targetAssertionId }
|
|
179
|
+
}) } : {}),
|
|
180
|
+
...(values.length > 1 ? { feedbackCandidates: feedbackCandidates(values),
|
|
181
|
+
feedbackReview: { status: "multiple-unresolved", completionVerified: false,
|
|
182
|
+
targetAssertionId: feedback[0].value.targetAssertionId,
|
|
183
|
+
...(() => {
|
|
184
|
+
const ids = feedback.slice(0, 3).map((item) => item.id).sort();
|
|
185
|
+
const proposal = interpretations.find((item) => item.value?.schema
|
|
186
|
+
=== "agentspine.timeline-user-feedback-clarification/v2"
|
|
187
|
+
&& JSON.stringify(item.value.sourceBindings.map((source) => source.feedbackAssertionId))
|
|
188
|
+
=== JSON.stringify(ids));
|
|
189
|
+
return proposal ? { modelClarification: { status: proposal.value.interpretationStatus,
|
|
190
|
+
question: proposal.value.clarificationQuestion, provider: proposal.value.modelProvider,
|
|
191
|
+
replaces: proposal.value.replacedNextStepId, digest: proposal.source.digest,
|
|
192
|
+
completionVerified: false } } : {};
|
|
193
|
+
})(),
|
|
194
|
+
...(feedback.length > 3 ? { omitted: feedback.length - 3 } : {}) } } : {}),
|
|
195
|
+
authority: "context-only"
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
|
|
99
199
|
async function settleReads(promises) {
|
|
100
200
|
const settled = await Promise.allSettled(promises);
|
|
101
201
|
const failed = settled.find((item) => item.status === "rejected");
|
|
@@ -103,16 +203,13 @@ async function settleReads(promises) {
|
|
|
103
203
|
return settled.map((item) => item.value);
|
|
104
204
|
}
|
|
105
205
|
|
|
106
|
-
/**
|
|
107
|
-
* Assemble one immutable, privacy-filtered context packet for a host session.
|
|
108
|
-
* The packet is descriptive only and fits maxBytes as compact UTF-8 JSON.
|
|
109
|
-
*/
|
|
110
206
|
export async function sessionBriefing({
|
|
111
207
|
root = process.cwd(), cwd = root, host = "generic", entityId = null,
|
|
112
208
|
userId = null, tenantId = null, groupId = null, projectId = null, currentTaskId = null,
|
|
209
|
+
portalRef = null, threadRef = null,
|
|
113
210
|
includePrivate = false, focusActive = true, includeSourceContent = true,
|
|
114
211
|
maxBytes = 16384, now = new Date(), catalog: providedCatalog = null, userStateRoot = null,
|
|
115
|
-
sourceDiagnostics = null, prompt = null
|
|
212
|
+
sourceDiagnostics = null, prompt = null, preAnswer = false
|
|
116
213
|
} = {}) {
|
|
117
214
|
const limit = integer(maxBytes, "maxBytes", MIN_BYTES, MAX_BYTES);
|
|
118
215
|
if (!new Set(["codex", "claude", "generic"]).has(host)) throw new Error(`unsupported host: ${host}`);
|
|
@@ -136,7 +233,8 @@ export async function sessionBriefing({
|
|
|
136
233
|
: { root: catalog.root, entityId, includePrivate, groupId, catalog })
|
|
137
234
|
: null;
|
|
138
235
|
const [learned, attention, tasks, shared, userLearned, personas, gateway, world, portfolio] = await settleReads([
|
|
139
|
-
learningContext({ root: catalog.root, includePrivate, groupId, scope: learningScope, maxItems: 50,
|
|
236
|
+
learningContext({ root: catalog.root, includePrivate, groupId, scope: learningScope, maxItems: 50,
|
|
237
|
+
catalog, now, taskFocus: currentTaskId }),
|
|
140
238
|
attentionContext({
|
|
141
239
|
root: catalog.root, includePrivate, entityId, groupId, projectId, currentTaskId,
|
|
142
240
|
focusActive, markPresented: false, maxItems: 20, now, catalog
|
|
@@ -145,11 +243,11 @@ export async function sessionBriefing({
|
|
|
145
243
|
sharedContext({ root: catalog.root, includePrivate, groupId, maxItems: 50, catalog }),
|
|
146
244
|
userStateRoot && userStateRoot !== catalog.root
|
|
147
245
|
? learningContext({ root: userStateRoot, includePrivate, groupId, scope: learningScope, maxItems: 50, now,
|
|
148
|
-
catalog: userCatalog })
|
|
246
|
+
catalog: userCatalog, taskFocus: currentTaskId })
|
|
149
247
|
: Promise.resolve({ items: [] }),
|
|
150
248
|
loadPersonaRuntime(catalog.root, catalog),
|
|
151
249
|
loadGatewayRuntime(catalog.root, catalog),
|
|
152
|
-
worldContext({ root: catalog.root, projectId, groupId, includePrivate,
|
|
250
|
+
worldContext({ root: catalog.root, projectId, groupId, includePrivate, portalRef, threadRef,
|
|
153
251
|
continuationTaskId: currentTaskId, maxItems: 50, now }),
|
|
154
252
|
tenantId ? projectPortfolioContext({ root: catalog.root, tenantId, groupId, markPresented: false, now })
|
|
155
253
|
: Promise.resolve({ projects: [], observations: [], notice: null, rateLimited: false })
|
|
@@ -163,13 +261,15 @@ export async function sessionBriefing({
|
|
|
163
261
|
}
|
|
164
262
|
const gatewayFindings = gatewayRuntimeFindings(gateway.policy, gateway.runtime);
|
|
165
263
|
if (gatewayFindings.length) throw new Error(`gateway runtime failed closed: ${gatewayFindings.join(", ")}`);
|
|
264
|
+
const compactFeedbackRecall = !preAnswer && currentTaskId
|
|
265
|
+
&& world.knowledge.taskContext.items.filter((item) => item.predicate === "task.user-feedback").length >= 3;
|
|
166
266
|
|
|
167
267
|
const result = {
|
|
168
268
|
schema: "agentspine.session-briefing/v1",
|
|
169
|
-
root: catalog.root,
|
|
170
|
-
cwd: sources.cwd,
|
|
269
|
+
...(preAnswer ? {} : { root: catalog.root, cwd: sources.cwd }),
|
|
171
270
|
host,
|
|
172
|
-
scope: { entityId, userId, tenantId, groupId, projectId, includePrivate
|
|
271
|
+
scope: { entityId, userId, tenantId, groupId, projectId, includePrivate,
|
|
272
|
+
...(portalRef && threadRef ? { portalRef, threadRef } : {}) },
|
|
173
273
|
focus: { active: Boolean(focusActive), currentTaskId },
|
|
174
274
|
sources: { documents: [], diagnostics: sourceDiagnostics },
|
|
175
275
|
tasks: [],
|
|
@@ -195,16 +295,14 @@ export async function sessionBriefing({
|
|
|
195
295
|
activeSignals: [],
|
|
196
296
|
cue: voiceCue(prompt),
|
|
197
297
|
guidance: [
|
|
198
|
-
"
|
|
199
|
-
"Use the active persona naturally; do not imitate emotion or claim consciousness.",
|
|
200
|
-
"Do not ask again for facts already present in current scoped context.",
|
|
201
|
-
"Acknowledge current frustration, uncertainty, correction, or success briefly when relevant, then act.",
|
|
202
|
-
"Be honest about uncertainty and take responsibility for concrete mistakes."
|
|
298
|
+
"Use scoped facts first; be honest; never claim consciousness; heed corrections; own errors."
|
|
203
299
|
],
|
|
204
300
|
authority: "context-only"
|
|
205
301
|
},
|
|
206
302
|
learning: [],
|
|
207
303
|
shared: [],
|
|
304
|
+
...(preAnswer || compactFeedbackRecall
|
|
305
|
+
? { preAnswerRecall: preAnswerRecall(world, currentTaskId) } : {}),
|
|
208
306
|
world: {
|
|
209
307
|
schema: world.schema,
|
|
210
308
|
facts: [], conflicts: [], proposals: [], stale: [],
|
|
@@ -226,33 +324,48 @@ export async function sessionBriefing({
|
|
|
226
324
|
measurement: "compact-json-utf8",
|
|
227
325
|
omitted: { sources: 0, tasks: 0, relationships: 0, voice: 0, learning: 0, shared: 0, world: 0, attention: 0, portfolio: 0 }
|
|
228
326
|
},
|
|
229
|
-
authority: "context-only"
|
|
230
|
-
note: "This packet is descriptive context only. It grants no delegation, host, tool, file, network, production, spending, or policy rights. Native host rules and explicit local policy remain authoritative."
|
|
327
|
+
authority: "context-only"
|
|
231
328
|
};
|
|
232
329
|
recalculateBudget(result);
|
|
233
330
|
if (result.budget.usedBytes > limit) throw new Error(`maxBytes is too small for the briefing envelope; use at least ${MIN_BYTES}`);
|
|
234
331
|
|
|
235
|
-
const
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
332
|
+
const portableKinds = new Set(["preference", "no-go", "correction", "reference"]);
|
|
333
|
+
const portableItems = userLearned.items.filter((item) => portableKinds.has(item.kind) && matchesScope(item, entityId, null));
|
|
334
|
+
const localItems = [...portableItems, ...learned.items.filter((item) => matchesScope(item, entityId, projectId))];
|
|
335
|
+
const attemptedLearning = new Set();
|
|
336
|
+
|
|
337
|
+
const continuationIds = new Set([
|
|
338
|
+
...world.knowledge.continuation.tasks.map((item) => item.assertionId),
|
|
339
|
+
...world.knowledge.continuation.terminal.map((item) => item.assertionId)
|
|
340
|
+
]);
|
|
341
|
+
for (const [items, key] of [[world.knowledge.continuation.tasks, "tasks"],
|
|
342
|
+
[world.knowledge.continuation.terminal, "terminal"]]) {
|
|
343
|
+
for (const item of items) {
|
|
344
|
+
if (preAnswer || !tryAdd(result, result.world.knowledge.continuation[key], item)) countOmitted(result, "world");
|
|
345
|
+
}
|
|
243
346
|
}
|
|
244
|
-
const contextualIds = new Set(continuationIds
|
|
347
|
+
const contextualIds = new Set([...continuationIds, ...world.knowledge.current
|
|
348
|
+
.filter((item) => ["task.user-feedback", "task.user-feedback-interpretation"]
|
|
349
|
+
.includes(item.predicate)).map((item) => item.id)]);
|
|
245
350
|
for (const item of world.knowledge.taskContext.items) {
|
|
246
|
-
|
|
247
|
-
|
|
351
|
+
contextualIds.add(item.id);
|
|
352
|
+
if (preAnswer || (compactFeedbackRecall
|
|
353
|
+
&& ["task.user-feedback", "task.user-feedback-interpretation"].includes(item.predicate))) {
|
|
354
|
+
result.world.knowledge.taskContext.omitted += 1;
|
|
355
|
+
countOmitted(result, "world");
|
|
356
|
+
} else if (!tryAdd(result, result.world.knowledge.taskContext.items, item)) {
|
|
248
357
|
result.world.knowledge.taskContext.omitted += 1;
|
|
249
358
|
countOmitted(result, "world");
|
|
250
359
|
}
|
|
251
360
|
}
|
|
361
|
+
for (const item of localItems.filter((entry) => entry.relevance)) {
|
|
362
|
+
attemptedLearning.add(item);
|
|
363
|
+
if (!tryAdd(result, result.learning, item)) countOmitted(result, "learning");
|
|
364
|
+
}
|
|
252
365
|
for (const section of ["facts", "conflicts", "proposals", "stale"]) {
|
|
253
366
|
const items = section === "facts"
|
|
254
367
|
? world[section].filter((item) => !item.assertionIds?.some((id) => contextualIds.has(id)))
|
|
255
|
-
: world[section];
|
|
368
|
+
: world[section].filter((item) => !contextualIds.has(item.id));
|
|
256
369
|
for (const item of items) {
|
|
257
370
|
if (!tryAdd(result, result.world[section], item)) countOmitted(result, "world");
|
|
258
371
|
}
|
|
@@ -317,9 +430,6 @@ export async function sessionBriefing({
|
|
|
317
430
|
}
|
|
318
431
|
}
|
|
319
432
|
|
|
320
|
-
const portableKinds = new Set(["preference", "no-go", "correction", "reference"]);
|
|
321
|
-
const portableItems = userLearned.items.filter((item) => portableKinds.has(item.kind) && matchesScope(item, entityId, null));
|
|
322
|
-
const localItems = [...portableItems, ...learned.items.filter((item) => matchesScope(item, entityId, projectId))];
|
|
323
433
|
const voiceCollections = {
|
|
324
434
|
preference: result.voiceBrief.preferences,
|
|
325
435
|
correction: result.voiceBrief.corrections,
|
|
@@ -329,7 +439,7 @@ export async function sessionBriefing({
|
|
|
329
439
|
if (!tryAdd(result, voiceCollections[item.kind], item.claim)) countOmitted(result, "voice");
|
|
330
440
|
}
|
|
331
441
|
const localKeys = new Set(localItems.map(normalizeKey));
|
|
332
|
-
for (const item of localItems) {
|
|
442
|
+
for (const item of localItems.filter((entry) => !attemptedLearning.has(entry))) {
|
|
333
443
|
if (!tryAdd(result, result.learning, item)) countOmitted(result, "learning");
|
|
334
444
|
}
|
|
335
445
|
for (const item of shared.items.filter((entry) => matchesScope(entry, entityId, projectId))) {
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
|
|
3
|
+
function digest(parts) {
|
|
4
|
+
return createHash("sha256").update(parts.join("\0")).digest("hex").slice(0, 32);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
// Produce opaque continuity references from an already authenticated channel
|
|
8
|
+
// event. Raw account, chat and thread identifiers never enter timeline state.
|
|
9
|
+
export function channelTimelineContinuity(event) {
|
|
10
|
+
if (!event) return null;
|
|
11
|
+
const portalRef = `portal-ref:${digest([
|
|
12
|
+
"agentspine.portal-ref/v1", event.provider, event.tenantId, event.accountId, event.bindingId
|
|
13
|
+
])}`;
|
|
14
|
+
const threadRef = `thread-ref:${digest([
|
|
15
|
+
"agentspine.thread-ref/v1", portalRef, event.chatId, event.threadId || "",
|
|
16
|
+
event.sessionKey, event.agentId, event.projectId, event.groupId || ""
|
|
17
|
+
])}`;
|
|
18
|
+
return { portalRef, threadRef };
|
|
19
|
+
}
|
|
@@ -36,7 +36,12 @@ function sealState(state) {
|
|
|
36
36
|
function validReceipt(value, stage, requirementId) {
|
|
37
37
|
return value && value.schema === RECEIPT_SCHEMA && value.stage === stage
|
|
38
38
|
&& value.requirementId === requirementId && value.authority === AUTHORITY
|
|
39
|
-
&&
|
|
39
|
+
&& [undefined, "verified-host-preflight", "verified-host-handoff"].includes(value.origin)
|
|
40
|
+
&& (value.origin !== "verified-host-handoff" || (value.handoff?.schema === "agentspine.host-context-handoff/v1"
|
|
41
|
+
&& ["additionalContext", "message"].includes(value.handoff.field)
|
|
42
|
+
&& ["claude", "codex", "generic", "king"].includes(value.handoff.host)
|
|
43
|
+
&& Number.isSafeInteger(value.handoff.bytes) && value.handoff.bytes > 0
|
|
44
|
+
&& DIGEST_RE.test(value.handoff.digest || "")))
|
|
40
45
|
&& DIGEST_RE.test(value.inputDigest || "") && DIGEST_RE.test(value.resultDigest || "")
|
|
41
46
|
&& validTime(value.recordedAt) && validSeal(value);
|
|
42
47
|
}
|
|
@@ -103,15 +108,15 @@ async function currentRequirement(root, requirementId) {
|
|
|
103
108
|
return current;
|
|
104
109
|
}
|
|
105
110
|
|
|
106
|
-
function receipt(stage, requirementId, input, result, now,
|
|
111
|
+
function receipt(stage, requirementId, input, result, now, verifiedHostHandoff) {
|
|
107
112
|
return seal({ schema: RECEIPT_SCHEMA, stage, requirementId,
|
|
108
|
-
...(
|
|
113
|
+
...(verifiedHostHandoff ? { origin: "verified-host-handoff", handoff: structuredClone(result.handoff) } : {}),
|
|
109
114
|
inputDigest: sha256(input), resultDigest: sha256(result),
|
|
110
115
|
recordedAt: at(now), authority: AUTHORITY });
|
|
111
116
|
}
|
|
112
117
|
|
|
113
118
|
async function recordStage({ root, requirementId, stage, input, result,
|
|
114
|
-
|
|
119
|
+
verifiedHostHandoff = false, preserveConsumed = false, now = new Date() }) {
|
|
115
120
|
try {
|
|
116
121
|
const current = await currentRequirement(root, requirementId);
|
|
117
122
|
if (current.status === "degraded" || current.blocked) return current;
|
|
@@ -119,18 +124,18 @@ async function recordStage({ root, requirementId, stage, input, result,
|
|
|
119
124
|
return await withOwnedFileLock(paths.lockPath, async ({ assertOwned }) => {
|
|
120
125
|
let state = await readState(paths.path, paths.parsed)
|
|
121
126
|
|| emptyState(requirementId, paths.parsed);
|
|
122
|
-
if (!preserveConsumed && state.briefing?.origin !== "verified-host-
|
|
127
|
+
if (!preserveConsumed && state.briefing?.origin !== "verified-host-handoff"
|
|
123
128
|
&& state.consumedAt && stage === "briefing" && current.closed && !current.consumed) {
|
|
124
129
|
state = emptyState(requirementId, paths.parsed);
|
|
125
130
|
} else if (state.consumedAt) return block("reused",
|
|
126
131
|
`AgentSpine usage receipts for ${requirementId} were already consumed.`, { requirementId });
|
|
127
132
|
if (stage === "knowledge" && !state.briefing) return block("missing-briefing",
|
|
128
133
|
"AgentSpine delivery preflight is missing stage 1: session_briefing.", { requirementId });
|
|
129
|
-
if (stage === "briefing" && !
|
|
134
|
+
if (stage === "briefing" && !verifiedHostHandoff && state.briefing?.origin === "verified-host-handoff") {
|
|
130
135
|
return { status: "satisfied-by-host", blocked: false, requirementId,
|
|
131
136
|
receipt: structuredClone(state.briefing), digest: state.briefing.digest };
|
|
132
137
|
}
|
|
133
|
-
const proposed = receipt(stage, requirementId, input, result, now,
|
|
138
|
+
const proposed = receipt(stage, requirementId, input, result, now, verifiedHostHandoff);
|
|
134
139
|
if (state[stage]) {
|
|
135
140
|
if (state[stage].inputDigest !== proposed.inputDigest
|
|
136
141
|
|| state[stage].resultDigest !== proposed.resultDigest) {
|
|
@@ -173,6 +178,8 @@ export async function verifyDeliveryAgentUse({ root, requirementId }) {
|
|
|
173
178
|
const state = await readState(paths.path, paths.parsed);
|
|
174
179
|
if (!state?.briefing) return block("missing-briefing",
|
|
175
180
|
"AgentSpine delivery preflight is missing stage 1: session_briefing.", { requirementId });
|
|
181
|
+
if (state.briefing.origin === "verified-host-preflight") return block("handoff-unverified",
|
|
182
|
+
"The historical hook receipt predates verified host-context handoff.", { requirementId });
|
|
176
183
|
if (!state.knowledge) return block("missing-knowledge",
|
|
177
184
|
"AgentSpine delivery preflight is missing stage 2: delivery_knowledge_query.", { requirementId });
|
|
178
185
|
if (state.consumedAt) return block("reused",
|