@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,165 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import {
|
|
4
|
+
existsSync,
|
|
5
|
+
mkdirSync,
|
|
6
|
+
readdirSync,
|
|
7
|
+
readFileSync,
|
|
8
|
+
statSync,
|
|
9
|
+
unlinkSync,
|
|
10
|
+
writeFileSync,
|
|
11
|
+
} from "node:fs";
|
|
12
|
+
import { tmpdir } from "node:os";
|
|
13
|
+
import { join } from "node:path";
|
|
14
|
+
|
|
15
|
+
import { parseImageDimensions } from "../context/image-dimensions.js";
|
|
16
|
+
|
|
17
|
+
// Anthropic's documented max dimension — images larger than this are scaled
|
|
18
|
+
// down server-side anyway, so pre-scaling is zero quality loss.
|
|
19
|
+
const MAX_DIMENSION = 1568;
|
|
20
|
+
|
|
21
|
+
// Threshold below which we skip optimization — small images don't need it.
|
|
22
|
+
const OPTIMIZE_THRESHOLD_BYTES = 300 * 1024; // 300 KB
|
|
23
|
+
|
|
24
|
+
const JPEG_QUALITY = 80;
|
|
25
|
+
|
|
26
|
+
// Content-addressed disk cache to avoid re-running sips on the same image.
|
|
27
|
+
const CACHE_MAX_ENTRIES = 500;
|
|
28
|
+
|
|
29
|
+
function getCacheDir(): string {
|
|
30
|
+
return join(tmpdir(), "vellum-optimized-images");
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function readFromCache(
|
|
34
|
+
key: string,
|
|
35
|
+
): { data: string; mediaType: string } | null {
|
|
36
|
+
try {
|
|
37
|
+
const cachePath = join(getCacheDir(), `${key}.jpg`);
|
|
38
|
+
if (!existsSync(cachePath)) return null;
|
|
39
|
+
const buf = readFileSync(cachePath) as Buffer;
|
|
40
|
+
return { data: buf.toString("base64"), mediaType: "image/jpeg" };
|
|
41
|
+
} catch {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function writeToCache(key: string, optimizedBytes: Buffer): void {
|
|
47
|
+
try {
|
|
48
|
+
const dir = getCacheDir();
|
|
49
|
+
mkdirSync(dir, { recursive: true });
|
|
50
|
+
writeFileSync(join(dir, `${key}.jpg`), optimizedBytes);
|
|
51
|
+
evictIfNeeded(dir);
|
|
52
|
+
} catch {
|
|
53
|
+
// Cache write failure is non-fatal.
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function evictIfNeeded(dir: string): void {
|
|
58
|
+
try {
|
|
59
|
+
const entries = readdirSync(dir)
|
|
60
|
+
.filter((f) => f.endsWith(".jpg"))
|
|
61
|
+
.map((f) => {
|
|
62
|
+
const full = join(dir, f);
|
|
63
|
+
return { path: full, mtimeMs: statSync(full).mtimeMs };
|
|
64
|
+
})
|
|
65
|
+
.sort((a, b) => a.mtimeMs - b.mtimeMs);
|
|
66
|
+
const excess = entries.length - CACHE_MAX_ENTRIES;
|
|
67
|
+
for (let i = 0; i < excess; i++) {
|
|
68
|
+
try {
|
|
69
|
+
unlinkSync(entries[i]!.path);
|
|
70
|
+
} catch {
|
|
71
|
+
/* ignore */
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
} catch {
|
|
75
|
+
/* ignore */
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function runSips(inputBytes: Buffer): Buffer | null {
|
|
80
|
+
const srcPath = join(tmpdir(), `vellum-img-opt-${Date.now()}-src`);
|
|
81
|
+
const outPath = join(tmpdir(), `vellum-img-opt-${Date.now()}-out.jpg`);
|
|
82
|
+
try {
|
|
83
|
+
writeFileSync(srcPath, inputBytes);
|
|
84
|
+
execFileSync(
|
|
85
|
+
"sips",
|
|
86
|
+
[
|
|
87
|
+
"--resampleHeightWidthMax",
|
|
88
|
+
String(MAX_DIMENSION),
|
|
89
|
+
"-s",
|
|
90
|
+
"format",
|
|
91
|
+
"jpeg",
|
|
92
|
+
"-s",
|
|
93
|
+
"formatOptions",
|
|
94
|
+
String(JPEG_QUALITY),
|
|
95
|
+
srcPath,
|
|
96
|
+
"--out",
|
|
97
|
+
outPath,
|
|
98
|
+
],
|
|
99
|
+
{ stdio: "pipe", timeout: 15_000 },
|
|
100
|
+
);
|
|
101
|
+
return readFileSync(outPath) as Buffer;
|
|
102
|
+
} catch {
|
|
103
|
+
return null;
|
|
104
|
+
} finally {
|
|
105
|
+
try {
|
|
106
|
+
unlinkSync(srcPath);
|
|
107
|
+
} catch {
|
|
108
|
+
/* ignore */
|
|
109
|
+
}
|
|
110
|
+
try {
|
|
111
|
+
unlinkSync(outPath);
|
|
112
|
+
} catch {
|
|
113
|
+
/* ignore */
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Downscale a base64 image to fit within Anthropic's recommended dimensions
|
|
120
|
+
* (1568px max side). Returns the original data unchanged if the image is
|
|
121
|
+
* already small enough or if optimization fails.
|
|
122
|
+
*
|
|
123
|
+
* Anthropic applies the same scaling server-side, so this is zero quality
|
|
124
|
+
* loss — we just do it pre-flight to keep request payloads small and avoid
|
|
125
|
+
* 413 "request too large" errors when many images accumulate in context.
|
|
126
|
+
*
|
|
127
|
+
* Results are cached on disk by content hash so repeated sends of the same
|
|
128
|
+
* image (or daemon restarts) skip the sips call entirely.
|
|
129
|
+
*/
|
|
130
|
+
export function optimizeImageForTransport(
|
|
131
|
+
base64Data: string,
|
|
132
|
+
mediaType: string,
|
|
133
|
+
): { data: string; mediaType: string } {
|
|
134
|
+
const rawBytes = Buffer.from(base64Data, "base64");
|
|
135
|
+
|
|
136
|
+
// Small images don't need optimization.
|
|
137
|
+
if (rawBytes.length <= OPTIMIZE_THRESHOLD_BYTES) {
|
|
138
|
+
return { data: base64Data, mediaType };
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// If dimensions are already within limits, skip.
|
|
142
|
+
const dims = parseImageDimensions(base64Data, mediaType);
|
|
143
|
+
if (
|
|
144
|
+
dims &&
|
|
145
|
+
dims.width <= MAX_DIMENSION &&
|
|
146
|
+
dims.height <= MAX_DIMENSION
|
|
147
|
+
) {
|
|
148
|
+
return { data: base64Data, mediaType };
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Content-addressed cache lookup.
|
|
152
|
+
const hash = createHash("sha256").update(rawBytes).digest("hex");
|
|
153
|
+
const cacheKey = hash.slice(0, 16);
|
|
154
|
+
const cached = readFromCache(cacheKey);
|
|
155
|
+
if (cached) return cached;
|
|
156
|
+
|
|
157
|
+
// Run sips (macOS). On other platforms this gracefully returns null.
|
|
158
|
+
const optimized = runSips(rawBytes);
|
|
159
|
+
if (!optimized) {
|
|
160
|
+
return { data: base64Data, mediaType };
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
writeToCache(cacheKey, optimized);
|
|
164
|
+
return { data: optimized.toString("base64"), mediaType: "image/jpeg" };
|
|
165
|
+
}
|
package/src/agent/loop.ts
CHANGED
|
@@ -101,10 +101,7 @@ const DEFAULT_CONFIG: AgentLoopConfig = {
|
|
|
101
101
|
minTurnIntervalMs: 150,
|
|
102
102
|
};
|
|
103
103
|
|
|
104
|
-
const PROGRESS_CHECK_INTERVAL = 5;
|
|
105
104
|
const MAX_CONSECUTIVE_ERROR_NUDGES = 3;
|
|
106
|
-
const PROGRESS_CHECK_REMINDER =
|
|
107
|
-
"You have been using tools for several turns. Check whether you are making meaningful progress toward the user's goal. If you are stuck in a loop or not making progress, summarize what you have tried and ask the user for guidance instead of continuing.";
|
|
108
105
|
|
|
109
106
|
export interface ResolvedSystemPrompt {
|
|
110
107
|
systemPrompt: string;
|
|
@@ -573,21 +570,11 @@ export class AgentLoop {
|
|
|
573
570
|
break;
|
|
574
571
|
}
|
|
575
572
|
|
|
576
|
-
// Track tool-use turns and inject progress reminder every N turns
|
|
577
573
|
toolUseTurns++;
|
|
578
|
-
const isProgressCheckTurn =
|
|
579
|
-
toolUseTurns % PROGRESS_CHECK_INTERVAL === 0;
|
|
580
|
-
if (isProgressCheckTurn) {
|
|
581
|
-
resultBlocks.push({
|
|
582
|
-
type: "text",
|
|
583
|
-
text: `<system_notice>${PROGRESS_CHECK_REMINDER}</system_notice>`,
|
|
584
|
-
});
|
|
585
|
-
}
|
|
586
574
|
|
|
587
575
|
// When any tool returned an error, nudge the LLM to retry with
|
|
588
576
|
// corrected parameters instead of ending its turn. Skip the nudge
|
|
589
|
-
//
|
|
590
|
-
// and after MAX_CONSECUTIVE_ERROR_NUDGES consecutive error turns
|
|
577
|
+
// after MAX_CONSECUTIVE_ERROR_NUDGES consecutive error turns
|
|
591
578
|
// (the error is likely unrecoverable at that point).
|
|
592
579
|
const hasToolError = toolResults.some(({ result }) => result.isError);
|
|
593
580
|
if (hasToolError) {
|
|
@@ -597,7 +584,6 @@ export class AgentLoop {
|
|
|
597
584
|
}
|
|
598
585
|
if (
|
|
599
586
|
hasToolError &&
|
|
600
|
-
!isProgressCheckTurn &&
|
|
601
587
|
consecutiveErrorTurns <= MAX_CONSECUTIVE_ERROR_NUDGES
|
|
602
588
|
) {
|
|
603
589
|
resultBlocks.push({
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
import { existsSync, rmSync } from "node:fs";
|
|
13
13
|
import { mkdir, readdir, readFile, writeFile } from "node:fs/promises";
|
|
14
|
-
import { dirname, join } from "node:path";
|
|
14
|
+
import { dirname, join, resolve } from "node:path";
|
|
15
15
|
|
|
16
16
|
import { getLogger } from "../util/logger.js";
|
|
17
17
|
import { ensureCompilerTools } from "./compiler-tools.js";
|
|
@@ -79,6 +79,161 @@ function parseEsbuildStderr(stderr: string): {
|
|
|
79
79
|
return { errors, warnings };
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
+
/**
|
|
83
|
+
* Decode JS string escape sequences (\xHH, \uHHHH, \u{H+}, standard
|
|
84
|
+
* escapes) so that obfuscated specifiers like `"\x2e\x2e/etc/passwd"` are
|
|
85
|
+
* normalised before the path-containment check.
|
|
86
|
+
*/
|
|
87
|
+
function decodeJsEscapes(raw: string): string {
|
|
88
|
+
return raw.replace(
|
|
89
|
+
/\\(?:x([0-9a-fA-F]{2})|u\{([0-9a-fA-F]+)\}|u([0-9a-fA-F]{4})|([nrtbfv0'"\\]))/g,
|
|
90
|
+
(_, hex2, codePoint, hex4, std) => {
|
|
91
|
+
if (hex2) return String.fromCharCode(parseInt(hex2, 16));
|
|
92
|
+
if (codePoint) return String.fromCodePoint(parseInt(codePoint, 16));
|
|
93
|
+
if (hex4) return String.fromCharCode(parseInt(hex4, 16));
|
|
94
|
+
const map: Record<string, string> = {
|
|
95
|
+
n: "\n",
|
|
96
|
+
r: "\r",
|
|
97
|
+
t: "\t",
|
|
98
|
+
b: "\b",
|
|
99
|
+
f: "\f",
|
|
100
|
+
v: "\v",
|
|
101
|
+
"0": "\0",
|
|
102
|
+
"'": "'",
|
|
103
|
+
'"': '"',
|
|
104
|
+
"\\": "\\",
|
|
105
|
+
};
|
|
106
|
+
return map[std] ?? std;
|
|
107
|
+
},
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Strip JS block comments and line comments from source, replacing them
|
|
113
|
+
* with same-length whitespace so character offsets (used for line-number
|
|
114
|
+
* calculation) are preserved. String literals are left intact.
|
|
115
|
+
*/
|
|
116
|
+
function stripJsComments(source: string): string {
|
|
117
|
+
let out = "";
|
|
118
|
+
for (let i = 0; i < source.length; ) {
|
|
119
|
+
const c = source[i];
|
|
120
|
+
const next = source[i + 1];
|
|
121
|
+
|
|
122
|
+
// String literal — pass through unchanged
|
|
123
|
+
if (c === '"' || c === "'" || c === "`") {
|
|
124
|
+
const q = c;
|
|
125
|
+
out += source[i++];
|
|
126
|
+
while (i < source.length && source[i] !== q) {
|
|
127
|
+
if (source[i] === "\\") {
|
|
128
|
+
out += source[i++]; // backslash
|
|
129
|
+
}
|
|
130
|
+
if (i < source.length) out += source[i++]; // char or escaped char
|
|
131
|
+
}
|
|
132
|
+
if (i < source.length) out += source[i++]; // closing quote
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Block comment → replace with spaces (keep newlines for line counting)
|
|
137
|
+
if (c === "/" && next === "*") {
|
|
138
|
+
out += " "; // replace /*
|
|
139
|
+
i += 2;
|
|
140
|
+
while (
|
|
141
|
+
i < source.length &&
|
|
142
|
+
!(source[i] === "*" && source[i + 1] === "/")
|
|
143
|
+
) {
|
|
144
|
+
out += source[i] === "\n" ? "\n" : " ";
|
|
145
|
+
i++;
|
|
146
|
+
}
|
|
147
|
+
if (i < source.length) {
|
|
148
|
+
out += " "; // replace */
|
|
149
|
+
i += 2;
|
|
150
|
+
}
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Line comment → replace with spaces
|
|
155
|
+
if (c === "/" && next === "/") {
|
|
156
|
+
out += " "; // replace //
|
|
157
|
+
i += 2;
|
|
158
|
+
while (i < source.length && source[i] !== "\n") {
|
|
159
|
+
out += " ";
|
|
160
|
+
i++;
|
|
161
|
+
}
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
out += source[i++];
|
|
166
|
+
}
|
|
167
|
+
return out;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Validate that all relative/absolute import paths in source files resolve
|
|
172
|
+
* within the app directory. This prevents crafted apps from importing
|
|
173
|
+
* arbitrary host files (e.g. `import data from '../../../../etc/passwd'`).
|
|
174
|
+
*/
|
|
175
|
+
async function validateImportPaths(
|
|
176
|
+
srcDir: string,
|
|
177
|
+
appDir: string,
|
|
178
|
+
): Promise<CompileDiagnostic[]> {
|
|
179
|
+
const resolvedAppDir = resolve(appDir);
|
|
180
|
+
const errors: CompileDiagnostic[] = [];
|
|
181
|
+
|
|
182
|
+
const files = await readdir(srcDir, { recursive: true });
|
|
183
|
+
for (const file of files) {
|
|
184
|
+
const fileName = String(file);
|
|
185
|
+
const isJs = /\.[jt]sx?$/.test(fileName);
|
|
186
|
+
const isCss = /\.css$/.test(fileName);
|
|
187
|
+
if (!isJs && !isCss) continue;
|
|
188
|
+
|
|
189
|
+
const filePath = join(srcDir, fileName);
|
|
190
|
+
const content = await readFile(filePath, "utf-8");
|
|
191
|
+
const fileDir = dirname(filePath);
|
|
192
|
+
|
|
193
|
+
// Strip JS comments so patterns like `from /* */ "path"` are detected
|
|
194
|
+
const scannable = isJs ? stripJsComments(content) : content;
|
|
195
|
+
|
|
196
|
+
const specifiers: Array<{ specifier: string; index: number }> = [];
|
|
197
|
+
|
|
198
|
+
if (isJs) {
|
|
199
|
+
// Match: from "x", import "x", import("x"), require("x")
|
|
200
|
+
const re = /(?:from|import|require)\s*\(?\s*["']([^"']+)["']/g;
|
|
201
|
+
for (const m of scannable.matchAll(re)) {
|
|
202
|
+
specifiers.push({ specifier: m[1], index: m.index! });
|
|
203
|
+
}
|
|
204
|
+
} else {
|
|
205
|
+
// CSS: @import "x", @import url("x"), url("x")
|
|
206
|
+
const re =
|
|
207
|
+
/(?:@import\s+(?:url\s*\(\s*)?|url\s*\(\s*)["']?([^"')\s;]+)["']?/g;
|
|
208
|
+
for (const m of content.matchAll(re)) {
|
|
209
|
+
if (m[1]) specifiers.push({ specifier: m[1], index: m.index! });
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
for (const { specifier, index } of specifiers) {
|
|
214
|
+
// Decode JS string escapes so \x2e\x2e/… is normalised to ../../…
|
|
215
|
+
const decoded = isJs ? decodeJsEscapes(specifier) : specifier;
|
|
216
|
+
|
|
217
|
+
// Only validate path-based imports (starting with . or /)
|
|
218
|
+
if (!decoded.startsWith(".") && !decoded.startsWith("/")) continue;
|
|
219
|
+
|
|
220
|
+
const resolved = resolve(fileDir, decoded);
|
|
221
|
+
if (
|
|
222
|
+
!resolved.startsWith(resolvedAppDir + "/") &&
|
|
223
|
+
resolved !== resolvedAppDir
|
|
224
|
+
) {
|
|
225
|
+
const line = content.substring(0, index).split("\n").length;
|
|
226
|
+
errors.push({
|
|
227
|
+
text: `Import "${specifier}" resolves outside the app directory`,
|
|
228
|
+
location: { file: fileName, line, column: 0 },
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return errors;
|
|
235
|
+
}
|
|
236
|
+
|
|
82
237
|
/**
|
|
83
238
|
* Scan source files for bare import specifiers and pre-install any
|
|
84
239
|
* allowlisted packages into the shared cache so esbuild can resolve them.
|
|
@@ -86,6 +241,7 @@ function parseEsbuildStderr(stderr: string): {
|
|
|
86
241
|
async function resolveAppImports(srcDir: string): Promise<void> {
|
|
87
242
|
const importRe = /(?:import|from)\s+["']([^"'.][^"']*)["']/g;
|
|
88
243
|
const seen = new Set<string>();
|
|
244
|
+
const failed: string[] = [];
|
|
89
245
|
|
|
90
246
|
const files = await readdir(srcDir, { recursive: true });
|
|
91
247
|
for (const file of files) {
|
|
@@ -97,9 +253,19 @@ async function resolveAppImports(srcDir: string): Promise<void> {
|
|
|
97
253
|
const pkg = packageName(specifier);
|
|
98
254
|
if (seen.has(pkg)) continue;
|
|
99
255
|
seen.add(pkg);
|
|
100
|
-
await resolvePackage(pkg);
|
|
256
|
+
const result = await resolvePackage(pkg);
|
|
257
|
+
if (result === null) {
|
|
258
|
+
failed.push(pkg);
|
|
259
|
+
}
|
|
101
260
|
}
|
|
102
261
|
}
|
|
262
|
+
|
|
263
|
+
if (failed.length > 0) {
|
|
264
|
+
log.warn(
|
|
265
|
+
{ failed },
|
|
266
|
+
"Some imported packages could not be resolved — esbuild may fail",
|
|
267
|
+
);
|
|
268
|
+
}
|
|
103
269
|
}
|
|
104
270
|
|
|
105
271
|
/**
|
|
@@ -137,6 +303,17 @@ export async function compileApp(appDir: string): Promise<CompileResult> {
|
|
|
137
303
|
};
|
|
138
304
|
}
|
|
139
305
|
|
|
306
|
+
// Validate that path-based imports don't escape the app directory
|
|
307
|
+
const pathErrors = await validateImportPaths(srcDir, appDir);
|
|
308
|
+
if (pathErrors.length > 0) {
|
|
309
|
+
const durationMs = Math.round(performance.now() - start);
|
|
310
|
+
log.info(
|
|
311
|
+
{ durationMs, errorCount: pathErrors.length },
|
|
312
|
+
"Build blocked: imports resolve outside app directory",
|
|
313
|
+
);
|
|
314
|
+
return { ok: false, errors: pathErrors, warnings: [], durationMs };
|
|
315
|
+
}
|
|
316
|
+
|
|
140
317
|
// Scan source files for bare imports and JIT-install allowed packages
|
|
141
318
|
await resolveAppImports(srcDir);
|
|
142
319
|
|
|
@@ -10,6 +10,7 @@ import { mkdir, stat } from "node:fs/promises";
|
|
|
10
10
|
import { homedir } from "node:os";
|
|
11
11
|
import { join } from "node:path";
|
|
12
12
|
|
|
13
|
+
import { ensureBun } from "../util/bun-runtime.js";
|
|
13
14
|
import { getLogger } from "../util/logger.js";
|
|
14
15
|
|
|
15
16
|
const log = getLogger("package-resolver");
|
|
@@ -117,14 +118,11 @@ async function installPackage(
|
|
|
117
118
|
log.info({ pkg }, "Installing package into shared cache");
|
|
118
119
|
|
|
119
120
|
try {
|
|
120
|
-
const
|
|
121
|
+
const bunPath = await ensureBun();
|
|
122
|
+
const proc = Bun.spawn([bunPath, "install", "--no-save", pkg], {
|
|
121
123
|
cwd: cacheDir,
|
|
122
124
|
stdout: "pipe",
|
|
123
125
|
stderr: "pipe",
|
|
124
|
-
env: {
|
|
125
|
-
...process.env,
|
|
126
|
-
PATH: `${homedir()}/.bun/bin:${process.env.PATH}`,
|
|
127
|
-
},
|
|
128
126
|
});
|
|
129
127
|
|
|
130
128
|
// Race against timeout
|
|
@@ -55,7 +55,7 @@ mock.module("../../channels/config.js", () => ({
|
|
|
55
55
|
|
|
56
56
|
import { Command } from "commander";
|
|
57
57
|
|
|
58
|
-
import { getDb, initializeDb
|
|
58
|
+
import { getDb, initializeDb } from "../../memory/db.js";
|
|
59
59
|
import { createEvent } from "../../notifications/events-store.js";
|
|
60
60
|
import { registerNotificationsCommand } from "../commands/notifications.js";
|
|
61
61
|
|
|
@@ -129,7 +129,6 @@ beforeEach(() => {
|
|
|
129
129
|
});
|
|
130
130
|
|
|
131
131
|
afterAll(() => {
|
|
132
|
-
resetDb();
|
|
133
132
|
process.exitCode = 0;
|
|
134
133
|
});
|
|
135
134
|
|
package/src/cli/cli-memory.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { and, eq } from "drizzle-orm";
|
|
1
|
+
import { and, eq, like, sql } from "drizzle-orm";
|
|
2
2
|
import { v4 as uuid } from "uuid";
|
|
3
3
|
|
|
4
4
|
import { getDb } from "../memory/db.js";
|
|
5
|
-
import { computeMemoryFingerprint } from "../memory/fingerprint.js";
|
|
6
5
|
import { enqueueMemoryJob } from "../memory/jobs-store.js";
|
|
7
|
-
import {
|
|
6
|
+
import { memoryGraphNodes } from "../memory/schema.js";
|
|
8
7
|
import { getLogger } from "../util/logger.js";
|
|
9
8
|
import { buildCliProgram } from "./program.js";
|
|
10
9
|
|
|
@@ -28,8 +27,17 @@ export function buildCliCapabilityStatement(
|
|
|
28
27
|
return statement;
|
|
29
28
|
}
|
|
30
29
|
|
|
30
|
+
/** Default emotional charge for capability graph nodes. */
|
|
31
|
+
const DEFAULT_EMOTIONAL_CHARGE = JSON.stringify({
|
|
32
|
+
valence: 0,
|
|
33
|
+
intensity: 0.1,
|
|
34
|
+
decayCurve: "linear",
|
|
35
|
+
decayRate: 0.05,
|
|
36
|
+
originalIntensity: 0.1,
|
|
37
|
+
});
|
|
38
|
+
|
|
31
39
|
/**
|
|
32
|
-
* Upsert a capability memory
|
|
40
|
+
* Upsert a capability memory graph node for a CLI command.
|
|
33
41
|
* Best-effort: errors are logged but never thrown.
|
|
34
42
|
*/
|
|
35
43
|
export function upsertCliCapabilityMemory(
|
|
@@ -38,100 +46,95 @@ export function upsertCliCapabilityMemory(
|
|
|
38
46
|
): void {
|
|
39
47
|
try {
|
|
40
48
|
const db = getDb();
|
|
41
|
-
const subject = `cli:${commandName}`;
|
|
42
49
|
const statement = buildCliCapabilityStatement(commandName, description);
|
|
43
|
-
const
|
|
50
|
+
const content = `cli:${commandName}\n${statement}`;
|
|
44
51
|
const scopeId = "default";
|
|
45
|
-
const confidence = 1.0;
|
|
46
|
-
const importance = 0.7;
|
|
47
|
-
const fingerprint = computeMemoryFingerprint(
|
|
48
|
-
scopeId,
|
|
49
|
-
kind,
|
|
50
|
-
subject,
|
|
51
|
-
statement,
|
|
52
|
-
);
|
|
53
52
|
const now = Date.now();
|
|
54
53
|
|
|
55
54
|
const existing = db
|
|
56
55
|
.select()
|
|
57
|
-
.from(
|
|
56
|
+
.from(memoryGraphNodes)
|
|
58
57
|
.where(
|
|
59
58
|
and(
|
|
60
|
-
eq(
|
|
61
|
-
|
|
62
|
-
eq(
|
|
59
|
+
eq(memoryGraphNodes.type, "procedural"),
|
|
60
|
+
like(memoryGraphNodes.content, `cli:${commandName}\n%`),
|
|
61
|
+
eq(memoryGraphNodes.scopeId, scopeId),
|
|
63
62
|
),
|
|
64
63
|
)
|
|
65
64
|
.get();
|
|
66
65
|
|
|
67
66
|
if (existing) {
|
|
68
67
|
if (
|
|
69
|
-
existing.
|
|
70
|
-
existing.
|
|
68
|
+
existing.content === content &&
|
|
69
|
+
existing.fidelity !== "gone"
|
|
71
70
|
) {
|
|
72
|
-
// Same content — just touch
|
|
73
|
-
db.update(
|
|
74
|
-
.set({
|
|
75
|
-
.where(eq(
|
|
71
|
+
// Same content — just touch lastAccessed
|
|
72
|
+
db.update(memoryGraphNodes)
|
|
73
|
+
.set({ lastAccessed: now })
|
|
74
|
+
.where(eq(memoryGraphNodes.id, existing.id))
|
|
76
75
|
.run();
|
|
77
76
|
return;
|
|
78
77
|
}
|
|
79
78
|
|
|
80
|
-
if (existing.
|
|
81
|
-
// Content changed — update
|
|
82
|
-
db.update(
|
|
79
|
+
if (existing.fidelity !== "gone") {
|
|
80
|
+
// Content changed — update content
|
|
81
|
+
db.update(memoryGraphNodes)
|
|
83
82
|
.set({
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
lastSeenAt: now,
|
|
83
|
+
content,
|
|
84
|
+
lastAccessed: now,
|
|
87
85
|
})
|
|
88
|
-
.where(eq(
|
|
86
|
+
.where(eq(memoryGraphNodes.id, existing.id))
|
|
89
87
|
.run();
|
|
90
|
-
enqueueMemoryJob("
|
|
88
|
+
enqueueMemoryJob("embed_graph_node", { nodeId: existing.id });
|
|
91
89
|
return;
|
|
92
90
|
}
|
|
93
91
|
|
|
94
|
-
//
|
|
95
|
-
db.update(
|
|
92
|
+
// fidelity === "gone" — reactivate
|
|
93
|
+
db.update(memoryGraphNodes)
|
|
96
94
|
.set({
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
firstSeenAt: now,
|
|
95
|
+
fidelity: "vivid",
|
|
96
|
+
content,
|
|
97
|
+
created: now,
|
|
98
|
+
lastAccessed: now,
|
|
102
99
|
})
|
|
103
|
-
.where(eq(
|
|
100
|
+
.where(eq(memoryGraphNodes.id, existing.id))
|
|
104
101
|
.run();
|
|
105
|
-
enqueueMemoryJob("
|
|
102
|
+
enqueueMemoryJob("embed_graph_node", { nodeId: existing.id });
|
|
106
103
|
return;
|
|
107
104
|
}
|
|
108
105
|
|
|
109
|
-
// No existing — insert new
|
|
106
|
+
// No existing — insert new graph node
|
|
110
107
|
const id = uuid();
|
|
111
|
-
db.insert(
|
|
108
|
+
db.insert(memoryGraphNodes)
|
|
112
109
|
.values({
|
|
113
110
|
id,
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
111
|
+
content,
|
|
112
|
+
type: "procedural",
|
|
113
|
+
created: now,
|
|
114
|
+
lastAccessed: now,
|
|
115
|
+
lastConsolidated: now,
|
|
116
|
+
emotionalCharge: DEFAULT_EMOTIONAL_CHARGE,
|
|
117
|
+
fidelity: "vivid",
|
|
118
|
+
confidence: 1.0,
|
|
119
|
+
significance: 0.7,
|
|
120
|
+
stability: 14,
|
|
121
|
+
reinforcementCount: 0,
|
|
122
|
+
lastReinforced: now,
|
|
123
|
+
sourceConversations: JSON.stringify([]),
|
|
124
|
+
sourceType: "inferred",
|
|
125
|
+
narrativeRole: null,
|
|
126
|
+
partOfStory: null,
|
|
122
127
|
scopeId,
|
|
123
|
-
firstSeenAt: now,
|
|
124
|
-
lastSeenAt: now,
|
|
125
128
|
})
|
|
126
129
|
.run();
|
|
127
|
-
enqueueMemoryJob("
|
|
130
|
+
enqueueMemoryJob("embed_graph_node", { nodeId: id });
|
|
128
131
|
} catch (err) {
|
|
129
132
|
log.warn({ err, commandName }, "Failed to upsert CLI capability memory");
|
|
130
133
|
}
|
|
131
134
|
}
|
|
132
135
|
|
|
133
136
|
/**
|
|
134
|
-
* Seed capability memory
|
|
137
|
+
* Seed capability memory graph nodes for all CLI commands.
|
|
135
138
|
* Prunes stale entries whose commands are no longer registered.
|
|
136
139
|
* Best-effort: errors are logged but never thrown.
|
|
137
140
|
*/
|
|
@@ -149,24 +152,24 @@ export function seedCliCommandMemories(): void {
|
|
|
149
152
|
const db = getDb();
|
|
150
153
|
const allCapabilities = db
|
|
151
154
|
.select()
|
|
152
|
-
.from(
|
|
155
|
+
.from(memoryGraphNodes)
|
|
153
156
|
.where(
|
|
154
157
|
and(
|
|
155
|
-
eq(
|
|
156
|
-
eq(
|
|
157
|
-
|
|
158
|
+
eq(memoryGraphNodes.type, "procedural"),
|
|
159
|
+
eq(memoryGraphNodes.scopeId, "default"),
|
|
160
|
+
sql`${memoryGraphNodes.fidelity} != 'gone'`,
|
|
158
161
|
),
|
|
159
162
|
)
|
|
160
163
|
.all();
|
|
161
164
|
|
|
162
165
|
const now = Date.now();
|
|
163
166
|
for (const item of allCapabilities) {
|
|
164
|
-
if (!item.
|
|
165
|
-
const itemCommandName = item.
|
|
167
|
+
if (!item.content.startsWith("cli:")) continue;
|
|
168
|
+
const itemCommandName = item.content.split("\n")[0].replace("cli:", "");
|
|
166
169
|
if (!commandNames.has(itemCommandName)) {
|
|
167
|
-
db.update(
|
|
168
|
-
.set({
|
|
169
|
-
.where(eq(
|
|
170
|
+
db.update(memoryGraphNodes)
|
|
171
|
+
.set({ fidelity: "gone", lastAccessed: now })
|
|
172
|
+
.where(eq(memoryGraphNodes.id, item.id))
|
|
170
173
|
.run();
|
|
171
174
|
}
|
|
172
175
|
}
|