@vellumai/assistant 0.5.16 → 0.6.0
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/ARCHITECTURE.md +1 -1
- package/Dockerfile +0 -3
- package/knip.json +2 -1
- package/openapi.yaml +660 -80
- package/package.json +1 -1
- package/src/__tests__/actor-token-service.test.ts +68 -0
- package/src/__tests__/agent-loop.test.ts +0 -32
- package/src/__tests__/always-loaded-tools-guard.test.ts +2 -2
- package/src/__tests__/anthropic-provider.test.ts +57 -3
- package/src/__tests__/app-compiler.test.ts +120 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +2 -2
- package/src/__tests__/call-conversation-messages.test.ts +2 -6
- package/src/__tests__/call-domain.test.ts +2 -6
- package/src/__tests__/call-pointer-messages.test.ts +2 -14
- package/src/__tests__/call-recovery.test.ts +2 -6
- package/src/__tests__/call-routes-http.test.ts +2 -6
- package/src/__tests__/call-store.test.ts +2 -6
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +2 -6
- package/src/__tests__/canonical-guardian-store.test.ts +2 -6
- package/src/__tests__/channel-delivery-store.test.ts +2 -6
- package/src/__tests__/channel-retry-sweep.test.ts +2 -6
- package/src/__tests__/checker.test.ts +25 -3
- package/src/__tests__/clawhub.test.ts +54 -24
- package/src/__tests__/cli-command-risk-guard.test.ts +14 -0
- package/src/__tests__/cli-memory.test.ts +74 -69
- package/src/__tests__/config-schema.test.ts +1 -1
- package/src/__tests__/config-set-platform-guard.test.ts +302 -0
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +2 -6
- package/src/__tests__/contacts-tools.test.ts +31 -0
- package/src/__tests__/context-overflow-reducer.test.ts +86 -0
- package/src/__tests__/context-token-estimator.test.ts +175 -10
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +9 -0
- package/src/__tests__/conversation-agent-loop.test.ts +9 -0
- package/src/__tests__/conversation-attachments.test.ts +2 -6
- package/src/__tests__/conversation-attention-store.test.ts +2 -6
- package/src/__tests__/conversation-clear-safety.test.ts +2 -6
- package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +4 -10
- package/src/__tests__/conversation-disk-view-integration.test.ts +2 -6
- package/src/__tests__/conversation-disk-view.test.ts +2 -6
- package/src/__tests__/conversation-error.test.ts +33 -2
- package/src/__tests__/conversation-fork-crud.test.ts +2 -6
- package/src/__tests__/conversation-history-web-search.test.ts +5 -0
- package/src/__tests__/conversation-load-history-repair.test.ts +5 -1
- package/src/__tests__/conversation-media-retry.test.ts +91 -0
- package/src/__tests__/conversation-starter-routes.test.ts +20 -11
- package/src/__tests__/conversation-store.test.ts +2 -6
- package/src/__tests__/conversation-usage.test.ts +2 -6
- package/src/__tests__/conversation-wipe.test.ts +11 -408
- package/src/__tests__/credential-execution-feature-gates.test.ts +3 -3
- package/src/__tests__/credential-execution-shell-lockdown.test.ts +2 -2
- package/src/__tests__/credential-security-e2e.test.ts +2 -0
- package/src/__tests__/followup-tools.test.ts +2 -6
- package/src/__tests__/graph-extraction-event-date.test.ts +186 -0
- package/src/__tests__/guardian-action-conversation-turn.test.ts +2 -6
- package/src/__tests__/guardian-action-followup-executor.test.ts +2 -6
- package/src/__tests__/guardian-action-followup-store.test.ts +2 -6
- package/src/__tests__/guardian-action-grant-mint-consume.test.ts +2 -6
- package/src/__tests__/guardian-action-late-reply.test.ts +2 -6
- package/src/__tests__/guardian-action-store.test.ts +2 -6
- package/src/__tests__/guardian-binding-drift-heal.test.ts +2 -6
- package/src/__tests__/guardian-decision-primitive-canonical.test.ts +8 -8
- package/src/__tests__/guardian-dispatch.test.ts +2 -6
- package/src/__tests__/guardian-grant-minting.test.ts +2 -14
- package/src/__tests__/guardian-principal-id-roundtrip.test.ts +2 -6
- package/src/__tests__/guardian-routing-invariants.test.ts +192 -6
- package/src/__tests__/guardian-routing-state.test.ts +2 -6
- package/src/__tests__/guardian-verification-voice-binding.test.ts +2 -6
- package/src/__tests__/inbound-invite-redemption.test.ts +2 -6
- package/src/__tests__/injection-block.test.ts +154 -0
- package/src/__tests__/install-meta.test.ts +506 -0
- package/src/__tests__/install-skill-routing.test.ts +292 -0
- package/src/__tests__/invite-redemption-service.test.ts +2 -6
- package/src/__tests__/invite-routes-http.test.ts +2 -6
- package/src/__tests__/jobs-store-qdrant-breaker.test.ts +2 -14
- package/src/__tests__/list-messages-attachments.test.ts +2 -6
- package/src/__tests__/llm-context-route-provider.test.ts +2 -6
- package/src/__tests__/llm-request-log-turn-query.test.ts +2 -6
- package/src/__tests__/llm-usage-store.test.ts +2 -6
- package/src/__tests__/log-export-workspace.test.ts +2 -6
- package/src/__tests__/managed-store.test.ts +38 -11
- package/src/__tests__/memory-jobs-worker-backoff.test.ts +2 -8
- package/src/__tests__/memory-recall-log-store.test.ts +2 -6
- package/src/__tests__/memory-upsert-concurrency.test.ts +4 -112
- package/src/__tests__/non-member-access-request.test.ts +2 -6
- package/src/__tests__/notification-guardian-path.test.ts +2 -6
- package/src/__tests__/oauth-cli.test.ts +364 -2
- package/src/__tests__/oauth2-gateway-transport.test.ts +18 -3
- package/src/__tests__/outlook-attachments.test.ts +301 -0
- package/src/__tests__/outlook-automation-tools.test.ts +425 -0
- package/src/__tests__/outlook-categories.test.ts +212 -0
- package/src/__tests__/outlook-client-automation.test.ts +246 -0
- package/src/__tests__/outlook-compose-tools.test.ts +325 -0
- package/src/__tests__/outlook-declutter-tools.test.ts +585 -0
- package/src/__tests__/outlook-email-watcher.test.ts +322 -0
- package/src/__tests__/outlook-follow-up.test.ts +196 -0
- package/src/__tests__/outlook-messaging-provider.test.ts +498 -3
- package/src/__tests__/outlook-trash.test.ts +77 -0
- package/src/__tests__/outlook-unsubscribe.test.ts +250 -0
- package/src/__tests__/platform-callback-registration.test.ts +4 -4
- package/src/__tests__/playbook-execution.test.ts +76 -80
- package/src/__tests__/playbook-tools.test.ts +5 -7
- package/src/__tests__/provider-error-scenarios.test.ts +21 -0
- package/src/__tests__/rebuild-index-graph-nodes.test.ts +273 -0
- package/src/__tests__/registry.test.ts +2 -2
- package/src/__tests__/require-fresh-approval.test.ts +64 -2
- package/src/__tests__/runtime-events-sse-parity.test.ts +2 -6
- package/src/__tests__/runtime-events-sse.test.ts +2 -6
- package/src/__tests__/schedule-store.test.ts +2 -6
- package/src/__tests__/schedule-tools.test.ts +2 -6
- package/src/__tests__/scheduler-recurrence.test.ts +1 -5
- package/src/__tests__/scoped-approval-grants.test.ts +2 -6
- package/src/__tests__/scoped-grant-security-matrix.test.ts +2 -6
- package/src/__tests__/search-skills-unified.test.ts +421 -0
- package/src/__tests__/secret-onetime-send.test.ts +2 -0
- package/src/__tests__/send-endpoint-busy.test.ts +2 -6
- package/src/__tests__/sequence-store.test.ts +2 -6
- package/src/__tests__/server-history-render.test.ts +2 -6
- package/src/__tests__/skill-feature-flags-integration.test.ts +38 -31
- package/src/__tests__/skill-feature-flags.test.ts +6 -6
- package/src/__tests__/skill-load-feature-flag.test.ts +11 -11
- package/src/__tests__/skill-memory.test.ts +140 -98
- package/src/__tests__/skills-uninstall.test.ts +2 -2
- package/src/__tests__/skills.test.ts +1 -1
- package/src/__tests__/slack-inbound-verification.test.ts +2 -6
- package/src/__tests__/task-compiler.test.ts +2 -6
- package/src/__tests__/task-management-tools.test.ts +2 -6
- package/src/__tests__/task-memory-cleanup.test.ts +173 -229
- package/src/__tests__/task-runner.test.ts +2 -6
- package/src/__tests__/task-scheduler.test.ts +2 -6
- package/src/__tests__/test-preload.ts +3 -0
- package/src/__tests__/tool-approval-handler.test.ts +2 -6
- package/src/__tests__/tool-grant-request-escalation.test.ts +2 -6
- package/src/__tests__/tool-side-effects-slack-dm.test.ts +276 -0
- package/src/__tests__/trust-store.test.ts +1 -1
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +2 -6
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +2 -6
- package/src/__tests__/trusted-contact-multichannel.test.ts +2 -6
- package/src/__tests__/trusted-contact-verification.test.ts +2 -6
- package/src/__tests__/turn-boundary-resolution.test.ts +2 -6
- package/src/__tests__/usage-cache-backfill-migration.test.ts +1 -6
- package/src/__tests__/usage-routes.test.ts +2 -6
- package/src/__tests__/verification-control-plane-policy.test.ts +0 -2
- package/src/__tests__/voice-invite-redemption.test.ts +2 -6
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +2 -6
- package/src/__tests__/voice-session-bridge.test.ts +2 -6
- package/src/__tests__/volume-security-guard.test.ts +2 -0
- package/src/__tests__/workspace-lifecycle.test.ts +29 -1
- package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +2 -6
- package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +2 -6
- package/src/__tests__/workspace-migration-026-backfill-install-meta.test.ts +558 -0
- package/src/__tests__/workspace-policy.test.ts +1 -1
- package/src/agent/attachments.ts +7 -2
- package/src/agent/image-optimize.ts +165 -0
- package/src/agent/loop.ts +1 -15
- package/src/bundler/app-compiler.ts +179 -2
- package/src/bundler/package-resolver.ts +3 -5
- package/src/cli/__tests__/notifications.test.ts +1 -2
- package/src/cli/cli-memory.ts +67 -64
- package/src/cli/commands/avatar.ts +3 -3
- package/src/cli/commands/config.ts +26 -13
- package/src/cli/commands/doctor.ts +2 -2
- package/src/cli/commands/memory.ts +41 -55
- package/src/cli/commands/oauth/__tests__/connect.test.ts +2 -2
- package/src/cli/commands/oauth/__tests__/disconnect.test.ts +2 -2
- package/src/cli/commands/oauth/__tests__/mode.test.ts +8 -1
- package/src/cli/commands/oauth/__tests__/status.test.ts +2 -2
- package/src/cli/commands/oauth/connect.ts +11 -6
- package/src/cli/commands/oauth/mode.ts +7 -0
- package/src/cli/commands/oauth/shared.ts +39 -3
- package/src/cli/commands/platform/__tests__/connect.test.ts +1 -1
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +1 -1
- package/src/cli/commands/platform/__tests__/status.test.ts +5 -5
- package/src/cli/commands/platform/index.ts +16 -16
- package/src/cli/commands/skills.ts +88 -16
- package/src/cli/commands/trust.ts +2 -2
- package/src/cli/lib/daemon-credential-client.ts +2 -3
- package/src/config/bundled-skills/acp/TOOLS.json +1 -1
- package/src/config/bundled-skills/contacts/SKILL.md +0 -1
- package/src/config/bundled-skills/contacts/TOOLS.json +0 -8
- package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +0 -4
- package/src/config/bundled-skills/gmail/SKILL.md +2 -10
- package/src/config/bundled-skills/google-calendar/SKILL.md +1 -9
- package/src/config/bundled-skills/messaging/SKILL.md +10 -18
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +40 -33
- package/src/config/bundled-skills/outlook/SKILL.md +189 -0
- package/src/config/bundled-skills/outlook/TOOLS.json +530 -0
- package/src/config/bundled-skills/outlook/tools/outlook-attachments.ts +85 -0
- package/src/config/bundled-skills/outlook/tools/outlook-categories.ts +77 -0
- package/src/config/bundled-skills/outlook/tools/outlook-draft.ts +84 -0
- package/src/config/bundled-skills/outlook/tools/outlook-follow-up.ts +94 -0
- package/src/config/bundled-skills/outlook/tools/outlook-forward.ts +49 -0
- package/src/config/bundled-skills/outlook/tools/outlook-outreach-scan.ts +237 -0
- package/src/config/bundled-skills/outlook/tools/outlook-rules.ts +161 -0
- package/src/config/bundled-skills/outlook/tools/outlook-send-draft.ts +32 -0
- package/src/config/bundled-skills/outlook/tools/outlook-sender-digest.ts +272 -0
- package/src/config/bundled-skills/outlook/tools/outlook-trash.ts +29 -0
- package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +129 -0
- package/src/config/bundled-skills/outlook/tools/outlook-vacation.ts +87 -0
- package/src/config/bundled-skills/outlook/tools/shared.ts +20 -0
- package/src/config/bundled-skills/outlook-calendar/SKILL.md +51 -0
- package/src/config/bundled-skills/outlook-calendar/TOOLS.json +221 -0
- package/src/config/bundled-skills/outlook-calendar/calendar-client.ts +252 -0
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-check-availability.ts +53 -0
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-create-event.ts +74 -0
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-get-event.ts +18 -0
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-list-events.ts +46 -0
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-rsvp.ts +36 -0
- package/src/config/bundled-skills/outlook-calendar/tools/shared.ts +17 -0
- package/src/config/bundled-skills/outlook-calendar/types.ts +120 -0
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +47 -40
- package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +16 -29
- package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +16 -18
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +39 -47
- package/src/config/bundled-skills/slack/SKILL.md +1 -7
- package/src/config/bundled-tool-registry.ts +56 -4
- package/src/config/env-registry.ts +15 -8
- package/src/config/feature-flag-registry.json +21 -124
- package/src/config/schemas/platform.ts +8 -0
- package/src/config/schemas/timeouts.ts +1 -1
- package/src/config/skills.ts +18 -7
- package/src/context/token-estimator.ts +25 -18
- package/src/context/window-manager.ts +6 -2
- package/src/credential-execution/process-manager.ts +3 -1
- package/src/daemon/context-overflow-reducer.ts +46 -2
- package/src/daemon/conversation-agent-loop-handlers.ts +123 -82
- package/src/daemon/conversation-agent-loop.ts +96 -61
- package/src/daemon/conversation-error.ts +31 -8
- package/src/daemon/conversation-lifecycle.ts +33 -0
- package/src/daemon/conversation-media-retry.ts +85 -7
- package/src/daemon/conversation-notifiers.ts +4 -1
- package/src/daemon/conversation-runtime-assembly.ts +5 -0
- package/src/daemon/conversation.ts +41 -2
- package/src/daemon/daemon-control.ts +8 -2
- package/src/daemon/handlers/shared.ts +22 -12
- package/src/daemon/handlers/skills.ts +416 -202
- package/src/daemon/lifecycle.ts +40 -1
- package/src/daemon/main.ts +5 -1
- package/src/daemon/message-types/conversations.ts +4 -1
- package/src/daemon/message-types/messages.ts +3 -1
- package/src/daemon/message-types/skills.ts +97 -36
- package/src/daemon/providers-setup.ts +5 -0
- package/src/daemon/server.ts +11 -2
- package/src/daemon/tool-side-effects.ts +27 -5
- package/src/heartbeat/heartbeat-service.ts +1 -0
- package/src/hooks/cli.ts +2 -2
- package/src/hooks/runner.ts +15 -38
- package/src/inbound/platform-callback-registration.ts +14 -14
- package/src/memory/admin.ts +11 -45
- package/src/memory/conversation-bootstrap.ts +2 -0
- package/src/memory/conversation-crud.ts +242 -348
- package/src/memory/conversation-group-migration.ts +157 -0
- package/src/memory/conversation-queries.ts +4 -2
- package/src/memory/db-init.ts +30 -3
- package/src/memory/embed.ts +73 -0
- package/src/memory/embedding-backend.ts +8 -14
- package/src/memory/embedding-runtime-manager.ts +12 -114
- package/src/memory/fingerprint.ts +2 -2
- package/src/memory/graph/bootstrap.ts +512 -0
- package/src/memory/graph/capability-seed.ts +297 -0
- package/src/memory/graph/consolidation.ts +691 -0
- package/src/memory/graph/conversation-graph-memory.ts +630 -0
- package/src/memory/graph/decay.test.ts +208 -0
- package/src/memory/graph/decay.ts +195 -0
- package/src/memory/graph/extraction-job.ts +69 -0
- package/src/memory/graph/extraction.test.ts +936 -0
- package/src/memory/graph/extraction.ts +1254 -0
- package/src/memory/graph/graph-search.ts +266 -0
- package/src/memory/graph/image-ref-utils.ts +29 -0
- package/src/memory/graph/injection.test.ts +513 -0
- package/src/memory/graph/injection.ts +439 -0
- package/src/memory/graph/inspect.ts +534 -0
- package/src/memory/graph/narrative.ts +267 -0
- package/src/memory/graph/pattern-scan.ts +269 -0
- package/src/memory/graph/retriever.ts +1008 -0
- package/src/memory/graph/scoring.test.ts +548 -0
- package/src/memory/graph/scoring.ts +232 -0
- package/src/memory/graph/serendipity.ts +65 -0
- package/src/memory/graph/store.test.ts +1050 -0
- package/src/memory/graph/store.ts +699 -0
- package/src/memory/graph/tool-handlers.ts +426 -0
- package/src/memory/graph/tools.ts +141 -0
- package/src/memory/graph/triggers.test.ts +487 -0
- package/src/memory/graph/triggers.ts +223 -0
- package/src/memory/graph/types.ts +271 -0
- package/src/memory/group-crud.ts +191 -0
- package/src/memory/indexer.ts +37 -19
- package/src/memory/job-handlers/cleanup.ts +0 -53
- package/src/memory/job-handlers/conversation-starters.ts +91 -53
- package/src/memory/job-handlers/embedding.ts +5 -31
- package/src/memory/job-handlers/index-maintenance.ts +23 -11
- package/src/memory/job-handlers/summarization.ts +32 -17
- package/src/memory/job-utils.ts +1 -1
- package/src/memory/jobs-store.ts +50 -70
- package/src/memory/jobs-worker.ts +147 -112
- package/src/memory/message-content.ts +1 -0
- package/src/memory/migrations/202-memory-graph-tables.ts +130 -0
- package/src/memory/migrations/203-drop-memory-items-tables.ts +23 -0
- package/src/memory/migrations/204-rename-memory-graph-type-values.ts +46 -0
- package/src/memory/migrations/205-memory-graph-image-refs.ts +11 -0
- package/src/memory/migrations/index.ts +4 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/qdrant-client.ts +44 -17
- package/src/memory/schema/index.ts +1 -0
- package/src/memory/schema/memory-graph.ts +139 -0
- package/src/memory/search/semantic.ts +47 -91
- package/src/memory/task-memory-cleanup.ts +28 -50
- package/src/messaging/providers/outlook/adapter.ts +8 -1
- package/src/messaging/providers/outlook/client.ts +299 -0
- package/src/messaging/providers/outlook/types.ts +118 -0
- package/src/notifications/adapters/macos.ts +1 -0
- package/src/notifications/copy-composer.ts +9 -0
- package/src/notifications/signal.ts +16 -0
- package/src/oauth/seed-providers.ts +2 -1
- package/src/permissions/checker.ts +24 -3
- package/src/permissions/defaults.ts +4 -4
- package/src/permissions/workspace-policy.ts +1 -1
- package/src/playbooks/playbook-compiler.ts +19 -18
- package/src/playbooks/types.ts +4 -3
- package/src/prompts/system-prompt.ts +3 -29
- package/src/providers/anthropic/client.ts +47 -19
- package/src/providers/gemini/client.ts +1 -1
- package/src/providers/openai/client.ts +1 -1
- package/src/providers/registry.ts +1 -1
- package/src/providers/retry.ts +19 -3
- package/src/runtime/actor-trust-resolver.ts +5 -1
- package/src/runtime/auth/route-policy.ts +7 -0
- package/src/runtime/guardian-reply-router.ts +5 -1
- package/src/runtime/http-server.ts +23 -3
- package/src/runtime/middleware/auth.ts +20 -0
- package/src/runtime/routes/attachment-routes.test.ts +106 -0
- package/src/runtime/routes/attachment-routes.ts +106 -16
- package/src/runtime/routes/brain-graph-routes.ts +21 -22
- package/src/runtime/routes/btw-routes.ts +8 -0
- package/src/runtime/routes/conversation-management-routes.ts +2 -0
- package/src/runtime/routes/conversation-starter-routes.ts +2 -2
- package/src/runtime/routes/debug-routes.ts +1 -1
- package/src/runtime/routes/global-search-routes.ts +21 -19
- package/src/runtime/routes/group-routes.ts +207 -0
- package/src/runtime/routes/guardian-action-routes.ts +21 -10
- package/src/runtime/routes/guardian-bootstrap-routes.ts +23 -19
- package/src/runtime/routes/inbound-message-handler.ts +19 -0
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +292 -0
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +207 -0
- package/src/runtime/routes/memory-item-routes.test.ts +2 -14
- package/src/runtime/routes/memory-item-routes.ts +341 -388
- package/src/runtime/routes/schedule-routes.ts +2 -0
- package/src/runtime/routes/skills-routes.ts +103 -37
- package/src/runtime/routes/work-items-routes.test.ts +2 -6
- package/src/schedule/scheduler.ts +8 -1
- package/src/security/oauth2.ts +1 -1
- package/src/security/secure-keys.ts +4 -8
- package/src/shared/provider-env-vars.ts +19 -0
- package/src/skills/catalog-cache.ts +5 -0
- package/src/skills/catalog-install.ts +15 -14
- package/src/skills/clawhub.ts +134 -154
- package/src/skills/install-meta.ts +208 -0
- package/src/skills/managed-store.ts +27 -16
- package/src/skills/skill-memory.ts +152 -77
- package/src/skills/skillssh-registry.ts +19 -17
- package/src/tasks/task-runner.ts +3 -1
- package/src/telemetry/usage-telemetry-reporter.test.ts +3 -5
- package/src/tools/browser/runtime-check.ts +3 -1
- package/src/tools/memory/register.ts +63 -46
- package/src/tools/permission-checker.ts +7 -1
- package/src/tools/shared/filesystem/image-read.ts +22 -85
- package/src/tools/terminal/safe-env.ts +1 -0
- package/src/tools/tool-manifest.ts +3 -3
- package/src/util/browser.ts +25 -10
- package/src/util/bun-runtime.ts +172 -0
- package/src/watcher/providers/outlook-calendar.ts +343 -0
- package/src/watcher/providers/outlook.ts +198 -0
- package/src/workspace/migrations/025-remove-oauth-app-setup-skills.ts +76 -0
- package/src/workspace/migrations/026-backfill-install-meta.ts +325 -0
- package/src/workspace/migrations/027-remove-orphaned-optimized-images-cache.ts +42 -0
- package/src/workspace/migrations/registry.ts +6 -0
- package/src/__tests__/context-memory-e2e.test.ts +0 -415
- package/src/__tests__/journal-context.test.ts +0 -268
- package/src/__tests__/memory-context-benchmark.benchmark.test.ts +0 -297
- package/src/__tests__/memory-lifecycle-e2e.test.ts +0 -459
- package/src/__tests__/memory-query-builder.test.ts +0 -59
- package/src/__tests__/memory-recall-quality.test.ts +0 -1046
- package/src/__tests__/memory-regressions.experimental.test.ts +0 -629
- package/src/__tests__/memory-regressions.test.ts +0 -3696
- package/src/__tests__/memory-retrieval.benchmark.test.ts +0 -295
- package/src/daemon/conversation-memory.ts +0 -207
- package/src/memory/conversation-starters-cadence.ts +0 -74
- package/src/memory/items-extractor.ts +0 -860
- package/src/memory/job-handlers/batch-extraction.ts +0 -753
- package/src/memory/job-handlers/extraction.ts +0 -40
- package/src/memory/job-handlers/journal-carry-forward.test.ts +0 -355
- package/src/memory/job-handlers/journal-carry-forward.ts +0 -255
- package/src/memory/journal-memory.ts +0 -224
- package/src/memory/query-builder.ts +0 -47
- package/src/memory/query-expansion.ts +0 -83
- package/src/memory/retriever.test.ts +0 -1592
- package/src/memory/retriever.ts +0 -1331
- package/src/memory/search/formatting.test.ts +0 -140
- package/src/memory/search/formatting.ts +0 -262
- package/src/memory/search/mmr.ts +0 -139
- package/src/memory/search/ranking.ts +0 -15
- package/src/memory/search/staleness.ts +0 -40
- package/src/memory/search/tier-classifier.ts +0 -18
- package/src/memory/search/types.ts +0 -121
- package/src/prompts/journal-context.ts +0 -154
- package/src/tools/memory/definitions.ts +0 -69
- package/src/tools/memory/handlers.test.ts +0 -562
- package/src/tools/memory/handlers.ts +0 -434
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Outlook Calendar watcher provider — uses Microsoft Graph delta queries
|
|
3
|
+
* for efficient change detection.
|
|
4
|
+
*
|
|
5
|
+
* On first poll, performs a delta query to capture the initial @odata.deltaLink
|
|
6
|
+
* as the watermark (start from "now"). Subsequent polls use the deltaLink to
|
|
7
|
+
* detect new/updated events. Falls back to a fresh delta query if the delta
|
|
8
|
+
* token has expired (410 Gone).
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { OutlookCalendarApiError } from "../../config/bundled-skills/outlook-calendar/calendar-client.js";
|
|
12
|
+
import type { OutlookCalendarEvent } from "../../config/bundled-skills/outlook-calendar/types.js";
|
|
13
|
+
import type { OAuthConnection } from "../../oauth/connection.js";
|
|
14
|
+
import { resolveOAuthConnection } from "../../oauth/connection-resolver.js";
|
|
15
|
+
import { getLogger } from "../../util/logger.js";
|
|
16
|
+
import type {
|
|
17
|
+
FetchResult,
|
|
18
|
+
WatcherItem,
|
|
19
|
+
WatcherProvider,
|
|
20
|
+
} from "../provider-types.js";
|
|
21
|
+
|
|
22
|
+
const CREDENTIAL_SERVICE = "outlook";
|
|
23
|
+
const log = getLogger("watcher:outlook-calendar");
|
|
24
|
+
|
|
25
|
+
const DELTA_SELECT_FIELDS = [
|
|
26
|
+
"subject",
|
|
27
|
+
"start",
|
|
28
|
+
"end",
|
|
29
|
+
"location",
|
|
30
|
+
"bodyPreview",
|
|
31
|
+
"isAllDay",
|
|
32
|
+
"showAs",
|
|
33
|
+
"organizer",
|
|
34
|
+
"attendees",
|
|
35
|
+
"webLink",
|
|
36
|
+
"createdDateTime",
|
|
37
|
+
"lastModifiedDateTime",
|
|
38
|
+
"isCancelled",
|
|
39
|
+
"type",
|
|
40
|
+
].join(",");
|
|
41
|
+
|
|
42
|
+
function eventToItem(
|
|
43
|
+
event: OutlookCalendarEvent,
|
|
44
|
+
eventType: string,
|
|
45
|
+
): WatcherItem {
|
|
46
|
+
const start = event.start?.dateTime ?? "";
|
|
47
|
+
const end = event.end?.dateTime ?? "";
|
|
48
|
+
|
|
49
|
+
// Include lastModifiedDateTime in the dedup key so subsequent edits to the
|
|
50
|
+
// same event aren't silently dropped by the watcher_id + external_id constraint.
|
|
51
|
+
const version = event.lastModifiedDateTime ?? "";
|
|
52
|
+
const externalId = version ? `${event.id}@${version}` : event.id;
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
externalId,
|
|
56
|
+
eventType,
|
|
57
|
+
summary: `Calendar event: ${event.subject ?? "(no title)"} — ${start}`,
|
|
58
|
+
payload: {
|
|
59
|
+
id: event.id,
|
|
60
|
+
subject: event.subject ?? "",
|
|
61
|
+
start,
|
|
62
|
+
end,
|
|
63
|
+
startTimeZone: event.start?.timeZone ?? "",
|
|
64
|
+
endTimeZone: event.end?.timeZone ?? "",
|
|
65
|
+
location: event.location?.displayName ?? "",
|
|
66
|
+
bodyPreview: event.bodyPreview ?? "",
|
|
67
|
+
isAllDay: event.isAllDay ?? false,
|
|
68
|
+
showAs: event.showAs ?? "busy",
|
|
69
|
+
organizer: event.organizer?.emailAddress?.address ?? "",
|
|
70
|
+
attendees:
|
|
71
|
+
event.attendees?.map((a) => ({
|
|
72
|
+
email: a.emailAddress.address,
|
|
73
|
+
response: a.status?.response,
|
|
74
|
+
})) ?? [],
|
|
75
|
+
webLink: event.webLink ?? "",
|
|
76
|
+
},
|
|
77
|
+
timestamp: event.lastModifiedDateTime
|
|
78
|
+
? new Date(event.lastModifiedDateTime).getTime()
|
|
79
|
+
: Date.now(),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Thrown when Microsoft Graph returns 410 Gone (delta token expired). */
|
|
84
|
+
class DeltaSyncExpiredError extends Error {
|
|
85
|
+
constructor(message: string) {
|
|
86
|
+
super(message);
|
|
87
|
+
this.name = "DeltaSyncExpiredError";
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
interface DeltaSyncResult {
|
|
92
|
+
items: OutlookCalendarEvent[];
|
|
93
|
+
deltaLink: string;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Perform an incremental delta sync using a stored @odata.deltaLink.
|
|
98
|
+
* Follows pagination (@odata.nextLink) until the final page returns
|
|
99
|
+
* @odata.deltaLink. Returns all accumulated events and the new deltaLink.
|
|
100
|
+
*/
|
|
101
|
+
async function deltaSync(
|
|
102
|
+
connection: OAuthConnection,
|
|
103
|
+
deltaLink: string,
|
|
104
|
+
): Promise<DeltaSyncResult> {
|
|
105
|
+
const allItems: OutlookCalendarEvent[] = [];
|
|
106
|
+
let currentUrl = deltaLink;
|
|
107
|
+
let newDeltaLink: string | undefined;
|
|
108
|
+
|
|
109
|
+
do {
|
|
110
|
+
const parsed = new URL(currentUrl);
|
|
111
|
+
const path = parsed.pathname;
|
|
112
|
+
const query: Record<string, string> = {};
|
|
113
|
+
parsed.searchParams.forEach((v, k) => {
|
|
114
|
+
query[k] = v;
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
const resp = await connection.request({
|
|
118
|
+
method: "GET",
|
|
119
|
+
path,
|
|
120
|
+
query: Object.keys(query).length > 0 ? query : undefined,
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
if (resp.status < 200 || resp.status >= 300) {
|
|
124
|
+
const bodyStr =
|
|
125
|
+
typeof resp.body === "string"
|
|
126
|
+
? resp.body
|
|
127
|
+
: JSON.stringify(resp.body ?? "");
|
|
128
|
+
if (resp.status === 410) {
|
|
129
|
+
throw new DeltaSyncExpiredError(bodyStr);
|
|
130
|
+
}
|
|
131
|
+
throw new OutlookCalendarApiError(
|
|
132
|
+
resp.status,
|
|
133
|
+
"",
|
|
134
|
+
`Microsoft Graph Calendar Delta API ${resp.status}: ${bodyStr}`,
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const page = resp.body as {
|
|
139
|
+
value?: OutlookCalendarEvent[];
|
|
140
|
+
"@odata.nextLink"?: string;
|
|
141
|
+
"@odata.deltaLink"?: string;
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
if (page.value) {
|
|
145
|
+
allItems.push(...page.value);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
newDeltaLink = page["@odata.deltaLink"];
|
|
149
|
+
currentUrl = page["@odata.nextLink"] ?? "";
|
|
150
|
+
} while (currentUrl && !newDeltaLink);
|
|
151
|
+
|
|
152
|
+
if (!newDeltaLink) {
|
|
153
|
+
throw new Error(
|
|
154
|
+
"Outlook Calendar delta query completed without returning a deltaLink",
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return { items: allItems, deltaLink: newDeltaLink };
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Perform the initial delta query to capture the current position.
|
|
163
|
+
* Queries calendarView/delta from now to 30 days out with the selected fields,
|
|
164
|
+
* paginating through all pages until reaching the final @odata.deltaLink.
|
|
165
|
+
*/
|
|
166
|
+
async function initialDeltaQuery(
|
|
167
|
+
connection: OAuthConnection,
|
|
168
|
+
): Promise<DeltaSyncResult> {
|
|
169
|
+
const now = new Date();
|
|
170
|
+
const thirtyDaysOut = new Date(now.getTime() + 30 * 24 * 60 * 60 * 1000);
|
|
171
|
+
|
|
172
|
+
const allItems: OutlookCalendarEvent[] = [];
|
|
173
|
+
let nextLink: string | undefined;
|
|
174
|
+
let newDeltaLink: string | undefined;
|
|
175
|
+
|
|
176
|
+
// First request — initial delta query with parameters
|
|
177
|
+
const initialQuery: Record<string, string> = {
|
|
178
|
+
startDateTime: now.toISOString(),
|
|
179
|
+
endDateTime: thirtyDaysOut.toISOString(),
|
|
180
|
+
$select: DELTA_SELECT_FIELDS,
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
const firstResp = await connection.request({
|
|
184
|
+
method: "GET",
|
|
185
|
+
path: "/v1.0/me/calendarView/delta",
|
|
186
|
+
query: initialQuery,
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
if (firstResp.status < 200 || firstResp.status >= 300) {
|
|
190
|
+
const bodyStr =
|
|
191
|
+
typeof firstResp.body === "string"
|
|
192
|
+
? firstResp.body
|
|
193
|
+
: JSON.stringify(firstResp.body ?? "");
|
|
194
|
+
throw new OutlookCalendarApiError(
|
|
195
|
+
firstResp.status,
|
|
196
|
+
"",
|
|
197
|
+
`Microsoft Graph Calendar Delta API ${firstResp.status}: ${bodyStr}`,
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const firstPage = firstResp.body as {
|
|
202
|
+
value?: OutlookCalendarEvent[];
|
|
203
|
+
"@odata.nextLink"?: string;
|
|
204
|
+
"@odata.deltaLink"?: string;
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
if (firstPage.value) {
|
|
208
|
+
allItems.push(...firstPage.value);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
newDeltaLink = firstPage["@odata.deltaLink"];
|
|
212
|
+
nextLink = firstPage["@odata.nextLink"];
|
|
213
|
+
|
|
214
|
+
// Follow pagination until we get a deltaLink
|
|
215
|
+
while (nextLink && !newDeltaLink) {
|
|
216
|
+
const parsed = new URL(nextLink);
|
|
217
|
+
const path = parsed.pathname;
|
|
218
|
+
const query: Record<string, string> = {};
|
|
219
|
+
parsed.searchParams.forEach((v, k) => {
|
|
220
|
+
query[k] = v;
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
const resp = await connection.request({
|
|
224
|
+
method: "GET",
|
|
225
|
+
path,
|
|
226
|
+
query: Object.keys(query).length > 0 ? query : undefined,
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
if (resp.status < 200 || resp.status >= 300) {
|
|
230
|
+
const bodyStr =
|
|
231
|
+
typeof resp.body === "string"
|
|
232
|
+
? resp.body
|
|
233
|
+
: JSON.stringify(resp.body ?? "");
|
|
234
|
+
throw new OutlookCalendarApiError(
|
|
235
|
+
resp.status,
|
|
236
|
+
"",
|
|
237
|
+
`Microsoft Graph Calendar Delta API ${resp.status}: ${bodyStr}`,
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const page = resp.body as {
|
|
242
|
+
value?: OutlookCalendarEvent[];
|
|
243
|
+
"@odata.nextLink"?: string;
|
|
244
|
+
"@odata.deltaLink"?: string;
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
if (page.value) {
|
|
248
|
+
allItems.push(...page.value);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
newDeltaLink = page["@odata.deltaLink"];
|
|
252
|
+
nextLink = page["@odata.nextLink"];
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
if (!newDeltaLink) {
|
|
256
|
+
throw new Error(
|
|
257
|
+
"Outlook Calendar initial delta query completed without returning a deltaLink",
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return { items: allItems, deltaLink: newDeltaLink };
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export const outlookCalendarProvider: WatcherProvider = {
|
|
265
|
+
id: "outlook-calendar",
|
|
266
|
+
displayName: "Outlook Calendar",
|
|
267
|
+
requiredCredentialService: CREDENTIAL_SERVICE,
|
|
268
|
+
|
|
269
|
+
async getInitialWatermark(credentialService: string): Promise<string> {
|
|
270
|
+
const connection = await resolveOAuthConnection(credentialService);
|
|
271
|
+
const { deltaLink } = await initialDeltaQuery(connection);
|
|
272
|
+
return deltaLink;
|
|
273
|
+
},
|
|
274
|
+
|
|
275
|
+
async fetchNew(
|
|
276
|
+
credentialService: string,
|
|
277
|
+
watermark: string | null,
|
|
278
|
+
_config: Record<string, unknown>,
|
|
279
|
+
_watcherKey: string,
|
|
280
|
+
): Promise<FetchResult> {
|
|
281
|
+
const connection = await resolveOAuthConnection(credentialService);
|
|
282
|
+
|
|
283
|
+
if (!watermark) {
|
|
284
|
+
// No watermark — get initial position, return no items
|
|
285
|
+
const { deltaLink } = await initialDeltaQuery(connection);
|
|
286
|
+
return { items: [], watermark: deltaLink };
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
try {
|
|
290
|
+
const { items: events, deltaLink: newDeltaLink } = await deltaSync(
|
|
291
|
+
connection,
|
|
292
|
+
watermark,
|
|
293
|
+
);
|
|
294
|
+
|
|
295
|
+
if (events.length === 0) {
|
|
296
|
+
return { items: [], watermark: newDeltaLink };
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Filter out cancelled events and convert to watcher items
|
|
300
|
+
const items: WatcherItem[] = [];
|
|
301
|
+
for (const event of events) {
|
|
302
|
+
if (event.isCancelled) continue;
|
|
303
|
+
|
|
304
|
+
const eventType =
|
|
305
|
+
event.createdDateTime === event.lastModifiedDateTime
|
|
306
|
+
? "new_calendar_event"
|
|
307
|
+
: "updated_calendar_event";
|
|
308
|
+
items.push(eventToItem(event, eventType));
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
log.info(
|
|
312
|
+
{ count: items.length, watermark: newDeltaLink },
|
|
313
|
+
"Outlook Calendar: fetched event changes",
|
|
314
|
+
);
|
|
315
|
+
|
|
316
|
+
return { items, watermark: newDeltaLink };
|
|
317
|
+
} catch (err) {
|
|
318
|
+
if (err instanceof DeltaSyncExpiredError) {
|
|
319
|
+
log.warn(
|
|
320
|
+
"Outlook Calendar delta token expired, falling back to fresh query",
|
|
321
|
+
);
|
|
322
|
+
return fallbackFetch(connection);
|
|
323
|
+
}
|
|
324
|
+
throw err;
|
|
325
|
+
}
|
|
326
|
+
},
|
|
327
|
+
};
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Fallback when delta token expires (410 Gone): perform a fresh initial
|
|
331
|
+
* delta query to get current events and a new deltaLink.
|
|
332
|
+
*/
|
|
333
|
+
async function fallbackFetch(
|
|
334
|
+
connection: OAuthConnection,
|
|
335
|
+
): Promise<FetchResult> {
|
|
336
|
+
const { items: events, deltaLink } = await initialDeltaQuery(connection);
|
|
337
|
+
|
|
338
|
+
const items = events
|
|
339
|
+
.filter((event) => !event.isCancelled)
|
|
340
|
+
.map((event) => eventToItem(event, "new_calendar_event"));
|
|
341
|
+
|
|
342
|
+
return { items, watermark: deltaLink };
|
|
343
|
+
}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Outlook watcher provider — uses Microsoft Graph delta queries for efficient
|
|
3
|
+
* change detection.
|
|
4
|
+
*
|
|
5
|
+
* On first poll, captures the initial deltaLink as the watermark (start from "now").
|
|
6
|
+
* Subsequent polls use the deltaLink to detect new messages.
|
|
7
|
+
* Falls back to listing recent inbox messages if the sync state has expired (410 Gone).
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
listMessages,
|
|
12
|
+
listMessagesDelta,
|
|
13
|
+
OutlookApiError,
|
|
14
|
+
} from "../../messaging/providers/outlook/client.js";
|
|
15
|
+
import type {
|
|
16
|
+
OutlookDeltaResponse,
|
|
17
|
+
OutlookMessage,
|
|
18
|
+
} from "../../messaging/providers/outlook/types.js";
|
|
19
|
+
import type { OAuthConnection } from "../../oauth/connection.js";
|
|
20
|
+
import { resolveOAuthConnection } from "../../oauth/connection-resolver.js";
|
|
21
|
+
import { getLogger } from "../../util/logger.js";
|
|
22
|
+
import type {
|
|
23
|
+
FetchResult,
|
|
24
|
+
WatcherItem,
|
|
25
|
+
WatcherProvider,
|
|
26
|
+
} from "../provider-types.js";
|
|
27
|
+
|
|
28
|
+
const log = getLogger("watcher:outlook");
|
|
29
|
+
|
|
30
|
+
/** Thrown when Microsoft Graph returns 410 Gone (delta sync state expired). */
|
|
31
|
+
export class DeltaSyncExpiredError extends Error {
|
|
32
|
+
constructor(message: string) {
|
|
33
|
+
super(message);
|
|
34
|
+
this.name = "DeltaSyncExpiredError";
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function messageToItem(msg: OutlookMessage): WatcherItem {
|
|
39
|
+
const from =
|
|
40
|
+
msg.from?.emailAddress?.name ||
|
|
41
|
+
msg.from?.emailAddress?.address ||
|
|
42
|
+
"Unknown";
|
|
43
|
+
const subject = msg.subject ?? "(no subject)";
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
externalId: msg.id,
|
|
47
|
+
eventType: "new_email",
|
|
48
|
+
summary: `Email from ${from}: ${subject}`,
|
|
49
|
+
payload: {
|
|
50
|
+
id: msg.id,
|
|
51
|
+
conversationId: msg.conversationId,
|
|
52
|
+
from,
|
|
53
|
+
fromAddress: msg.from?.emailAddress?.address ?? "",
|
|
54
|
+
subject,
|
|
55
|
+
receivedDateTime: msg.receivedDateTime,
|
|
56
|
+
bodyPreview: msg.bodyPreview ?? "",
|
|
57
|
+
isRead: msg.isRead ?? false,
|
|
58
|
+
hasAttachments: msg.hasAttachments ?? false,
|
|
59
|
+
},
|
|
60
|
+
timestamp: msg.receivedDateTime
|
|
61
|
+
? new Date(msg.receivedDateTime).getTime()
|
|
62
|
+
: Date.now(),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Fetch all pages of a delta response, following @odata.nextLink until
|
|
68
|
+
* a @odata.deltaLink is returned.
|
|
69
|
+
*/
|
|
70
|
+
async function fetchAllDeltaPages(
|
|
71
|
+
connection: OAuthConnection,
|
|
72
|
+
folderId: string,
|
|
73
|
+
deltaLink?: string,
|
|
74
|
+
): Promise<{ messages: OutlookMessage[]; newDeltaLink: string }> {
|
|
75
|
+
const messages: OutlookMessage[] = [];
|
|
76
|
+
|
|
77
|
+
let resp: OutlookDeltaResponse<OutlookMessage>;
|
|
78
|
+
try {
|
|
79
|
+
resp = await listMessagesDelta(connection, folderId, deltaLink);
|
|
80
|
+
} catch (err) {
|
|
81
|
+
if (err instanceof OutlookApiError && err.status === 410) {
|
|
82
|
+
throw new DeltaSyncExpiredError(err.message);
|
|
83
|
+
}
|
|
84
|
+
throw err;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (resp.value) {
|
|
88
|
+
messages.push(...resp.value);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Follow pagination until we get a deltaLink
|
|
92
|
+
while (resp["@odata.nextLink"] && !resp["@odata.deltaLink"]) {
|
|
93
|
+
try {
|
|
94
|
+
resp = await listMessagesDelta(
|
|
95
|
+
connection,
|
|
96
|
+
folderId,
|
|
97
|
+
resp["@odata.nextLink"],
|
|
98
|
+
);
|
|
99
|
+
} catch (err) {
|
|
100
|
+
if (err instanceof OutlookApiError && err.status === 410) {
|
|
101
|
+
throw new DeltaSyncExpiredError(
|
|
102
|
+
err instanceof Error ? err.message : String(err),
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
throw err;
|
|
106
|
+
}
|
|
107
|
+
if (resp.value) {
|
|
108
|
+
messages.push(...resp.value);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const newDeltaLink = resp["@odata.deltaLink"];
|
|
113
|
+
if (!newDeltaLink) {
|
|
114
|
+
throw new Error(
|
|
115
|
+
"Outlook delta query completed without returning a deltaLink",
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return { messages, newDeltaLink };
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export const outlookProvider: WatcherProvider = {
|
|
123
|
+
id: "outlook",
|
|
124
|
+
displayName: "Outlook",
|
|
125
|
+
requiredCredentialService: "outlook",
|
|
126
|
+
|
|
127
|
+
async getInitialWatermark(credentialService: string): Promise<string> {
|
|
128
|
+
const connection = await resolveOAuthConnection(credentialService);
|
|
129
|
+
const { newDeltaLink } = await fetchAllDeltaPages(connection, "inbox");
|
|
130
|
+
return newDeltaLink;
|
|
131
|
+
},
|
|
132
|
+
|
|
133
|
+
async fetchNew(
|
|
134
|
+
credentialService: string,
|
|
135
|
+
watermark: string | null,
|
|
136
|
+
_config: Record<string, unknown>,
|
|
137
|
+
_watcherKey: string,
|
|
138
|
+
): Promise<FetchResult> {
|
|
139
|
+
const connection = await resolveOAuthConnection(credentialService);
|
|
140
|
+
|
|
141
|
+
if (!watermark) {
|
|
142
|
+
// No watermark — get initial position, return no items
|
|
143
|
+
const { newDeltaLink } = await fetchAllDeltaPages(connection, "inbox");
|
|
144
|
+
return { items: [], watermark: newDeltaLink };
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
try {
|
|
148
|
+
const { messages, newDeltaLink } = await fetchAllDeltaPages(
|
|
149
|
+
connection,
|
|
150
|
+
"inbox",
|
|
151
|
+
watermark,
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
if (messages.length === 0) {
|
|
155
|
+
return { items: [], watermark: newDeltaLink };
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const items = messages.map(messageToItem);
|
|
159
|
+
log.info(
|
|
160
|
+
{ count: items.length, watermark: newDeltaLink },
|
|
161
|
+
"Outlook: fetched new messages",
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
return { items, watermark: newDeltaLink };
|
|
165
|
+
} catch (err) {
|
|
166
|
+
if (err instanceof DeltaSyncExpiredError) {
|
|
167
|
+
log.warn(
|
|
168
|
+
"Outlook delta sync state expired, falling back to recent inbox messages",
|
|
169
|
+
);
|
|
170
|
+
return fallbackFetch(connection);
|
|
171
|
+
}
|
|
172
|
+
throw err;
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Fallback when sync state expires (410 Gone): list recent inbox messages
|
|
179
|
+
* from the last day, then get a fresh deltaLink.
|
|
180
|
+
*/
|
|
181
|
+
async function fallbackFetch(
|
|
182
|
+
connection: OAuthConnection,
|
|
183
|
+
): Promise<FetchResult> {
|
|
184
|
+
const oneDayAgo = new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString();
|
|
185
|
+
const resp = await listMessages(connection, {
|
|
186
|
+
folderId: "inbox",
|
|
187
|
+
top: 20,
|
|
188
|
+
filter: `receivedDateTime ge ${oneDayAgo}`,
|
|
189
|
+
orderby: "receivedDateTime desc",
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
const items = (resp.value ?? []).map(messageToItem);
|
|
193
|
+
|
|
194
|
+
// Get a fresh deltaLink for the new watermark
|
|
195
|
+
const { newDeltaLink } = await fetchAllDeltaPages(connection, "inbox");
|
|
196
|
+
|
|
197
|
+
return { items, watermark: newDeltaLink };
|
|
198
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workspace migration 025: Remove standalone OAuth app setup skill directories
|
|
3
|
+
* and their SKILLS.md entries from user workspaces.
|
|
4
|
+
*
|
|
5
|
+
* These skills have been consolidated into vellum-oauth-integrations and are
|
|
6
|
+
* no longer shipped as standalone skills.
|
|
7
|
+
*
|
|
8
|
+
* Idempotent: safe to re-run after interruption at any point.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { existsSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
12
|
+
import { join } from "node:path";
|
|
13
|
+
|
|
14
|
+
import type { WorkspaceMigration } from "./types.js";
|
|
15
|
+
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
// Skills to remove
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
|
|
20
|
+
const DELETED_SKILLS = [
|
|
21
|
+
"airtable-oauth-app-setup",
|
|
22
|
+
"asana-oauth-app-setup",
|
|
23
|
+
"discord-oauth-app-setup",
|
|
24
|
+
"dropbox-oauth-app-setup",
|
|
25
|
+
"figma-oauth-app-setup",
|
|
26
|
+
"github-oauth-app-setup",
|
|
27
|
+
"google-oauth-app-setup",
|
|
28
|
+
"hubspot-oauth-app-setup",
|
|
29
|
+
"linear-oauth-app-setup",
|
|
30
|
+
"notion-oauth-app-setup",
|
|
31
|
+
"spotify-oauth-app-setup",
|
|
32
|
+
"todoist-oauth-app-setup",
|
|
33
|
+
"twitter-oauth-app-setup",
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
// Migration
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
|
|
40
|
+
export const removeOauthAppSetupSkillsMigration: WorkspaceMigration = {
|
|
41
|
+
id: "025-remove-oauth-app-setup-skills",
|
|
42
|
+
description:
|
|
43
|
+
"Remove standalone OAuth app setup skill directories consolidated into vellum-oauth-integrations",
|
|
44
|
+
|
|
45
|
+
run(workspaceDir: string): void {
|
|
46
|
+
const skillsDir = join(workspaceDir, "skills");
|
|
47
|
+
if (!existsSync(skillsDir)) return;
|
|
48
|
+
|
|
49
|
+
// 1. Remove skill directories
|
|
50
|
+
for (const name of DELETED_SKILLS) {
|
|
51
|
+
const dir = join(skillsDir, name);
|
|
52
|
+
if (existsSync(dir)) {
|
|
53
|
+
rmSync(dir, { recursive: true, force: true });
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// 2. Update SKILLS.md to remove entries referencing deleted skills
|
|
58
|
+
const indexPath = join(skillsDir, "SKILLS.md");
|
|
59
|
+
if (existsSync(indexPath)) {
|
|
60
|
+
let content = readFileSync(indexPath, "utf-8");
|
|
61
|
+
for (const name of DELETED_SKILLS) {
|
|
62
|
+
content = content.replace(
|
|
63
|
+
new RegExp(`^[\\t ]*-\\s*${name}\\s*\\n?`, "gm"),
|
|
64
|
+
"",
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
writeFileSync(indexPath, content, "utf-8");
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
down(_workspaceDir: string): void {
|
|
72
|
+
// Deleted skills cannot be restored since they have been removed from the
|
|
73
|
+
// repo. Users would need to reinstall the `vellum-oauth-integrations`
|
|
74
|
+
// skill to regain the consolidated OAuth setup functionality.
|
|
75
|
+
},
|
|
76
|
+
};
|