@ouro.bot/cli 0.1.0-alpha.81 → 0.1.0-alpha.810
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/LICENSE +21 -0
- package/README.md +154 -23
- package/RepairGuide.ouro/agent.json +5 -0
- package/RepairGuide.ouro/psyche/IDENTITY.md +19 -0
- package/RepairGuide.ouro/psyche/SOUL.md +55 -0
- package/RepairGuide.ouro/skills/diagnose-broken-remote.md +63 -0
- package/RepairGuide.ouro/skills/diagnose-stacked-typed-issues.md +35 -0
- package/RepairGuide.ouro/skills/diagnose-sync-blocked.md +54 -0
- package/RepairGuide.ouro/skills/diagnose-vault-expired.md +60 -0
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/agent.json +4 -2
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/SOUL.md +2 -2
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +1 -1
- package/assets/bluebubbles-host +264 -0
- package/changelog.json +5177 -16
- package/deploy/unraid/Dockerfile +48 -0
- package/deploy/unraid/README.txt +3032 -0
- package/deploy/unraid/audit-container-spec.sh +4 -0
- package/deploy/unraid/container-runtime.json +1 -0
- package/deploy/unraid/docker-man-template-transaction.mjs +526 -0
- package/deploy/unraid/docker-man-template-xml.cjs +105 -0
- package/deploy/unraid/migrate-sanctuary-bundle.mjs +60 -0
- package/deploy/unraid/ouro-events/bootstrap-spool.sh +92 -0
- package/deploy/unraid/ouro-events/emit-event.mjs +310 -0
- package/deploy/unraid/ouro-events/emit-usenet-event.sh +54 -0
- package/deploy/unraid/ouro-events/install-usenet-guard.sh +435 -0
- package/deploy/unraid/ouro-events/usenet-health.sh +176 -0
- package/deploy/unraid/sanctuary-acceptance-adapter.sh +43 -0
- package/deploy/unraid/sanctuary-acceptance-contract.json +198 -0
- package/deploy/unraid/sanctuary-acceptance-harness.sh +23 -0
- package/deploy/unraid/sanctuary-deployment-target.mjs +709 -0
- package/deploy/unraid/sanctuary-safe-rename.py +24 -0
- package/deploy/unraid/sanctuary-unit16-host-broker.mjs +2030 -0
- package/deploy/unraid/sanctuary-unit16-run.sh +560 -0
- package/deploy/unraid/sanctuary-unit18-target-audit.sh +27 -0
- package/deploy/unraid/sanctuary.ouro/agent.json +24 -0
- package/deploy/unraid/sanctuary.ouro/arc/README.md +3 -0
- package/deploy/unraid/sanctuary.ouro/bundle-meta.json +5 -0
- package/deploy/unraid/sanctuary.ouro/habits/sanctuary-health.md +8 -0
- package/deploy/unraid/sanctuary.ouro/provider-readiness.json +11 -0
- package/deploy/unraid/sanctuary.ouro/psyche/ASPIRATIONS.md +5 -0
- package/deploy/unraid/sanctuary.ouro/psyche/IDENTITY.md +5 -0
- package/deploy/unraid/sanctuary.ouro/psyche/LORE.md +11 -0
- package/deploy/unraid/sanctuary.ouro/psyche/SOUL.md +25 -0
- package/deploy/unraid/sanctuary.ouro/psyche/TACIT.md +11 -0
- package/deploy/unraid/sanctuary.ouro/state/policy/steward.json +7 -0
- package/deploy/unraid/sanctuary.ouro/tool-profiles.json +23 -0
- package/deploy/unraid/sanctuary.xml +27 -0
- package/dist/a2a/card.js +57 -0
- package/dist/a2a/client.js +180 -0
- package/dist/a2a/config.js +50 -0
- package/dist/a2a/delegation-stores.js +56 -0
- package/dist/a2a/did-resolution.js +93 -0
- package/dist/a2a/identity.js +170 -0
- package/dist/a2a/inbound-share.js +107 -0
- package/dist/a2a/mission-result-wire.js +196 -0
- package/dist/a2a/onboarding.js +115 -0
- package/dist/a2a/pin-store.js +132 -0
- package/dist/a2a/seen-ledger.js +120 -0
- package/dist/a2a/server.js +604 -0
- package/dist/a2a/task-store.js +69 -0
- package/dist/a2a/transport.js +45 -0
- package/dist/a2a/types.js +3 -0
- package/dist/arc/attention-types.js +8 -0
- package/dist/arc/cares.js +360 -0
- package/dist/arc/episodes.js +118 -0
- package/dist/arc/evolution.js +490 -0
- package/dist/arc/flight-recorder.js +1034 -0
- package/dist/arc/intentions.js +134 -0
- package/dist/arc/json-store.js +117 -0
- package/dist/arc/obligations.js +386 -0
- package/dist/arc/packets.js +336 -0
- package/dist/arc/presence.js +185 -0
- package/dist/arc/task-lifecycle.js +57 -0
- package/dist/commerce/store.js +755 -0
- package/dist/commerce/types.js +3 -0
- package/dist/heart/active-work.js +820 -29
- package/dist/heart/agent-entry.js +252 -3
- package/dist/heart/approval-files.js +113 -0
- package/dist/heart/approval-store.js +950 -0
- package/dist/heart/attachments/image-normalize.js +194 -0
- package/dist/heart/attachments/materialize.js +97 -0
- package/dist/heart/attachments/originals.js +88 -0
- package/dist/heart/attachments/render.js +29 -0
- package/dist/heart/attachments/sources/bluebubbles.js +156 -0
- package/dist/heart/attachments/sources/cli-local-file.js +78 -0
- package/dist/heart/attachments/sources/index.js +18 -0
- package/dist/heart/attachments/sources/telegram.js +71 -0
- package/dist/heart/attachments/store.js +132 -0
- package/dist/heart/attachments/types.js +93 -0
- package/dist/heart/auth/auth-flow.js +495 -0
- package/dist/heart/autonomy-budget.js +478 -0
- package/dist/heart/awaiting/await-alert.js +148 -0
- package/dist/heart/awaiting/await-expiry.js +143 -0
- package/dist/heart/awaiting/await-loader.js +91 -0
- package/dist/heart/awaiting/await-parser.js +149 -0
- package/dist/heart/awaiting/await-runtime-state.js +100 -0
- package/dist/heart/awaiting/await-scheduler.js +382 -0
- package/dist/heart/background-operations.js +281 -0
- package/dist/heart/bridges/manager.js +137 -17
- package/dist/heart/bridges/store.js +14 -2
- package/dist/heart/bundle-state.js +168 -0
- package/dist/heart/commitments.js +64 -18
- package/dist/heart/config-registry.js +331 -0
- package/dist/heart/config.js +142 -129
- package/dist/heart/context-loss-gauntlet.js +387 -0
- package/dist/heart/context-loss-sentinel.js +1157 -0
- package/dist/heart/core.js +2105 -574
- package/dist/heart/cross-chat-delivery.js +9 -22
- package/dist/heart/daemon/agent-config-check.js +451 -0
- package/dist/heart/daemon/agent-discovery.js +185 -3
- package/dist/heart/daemon/agent-service.js +542 -0
- package/dist/heart/daemon/agentic-repair.js +547 -0
- package/dist/heart/daemon/await-private-wake.js +59 -0
- package/dist/heart/daemon/bluebubbles-cli-integration.js +71 -0
- package/dist/heart/daemon/bluebubbles-health-diagnostics.js +122 -0
- package/dist/heart/daemon/bluebubbles-host-protocol.js +433 -0
- package/dist/heart/daemon/bluebubbles-host.js +273 -0
- package/dist/heart/daemon/boot-sync-probe.js +197 -0
- package/dist/heart/daemon/cadence.js +180 -0
- package/dist/heart/daemon/cli-defaults.js +854 -0
- package/dist/heart/daemon/cli-desk.js +322 -0
- package/dist/heart/daemon/cli-exec.js +8822 -0
- package/dist/heart/daemon/cli-help.js +716 -0
- package/dist/heart/daemon/cli-parse.js +2771 -0
- package/dist/heart/daemon/cli-render-doctor.js +57 -0
- package/dist/heart/daemon/cli-render.js +777 -0
- package/dist/heart/daemon/cli-types.js +8 -0
- package/dist/heart/daemon/connect-bay.js +323 -0
- package/dist/heart/daemon/container-credential-bootstrap.js +273 -0
- package/dist/heart/daemon/container-healthcheck.js +112 -0
- package/dist/heart/daemon/container-runtime.js +97 -0
- package/dist/heart/daemon/container-spec-auditor-main.js +170 -0
- package/dist/heart/daemon/container-spec-auditor.js +236 -0
- package/dist/heart/daemon/daemon-bootstrap-startup.js +115 -0
- package/dist/heart/daemon/daemon-cli.js +29 -2317
- package/dist/heart/daemon/daemon-entry.js +921 -11
- package/dist/heart/daemon/daemon-health.js +186 -0
- package/dist/heart/daemon/daemon-rollup.js +57 -0
- package/dist/heart/daemon/daemon-runtime-sync.js +88 -13
- package/dist/heart/daemon/daemon-tombstone.js +236 -0
- package/dist/heart/daemon/daemon.js +2073 -104
- package/dist/heart/daemon/dns-workflow.js +394 -0
- package/dist/heart/daemon/doctor-types.js +8 -0
- package/dist/heart/daemon/doctor.js +1755 -0
- package/dist/heart/daemon/freshness.js +345 -0
- package/dist/heart/daemon/habit-private-wake.js +61 -0
- package/dist/heart/daemon/health-monitor.js +142 -11
- package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
- package/dist/heart/daemon/hooks/bundle-meta.js +135 -1
- package/dist/heart/daemon/http-health-probe.js +80 -0
- package/dist/heart/daemon/human-command-screens.js +234 -0
- package/dist/heart/daemon/human-readiness.js +114 -0
- package/dist/heart/daemon/inner-status.js +78 -0
- package/dist/heart/daemon/interactive-repair.js +394 -0
- package/dist/heart/daemon/launchd.js +37 -8
- package/dist/heart/daemon/log-tailer.js +79 -10
- package/dist/heart/daemon/logs-prune.js +132 -0
- package/dist/heart/daemon/mcp-canary.js +524 -0
- package/dist/heart/daemon/message-router.js +65 -5
- package/dist/heart/daemon/migrate-to-desk.js +848 -0
- package/dist/heart/daemon/os-cron-deps.js +135 -0
- package/dist/heart/daemon/os-cron.js +22 -14
- package/dist/heart/daemon/ouro-bot-entry.js +4 -2
- package/dist/heart/daemon/ouro-entry.js +3 -1
- package/dist/heart/daemon/plugin-cli.js +432 -0
- package/dist/heart/daemon/process-manager.js +733 -61
- package/dist/heart/daemon/provider-discovery.js +137 -0
- package/dist/heart/daemon/provider-ping-progress.js +83 -0
- package/dist/heart/daemon/prunable-bundle.js +144 -0
- package/dist/heart/daemon/pulse.js +511 -0
- package/dist/heart/daemon/readiness-repair.js +365 -0
- package/dist/heart/daemon/run-hooks.js +2 -0
- package/dist/heart/daemon/runtime-logging.js +47 -14
- package/dist/heart/daemon/runtime-metadata.js +2 -30
- package/dist/heart/daemon/runtime-mode.js +13 -2
- package/dist/heart/daemon/safe-mode.js +161 -0
- package/dist/heart/daemon/sanctuary-acceptance-adapter.js +2609 -0
- package/dist/heart/daemon/sanctuary-acceptance-harness.js +1866 -0
- package/dist/heart/daemon/sanctuary-acceptance-marker.js +267 -0
- package/dist/heart/daemon/sanctuary-acceptance-scenarios.js +976 -0
- package/dist/heart/daemon/sanctuary-bundle-migration.js +728 -0
- package/dist/heart/daemon/sanctuary-package-management.js +103 -0
- package/dist/heart/daemon/sanctuary-scheduler-liveness.js +227 -0
- package/dist/heart/daemon/sanctuary-scheduler-origin.js +132 -0
- package/dist/heart/daemon/sense-manager.js +689 -48
- package/dist/heart/daemon/session-id-resolver.js +131 -0
- package/dist/heart/daemon/skill-management-installer.js +1 -1
- package/dist/heart/daemon/socket-client.js +180 -12
- package/dist/heart/daemon/stale-bundle-prune.js +113 -0
- package/dist/heart/daemon/startup-tui.js +339 -0
- package/dist/heart/daemon/supercronic-supervisor.js +282 -0
- package/dist/heart/daemon/task-scheduler.js +117 -39
- package/dist/heart/daemon/terminal-ui.js +499 -0
- package/dist/heart/daemon/thoughts.js +138 -54
- package/dist/heart/daemon/up-progress.js +366 -0
- package/dist/heart/daemon/vault-items.js +56 -0
- package/dist/heart/delegation.js +1 -4
- package/dist/heart/external-events/router.js +1414 -0
- package/dist/heart/frontend-approval-runtime.js +432 -0
- package/dist/heart/frontend-journal.js +215 -0
- package/dist/heart/frontend-session-service.js +237 -0
- package/dist/heart/frontend-socket-client.js +154 -0
- package/dist/heart/frontend-socket.js +400 -0
- package/dist/heart/habits/habit-cancel.js +810 -0
- package/dist/heart/habits/habit-lifecycle.js +1327 -0
- package/dist/heart/habits/habit-migration.js +194 -0
- package/dist/heart/habits/habit-parser.js +278 -0
- package/dist/heart/habits/habit-runtime-state.js +93 -0
- package/dist/heart/habits/habit-scheduler.js +653 -0
- package/dist/heart/habits/habit-session-summary.js +318 -0
- package/dist/heart/habits/habit-session.js +636 -0
- package/dist/heart/{daemon → hatch}/hatch-flow.js +55 -62
- package/dist/heart/{daemon → hatch}/hatch-specialist.js +6 -8
- package/dist/heart/{daemon → hatch}/specialist-prompt.js +12 -9
- package/dist/heart/{daemon → hatch}/specialist-tools.js +53 -18
- package/dist/heart/identity.js +184 -59
- package/dist/heart/kept-notes.js +289 -0
- package/dist/heart/kicks.js +1 -1
- package/dist/heart/machine-identity.js +161 -0
- package/dist/heart/mail-import-discovery.js +356 -0
- package/dist/heart/mailbox/mailbox-http-hooks.js +98 -0
- package/dist/heart/mailbox/mailbox-http-response.js +7 -0
- package/dist/heart/mailbox/mailbox-http-routes.js +398 -0
- package/dist/heart/mailbox/mailbox-http-static.js +103 -0
- package/dist/heart/mailbox/mailbox-http-transport.js +129 -0
- package/dist/heart/mailbox/mailbox-http.js +99 -0
- package/dist/heart/mailbox/mailbox-read.js +39 -0
- package/dist/heart/mailbox/mailbox-types.js +27 -0
- package/dist/heart/mailbox/mailbox-view.js +197 -0
- package/dist/heart/mailbox/readers/agent-machine.js +428 -0
- package/dist/heart/mailbox/readers/continuity-readers.js +329 -0
- package/dist/heart/mailbox/readers/mail.js +375 -0
- package/dist/heart/mailbox/readers/runtime-readers.js +823 -0
- package/dist/heart/mailbox/readers/sessions.js +231 -0
- package/dist/heart/mailbox/readers/shared.js +111 -0
- package/dist/heart/mcp/mcp-server.js +696 -0
- package/dist/heart/migrate-config.js +100 -0
- package/dist/heart/model-capabilities.js +11 -0
- package/dist/heart/orientation-frame.js +345 -0
- package/dist/heart/platform.js +81 -0
- package/dist/heart/primitives.js +1 -1
- package/dist/heart/private-runtime/decision-renderer.js +158 -0
- package/dist/heart/private-runtime/index.js +18 -0
- package/dist/heart/private-runtime/ledger.js +221 -0
- package/dist/heart/private-runtime/policy.js +252 -0
- package/dist/heart/private-runtime/types.js +2 -0
- package/dist/heart/progress-story.js +1 -1
- package/dist/heart/provider-attempt.js +137 -0
- package/dist/heart/provider-binding-resolver.js +273 -0
- package/dist/heart/provider-credentials.js +449 -0
- package/dist/heart/provider-failover.js +311 -0
- package/dist/heart/provider-models.js +96 -0
- package/dist/heart/provider-ping.js +265 -0
- package/dist/heart/provider-readiness-cache.js +119 -0
- package/dist/heart/provider-visibility.js +188 -0
- package/dist/heart/providers/anthropic-token.js +131 -0
- package/dist/heart/providers/anthropic.js +173 -60
- package/dist/heart/providers/azure.js +23 -11
- package/dist/heart/providers/error-classification.js +127 -0
- package/dist/heart/providers/github-copilot.js +34 -38
- package/dist/heart/providers/minimax-vlm.js +189 -0
- package/dist/heart/providers/minimax.js +26 -8
- package/dist/heart/providers/openai-codex-token.js +349 -0
- package/dist/heart/providers/openai-codex.js +55 -40
- package/dist/heart/providers/openai-compatible.js +177 -0
- package/dist/heart/run-ledger.js +247 -0
- package/dist/heart/runtime-capability-check.js +170 -0
- package/dist/heart/runtime-credentials.js +607 -0
- package/dist/heart/runtime-cwd.js +87 -0
- package/dist/heart/sense-truth.js +22 -4
- package/dist/heart/session-activity.js +92 -24
- package/dist/heart/session-events.js +1433 -0
- package/dist/heart/session-playback-cli-main.js +5 -0
- package/dist/heart/session-playback-cli.js +36 -0
- package/dist/heart/session-playback.js +231 -0
- package/dist/heart/session-redaction-repair-cli-main.js +31 -0
- package/dist/heart/session-redaction-repair.js +543 -0
- package/dist/heart/session-stats-cli-main.js +5 -0
- package/dist/heart/session-stats.js +182 -0
- package/dist/heart/session-transcript.js +133 -0
- package/dist/heart/start-of-turn-packet.js +372 -0
- package/dist/heart/steward-policy.js +302 -0
- package/dist/heart/streaming.js +604 -207
- package/dist/heart/structured-output.js +196 -0
- package/dist/heart/sync-classification.js +176 -0
- package/dist/heart/sync.js +449 -0
- package/dist/heart/target-resolution.js +11 -7
- package/dist/heart/tempo.js +93 -0
- package/dist/heart/temporal-view.js +41 -0
- package/dist/heart/timeouts.js +101 -0
- package/dist/heart/tool-activity-callbacks.js +59 -0
- package/dist/heart/tool-approval.js +342 -0
- package/dist/heart/tool-description.js +155 -0
- package/dist/heart/tool-friction.js +55 -0
- package/dist/heart/tool-loop.js +200 -0
- package/dist/heart/turn-context.js +482 -0
- package/dist/heart/turn-execution-lease.js +30 -0
- package/dist/heart/{daemon → versioning}/ouro-bot-global-installer.js +6 -5
- package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
- package/dist/heart/versioning/ouro-path-installer.js +432 -0
- package/dist/heart/versioning/ouro-recovery-launcher.js +76 -0
- package/dist/heart/versioning/ouro-version-manager.js +409 -0
- package/dist/heart/{daemon → versioning}/staged-restart.js +40 -8
- package/dist/heart/{daemon → versioning}/update-checker.js +6 -1
- package/dist/heart/versioning/update-hooks.js +154 -0
- package/dist/heart/versioning/version-intent.js +114 -0
- package/dist/heart/work-card.js +380 -0
- package/dist/mailbox-ui/assets/index-Du_9G9WO.css +1 -0
- package/dist/mailbox-ui/assets/index-J8zDwHmE.js +1 -0
- package/dist/mailbox-ui/assets/vendor-CcN1XpQ9.js +61 -0
- package/dist/mailbox-ui/index.html +16 -0
- package/dist/mailroom/attention.js +167 -0
- package/dist/mailroom/autonomy.js +209 -0
- package/dist/mailroom/blob-store.js +889 -0
- package/dist/mailroom/body-cache.js +61 -0
- package/dist/mailroom/cache-sync-cli.js +58 -0
- package/dist/mailroom/core.js +803 -0
- package/dist/mailroom/entry.js +160 -0
- package/dist/mailroom/file-store.js +568 -0
- package/dist/mailroom/hosted-cache-sync.js +384 -0
- package/dist/mailroom/mbox-import.js +393 -0
- package/dist/mailroom/migration.js +164 -0
- package/dist/mailroom/outbound.js +380 -0
- package/dist/mailroom/policy.js +263 -0
- package/dist/mailroom/reader.js +292 -0
- package/dist/mailroom/search-cache.js +513 -0
- package/dist/mailroom/search-relevance.js +319 -0
- package/dist/mailroom/smtp-ingress.js +176 -0
- package/dist/mailroom/source-state.js +176 -0
- package/dist/mailroom/thread.js +109 -0
- package/dist/mailroom/travel-extract.js +89 -0
- package/dist/mind/bundle-manifest.js +24 -2
- package/dist/mind/context.js +279 -111
- package/dist/mind/desk-section.js +362 -0
- package/dist/mind/diary-integrity.js +60 -0
- package/dist/mind/{memory.js → diary.js} +68 -77
- package/dist/mind/embedding-provider.js +60 -0
- package/dist/mind/file-state.js +179 -0
- package/dist/mind/{associative-recall.js → note-search.js} +47 -58
- package/dist/mind/obligation-steering.js +227 -0
- package/dist/mind/pending.js +34 -8
- package/dist/mind/prompt-budget.js +479 -0
- package/dist/mind/prompt-refresh.js +3 -2
- package/dist/mind/prompt.js +1059 -187
- package/dist/mind/provenance-trust.js +26 -0
- package/dist/mind/record-paths.js +312 -0
- package/dist/mind/scrutiny.js +173 -0
- package/dist/mind/session-transaction.js +564 -0
- package/dist/nerves/cli-logging.js +7 -1
- package/dist/nerves/coverage/audit-rules.js +15 -6
- package/dist/nerves/coverage/audit.js +28 -2
- package/dist/nerves/coverage/cli.js +1 -1
- package/dist/nerves/coverage/contract.js +5 -5
- package/dist/nerves/coverage/file-completeness.js +139 -5
- package/dist/nerves/coverage/run-artifacts.js +55 -35
- package/dist/nerves/coverage/source-scanner.js +4 -4
- package/dist/nerves/event-buffer.js +111 -0
- package/dist/nerves/index.js +293 -9
- package/dist/nerves/observation.js +20 -0
- package/dist/nerves/redact.js +79 -0
- package/dist/nerves/review/cli-main.js +5 -0
- package/dist/nerves/review/cli.js +156 -0
- package/dist/nerves/review/core.js +159 -0
- package/dist/nerves/runtime.js +17 -1
- package/dist/repertoire/ado-client.js +15 -56
- package/dist/repertoire/ado-semantic.js +16 -10
- package/dist/repertoire/api-client.js +97 -0
- package/dist/repertoire/bitwarden-store.js +1045 -0
- package/dist/repertoire/bundle-templates.js +71 -0
- package/dist/repertoire/bw-installer.js +180 -0
- package/dist/repertoire/coding/codex-jsonl.js +64 -0
- package/dist/repertoire/coding/context-pack.js +331 -0
- package/dist/repertoire/coding/feedback.js +218 -30
- package/dist/repertoire/coding/index.js +15 -3
- package/dist/repertoire/coding/manager.js +166 -10
- package/dist/repertoire/coding/spawner.js +58 -11
- package/dist/repertoire/coding/tools.js +242 -14
- package/dist/repertoire/coding/workbench-client.js +272 -0
- package/dist/repertoire/coding/workbench-manager.js +346 -0
- package/dist/repertoire/commerce-errors.js +109 -0
- package/dist/repertoire/commerce-self-test.js +156 -0
- package/dist/repertoire/credential-access.js +178 -0
- package/dist/repertoire/desk/classifier.js +362 -0
- package/dist/repertoire/duffel-client.js +185 -0
- package/dist/repertoire/github-client.js +14 -55
- package/dist/repertoire/graph-client.js +11 -52
- package/dist/repertoire/guardrails.js +811 -18
- package/dist/repertoire/mcp-client.js +44 -3
- package/dist/repertoire/mcp-manager.js +331 -27
- package/dist/repertoire/mcp-tools.js +83 -0
- package/dist/repertoire/plugin-mcp.js +175 -0
- package/dist/repertoire/plugins.js +253 -0
- package/dist/repertoire/relationship-authorization.js +194 -0
- package/dist/repertoire/shell-sessions.js +133 -0
- package/dist/repertoire/skills.js +48 -4
- package/dist/repertoire/stripe-client.js +131 -0
- package/dist/repertoire/tool-arguments.js +148 -0
- package/dist/repertoire/tool-results.js +29 -0
- package/dist/repertoire/tools-a2a.js +699 -0
- package/dist/repertoire/tools-attachments.js +322 -0
- package/dist/repertoire/tools-awaiting.js +575 -0
- package/dist/repertoire/tools-base.js +82 -1139
- package/dist/repertoire/tools-bluebubbles.js +2 -0
- package/dist/repertoire/tools-bridge.js +144 -0
- package/dist/repertoire/tools-bundle.js +993 -0
- package/dist/repertoire/tools-commerce.js +253 -0
- package/dist/repertoire/tools-config.js +186 -0
- package/dist/repertoire/tools-continuity.js +575 -0
- package/dist/repertoire/tools-credential.js +383 -0
- package/dist/repertoire/tools-evolution.js +527 -0
- package/dist/repertoire/tools-files.js +344 -0
- package/dist/repertoire/tools-flight.js +290 -0
- package/dist/repertoire/tools-flow.js +119 -0
- package/dist/repertoire/tools-github.js +3 -8
- package/dist/repertoire/tools-habits.js +103 -0
- package/dist/repertoire/tools-mail.js +1828 -0
- package/dist/repertoire/tools-notes.js +485 -0
- package/dist/repertoire/tools-obligations.js +182 -0
- package/dist/repertoire/tools-orientation.js +31 -0
- package/dist/repertoire/tools-record.js +482 -0
- package/dist/repertoire/tools-rsvp.js +139 -0
- package/dist/repertoire/tools-runtime.js +150 -0
- package/dist/repertoire/tools-session.js +1108 -0
- package/dist/repertoire/tools-shell.js +133 -0
- package/dist/repertoire/tools-steward-policy.js +95 -0
- package/dist/repertoire/tools-stripe.js +224 -0
- package/dist/repertoire/tools-surface.js +369 -0
- package/dist/repertoire/tools-teams.js +12 -39
- package/dist/repertoire/tools-telegram-contacts.js +37 -0
- package/dist/repertoire/tools-travel.js +125 -0
- package/dist/repertoire/tools-trip.js +982 -0
- package/dist/repertoire/tools-unraid.js +484 -0
- package/dist/repertoire/tools-user-profile.js +146 -0
- package/dist/repertoire/tools-vault.js +40 -0
- package/dist/repertoire/tools-voice.js +145 -0
- package/dist/repertoire/tools.js +377 -80
- package/dist/repertoire/travel-api-client.js +360 -0
- package/dist/repertoire/unraid-client.js +155 -0
- package/dist/repertoire/unraid-restart.js +212 -0
- package/dist/repertoire/user-profile.js +131 -0
- package/dist/repertoire/vault-setup.js +246 -0
- package/dist/repertoire/vault-unlock.js +628 -0
- package/dist/rsvp/aisleplanner-client.js +354 -0
- package/dist/rsvp/cli.js +926 -0
- package/dist/rsvp/config.js +327 -0
- package/dist/rsvp/cutover.js +433 -0
- package/dist/rsvp/diagnostics.js +232 -0
- package/dist/rsvp/diff-renderer.js +176 -0
- package/dist/rsvp/habit-policy.js +110 -0
- package/dist/rsvp/habit-stage.js +123 -0
- package/dist/rsvp/incident-bundle.js +97 -0
- package/dist/rsvp/migration.js +204 -0
- package/dist/rsvp/native-habit-runner.js +630 -0
- package/dist/rsvp/outbound-state.js +628 -0
- package/dist/rsvp/query.js +118 -0
- package/dist/rsvp/replay.js +233 -0
- package/dist/rsvp/snapshot.js +232 -0
- package/dist/rsvp/spend-ledger.js +175 -0
- package/dist/scripts/claude-code-hook.js +41 -0
- package/dist/scripts/claude-code-stop-hook.js +47 -0
- package/dist/senses/a2a-entry.js +115 -0
- package/dist/senses/acp-server.js +386 -0
- package/dist/senses/attention-queue.js +186 -0
- package/dist/senses/await-turn-message.js +58 -0
- package/dist/senses/bluebubbles/active-turns.js +216 -0
- package/dist/senses/bluebubbles/attachment-cache.js +53 -0
- package/dist/senses/bluebubbles/attachment-download.js +137 -0
- package/dist/senses/{bluebubbles-client.js → bluebubbles/client.js} +355 -40
- package/dist/senses/bluebubbles/context-packet.js +207 -0
- package/dist/senses/bluebubbles/context-smoke.js +144 -0
- package/dist/senses/bluebubbles/entry.js +90 -0
- package/dist/senses/{bluebubbles-inbound-log.js → bluebubbles/inbound-log.js} +21 -3
- package/dist/senses/bluebubbles/index.js +3839 -0
- package/dist/senses/bluebubbles/latest-turn.js +311 -0
- package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +121 -71
- package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +159 -28
- package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +24 -13
- package/dist/senses/bluebubbles/outbound-state.js +308 -0
- package/dist/senses/bluebubbles/processed-log.js +133 -0
- package/dist/senses/bluebubbles/reaction-policy.js +47 -0
- package/dist/senses/bluebubbles/replay.js +284 -0
- package/dist/senses/{bluebubbles-runtime-state.js → bluebubbles/runtime-state.js} +30 -2
- package/dist/senses/bluebubbles/semantic-receipts.js +1986 -0
- package/dist/senses/{bluebubbles-session-cleanup.js → bluebubbles/session-cleanup.js} +1 -1
- package/dist/senses/bluebubbles/webhook-registration.js +228 -0
- package/dist/senses/bluebubbles-meta-guard.js +39 -0
- package/dist/senses/cli/bracketed-paste.js +82 -0
- package/dist/senses/cli/image-paste.js +287 -0
- package/dist/senses/cli/image-ref-navigation.js +75 -0
- package/dist/senses/cli/ink-app.js +156 -0
- package/dist/senses/cli/inline-diff.js +64 -0
- package/dist/senses/cli/input-keys.js +174 -0
- package/dist/senses/cli/kill-ring.js +86 -0
- package/dist/senses/cli/message-list.js +51 -0
- package/dist/senses/cli/ouro-tui.js +607 -0
- package/dist/senses/cli/spinner-imperative.js +135 -0
- package/dist/senses/cli/spinner.js +101 -0
- package/dist/senses/cli/status-line.js +60 -0
- package/dist/senses/cli/streaming-markdown.js +526 -0
- package/dist/senses/cli/tool-display.js +85 -0
- package/dist/senses/cli/tool-render.js +85 -0
- package/dist/senses/cli/tui-store.js +241 -0
- package/dist/senses/cli/virtual-list.js +35 -0
- package/dist/senses/cli-entry.js +60 -8
- package/dist/senses/cli.js +600 -317
- package/dist/senses/commands.js +66 -3
- package/dist/senses/context-packet-ledger.js +371 -0
- package/dist/senses/context-packets.js +154 -0
- package/dist/senses/habit-lifecycle-guard.js +24 -0
- package/dist/senses/habit-turn-message.js +160 -0
- package/dist/senses/ingress-evidence.js +2 -0
- package/dist/senses/mail-entry.js +66 -0
- package/dist/senses/mail.js +524 -0
- package/dist/senses/pipeline.js +1115 -204
- package/dist/senses/private-runtime-worker.js +859 -0
- package/dist/senses/private-runtime.js +1496 -0
- package/dist/senses/proactive-content-guard.js +51 -0
- package/dist/senses/sanctuary-download-credit-presentation.js +31 -0
- package/dist/senses/sanctuary-full-visibility-contract.js +302 -0
- package/dist/senses/sanctuary-grounding.js +118 -0
- package/dist/senses/sanctuary-health-acceptance-probe-entry.js +12 -0
- package/dist/senses/sanctuary-health-acceptance-probe.js +774 -0
- package/dist/senses/sanctuary-health-runner.js +101 -0
- package/dist/senses/sanctuary-health.js +408 -0
- package/dist/senses/sanctuary-install-state-contract.js +126 -0
- package/dist/senses/sanctuary-interactive-control.js +306 -0
- package/dist/senses/sanctuary-media-catalog-contract.js +235 -0
- package/dist/senses/sanctuary-media-optimization.js +514 -0
- package/dist/senses/sanctuary-runtime.js +338 -0
- package/dist/senses/sanctuary-sab.js +85 -0
- package/dist/senses/sanctuary-storage-optimization-contract.js +32 -0
- package/dist/senses/shared-turn.js +756 -0
- package/dist/senses/surface-tool.js +109 -0
- package/dist/senses/teams-entry.js +60 -8
- package/dist/senses/teams.js +515 -217
- package/dist/senses/telegram-admission.js +711 -0
- package/dist/senses/telegram-approval-runtime.js +566 -0
- package/dist/senses/telegram-attachments.js +182 -0
- package/dist/senses/telegram-audit-ledger.js +220 -0
- package/dist/senses/telegram-client.js +1677 -0
- package/dist/senses/telegram-effect-adapter.js +859 -0
- package/dist/senses/telegram-entry.js +83 -0
- package/dist/senses/telegram.js +2045 -0
- package/dist/senses/trust-gate.js +104 -9
- package/dist/senses/voice/audio-playback.js +237 -0
- package/dist/senses/voice/audio-routing.js +119 -0
- package/dist/senses/voice/elevenlabs.js +202 -0
- package/dist/senses/voice/floor-control.js +431 -0
- package/dist/senses/voice/floor-controller.js +115 -0
- package/dist/senses/voice/golden-path.js +116 -0
- package/dist/senses/voice/index.js +29 -0
- package/dist/senses/voice/meeting.js +113 -0
- package/dist/senses/voice/outbound.js +190 -0
- package/dist/senses/voice/phone.js +33 -0
- package/dist/senses/voice/playback.js +139 -0
- package/dist/senses/voice/realtime-eval.js +496 -0
- package/dist/senses/voice/realtime-trace.js +531 -0
- package/dist/senses/voice/transcript.js +70 -0
- package/dist/senses/voice/turn.js +191 -0
- package/dist/senses/voice/twilio-phone-runtime.js +807 -0
- package/dist/senses/voice/twilio-phone.js +5081 -0
- package/dist/senses/voice/types.js +2 -0
- package/dist/senses/voice/whisper.js +161 -0
- package/dist/senses/voice-entry.js +81 -0
- package/dist/senses/voice-realtime-eval-command.js +99 -0
- package/dist/senses/voice-realtime-eval-entry.js +21 -0
- package/dist/senses/voice-twilio-entry.js +87 -0
- package/dist/trips/core.js +138 -0
- package/dist/trips/store.js +265 -0
- package/dist/util/frontmatter.js +69 -0
- package/npm-shrinkwrap.json +8138 -0
- package/package.json +72 -13
- package/skills/agent-commerce.md +113 -0
- package/skills/browser-navigation.md +117 -0
- package/skills/commerce-setup-guide.md +116 -0
- package/skills/commerce-setup.md +84 -0
- package/skills/configure-dev-tools.md +99 -0
- package/skills/travel-planning.md +138 -0
- package/dist/heart/daemon/auth-flow.js +0 -430
- package/dist/heart/daemon/ouro-path-installer.js +0 -260
- package/dist/heart/daemon/ouro-version-manager.js +0 -164
- package/dist/heart/daemon/update-hooks.js +0 -138
- package/dist/heart/obligations.js +0 -141
- package/dist/heart/safe-workspace.js +0 -228
- package/dist/heart/session-recall.js +0 -116
- package/dist/mind/friends/channel.js +0 -84
- package/dist/mind/friends/group-context.js +0 -144
- package/dist/mind/friends/resolver.js +0 -84
- package/dist/mind/friends/store-file.js +0 -190
- package/dist/mind/friends/store.js +0 -4
- package/dist/mind/friends/tokens.js +0 -26
- package/dist/mind/friends/trust-explanation.js +0 -74
- package/dist/mind/friends/types.js +0 -29
- package/dist/repertoire/tasks/board.js +0 -134
- package/dist/repertoire/tasks/index.js +0 -224
- package/dist/repertoire/tasks/lifecycle.js +0 -80
- package/dist/repertoire/tasks/middleware.js +0 -65
- package/dist/repertoire/tasks/parser.js +0 -173
- package/dist/repertoire/tasks/scanner.js +0 -132
- package/dist/repertoire/tasks/transitions.js +0 -144
- package/dist/senses/bluebubbles-entry.js +0 -13
- package/dist/senses/bluebubbles.js +0 -1181
- package/dist/senses/debug-activity.js +0 -154
- package/dist/senses/inner-dialog-worker.js +0 -90
- package/dist/senses/inner-dialog.js +0 -525
- package/subagents/README.md +0 -7
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
- /package/dist/{repertoire/tasks/types.js → heart/attachments/sources/adapter.js} +0 -0
- /package/dist/heart/{daemon → hatch}/hatch-animation.js +0 -0
- /package/dist/heart/{daemon → hatch}/specialist-orchestrator.js +0 -0
- /package/dist/heart/{daemon → versioning}/ouro-uti.js +0 -0
- /package/dist/heart/{daemon → versioning}/wrapper-publish-guard.js +0 -0
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.proveSanctuaryAttemptedRecoveryWithoutRetry = proveSanctuaryAttemptedRecoveryWithoutRetry;
|
|
37
|
+
exports.executeSanctuaryInteractiveEngine = executeSanctuaryInteractiveEngine;
|
|
38
|
+
exports.createSanctuaryInteractiveControl = createSanctuaryInteractiveControl;
|
|
39
|
+
exports.sanctuaryInteractiveControlReady = sanctuaryInteractiveControlReady;
|
|
40
|
+
const node_crypto_1 = require("node:crypto");
|
|
41
|
+
const node_fs_1 = require("node:fs");
|
|
42
|
+
const node_net_1 = require("node:net");
|
|
43
|
+
const path = __importStar(require("node:path"));
|
|
44
|
+
const approval_store_1 = require("../heart/approval-store");
|
|
45
|
+
const tool_approval_1 = require("../heart/tool-approval");
|
|
46
|
+
const runtime_1 = require("../nerves/runtime");
|
|
47
|
+
const telegram_client_1 = require("./telegram-client");
|
|
48
|
+
const SHA256 = /^[0-9a-f]{64}$/u;
|
|
49
|
+
const MAX_CONTROL_REQUEST = 16 * 1024;
|
|
50
|
+
function object(value, label) {
|
|
51
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
52
|
+
throw new Error(`${label} must be an object`);
|
|
53
|
+
return value;
|
|
54
|
+
}
|
|
55
|
+
function exactKeys(value, keys, label) {
|
|
56
|
+
if (JSON.stringify(Object.keys(value).sort()) !== JSON.stringify([...keys].sort()))
|
|
57
|
+
throw new Error(`${label} shape is invalid`);
|
|
58
|
+
}
|
|
59
|
+
function sha256(value) {
|
|
60
|
+
return (0, node_crypto_1.createHash)("sha256").update(value, "utf8").digest("hex");
|
|
61
|
+
}
|
|
62
|
+
function exactApproval(projections) {
|
|
63
|
+
const matches = projections.filter(({ approval }) => approval.toolName === "unraid_restart_container" && approval.arguments.container === "calibre-web");
|
|
64
|
+
if (matches.length !== 1)
|
|
65
|
+
throw new Error("interactive production approval is absent or ambiguous");
|
|
66
|
+
return matches[0];
|
|
67
|
+
}
|
|
68
|
+
function exactPending(records, approvalId) {
|
|
69
|
+
const validCallback = (value) => typeof value === "string" && Buffer.byteLength(value) >= 1 && Buffer.byteLength(value) <= 64;
|
|
70
|
+
const matches = records.filter((record) => record.approvalId === approvalId && record.deliveryState === "bound" && record.messageId !== null
|
|
71
|
+
&& validCallback(record.approveCallbackData) && validCallback(record.denyCallbackData));
|
|
72
|
+
if (matches.length !== 1)
|
|
73
|
+
throw new Error("interactive production pending approval is absent or ambiguous");
|
|
74
|
+
return matches[0];
|
|
75
|
+
}
|
|
76
|
+
function exactTerminalTombstone(records, approvalId) {
|
|
77
|
+
const validCallback = (value) => typeof value === "string" && Buffer.byteLength(value) >= 1 && Buffer.byteLength(value) <= 64;
|
|
78
|
+
const matches = records.filter((record) => record.approvalId === approvalId && record.deliveryState === "terminal_tombstone" && record.messageId !== null
|
|
79
|
+
&& validCallback(record.approveCallbackData) && validCallback(record.denyCallbackData)
|
|
80
|
+
&& record.expiryObservation?.schemaVersion === "telegram-approval-expiry-observation-v1"
|
|
81
|
+
&& record.expiryObservation.deadlineAt === record.expiresAt && Number.isSafeInteger(record.expiryObservation.observedAt)
|
|
82
|
+
&& record.expiryObservation.observedAt >= record.expiresAt && typeof record.expiryObservation.evidenceMac === "string" && SHA256.test(record.expiryObservation.evidenceMac)
|
|
83
|
+
&& Number.isSafeInteger(record.terminalizedAt) && Number(record.terminalizedAt) >= record.expiryObservation.observedAt);
|
|
84
|
+
if (matches.length !== 1)
|
|
85
|
+
throw new Error("interactive production terminal tombstone is absent or ambiguous");
|
|
86
|
+
return matches[0];
|
|
87
|
+
}
|
|
88
|
+
function pendingDigest(record) {
|
|
89
|
+
return sha256(JSON.stringify({ approvalId: record.approvalId, messageId: record.messageId, deliveryState: record.deliveryState, approveCallbackData: record.approveCallbackData, denyCallbackData: record.denyCallbackData, expiresAt: record.expiresAt }));
|
|
90
|
+
}
|
|
91
|
+
function proveSanctuaryAttemptedRecoveryWithoutRetry(agentRoot, scenarioHandleDigest, approval) {
|
|
92
|
+
if (!SHA256.test(scenarioHandleDigest))
|
|
93
|
+
throw new Error("attempted recovery scenario is invalid");
|
|
94
|
+
const databaseRoot = path.join(agentRoot, "state", "acceptance", "attempted-recovery-probes");
|
|
95
|
+
(0, node_fs_1.mkdirSync)(databaseRoot, { recursive: true, mode: 0o700 });
|
|
96
|
+
const databasePath = path.join(databaseRoot, `${scenarioHandleDigest}.sqlite`);
|
|
97
|
+
if ((0, node_fs_1.existsSync)(databasePath))
|
|
98
|
+
throw new Error("attempted recovery proof requires inspect-before-retry");
|
|
99
|
+
const instant = new Date("2026-08-21T00:00:00.000Z");
|
|
100
|
+
const first = (0, approval_store_1.openApprovalStore)({ databasePath, now: () => instant });
|
|
101
|
+
const ownerId = "acceptance-attempted-recovery";
|
|
102
|
+
const toolCallId = `acceptance-${approval.toolCallId}`;
|
|
103
|
+
const frozenAssistantMessage = structuredClone(approval.frozenAssistantMessage);
|
|
104
|
+
const toolCalls = frozenAssistantMessage.tool_calls;
|
|
105
|
+
if (!Array.isArray(toolCalls) || toolCalls.length !== 1 || !toolCalls[0] || typeof toolCalls[0] !== "object" || Array.isArray(toolCalls[0])) {
|
|
106
|
+
first.close();
|
|
107
|
+
throw new Error("attempted recovery frozen tool call is invalid");
|
|
108
|
+
}
|
|
109
|
+
toolCalls[0].id = toolCallId;
|
|
110
|
+
const prepared = first.prepare({
|
|
111
|
+
toolCallId, toolName: approval.toolName, arguments: approval.arguments,
|
|
112
|
+
schemaDigest: approval.schemaDigest, toolDigest: approval.toolDigest, policyDigest: approval.policyDigest, policyId: approval.policyId,
|
|
113
|
+
sessionKey: "acceptance:attempted-recovery", sessionPath: path.join(databaseRoot, `${scenarioHandleDigest}.session.json`),
|
|
114
|
+
baseSessionRevision: approval.baseSessionRevision, checkpointDigest: approval.checkpointDigest,
|
|
115
|
+
requesterId: "acceptance-probe", transport: "telegram", transportUserId: "acceptance-probe", transportChatId: "acceptance-probe",
|
|
116
|
+
expiresAt: "2099-01-01T00:00:00.000Z", frozenAssistantMessage,
|
|
117
|
+
});
|
|
118
|
+
first.activate({ approvalId: prepared.record.approvalId, checkpointDigest: prepared.record.checkpointDigest, suspendedSessionRevision: approval.suspendedSessionRevision });
|
|
119
|
+
first.bindPrompt({ approvalId: prepared.record.approvalId, transport: "telegram", transportChatId: "acceptance-probe", transportMessageId: "acceptance-message" });
|
|
120
|
+
const claimed = first.decide({
|
|
121
|
+
approvalId: prepared.record.approvalId, decisionToken: prepared.decisionToken, decision: "approve", requesterId: "acceptance-probe",
|
|
122
|
+
transport: "telegram", transportUserId: "acceptance-probe", transportChatId: "acceptance-probe", transportMessageId: "acceptance-message",
|
|
123
|
+
sessionKey: "acceptance:attempted-recovery", ownerId,
|
|
124
|
+
});
|
|
125
|
+
const attempted = first.markAttempted({ approvalId: claimed.approvalId, ownerId, epoch: claimed.epoch });
|
|
126
|
+
first.close();
|
|
127
|
+
const attemptedRecordDigest = sha256(JSON.stringify(attempted));
|
|
128
|
+
const reopened = (0, approval_store_1.openApprovalStore)({ databasePath, now: () => instant });
|
|
129
|
+
const durableAttempted = reopened.read(attempted.approvalId);
|
|
130
|
+
if (!durableAttempted || durableAttempted.state !== "attempted") {
|
|
131
|
+
reopened.close();
|
|
132
|
+
throw new Error("attempted recovery record was not durable across reopen");
|
|
133
|
+
}
|
|
134
|
+
const recovered = (0, tool_approval_1.recoverAttemptedApproval)({ approvalStore: reopened, approvalId: durableAttempted.approvalId });
|
|
135
|
+
let retryCount = 0;
|
|
136
|
+
try {
|
|
137
|
+
(0, tool_approval_1.recoverAttemptedApproval)({ approvalStore: reopened, approvalId: durableAttempted.approvalId });
|
|
138
|
+
retryCount += 1;
|
|
139
|
+
}
|
|
140
|
+
catch { /* expected */ }
|
|
141
|
+
reopened.close();
|
|
142
|
+
return { observed: recovered.state === "attempted_indeterminate", retryCount, reopened: true, attemptedRecordDigest, recoveredRecordDigest: sha256(JSON.stringify(recovered)) };
|
|
143
|
+
}
|
|
144
|
+
async function executeSanctuaryInteractiveEngine(raw, deps) {
|
|
145
|
+
const payload = object(raw, "interactive runtime payload");
|
|
146
|
+
exactKeys(payload, ["operation", "label", "scenarioHandleDigest"], "interactive runtime payload");
|
|
147
|
+
const operation = payload.operation;
|
|
148
|
+
const label = payload.label;
|
|
149
|
+
const scenarioHandleDigest = payload.scenarioHandleDigest;
|
|
150
|
+
if (typeof scenarioHandleDigest !== "string" || !SHA256.test(scenarioHandleDigest)
|
|
151
|
+
|| !["unit-16k-timeout-stale", "unit-16l-duplicate-callback", "unit-16m-restart-continuation"].includes(label)
|
|
152
|
+
|| !["drive_timeout_stale", "drive_duplicate_callbacks", "prepare_restart_continuation", "reconcile_restart_continuation"].includes(String(operation))
|
|
153
|
+
|| (operation === "drive_timeout_stale") !== (label === "unit-16k-timeout-stale")
|
|
154
|
+
|| (operation === "drive_duplicate_callbacks") !== (label === "unit-16l-duplicate-callback"))
|
|
155
|
+
throw new Error("interactive runtime operation binding is invalid");
|
|
156
|
+
const before = exactApproval(deps.readApprovals(scenarioHandleDigest));
|
|
157
|
+
if (!before.approval.suspendedSessionRevision)
|
|
158
|
+
throw new Error("interactive production approval checkpoint is unavailable");
|
|
159
|
+
if (operation === "drive_timeout_stale") {
|
|
160
|
+
if (before.approval.state === "proposed") {
|
|
161
|
+
exactPending(deps.readPending(), before.approval.approvalId);
|
|
162
|
+
return { state: "waiting" };
|
|
163
|
+
}
|
|
164
|
+
if (before.approval.state !== "expired" || before.approval.epoch !== 0)
|
|
165
|
+
throw new Error("timeout stale approval is not expired without a claim");
|
|
166
|
+
const captured = exactTerminalTombstone(deps.readPending(), before.approval.approvalId);
|
|
167
|
+
const session = await deps.createSession();
|
|
168
|
+
try {
|
|
169
|
+
const queryId = (0, node_crypto_1.randomBytes)(18).toString("base64url");
|
|
170
|
+
const result = await session.handle({ callbackData: captured.approveCallbackData, queryId, messageId: captured.messageId });
|
|
171
|
+
const after = exactApproval(deps.readApprovals(scenarioHandleDigest));
|
|
172
|
+
const promptTerminal = !session.pendingApprovalIds().includes(before.approval.approvalId);
|
|
173
|
+
if (!result.handled || result.accepted || result.reason !== "stale_callback" || after.approval.state !== "expired" || after.approval.epoch !== 0 || !promptTerminal) {
|
|
174
|
+
throw new Error("timeout stale callback proof failed");
|
|
175
|
+
}
|
|
176
|
+
return {
|
|
177
|
+
schemaVersion: "sanctuary-timeout-stale-driver-receipt-v1", phase: "complete", label, scenarioHandleDigest,
|
|
178
|
+
approvalIdDigest: sha256(before.approval.approvalId), checkpointDigest: before.approval.checkpointDigest,
|
|
179
|
+
suspendedSessionRevisionDigest: sha256(before.approval.suspendedSessionRevision), approvalEpochBefore: before.approval.epoch,
|
|
180
|
+
callbackAttempts: 1, distinctQueryCount: 1, callbackDataDigest: sha256(captured.approveCallbackData),
|
|
181
|
+
settledCount: 1, claimCount: 0, mutationCount: 0, staleAcknowledged: true, promptTerminal,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
finally {
|
|
185
|
+
session.close();
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
if (before.approval.state !== "proposed")
|
|
189
|
+
throw new Error("interactive production approval is not currently proposed");
|
|
190
|
+
const pending = exactPending(deps.readPending(), before.approval.approvalId);
|
|
191
|
+
const common = { approvalIdDigest: sha256(before.approval.approvalId), checkpointDigest: before.approval.checkpointDigest, suspendedSessionRevisionDigest: sha256(before.approval.suspendedSessionRevision), approvalEpochBefore: before.approval.epoch };
|
|
192
|
+
if (operation === "prepare_restart_continuation") {
|
|
193
|
+
const recovery = deps.proveIndeterminateRecovery(before.approval, scenarioHandleDigest);
|
|
194
|
+
if (!recovery.observed || recovery.retryCount !== 0 || !recovery.reopened
|
|
195
|
+
|| !SHA256.test(recovery.attemptedRecordDigest) || !SHA256.test(recovery.recoveredRecordDigest)
|
|
196
|
+
|| recovery.attemptedRecordDigest === recovery.recoveredRecordDigest)
|
|
197
|
+
throw new Error("isolated attempted recovery proof failed");
|
|
198
|
+
return {
|
|
199
|
+
schemaVersion: "sanctuary-interactive-driver-receipt-v2", phase: "prepared", label, scenarioHandleDigest, ...common,
|
|
200
|
+
pendingDigestBefore: pendingDigest(pending), indeterminateRecoveryObserved: true,
|
|
201
|
+
attemptedRecoveryReopened: true, attemptedRecordDigest: recovery.attemptedRecordDigest, recoveredRecordDigest: recovery.recoveredRecordDigest,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
const session = await deps.createSession();
|
|
205
|
+
try {
|
|
206
|
+
if (operation === "drive_duplicate_callbacks") {
|
|
207
|
+
const queryIds = [(0, node_crypto_1.randomBytes)(18).toString("base64url"), (0, node_crypto_1.randomBytes)(18).toString("base64url")];
|
|
208
|
+
let arrivals = 0;
|
|
209
|
+
let release;
|
|
210
|
+
const barrier = new Promise((resolve) => { release = resolve; });
|
|
211
|
+
const invoke = async (queryId) => { arrivals += 1; if (arrivals === 2)
|
|
212
|
+
release(); await barrier; return session.handle({ callbackData: pending.approveCallbackData, queryId, messageId: pending.messageId }); };
|
|
213
|
+
const results = await Promise.all(queryIds.map(invoke));
|
|
214
|
+
const after = exactApproval(deps.readApprovals(scenarioHandleDigest));
|
|
215
|
+
const stale = await session.handle({ callbackData: pending.approveCallbackData, queryId: (0, node_crypto_1.randomBytes)(18).toString("base64url"), messageId: pending.messageId });
|
|
216
|
+
return { schemaVersion: "sanctuary-interactive-driver-receipt-v2", phase: "complete", label, scenarioHandleDigest, ...common, callbackAttempts: 2, distinctQueryCount: new Set(queryIds).size, callbackDataDigest: sha256(pending.approveCallbackData), barrierObserved: arrivals === 2, settledCount: results.filter(({ handled }) => handled).length, claimCount: after.approval.epoch === before.approval.epoch + 1 ? 1 : 0, mutationCount: after.approval.state === "succeeded" ? 1 : 0, staleReplayAttempts: 1, staleReplaySettled: stale.handled, staleReplayMutationCount: 0, promptTerminal: !session.pendingApprovalIds().includes(before.approval.approvalId), writeCredentialObserved: deps.writeCredentialObserved() };
|
|
217
|
+
}
|
|
218
|
+
const result = await session.handle({ callbackData: pending.approveCallbackData, queryId: (0, node_crypto_1.randomBytes)(18).toString("base64url"), messageId: pending.messageId });
|
|
219
|
+
const after = exactApproval(deps.readApprovals(scenarioHandleDigest));
|
|
220
|
+
if (!after.continuation || after.approval.state !== "succeeded")
|
|
221
|
+
throw new Error("restart continuation did not complete");
|
|
222
|
+
return { approvalEpochAfterRestart: before.approval.epoch, continuationEpochAfter: after.continuation.continuationEpoch, pendingDigestAfter: pendingDigest(pending), pendingRestored: true, callbackAttempts: 1, mutationCount: result.accepted ? 1 : 0, indeterminateRetryCount: 0 };
|
|
223
|
+
}
|
|
224
|
+
finally {
|
|
225
|
+
session.close();
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
function createSanctuaryInteractiveControl(options) {
|
|
229
|
+
const socketPath = path.join(options.agentRoot, "state", "acceptance", "telegram-control.sock");
|
|
230
|
+
const runRequest = options.runRequest ?? (async (operation) => operation());
|
|
231
|
+
let server;
|
|
232
|
+
let updateId = 2_100_000_000;
|
|
233
|
+
return {
|
|
234
|
+
socketPath,
|
|
235
|
+
async start() {
|
|
236
|
+
if (server)
|
|
237
|
+
return;
|
|
238
|
+
(0, node_fs_1.mkdirSync)(path.dirname(socketPath), { recursive: true, mode: 0o700 });
|
|
239
|
+
if ((0, node_fs_1.existsSync)(socketPath))
|
|
240
|
+
(0, node_fs_1.unlinkSync)(socketPath);
|
|
241
|
+
server = (0, node_net_1.createServer)({ allowHalfOpen: true }, (connection) => {
|
|
242
|
+
let raw = "";
|
|
243
|
+
connection.setEncoding("utf8");
|
|
244
|
+
connection.on("error", () => undefined);
|
|
245
|
+
connection.on("data", (chunk) => { raw += chunk; if (Buffer.byteLength(raw) > MAX_CONTROL_REQUEST)
|
|
246
|
+
connection.destroy(); });
|
|
247
|
+
connection.on("end", () => {
|
|
248
|
+
void runRequest(async () => {
|
|
249
|
+
try {
|
|
250
|
+
(0, runtime_1.emitNervesEvent)({ component: "senses", event: "senses.sanctuary_interactive_control_request", message: "Sanctuary interactive control request received", meta: { bytes: Buffer.byteLength(raw) } });
|
|
251
|
+
const parsed = object(JSON.parse(raw), "interactive control request");
|
|
252
|
+
if (parsed.operation === "interactive_runtime_ready") {
|
|
253
|
+
exactKeys(parsed, ["operation", "label", "scenarioHandleDigest"], "interactive readiness request");
|
|
254
|
+
if (parsed.label !== "unit-16m-restart-continuation" || typeof parsed.scenarioHandleDigest !== "string" || !SHA256.test(parsed.scenarioHandleDigest))
|
|
255
|
+
throw new Error("interactive readiness binding is invalid");
|
|
256
|
+
connection.end(`${JSON.stringify({ ok: true, result: { ready: true } })}\n`);
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
const result = await executeSanctuaryInteractiveEngine(parsed, {
|
|
260
|
+
agentRoot: options.agentRoot,
|
|
261
|
+
readApprovals: (digest) => (0, approval_store_1.readApprovalsByScenarioHandleDigest)(path.join(options.agentRoot, "state", "approvals", "approvals.sqlite"), digest),
|
|
262
|
+
readPending: () => new telegram_client_1.FileTelegramPendingApprovalStore(path.join(options.agentRoot, "state", "approvals", "telegram-pending.json")).load(),
|
|
263
|
+
createSession: async () => ({
|
|
264
|
+
handle: ({ callbackData, queryId, messageId }) => runRequest(() => options.transport.handleUpdate({
|
|
265
|
+
update_id: updateId++,
|
|
266
|
+
callback_query: {
|
|
267
|
+
id: queryId,
|
|
268
|
+
from: { id: Number(options.authorizedUserId) },
|
|
269
|
+
data: callbackData,
|
|
270
|
+
message: {
|
|
271
|
+
message_id: Number(messageId),
|
|
272
|
+
chat: { id: Number(options.authorizedChatId) },
|
|
273
|
+
},
|
|
274
|
+
},
|
|
275
|
+
})),
|
|
276
|
+
pendingApprovalIds: () => options.transport.listPendingDeliveries().map(({ approvalId }) => approvalId),
|
|
277
|
+
close: () => undefined,
|
|
278
|
+
}),
|
|
279
|
+
proveIndeterminateRecovery: (approval, digest) => proveSanctuaryAttemptedRecoveryWithoutRetry(options.agentRoot, digest, approval),
|
|
280
|
+
writeCredentialObserved: () => /credential|api[_-]?key|token|secret/iu.test(raw),
|
|
281
|
+
});
|
|
282
|
+
connection.end(`${JSON.stringify({ ok: true, result })}\n`);
|
|
283
|
+
}
|
|
284
|
+
catch {
|
|
285
|
+
connection.end(`${JSON.stringify({ ok: false, error: "interactive runtime operation failed" })}\n`);
|
|
286
|
+
}
|
|
287
|
+
}).catch(() => { if (!connection.destroyed)
|
|
288
|
+
connection.end(`${JSON.stringify({ ok: false, error: "interactive runtime operation failed" })}\n`); });
|
|
289
|
+
});
|
|
290
|
+
});
|
|
291
|
+
await new Promise((resolve, reject) => { server.once("error", reject); server.listen(socketPath, () => { server.off("error", reject); (0, node_fs_1.chmodSync)(socketPath, 0o600); resolve(); }); });
|
|
292
|
+
},
|
|
293
|
+
async stop() { const active = server; server = undefined; if (active)
|
|
294
|
+
await new Promise((resolve) => active.close(() => resolve())); if ((0, node_fs_1.existsSync)(socketPath))
|
|
295
|
+
(0, node_fs_1.unlinkSync)(socketPath); },
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
async function sanctuaryInteractiveControlReady(socketPath, timeoutMs = 1_000) {
|
|
299
|
+
return new Promise((resolve) => {
|
|
300
|
+
const socket = (0, node_net_1.createConnection)(socketPath);
|
|
301
|
+
const finish = (ready) => { socket.destroy(); resolve(ready); };
|
|
302
|
+
socket.setTimeout(timeoutMs, () => finish(false));
|
|
303
|
+
socket.once("connect", () => finish(true));
|
|
304
|
+
socket.once("error", () => finish(false));
|
|
305
|
+
});
|
|
306
|
+
}
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sanctuaryMediaCatalogRequiredToolCalls = sanctuaryMediaCatalogRequiredToolCalls;
|
|
4
|
+
const runtime_1 = require("../nerves/runtime");
|
|
5
|
+
const sanctuary_media_optimization_1 = require("./sanctuary-media-optimization");
|
|
6
|
+
const REQUIRED_TOOL_NAMES = ["sanctuary_search_media_catalog"];
|
|
7
|
+
const HOUSEHOLD_JARGON = /\b(?:bounded|catalog|inventory|endpoint|backend|data shape|pars(?:e|ed|ing)|json|jellyfin|unmanic|sanctuary_search_media_catalog)\b/iu;
|
|
8
|
+
const NEGATED_MEDIA_ACCESS = /\b(?:not|never|none|nothing|zero|inaccessible|invisible|unavailable|broken|failed|failing)\b|\b(?:isn[’']t|won[’']t)\b|\bno\s+access\b|\b(?:lost|lacks?|lacking|without)\s+access\b|\bonly\s+\d|\bfewer\s+than\b|\bsome\s+of\b|\b(?:part|portion|subset)\s+of\b|\bi\s+(?:can(?:not|[’']t)|do\s+not|don[’']t|have\s+no)\b|\bi[’']m\s+not\b/iu;
|
|
9
|
+
const UNSOLICITED_PIVOT = /\b(?:what would you like|what are you in the mood for|would you like me to|do you want me to|want me to|recommend we add)\b/iu;
|
|
10
|
+
const REPORT_LABEL = /(?:^|\n)\s*(?:version|house|the house|render check|status|result)\s*:/iu;
|
|
11
|
+
const TITLE_LIST_GLUE = new Set(["and", "are", "catalog", "film", "films", "from", "have", "here", "in", "is", "library", "movie", "movies", "on", "shelf", "show", "shows", "the", "these", "titles", "we"]);
|
|
12
|
+
const COUNT_ANSWER_GLUE = new Set(["and", "are", "currently", "episodes", "film", "films", "have", "in", "items", "library", "movie", "movies", "on", "shelf", "show", "shows", "the", "there", "tv", "we"]);
|
|
13
|
+
function requestKind(request, titleQuery) {
|
|
14
|
+
if (/\b(?:favorite|favourite|recommend|suggest|pick|what (?:movie|film|show) should|should (?:we|i) (?:watch|add)|what to watch|missing from|must (?:watch|add|get))\b/u.test(request))
|
|
15
|
+
return "taste_recommendation";
|
|
16
|
+
if (/\b(?:see|visible|visibility|access|accessible|browse|browseable|browsable)\b.*\b(?:jellyfin|library|lib|catalog|shelf)\b|\b(?:jellyfin|library|lib|catalog|shelf)\b.*\b(?:see|visible|visibility|access|accessible|browse|browseable|browsable)\b/u.test(request))
|
|
17
|
+
return "visibility";
|
|
18
|
+
if (titleQuery)
|
|
19
|
+
return "title_lookup";
|
|
20
|
+
return "other";
|
|
21
|
+
}
|
|
22
|
+
function requestedListCount(request) {
|
|
23
|
+
const match = request.match(/\b(?:show|list)\s+(?:me\s+)?(one|two|three|four|five|six|seven|eight|nine|ten|[1-9]|1[0-9]|20)\b/u);
|
|
24
|
+
if (!match)
|
|
25
|
+
return null;
|
|
26
|
+
const words = { one: 1, two: 2, three: 3, four: 4, five: 5, six: 6, seven: 7, eight: 8, nine: 9, ten: 10 };
|
|
27
|
+
return words[match[1]] ?? Number(match[1]);
|
|
28
|
+
}
|
|
29
|
+
function requestedTitle(request) {
|
|
30
|
+
const conversationalSuffixRemoved = request.replace(/\s+(?:please|(?:right\s+)?now|currently)$/u, "");
|
|
31
|
+
const haveMatch = conversationalSuffixRemoved.match(/\b(?:do|did|can|could)\s+(?:we|you)\s+(?:have|got|stock)\s+(.+)$/u);
|
|
32
|
+
if (haveMatch)
|
|
33
|
+
return haveMatch[1].replace(/^(?:the\s+)?(?:movie|film|show)\s+/u, "").trim();
|
|
34
|
+
const locationMatch = conversationalSuffixRemoved.match(/\b(?:is|are)\s+(.+?)\s+(?:in|on)\s+(?:(?:the|our)\s+)?(?:jellyfin|library|lib|catalog|shelf)$/u);
|
|
35
|
+
return locationMatch?.[1]?.replace(/^(?:the\s+)?(?:movie|film|show)\s+/u, "").trim() ?? "";
|
|
36
|
+
}
|
|
37
|
+
function includesNormalizedPhrase(text, phrase) {
|
|
38
|
+
return ` ${(0, sanctuary_media_optimization_1.normalizeSanctuaryMediaText)(text)} `.includes(` ${(0, sanctuary_media_optimization_1.normalizeSanctuaryMediaText)(phrase)} `);
|
|
39
|
+
}
|
|
40
|
+
function catalogTitleGroundingRejection(answer, current, expectedCount) {
|
|
41
|
+
let remainder = ` ${(0, sanctuary_media_optimization_1.normalizeSanctuaryMediaText)(answer)} `;
|
|
42
|
+
const titles = [...new Set(current.titles.map(sanctuary_media_optimization_1.normalizeSanctuaryMediaText).filter(Boolean))].sort((left, right) => right.length - left.length);
|
|
43
|
+
const mentioned = [];
|
|
44
|
+
for (const title of titles) {
|
|
45
|
+
const phrase = ` ${title} `;
|
|
46
|
+
if (!remainder.includes(phrase))
|
|
47
|
+
continue;
|
|
48
|
+
mentioned.push(title);
|
|
49
|
+
remainder = remainder.replaceAll(phrase, " ");
|
|
50
|
+
}
|
|
51
|
+
const hasUnverifiedWords = remainder.split(/\s+/u).some((word) => word && !TITLE_LIST_GLUE.has(word));
|
|
52
|
+
const hasExactCount = expectedCount === null || (titles.length === expectedCount && mentioned.length === expectedCount);
|
|
53
|
+
if (mentioned.length === 0 || !hasExactCount || hasUnverifiedWords)
|
|
54
|
+
return "Name exactly the returned catalog titles; do not add or substitute unverified titles.";
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
function catalogCountGroundingRejection(answer, current) {
|
|
58
|
+
const formattedCount = new Intl.NumberFormat("en-US").format(current.totalItems);
|
|
59
|
+
let remainder = ` ${(0, sanctuary_media_optimization_1.normalizeSanctuaryMediaText)(answer)} `;
|
|
60
|
+
const countPhrase = ` ${(0, sanctuary_media_optimization_1.normalizeSanctuaryMediaText)(formattedCount)} `;
|
|
61
|
+
const countOccurrences = remainder.split(countPhrase).length - 1;
|
|
62
|
+
if (countOccurrences === 0)
|
|
63
|
+
return `Report the current verified shelf count of ${formattedCount}.`;
|
|
64
|
+
if (countOccurrences !== 1)
|
|
65
|
+
return "Report the verified shelf count once.";
|
|
66
|
+
remainder = remainder.replaceAll(countPhrase, " ");
|
|
67
|
+
if (remainder.split(/\s+/u).some((word) => word && !COUNT_ANSWER_GLUE.has(word)))
|
|
68
|
+
return "Report only the verified count in ordinary household language.";
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
function parseCatalogEvidence(result, args) {
|
|
72
|
+
try {
|
|
73
|
+
const parsed = JSON.parse(result);
|
|
74
|
+
if (parsed.ok !== true || !parsed.data || !Number.isSafeInteger(parsed.data.totalItems) || !Number.isSafeInteger(parsed.data.matchedItems) || !Array.isArray(parsed.data.items))
|
|
75
|
+
return null;
|
|
76
|
+
const titles = parsed.data.items.flatMap((item) => {
|
|
77
|
+
if (!item || typeof item !== "object" || Array.isArray(item))
|
|
78
|
+
return [];
|
|
79
|
+
const title = item.untrustedTitle;
|
|
80
|
+
return typeof title === "string" && title.trim() ? [title.trim()] : [];
|
|
81
|
+
});
|
|
82
|
+
return {
|
|
83
|
+
query: (0, sanctuary_media_optimization_1.normalizeSanctuaryMediaText)(args.query ?? ""),
|
|
84
|
+
totalItems: parsed.data.totalItems,
|
|
85
|
+
matchedItems: parsed.data.matchedItems,
|
|
86
|
+
titles,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function sentenceCount(answer) {
|
|
94
|
+
return answer.split(/[.!?]+(?:\s+|$)/u).filter((part) => part.trim()).length;
|
|
95
|
+
}
|
|
96
|
+
function hasGroundedFirstPersonVisibility(answer, formattedCount) {
|
|
97
|
+
if (NEGATED_MEDIA_ACCESS.test(answer) || answer.split(formattedCount).length - 1 !== 1)
|
|
98
|
+
return false;
|
|
99
|
+
const escapedCount = formattedCount.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
|
100
|
+
const mediaNoun = "(?:titles?|movies?|films?|shows?|episodes?|items?)";
|
|
101
|
+
const countedObject = `(?:all\\s+|about\\s+|around\\s+|exactly\\s+|roughly\\s+)?${escapedCount}\\s+${mediaNoun}\\b`;
|
|
102
|
+
const contextObject = `(?:it|(?:(?:the|our)\\s+)?(?:full\\s+)?(?:library|shelf))(?:\\s+(?:now|again))?(?=\\s*(?:[.!?;,:—-]|$))`;
|
|
103
|
+
const accessObject = `(?:${contextObject}|${countedObject})`;
|
|
104
|
+
const firstPersonAccess = [
|
|
105
|
+
new RegExp(`\\bi\\s+(?:(?:can\\s+(?:(?:absolutely|clearly|currently|definitely|now|plainly|readily)\\s+)?|(?:currently|now)\\s+)?(?:see|browse|access|view))\\s+${accessObject}`, "iu"),
|
|
106
|
+
new RegExp(`\\bi(?:\\s+have|[’']ve\\s+got)\\s+(?:(?:full\\s+)?access\\s+to\\s+${accessObject}|${countedObject})`, "iu"),
|
|
107
|
+
new RegExp(`\\bi(?:\\s+am|[’']m)\\s+(?:(?:currently|now)\\s+)?(?:looking\\s+at|able\\s+to\\s+(?:see|browse|access|view))\\s+${accessObject}`, "iu"),
|
|
108
|
+
/\b(?:(?:the|our)\s+)?(?:full\s+)?(?:library|shelf)\s+is\s+(?:fully\s+)?(?:visible|accessible)\s+to\s+me\b/iu,
|
|
109
|
+
];
|
|
110
|
+
const groundedCount = new RegExp(`\\b${escapedCount}\\s+${mediaNoun}\\b`, "iu");
|
|
111
|
+
return firstPersonAccess.some((pattern) => pattern.test(answer)) && groundedCount.test(answer);
|
|
112
|
+
}
|
|
113
|
+
function commonAnswerRejection(answer, technicalDetailRequested) {
|
|
114
|
+
if (/\b(?:just|only|actually|merely)\s+(?:a\s+)?(?:bot|ai|assistant)\b|\bi\s+(?:can[’']?t|cannot|don[’']?t|do not)\s+(?:actually\s+)?watch\b|\bif i had to pick\b/iu.test(answer)) {
|
|
115
|
+
return "Answer from the catalog evidence with a confident, personable choice; do not retreat into an AI or 'I cannot watch' disclaimer.";
|
|
116
|
+
}
|
|
117
|
+
if (/\b(?:you'?d|you\s+would|you\s+need\s+to|please)\b.*\b(?:check|look at|poke|nudge)\b.*\b(?:log|logs|dashboard|jellyfin|unmanic)\b/iu.test(answer)) {
|
|
118
|
+
return "Do not send Ari to check Jellyfin, Unmanic, dashboards, or logs for ordinary library visibility while safe catalog tools are available. Use the catalog evidence, or if the catalog read itself fails, say exactly what I could and could not verify.";
|
|
119
|
+
}
|
|
120
|
+
if (UNSOLICITED_PIVOT.test(answer))
|
|
121
|
+
return "Answer the media question that was asked, then stop; do not append an unsolicited question or recommendation pivot.";
|
|
122
|
+
if (REPORT_LABEL.test(answer))
|
|
123
|
+
return "Answer conversationally; do not use status-report labels such as version:, house:, render check:, status:, or result:.";
|
|
124
|
+
if (!technicalDetailRequested && HOUSEHOLD_JARGON.test(answer))
|
|
125
|
+
return "Use household language such as shelf or library; omit implementation jargon unless technical detail was requested.";
|
|
126
|
+
return undefined;
|
|
127
|
+
}
|
|
128
|
+
function sanctuaryMediaCatalogRequiredToolCalls(request, advertisedToolNames) {
|
|
129
|
+
if (!advertisedToolNames.includes("sanctuary_search_media_catalog"))
|
|
130
|
+
return undefined;
|
|
131
|
+
const normalized = (0, sanctuary_media_optimization_1.normalizeSanctuaryMediaText)(request);
|
|
132
|
+
const mentionsMedia = /\b(?:film|films|movie|movies|shows|tv|jellyfin|watch|shelf|stock|catalog|library|lib)\b/u.test(normalized);
|
|
133
|
+
const asksCatalog = /\b(?:have|got|stock|catalog|library|lib|shelf|jellyfin|favorite|favourite|recommend|suggest|pick|watch|add|see|show|list|browse|access)\b/u.test(normalized);
|
|
134
|
+
const requestedTitleQuery = requestedTitle(normalized);
|
|
135
|
+
if ((!mentionsMedia && !requestedTitleQuery) || !asksCatalog)
|
|
136
|
+
return undefined;
|
|
137
|
+
const kind = requestKind(normalized, requestedTitleQuery);
|
|
138
|
+
const asksForAddition = /\b(?:add|missing from|must get)\b/u.test(normalized);
|
|
139
|
+
const asksForCount = /\b(?:how many|count)\b/u.test(normalized);
|
|
140
|
+
const listCount = requestedListCount(normalized);
|
|
141
|
+
const technicalDetailRequested = /\b(?:technical|technically|implementation|endpoint|backend|debug|detail|internals?)\b/u.test(normalized);
|
|
142
|
+
let latestEvidence;
|
|
143
|
+
const names = [...REQUIRED_TOOL_NAMES];
|
|
144
|
+
(0, runtime_1.emitNervesEvent)({
|
|
145
|
+
component: "senses",
|
|
146
|
+
event: "senses.sanctuary_media_catalog_obligation",
|
|
147
|
+
message: "media catalog intent requires safe restricted catalog evidence",
|
|
148
|
+
meta: { requiredToolNames: names },
|
|
149
|
+
});
|
|
150
|
+
return {
|
|
151
|
+
names,
|
|
152
|
+
requireSuccessfulResults: true,
|
|
153
|
+
retryMessage: asksForCount
|
|
154
|
+
? "Use sanctuary_search_media_catalog before answering, then report only the current shelf count in ordinary household language."
|
|
155
|
+
: kind === "visibility"
|
|
156
|
+
? "Use sanctuary_search_media_catalog before answering. Lead with the direct answer from current catalog evidence, report the shelf count in ordinary household language, and stop without sampled titles or a follow-up question."
|
|
157
|
+
: kind === "title_lookup"
|
|
158
|
+
? "Use sanctuary_search_media_catalog with the requested title before answering. Confirm its presence or absence directly from current catalog evidence."
|
|
159
|
+
: kind === "taste_recommendation"
|
|
160
|
+
? "Use sanctuary_search_media_catalog before answering. Make one concise, decisive choice grounded in returned catalog evidence; do not volunteer an AI or 'I cannot watch' disclaimer."
|
|
161
|
+
: listCount
|
|
162
|
+
? `Use sanctuary_search_media_catalog with limit ${listCount} before answering, then name exactly the returned catalog titles.`
|
|
163
|
+
: "Use sanctuary_search_media_catalog before answering and base any named titles on the returned catalog evidence.",
|
|
164
|
+
validateRequiredToolResult(name, result, args) {
|
|
165
|
+
if (name !== "sanctuary_search_media_catalog")
|
|
166
|
+
return false;
|
|
167
|
+
const current = parseCatalogEvidence(result, args);
|
|
168
|
+
if (!current)
|
|
169
|
+
return false;
|
|
170
|
+
latestEvidence = current;
|
|
171
|
+
return true;
|
|
172
|
+
},
|
|
173
|
+
validateToolCallBeforeDispatch(name, args) {
|
|
174
|
+
if (name !== "sanctuary_search_media_catalog")
|
|
175
|
+
return undefined;
|
|
176
|
+
const query = (0, sanctuary_media_optimization_1.normalizeSanctuaryMediaText)(args.query ?? "");
|
|
177
|
+
if (kind === "title_lookup" && !query)
|
|
178
|
+
return "Search for the requested title by name before answering whether it is on the shelf.";
|
|
179
|
+
if (kind === "title_lookup" && query !== requestedTitleQuery)
|
|
180
|
+
return `Search for the requested title ${requestedTitleQuery} before answering whether it is on the shelf.`;
|
|
181
|
+
if (asksForAddition && !query)
|
|
182
|
+
return "Search for one candidate title by name before recommending it as an addition.";
|
|
183
|
+
if (listCount && Number(args.limit) !== listCount)
|
|
184
|
+
return `Set the catalog limit to ${listCount} so the answer is grounded in exactly the requested number of titles.`;
|
|
185
|
+
return undefined;
|
|
186
|
+
},
|
|
187
|
+
validateTerminalAnswer(answer) {
|
|
188
|
+
const commonRejection = commonAnswerRejection(answer, technicalDetailRequested);
|
|
189
|
+
if (commonRejection)
|
|
190
|
+
return commonRejection;
|
|
191
|
+
const latest = latestEvidence;
|
|
192
|
+
if (asksForCount && latest)
|
|
193
|
+
return catalogCountGroundingRejection(answer, latest);
|
|
194
|
+
if (kind === "visibility") {
|
|
195
|
+
if (answer.length > 240 || answer.includes("\n") || sentenceCount(answer) > 2)
|
|
196
|
+
return "Answer library visibility in no more than two short sentences and 240 characters.";
|
|
197
|
+
if (!/^yes\b/iu.test(answer.trim()))
|
|
198
|
+
return "Lead with a direct yes when the current catalog read succeeds.";
|
|
199
|
+
if (latest) {
|
|
200
|
+
const formattedCount = new Intl.NumberFormat("en-US").format(latest.totalItems);
|
|
201
|
+
if (!hasGroundedFirstPersonVisibility(answer, formattedCount))
|
|
202
|
+
return `Reply in one or two sentences. A valid shape is: Yes—I can see the library now. It contains ${formattedCount} titles.`;
|
|
203
|
+
}
|
|
204
|
+
if (/\b(?:titles? like|such as|including)\b/iu.test(answer))
|
|
205
|
+
return "Do not sample titles for a visibility question; answer whether the shelf is visible and give the current count.";
|
|
206
|
+
if ([...answer.matchAll(/\byes\b/giu)].length > 1)
|
|
207
|
+
return "Give one answer once; do not repeat the yes or restate the response.";
|
|
208
|
+
if (answer.includes("?"))
|
|
209
|
+
return "Answer the visibility question and stop without asking a new question.";
|
|
210
|
+
}
|
|
211
|
+
if (kind === "title_lookup" && latest?.query) {
|
|
212
|
+
const exactMatch = latest.titles.some((title) => (0, sanctuary_media_optimization_1.normalizeSanctuaryMediaText)(title) === requestedTitleQuery);
|
|
213
|
+
const expectedLead = exactMatch ? /^yes\b/iu : /^no\b/iu;
|
|
214
|
+
if (!expectedLead.test(answer.trim()))
|
|
215
|
+
return `Lead with ${exactMatch ? "yes" : "no"} based on the current title search.`;
|
|
216
|
+
if (!includesNormalizedPhrase(answer, requestedTitleQuery))
|
|
217
|
+
return "Name the requested title in the direct answer.";
|
|
218
|
+
}
|
|
219
|
+
if (kind === "taste_recommendation" && latest) {
|
|
220
|
+
if (asksForAddition) {
|
|
221
|
+
if (!latest.query || latest.matchedItems !== 0 || !includesNormalizedPhrase(answer, latest.query))
|
|
222
|
+
return "Recommend an addition only after an exact current catalog search shows that candidate is absent.";
|
|
223
|
+
if (/\b(?:i|we)\s+(?:added|requested|submitted|queued)\b/iu.test(answer))
|
|
224
|
+
return "Do not claim the title was added or requested when no media-request action was available.";
|
|
225
|
+
}
|
|
226
|
+
else if (!latest.titles.some((title) => includesNormalizedPhrase(answer, title))) {
|
|
227
|
+
return "Make the choice from a title returned by the current catalog evidence.";
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
if (kind === "other" && latest)
|
|
231
|
+
return catalogTitleGroundingRejection(answer, latest, listCount);
|
|
232
|
+
return undefined;
|
|
233
|
+
},
|
|
234
|
+
};
|
|
235
|
+
}
|