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
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
-
import {
|
|
3
|
-
import { mkdir, open } from "node:fs/promises";
|
|
2
|
+
import { mkdir } from "node:fs/promises";
|
|
4
3
|
import { isAbsolute } from "node:path";
|
|
5
4
|
import { withOwnedFileLock } from "./owned-file-lock.js";
|
|
6
5
|
import {
|
|
@@ -23,10 +22,12 @@ import { timelineContinuationCapsule, timelineSearchResult } from "./session-tim
|
|
|
23
22
|
import { seekTimelineEvidence, verifyTimelineEvent } from "./session-timeline-search.js";
|
|
24
23
|
import { eventFromTimelineLine, extractTimelineTimestamp } from "./session-timeline-event-extract.js";
|
|
25
24
|
import { verifiedTimelineEventFromLine } from "./session-timeline-event-extract.js";
|
|
26
|
-
import {
|
|
25
|
+
import { pathMatchesSource } from "./session-timeline-source.js";
|
|
26
|
+
import { readRange, unchangedHandle, validatedHandle } from "./session-timeline-source-open.js";
|
|
27
27
|
import { readTimelineState, saveTimelineState } from "./session-timeline-state.js";
|
|
28
28
|
import { sessionTimelineRootDigest } from "./session-timeline-root.js";
|
|
29
29
|
import { priorTimelineHint, selectPriorTimelineSource, timelineSessionReference } from "./session-timeline-prior.js";
|
|
30
|
+
import { crossProviderTimelineEnabled } from "./session-timeline-provider.js";
|
|
30
31
|
|
|
31
32
|
export const SESSION_TIMELINE_SCHEMA = "agentspine.session-timeline/v1";
|
|
32
33
|
const STATE_SCHEMA = "agentspine.session-timeline-state/v1";
|
|
@@ -39,8 +40,7 @@ const MAX_INDEX_BYTES = 16 * 1024 * 1024;
|
|
|
39
40
|
const ROOM_BYTES = 1024 * 1024;
|
|
40
41
|
const EVENT_OUTCOMES = new Set(["pass", "fail", "blocked", "timeout", "error", "skipped"]);
|
|
41
42
|
const EVENT_LABEL_RE = /^(?:suite-(?:0|[1-9]\d{0,3})|acceptance|audit|npm-check|ci|test)$/;
|
|
42
|
-
const EVENT_KEYS = new Set(["nativeMessageId", "id", "at", "offset", "bytes", "sha256", "kind", "outcome", "count", "testLabel", "terms", "authority"]);
|
|
43
|
-
const MUTATION_TAILS = new Map();
|
|
43
|
+
const EVENT_KEYS = new Set(["nativeMessageId", "id", "at", "offset", "bytes", "sha256", "kind", "outcome", "count", "testLabel", "nextStepSummary", "terms", "authority"]);
|
|
44
44
|
|
|
45
45
|
function digest(value) { return createHash("sha256").update(value).digest("hex"); }
|
|
46
46
|
function asDate(value) {
|
|
@@ -58,15 +58,26 @@ function validCount(item) {
|
|
|
58
58
|
&& item.total > 0 && item.value <= item.total);
|
|
59
59
|
}
|
|
60
60
|
function validEvent(item) {
|
|
61
|
-
|
|
61
|
+
const common = item && typeof item === "object" && hasOnlyKeys(item, EVENT_KEYS)
|
|
62
62
|
&& typeof item.id === "string" && TIMELINE_ID_RE.test(item.id) && date(item.at)
|
|
63
63
|
&& Number.isSafeInteger(item.offset) && item.offset >= 0 && Number.isSafeInteger(item.bytes) && item.bytes > 0
|
|
64
|
-
&& /^[a-f0-9]{64}$/.test(item.sha256 || "")
|
|
65
|
-
&& EVENT_OUTCOMES.has(item.outcome) && validCount(item.count)
|
|
66
|
-
&& (item.testLabel === null || typeof item.testLabel === "string" && EVENT_LABEL_RE.test(item.testLabel))
|
|
64
|
+
&& /^[a-f0-9]{64}$/.test(item.sha256 || "")
|
|
67
65
|
&& Array.isArray(item.terms) && item.terms.length <= 24 && item.terms.every((term) => /^[\p{L}\p{N}]{3,}$/u.test(term))
|
|
68
66
|
&& (item.nativeMessageId === undefined || typeof item.nativeMessageId === "string" && TIMELINE_ID_RE.test(item.nativeMessageId))
|
|
69
67
|
&& item.authority === AUTHORITY;
|
|
68
|
+
if (!common) return false;
|
|
69
|
+
if (item.kind === "user-message-candidate") return item.outcome === undefined
|
|
70
|
+
&& item.count === undefined && item.testLabel === undefined && item.nextStepSummary === undefined
|
|
71
|
+
&& item.terms.join(" ") === "user message";
|
|
72
|
+
if (item.kind === "objective-result") {
|
|
73
|
+
return EVENT_OUTCOMES.has(item.outcome) && validCount(item.count)
|
|
74
|
+
&& (item.testLabel === null || typeof item.testLabel === "string" && EVENT_LABEL_RE.test(item.testLabel))
|
|
75
|
+
&& item.nextStepSummary === undefined;
|
|
76
|
+
}
|
|
77
|
+
return item.kind === "explicit-next-step-correction" && item.outcome === undefined
|
|
78
|
+
&& item.count === undefined && item.testLabel === undefined
|
|
79
|
+
&& (item.nextStepSummary === undefined || typeof item.nextStepSummary === "string"
|
|
80
|
+
&& Boolean(item.nextStepSummary.trim()) && item.nextStepSummary.length <= 500);
|
|
70
81
|
}
|
|
71
82
|
function validSource(item) {
|
|
72
83
|
return item && validTimelineBinding(item.binding) && typeof item.path === "string" && isAbsolute(item.path)
|
|
@@ -97,20 +108,6 @@ function saveState(state, path, assertOwned, root, assertStable) {
|
|
|
97
108
|
return saveTimelineState({ state, path, root, maximumBytes: MAX_STATE_BYTES, assertOwned, assertStable });
|
|
98
109
|
}
|
|
99
110
|
|
|
100
|
-
async function serializeLocalMutation(key, task) {
|
|
101
|
-
const previous = MUTATION_TAILS.get(key) || Promise.resolve();
|
|
102
|
-
let release;
|
|
103
|
-
const current = new Promise(resolve => { release = resolve; });
|
|
104
|
-
const tail = previous.catch(() => {}).then(() => current);
|
|
105
|
-
MUTATION_TAILS.set(key, tail);
|
|
106
|
-
await previous.catch(() => {});
|
|
107
|
-
try { return await task(); }
|
|
108
|
-
finally {
|
|
109
|
-
release();
|
|
110
|
-
if (MUTATION_TAILS.get(key) === tail) MUTATION_TAILS.delete(key);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
111
|
function status(value, extra = {}) { return { schema: SESSION_TIMELINE_SCHEMA, ...value, ...extra, authority: AUTHORITY }; }
|
|
115
112
|
function hasExactPrivateTimelineScope(scope) { return scope?.groupId === null; }
|
|
116
113
|
function sourceFor(state, scope) { return state.sources.find((item) => sameTimelineBinding(item.binding, scope)) || null; }
|
|
@@ -204,7 +201,8 @@ export async function sessionTimelineLifecycleHint({
|
|
|
204
201
|
const source = sourceFor(state, scoped);
|
|
205
202
|
if (!source) return status({ status: "unavailable", reason: "timeline-not-registered" });
|
|
206
203
|
return status({ status: source.indexedBytes >= source.size ? "indexed" : "partial", ...sourceMetadata(source),
|
|
207
|
-
priorSessions: priorTimelineHint(state, scoped, (item) => sourceMetadata(item).sourceDigest
|
|
204
|
+
priorSessions: priorTimelineHint(state, scoped, (item) => sourceMetadata(item).sourceDigest,
|
|
205
|
+
{ includePriorProviders: crossProviderTimelineEnabled(environment) }),
|
|
208
206
|
freshness: "source-not-read", instruction: "Use session_timeline_index before search when this snapshot is partial." });
|
|
209
207
|
} catch {
|
|
210
208
|
return status({ status: "unavailable", reason: "timeline-state-unavailable" });
|
|
@@ -222,32 +220,14 @@ export async function registerSessionTimelineSource() {
|
|
|
222
220
|
function mergeEvents(existing, additions) {
|
|
223
221
|
const byId = new Map(existing.map((item) => [item.id, item]));
|
|
224
222
|
for (const item of additions) byId.set(item.id, item);
|
|
225
|
-
|
|
223
|
+
const ordered = [...byId.values()].sort((left, right) => left.at.localeCompare(right.at) || left.offset - right.offset);
|
|
224
|
+
const evidence = ordered.filter((item) => item.kind !== "user-message-candidate").slice(-MAX_EVENTS);
|
|
225
|
+
const available = Math.min(256, MAX_EVENTS - evidence.length);
|
|
226
|
+
const feedback = ordered.filter((item) => item.kind === "user-message-candidate")
|
|
227
|
+
.slice(available ? -available : ordered.length);
|
|
228
|
+
return [...evidence, ...feedback].sort((left, right) => left.at.localeCompare(right.at) || left.offset - right.offset);
|
|
226
229
|
}
|
|
227
|
-
|
|
228
|
-
try {
|
|
229
|
-
const metadata = await handle.stat({ bigint: true });
|
|
230
|
-
return matchesSourceMetadata(metadata, source) && await pathMatchesSource(source, hostHome);
|
|
231
|
-
} catch { return false; }
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
async function validatedHandle(source, hostHome = null) {
|
|
235
|
-
if (!await pathMatchesSource(source, hostHome)) return { status: "unavailable", reason: "transcript-changed" };
|
|
236
|
-
let handle;
|
|
237
|
-
try { handle = await open(source.path, fsConstants.O_RDONLY | (fsConstants.O_NOFOLLOW || 0)); }
|
|
238
|
-
catch { return { status: "unavailable", reason: "transcript-changed" }; }
|
|
239
|
-
if (!await unchangedHandle(handle, source, hostHome)) {
|
|
240
|
-
await handle.close();
|
|
241
|
-
return { status: "unavailable", reason: "transcript-changed" };
|
|
242
|
-
}
|
|
243
|
-
return { status: "open", handle, size: source.size };
|
|
244
|
-
}
|
|
245
|
-
async function readRange(handle, offset, length) {
|
|
246
|
-
const buffer = Buffer.alloc(length);
|
|
247
|
-
const { bytesRead } = await handle.read(buffer, 0, length, offset);
|
|
248
|
-
return buffer.subarray(0, bytesRead);
|
|
249
|
-
}
|
|
250
|
-
function parsedEvents(buffer, start, dropFirst = false, host = "claude") {
|
|
230
|
+
function parsedEvents(buffer, start, dropFirst = false, host = "claude", includeUserMessages = false) {
|
|
251
231
|
const result = [];
|
|
252
232
|
let index = 0;
|
|
253
233
|
while (index < buffer.byteLength) {
|
|
@@ -256,7 +236,11 @@ function parsedEvents(buffer, start, dropFirst = false, host = "claude") {
|
|
|
256
236
|
const line = buffer.subarray(index, end);
|
|
257
237
|
if (!(dropFirst && index === 0) && line.byteLength) {
|
|
258
238
|
const event = eventFromTimelineLine(line.toString("utf8"), start + index, AUTHORITY, host);
|
|
259
|
-
if (event
|
|
239
|
+
if (event && (includeUserMessages || event.kind !== "user-message-candidate")) {
|
|
240
|
+
if (event.kind === "explicit-next-step-correction") delete event.nextStepSummary;
|
|
241
|
+
delete event.sourceText;
|
|
242
|
+
result.push(event);
|
|
243
|
+
}
|
|
260
244
|
}
|
|
261
245
|
index = end;
|
|
262
246
|
}
|
|
@@ -276,7 +260,8 @@ async function indexRange(source, start, maximum, hostHome = null) {
|
|
|
276
260
|
const before = start > 0 ? await readRange(opened.handle, start - 1, 1) : Buffer.alloc(0);
|
|
277
261
|
if (!await unchangedHandle(opened.handle, source, hostHome)) return { status: "unavailable", reason: "transcript-changed" };
|
|
278
262
|
return { status: "indexed", next: start + selected.byteLength,
|
|
279
|
-
events: parsedEvents(selected, start, start > 0 && before[0] !== 0x0a, source.binding.host
|
|
263
|
+
events: parsedEvents(selected, start, start > 0 && before[0] !== 0x0a, source.binding.host,
|
|
264
|
+
Boolean(source.binding.portalRef && source.binding.threadRef)), size: opened.size };
|
|
280
265
|
} finally { await opened.handle.close(); }
|
|
281
266
|
}
|
|
282
267
|
|
|
@@ -286,7 +271,7 @@ async function mutateSource(root, scoped, task) {
|
|
|
286
271
|
let names;
|
|
287
272
|
try { names = await paths(root); }
|
|
288
273
|
catch { return status({ status: "unavailable", reason: "timeline-state-unavailable" }); }
|
|
289
|
-
return
|
|
274
|
+
return withOwnedFileLock(names.lock, async ({ assertOwned }) => {
|
|
290
275
|
let state;
|
|
291
276
|
try { state = await readState(names.path, root, names.assertStable); }
|
|
292
277
|
catch { return status({ status: "unavailable", reason: "timeline-state-unavailable" }); }
|
|
@@ -302,7 +287,7 @@ async function mutateSource(root, scoped, task) {
|
|
|
302
287
|
return result.status === "indexed" ? status({ status: source.indexedBytes >= source.size ? "indexed"
|
|
303
288
|
: result.preserveCursor ? "fresh-tail" : "partial", ...sourceMetadata(source), added: result.events.length })
|
|
304
289
|
: status(result);
|
|
305
|
-
}, { assertPath: names.assertStable })
|
|
290
|
+
}, { assertPath: names.assertStable }).catch(() =>
|
|
306
291
|
status({ status: "unavailable", reason: "timeline-state-unavailable" }));
|
|
307
292
|
}
|
|
308
293
|
|
|
@@ -345,10 +330,11 @@ export async function sessionTimelineStatus({ root, host, sessionId, scope, envi
|
|
|
345
330
|
}
|
|
346
331
|
|
|
347
332
|
export async function authorizeSessionTimelineInvocation({
|
|
348
|
-
root, host, sessionId, scope, hostHome, tool, request, toolUseId, transportDigest, enrollmentDigest
|
|
333
|
+
root, host, sessionId, scope, hostHome, tool, request, toolUseId, transportDigest, enrollmentDigest,
|
|
334
|
+
environment = process.env
|
|
349
335
|
}) {
|
|
350
336
|
const scoped = sessionTimelineBinding({ host, sessionId, scope });
|
|
351
|
-
if (!hasExactPrivateTimelineScope(scope) || !completeTimelineBinding(scoped) || !/^(index|search)$/.test(tool || "")) return null;
|
|
337
|
+
if (!hasExactPrivateTimelineScope(scope) || !completeTimelineBinding(scoped) || !/^(index|search|capture)$/.test(tool || "")) return null;
|
|
352
338
|
if (!hasVerifiedTimelinePrivateScope(scope)) return null;
|
|
353
339
|
try {
|
|
354
340
|
await ensureSessionTimelineTrust();
|
|
@@ -357,10 +343,15 @@ export async function authorizeSessionTimelineInvocation({
|
|
|
357
343
|
const currentSource = sourceFor(state, scoped);
|
|
358
344
|
if (!currentSource || !await pathMatchesSource(currentSource, hostHome)
|
|
359
345
|
|| !await confirmedSourceEnrollment({ root, scoped, source: currentSource, hostHome })) return null;
|
|
360
|
-
const
|
|
346
|
+
const includePriorProviders = request?.includePriorProviders === true;
|
|
347
|
+
if (includePriorProviders && (request?.includePriorSessions !== true || !crossProviderTimelineEnabled(environment))) return null;
|
|
348
|
+
const query = tool !== "index" ? timelineQuery({ at: request?.at, query: request?.query }) : null;
|
|
361
349
|
const source = request?.includePriorSessions === true
|
|
362
|
-
? selectPriorTimelineSource(state, scoped, { ...query, windowMs: request.windowSeconds * 1000
|
|
363
|
-
|
|
350
|
+
? selectPriorTimelineSource(state, scoped, { ...query, windowMs: request.windowSeconds * 1000,
|
|
351
|
+
includePriorProviders }) : currentSource;
|
|
352
|
+
const sourceHome = source?.binding.host === scoped.host ? hostHome : source?.profileRoot;
|
|
353
|
+
if (!source || !await pathMatchesSource(source, sourceHome)
|
|
354
|
+
|| !await confirmedSourceEnrollment({ root, scoped: source.binding, source, hostHome: sourceHome })) return null;
|
|
364
355
|
const sourceDigest = sourceMetadata(source).sourceDigest;
|
|
365
356
|
if (!await timelineTransportEnrollmentMatches({ root, binding: scoped, enrollmentDigest, transportDigest, hostHome })) return null;
|
|
366
357
|
await issueSessionTimelineInvocation({
|
|
@@ -370,17 +361,60 @@ export async function authorizeSessionTimelineInvocation({
|
|
|
370
361
|
} catch { return null; }
|
|
371
362
|
}
|
|
372
363
|
|
|
373
|
-
|
|
364
|
+
// Reopen only exact, already-captured sources needed by one interpretation.
|
|
365
|
+
// The outer capture invocation remains the sole public gate.
|
|
366
|
+
export async function reverifyTimelineFeedbackSources({
|
|
367
|
+
root, host, sessionId, scope, references, includePriorProviders = false,
|
|
368
|
+
environment = process.env, hostHome = null
|
|
369
|
+
}) {
|
|
370
|
+
const scoped = sessionTimelineBinding({ host, sessionId, scope });
|
|
371
|
+
if (!completeTimelineBinding(scoped) || !hasVerifiedTimelinePrivateScope(scope)
|
|
372
|
+
|| !Array.isArray(references) || !references.length || references.length > 3
|
|
373
|
+
|| includePriorProviders && !crossProviderTimelineEnabled(environment)) return null;
|
|
374
|
+
try {
|
|
375
|
+
await ensureSessionTimelineTrust();
|
|
376
|
+
const names = await paths(root);
|
|
377
|
+
const state = await readState(names.path, root, names.assertStable);
|
|
378
|
+
const fields = ["entityId", "userId", "tenantId", "projectId", "taskId", "groupId", "portalRef", "threadRef"];
|
|
379
|
+
const eligible = state.sources.filter((source) => fields.every((key) =>
|
|
380
|
+
(source.binding[key] ?? null) === (scoped[key] ?? null))
|
|
381
|
+
&& (includePriorProviders || source.binding.host === scoped.host));
|
|
382
|
+
const verified = [];
|
|
383
|
+
for (const reference of references) {
|
|
384
|
+
const source = eligible.find((item) => item.binding.host === reference.sourceProvider
|
|
385
|
+
&& timelineSessionReference(item.binding) === reference.sessionRef
|
|
386
|
+
&& sourceMetadata(item).sourceDigest === reference.sourceDigest);
|
|
387
|
+
const sourceHome = source?.binding.host === scoped.host ? hostHome : source?.profileRoot;
|
|
388
|
+
const indexed = source?.events.find((item) => item.id === reference.eventId
|
|
389
|
+
&& item.sha256 === reference.messageDigest && item.at === reference.observedAt);
|
|
390
|
+
if (!source || !indexed || reference.messageRef !== reference.eventId
|
|
391
|
+
|| !await confirmedSourceEnrollment({ root, scoped: source.binding, source, hostHome: sourceHome })) return null;
|
|
392
|
+
const opened = await validatedHandle(source, sourceHome);
|
|
393
|
+
if (opened.status !== "open") return null;
|
|
394
|
+
try {
|
|
395
|
+
const current = await verifyTimelineEvent({ handle: opened.handle, event: indexed, readRange, digest,
|
|
396
|
+
eventFromLine: (line, offset) => verifiedTimelineEventFromLine(line, offset, AUTHORITY, source.binding.host) });
|
|
397
|
+
if (!current || current.kind !== "user-message-candidate"
|
|
398
|
+
|| !await unchangedHandle(opened.handle, source, sourceHome)) return null;
|
|
399
|
+
verified.push({ ...current, sourceDigest: reference.sourceDigest,
|
|
400
|
+
sourceProvider: reference.sourceProvider, sessionRef: reference.sessionRef });
|
|
401
|
+
} finally { await opened.handle.close(); }
|
|
402
|
+
}
|
|
403
|
+
return verified;
|
|
404
|
+
} catch { return null; }
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
function searchResult(source, target, wanted, mode, events, extra = {}, includeMessageDigest = false) {
|
|
374
408
|
const index = sourceMetadata(source);
|
|
375
409
|
return timelineSearchResult({ sourceDigest: index.sourceDigest, sessionRef: timelineSessionReference(source.binding),
|
|
376
|
-
target, wanted, mode, events, index,
|
|
377
|
-
roomBytes: ROOM_BYTES, authority: AUTHORITY, extra });
|
|
410
|
+
sourceProvider: source.binding.host, binding: source.binding, target, wanted, mode, events, index,
|
|
411
|
+
roomBytes: ROOM_BYTES, authority: AUTHORITY, extra, includeMessageDigest });
|
|
378
412
|
}
|
|
379
413
|
|
|
380
414
|
export async function searchSessionTimeline({
|
|
381
415
|
root, host, sessionId, scope, at, query, windowSeconds = undefined,
|
|
382
|
-
includePriorSessions = false,
|
|
383
|
-
invocationRequest = null, transportDigest = null, enrollmentDigest = null, hostHome = null
|
|
416
|
+
includePriorSessions = false, includePriorProviders = false, environment = process.env,
|
|
417
|
+
invocationRequest = null, invocationTool = "search", transportDigest = null, enrollmentDigest = null, hostHome = null
|
|
384
418
|
}) {
|
|
385
419
|
const scoped = sessionTimelineBinding({ host, sessionId, scope });
|
|
386
420
|
if (!hasExactPrivateTimelineScope(scope) || !hasVerifiedTimelinePrivateScope(scope) || !completeTimelineBinding(scoped)) {
|
|
@@ -392,6 +426,10 @@ export async function searchSessionTimeline({
|
|
|
392
426
|
throw new Error("timeline window is invalid");
|
|
393
427
|
}
|
|
394
428
|
if (typeof includePriorSessions !== "boolean") throw new Error("prior session selection is invalid");
|
|
429
|
+
if (typeof includePriorProviders !== "boolean") throw new Error("prior provider selection is invalid");
|
|
430
|
+
if (includePriorProviders && (!includePriorSessions || !crossProviderTimelineEnabled(environment))) {
|
|
431
|
+
return { blocked: true, reason: "cross-provider timeline recall is unavailable", authority: AUTHORITY };
|
|
432
|
+
}
|
|
395
433
|
try { await ensureSessionTimelineTrust(); }
|
|
396
434
|
catch { return { blocked: true, reason: "session timeline is unavailable", authority: AUTHORITY }; }
|
|
397
435
|
let names; let state;
|
|
@@ -406,23 +444,28 @@ export async function searchSessionTimeline({
|
|
|
406
444
|
return { blocked: true, reason: "session timeline is unavailable", authority: AUTHORITY };
|
|
407
445
|
}
|
|
408
446
|
const source = includePriorSessions
|
|
409
|
-
? selectPriorTimelineSource(state, scoped, { target, wanted, windowMs: boundedWindowSeconds * 1000
|
|
447
|
+
? selectPriorTimelineSource(state, scoped, { target, wanted, windowMs: boundedWindowSeconds * 1000,
|
|
448
|
+
includePriorProviders })
|
|
410
449
|
: currentSource;
|
|
411
|
-
|
|
450
|
+
const sourceHome = source?.binding.host === scoped.host ? hostHome : source?.profileRoot;
|
|
451
|
+
if (!source || !await pathMatchesSource(source, sourceHome)
|
|
452
|
+
|| !await confirmedSourceEnrollment({ root, scoped: source.binding, source, hostHome: sourceHome })) {
|
|
412
453
|
return { blocked: true, reason: "session timeline is unavailable", authority: AUTHORITY };
|
|
413
454
|
}
|
|
414
455
|
const sourceDigest = sourceMetadata(source).sourceDigest;
|
|
415
|
-
if (
|
|
416
|
-
|| !await
|
|
456
|
+
if (!/^(search|capture)$/.test(invocationTool) || !invocationRequest
|
|
457
|
+
|| !await timelineTransportEnrollmentMatches({ root, binding: scoped, enrollmentDigest, transportDigest, hostHome })
|
|
458
|
+
|| !await consumeSessionTimelineInvocation({ root, tool: invocationTool, binding: scoped, sourceDigest,
|
|
417
459
|
request: invocationRequest, transportDigest })) {
|
|
418
460
|
return { blocked: true, reason: "session timeline invocation is unavailable", authority: AUTHORITY };
|
|
419
461
|
}
|
|
420
462
|
const indexed = rankTimelineEvents(source.events
|
|
421
463
|
.filter((event) => matchesTimelineEvent(event, wanted, target, boundedWindowSeconds * 1000)), wanted, target).slice(0, 8);
|
|
422
464
|
if (includePriorSessions && !indexed.length) {
|
|
423
|
-
return searchResult(source, target, wanted, "prior-index", [], { priorSession: true
|
|
465
|
+
return searchResult(source, target, wanted, "prior-index", [], { priorSession: true,
|
|
466
|
+
priorProvider: source.binding.host !== scoped.host }, invocationTool === "capture");
|
|
424
467
|
}
|
|
425
|
-
const opened = await validatedHandle(source,
|
|
468
|
+
const opened = await validatedHandle(source, sourceHome);
|
|
426
469
|
if (opened.status !== "open") return { blocked: true, reason: opened.reason, authority: AUTHORITY };
|
|
427
470
|
try {
|
|
428
471
|
const verified = [];
|
|
@@ -433,21 +476,25 @@ export async function searchSessionTimeline({
|
|
|
433
476
|
verified.push(current);
|
|
434
477
|
}
|
|
435
478
|
if (verified.length) {
|
|
436
|
-
if (!await unchangedHandle(opened.handle, source,
|
|
479
|
+
if (!await unchangedHandle(opened.handle, source, sourceHome)) return { blocked: true, reason: "transcript-changed", authority: AUTHORITY };
|
|
437
480
|
return searchResult(source, target, wanted, includePriorSessions ? "prior-verified-index" : "verified-index", verified,
|
|
438
|
-
includePriorSessions ? { priorSession: true } : {}
|
|
481
|
+
includePriorSessions ? { priorSession: true, priorProvider: source.binding.host !== scoped.host } : {},
|
|
482
|
+
invocationTool === "capture");
|
|
439
483
|
}
|
|
440
|
-
if (!target) return searchResult(source, target, wanted, "verified-index", []);
|
|
484
|
+
if (!target) return searchResult(source, target, wanted, "verified-index", [], {}, invocationTool === "capture");
|
|
441
485
|
const sought = await seekTimelineEvidence({ handle: opened.handle, size: opened.size, target, wanted,
|
|
442
486
|
windowMs: boundedWindowSeconds * 1000, readRange,
|
|
443
487
|
eventFromLine: (line, offset) => verifiedTimelineEventFromLine(line, offset, AUTHORITY, source.binding.host),
|
|
444
488
|
extractTimestamp: extractTimelineTimestamp,
|
|
445
489
|
matches: matchesTimelineEvent, rank: rankTimelineEvents });
|
|
446
490
|
if (sought.status === "searched") {
|
|
447
|
-
if (!await unchangedHandle(opened.handle, source,
|
|
448
|
-
return searchResult(source, target, wanted, "timestamp-seek", sought.events,
|
|
491
|
+
if (!await unchangedHandle(opened.handle, source, sourceHome)) return { blocked: true, reason: "transcript-changed", authority: AUTHORITY };
|
|
492
|
+
return searchResult(source, target, wanted, "timestamp-seek", sought.events,
|
|
493
|
+
{ budgetExhausted: sought.budgetExhausted }, invocationTool === "capture");
|
|
494
|
+
}
|
|
495
|
+
if (sought.status === "out-of-range") {
|
|
496
|
+
return searchResult(source, target, wanted, "timestamp-seek", [], {}, invocationTool === "capture");
|
|
449
497
|
}
|
|
450
|
-
if (sought.status === "out-of-range") return searchResult(source, target, wanted, "timestamp-seek", []);
|
|
451
498
|
return { blocked: true, reason: sought.reason, authority: AUTHORITY };
|
|
452
499
|
} finally { await opened.handle.close(); }
|
|
453
500
|
}
|
|
@@ -255,7 +255,7 @@ async function claudeSources({ cwd, projectRoot, configDir, input, env, registry
|
|
|
255
255
|
const value = await readJsonObject(path);
|
|
256
256
|
if (typeof value?.autoMemoryDirectory === "string") {
|
|
257
257
|
const expanded = expandHome(value.autoMemoryDirectory, homedir());
|
|
258
|
-
if (!isAbsolute(expanded)) throw new Error("
|
|
258
|
+
if (!isAbsolute(expanded)) throw new Error("autoMemoryDirectory must be absolute or home-relative");
|
|
259
259
|
memoryRoot = await existingDirectory(expanded);
|
|
260
260
|
memoryProvenance = "autoMemoryDirectory";
|
|
261
261
|
}
|
|
@@ -358,7 +358,8 @@ export async function resolveHostSourceCatalog({ host, cwd = process.cwd(), inpu
|
|
|
358
358
|
let hostDetails = {};
|
|
359
359
|
let rootResolution = "explicit-root";
|
|
360
360
|
if (host === "codex") {
|
|
361
|
-
const codexHome = env.
|
|
361
|
+
const codexHome = env.BLUN_PLUGIN_ROOT && env.BLUN_HOME
|
|
362
|
+
? env.BLUN_HOME : env.CODEX_HOME || env.BLUN_HOME || join(homedir(), ".codex");
|
|
362
363
|
hostHome = await existingDirectory(resolve(codexHome)) || resolve(codexHome);
|
|
363
364
|
const config = await codexConfig(hostHome);
|
|
364
365
|
if (env.AGENTSPINE_ROOT) projectRoot = await canonicalPath(env.AGENTSPINE_ROOT);
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
relevantUserFeedback, relevantUserFeedbackInterpretation
|
|
3
|
+
} from "./timeline-user-feedback.js";
|
|
4
|
+
|
|
1
5
|
const MAX_ITEMS = 6;
|
|
2
6
|
const STOP_WORDS = new Set([
|
|
3
7
|
"and", "are", "das", "der", "die", "eine", "einer", "for", "from", "für", "ist",
|
|
@@ -39,7 +43,7 @@ function empty(taskId, status) {
|
|
|
39
43
|
|
|
40
44
|
export function taskKnowledgeContext(entries, { taskId = null, continuation, maxItems = MAX_ITEMS } = {}) {
|
|
41
45
|
if (!taskId) return empty(null, "not-requested");
|
|
42
|
-
const task = continuation.tasks.find((item) => item.taskId === taskId);
|
|
46
|
+
const task = [...continuation.tasks, ...continuation.terminal].find((item) => item.taskId === taskId);
|
|
43
47
|
if (!task) {
|
|
44
48
|
const terminal = continuation.terminal.some((item) => item.taskId === taskId);
|
|
45
49
|
return empty(taskId, terminal ? "terminal" : "unavailable");
|
|
@@ -50,7 +54,23 @@ export function taskKnowledgeContext(entries, { taskId = null, continuation, max
|
|
|
50
54
|
const minimumMatches = Math.min(2, queryTerms.length);
|
|
51
55
|
const seen = new Set();
|
|
52
56
|
const ranked = [];
|
|
57
|
+
const feedbackIds = entries.filter((entry) => relevantUserFeedback(entry, task))
|
|
58
|
+
.map((entry) => entry.id).sort();
|
|
53
59
|
for (const entry of entries) {
|
|
60
|
+
if (relevantUserFeedback(entry, task)) {
|
|
61
|
+
ranked.push({ entry, matchedTerms: [], score: 100_000 });
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
if (relevantUserFeedbackInterpretation(entry, task)) {
|
|
65
|
+
const sourceIds = [...(entry.value.sourceBindings?.map((item) => item.feedbackAssertionId)
|
|
66
|
+
|| [entry.value.sourceFeedbackAssertionId])].sort();
|
|
67
|
+
if (sourceIds.length === feedbackIds.length
|
|
68
|
+
&& sourceIds.every((id, index) => id === feedbackIds[index])) {
|
|
69
|
+
ranked.push({ entry, matchedTerms: [], score: 99_999 });
|
|
70
|
+
}
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
if (task.status === "completed") continue;
|
|
54
74
|
if (entry.status !== "confirmed" || !(entry.kind in KIND_WEIGHT)) continue;
|
|
55
75
|
const matchedTerms = terms(entryText(entry)).filter((item) => querySet.has(item));
|
|
56
76
|
if (matchedTerms.length < minimumMatches) continue;
|
|
@@ -63,6 +83,7 @@ export function taskKnowledgeContext(entries, { taskId = null, continuation, max
|
|
|
63
83
|
ranked.sort((left, right) => right.score - left.score
|
|
64
84
|
|| right.entry.observedAt.localeCompare(left.entry.observedAt)
|
|
65
85
|
|| left.entry.id.localeCompare(right.entry.id));
|
|
86
|
+
if (task.status === "completed" && !ranked.length) return empty(taskId, "terminal");
|
|
66
87
|
const limit = Math.min(MAX_ITEMS, Math.max(1, maxItems));
|
|
67
88
|
return {
|
|
68
89
|
schema: "agentspine.task-knowledge-context/v1",
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { recordWorldAssertion, worldContext } from "./world-model.js";
|
|
3
|
+
import { TIMELINE_OUTCOME_CONTRACT_SCHEMA } from "./world-knowledge.js";
|
|
4
|
+
|
|
5
|
+
const CONTINUATION_SCHEMA = "agentspine.task-continuation/v1";
|
|
6
|
+
|
|
7
|
+
function digest(value) {
|
|
8
|
+
return createHash("sha256").update(value).digest("hex");
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function sameStep(left, right) {
|
|
12
|
+
return Boolean(left && right && left.id === right.id && left.summary === right.summary);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function measuredResult(event, contract) {
|
|
16
|
+
if (event.testLabel !== contract.measurement.testLabel) return null;
|
|
17
|
+
const expectedTotal = contract.measurement.total;
|
|
18
|
+
if ((expectedTotal === null) !== (event.count === null)
|
|
19
|
+
|| (event.count && event.count.total !== expectedTotal)) return null;
|
|
20
|
+
const succeeded = event.outcome === "pass"
|
|
21
|
+
&& (event.count === null || event.count.value === contract.measurement.successCount);
|
|
22
|
+
const result = succeeded ? "passed"
|
|
23
|
+
: event.outcome === "blocked" || event.outcome === "skipped" ? "blocked" : "failed";
|
|
24
|
+
return { succeeded, result };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function response(status, reason = null, assertion = null) {
|
|
28
|
+
return { schema: "agentspine.timeline-continuation-update/v1", status, reason, assertion,
|
|
29
|
+
completionVerified: assertion?.value?.status === "completed", automaticRetry: false,
|
|
30
|
+
authority: "context-only" };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export async function updateTimelineContinuationFromObjective({ root, scope, event, now }) {
|
|
34
|
+
try {
|
|
35
|
+
const context = await worldContext({ root, subjectId: scope.currentTaskId,
|
|
36
|
+
projectId: scope.projectId, groupId: null, includePrivate: true, includeKnowledgeHistory: true,
|
|
37
|
+
continuationTaskId: scope.currentTaskId, portalRef: scope.portalRef, threadRef: scope.threadRef,
|
|
38
|
+
maxItems: 100, now });
|
|
39
|
+
const continuations = context.knowledge.current.filter((item) => item.subjectId === scope.currentTaskId
|
|
40
|
+
&& item.predicate === "task.continuation" && item.value?.schema === CONTINUATION_SCHEMA);
|
|
41
|
+
const replay = continuations.find((item) => item.status === "confirmed"
|
|
42
|
+
&& item.source.id === event.id && item.value.lastVerifiedStep?.evidenceId === event.id);
|
|
43
|
+
if (replay) return response("duplicate", null, replay);
|
|
44
|
+
if (continuations.length !== 1 || continuations[0].status !== "confirmed") {
|
|
45
|
+
return response("unavailable", continuations.length ? "timeline-continuation-conflicted"
|
|
46
|
+
: "timeline-continuation-missing");
|
|
47
|
+
}
|
|
48
|
+
const current = continuations[0];
|
|
49
|
+
const contracts = context.knowledge.current.filter((item) => item.subjectId === scope.currentTaskId
|
|
50
|
+
&& item.predicate === "task.timeline-outcome-contract"
|
|
51
|
+
&& item.value?.schema === TIMELINE_OUTCOME_CONTRACT_SCHEMA);
|
|
52
|
+
if (contracts.length !== 1 || contracts[0].status !== "confirmed") {
|
|
53
|
+
return response("unavailable", contracts.length ? "timeline-outcome-contract-conflicted"
|
|
54
|
+
: "timeline-outcome-contract-missing");
|
|
55
|
+
}
|
|
56
|
+
const contract = contracts[0];
|
|
57
|
+
if (!sameStep(current.value.nextStep, contract.value.step)) {
|
|
58
|
+
return response("unavailable", "timeline-outcome-contract-superseded");
|
|
59
|
+
}
|
|
60
|
+
const eventTime = new Date(event.at).getTime();
|
|
61
|
+
if (eventTime < new Date(contract.recordedAt).getTime()) {
|
|
62
|
+
return response("unavailable", "timeline-outcome-contract-postdated");
|
|
63
|
+
}
|
|
64
|
+
if (eventTime < new Date(current.observedAt).getTime()
|
|
65
|
+
|| eventTime < new Date(contract.observedAt).getTime()) {
|
|
66
|
+
return response("unavailable", "timeline-outcome-event-stale");
|
|
67
|
+
}
|
|
68
|
+
const measured = measuredResult(event, contract.value);
|
|
69
|
+
if (!measured) return response("unavailable", "timeline-outcome-contract-mismatch");
|
|
70
|
+
const value = structuredClone(current.value);
|
|
71
|
+
value.lastVerifiedStep = {
|
|
72
|
+
id: contract.value.step.id, summary: contract.value.step.summary, result: measured.result,
|
|
73
|
+
evidenceId: event.id, evidenceDigest: event.messageDigest,
|
|
74
|
+
observedAt: new Date(event.at).toISOString(), sessionRef: event.sessionRef,
|
|
75
|
+
messageRef: event.messageRef
|
|
76
|
+
};
|
|
77
|
+
if (measured.succeeded) {
|
|
78
|
+
value.status = contract.value.onSuccess.status;
|
|
79
|
+
value.nextStep = structuredClone(contract.value.onSuccess.nextStep);
|
|
80
|
+
if (value.status === "completed" && value.openQuestions.length) {
|
|
81
|
+
return response("unavailable", "timeline-outcome-completion-questions-open");
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
const material = [scope.currentTaskId, scope.projectId, scope.portalRef, scope.threadRef,
|
|
85
|
+
contract.id, current.id, event.id, event.messageDigest].join("\0");
|
|
86
|
+
const recorded = await recordWorldAssertion({ root,
|
|
87
|
+
id: `assertion:timeline-continuation-${digest(material).slice(0, 32)}`,
|
|
88
|
+
subjectId: scope.currentTaskId, predicate: "task.continuation", value,
|
|
89
|
+
evidenceKind: "objective-measurement", evidenceId: event.id,
|
|
90
|
+
evidenceDigest: event.messageDigest, observedAt: new Date(event.at).toISOString(),
|
|
91
|
+
projectId: scope.projectId, groupId: null, privacy: "private", knowledgeKind: "task-state",
|
|
92
|
+
sessionRef: event.sessionRef, messageRef: event.messageRef,
|
|
93
|
+
supersedes: [current.id], requireActiveSupersedes: true,
|
|
94
|
+
reason: `The source-verified timeline result matched pre-existing contract ${contract.id}.`,
|
|
95
|
+
portalRef: scope.portalRef, threadRef: scope.threadRef, now });
|
|
96
|
+
return response(recorded.status === "duplicate" ? "duplicate" : "updated", null, recorded.assertion);
|
|
97
|
+
} catch {
|
|
98
|
+
return response("unavailable", "timeline-continuation-update-unavailable");
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import { canonicalPath } from "./paths.js";
|
|
2
2
|
import { resolveHostSourceCatalog } from "./source-roots.js";
|
|
3
3
|
import { authorizeSessionTimelineInvocation } from "./session-timeline.js";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
timelineInterpretationRequest, timelineInvocationRequest, timelineToolKind
|
|
6
|
+
} from "./mcp-timeline-tools.js";
|
|
5
7
|
import { gatewayEnvironmentContext, hookDeliveryId, hostFromInput, sessionId } from "./hook-context.js";
|
|
6
8
|
import { blockedHookOutput } from "./hook-output.js";
|
|
7
9
|
import { sessionTimelineBinding } from "./session-timeline-contract.js";
|
|
8
10
|
import { resolvePrivateSessionTimelineEnrollment } from "./session-timeline-enrollment.js";
|
|
9
11
|
import { timelineTransportDigest } from "./session-timeline-transport.js";
|
|
10
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
crossProviderTimelineEnabled, runtimeHostForTimeline, timelineHostForRuntime, timelineHostHome
|
|
14
|
+
} from "./session-timeline-provider.js";
|
|
11
15
|
|
|
12
16
|
function plainObject(value) {
|
|
13
17
|
return value && typeof value === "object" && !Array.isArray(value)
|
|
@@ -32,6 +36,8 @@ function gatewayMatchesEnrollment(gateway, binding) {
|
|
|
32
36
|
];
|
|
33
37
|
return gateway.host === runtimeHostForTimeline(binding.host)
|
|
34
38
|
&& fields.slice(1).every(([gatewayField, bindingField]) => gateway[gatewayField] === binding[bindingField])
|
|
39
|
+
&& (gateway.portalRef ?? null) === (binding.portalRef ?? null)
|
|
40
|
+
&& (gateway.threadRef ?? null) === (binding.threadRef ?? null)
|
|
35
41
|
&& process.env.AGENTSPINE_USER_ID === binding.userId && process.env.AGENTSPINE_TENANT_ID === binding.tenantId;
|
|
36
42
|
}
|
|
37
43
|
|
|
@@ -39,6 +45,7 @@ function bindingScope(binding, enrollment) {
|
|
|
39
45
|
return { entityId: binding.entityId, userId: binding.userId, tenantId: binding.tenantId,
|
|
40
46
|
projectId: binding.projectId, groupId: null, currentTaskId: binding.taskId,
|
|
41
47
|
goalId: binding.goalId, goalStepId: binding.goalStepId,
|
|
48
|
+
portalRef: binding.portalRef ?? null, threadRef: binding.threadRef ?? null,
|
|
42
49
|
timelineVisibility: enrollment.timelineVisibility };
|
|
43
50
|
}
|
|
44
51
|
|
|
@@ -73,6 +80,8 @@ function matchesScopeBinding(args, binding) {
|
|
|
73
80
|
&& scopeClaimsMatch(args, ["taskId", "task_id", "currentTaskId", "current_task_id"], binding.taskId)
|
|
74
81
|
&& scopeClaimsMatch(args, ["goalId", "goal_id"], binding.goalId)
|
|
75
82
|
&& scopeClaimsMatch(args, ["goalStepId", "goal_step_id"], binding.goalStepId)
|
|
83
|
+
&& scopeClaimsMatch(args, ["portalRef", "portal_ref"], binding.portalRef ?? null)
|
|
84
|
+
&& scopeClaimsMatch(args, ["threadRef", "thread_ref"], binding.threadRef ?? null)
|
|
76
85
|
&& noScopeClaims(args, ["groupId", "group_id"]);
|
|
77
86
|
}
|
|
78
87
|
|
|
@@ -90,7 +99,7 @@ function matchesHostBinding(input, binding) {
|
|
|
90
99
|
"transportDigest", "transport_digest", "enrollmentDigest", "enrollment_digest"]);
|
|
91
100
|
}
|
|
92
101
|
|
|
93
|
-
function claimedScope(input) {
|
|
102
|
+
function claimedScope(input, gateway) {
|
|
94
103
|
const claim = (keys) => {
|
|
95
104
|
const values = scopeValues(input, keys).filter((value) => !absent(value));
|
|
96
105
|
return values.length && values.every((value) => value === values[0]) ? values[0] : null;
|
|
@@ -99,7 +108,8 @@ function claimedScope(input) {
|
|
|
99
108
|
entityId: claim(["entityId", "entity_id"]), userId: claim(["userId", "user_id"]),
|
|
100
109
|
tenantId: claim(["tenantId", "tenant_id"]), projectId: claim(["projectId", "project_id"]),
|
|
101
110
|
groupId: claim(["groupId", "group_id"]), currentTaskId: claim(["taskId", "task_id", "currentTaskId", "current_task_id"]),
|
|
102
|
-
goalId: claim(["goalId", "goal_id"]), goalStepId: claim(["goalStepId", "goal_step_id"])
|
|
111
|
+
goalId: claim(["goalId", "goal_id"]), goalStepId: claim(["goalStepId", "goal_step_id"]),
|
|
112
|
+
portalRef: gateway?.portalRef ?? null, threadRef: gateway?.threadRef ?? null
|
|
103
113
|
};
|
|
104
114
|
}
|
|
105
115
|
|
|
@@ -113,10 +123,19 @@ async function matchesRoot(value, root) {
|
|
|
113
123
|
function requestInput(tool, args) {
|
|
114
124
|
if (tool === "index") return args.maxBytes === undefined ? {} : { maxBytes: args.maxBytes };
|
|
115
125
|
if (args.at === undefined && args.query === undefined) return null;
|
|
126
|
+
if (tool === "capture" && !/^timeline-event:[a-f0-9]{32}$/.test(args.eventId || "")) return null;
|
|
116
127
|
if (args.includePriorSessions !== undefined && typeof args.includePriorSessions !== "boolean") return null;
|
|
117
|
-
|
|
128
|
+
if (args.includePriorProviders !== undefined && typeof args.includePriorProviders !== "boolean") return null;
|
|
129
|
+
if (args.includePriorProviders === true && args.includePriorSessions !== true) return null;
|
|
130
|
+
const interpretation = tool === "capture" && args.interpretation !== undefined
|
|
131
|
+
? timelineInterpretationRequest(args.interpretation) : null;
|
|
132
|
+
if (tool === "capture" && args.interpretation !== undefined && !interpretation) return null;
|
|
133
|
+
return { ...(tool === "capture" ? { eventId: args.eventId,
|
|
134
|
+
...(interpretation ? { interpretation } : {}) } : {}),
|
|
135
|
+
...(args.at === undefined ? {} : { at: args.at }), ...(args.query === undefined ? {} : { query: args.query }),
|
|
118
136
|
...(args.windowSeconds === undefined ? {} : { windowSeconds: args.windowSeconds }),
|
|
119
|
-
...(args.includePriorSessions === undefined ? {} : { includePriorSessions: args.includePriorSessions })
|
|
137
|
+
...(args.includePriorSessions === undefined ? {} : { includePriorSessions: args.includePriorSessions }),
|
|
138
|
+
...(args.includePriorProviders === undefined ? {} : { includePriorProviders: args.includePriorProviders }) };
|
|
120
139
|
}
|
|
121
140
|
|
|
122
141
|
function denied(reason) {
|
|
@@ -155,7 +174,7 @@ export async function runTimelineToolGuard(input) {
|
|
|
155
174
|
const hostSession = sessionId(input);
|
|
156
175
|
const gateway = gatewayEnvironmentContext();
|
|
157
176
|
if (rawGroupClaim(input, gateway)) return denied("AgentSpine session timeline is unavailable for group-scoped activity.");
|
|
158
|
-
const provisionalBinding = sessionTimelineBinding({ host, sessionId: hostSession, scope: claimedScope(input) });
|
|
177
|
+
const provisionalBinding = sessionTimelineBinding({ host, sessionId: hostSession, scope: claimedScope(input, gateway) });
|
|
159
178
|
const transportDigest = timelineTransportDigest({ root, binding: provisionalBinding });
|
|
160
179
|
if (!transportDigest) {
|
|
161
180
|
return denied("AgentSpine session timeline requires a locally configured per-session transport capability.");
|
|
@@ -179,11 +198,15 @@ export async function runTimelineToolGuard(input) {
|
|
|
179
198
|
const scope = bindingScope(enrollment.binding, enrollment);
|
|
180
199
|
const requestFields = requestInput(tool, input.tool_input);
|
|
181
200
|
if (!requestFields) return denied("AgentSpine session timeline search needs an exact time or a concrete query.");
|
|
201
|
+
if (requestFields.includePriorProviders && !crossProviderTimelineEnabled(process.env)) {
|
|
202
|
+
return denied("AgentSpine cross-provider timeline recall is not enabled by this local host.");
|
|
203
|
+
}
|
|
182
204
|
if (input.tool_input.host && input.tool_input.host !== host) return denied("Timeline provider binding mismatch.");
|
|
183
205
|
const updatedInput = { ...requestFields, ...(["codex", "king"].includes(host) ? { host } : {}), root, sessionId: enrollment.binding.sessionId,
|
|
184
206
|
entityId: enrollment.binding.entityId, userId: enrollment.binding.userId, tenantId: enrollment.binding.tenantId,
|
|
185
207
|
projectId: enrollment.binding.projectId, taskId: enrollment.binding.taskId, groupId: null,
|
|
186
208
|
goalId: enrollment.binding.goalId, goalStepId: enrollment.binding.goalStepId,
|
|
209
|
+
portalRef: enrollment.binding.portalRef ?? null, threadRef: enrollment.binding.threadRef ?? null,
|
|
187
210
|
timelineVisibility: enrollment.timelineVisibility, enrollmentDigest: enrollment.enrollmentDigest };
|
|
188
211
|
const request = timelineInvocationRequest(tool, updatedInput, root);
|
|
189
212
|
const authorization = await authorizeSessionTimelineInvocation({
|