@vellumai/assistant 0.5.16 → 0.6.1
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/AGENTS.md +4 -0
- package/ARCHITECTURE.md +69 -16
- package/Dockerfile +2 -5
- package/bun.lock +6 -2
- package/docker-entrypoint.sh +32 -1
- package/docs/architecture/integrations.md +1 -1
- package/docs/architecture/memory.md +21 -24
- package/knip.json +2 -1
- package/openapi.yaml +1198 -83
- package/package.json +5 -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 +217 -98
- package/src/__tests__/app-compiler.test.ts +120 -0
- package/src/__tests__/app-dir-path-guard.test.ts +1 -0
- package/src/__tests__/app-executors.test.ts +47 -1
- package/src/__tests__/app-source-watcher.test.ts +159 -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 +63 -9
- package/src/__tests__/clawhub.test.ts +54 -24
- package/src/__tests__/cli-command-risk-guard.test.ts +14 -0
- package/src/__tests__/config-schema.test.ts +6 -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 +13 -6
- package/src/__tests__/conversation-agent-loop.test.ts +13 -51
- 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 +6 -1
- 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-runtime-assembly.test.ts +653 -832
- package/src/__tests__/conversation-runtime-workspace.test.ts +1 -93
- package/src/__tests__/conversation-starter-routes.test.ts +20 -11
- package/src/__tests__/conversation-store.test.ts +2 -6
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +17 -4
- package/src/__tests__/conversation-usage.test.ts +2 -6
- package/src/__tests__/conversation-wipe.test.ts +13 -414
- package/src/__tests__/conversation-workspace-cache-state.test.ts +6 -12
- package/src/__tests__/conversation-workspace-injection.test.ts +25 -26
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +1 -1
- package/src/__tests__/copy-composer-tc-templates.test.ts +335 -0
- 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__/date-context.test.ts +76 -210
- package/src/__tests__/db-schedule-syntax-migration.test.ts +16 -1
- package/src/__tests__/file-list-tool.test.ts +219 -0
- package/src/__tests__/first-greeting.test.ts +1 -1
- 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__/heartbeat-service.test.ts +180 -3
- package/src/__tests__/identity-routes.test.ts +328 -0
- package/src/__tests__/inbound-invite-redemption.test.ts +2 -6
- package/src/__tests__/injection-block.test.ts +178 -0
- package/src/__tests__/install-meta.test.ts +506 -0
- package/src/__tests__/install-skill-routing.test.ts +293 -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 +17 -28
- package/src/__tests__/list-messages-attachments.test.ts +2 -6
- package/src/__tests__/list-messages-tool-merge.test.ts +300 -0
- package/src/__tests__/llm-context-normalization.test.ts +18 -18
- package/src/__tests__/llm-context-route-provider.test.ts +103 -6
- package/src/__tests__/llm-request-log-turn-query.test.ts +164 -6
- package/src/__tests__/llm-usage-store.test.ts +2 -6
- package/src/__tests__/log-export-workspace.test.ts +74 -111
- package/src/__tests__/managed-store.test.ts +38 -11
- package/src/__tests__/mcp-abort-signal.test.ts +5 -0
- package/src/__tests__/mcp-client-auth.test.ts +5 -0
- package/src/__tests__/memory-jobs-worker-backoff.test.ts +2 -8
- package/src/__tests__/memory-recall-log-store.test.ts +134 -6
- package/src/__tests__/memory-upsert-concurrency.test.ts +4 -112
- package/src/__tests__/migration-export-streaming.test.ts +304 -0
- package/src/__tests__/migration-import-commit-http.test.ts +11 -10
- package/src/__tests__/mock-fetch.ts +87 -0
- package/src/__tests__/non-member-access-request.test.ts +2 -6
- package/src/__tests__/notification-decision-recipient-context.test.ts +282 -0
- 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__/onboarding-template-contract.test.ts +62 -14
- 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__/parser.test.ts +32 -0
- package/src/__tests__/permission-checker-host-gate.test.ts +452 -0
- package/src/__tests__/permission-controls-v2-flag.test.ts +55 -0
- package/src/__tests__/permission-mode-sse.test.ts +418 -0
- package/src/__tests__/permission-mode-store.test.ts +277 -0
- package/src/__tests__/permission-mode.test.ts +101 -0
- package/src/__tests__/platform-bash-auto-approve.test.ts +359 -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__/profiler-routes.test.ts +502 -0
- package/src/__tests__/profiler-run-store.test.ts +441 -0
- package/src/__tests__/provider-error-scenarios.test.ts +21 -0
- package/src/__tests__/proxy-approval-callback.test.ts +4 -75
- package/src/__tests__/rebuild-index-graph-nodes.test.ts +273 -0
- package/src/__tests__/registry.test.ts +3 -3
- 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__/sandbox-host-parity.test.ts +5 -4
- 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__/scheduler-reuse-conversation.test.ts +368 -0
- package/src/__tests__/scoped-approval-grants.test.ts +2 -6
- package/src/__tests__/scoped-grant-security-matrix.test.ts +2 -6
- package/src/__tests__/scrub-corrupted-image-attachments.test.ts +278 -0
- package/src/__tests__/search-skills-unified.test.ts +422 -0
- package/src/__tests__/secret-onetime-send.test.ts +2 -0
- package/src/__tests__/send-endpoint-busy.test.ts +44 -9
- package/src/__tests__/sequence-store.test.ts +2 -6
- package/src/__tests__/server-history-render.test.ts +2 -6
- package/src/__tests__/set-permission-mode.test.ts +274 -0
- 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 +23 -11
- package/src/__tests__/skill-memory.test.ts +2 -741
- 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__/strip-memory-injections.test.ts +187 -0
- package/src/__tests__/subagent-detail.test.ts +84 -0
- package/src/__tests__/subagent-disposal.test.ts +308 -0
- package/src/__tests__/subagent-manager-notify.test.ts +19 -10
- package/src/__tests__/subagent-notify-parent.test.ts +390 -0
- package/src/__tests__/subagent-role-registry.test.ts +108 -0
- package/src/__tests__/subagent-tool-filtering.test.ts +71 -0
- package/src/__tests__/subagent-tools.test.ts +464 -4
- package/src/__tests__/system-prompt-ask-mode.test.ts +139 -0
- 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 +185 -241
- package/src/__tests__/task-runner.test.ts +2 -6
- package/src/__tests__/task-scheduler.test.ts +2 -6
- package/src/__tests__/terminal-tools.test.ts +17 -27
- package/src/__tests__/test-preload.ts +7 -0
- package/src/__tests__/tool-approval-handler.test.ts +2 -6
- package/src/__tests__/tool-executor.test.ts +4 -26
- package/src/__tests__/tool-grant-request-escalation.test.ts +2 -6
- package/src/__tests__/tool-side-effects-slack-dm.test.ts +277 -0
- package/src/__tests__/top-level-renderer.test.ts +10 -13
- 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 +118 -8
- 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-migration-028-recover-conversations-from-disk-view.test.ts +387 -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 +7 -15
- package/src/approvals/guardian-request-resolvers.ts +24 -0
- package/src/avatar/traits-png-sync.ts +3 -3
- 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/__tests__/run-assistant-command.ts +29 -0
- package/src/cli/commands/__tests__/email-download.test.ts +245 -0
- package/src/cli/commands/__tests__/email-list.test.ts +192 -0
- package/src/cli/commands/__tests__/email-register.test.ts +186 -0
- package/src/cli/commands/__tests__/email-send.test.ts +291 -0
- package/src/cli/commands/__tests__/email-status.test.ts +181 -0
- package/src/cli/commands/__tests__/email-unregister.test.ts +139 -0
- package/src/cli/commands/__tests__/routes.test.ts +562 -0
- package/src/cli/commands/avatar.ts +3 -3
- package/src/cli/commands/config.ts +26 -13
- package/src/cli/commands/conversations.ts +1 -8
- package/src/cli/commands/doctor.ts +2 -2
- package/src/cli/commands/email.ts +584 -835
- package/src/cli/commands/memory.ts +37 -84
- package/src/cli/commands/notifications.ts +7 -2
- 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 +25 -11
- 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/routes.ts +396 -0
- package/src/cli/commands/skills.ts +218 -36
- package/src/cli/commands/trust.ts +2 -2
- package/src/cli/lib/daemon-credential-client.ts +2 -3
- package/src/cli/program.ts +2 -0
- package/src/cli.ts +1 -120
- package/src/config/bundled-skills/acp/TOOLS.json +1 -1
- package/src/config/bundled-skills/app-builder/SKILL.md +4 -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 +4 -12
- package/src/config/bundled-skills/google-calendar/SKILL.md +1 -9
- package/src/config/bundled-skills/messaging/SKILL.md +17 -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/schedule/SKILL.md +22 -2
- package/src/config/bundled-skills/schedule/TOOLS.json +8 -0
- package/src/config/bundled-skills/settings/tools/avatar-get.ts +3 -13
- package/src/config/bundled-skills/settings/tools/avatar-remove.ts +2 -4
- package/src/config/bundled-skills/settings/tools/avatar-update.ts +5 -2
- package/src/config/bundled-skills/slack/SKILL.md +3 -7
- package/src/config/bundled-skills/subagent/SKILL.md +43 -3
- package/src/config/bundled-skills/subagent/TOOLS.json +29 -4
- package/src/config/bundled-tool-registry.ts +56 -4
- package/src/config/env-registry.ts +78 -8
- package/src/config/feature-flag-registry.json +38 -125
- package/src/config/schema.ts +8 -0
- package/src/config/schemas/filing.ts +51 -0
- package/src/config/schemas/heartbeat.ts +15 -12
- package/src/config/schemas/memory-lifecycle.ts +12 -0
- package/src/config/schemas/platform.ts +8 -0
- package/src/config/schemas/security.ts +14 -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/app-source-watcher.ts +93 -0
- package/src/daemon/config-watcher.ts +79 -1
- package/src/daemon/context-overflow-reducer.ts +46 -2
- package/src/daemon/conversation-agent-loop-handlers.ts +143 -82
- package/src/daemon/conversation-agent-loop.ts +236 -108
- package/src/daemon/conversation-error.ts +31 -8
- package/src/daemon/conversation-history.ts +4 -19
- package/src/daemon/conversation-lifecycle.ts +36 -9
- package/src/daemon/conversation-media-retry.ts +85 -7
- package/src/daemon/conversation-notifiers.ts +4 -1
- package/src/daemon/conversation-process.ts +13 -7
- package/src/daemon/conversation-runtime-assembly.ts +305 -306
- package/src/daemon/conversation-tool-setup.ts +44 -14
- package/src/daemon/conversation-workspace.ts +1 -2
- package/src/daemon/conversation.ts +59 -2
- package/src/daemon/daemon-control.ts +8 -2
- package/src/daemon/date-context.ts +26 -53
- package/src/daemon/first-greeting.ts +1 -1
- package/src/daemon/handlers/conversations.ts +4 -7
- package/src/daemon/handlers/shared.test.ts +143 -0
- package/src/daemon/handlers/shared.ts +85 -17
- package/src/daemon/handlers/skills.ts +416 -209
- package/src/daemon/lifecycle.ts +212 -131
- package/src/daemon/main.ts +5 -1
- package/src/daemon/message-types/conversations.ts +29 -7
- package/src/daemon/message-types/messages.ts +12 -2
- package/src/daemon/message-types/schedules.ts +1 -0
- package/src/daemon/message-types/settings.ts +6 -0
- package/src/daemon/message-types/skills.ts +97 -36
- package/src/daemon/profiler-run-store.ts +557 -0
- package/src/daemon/providers-setup.ts +5 -0
- package/src/daemon/server.ts +100 -11
- package/src/daemon/shutdown-handlers.ts +5 -0
- package/src/daemon/tool-side-effects.ts +50 -8
- package/src/export/transcript-formatter.ts +148 -0
- package/src/filing/filing-service.ts +228 -0
- package/src/heartbeat/heartbeat-service.ts +97 -7
- 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/mcp/client.ts +6 -0
- package/src/mcp/mcp-oauth-provider.ts +149 -27
- package/src/memory/admin.ts +42 -75
- package/src/memory/app-store.ts +69 -0
- package/src/memory/conversation-bootstrap.ts +3 -1
- package/src/memory/conversation-crud.ts +211 -288
- package/src/memory/conversation-group-migration.ts +157 -0
- package/src/memory/conversation-queries.ts +61 -13
- package/src/memory/conversation-title-service.ts +1 -0
- package/src/memory/db-init.ts +194 -361
- 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 +521 -0
- package/src/memory/graph/capability-seed.ts +449 -0
- package/src/memory/graph/consolidation.ts +725 -0
- package/src/memory/graph/conversation-graph-memory.ts +659 -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 +74 -0
- package/src/memory/graph/extraction.test.ts +936 -0
- package/src/memory/graph/extraction.ts +1297 -0
- package/src/memory/graph/graph-memory-state-store.ts +37 -0
- package/src/memory/graph/graph-search.ts +280 -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 +469 -0
- package/src/memory/graph/inspect.ts +543 -0
- package/src/memory/graph/narrative.ts +267 -0
- package/src/memory/graph/pattern-scan.ts +269 -0
- package/src/memory/graph/retriever.ts +1111 -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 +1098 -0
- package/src/memory/graph/store.ts +838 -0
- package/src/memory/graph/tool-handlers.ts +301 -0
- package/src/memory/graph/tools.ts +97 -0
- package/src/memory/graph/triggers.test.ts +487 -0
- package/src/memory/graph/triggers.ts +223 -0
- package/src/memory/graph/types.ts +295 -0
- package/src/memory/group-crud.ts +191 -0
- package/src/memory/indexer.ts +37 -19
- package/src/memory/job-handlers/cleanup.ts +32 -42
- 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 +21 -31
- package/src/memory/jobs-worker.ts +180 -129
- package/src/memory/llm-request-log-store.ts +96 -12
- package/src/memory/memory-recall-log-store.ts +49 -5
- 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 +55 -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/206-memory-graph-node-edits.ts +19 -0
- package/src/memory/migrations/206-scrub-corrupted-image-attachments.ts +131 -0
- package/src/memory/migrations/207-conversation-graph-memory-state.ts +20 -0
- package/src/memory/migrations/208-conversations-last-message-at.ts +35 -0
- package/src/memory/migrations/209-strip-thinking-from-consolidated.ts +85 -0
- package/src/memory/migrations/210-schedule-reuse-conversation.ts +13 -0
- package/src/memory/migrations/211-memory-recall-logs-query-context.ts +21 -0
- package/src/memory/migrations/212-llm-request-logs-created-at-index.ts +19 -0
- package/src/memory/migrations/index.ts +12 -0
- package/src/memory/migrations/registry.ts +16 -0
- package/src/memory/qdrant-client.ts +44 -17
- package/src/memory/schema/conversations.ts +14 -0
- package/src/memory/schema/index.ts +1 -0
- package/src/memory/schema/infrastructure.ts +8 -1
- package/src/memory/schema/memory-core.ts +0 -51
- package/src/memory/schema/memory-graph.ts +154 -0
- package/src/memory/search/semantic.ts +47 -91
- package/src/memory/task-memory-cleanup.ts +58 -61
- 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 +95 -0
- package/src/notifications/decision-engine.ts +35 -0
- package/src/notifications/signal.ts +16 -0
- package/src/oauth/seed-providers.ts +2 -1
- package/src/permissions/checker.ts +36 -4
- package/src/permissions/defaults.ts +4 -4
- package/src/permissions/permission-mode-store.ts +180 -0
- package/src/permissions/permission-mode.ts +31 -0
- package/src/permissions/workspace-policy.ts +10 -1
- package/src/playbooks/playbook-compiler.ts +19 -18
- package/src/playbooks/types.ts +4 -3
- package/src/prompts/system-prompt.ts +62 -36
- package/src/prompts/templates/BOOTSTRAP-REFERENCE.md +100 -0
- package/src/prompts/templates/BOOTSTRAP.md +70 -165
- package/src/prompts/templates/HEARTBEAT.md +3 -1
- package/src/prompts/templates/SOUL.md +25 -4
- package/src/prompts/templates/UPDATES.md +8 -0
- package/src/providers/anthropic/client.ts +136 -220
- 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 +30 -0
- package/src/runtime/guardian-reply-router.ts +5 -1
- package/src/runtime/http-server.ts +55 -5
- package/src/runtime/http-types.ts +12 -1
- package/src/runtime/middleware/auth.ts +20 -0
- package/src/runtime/migrations/vbundle-builder.ts +389 -3
- package/src/runtime/migrations/vbundle-importer.ts +8 -6
- package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +378 -0
- package/src/runtime/routes/app-management-routes.ts +1 -11
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +26 -0
- package/src/runtime/routes/archive-utils.ts +29 -0
- package/src/runtime/routes/attachment-routes.test.ts +106 -0
- package/src/runtime/routes/attachment-routes.ts +106 -16
- package/src/runtime/routes/avatar-routes.ts +2 -9
- package/src/runtime/routes/brain-graph-routes.ts +21 -22
- package/src/runtime/routes/btw-routes.ts +22 -1
- package/src/runtime/routes/conversation-analysis-routes.ts +173 -0
- package/src/runtime/routes/conversation-management-routes.ts +3 -14
- package/src/runtime/routes/conversation-query-routes.ts +49 -3
- package/src/runtime/routes/conversation-routes.ts +264 -44
- 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/heartbeat-routes.ts +4 -10
- package/src/runtime/routes/identity-routes.ts +53 -18
- 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/llm-context-normalization.ts +14 -10
- package/src/runtime/routes/log-export-routes.ts +23 -275
- package/src/runtime/routes/memory-item-routes.test.ts +170 -247
- package/src/runtime/routes/memory-item-routes.ts +341 -388
- package/src/runtime/routes/migration-routes.ts +18 -7
- package/src/runtime/routes/profiler-routes.ts +350 -0
- package/src/runtime/routes/schedule-routes.ts +28 -11
- package/src/runtime/routes/settings-routes.ts +95 -8
- package/src/runtime/routes/skills-routes.ts +103 -37
- package/src/runtime/routes/subagents-routes.ts +28 -7
- package/src/runtime/routes/user-route-dispatcher.ts +223 -0
- package/src/runtime/routes/user-routes.ts +41 -0
- package/src/runtime/routes/work-items-routes.test.ts +2 -6
- package/src/runtime/routes/workspace-routes.ts +0 -1
- package/src/schedule/schedule-store.ts +30 -0
- package/src/schedule/scheduler.ts +52 -18
- 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 +25 -16
- package/src/skills/clawhub.ts +134 -154
- package/src/skills/install-meta.ts +208 -0
- package/src/skills/managed-store.ts +29 -18
- package/src/skills/skill-memory.ts +12 -229
- package/src/skills/skillssh-registry.ts +19 -17
- package/src/subagent/index.ts +13 -3
- package/src/subagent/manager.ts +308 -29
- package/src/subagent/types.ts +68 -0
- package/src/tasks/task-runner.ts +7 -5
- package/src/telemetry/usage-telemetry-reporter.test.ts +3 -5
- package/src/tools/apps/executors.ts +29 -4
- package/src/tools/browser/runtime-check.ts +3 -1
- package/src/tools/filesystem/list.ts +93 -0
- package/src/tools/memory/register.ts +63 -46
- package/src/tools/permission-checker.ts +85 -1
- package/src/tools/registry.ts +4 -0
- package/src/tools/schedule/create.ts +3 -0
- package/src/tools/schedule/list.ts +1 -0
- package/src/tools/schedule/update.ts +6 -0
- package/src/tools/shared/filesystem/errors.ts +5 -0
- package/src/tools/shared/filesystem/file-ops-service.ts +90 -2
- package/src/tools/shared/filesystem/image-read.ts +22 -85
- package/src/tools/shared/filesystem/types.ts +17 -0
- package/src/tools/shared/shell-output.ts +31 -2
- package/src/tools/subagent/abort.ts +12 -2
- package/src/tools/subagent/message.ts +9 -2
- package/src/tools/subagent/notify-parent.ts +79 -0
- package/src/tools/subagent/read.ts +29 -8
- package/src/tools/subagent/resolve.ts +21 -0
- package/src/tools/subagent/spawn.ts +2 -0
- package/src/tools/subagent/status.ts +11 -1
- package/src/tools/system/avatar-generator.ts +3 -3
- package/src/tools/system/register.ts +23 -0
- package/src/tools/system/set-permission-mode.ts +103 -0
- package/src/tools/terminal/parser.ts +30 -5
- package/src/tools/terminal/safe-env.ts +17 -1
- package/src/tools/tool-manifest.ts +9 -3
- package/src/tools/types.ts +2 -0
- package/src/util/browser.ts +25 -10
- package/src/util/bun-runtime.ts +172 -0
- package/src/util/logger.ts +1 -1
- package/src/util/platform.ts +50 -17
- package/src/watcher/providers/outlook-calendar.ts +343 -0
- package/src/watcher/providers/outlook.ts +198 -0
- package/src/workspace/migrations/023-move-config-files-to-workspace.ts +2 -2
- package/src/workspace/migrations/024-move-runtime-files-to-workspace.ts +2 -2
- 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/028-recover-conversations-from-disk-view.ts +270 -0
- package/src/workspace/migrations/029-seed-pkb.ts +84 -0
- package/src/workspace/migrations/registry.ts +10 -0
- package/src/workspace/top-level-renderer.ts +5 -9
- package/src/__tests__/cli-memory.test.ts +0 -372
- package/src/__tests__/clipboard.test.ts +0 -88
- 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/cli/cli-memory.ts +0 -176
- 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
- package/src/util/clipboard.ts +0 -34
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { isHttpAuthDisabled } from "../config/env.js";
|
|
10
|
+
import { getIsPlatform } from "../config/env-registry.js";
|
|
10
11
|
import type { CesClient } from "../credential-execution/client.js";
|
|
11
12
|
import { getBindingByConversation } from "../memory/external-conversation-store.js";
|
|
12
13
|
import {
|
|
@@ -192,6 +193,7 @@ export function createToolExecutor(
|
|
|
192
193
|
toolUseId,
|
|
193
194
|
hostBashProxy: ctx.hostBashProxy,
|
|
194
195
|
hostFileProxy: ctx.hostFileProxy,
|
|
196
|
+
isPlatformHosted: getIsPlatform(),
|
|
195
197
|
cesClient: ctx.cesClient,
|
|
196
198
|
onToolLifecycleEvent: handleToolLifecycleEvent,
|
|
197
199
|
sendToClient: (msg) => {
|
|
@@ -320,8 +322,7 @@ export function createProxyApprovalCallback(
|
|
|
320
322
|
input.matching_patterns = decision.matchingPatterns;
|
|
321
323
|
}
|
|
322
324
|
|
|
323
|
-
const riskLevel =
|
|
324
|
-
decision.kind === "ask_missing_credential" ? "high" : "medium";
|
|
325
|
+
const riskLevel: string = "medium";
|
|
325
326
|
|
|
326
327
|
// Check trust store before prompting — build candidates that mirror
|
|
327
328
|
// buildCommandCandidates() in checker.ts for network_request.
|
|
@@ -342,10 +343,7 @@ export function createProxyApprovalCallback(
|
|
|
342
343
|
);
|
|
343
344
|
if (existingRule && existingRule.decision !== "ask") {
|
|
344
345
|
if (existingRule.decision === "deny") return false;
|
|
345
|
-
|
|
346
|
-
// must fall through to prompting — mirroring the checker's behavior.
|
|
347
|
-
if (riskLevel !== "high" || existingRule.allowHighRisk === true)
|
|
348
|
-
return true;
|
|
346
|
+
return true;
|
|
349
347
|
}
|
|
350
348
|
|
|
351
349
|
// Use the checker's built-in allowlist generation for network_request
|
|
@@ -384,12 +382,13 @@ export function createProxyApprovalCallback(
|
|
|
384
382
|
response.selectedPattern &&
|
|
385
383
|
response.selectedScope
|
|
386
384
|
) {
|
|
385
|
+
const allowHighRisk = response.decision === "always_allow_high_risk";
|
|
387
386
|
log.info(
|
|
388
387
|
{
|
|
389
388
|
toolName,
|
|
390
389
|
pattern: response.selectedPattern,
|
|
391
390
|
scope: response.selectedScope,
|
|
392
|
-
|
|
391
|
+
allowHighRisk,
|
|
393
392
|
},
|
|
394
393
|
"Persisting always-allow trust rule (proxy)",
|
|
395
394
|
);
|
|
@@ -399,9 +398,7 @@ export function createProxyApprovalCallback(
|
|
|
399
398
|
response.selectedScope,
|
|
400
399
|
"allow",
|
|
401
400
|
100,
|
|
402
|
-
|
|
403
|
-
? { allowHighRisk: true }
|
|
404
|
-
: undefined,
|
|
401
|
+
allowHighRisk ? { allowHighRisk: true } : undefined,
|
|
405
402
|
);
|
|
406
403
|
}
|
|
407
404
|
if (
|
|
@@ -436,7 +433,7 @@ export function createProxyApprovalCallback(
|
|
|
436
433
|
* history or explicit preactivation. Without this, their tools are
|
|
437
434
|
* unavailable in fresh conversations until `skill_load` is called.
|
|
438
435
|
*/
|
|
439
|
-
const DEFAULT_PREACTIVATED_SKILL_IDS = ["tasks", "notifications"];
|
|
436
|
+
const DEFAULT_PREACTIVATED_SKILL_IDS = ["tasks", "notifications", "subagent"];
|
|
440
437
|
|
|
441
438
|
/**
|
|
442
439
|
* Subset of Conversation state that the resolveTools callback reads at each
|
|
@@ -454,9 +451,14 @@ export interface SkillProjectionContext {
|
|
|
454
451
|
readonly channelCapabilities?: {
|
|
455
452
|
channel: string;
|
|
456
453
|
supportsDynamicUi: boolean;
|
|
454
|
+
clientOS?: string;
|
|
457
455
|
};
|
|
458
456
|
/** True when no client is connected (HTTP-only). */
|
|
459
457
|
readonly hasNoClient?: boolean;
|
|
458
|
+
/** When set, only tools in this set are included in the resolved tool list (subagent delegation). */
|
|
459
|
+
subagentAllowedTools?: Set<string>;
|
|
460
|
+
/** True when this conversation belongs to a subagent spawned by SubagentManager. */
|
|
461
|
+
readonly isSubagent?: boolean;
|
|
460
462
|
}
|
|
461
463
|
|
|
462
464
|
// ── Conditional tool sets ────────────────────────────────────────────
|
|
@@ -471,6 +473,16 @@ const HOST_TOOL_NAMES = new Set([
|
|
|
471
473
|
const CLIENT_CAPABILITY_TOOL_NAMES = new Set(["app_open"]);
|
|
472
474
|
const PLATFORM_TOOL_NAMES = new Set(["request_system_permission"]);
|
|
473
475
|
|
|
476
|
+
/**
|
|
477
|
+
* Tools that should only be visible to subagent conversations. Main (parent)
|
|
478
|
+
* conversations never see these in the LLM tool definitions. Subsequent PRs
|
|
479
|
+
* will populate this set; it starts empty so there is no behavioral change.
|
|
480
|
+
*/
|
|
481
|
+
export const SUBAGENT_ONLY_TOOL_NAMES = new Set<string>([
|
|
482
|
+
"file_list",
|
|
483
|
+
"notify_parent",
|
|
484
|
+
]);
|
|
485
|
+
|
|
474
486
|
/**
|
|
475
487
|
* Determine whether a tool should be included in the LLM tool definitions
|
|
476
488
|
* for the current turn based on conversation context. Tools not active for the
|
|
@@ -495,7 +507,12 @@ export function isToolActiveForContext(
|
|
|
495
507
|
return !ctx.hasNoClient;
|
|
496
508
|
}
|
|
497
509
|
if (PLATFORM_TOOL_NAMES.has(name)) {
|
|
498
|
-
|
|
510
|
+
// Check the *client's* platform, not the daemon's process.platform.
|
|
511
|
+
// In Docker the daemon runs on Linux but the connected client may be macOS.
|
|
512
|
+
return ctx.channelCapabilities?.clientOS === "macos" && !ctx.hasNoClient;
|
|
513
|
+
}
|
|
514
|
+
if (SUBAGENT_ONLY_TOOL_NAMES.has(name)) {
|
|
515
|
+
return ctx.isSubagent === true;
|
|
499
516
|
}
|
|
500
517
|
return true;
|
|
501
518
|
}
|
|
@@ -548,18 +565,27 @@ export function createResolveToolsCallback(
|
|
|
548
565
|
isToolActiveForContext(d.name, ctx),
|
|
549
566
|
);
|
|
550
567
|
|
|
568
|
+
// When the conversation is acting as a subagent, restrict core tools to
|
|
569
|
+
// only those explicitly allowed by the parent orchestrator.
|
|
570
|
+
const scopedCoreDefs = ctx.subagentAllowedTools
|
|
571
|
+
? filteredCoreDefs.filter((d) => ctx.subagentAllowedTools!.has(d.name))
|
|
572
|
+
: filteredCoreDefs;
|
|
573
|
+
|
|
551
574
|
// Re-read MCP tool definitions from the registry each turn so conversations
|
|
552
575
|
// automatically pick up tools added/removed by `vellum mcp reload`.
|
|
553
576
|
const currentMcpDefs = getMcpToolDefinitions();
|
|
554
577
|
log.debug(
|
|
555
578
|
{
|
|
556
|
-
coreCount:
|
|
579
|
+
coreCount: scopedCoreDefs.length,
|
|
557
580
|
mcpCount: currentMcpDefs.length,
|
|
558
581
|
mcpTools: currentMcpDefs.map((d) => d.name),
|
|
559
582
|
},
|
|
560
583
|
"MCP tools resolved for turn",
|
|
561
584
|
);
|
|
562
|
-
const
|
|
585
|
+
const scopedMcpDefs = ctx.subagentAllowedTools
|
|
586
|
+
? currentMcpDefs.filter((d) => ctx.subagentAllowedTools!.has(d.name))
|
|
587
|
+
: currentMcpDefs;
|
|
588
|
+
const allBaseDefs = [...scopedCoreDefs, ...scopedMcpDefs];
|
|
563
589
|
|
|
564
590
|
const effectivePreactivated = [
|
|
565
591
|
...DEFAULT_PREACTIVATED_SKILL_IDS,
|
|
@@ -572,6 +598,10 @@ export function createResolveToolsCallback(
|
|
|
572
598
|
});
|
|
573
599
|
const turnAllowed = new Set(allBaseDefs.map((d) => d.name));
|
|
574
600
|
for (const name of projection.allowedToolNames) {
|
|
601
|
+
// When a subagent allowlist is active, exclude skill tools not on it.
|
|
602
|
+
if (ctx.subagentAllowedTools && !ctx.subagentAllowedTools.has(name)) {
|
|
603
|
+
continue;
|
|
604
|
+
}
|
|
575
605
|
turnAllowed.add(name);
|
|
576
606
|
}
|
|
577
607
|
ctx.allowedToolNames = turnAllowed;
|
|
@@ -33,8 +33,7 @@ export function refreshWorkspaceTopLevelContextIfNeeded(
|
|
|
33
33
|
currentConversationPath = `conversations/${resolvedDirName}/`;
|
|
34
34
|
}
|
|
35
35
|
ctx.workspaceTopLevelContext = renderWorkspaceTopLevelContext(snapshot, {
|
|
36
|
-
currentConversationPath
|
|
37
|
-
currentConversationAttachmentsPath: currentConversationPath
|
|
36
|
+
conversationAttachmentsPath: currentConversationPath
|
|
38
37
|
? `${currentConversationPath}attachments/`
|
|
39
38
|
: null,
|
|
40
39
|
});
|
|
@@ -44,6 +44,7 @@ import { registerToolTraceListener } from "../events/tool-trace-listener.js";
|
|
|
44
44
|
import { getHookManager } from "../hooks/manager.js";
|
|
45
45
|
import { resolveCanonicalGuardianRequest } from "../memory/canonical-guardian-store.js";
|
|
46
46
|
import { updateConversationContextWindow } from "../memory/conversation-crud.js";
|
|
47
|
+
import { ConversationGraphMemory } from "../memory/graph/conversation-graph-memory.js";
|
|
47
48
|
import { PermissionPrompter } from "../permissions/prompter.js";
|
|
48
49
|
import { SecretPrompter } from "../permissions/secret-prompter.js";
|
|
49
50
|
import { patternMatchesCandidate } from "../permissions/trust-store.js";
|
|
@@ -57,6 +58,7 @@ import type { AuthContext } from "../runtime/auth/types.js";
|
|
|
57
58
|
import * as approvalOverrides from "../runtime/conversation-approval-overrides.js";
|
|
58
59
|
import * as pendingInteractions from "../runtime/pending-interactions.js";
|
|
59
60
|
import { ToolExecutor } from "../tools/executor.js";
|
|
61
|
+
import { getLogger } from "../util/logger.js";
|
|
60
62
|
import type { AssistantAttachmentDraft } from "./assistant-attachments.js";
|
|
61
63
|
import { runAgentLoopImpl } from "./conversation-agent-loop.js";
|
|
62
64
|
import type { HistoryConversationContext } from "./conversation-history.js";
|
|
@@ -118,6 +120,8 @@ import type {
|
|
|
118
120
|
} from "./message-types/messages.js";
|
|
119
121
|
import { TraceEmitter } from "./trace-emitter.js";
|
|
120
122
|
|
|
123
|
+
const log = getLogger("conversation");
|
|
124
|
+
|
|
121
125
|
export interface ConversationMemoryPolicy {
|
|
122
126
|
scopeId: string;
|
|
123
127
|
includeDefaultFallback: boolean;
|
|
@@ -156,6 +160,7 @@ export class Conversation {
|
|
|
156
160
|
/** @internal */ allowedToolNames?: Set<string>;
|
|
157
161
|
/** @internal */ toolsDisabledDepth = 0;
|
|
158
162
|
/** @internal */ preactivatedSkillIds?: string[];
|
|
163
|
+
/** @internal */ subagentAllowedTools?: Set<string>;
|
|
159
164
|
/** @internal */ coreToolNames: Set<string>;
|
|
160
165
|
/** @internal */ readonly skillProjectionState = new Map<string, string>();
|
|
161
166
|
/** @internal */ readonly skillProjectionCache: SkillProjectionCache = {};
|
|
@@ -170,6 +175,7 @@ export class Conversation {
|
|
|
170
175
|
/** @internal */ contextCompactedAt: number | null = null;
|
|
171
176
|
/** @internal */ currentRequestId?: string;
|
|
172
177
|
/** @internal */ hasNoClient = false;
|
|
178
|
+
/** @internal */ isSubagent = false;
|
|
173
179
|
/** @internal */ headlessLock = false;
|
|
174
180
|
/** @internal */ taskRunId?: string;
|
|
175
181
|
/** @internal */ callSessionId?: string;
|
|
@@ -243,6 +249,9 @@ export class Conversation {
|
|
|
243
249
|
public readonly traceEmitter: TraceEmitter;
|
|
244
250
|
public readonly hasSystemPromptOverride: boolean;
|
|
245
251
|
public memoryPolicy: ConversationMemoryPolicy;
|
|
252
|
+
/** @internal */ readonly graphMemory: ConversationGraphMemory;
|
|
253
|
+
/** @internal */ activeContextNodeIds?: string[];
|
|
254
|
+
/** @internal */ memoryScopeId?: string;
|
|
246
255
|
/** @internal */ streamThinking: boolean;
|
|
247
256
|
/** @internal */ turnCount = 0;
|
|
248
257
|
public lastAssistantAttachments: AssistantAttachmentDraft[] = [];
|
|
@@ -251,6 +260,8 @@ export class Conversation {
|
|
|
251
260
|
/** @internal */ currentTurnInterfaceContext: TurnInterfaceContext | null =
|
|
252
261
|
null;
|
|
253
262
|
/** @internal */ activityVersion = 0;
|
|
263
|
+
/** Last emitted activity state message, retained for replay on SSE reconnection. */
|
|
264
|
+
/** @internal */ lastActivityStateMsg: ServerMessage | null = null;
|
|
254
265
|
/** Set by the agent loop to track confirmation outcomes for persistence. */
|
|
255
266
|
onConfirmationOutcome?: (
|
|
256
267
|
requestId: string,
|
|
@@ -270,6 +281,7 @@ export class Conversation {
|
|
|
270
281
|
memoryPolicy?: ConversationMemoryPolicy,
|
|
271
282
|
sharedCesClient?: CesClient,
|
|
272
283
|
speedOverride?: Speed,
|
|
284
|
+
cacheTtl?: "5m" | "1h",
|
|
273
285
|
) {
|
|
274
286
|
this.conversationId = conversationId;
|
|
275
287
|
this.systemPrompt = systemPrompt;
|
|
@@ -280,6 +292,10 @@ export class Conversation {
|
|
|
280
292
|
this.memoryPolicy = memoryPolicy
|
|
281
293
|
? { ...memoryPolicy }
|
|
282
294
|
: { ...DEFAULT_MEMORY_POLICY };
|
|
295
|
+
this.graphMemory = new ConversationGraphMemory(
|
|
296
|
+
this.memoryPolicy.scopeId,
|
|
297
|
+
conversationId,
|
|
298
|
+
);
|
|
283
299
|
this.traceEmitter = new TraceEmitter(conversationId, sendToClient);
|
|
284
300
|
this.prompter = new PermissionPrompter(sendToClient);
|
|
285
301
|
this.prompter.setOnStateChanged((requestId, state, source, toolUseId) => {
|
|
@@ -404,6 +420,7 @@ export class Conversation {
|
|
|
404
420
|
...(fastModeEnabled && resolvedSpeed === "fast"
|
|
405
421
|
? { speed: resolvedSpeed }
|
|
406
422
|
: {}),
|
|
423
|
+
...(cacheTtl ? { cacheTtl } : {}),
|
|
407
424
|
},
|
|
408
425
|
toolDefs.length > 0 ? toolDefs : undefined,
|
|
409
426
|
toolDefs.length > 0 ? toolExecutor : undefined,
|
|
@@ -428,6 +445,7 @@ export class Conversation {
|
|
|
428
445
|
async loadFromDb(): Promise<void> {
|
|
429
446
|
await loadFromDbImpl(this);
|
|
430
447
|
this.restoreSurfaceStateFromHistory();
|
|
448
|
+
this.graphMemory.restoreState();
|
|
431
449
|
}
|
|
432
450
|
|
|
433
451
|
/**
|
|
@@ -486,6 +504,19 @@ export class Conversation {
|
|
|
486
504
|
this.hostCuProxy?.updateSender(sendToClient, !hasNoClient);
|
|
487
505
|
this.hostFileProxy?.updateSender(sendToClient, !hasNoClient);
|
|
488
506
|
}
|
|
507
|
+
|
|
508
|
+
// Replay last activity state so a reconnecting client sees the current phase
|
|
509
|
+
// instead of being stuck on the last state it received before disconnection.
|
|
510
|
+
if (!hasNoClient && this.lastActivityStateMsg) {
|
|
511
|
+
try {
|
|
512
|
+
sendToClient(this.lastActivityStateMsg);
|
|
513
|
+
} catch (err) {
|
|
514
|
+
log.warn(
|
|
515
|
+
{ err, conversationId: this.conversationId },
|
|
516
|
+
"Failed to replay activity state on client reconnection",
|
|
517
|
+
);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
489
520
|
}
|
|
490
521
|
|
|
491
522
|
/** Returns the current sendToClient reference for identity comparison. */
|
|
@@ -513,6 +544,14 @@ export class Conversation {
|
|
|
513
544
|
this.sandboxOverride = enabled;
|
|
514
545
|
}
|
|
515
546
|
|
|
547
|
+
setSubagentAllowedTools(tools: Set<string> | undefined): void {
|
|
548
|
+
this.subagentAllowedTools = tools;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
setIsSubagent(value: boolean): void {
|
|
552
|
+
this.isSubagent = value;
|
|
553
|
+
}
|
|
554
|
+
|
|
516
555
|
isProcessing(): boolean {
|
|
517
556
|
return this.processing;
|
|
518
557
|
}
|
|
@@ -540,6 +579,9 @@ export class Conversation {
|
|
|
540
579
|
// CES client is owned by DaemonServer — just drop the reference.
|
|
541
580
|
// Do NOT close it here; the server manages the CES lifecycle.
|
|
542
581
|
this.cesClient = undefined;
|
|
582
|
+
this.activeContextNodeIds = this.graphMemory.tracker.getActiveNodeIds();
|
|
583
|
+
this.memoryScopeId = this.memoryPolicy.scopeId;
|
|
584
|
+
this.graphMemory.persistState();
|
|
543
585
|
disposeConversation(this);
|
|
544
586
|
}
|
|
545
587
|
|
|
@@ -862,7 +904,14 @@ export class Conversation {
|
|
|
862
904
|
type: "confirmation_state_changed",
|
|
863
905
|
...params,
|
|
864
906
|
} as ServerMessage;
|
|
865
|
-
|
|
907
|
+
try {
|
|
908
|
+
this.sendToClient(msg);
|
|
909
|
+
} catch (err) {
|
|
910
|
+
log.warn(
|
|
911
|
+
{ err, conversationId: this.conversationId },
|
|
912
|
+
"sendToClient threw in emitConfirmationStateChanged",
|
|
913
|
+
);
|
|
914
|
+
}
|
|
866
915
|
}
|
|
867
916
|
|
|
868
917
|
emitActivityState(
|
|
@@ -883,7 +932,15 @@ export class Conversation {
|
|
|
883
932
|
reason,
|
|
884
933
|
...(statusText ? { statusText } : {}),
|
|
885
934
|
} as ServerMessage;
|
|
886
|
-
this.
|
|
935
|
+
this.lastActivityStateMsg = msg;
|
|
936
|
+
try {
|
|
937
|
+
this.sendToClient(msg);
|
|
938
|
+
} catch (err) {
|
|
939
|
+
log.warn(
|
|
940
|
+
{ err, conversationId: this.conversationId },
|
|
941
|
+
"sendToClient threw in emitActivityState",
|
|
942
|
+
);
|
|
943
|
+
}
|
|
887
944
|
}
|
|
888
945
|
|
|
889
946
|
async forceCompact(): Promise<ContextWindowResult> {
|
|
@@ -12,12 +12,14 @@ import { resolve } from "node:path";
|
|
|
12
12
|
import { getRuntimeHttpHost, getRuntimeHttpPort } from "../config/env.js";
|
|
13
13
|
import { getIsContainerized } from "../config/env-registry.js";
|
|
14
14
|
import { loadOrCreateSigningKey } from "../runtime/auth/token-service.js";
|
|
15
|
+
import { ensureBun } from "../util/bun-runtime.js";
|
|
15
16
|
import { DaemonError } from "../util/errors.js";
|
|
16
17
|
import { getLogger } from "../util/logger.js";
|
|
17
18
|
import {
|
|
18
19
|
ensureDataDir,
|
|
19
20
|
getDaemonStartupLockPath,
|
|
20
21
|
getDaemonStderrLogPath,
|
|
22
|
+
getDataDir,
|
|
21
23
|
getPidPath,
|
|
22
24
|
getWorkspaceConfigPath,
|
|
23
25
|
} from "../util/platform.js";
|
|
@@ -371,6 +373,10 @@ async function startDaemonLocked(): Promise<{
|
|
|
371
373
|
}
|
|
372
374
|
}
|
|
373
375
|
|
|
376
|
+
// Resolve bun before opening stderrFd to avoid leaking the file
|
|
377
|
+
// descriptor if ensureBun() throws (same pattern as loadOrCreateSigningKey).
|
|
378
|
+
const bunPath = await ensureBun();
|
|
379
|
+
|
|
374
380
|
// Redirect the child's stderr to a file instead of piping it back to the
|
|
375
381
|
// parent. A pipe's read end is destroyed when the parent exits, leaving
|
|
376
382
|
// fd 2 broken in the child. Bun (unlike Node.js) does not ignore SIGPIPE,
|
|
@@ -378,7 +384,7 @@ async function startDaemonLocked(): Promise<{
|
|
|
378
384
|
const stderrPath = getDaemonStderrLogPath();
|
|
379
385
|
const stderrFd = openSync(stderrPath, "w");
|
|
380
386
|
|
|
381
|
-
const child = spawn(
|
|
387
|
+
const child = spawn(bunPath, ["run", mainPath], {
|
|
382
388
|
detached: true,
|
|
383
389
|
stdio: ["ignore", "ignore", stderrFd],
|
|
384
390
|
env: spawnEnv,
|
|
@@ -413,7 +419,7 @@ async function startDaemonLocked(): Promise<{
|
|
|
413
419
|
const stderr = readFileSync(stderrPath, "utf-8").trim();
|
|
414
420
|
const detail = stderr
|
|
415
421
|
? `\n${stderr}`
|
|
416
|
-
: `\nCheck logs at
|
|
422
|
+
: `\nCheck logs at ${getDataDir()}/logs/ for details.`;
|
|
417
423
|
throw new DaemonError(
|
|
418
424
|
`Daemon exited immediately (code ${
|
|
419
425
|
childExitCode ?? "unknown"
|
|
@@ -290,31 +290,14 @@ function formatLocalDate(date: Date, timeZone: string): string {
|
|
|
290
290
|
}
|
|
291
291
|
|
|
292
292
|
/**
|
|
293
|
-
* Format HH:MM
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
const fmt = new Intl.DateTimeFormat("en-US", {
|
|
300
|
-
timeZone,
|
|
301
|
-
hour: "2-digit",
|
|
302
|
-
minute: "2-digit",
|
|
303
|
-
hourCycle: "h23",
|
|
304
|
-
timeZoneName: "shortOffset",
|
|
305
|
-
});
|
|
306
|
-
const parts = fmt.formatToParts(date);
|
|
307
|
-
const get = (t: string) => parts.find((p) => p.type === t)?.value ?? "";
|
|
308
|
-
const hour = get("hour");
|
|
309
|
-
const minute = get("minute");
|
|
310
|
-
const offset = normalizeOffsetToken(get("timeZoneName"));
|
|
311
|
-
return { time: `${hour}:${minute}`, offset };
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
/**
|
|
315
|
-
* Build a compact temporal context string for model injection.
|
|
293
|
+
* Format time as HH:MM:SS with UTC offset and timezone name.
|
|
294
|
+
*
|
|
295
|
+
* Uses the timezone resolution cascade:
|
|
296
|
+
* explicit override → configured user tz → profile user tz → host fallback.
|
|
297
|
+
*
|
|
298
|
+
* Returns format: `2026-04-02 (Thu) 01:52:33 -05:00 (America/Chicago)`
|
|
316
299
|
*/
|
|
317
|
-
export function
|
|
300
|
+
export function formatTurnTimestamp(
|
|
318
301
|
options: TemporalContextOptions = {},
|
|
319
302
|
): string {
|
|
320
303
|
const now = new Date(options.nowMs ?? Date.now());
|
|
@@ -336,36 +319,26 @@ export function buildTemporalContext(
|
|
|
336
319
|
resolvedConfiguredUserTimeZone ??
|
|
337
320
|
resolvedUserTimeZone ??
|
|
338
321
|
resolvedHostTimeZone;
|
|
339
|
-
const userTimeZone = resolvedConfiguredUserTimeZone ?? resolvedUserTimeZone;
|
|
340
|
-
const timeZoneSource = resolvedTimeZone
|
|
341
|
-
? "explicit_override"
|
|
342
|
-
: resolvedConfiguredUserTimeZone
|
|
343
|
-
? "user_settings"
|
|
344
|
-
: resolvedUserTimeZone
|
|
345
|
-
? "user_profile_memory"
|
|
346
|
-
: "assistant_host_fallback";
|
|
347
|
-
const todayParts = localDateParts(now, timeZone);
|
|
348
|
-
const todayStr = formatLocalDate(now, timeZone);
|
|
349
|
-
const todayWeekday = WEEKDAY_SHORT[todayParts.weekday];
|
|
350
|
-
const { time, offset } = formatCompactTimeAndOffset(now, timeZone);
|
|
351
|
-
|
|
352
|
-
const tzSuffix =
|
|
353
|
-
timeZoneSource === "assistant_host_fallback" ? " (host fallback)" : "";
|
|
354
322
|
|
|
355
|
-
const
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
`TZ: ${timeZone}${tzSuffix}`,
|
|
359
|
-
];
|
|
360
|
-
|
|
361
|
-
if (userTimeZone && userTimeZone !== timeZone) {
|
|
362
|
-
lines.push(`User TZ: ${userTimeZone}`);
|
|
363
|
-
}
|
|
364
|
-
if (resolvedHostTimeZone !== timeZone) {
|
|
365
|
-
lines.push(`Host TZ: ${resolvedHostTimeZone}`);
|
|
366
|
-
}
|
|
323
|
+
const dateStr = formatLocalDate(now, timeZone);
|
|
324
|
+
const todayParts = localDateParts(now, timeZone);
|
|
325
|
+
const dayName = WEEKDAY_SHORT[todayParts.weekday];
|
|
367
326
|
|
|
368
|
-
|
|
327
|
+
const fmt = new Intl.DateTimeFormat("en-US", {
|
|
328
|
+
timeZone,
|
|
329
|
+
hour: "2-digit",
|
|
330
|
+
minute: "2-digit",
|
|
331
|
+
second: "2-digit",
|
|
332
|
+
hourCycle: "h23",
|
|
333
|
+
timeZoneName: "shortOffset",
|
|
334
|
+
});
|
|
335
|
+
const parts = fmt.formatToParts(now);
|
|
336
|
+
const get = (t: string) => parts.find((p) => p.type === t)?.value ?? "";
|
|
337
|
+
const hour = get("hour");
|
|
338
|
+
const minute = get("minute");
|
|
339
|
+
const second = get("second");
|
|
340
|
+
const offset = normalizeOffsetToken(get("timeZoneName"));
|
|
369
341
|
|
|
370
|
-
return
|
|
342
|
+
return `${dateStr} (${dayName}) ${hour}:${minute}:${second} ${offset} (${timeZone})`;
|
|
371
343
|
}
|
|
344
|
+
|
|
@@ -8,7 +8,7 @@ import { getWorkspacePromptPath } from "../util/platform.js";
|
|
|
8
8
|
* time," "I'm ready to be useful," and "you're in control."
|
|
9
9
|
*/
|
|
10
10
|
export const CANNED_FIRST_GREETING =
|
|
11
|
-
"Hey
|
|
11
|
+
"Hey, I'm brand new. No name, no memories, nothing yet. Think of me like a new colleague on their first day: I'll get better the more we work together. First things first, let's figure out how we work best. What should I call you?";
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* Returns `true` when all of the following are true:
|
|
@@ -103,13 +103,10 @@ export function makeEventSender(params: {
|
|
|
103
103
|
guardianPrincipalId: trustContext?.guardianPrincipalId ?? undefined,
|
|
104
104
|
toolName: event.toolName,
|
|
105
105
|
commandPreview:
|
|
106
|
-
redactSecrets(
|
|
107
|
-
|
|
108
|
-
) || undefined,
|
|
106
|
+
redactSecrets(summarizeToolInput(event.toolName, inputRecord)) ||
|
|
107
|
+
undefined,
|
|
109
108
|
riskLevel: event.riskLevel,
|
|
110
|
-
activityText: activityRaw
|
|
111
|
-
? redactSecrets(activityRaw)
|
|
112
|
-
: undefined,
|
|
109
|
+
activityText: activityRaw ? redactSecrets(activityRaw) : undefined,
|
|
113
110
|
executionTarget: event.executionTarget,
|
|
114
111
|
status: "pending",
|
|
115
112
|
requestCode: generateCanonicalRequestCode(),
|
|
@@ -304,7 +301,7 @@ export async function handleConversationCreate(
|
|
|
304
301
|
// Only create the host bash proxy for desktop client interfaces that can
|
|
305
302
|
// execute commands on the user's machine. Set before updateClient so
|
|
306
303
|
// updateClient's call to hostBashProxy.updateSender targets the new proxy.
|
|
307
|
-
if (transportInterface === "macos"
|
|
304
|
+
if (transportInterface === "macos") {
|
|
308
305
|
const proxy = new HostBashProxy(sendEvent, (requestId) => {
|
|
309
306
|
pendingInteractions.resolve(requestId);
|
|
310
307
|
});
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import { compareSemver } from "./shared.js";
|
|
4
|
+
|
|
5
|
+
describe("compareSemver", () => {
|
|
6
|
+
// ── Basic numeric comparison ──────────────────────────────────────
|
|
7
|
+
test("equal versions return 0", () => {
|
|
8
|
+
expect(compareSemver("1.2.3", "1.2.3")).toBe(0);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
test("higher major returns positive", () => {
|
|
12
|
+
expect(compareSemver("2.0.0", "1.0.0")).toBeGreaterThan(0);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
test("lower major returns negative", () => {
|
|
16
|
+
expect(compareSemver("1.0.0", "2.0.0")).toBeLessThan(0);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test("higher minor returns positive", () => {
|
|
20
|
+
expect(compareSemver("1.3.0", "1.2.0")).toBeGreaterThan(0);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test("higher patch returns positive", () => {
|
|
24
|
+
expect(compareSemver("1.2.4", "1.2.3")).toBeGreaterThan(0);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// ── v/V prefix handling ───────────────────────────────────────────
|
|
28
|
+
test("strips v prefix", () => {
|
|
29
|
+
expect(compareSemver("v1.2.3", "1.2.3")).toBe(0);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test("strips V prefix", () => {
|
|
33
|
+
expect(compareSemver("V1.2.3", "1.2.3")).toBe(0);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test("compares with mixed v prefix", () => {
|
|
37
|
+
expect(compareSemver("v2.0.0", "1.0.0")).toBeGreaterThan(0);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// ── Pre-release vs release ────────────────────────────────────────
|
|
41
|
+
test("pre-release sorts lower than release", () => {
|
|
42
|
+
expect(compareSemver("0.6.0-staging.1", "0.6.0")).toBeLessThan(0);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test("release sorts higher than pre-release", () => {
|
|
46
|
+
expect(compareSemver("0.6.0", "0.6.0-staging.1")).toBeGreaterThan(0);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test("both without pre-release and same version return 0", () => {
|
|
50
|
+
expect(compareSemver("0.6.0", "0.6.0")).toBe(0);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// ── Pre-release numeric comparison ────────────────────────────────
|
|
54
|
+
test("staging.1 < staging.2", () => {
|
|
55
|
+
expect(compareSemver("0.6.0-staging.1", "0.6.0-staging.2")).toBeLessThan(0);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test("staging.10 > staging.2 (numeric, not lexical)", () => {
|
|
59
|
+
expect(
|
|
60
|
+
compareSemver("0.6.0-staging.10", "0.6.0-staging.2"),
|
|
61
|
+
).toBeGreaterThan(0);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test("equal pre-release returns 0", () => {
|
|
65
|
+
expect(compareSemver("0.6.0-staging.5", "0.6.0-staging.5")).toBe(0);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// ── Pre-release lexical comparison ────────────────────────────────
|
|
69
|
+
test("alpha < beta (lexical)", () => {
|
|
70
|
+
expect(compareSemver("1.0.0-alpha", "1.0.0-beta")).toBeLessThan(0);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test("rc < staging (lexical)", () => {
|
|
74
|
+
expect(compareSemver("1.0.0-rc", "1.0.0-staging")).toBeLessThan(0);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// ── Pre-release fewer identifiers sorts earlier ───────────────────
|
|
78
|
+
test("fewer pre-release identifiers sorts earlier", () => {
|
|
79
|
+
expect(compareSemver("1.0.0-alpha", "1.0.0-alpha.1")).toBeLessThan(0);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// ── Mixed numeric vs non-numeric per §11.4.4 ─────────────────────
|
|
83
|
+
test("numeric identifier sorts lower than non-numeric", () => {
|
|
84
|
+
expect(compareSemver("1.0.0-1", "1.0.0-alpha")).toBeLessThan(0);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test("non-numeric identifier sorts higher than numeric", () => {
|
|
88
|
+
expect(compareSemver("1.0.0-alpha", "1.0.0-1")).toBeGreaterThan(0);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// ── Multi-segment pre-release ─────────────────────────────────────
|
|
92
|
+
test("multi-segment pre-release comparison", () => {
|
|
93
|
+
expect(
|
|
94
|
+
compareSemver("1.0.0-alpha.beta.1", "1.0.0-alpha.beta.2"),
|
|
95
|
+
).toBeLessThan(0);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// ── Hyphenated pre-release identifiers ────────────────────────────
|
|
99
|
+
test("pre-release with multiple hyphens", () => {
|
|
100
|
+
expect(
|
|
101
|
+
compareSemver("1.0.0-pre-release-1", "1.0.0-pre-release-2"),
|
|
102
|
+
).toBeLessThan(0);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// ── Different major.minor.patch trumps pre-release ────────────────
|
|
106
|
+
test("higher patch wins regardless of pre-release", () => {
|
|
107
|
+
expect(compareSemver("0.6.1", "0.6.0-staging.99")).toBeGreaterThan(0);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test("lower patch loses regardless of pre-release absence", () => {
|
|
111
|
+
expect(compareSemver("0.5.9", "0.6.0-staging.1")).toBeLessThan(0);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// ── Edge cases ────────────────────────────────────────────────────
|
|
115
|
+
test("missing segments default to 0", () => {
|
|
116
|
+
expect(compareSemver("1", "1.0.0")).toBe(0);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
test("two-segment version", () => {
|
|
120
|
+
expect(compareSemver("1.2", "1.2.0")).toBe(0);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// ── Sort integration ──────────────────────────────────────────────
|
|
124
|
+
test("Array.sort produces correct semver order", () => {
|
|
125
|
+
const versions = [
|
|
126
|
+
"0.6.0",
|
|
127
|
+
"0.6.0-staging.2",
|
|
128
|
+
"0.5.9",
|
|
129
|
+
"0.6.0-staging.10",
|
|
130
|
+
"v0.6.0-staging.1",
|
|
131
|
+
"0.6.1",
|
|
132
|
+
];
|
|
133
|
+
const sorted = [...versions].sort(compareSemver);
|
|
134
|
+
expect(sorted).toEqual([
|
|
135
|
+
"0.5.9",
|
|
136
|
+
"v0.6.0-staging.1",
|
|
137
|
+
"0.6.0-staging.2",
|
|
138
|
+
"0.6.0-staging.10",
|
|
139
|
+
"0.6.0",
|
|
140
|
+
"0.6.1",
|
|
141
|
+
]);
|
|
142
|
+
});
|
|
143
|
+
});
|