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
|
@@ -37,7 +37,8 @@ export function visible(candidate, entities, audience, includePrivate, groupId)
|
|
|
37
37
|
|
|
38
38
|
export async function learningContext({
|
|
39
39
|
root = process.cwd(), includePrivate = false, groupId = null, kinds = null,
|
|
40
|
-
subjectIds = null, scope = null, maxItems = null, catalog: providedCatalog = null, now = new Date()
|
|
40
|
+
subjectIds = null, scope = null, maxItems = null, catalog: providedCatalog = null, now = new Date(),
|
|
41
|
+
taskFocus = null
|
|
41
42
|
} = {}) {
|
|
42
43
|
const catalog = providedCatalog || await buildCatalog(root);
|
|
43
44
|
const { learning } = await loadLearning(catalog.root, catalog);
|
|
@@ -75,10 +76,14 @@ export async function learningContext({
|
|
|
75
76
|
.filter((candidate) => !subjectFilter || subjectFilter.has(candidate.subjectId))
|
|
76
77
|
.filter((candidate) => candidate.privacy !== "group" || (groupId && candidate.groupId === groupId))
|
|
77
78
|
.filter((candidate) => visible(candidate, entities, audience, includePrivate, groupId));
|
|
78
|
-
const
|
|
79
|
+
const candidates = applicable
|
|
79
80
|
.filter((candidate) => !invalidCanaries.has(candidate.id))
|
|
80
|
-
.filter((candidate) => visible(candidate, entities, audience, includePrivate, groupId))
|
|
81
|
-
|
|
81
|
+
.filter((candidate) => visible(candidate, entities, audience, includePrivate, groupId));
|
|
82
|
+
const focusedTaskId = typeof taskFocus === "string" && taskFocus === runtimeScope.taskId ? taskFocus : null;
|
|
83
|
+
const items = candidates
|
|
84
|
+
.sort((a, b) => Number(Boolean(focusedTaskId && b.scope?.taskId === focusedTaskId))
|
|
85
|
+
- Number(Boolean(focusedTaskId && a.scope?.taskId === focusedTaskId))
|
|
86
|
+
|| b.confidence - a.confidence || b.updatedAt.localeCompare(a.updatedAt) || a.id.localeCompare(b.id))
|
|
82
87
|
.slice(0, limit)
|
|
83
88
|
.map((candidate) => ({
|
|
84
89
|
id: candidate.id,
|
|
@@ -97,6 +102,8 @@ export async function learningContext({
|
|
|
97
102
|
&& new Date(candidate.promotion.canary.revalidation.expiresAt).getTime() >= new Date(timestamp).getTime()
|
|
98
103
|
? "revalidating" : candidate.promotion.canary.status)
|
|
99
104
|
: "not-required",
|
|
105
|
+
...(focusedTaskId && candidate.scope?.taskId === focusedTaskId
|
|
106
|
+
? { relevance: { taskId: focusedTaskId, match: "exact-task" } } : {}),
|
|
100
107
|
authority: "context-only"
|
|
101
108
|
}));
|
|
102
109
|
return {
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
|
|
24
24
|
export async function recordLearningMeasurement({
|
|
25
25
|
root = process.cwd(), id = `measurement:${randomUUID()}`, learningId, evaluationId, phase, scope, metric,
|
|
26
|
-
measurement, coverage, measuredAt, confirmLocalMeasurement = false, now = new Date()
|
|
26
|
+
measurement, coverage, measuredAt, confirmLocalMeasurement = false, now = new Date(), catalog: providedCatalog = null
|
|
27
27
|
}) {
|
|
28
28
|
if (!confirmLocalMeasurement) throw new Error("measurement registration requires explicit local confirmation");
|
|
29
29
|
if (!ID_RE.test(id || "") || !ID_RE.test(learningId || "") || !ID_RE.test(evaluationId || "")) {
|
|
@@ -205,7 +205,7 @@ export async function recordLearningMeasurement({
|
|
|
205
205
|
state.measurementLineage.push(lineage);
|
|
206
206
|
state.measurementLineage.sort((a, b) => a.measurementReceiptId.localeCompare(b.measurementReceiptId));
|
|
207
207
|
return { receipt, lineage, learningPath, unchanged: false };
|
|
208
|
-
});
|
|
208
|
+
}, providedCatalog);
|
|
209
209
|
}
|
|
210
210
|
|
|
211
211
|
export async function revokeLearningMeasurement({
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
import { sharedContext } from "./sharing.js";
|
|
26
26
|
import { recordWorldAssertion, worldContext } from "./world-model.js";
|
|
27
27
|
import { indexSessionTimeline, searchSessionTimeline } from "./session-timeline.js";
|
|
28
|
+
import { captureSessionTimelineEvidence } from "./timeline-world-capture.js";
|
|
28
29
|
import { gatewayEnvironmentContext } from "./hook-context.js";
|
|
29
30
|
import {
|
|
30
31
|
timelineInvocationInput, timelineInvocationRequest
|
|
@@ -48,6 +49,66 @@ function timelineTransport(input, root, environment) {
|
|
|
48
49
|
|
|
49
50
|
function absent(value) { return value === undefined || value === null || value === ""; }
|
|
50
51
|
|
|
52
|
+
function gatewayWorldRoute(environment) {
|
|
53
|
+
const gateway = gatewayEnvironmentContext(environment);
|
|
54
|
+
return gateway?.portalRef && gateway?.threadRef ? gateway : null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function exactGatewayValue(args, key, value) {
|
|
58
|
+
if (!absent(args[key]) && args[key] !== value) {
|
|
59
|
+
throw new Error(`${key} does not match the authenticated gateway binding`);
|
|
60
|
+
}
|
|
61
|
+
return value ?? null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function boundGatewayBriefing(args, gateway) {
|
|
65
|
+
if (!gateway) return args;
|
|
66
|
+
const result = { ...args, portalRef: gateway.portalRef, threadRef: gateway.threadRef };
|
|
67
|
+
for (const [key, gatewayKey] of [["host", "host"], ["entityId", "entityId"],
|
|
68
|
+
["projectId", "projectId"], ["groupId", "groupId"], ["currentTaskId", "taskId"]]) {
|
|
69
|
+
result[key] = exactGatewayValue(args, key, gateway[gatewayKey]);
|
|
70
|
+
}
|
|
71
|
+
if (result.groupId && result.includePrivate) {
|
|
72
|
+
throw new Error("private briefing context cannot be requested from an authenticated group route");
|
|
73
|
+
}
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function boundWorldWrite(args, environment) {
|
|
78
|
+
if (Object.hasOwn(args, "portalRef") || Object.hasOwn(args, "threadRef")) {
|
|
79
|
+
throw new Error("portal and thread references are supplied only by the authenticated gateway");
|
|
80
|
+
}
|
|
81
|
+
const gateway = gatewayWorldRoute(environment);
|
|
82
|
+
if (!gateway || !args.knowledgeKind || args.subjectId !== gateway.taskId) return args;
|
|
83
|
+
const projectId = exactGatewayValue(args, "projectId", gateway.projectId);
|
|
84
|
+
const groupId = exactGatewayValue(args, "groupId", gateway.groupId);
|
|
85
|
+
if (groupId && args.privacy !== "group") {
|
|
86
|
+
throw new Error("task knowledge from an authenticated group route requires group privacy");
|
|
87
|
+
}
|
|
88
|
+
if (!groupId && args.privacy === "group") {
|
|
89
|
+
throw new Error("group task knowledge requires an authenticated group route");
|
|
90
|
+
}
|
|
91
|
+
return { ...args, projectId, groupId, portalRef: gateway.portalRef, threadRef: gateway.threadRef };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function boundWorldRead(args, environment) {
|
|
95
|
+
if (Object.hasOwn(args, "portalRef") || Object.hasOwn(args, "threadRef")) {
|
|
96
|
+
throw new Error("portal and thread references are supplied only by the authenticated gateway");
|
|
97
|
+
}
|
|
98
|
+
const gateway = gatewayWorldRoute(environment);
|
|
99
|
+
if (!gateway) return args;
|
|
100
|
+
if (args.continuationTaskId && gateway.taskId && args.continuationTaskId !== gateway.taskId) {
|
|
101
|
+
throw new Error("continuationTaskId does not match the authenticated gateway task");
|
|
102
|
+
}
|
|
103
|
+
const projectId = exactGatewayValue(args, "projectId", gateway.projectId);
|
|
104
|
+
const groupId = exactGatewayValue(args, "groupId", gateway.groupId);
|
|
105
|
+
if (groupId && args.includePrivate) {
|
|
106
|
+
throw new Error("private world context cannot be requested from an authenticated group route");
|
|
107
|
+
}
|
|
108
|
+
return { ...args, projectId, groupId, portalRef: gateway.portalRef, threadRef: gateway.threadRef,
|
|
109
|
+
continuationTaskId: args.continuationTaskId ?? gateway.taskId };
|
|
110
|
+
}
|
|
111
|
+
|
|
51
112
|
// The MCP process can outlive a host turn. A group claim that appears after a
|
|
52
113
|
// private permit was issued must therefore suppress consumption here as well
|
|
53
114
|
// as in PreToolUse; tool arguments cannot clear an authenticated environment.
|
|
@@ -99,7 +160,8 @@ async function callTool(name, args = {}, environment = process.env) {
|
|
|
99
160
|
}));
|
|
100
161
|
}
|
|
101
162
|
if (name === "session_briefing") {
|
|
102
|
-
const
|
|
163
|
+
const gateway = gatewayWorldRoute(environment);
|
|
164
|
+
const scoped = boundGatewayBriefing(await boundBriefingArguments({ ...args, root }), gateway);
|
|
103
165
|
const sources = await resolveMcpSources({ ...scoped, required: Boolean(args.requirementId) });
|
|
104
166
|
const briefing = await sessionBriefing({ ...scoped, host: sources.host,
|
|
105
167
|
catalog: sources.catalog, userStateRoot: sources.userStateRoot, sourceDiagnostics: sources.diagnostics });
|
|
@@ -150,8 +212,12 @@ async function callTool(name, args = {}, environment = process.env) {
|
|
|
150
212
|
if (name === "update_task") return textResult(await updateTask({ ...args, root }));
|
|
151
213
|
if (name === "task_context") return textResult(await taskContext({ ...args, root }));
|
|
152
214
|
if (name === "shared_context") return textResult(await sharedContext({ ...args, root }));
|
|
153
|
-
if (name === "record_world_assertion")
|
|
154
|
-
|
|
215
|
+
if (name === "record_world_assertion") {
|
|
216
|
+
return textResult(await recordWorldAssertion({ ...boundWorldWrite(args, environment), root }));
|
|
217
|
+
}
|
|
218
|
+
if (name === "world_context") {
|
|
219
|
+
return textResult(await worldContext({ ...boundWorldRead(args, environment), root }));
|
|
220
|
+
}
|
|
155
221
|
if (name === "project_portfolio") return textResult(await projectPortfolioContext({ ...args, root }));
|
|
156
222
|
if (name === "record_project_observation") return textResult(await recordProjectObservation({ ...args, root }));
|
|
157
223
|
if (name === "evaluate_autonomy_action") return textResult(await evaluateAutonomyAction({ ...args, root }));
|
|
@@ -181,10 +247,30 @@ async function callTool(name, args = {}, environment = process.env) {
|
|
|
181
247
|
if (!invocationRequest) return textResult(unavailableTimelineInvocation("timeline-invocation-unavailable"));
|
|
182
248
|
return textResult(await searchSessionTimeline({ root, host: timeline.host, sessionId: input.request.sessionId, scope: timeline.scope,
|
|
183
249
|
at: args.at, query: args.query, windowSeconds: args.windowSeconds, includePriorSessions: args.includePriorSessions,
|
|
250
|
+
includePriorProviders: args.includePriorProviders, environment,
|
|
184
251
|
enrollmentDigest: input.request.enrollmentDigest,
|
|
185
252
|
hostHome: timelineHostHome(timeline.host, environment), transportDigest: timeline.transportDigest,
|
|
186
253
|
invocationRequest }));
|
|
187
254
|
}
|
|
255
|
+
if (name === "session_timeline_capture") {
|
|
256
|
+
const input = timelineInvocationInput(args);
|
|
257
|
+
if (runtimeTimelineGroup(environment, input)) return textResult(unavailableTimelineInvocation("timeline-group-suppressed"));
|
|
258
|
+
if (!input.valid) return textResult(unavailableTimelineInvocation(input.reason || "timeline-scope-invalid"));
|
|
259
|
+
const timeline = timelineTransport(input, root, environment);
|
|
260
|
+
if (!runtimeGatewayMatchesTimeline(environment, timeline.scope, timeline.host)) {
|
|
261
|
+
return textResult(unavailableTimelineInvocation("timeline-gateway-binding-mismatch"));
|
|
262
|
+
}
|
|
263
|
+
const invocationRequest = timelineInvocationRequest("capture", args, root);
|
|
264
|
+
if (!invocationRequest) return textResult(unavailableTimelineInvocation("timeline-invocation-unavailable"));
|
|
265
|
+
return textResult(await captureSessionTimelineEvidence({ root, host: timeline.host,
|
|
266
|
+
sessionId: input.request.sessionId, scope: timeline.scope, eventId: args.eventId,
|
|
267
|
+
at: args.at, query: args.query, windowSeconds: args.windowSeconds,
|
|
268
|
+
includePriorSessions: args.includePriorSessions, includePriorProviders: args.includePriorProviders,
|
|
269
|
+
interpretation: args.interpretation ?? null,
|
|
270
|
+
environment, enrollmentDigest: input.request.enrollmentDigest,
|
|
271
|
+
hostHome: timelineHostHome(timeline.host, environment), transportDigest: timeline.transportDigest,
|
|
272
|
+
invocationRequest }));
|
|
273
|
+
}
|
|
188
274
|
if (name === "audit") return textResult(await runAudit(root));
|
|
189
275
|
if (name === "complete_delivery") {
|
|
190
276
|
const completed = await completeDelivery(args);
|
|
@@ -3,7 +3,7 @@ import { resolveHostSourceCatalog } from "./source-roots.js";
|
|
|
3
3
|
import { inspectPremortemState } from "./delivery-premortem.js";
|
|
4
4
|
|
|
5
5
|
const INTERNAL = new Set(["catalog", "userStateRoot", "sourceDiagnostics", "sourceRegistry",
|
|
6
|
-
"env", "input", "memoryHooks", "resolvedSources"]);
|
|
6
|
+
"env", "input", "memoryHooks", "resolvedSources", "portalRef", "threadRef"]);
|
|
7
7
|
|
|
8
8
|
export function rejectInternalSourceArguments(args) {
|
|
9
9
|
for (const key of INTERNAL) {
|
|
@@ -31,8 +31,18 @@ export async function boundBriefingArguments(args) {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
export async function resolveMcpSources({ root, cwd = root,
|
|
34
|
-
host
|
|
34
|
+
host, entityId = null,
|
|
35
35
|
groupId = null, projectId = null, currentTaskId = null, required = false }) {
|
|
36
|
+
const blunHost = Boolean(process.env.BLUN_HOME && process.env.BLUN_PLUGIN_ROOT);
|
|
37
|
+
const runtimeHost = blunHost && process.env.AGENTSPINE_HOST === "blun"
|
|
38
|
+
? "codex" : process.env.AGENTSPINE_HOST;
|
|
39
|
+
const selectedHost = host === undefined ? runtimeHost : host;
|
|
40
|
+
// King binds both values when loading this plugin; model arguments cannot
|
|
41
|
+
// switch that running host to another application's private profile.
|
|
42
|
+
if (blunHost && selectedHost !== undefined && selectedHost !== "codex") {
|
|
43
|
+
throw new Error("MCP source host does not match the running BLUN host");
|
|
44
|
+
}
|
|
45
|
+
host = blunHost ? "codex" : (host === undefined ? process.env.AGENTSPINE_HOST || "generic" : host);
|
|
36
46
|
const canonicalRoot = await canonicalPath(root);
|
|
37
47
|
const canonicalCwd = await canonicalPath(cwd);
|
|
38
48
|
if (!isInside(canonicalRoot, canonicalCwd)) throw new Error("MCP cwd must remain inside its root");
|
|
@@ -6,18 +6,60 @@ const stableId = {
|
|
|
6
6
|
};
|
|
7
7
|
|
|
8
8
|
const optionalId = { anyOf: [stableId, { type: "null" }] };
|
|
9
|
+
const assertionId = {
|
|
10
|
+
type: "string",
|
|
11
|
+
pattern: "^assertion:[A-Za-z0-9][A-Za-z0-9._/-]{0,190}$"
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const TIMELINE_INTERPRETATION_SCHEMA = "agentspine.timeline-user-feedback-interpretation-request/v1";
|
|
15
|
+
export const TIMELINE_CLARIFICATION_SCHEMA = "agentspine.timeline-user-feedback-clarification-request/v2";
|
|
16
|
+
const INTERPRETATION_KINDS = new Set([
|
|
17
|
+
"next-step-correction", "completion-claim", "not-current-instruction", "ambiguous"
|
|
18
|
+
]);
|
|
19
|
+
|
|
20
|
+
export function timelineInterpretationRequest(value) {
|
|
21
|
+
if (!value || typeof value !== "object" || Array.isArray(value)
|
|
22
|
+
|| Object.getPrototypeOf(value) !== Object.prototype) return null;
|
|
23
|
+
const clarificationKeys = ["schema", "feedbackAssertionIds", "targetAssertionId", "clarificationQuestion"];
|
|
24
|
+
if (Object.keys(value).sort().join("\0") === clarificationKeys.sort().join("\0")
|
|
25
|
+
&& value.schema === TIMELINE_CLARIFICATION_SCHEMA
|
|
26
|
+
&& Array.isArray(value.feedbackAssertionIds) && value.feedbackAssertionIds.length >= 2
|
|
27
|
+
&& value.feedbackAssertionIds.length <= 3
|
|
28
|
+
&& value.feedbackAssertionIds.every((id) => /^assertion:[A-Za-z0-9][A-Za-z0-9._/-]{0,190}$/.test(id))
|
|
29
|
+
&& new Set(value.feedbackAssertionIds).size === value.feedbackAssertionIds.length
|
|
30
|
+
&& [...value.feedbackAssertionIds].sort().every((id, index) => id === value.feedbackAssertionIds[index])
|
|
31
|
+
&& /^assertion:[A-Za-z0-9][A-Za-z0-9._/-]{0,190}$/.test(value.targetAssertionId || "")
|
|
32
|
+
&& typeof value.clarificationQuestion === "string" && Boolean(value.clarificationQuestion.trim())
|
|
33
|
+
&& value.clarificationQuestion.length <= 300 && !/[\r\n]/u.test(value.clarificationQuestion)) {
|
|
34
|
+
return structuredClone(value);
|
|
35
|
+
}
|
|
36
|
+
const keys = ["schema", "feedbackAssertionId", "targetAssertionId", "kind",
|
|
37
|
+
"proposedNextStepSummary", "clarificationQuestion"];
|
|
38
|
+
if (Object.keys(value).sort().join("\0") !== keys.sort().join("\0")
|
|
39
|
+
|| value.schema !== TIMELINE_INTERPRETATION_SCHEMA
|
|
40
|
+
|| !/^assertion:[A-Za-z0-9][A-Za-z0-9._/-]{0,190}$/.test(value.feedbackAssertionId || "")
|
|
41
|
+
|| !/^assertion:[A-Za-z0-9][A-Za-z0-9._/-]{0,190}$/.test(value.targetAssertionId || "")
|
|
42
|
+
|| !INTERPRETATION_KINDS.has(value.kind)) return null;
|
|
43
|
+
const next = value.proposedNextStepSummary;
|
|
44
|
+
const question = value.clarificationQuestion;
|
|
45
|
+
const validNext = typeof next === "string" && Boolean(next.trim())
|
|
46
|
+
&& next.length <= 500 && !/[\r\n]/u.test(next);
|
|
47
|
+
const validQuestion = typeof question === "string" && Boolean(question.trim())
|
|
48
|
+
&& question.length <= 300 && !/[\r\n]/u.test(question);
|
|
49
|
+
if ((value.kind === "next-step-correction" ? !validNext || question !== null
|
|
50
|
+
: next !== null || (value.kind === "ambiguous" ? !validQuestion : question !== null))) return null;
|
|
51
|
+
return structuredClone(value);
|
|
52
|
+
}
|
|
9
53
|
|
|
10
54
|
// Hosts qualify MCP tools differently. These prefixes must stay exact: a
|
|
11
55
|
// foreign MCP server can expose an identically named tool but must never
|
|
12
56
|
// receive a timeline invocation permit.
|
|
13
57
|
export const AGENTSPINE_TIMELINE_TOOL_PREFIX = "mcp__plugin_agent-spine_agent-spine__";
|
|
14
58
|
export const BLUN_TIMELINE_TOOL_PREFIX = "mcp__agent-spine__";
|
|
15
|
-
export const KING_PLUGIN_TIMELINE_TOOL_PREFIX = "mcp__plugin-agent-spine_agent-spine__";
|
|
16
59
|
|
|
17
60
|
const TIMELINE_TOOL_PREFIXES = [
|
|
18
61
|
AGENTSPINE_TIMELINE_TOOL_PREFIX,
|
|
19
|
-
BLUN_TIMELINE_TOOL_PREFIX
|
|
20
|
-
KING_PLUGIN_TIMELINE_TOOL_PREFIX
|
|
62
|
+
BLUN_TIMELINE_TOOL_PREFIX
|
|
21
63
|
];
|
|
22
64
|
|
|
23
65
|
const SCOPE_FIELDS = [
|
|
@@ -29,6 +71,8 @@ const SCOPE_FIELDS = [
|
|
|
29
71
|
["currentTaskId", ["taskId", "task_id", "currentTaskId", "current_task_id"]],
|
|
30
72
|
["goalId", ["goalId", "goal_id"]],
|
|
31
73
|
["goalStepId", ["goalStepId", "goal_step_id"]],
|
|
74
|
+
["portalRef", ["portalRef", "portal_ref"]],
|
|
75
|
+
["threadRef", ["threadRef", "thread_ref"]],
|
|
32
76
|
["timelineVisibility", ["timelineVisibility", "timeline_visibility"]]
|
|
33
77
|
];
|
|
34
78
|
|
|
@@ -110,6 +154,7 @@ export function timelineToolKind(name) {
|
|
|
110
154
|
const qualified = String(name || "");
|
|
111
155
|
if (TIMELINE_TOOL_PREFIXES.some((prefix) => qualified === `${prefix}session_timeline_index`)) return "index";
|
|
112
156
|
if (TIMELINE_TOOL_PREFIXES.some((prefix) => qualified === `${prefix}session_timeline_search`)) return "search";
|
|
157
|
+
if (TIMELINE_TOOL_PREFIXES.some((prefix) => qualified === `${prefix}session_timeline_capture`)) return "capture";
|
|
113
158
|
return null;
|
|
114
159
|
}
|
|
115
160
|
|
|
@@ -120,17 +165,22 @@ export function timelineInvocationRequest(tool, args, root) {
|
|
|
120
165
|
const request = { root, tool, sessionId: input.request.sessionId, entityId: scope.entityId, userId: scope.userId,
|
|
121
166
|
tenantId: scope.tenantId, projectId: scope.projectId, groupId: scope.groupId, taskId: scope.currentTaskId,
|
|
122
167
|
goalId: scope.goalId, goalStepId: scope.goalStepId, timelineVisibility: scope.timelineVisibility,
|
|
168
|
+
portalRef: scope.portalRef, threadRef: scope.threadRef,
|
|
123
169
|
enrollmentDigest: input.request.enrollmentDigest };
|
|
124
170
|
if (tool === "index") return { ...request, maxBytes: args.maxBytes ?? 4 * 1024 * 1024 };
|
|
125
|
-
return { ...request,
|
|
171
|
+
return { ...request, ...(tool === "capture" ? { eventId: args.eventId ?? null,
|
|
172
|
+
interpretation: args.interpretation ?? null } : {}),
|
|
173
|
+
at: args.at ?? null, query: args.query ?? null,
|
|
126
174
|
windowSeconds: args.windowSeconds === undefined ? 0 : args.windowSeconds,
|
|
127
|
-
includePriorSessions: args.includePriorSessions === true
|
|
175
|
+
includePriorSessions: args.includePriorSessions === true,
|
|
176
|
+
includePriorProviders: args.includePriorProviders === true };
|
|
128
177
|
}
|
|
129
178
|
|
|
130
179
|
const scopeProperties = {
|
|
131
180
|
host: { enum: TIMELINE_HOSTS },
|
|
132
181
|
entityId: stableId, userId: stableId, tenantId: stableId, projectId: stableId,
|
|
133
|
-
taskId: stableId, goalId: optionalId, goalStepId: optionalId
|
|
182
|
+
taskId: stableId, goalId: optionalId, goalStepId: optionalId,
|
|
183
|
+
portalRef: optionalId, threadRef: optionalId
|
|
134
184
|
};
|
|
135
185
|
|
|
136
186
|
export const sessionTimelineTools = [
|
|
@@ -148,7 +198,7 @@ export const sessionTimelineTools = [
|
|
|
148
198
|
},
|
|
149
199
|
{
|
|
150
200
|
name: "session_timeline_search",
|
|
151
|
-
description: "Search
|
|
201
|
+
description: "Search one enrolled immutable same-task source for objective evidence or strict user corrections. Query 'user message' explicitly selects bounded native user-message candidates without interpreting them; add exact UTC time to narrow. No source text is indexed. Cross-provider recall requires opt-in; one source is opened and no authority is granted.",
|
|
152
202
|
inputSchema: {
|
|
153
203
|
type: "object", additionalProperties: false,
|
|
154
204
|
required: [],
|
|
@@ -158,7 +208,40 @@ export const sessionTimelineTools = [
|
|
|
158
208
|
timelineVisibility: { const: "private-verified" }, groupId: { anyOf: [stableId, { type: "null" }] },
|
|
159
209
|
at: { type: "string", format: "date-time" }, query: { type: "string", minLength: 3, maxLength: 512 },
|
|
160
210
|
windowSeconds: { type: "integer", minimum: 0, maximum: 900 },
|
|
161
|
-
includePriorSessions: { type: "boolean" } }
|
|
211
|
+
includePriorSessions: { type: "boolean" }, includePriorProviders: { type: "boolean" } }
|
|
212
|
+
}
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
name: "session_timeline_capture",
|
|
216
|
+
description: "Reopen one source-bound event. Objective fields become descriptive task state; strict prefixed corrections may replace the same-thread next step. Natural user messages remain uninterpreted beside their exact checkpoint. A second source-bound call may preserve one model interpretation as an unconfirmed proposal; it never changes continuation, proves completion or grants authority.",
|
|
217
|
+
inputSchema: {
|
|
218
|
+
type: "object", additionalProperties: false,
|
|
219
|
+
required: ["eventId"],
|
|
220
|
+
anyOf: [{ required: ["at"] }, { required: ["query"] }],
|
|
221
|
+
properties: { root: { type: "string", minLength: 1 }, sessionId: stableId, ...scopeProperties,
|
|
222
|
+
enrollmentDigest: { type: "string", pattern: "^[a-f0-9]{64}$" },
|
|
223
|
+
timelineVisibility: { const: "private-verified" }, groupId: { anyOf: [stableId, { type: "null" }] },
|
|
224
|
+
eventId: { type: "string", pattern: "^timeline-event:[a-f0-9]{32}$" },
|
|
225
|
+
interpretation: { oneOf: [{
|
|
226
|
+
type: "object", additionalProperties: false,
|
|
227
|
+
required: ["schema", "feedbackAssertionId", "targetAssertionId", "kind",
|
|
228
|
+
"proposedNextStepSummary", "clarificationQuestion"],
|
|
229
|
+
properties: { schema: { const: TIMELINE_INTERPRETATION_SCHEMA },
|
|
230
|
+
feedbackAssertionId: assertionId, targetAssertionId: assertionId,
|
|
231
|
+
kind: { enum: [...INTERPRETATION_KINDS] },
|
|
232
|
+
proposedNextStepSummary: { anyOf: [{ type: "string", minLength: 1, maxLength: 500 }, { type: "null" }] },
|
|
233
|
+
clarificationQuestion: { anyOf: [{ type: "string", minLength: 1, maxLength: 300 }, { type: "null" }] } }
|
|
234
|
+
}, {
|
|
235
|
+
type: "object", additionalProperties: false,
|
|
236
|
+
required: ["schema", "feedbackAssertionIds", "targetAssertionId", "clarificationQuestion"],
|
|
237
|
+
properties: { schema: { const: TIMELINE_CLARIFICATION_SCHEMA },
|
|
238
|
+
feedbackAssertionIds: { type: "array", minItems: 2, maxItems: 3, uniqueItems: true,
|
|
239
|
+
items: assertionId }, targetAssertionId: assertionId,
|
|
240
|
+
clarificationQuestion: { type: "string", minLength: 1, maxLength: 300 } }
|
|
241
|
+
}] },
|
|
242
|
+
at: { type: "string", format: "date-time" }, query: { type: "string", minLength: 3, maxLength: 512 },
|
|
243
|
+
windowSeconds: { type: "integer", minimum: 0, maximum: 900 },
|
|
244
|
+
includePriorSessions: { type: "boolean" }, includePriorProviders: { type: "boolean" } }
|
|
162
245
|
}
|
|
163
246
|
}
|
|
164
247
|
];
|
|
@@ -8,7 +8,7 @@ const nullableStableId = { anyOf: [stableId, { type: "null" }] };
|
|
|
8
8
|
export const worldModelTools = [
|
|
9
9
|
{
|
|
10
10
|
name: "record_world_assertion",
|
|
11
|
-
description: "Persist one provenance-bound world, user, relationship, or team assertion outside source files. Optional typed knowledge distinguishes facts, user preferences, decisions, task state, and error lessons. Measurements and explicit user feedback become context-only facts; model output remains a proposal. Authority predicates and secret-shaped structured knowledge are rejected.",
|
|
11
|
+
description: "Persist one provenance-bound world, user, relationship, or team assertion outside source files. Optional typed knowledge distinguishes facts, user preferences, decisions, task state, and error lessons. In an authenticated portal task, task-subject knowledge is bound to the gateway's opaque portal/thread route; tool arguments cannot claim that route. Measurements and explicit user feedback become context-only facts; model output remains a proposal. Authority predicates and secret-shaped structured knowledge are rejected.",
|
|
12
12
|
inputSchema: {
|
|
13
13
|
type: "object", additionalProperties: false,
|
|
14
14
|
required: ["id", "subjectId", "predicate", "value", "evidenceKind", "evidenceId", "evidenceDigest", "observedAt"],
|
|
@@ -36,7 +36,7 @@ export const worldModelTools = [
|
|
|
36
36
|
},
|
|
37
37
|
{
|
|
38
38
|
name: "world_context",
|
|
39
|
-
description: "Read privacy-filtered world context. Conflicts, expiry, and suggestions remain separate; continuationTaskId adds bounded, sourced task-relevant knowledge.",
|
|
39
|
+
description: "Read privacy-filtered world context. Conflicts, expiry, and suggestions remain separate; continuationTaskId adds bounded, sourced task-relevant knowledge. An authenticated portal process automatically restricts task continuation to its opaque gateway route; route references are not accepted as tool input.",
|
|
40
40
|
inputSchema: {
|
|
41
41
|
type: "object", additionalProperties: false,
|
|
42
42
|
properties: {
|
|
@@ -3,11 +3,26 @@ import { open, readFile, stat, unlink, utimes } from "node:fs/promises";
|
|
|
3
3
|
import { isFileLockContention, isTransientLockMetadataError } from "./filesystem-retry.js";
|
|
4
4
|
|
|
5
5
|
const LOCK_SCHEMA = "agentspine.owned-file-lock/v1";
|
|
6
|
+
const LOCAL_TAILS = new Map();
|
|
6
7
|
|
|
7
8
|
function delay(milliseconds) {
|
|
8
9
|
return new Promise((resolve) => setTimeout(resolve, milliseconds));
|
|
9
10
|
}
|
|
10
11
|
|
|
12
|
+
async function serialize(path, task) {
|
|
13
|
+
const previous = LOCAL_TAILS.get(path) || Promise.resolve();
|
|
14
|
+
let release;
|
|
15
|
+
const current = new Promise(resolve => { release = resolve; });
|
|
16
|
+
const tail = previous.catch(() => {}).then(() => current);
|
|
17
|
+
LOCAL_TAILS.set(path, tail);
|
|
18
|
+
await previous.catch(() => {});
|
|
19
|
+
try { return await task(); }
|
|
20
|
+
finally {
|
|
21
|
+
release();
|
|
22
|
+
if (LOCAL_TAILS.get(path) === tail) LOCAL_TAILS.delete(path);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
11
26
|
function lockPayload(token, acquiredAt, leaseMs) {
|
|
12
27
|
return {
|
|
13
28
|
schema: LOCK_SCHEMA,
|
|
@@ -66,7 +81,7 @@ async function removeStaleLock(path, staleAfterMs, assertPath = null) {
|
|
|
66
81
|
}
|
|
67
82
|
}
|
|
68
83
|
|
|
69
|
-
|
|
84
|
+
async function acquire(path, task, {
|
|
70
85
|
staleAfterMs = 15000,
|
|
71
86
|
heartbeatIntervalMs = 1000,
|
|
72
87
|
retryDelayMs = 25,
|
|
@@ -161,3 +176,7 @@ export async function withOwnedFileLock(path, task, {
|
|
|
161
176
|
}
|
|
162
177
|
}
|
|
163
178
|
}
|
|
179
|
+
|
|
180
|
+
export function withOwnedFileLock(path, task, options) {
|
|
181
|
+
return serialize(path, () => acquire(path, task, options));
|
|
182
|
+
}
|
|
@@ -3,7 +3,7 @@ import { constants as fsConstants } from "node:fs";
|
|
|
3
3
|
import { lstat, open, opendir, readFile, realpath, stat, unlink, writeFile } from "node:fs/promises";
|
|
4
4
|
import { isAbsolute, join } from "node:path";
|
|
5
5
|
import { buildCatalog } from "./catalog.js";
|
|
6
|
-
import { isFileLockContention, replaceFileWithRetry } from "./filesystem-retry.js";
|
|
6
|
+
import { isFileLockContention, isTransientLockMetadataError, replaceFileWithRetry } from "./filesystem-retry.js";
|
|
7
7
|
import { linkEntities, loadGraph, unlinkEntities, upsertEntity } from "./graph.js";
|
|
8
8
|
import { isInside, projectStateDir } from "./paths.js";
|
|
9
9
|
|
|
@@ -175,7 +175,7 @@ async function withLock(paths, task) {
|
|
|
175
175
|
try {
|
|
176
176
|
const metadata = await stat(lockPath);
|
|
177
177
|
if (Date.now() - metadata.mtimeMs > 90000) await unlink(lockPath);
|
|
178
|
-
} catch (lockError) { if (lockError
|
|
178
|
+
} catch (lockError) { if (!isTransientLockMetadataError(lockError)) throw lockError; }
|
|
179
179
|
await new Promise((resolve) => setTimeout(resolve, 25));
|
|
180
180
|
}
|
|
181
181
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
2
|
+
|
|
3
|
+
const ID = /^[A-Za-z0-9][A-Za-z0-9:_.@/+~-]{0,255}$/;
|
|
4
|
+
const issued = new WeakMap();
|
|
5
|
+
|
|
6
|
+
function exact(value, field) {
|
|
7
|
+
if (value === null || value === undefined || value === "") return null;
|
|
8
|
+
if (typeof value !== "string" || !ID.test(value) || value.includes("*")) {
|
|
9
|
+
throw new Error(`${field} must be one exact ID`);
|
|
10
|
+
}
|
|
11
|
+
return value;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Without a host ID, only the parsed invocation object can verify its receipt.
|
|
15
|
+
export function preflightDeliveryId(input, { issue = false } = {}) {
|
|
16
|
+
if (!input || typeof input !== "object") return null;
|
|
17
|
+
const turn = exact(input.turn_id, "turnId");
|
|
18
|
+
const event = exact(input.event_id ?? input.hook_event_id, "hookEventId");
|
|
19
|
+
if (turn && event) return `host-turn:${createHash("sha256").update(`${turn}\0${event}`).digest("hex").slice(0, 32)}`;
|
|
20
|
+
if (turn || event) return turn || event;
|
|
21
|
+
let id = issued.get(input);
|
|
22
|
+
if (!id && issue) {
|
|
23
|
+
id = `hook-invocation:${randomBytes(16).toString("hex")}`;
|
|
24
|
+
issued.set(input, id);
|
|
25
|
+
}
|
|
26
|
+
return id || null;
|
|
27
|
+
}
|
|
@@ -5,6 +5,7 @@ import { lstat, mkdir, open, readFile, realpath, stat, unlink, writeFile } from
|
|
|
5
5
|
import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
6
6
|
import { isFileLockContention, replaceFileWithRetry } from "./filesystem-retry.js";
|
|
7
7
|
import { ancestorsBetween, isInside, stateRoot } from "./paths.js";
|
|
8
|
+
import { preflightDeliveryId } from "./preflight-delivery-id.js";
|
|
8
9
|
import { resolveHostSourceCatalog } from "./source-roots.js";
|
|
9
10
|
|
|
10
11
|
export const PREFLIGHT_SCHEMA = "agentspine.preflight/v2";
|
|
@@ -493,8 +494,8 @@ export async function runPreflight({ input, scope, resolvedSources, prompt, now
|
|
|
493
494
|
if (typeof prompt !== "string" || !prompt.length || Buffer.byteLength(prompt) > 64 * 1024) throw new Error("preflight requires one bounded prompt");
|
|
494
495
|
const exactScope = scopeFromInput({ input, scope, resolvedSources, env });
|
|
495
496
|
const promptDigest = sha256(prompt);
|
|
496
|
-
const deliveryId =
|
|
497
|
-
|
|
497
|
+
const deliveryId = preflightDeliveryId(input, { issue: true });
|
|
498
|
+
if (!deliveryId) throw new Error("preflight hook invocation identity is unavailable");
|
|
498
499
|
const paths = storagePaths(env);
|
|
499
500
|
const policy = validatePolicy(await readJson(paths.policy, MAX_POLICY_BYTES, emptyPolicy));
|
|
500
501
|
const profile = policy.profiles.find((item) => item.enabled && item.agentId === exactScope.agentId && item.host === exactScope.host
|
|
@@ -590,8 +591,7 @@ export async function verifyPreflightReceipt({ receipt, input, scope, resolvedSo
|
|
|
590
591
|
|| receipt.tenantId !== exactScope.tenantId || receipt.host !== exactScope.host || receipt.profileId !== exactScope.profileId
|
|
591
592
|
|| receipt.sessionId !== exactScope.sessionId || receipt.projectId !== exactScope.projectId || receipt.cwdDigest !== sha256(exactScope.cwd)
|
|
592
593
|
|| receipt.taskId !== exactScope.taskId || receipt.groupId !== exactScope.groupId) return false;
|
|
593
|
-
const deliveryId =
|
|
594
|
-
`prompt:${sha256(`${exactScope.sessionId}\0${sha256(prompt)}`).slice(0, 32)}`);
|
|
594
|
+
const deliveryId = preflightDeliveryId(input);
|
|
595
595
|
if (receipt.deliveryId !== deliveryId) return false;
|
|
596
596
|
const { id: _id, bodyDigest, signature, ...body } = receipt;
|
|
597
597
|
if (digestObject(body) !== bodyDigest) return false;
|
|
@@ -56,3 +56,18 @@ export function codexTimelineToolResult(line) {
|
|
|
56
56
|
}
|
|
57
57
|
return typeof output === "string" ? { role: "tool", content: output, nativeMessageId: item.call_id } : null;
|
|
58
58
|
}
|
|
59
|
+
|
|
60
|
+
export function codexTimelineUserMessage(line) {
|
|
61
|
+
if (!RECORDS.has(line?.type) || line.schema_version !== undefined) {
|
|
62
|
+
throw new Error("codex-history-format-mismatch");
|
|
63
|
+
}
|
|
64
|
+
if (line.type !== "response_item") return null;
|
|
65
|
+
const item = line.payload;
|
|
66
|
+
if (!item || item.type !== "message" || item.role !== "user" || !Array.isArray(item.content)
|
|
67
|
+
|| item.content.length > 12 || item.content.some((part) => part?.type !== "input_text"
|
|
68
|
+
|| typeof part.text !== "string")) return null;
|
|
69
|
+
const nativeMessageId = item.id === undefined ? undefined : ID.test(item.id) ? item.id : null;
|
|
70
|
+
if (nativeMessageId === null) return null;
|
|
71
|
+
return { role: "user", content: item.content.map((part) => part.text).join("\n"),
|
|
72
|
+
...(nativeMessageId ? { nativeMessageId } : {}) };
|
|
73
|
+
}
|
|
@@ -7,7 +7,7 @@ export function safeTimelineId(value) {
|
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
export function sessionTimelineBinding({ host, sessionId, scope }) {
|
|
10
|
-
|
|
10
|
+
const binding = {
|
|
11
11
|
host: validTimelineHost(host) ? host : null,
|
|
12
12
|
sessionId: safeTimelineId(sessionId),
|
|
13
13
|
entityId: safeTimelineId(scope?.entityId),
|
|
@@ -19,6 +19,11 @@ export function sessionTimelineBinding({ host, sessionId, scope }) {
|
|
|
19
19
|
goalId: safeTimelineId(scope?.goalId),
|
|
20
20
|
goalStepId: safeTimelineId(scope?.goalStepId)
|
|
21
21
|
};
|
|
22
|
+
if (scope?.portalRef || scope?.threadRef) {
|
|
23
|
+
binding.portalRef = safeTimelineId(scope?.portalRef);
|
|
24
|
+
binding.threadRef = safeTimelineId(scope?.threadRef);
|
|
25
|
+
}
|
|
26
|
+
return binding;
|
|
22
27
|
}
|
|
23
28
|
|
|
24
29
|
export function hasTimelineGroupScope(scope) {
|
|
@@ -31,12 +36,13 @@ export function hasVerifiedTimelinePrivateScope(scope) {
|
|
|
31
36
|
|
|
32
37
|
export function completeTimelineBinding(value) {
|
|
33
38
|
return validTimelineHost(value.host) && !value.groupId
|
|
39
|
+
&& Boolean(value.portalRef) === Boolean(value.threadRef)
|
|
34
40
|
&& ["sessionId", "entityId", "userId", "tenantId", "projectId", "taskId"].every((key) => value[key]);
|
|
35
41
|
}
|
|
36
42
|
|
|
37
43
|
export function sameTimelineBinding(left, right) {
|
|
38
|
-
return ["host", "sessionId", "entityId", "userId", "tenantId", "projectId", "groupId", "taskId", "goalId", "goalStepId"
|
|
39
|
-
.every((key) => left[key] === right[key]);
|
|
44
|
+
return ["host", "sessionId", "entityId", "userId", "tenantId", "projectId", "groupId", "taskId", "goalId", "goalStepId",
|
|
45
|
+
"portalRef", "threadRef"].every((key) => (left[key] ?? null) === (right[key] ?? null));
|
|
40
46
|
}
|
|
41
47
|
|
|
42
48
|
export function validTimelineBinding(value) {
|
|
@@ -44,5 +50,7 @@ export function validTimelineBinding(value) {
|
|
|
44
50
|
&& [value.sessionId, value.entityId, value.userId, value.tenantId, value.projectId, value.taskId]
|
|
45
51
|
.every((item) => typeof item === "string" && TIMELINE_ID_RE.test(item))
|
|
46
52
|
&& [value.groupId, value.goalId, value.goalStepId]
|
|
47
|
-
.every((item) => item === null || (typeof item === "string" && TIMELINE_ID_RE.test(item)))
|
|
53
|
+
.every((item) => item === null || (typeof item === "string" && TIMELINE_ID_RE.test(item)))
|
|
54
|
+
&& ((value.portalRef === undefined && value.threadRef === undefined)
|
|
55
|
+
|| [value.portalRef, value.threadRef].every((item) => typeof item === "string" && TIMELINE_ID_RE.test(item)));
|
|
48
56
|
}
|