@vellumai/assistant 0.10.0 → 0.10.1-dev.202606240317.ea25efe
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 +36 -37
- package/bun.lock +3 -0
- package/docs/workflows.md +12 -7
- package/eslint-rules/cli-no-daemon-internals.js +12 -0
- package/node_modules/@slack/types/LICENSE +23 -0
- package/node_modules/@slack/types/README.md +32 -0
- package/node_modules/@slack/types/dist/block-kit/block-elements.d.ts +953 -0
- package/node_modules/@slack/types/dist/block-kit/block-elements.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/block-kit/block-elements.js +4 -0
- package/node_modules/@slack/types/dist/block-kit/block-elements.js.map +1 -0
- package/node_modules/@slack/types/dist/block-kit/blocks.d.ts +474 -0
- package/node_modules/@slack/types/dist/block-kit/blocks.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/block-kit/blocks.js +3 -0
- package/node_modules/@slack/types/dist/block-kit/blocks.js.map +1 -0
- package/node_modules/@slack/types/dist/block-kit/composition-objects.d.ts +237 -0
- package/node_modules/@slack/types/dist/block-kit/composition-objects.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/block-kit/composition-objects.js +4 -0
- package/node_modules/@slack/types/dist/block-kit/composition-objects.js.map +1 -0
- package/node_modules/@slack/types/dist/block-kit/extensions.d.ts +88 -0
- package/node_modules/@slack/types/dist/block-kit/extensions.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/block-kit/extensions.js +3 -0
- package/node_modules/@slack/types/dist/block-kit/extensions.js.map +1 -0
- package/node_modules/@slack/types/dist/calls.d.ts +26 -0
- package/node_modules/@slack/types/dist/calls.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/calls.js +6 -0
- package/node_modules/@slack/types/dist/calls.js.map +1 -0
- package/node_modules/@slack/types/dist/chunk.d.ts +52 -0
- package/node_modules/@slack/types/dist/chunk.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/chunk.js +3 -0
- package/node_modules/@slack/types/dist/chunk.js.map +1 -0
- package/node_modules/@slack/types/dist/common/bot-profile.d.ts +12 -0
- package/node_modules/@slack/types/dist/common/bot-profile.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/common/bot-profile.js +3 -0
- package/node_modules/@slack/types/dist/common/bot-profile.js.map +1 -0
- package/node_modules/@slack/types/dist/common/status-emoji-display-info.d.ts +6 -0
- package/node_modules/@slack/types/dist/common/status-emoji-display-info.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/common/status-emoji-display-info.js +3 -0
- package/node_modules/@slack/types/dist/common/status-emoji-display-info.js.map +1 -0
- package/node_modules/@slack/types/dist/dialog.d.ts +36 -0
- package/node_modules/@slack/types/dist/dialog.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/dialog.js +3 -0
- package/node_modules/@slack/types/dist/dialog.js.map +1 -0
- package/node_modules/@slack/types/dist/events/app.d.ts +204 -0
- package/node_modules/@slack/types/dist/events/app.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/app.js +3 -0
- package/node_modules/@slack/types/dist/events/app.js.map +1 -0
- package/node_modules/@slack/types/dist/events/assistant.d.ts +29 -0
- package/node_modules/@slack/types/dist/events/assistant.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/assistant.js +3 -0
- package/node_modules/@slack/types/dist/events/assistant.js.map +1 -0
- package/node_modules/@slack/types/dist/events/call.d.ts +8 -0
- package/node_modules/@slack/types/dist/events/call.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/call.js +3 -0
- package/node_modules/@slack/types/dist/events/call.js.map +1 -0
- package/node_modules/@slack/types/dist/events/channel.d.ts +85 -0
- package/node_modules/@slack/types/dist/events/channel.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/channel.js +3 -0
- package/node_modules/@slack/types/dist/events/channel.js.map +1 -0
- package/node_modules/@slack/types/dist/events/dnd.d.ts +24 -0
- package/node_modules/@slack/types/dist/events/dnd.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/dnd.js +3 -0
- package/node_modules/@slack/types/dist/events/dnd.js.map +1 -0
- package/node_modules/@slack/types/dist/events/email.d.ts +6 -0
- package/node_modules/@slack/types/dist/events/email.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/email.js +3 -0
- package/node_modules/@slack/types/dist/events/email.js.map +1 -0
- package/node_modules/@slack/types/dist/events/emoji.d.ts +11 -0
- package/node_modules/@slack/types/dist/events/emoji.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/emoji.js +3 -0
- package/node_modules/@slack/types/dist/events/emoji.js.map +1 -0
- package/node_modules/@slack/types/dist/events/entity-details-requested.d.ts +21 -0
- package/node_modules/@slack/types/dist/events/entity-details-requested.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/entity-details-requested.js +3 -0
- package/node_modules/@slack/types/dist/events/entity-details-requested.js.map +1 -0
- package/node_modules/@slack/types/dist/events/file.d.ts +60 -0
- package/node_modules/@slack/types/dist/events/file.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/file.js +4 -0
- package/node_modules/@slack/types/dist/events/file.js.map +1 -0
- package/node_modules/@slack/types/dist/events/function.d.ts +33 -0
- package/node_modules/@slack/types/dist/events/function.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/function.js +3 -0
- package/node_modules/@slack/types/dist/events/function.js.map +1 -0
- package/node_modules/@slack/types/dist/events/grid-migration.d.ts +9 -0
- package/node_modules/@slack/types/dist/events/grid-migration.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/grid-migration.js +3 -0
- package/node_modules/@slack/types/dist/events/grid-migration.js.map +1 -0
- package/node_modules/@slack/types/dist/events/group.d.ts +55 -0
- package/node_modules/@slack/types/dist/events/group.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/group.js +3 -0
- package/node_modules/@slack/types/dist/events/group.js.map +1 -0
- package/node_modules/@slack/types/dist/events/im.d.ts +26 -0
- package/node_modules/@slack/types/dist/events/im.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/im.js +3 -0
- package/node_modules/@slack/types/dist/events/im.js.map +1 -0
- package/node_modules/@slack/types/dist/events/index.d.ts +60 -0
- package/node_modules/@slack/types/dist/events/index.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/index.js +43 -0
- package/node_modules/@slack/types/dist/events/index.js.map +1 -0
- package/node_modules/@slack/types/dist/events/invite.d.ts +20 -0
- package/node_modules/@slack/types/dist/events/invite.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/invite.js +3 -0
- package/node_modules/@slack/types/dist/events/invite.js.map +1 -0
- package/node_modules/@slack/types/dist/events/link-shared.d.ts +16 -0
- package/node_modules/@slack/types/dist/events/link-shared.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/link-shared.js +3 -0
- package/node_modules/@slack/types/dist/events/link-shared.js.map +1 -0
- package/node_modules/@slack/types/dist/events/member.d.ts +19 -0
- package/node_modules/@slack/types/dist/events/member.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/member.js +3 -0
- package/node_modules/@slack/types/dist/events/member.js.map +1 -0
- package/node_modules/@slack/types/dist/events/message-metadata.d.ts +38 -0
- package/node_modules/@slack/types/dist/events/message-metadata.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/message-metadata.js +3 -0
- package/node_modules/@slack/types/dist/events/message-metadata.js.map +1 -0
- package/node_modules/@slack/types/dist/events/message.d.ts +306 -0
- package/node_modules/@slack/types/dist/events/message.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/message.js +3 -0
- package/node_modules/@slack/types/dist/events/message.js.map +1 -0
- package/node_modules/@slack/types/dist/events/pin.d.ts +60 -0
- package/node_modules/@slack/types/dist/events/pin.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/pin.js +3 -0
- package/node_modules/@slack/types/dist/events/pin.js.map +1 -0
- package/node_modules/@slack/types/dist/events/reaction.d.ts +23 -0
- package/node_modules/@slack/types/dist/events/reaction.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/reaction.js +3 -0
- package/node_modules/@slack/types/dist/events/reaction.js.map +1 -0
- package/node_modules/@slack/types/dist/events/shared-channel.d.ts +134 -0
- package/node_modules/@slack/types/dist/events/shared-channel.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/shared-channel.js +3 -0
- package/node_modules/@slack/types/dist/events/shared-channel.js.map +1 -0
- package/node_modules/@slack/types/dist/events/star.d.ts +13 -0
- package/node_modules/@slack/types/dist/events/star.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/star.js +3 -0
- package/node_modules/@slack/types/dist/events/star.js.map +1 -0
- package/node_modules/@slack/types/dist/events/steps-from-apps.d.ts +82 -0
- package/node_modules/@slack/types/dist/events/steps-from-apps.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/steps-from-apps.js +3 -0
- package/node_modules/@slack/types/dist/events/steps-from-apps.js.map +1 -0
- package/node_modules/@slack/types/dist/events/subteam.d.ts +66 -0
- package/node_modules/@slack/types/dist/events/subteam.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/subteam.js +3 -0
- package/node_modules/@slack/types/dist/events/subteam.js.map +1 -0
- package/node_modules/@slack/types/dist/events/team.d.ts +99 -0
- package/node_modules/@slack/types/dist/events/team.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/team.js +3 -0
- package/node_modules/@slack/types/dist/events/team.js.map +1 -0
- package/node_modules/@slack/types/dist/events/token.d.ts +8 -0
- package/node_modules/@slack/types/dist/events/token.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/token.js +3 -0
- package/node_modules/@slack/types/dist/events/token.js.map +1 -0
- package/node_modules/@slack/types/dist/events/user.d.ts +313 -0
- package/node_modules/@slack/types/dist/events/user.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/user.js +3 -0
- package/node_modules/@slack/types/dist/events/user.js.map +1 -0
- package/node_modules/@slack/types/dist/index.d.ts +12 -0
- package/node_modules/@slack/types/dist/index.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/index.js +28 -0
- package/node_modules/@slack/types/dist/index.js.map +1 -0
- package/node_modules/@slack/types/dist/message-attachments.d.ts +171 -0
- package/node_modules/@slack/types/dist/message-attachments.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/message-attachments.js +3 -0
- package/node_modules/@slack/types/dist/message-attachments.js.map +1 -0
- package/node_modules/@slack/types/dist/message-metadata.d.ts +281 -0
- package/node_modules/@slack/types/dist/message-metadata.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/message-metadata.js +27 -0
- package/node_modules/@slack/types/dist/message-metadata.js.map +1 -0
- package/node_modules/@slack/types/dist/views.d.ts +71 -0
- package/node_modules/@slack/types/dist/views.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/views.js +3 -0
- package/node_modules/@slack/types/dist/views.js.map +1 -0
- package/node_modules/@slack/types/package.json +47 -0
- package/node_modules/@vellumai/gateway-client/bun.lock +3 -0
- package/node_modules/@vellumai/gateway-client/package.json +1 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/contact-read-contracts.test.ts +69 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/guardian-delivery-contract.test.ts +91 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/trust-verdict-contract.test.ts +96 -0
- package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +162 -0
- package/node_modules/@vellumai/gateway-client/src/guardian-delivery-contract.ts +48 -0
- package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +8 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +28 -0
- package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +4 -2
- package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +3 -2
- package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +95 -0
- package/openapi.yaml +458 -18
- package/package.json +2 -1
- package/scripts/memory-inspect.ts +24 -14
- package/scripts/test.sh +36 -15
- package/src/__tests__/access-request-seed-content-blocks.test.ts +83 -103
- package/src/__tests__/activation-early-marking.test.ts +1 -1
- package/src/__tests__/actor-token-service.test.ts +39 -17
- package/src/__tests__/agent-loop-callsite-precedence.test.ts +1 -40
- package/src/__tests__/agent-loop-compaction-events.test.ts +0 -1
- package/src/__tests__/agent-loop-compaction-strip.test.ts +0 -1
- package/src/__tests__/agent-loop-exit-reason.test.ts +0 -1
- package/src/__tests__/agent-loop-pushes-post-hook-prompt.test.ts +306 -0
- package/src/__tests__/agent-loop-regrowth-guard.test.ts +0 -1
- package/src/__tests__/agent-loop.test.ts +3 -0
- package/src/__tests__/agent-wake-override-profile.test.ts +2 -0
- package/src/__tests__/anthropic-provider.test.ts +210 -9
- package/src/__tests__/app-builder-skill-instructions.test.ts +47 -5
- package/src/__tests__/app-conversation-ids-backfill.test.ts +1 -1
- package/src/__tests__/app-source-watcher.test.ts +30 -10
- package/src/__tests__/approval-cascade.test.ts +6 -0
- package/src/__tests__/approval-interception-trust-gates.test.ts +151 -0
- package/src/__tests__/approval-primitive.test.ts +1 -1
- package/src/__tests__/approval-routes-http.test.ts +1 -1
- package/src/__tests__/assistant-attachments.test.ts +155 -0
- package/src/__tests__/assistant-event-hub-machine-name.test.ts +2 -4
- package/src/__tests__/assistant-events-sse-hardening.test.ts +1 -1
- package/src/__tests__/assistant-events-sse-shed.test.ts +1 -1
- package/src/__tests__/attachment-upload-trusted-source.test.ts +13 -8
- package/src/__tests__/attachments-store.test.ts +1 -1
- package/src/__tests__/audit-log-rotation.test.ts +50 -54
- package/src/__tests__/auth-fallback-events-store.test.ts +1 -1
- package/src/__tests__/auto-analysis-end-to-end.test.ts +9 -14
- package/src/__tests__/background-shell-bash.test.ts +4 -1
- package/src/__tests__/background-shell-host-bash.test.ts +17 -3
- package/src/__tests__/background-workers-disk-pressure.test.ts +1 -0
- package/src/__tests__/call-controller.test.ts +20 -1
- package/src/__tests__/call-conversation-messages.test.ts +1 -1
- package/src/__tests__/call-domain.test.ts +1 -1
- package/src/__tests__/call-pointer-messages.test.ts +3 -4
- package/src/__tests__/call-recovery.test.ts +1 -1
- package/src/__tests__/call-routes-http.test.ts +1 -1
- package/src/__tests__/call-store.test.ts +1 -1
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +1 -1
- package/src/__tests__/canonical-guardian-store.test.ts +24 -1
- package/src/__tests__/card-surface-data.test.ts +60 -0
- package/src/__tests__/channel-approval-routes.test.ts +73 -1119
- package/src/__tests__/channel-delivery-store.test.ts +1 -1
- package/src/__tests__/channel-guardian.test.ts +291 -641
- package/src/__tests__/channel-inbound-disk-pressure.test.ts +1 -2
- package/src/__tests__/channel-retry-sweep.test.ts +1 -1
- package/src/__tests__/compaction-events.test.ts +6 -0
- package/src/__tests__/compaction-trail-store.test.ts +6 -5
- package/src/__tests__/compaction.benchmark.test.ts +0 -1
- package/src/__tests__/compactor-image-manifest-trust.test.ts +1 -1
- package/src/__tests__/config-loader-backfill.test.ts +188 -52
- package/src/__tests__/config-schema.test.ts +35 -0
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +1 -2
- package/src/__tests__/contact-store-user-file.test.ts +2 -2
- package/src/__tests__/contacts-relay-reads.test.ts +409 -0
- package/src/__tests__/contacts-tools.test.ts +4 -4
- package/src/__tests__/contacts-write.test.ts +1 -2
- package/src/__tests__/context-search-conversations-source.test.ts +1 -1
- package/src/__tests__/context-window-manager-compact-retry.test.ts +6 -2
- package/src/__tests__/context-window-manager-overflow-rung.test.ts +6 -2
- package/src/__tests__/conversation-abort-tool-results.test.ts +6 -0
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +3 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +3 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +3 -0
- package/src/__tests__/conversation-agent-loop.test.ts +7 -0
- package/src/__tests__/conversation-attachments.test.ts +2 -5
- package/src/__tests__/conversation-attention-store.test.ts +1 -1
- package/src/__tests__/conversation-attention-telegram.test.ts +1 -2
- package/src/__tests__/conversation-clear-safety.test.ts +1 -1
- package/src/__tests__/conversation-confirmation-signals.test.ts +6 -0
- package/src/__tests__/conversation-crud-inference-profile.test.ts +1 -1
- package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +12 -19
- package/src/__tests__/conversation-disk-view-integration.test.ts +1 -1
- package/src/__tests__/conversation-disk-view.test.ts +1 -1
- package/src/__tests__/conversation-fork-crud.test.ts +10 -8
- package/src/__tests__/conversation-fork-retrospective.test.ts +250 -0
- package/src/__tests__/conversation-fork-route.test.ts +1 -1
- package/src/__tests__/conversation-inference-profile-list.test.ts +1 -1
- package/src/__tests__/conversation-inference-profile-route.test.ts +1 -1
- package/src/__tests__/conversation-init.benchmark.test.ts +1 -1
- package/src/__tests__/conversation-key-store-disk-view.test.ts +1 -1
- package/src/__tests__/conversation-lifecycle.test.ts +117 -0
- package/src/__tests__/conversation-list-source.test.ts +3 -3
- package/src/__tests__/conversation-process-callsite.test.ts +6 -14
- package/src/__tests__/conversation-provider-retry-repair.test.ts +6 -0
- package/src/__tests__/conversation-queue.test.ts +95 -0
- package/src/__tests__/conversation-routes-disk-view.test.ts +1 -1
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +12 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +12 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +115 -12
- package/src/__tests__/conversation-slash-queue.test.ts +6 -0
- package/src/__tests__/conversation-slash-unknown.test.ts +6 -0
- package/src/__tests__/conversation-speed-override.test.ts +6 -0
- package/src/__tests__/conversation-starter-routes.test.ts +5 -5
- package/src/__tests__/conversation-store.test.ts +1 -1
- package/src/__tests__/conversation-surfaces-activation-emit.test.ts +4 -4
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +352 -0
- package/src/__tests__/conversation-sync-tags.test.ts +1 -1
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +47 -0
- package/src/__tests__/conversation-usage.test.ts +1 -1
- package/src/__tests__/conversation-wipe.test.ts +9 -8
- package/src/__tests__/conversation-workspace-cache-state.test.ts +6 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +6 -0
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +6 -0
- package/src/__tests__/conversations-import-system-filter.test.ts +1 -1
- package/src/__tests__/copy-composer-tc-templates.test.ts +17 -0
- package/src/__tests__/credential-security-invariants.test.ts +0 -1
- package/src/__tests__/db-acp-history.test.ts +2 -2
- package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +5 -7
- package/src/__tests__/db-conversation-inference-profile-migration.test.ts +6 -7
- package/src/__tests__/db-llm-request-log-provider-migration.test.ts +5 -10
- package/src/__tests__/db-migration-rollback.test.ts +129 -39
- package/src/__tests__/db-proxy-transaction.test.ts +1 -1
- package/src/__tests__/db-schedule-syntax-migration.test.ts +0 -11
- package/src/__tests__/db-test-helpers.ts +36 -19
- package/src/__tests__/delete-propagation.test.ts +1 -1
- package/src/__tests__/deterministic-verification-control-plane.test.ts +28 -8
- package/src/__tests__/disk-pressure-guard.test.ts +41 -0
- package/src/__tests__/disk-pressure-tools.test.ts +41 -1
- package/src/__tests__/dm-backfill.test.ts +1 -1
- package/src/__tests__/drop-capability-card-state-migration.test.ts +0 -8
- package/src/__tests__/dynamic-page-surface.test.ts +0 -94
- package/src/__tests__/edit-propagation.test.ts +1 -1
- package/src/__tests__/emit-signal-routing-intent.test.ts +93 -5
- package/src/__tests__/empty-response-hook.test.ts +42 -0
- package/src/__tests__/events-client-registration.test.ts +1 -1
- package/src/__tests__/events-dev-bypass-actor.test.ts +7 -1
- package/src/__tests__/followup-tools.test.ts +1 -1
- package/src/__tests__/gemini-count-tokens.test.ts +70 -0
- package/src/__tests__/guardian-action-sweep.test.ts +9 -2
- package/src/__tests__/guardian-binding-drift-heal.test.ts +76 -11
- package/src/__tests__/guardian-card-withdrawal.test.ts +1 -1
- package/src/__tests__/guardian-decision-primitive-canonical.test.ts +1 -1
- package/src/__tests__/guardian-dispatch.test.ts +96 -2
- package/src/__tests__/guardian-outbound-http.test.ts +20 -12
- package/src/__tests__/guardian-principal-id-roundtrip.test.ts +1 -1
- package/src/__tests__/guardian-routing-invariants.test.ts +2 -4
- package/src/__tests__/guardian-routing-state.test.ts +1 -2
- package/src/__tests__/guardian-verification-voice-binding.test.ts +1 -1
- package/src/__tests__/headless-browser-mode.test.ts +2 -2
- package/src/__tests__/heartbeat-disk-pressure.test.ts +4 -0
- package/src/__tests__/heartbeat-service.test.ts +6 -0
- package/src/__tests__/helpers/channel-test-adapter.ts +92 -0
- package/src/__tests__/host-app-control-routes.test.ts +24 -30
- package/src/__tests__/host-bash-routes.test.ts +31 -41
- package/src/__tests__/host-browser-routes.test.ts +26 -32
- package/src/__tests__/host-cu-routes-targeted.test.ts +25 -33
- package/src/__tests__/host-file-routes-targeted.test.ts +40 -52
- package/src/__tests__/host-transfer-routes-targeted.test.ts +31 -43
- package/src/__tests__/http-conversation-lineage.test.ts +1 -1
- package/src/__tests__/http-user-message-parity.test.ts +165 -8
- package/src/__tests__/image-recovery-hook.test.ts +1 -1
- package/src/__tests__/inbound-invite-redemption.test.ts +1 -2
- package/src/__tests__/inbound-trust-verdict.test.ts +254 -0
- package/src/__tests__/inference-profile-reaper.test.ts +1 -1
- package/src/__tests__/inference-profile-session-handler.test.ts +1 -1
- package/src/__tests__/inference-profile-session-ipc.test.ts +1 -1
- package/src/__tests__/injector-chain.test.ts +1 -1
- package/src/__tests__/injector-disk-pressure.test.ts +11 -6
- package/src/__tests__/internal-telemetry-routes.test.ts +1 -1
- package/src/__tests__/invite-redemption-service.test.ts +244 -43
- package/src/__tests__/invite-routes-http.test.ts +35 -186
- package/src/__tests__/invite-service-ipc.test.ts +287 -0
- package/src/__tests__/jobs-store-qdrant-breaker.test.ts +5 -5
- package/src/__tests__/jobs-store-upsert-debounced.test.ts +9 -12
- package/src/__tests__/list-messages-attachments.test.ts +42 -1
- package/src/__tests__/list-messages-client-message-id.test.ts +1 -1
- package/src/__tests__/list-messages-hidden-metadata.test.ts +1 -1
- package/src/__tests__/list-messages-page-latest.test.ts +1 -1
- package/src/__tests__/list-messages-tool-merge.test.ts +1 -1
- package/src/__tests__/llm-context-normalization.test.ts +105 -0
- package/src/__tests__/llm-context-route-provider.test.ts +69 -4
- package/src/__tests__/llm-request-log-agent-loop-exit-reason.test.ts +9 -5
- package/src/__tests__/llm-request-log-call-site.test.ts +6 -6
- package/src/__tests__/llm-request-log-turn-query.test.ts +27 -13
- package/src/__tests__/llm-resolver.test.ts +205 -5
- package/src/__tests__/llm-usage-store.test.ts +65 -1
- package/src/__tests__/log-export-routes.test.ts +1 -1
- package/src/__tests__/log-export-workspace.test.ts +3 -3
- package/src/__tests__/media-stream-server-integration.test.ts +127 -0
- package/src/__tests__/memory-jobs-worker-lanes.test.ts +5 -5
- package/src/__tests__/memory-recall-log-store.test.ts +1 -1
- package/src/__tests__/memory-upsert-concurrency.test.ts +3 -4
- package/src/__tests__/messages-after-tiebreaker.test.ts +1 -1
- package/src/__tests__/migration-import-from-url.test.ts +2 -2
- package/src/__tests__/mtime-cache.test.ts +375 -0
- package/src/__tests__/non-member-access-request.test.ts +190 -19
- package/src/__tests__/notification-broadcaster.test.ts +4 -0
- package/src/__tests__/notification-candidate-guardian-context.test.ts +203 -0
- package/src/__tests__/notification-decision-recipient-context.test.ts +33 -32
- package/src/__tests__/notification-deep-link.test.ts +4 -0
- package/src/__tests__/notification-guardian-path.test.ts +20 -1
- package/src/__tests__/notification-schedule-notify-dedup.test.ts +1 -1
- package/src/__tests__/oauth-provider-profiles.test.ts +1 -1
- package/src/__tests__/oauth-provider-visibility.test.ts +1 -1
- package/src/__tests__/oauth-store.test.ts +1 -1
- package/src/__tests__/pending-interactions-resolved-event.test.ts +7 -4
- package/src/__tests__/persist-unsendable-image-downscale.test.ts +1 -1
- package/src/__tests__/persist-unsendable-image.test.ts +1 -1
- package/src/__tests__/persona-resolver.test.ts +39 -1
- package/src/__tests__/platform-bash-auto-approve.test.ts +1 -1
- package/src/__tests__/playbook-execution.test.ts +1 -1
- package/src/__tests__/playbook-tools.test.ts +1 -1
- package/src/__tests__/plugin-api-model-profiles.test.ts +74 -21
- package/src/__tests__/plugin-bootstrap.test.ts +78 -0
- package/src/__tests__/provider-platform-proxy-integration.test.ts +25 -5
- package/src/__tests__/provider-usage-tracking.test.ts +40 -1
- package/src/__tests__/prune-old-conversations-job.test.ts +1 -1
- package/src/__tests__/reaction-persistence.test.ts +1 -1
- package/src/__tests__/registry.test.ts +3 -0
- package/src/__tests__/relay-server.test.ts +1026 -73
- package/src/__tests__/runtime-attachment-metadata.test.ts +9 -1
- package/src/__tests__/runtime-events-sse-bilingual.test.ts +7 -9
- package/src/__tests__/runtime-events-sse-parity.test.ts +1 -1
- package/src/__tests__/runtime-events-sse-reconnect.test.ts +1 -1
- package/src/__tests__/runtime-events-sse.test.ts +1 -1
- package/src/__tests__/schedule-retry.test.ts +1 -1
- package/src/__tests__/schedule-routes-workflow-validation.test.ts +1 -1
- package/src/__tests__/schedule-routes.test.ts +1 -1
- package/src/__tests__/schedule-store.test.ts +1 -1
- package/src/__tests__/schedule-tools.test.ts +1 -1
- package/src/__tests__/scheduler-disk-pressure.test.ts +1 -1
- package/src/__tests__/scheduler-recurrence.test.ts +1 -1
- package/src/__tests__/scheduler-reuse-conversation.test.ts +1 -1
- package/src/__tests__/scheduler-wake.test.ts +2 -1
- package/src/__tests__/scoped-approval-grants.test.ts +1 -1
- package/src/__tests__/scoped-grant-security-matrix.test.ts +5 -5
- package/src/__tests__/scrub-corrupted-image-attachments.test.ts +0 -8
- package/src/__tests__/secret-ingress-http.test.ts +12 -0
- package/src/__tests__/secret-routes-platform-proxy.test.ts +1 -0
- package/src/__tests__/send-endpoint-busy.test.ts +31 -9
- package/src/__tests__/sequence-store.test.ts +1 -1
- package/src/__tests__/server-history-render.test.ts +40 -1
- package/src/__tests__/settings-routes.test.ts +11 -10
- package/src/__tests__/skill-load-tool.test.ts +72 -0
- package/src/__tests__/skills.test.ts +44 -0
- package/src/__tests__/slack-inbound-verification.test.ts +48 -5
- package/src/__tests__/slack-messaging-token-resolution.test.ts +13 -2
- package/src/__tests__/slack-reaction-canonical-approval.test.ts +1 -1
- package/src/__tests__/sse-actor-principal-guardian-source.test.ts +102 -0
- package/src/__tests__/steer-on-enqueue-question.test.ts +181 -0
- package/src/__tests__/stt-hints.test.ts +44 -13
- package/src/__tests__/subagent-detail.test.ts +27 -0
- package/src/__tests__/subagent-disposal.test.ts +65 -0
- package/src/__tests__/subagent-tool-gate-mode.test.ts +2 -73
- package/src/__tests__/subagent-tools.test.ts +1 -31
- package/src/__tests__/system-prompt.test.ts +1 -1
- package/src/__tests__/system-storage-cleanup-skill.test.ts +56 -0
- package/src/__tests__/task-compiler.test.ts +1 -1
- package/src/__tests__/task-management-tools.test.ts +1 -1
- package/src/__tests__/task-memory-cleanup.test.ts +9 -6
- package/src/__tests__/task-scheduler.test.ts +1 -1
- package/src/__tests__/thread-backfill.test.ts +1 -1
- package/src/__tests__/tool-approval-handler.test.ts +1 -1
- package/src/__tests__/tool-approval-seed-content-blocks.test.ts +2 -0
- package/src/__tests__/tool-executor.test.ts +37 -1
- package/src/__tests__/tool-grant-request-escalation.test.ts +1 -2
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +73 -1
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +34 -34
- package/src/__tests__/trusted-contact-multichannel.test.ts +1 -2
- package/src/__tests__/trusted-contact-verification.test.ts +1 -1
- package/src/__tests__/turn-boundary-resolution.test.ts +3 -3
- package/src/__tests__/turn-events-store.test.ts +1 -1
- package/src/__tests__/twilio-routes.test.ts +98 -3
- package/src/__tests__/usage-cache-backfill-migration.test.ts +20 -10
- package/src/__tests__/usage-routes.test.ts +1 -1
- package/src/__tests__/user-plugin-loader.test.ts +34 -29
- package/src/__tests__/verification-control-plane-policy.test.ts +2 -2
- package/src/__tests__/voice-invite-redemption.test.ts +134 -36
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +1 -1
- package/src/__tests__/voice-session-bridge.test.ts +1 -1
- package/src/__tests__/workspace-git-service.test.ts +114 -1
- package/src/__tests__/workspace-heartbeat-service.test.ts +45 -0
- package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +1 -1
- package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +1 -1
- package/src/__tests__/workspace-migration-028-recover-conversations-from-disk-view.test.ts +88 -18
- package/src/__tests__/workspace-migration-108-drop-balanced-economy-profile.test.ts +6 -6
- package/src/__tests__/workspace-migration-109-swap-quality-profile-to-glm-5p2.test.ts +281 -0
- package/src/__tests__/workspace-migration-110-flip-balanced-profile-to-together.test.ts +167 -0
- package/src/__tests__/workspace-migrations-runner.test.ts +55 -0
- package/src/__tests__/workspace-tool-loader.test.ts +3 -0
- package/src/a2a/__tests__/e2e-a2a-channel.test.ts +1 -1
- package/src/a2a/__tests__/task-store.test.ts +1 -1
- package/src/acp/__tests__/session-manager-persistence.test.ts +1 -1
- package/src/acp/__tests__/session-manager-resume.test.ts +22 -11
- package/src/acp/__tests__/session-manager-startup.test.ts +1 -1
- package/src/acp/__tests__/session-manager.test.ts +72 -1
- package/src/acp/index.ts +10 -0
- package/src/acp/session-manager.ts +35 -0
- package/src/agent/loop-exclusive-tool.test.ts +150 -0
- package/src/agent/loop.ts +101 -27
- package/src/api/constants/sse-replay.ts +41 -0
- package/src/api/events/ui-surface-show.ts +8 -3
- package/src/api/index.ts +7 -6
- package/src/api/responses/conversation-message.ts +4 -0
- package/src/api/responses/llm-request-log-entry.ts +25 -0
- package/src/api/responses/subagent-detail.ts +17 -0
- package/src/api/surfaces.ts +33 -0
- package/src/approvals/AGENTS.md +1 -2
- package/src/approvals/guardian-decision-primitive.ts +13 -210
- package/src/approvals/guardian-request-resolvers.ts +104 -58
- package/src/background-wake/wake-intent-hooks.test.ts +1 -1
- package/src/calls/__tests__/inbound-trust-reader.test.ts +110 -0
- package/src/calls/__tests__/relay-setup-router.test.ts +349 -65
- package/src/calls/guardian-dispatch.ts +10 -8
- package/src/calls/inbound-trust-reader.ts +56 -0
- package/src/calls/media-stream-server.ts +21 -0
- package/src/calls/relay-server.ts +231 -72
- package/src/calls/relay-setup-router.ts +57 -13
- package/src/calls/relay-verification.ts +7 -7
- package/src/calls/stt-hints.ts +9 -12
- package/src/calls/twilio-routes.ts +13 -3
- package/src/cli/commands/__tests__/cache.test.ts +8 -1
- package/src/cli/commands/cache.ts +194 -181
- package/src/cli/commands/contacts.ts +6 -24
- package/src/cli/commands/db/__tests__/repair.test.ts +15 -6
- package/src/cli/commands/db/__tests__/status.test.ts +7 -3
- package/src/cli/commands/db/status.ts +212 -33
- package/src/cli/commands/mcp.ts +252 -218
- package/src/cli/commands/memory/__tests__/memory-v3.test.ts +6 -1
- package/src/cli/commands/memory/__tests__/worker.test.ts +302 -0
- package/src/cli/commands/memory/index.ts +4 -0
- package/src/cli/commands/memory/memory-retrospective.ts +129 -0
- package/src/cli/commands/memory/memory-v3.ts +176 -4
- package/src/cli/commands/memory/worker.ts +175 -0
- package/src/cli/commands/plugins.ts +343 -14
- package/src/cli/lib/__tests__/install-from-github.test.ts +40 -0
- package/src/cli/lib/__tests__/list-installed-plugins.test.ts +160 -1
- package/src/cli/lib/__tests__/plugin-pin-history.test.ts +162 -0
- package/src/cli/lib/__tests__/toggle-plugin.test.ts +158 -0
- package/src/cli/lib/install-from-github.ts +47 -6
- package/src/cli/lib/list-installed-plugins.ts +179 -1
- package/src/cli/lib/plugin-marketplace.ts +11 -0
- package/src/cli/lib/plugin-pin-history.ts +257 -0
- package/src/cli/lib/toggle-plugin.ts +146 -0
- package/src/config/__tests__/loader-callsite-strip-fallback.test.ts +143 -0
- package/src/config/__tests__/sync-gated-profiles.test.ts +2 -2
- package/src/config/bundled-skills/app-builder/SKILL.md +15 -33
- package/src/config/bundled-skills/app-builder/references/DESIGN_SYSTEM.md +3 -8
- package/src/config/bundled-skills/app-builder/references/INTERACTION_HOOKS.md +64 -37
- package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +1 -1
- package/src/config/bundled-skills/app-builder/references/WIDGETS.md +14 -72
- package/src/config/bundled-skills/app-builder/references/examples/README.md +1 -2
- package/src/config/bundled-skills/contacts/SKILL.md +7 -12
- package/src/config/bundled-skills/messaging/tools/shared.ts +4 -1
- package/src/config/bundled-skills/system-storage-cleanup/SKILL.md +74 -0
- package/src/config/bundled-skills/workflows/SKILL.md +4 -3
- package/src/config/call-site-defaults.ts +11 -2
- package/src/config/feature-flag-registry.json +0 -8
- package/src/config/llm-resolver.ts +151 -14
- package/src/config/loader.ts +36 -5
- package/src/config/profile-dispatchability.ts +11 -0
- package/src/config/schemas/__tests__/memory-v3.test.ts +1 -0
- package/src/config/schemas/call-site-catalog.ts +7 -0
- package/src/config/schemas/llm.ts +2 -0
- package/src/config/schemas/memory-lifecycle.ts +17 -3
- package/src/config/schemas/memory-v3.ts +7 -0
- package/src/config/schemas/memory.ts +4 -0
- package/src/config/schemas/timeouts.ts +32 -0
- package/src/config/seed-inference-profiles.ts +147 -50
- package/src/config/skills.ts +27 -5
- package/src/config/sync-gated-profiles.ts +13 -1
- package/src/contacts/__tests__/guardian-delivery-reader.test.ts +312 -0
- package/src/contacts/contact-store.ts +21 -0
- package/src/contacts/contacts-write.ts +3 -0
- package/src/contacts/guardian-delivery-reader.ts +223 -0
- package/src/contacts/member-status.ts +9 -0
- package/src/credential-health/credential-health-service.ts +1 -5
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +44 -0
- package/src/daemon/app-source-watcher.ts +31 -18
- package/src/daemon/assistant-attachments.ts +94 -4
- package/src/daemon/conversation-agent-loop-handlers.ts +3 -0
- package/src/daemon/conversation-agent-loop.ts +18 -36
- package/src/daemon/conversation-process.ts +35 -16
- package/src/daemon/conversation-runtime-assembly.ts +91 -66
- package/src/daemon/conversation-surfaces.ts +273 -18
- package/src/daemon/conversation-tool-setup.ts +24 -64
- package/src/daemon/conversation.ts +149 -53
- package/src/daemon/disk-pressure-guard.ts +12 -2
- package/src/daemon/event-loop-watchdog.test.ts +85 -0
- package/src/daemon/event-loop-watchdog.ts +133 -0
- package/src/daemon/external-plugins-bootstrap.ts +26 -80
- package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +1 -1
- package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +1 -1
- package/src/daemon/handlers/__tests__/config-a2a-invite.test.ts +1 -1
- package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +1 -1
- package/src/daemon/handlers/__tests__/config-a2a.test.ts +1 -1
- package/src/daemon/handlers/config-channels.ts +41 -27
- package/src/daemon/handlers/conversations.ts +84 -0
- package/src/daemon/handlers/shared.ts +7 -0
- package/src/daemon/lifecycle.ts +44 -5
- package/src/daemon/memory-v2-startup.test.ts +72 -0
- package/src/daemon/memory-v2-startup.ts +87 -19
- package/src/daemon/message-types/inbox.ts +0 -6
- package/src/daemon/message-types/messages.ts +0 -4
- package/src/daemon/message-types/surfaces.ts +12 -11
- package/src/daemon/server.ts +0 -4
- package/src/daemon/shutdown-handlers.ts +20 -0
- package/src/daemon/tool-setup-types.ts +7 -5
- package/src/daemon/trust-context.ts +6 -0
- package/src/daemon/wake-conversation-ops.ts +70 -0
- package/src/daemon/workspace-tools-watcher.ts +7 -3
- package/src/documents/document-comments-store.test.ts +1 -1
- package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +1 -1
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +6 -0
- package/src/heartbeat/heartbeat-service.ts +3 -4
- package/src/ipc/__tests__/attachment-ipc.test.ts +1 -1
- package/src/ipc/__tests__/browser-ipc.test.ts +73 -2
- package/src/ipc/__tests__/clients-list-ipc.test.ts +1 -1
- package/src/ipc/__tests__/watcher-ipc.test.ts +59 -39
- package/src/ipc/assistant-server.ts +10 -2
- package/src/ipc/gateway-client.ts +2 -1
- package/src/ipc/routes/__tests__/invite-ipc-routes.test.ts +58 -0
- package/src/ipc/routes/invite-ipc-routes.ts +66 -0
- package/src/live-voice/__tests__/live-voice-archive.test.ts +1 -1
- package/src/memory/__tests__/activation-session-store.test.ts +1 -1
- package/src/memory/__tests__/auto-analysis-guard.test.ts +1 -1
- package/src/memory/__tests__/conversation-group-migration.test.ts +1 -1
- package/src/memory/__tests__/conversation-queries.test.ts +1 -1
- package/src/memory/__tests__/db-async-query.test.ts +1 -1
- package/src/memory/__tests__/db-logs-attach.test.ts +110 -0
- package/src/memory/__tests__/db-maintenance.test.ts +28 -36
- package/src/memory/__tests__/db-memory-attach.test.ts +113 -0
- package/src/memory/__tests__/find-analysis-conversation.test.ts +1 -1
- package/src/memory/__tests__/find-most-recent-retrospective-for.test.ts +1 -1
- package/src/memory/__tests__/fork-message-copy.test.ts +232 -0
- package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +3 -0
- package/src/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +5 -5
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +8 -6
- package/src/memory/__tests__/memory-retrospective-job.test.ts +30 -37
- package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +69 -66
- package/src/memory/__tests__/memory-retrospective-state.test.ts +1 -1
- package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +1 -1
- package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +1 -1
- package/src/memory/__tests__/onboarding-events-store.test.ts +1 -1
- package/src/memory/__tests__/prompt-override.test.ts +192 -0
- package/src/memory/__tests__/table-relocation.test.ts +129 -0
- package/src/memory/conversation-crud.ts +461 -152
- package/src/memory/db-async-query.ts +89 -5
- package/src/memory/db-connection.ts +101 -18
- package/src/memory/db-init.ts +409 -234
- package/src/memory/db-maintenance.ts +43 -38
- package/src/memory/db-singleton.ts +45 -19
- package/src/memory/embedding-gemini.test.ts +3 -1
- package/src/memory/embedding-gemini.ts +18 -2
- package/src/memory/fork-message-copy.ts +170 -0
- package/src/memory/graph/__tests__/handle-remember-v2.test.ts +92 -0
- package/src/memory/graph/bootstrap.test.ts +6 -3
- package/src/memory/graph/retriever.test.ts +12 -12
- package/src/memory/graph/store.test.ts +15 -25
- package/src/memory/graph/store.ts +23 -14
- package/src/memory/graph/tool-handlers.ts +34 -5
- package/src/memory/graph/tools.ts +5 -2
- package/src/memory/indexer.ts +21 -9
- package/src/memory/job-handlers/cleanup.ts +10 -3
- package/src/memory/job-handlers/embedding.test.ts +4 -4
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +4 -4
- package/src/memory/jobs/embed-pkb-file.test.ts +7 -7
- package/src/memory/jobs-store.ts +36 -24
- package/src/memory/llm-request-log-store.ts +51 -19
- package/src/memory/llm-usage-store.ts +79 -21
- package/src/memory/memory-retrospective-job.ts +27 -19
- package/src/memory/memory-retrospective-startup-cleanup.ts +10 -2
- package/src/memory/migrations/{100-core-tables.ts → 000-core-tables.ts} +6 -10
- package/src/memory/migrations/014-backfill-inbox-thread-state.ts +13 -3
- package/src/memory/migrations/104-core-indexes.ts +1 -1
- package/src/memory/migrations/126-backfill-guardian-principal-id.ts +189 -196
- package/src/memory/migrations/127-guardian-principal-id-not-null.ts +98 -105
- package/src/memory/migrations/134-contacts-notes-column.ts +66 -69
- package/src/memory/migrations/135-backfill-contact-interaction-stats.ts +19 -22
- package/src/memory/migrations/136-drop-assistant-id-columns.ts +241 -219
- package/src/memory/migrations/140-backfill-usage-cache-accounting.ts +204 -209
- package/src/memory/migrations/141-rename-verification-table.ts +45 -48
- package/src/memory/migrations/142-rename-verification-session-id-column.ts +16 -23
- package/src/memory/migrations/143-rename-guardian-verification-values.ts +23 -30
- package/src/memory/migrations/144-rename-voice-to-phone.ts +133 -136
- package/src/memory/migrations/145-drop-accounts-table.ts +4 -7
- package/src/memory/migrations/147-migrate-reminders-to-schedules.ts +79 -82
- package/src/memory/migrations/148-drop-reminders-table.ts +3 -6
- package/src/memory/migrations/150-oauth-apps-client-secret-path.ts +71 -78
- package/src/memory/migrations/157-invite-contact-id.ts +73 -76
- package/src/memory/migrations/162-guardian-timestamps-epoch-ms.ts +44 -58
- package/src/memory/migrations/169-rename-gmail-provider-key-to-google.ts +36 -43
- package/src/memory/migrations/174-rename-thread-starters-table.ts +30 -37
- package/src/memory/migrations/176-drop-capability-card-state.ts +17 -22
- package/src/memory/migrations/177-create-trace-events-table.ts +23 -28
- package/src/memory/migrations/180-backfill-inline-attachments-to-disk.ts +36 -43
- package/src/memory/migrations/181-rename-thread-starters-checkpoints.ts +14 -21
- package/src/memory/migrations/191-backfill-audio-attachment-mime-types.ts +17 -24
- package/src/memory/migrations/192-contacts-user-file-column.ts +6 -9
- package/src/memory/migrations/193-add-source-type-columns.ts +33 -36
- package/src/memory/migrations/194-memory-recall-logs.ts +34 -39
- package/src/memory/migrations/196-strip-integration-prefix-from-provider-keys.ts +59 -66
- package/src/memory/migrations/199-guardian-request-enrichment-columns.ts +41 -48
- package/src/memory/migrations/204-rename-memory-graph-type-values.ts +11 -18
- package/src/memory/migrations/206-scrub-corrupted-image-attachments.ts +76 -83
- package/src/memory/migrations/209-strip-thinking-from-consolidated.ts +135 -68
- package/src/memory/migrations/211-memory-recall-logs-query-context.ts +6 -11
- package/src/memory/migrations/212-llm-request-logs-created-at-index.ts +4 -9
- package/src/memory/migrations/217-conversation-host-access.ts +13 -18
- package/src/memory/migrations/220-normalize-user-file-by-principal.ts +86 -93
- package/src/memory/migrations/222-strip-placeholder-sentinels-from-messages.ts +41 -48
- package/src/memory/migrations/230-acp-session-history.ts +23 -28
- package/src/memory/migrations/231-repair-memory-graph-event-dates.ts +58 -62
- package/src/memory/migrations/232-activation-state.ts +11 -16
- package/src/memory/migrations/233-document-conversations.ts +20 -25
- package/src/memory/migrations/234-memory-v2-activation-logs.ts +26 -31
- package/src/memory/migrations/235-slack-compaction-watermark.ts +5 -10
- package/src/memory/migrations/236-tool-invocations-matched-rule-id.ts +6 -11
- package/src/memory/migrations/237-heartbeat-runs.ts +22 -27
- package/src/memory/migrations/239-trace-events-created-at-index.ts +4 -9
- package/src/memory/migrations/242-message-bookmarks.ts +17 -22
- package/src/memory/migrations/245-memory-retrospective-state.ts +8 -13
- package/src/memory/migrations/249-normalize-slack-external-content.ts +37 -41
- package/src/memory/migrations/251-a2a-tasks.ts +27 -32
- package/src/memory/migrations/254-external-conversation-binding-chat-name.ts +12 -17
- package/src/memory/migrations/255-channel-inbound-delivery-attempts.ts +10 -15
- package/src/memory/migrations/256-memory-v2-injection-events.ts +70 -74
- package/src/memory/migrations/259-conversation-cleaned-at.ts +4 -9
- package/src/memory/migrations/260-rename-cleaned-at.ts +11 -16
- package/src/memory/migrations/261-llm-usage-add-raw-usage.ts +3 -8
- package/src/memory/migrations/262-memory-v3-coactivation.ts +21 -26
- package/src/memory/migrations/263-memory-v3-auto-edges.ts +14 -19
- package/src/memory/migrations/270-schedule-description.ts +7 -12
- package/src/memory/migrations/272-acp-session-history-cwd.ts +8 -13
- package/src/memory/migrations/281-memory-retrospective-remembered-log.ts +8 -13
- package/src/memory/migrations/297-move-llm-request-logs-to-logs-db.ts +111 -0
- package/src/memory/migrations/298-move-memory-jobs-to-memory-db.ts +128 -0
- package/src/memory/migrations/299-canonical-guardian-deliveries-conversation-index.ts +19 -0
- package/src/memory/migrations/__tests__/014-backfill-inbox-thread-state.test.ts +108 -0
- package/src/memory/migrations/__tests__/136-drop-assistant-id-columns.test.ts +82 -0
- package/src/memory/migrations/__tests__/209-strip-thinking-from-consolidated.test.ts +224 -0
- package/src/memory/migrations/__tests__/297-move-llm-request-logs.test.ts +180 -0
- package/src/memory/migrations/__tests__/run-migrations.test.ts +333 -7
- package/src/memory/migrations/helpers/relocation.ts +227 -0
- package/src/memory/migrations/registry.ts +63 -0
- package/src/memory/migrations/run-migrations.ts +187 -16
- package/src/memory/migrations/schema-introspection.ts +14 -0
- package/src/memory/migrations/validate-migration-state.ts +50 -145
- package/src/memory/prompt-override.ts +129 -0
- package/src/memory/raw-query.ts +47 -2
- package/src/memory/skill-loaded-events-store.test.ts +1 -1
- package/src/memory/task-memory-cleanup.ts +62 -41
- package/src/memory/tool-executed-events-store.test.ts +1 -1
- package/src/memory/turn-trace-store.test.ts +1 -1
- package/src/memory/v2/__tests__/backfill-jobs.test.ts +16 -15
- package/src/memory/v2/__tests__/cli-command-store.test.ts +25 -0
- package/src/memory/v2/__tests__/harness-compare.test.ts +1 -1
- package/src/memory/v2/__tests__/harness-oracle.test.ts +1 -1
- package/src/memory/v2/__tests__/harness-replay-input.test.ts +1 -1
- package/src/memory/v2/__tests__/skill-store.test.ts +80 -0
- package/src/memory/v2/__tests__/sweep-job.test.ts +2 -2
- package/src/memory/v2/cli-command-store.ts +75 -38
- package/src/memory/v2/prompts/consolidation.ts +13 -82
- package/src/memory/v2/prompts/router.ts +21 -93
- package/src/memory/v2/skill-store.ts +68 -31
- package/src/memory/v3-eval/__tests__/eval-packets.test.ts +38 -0
- package/src/memory/v3-eval/__tests__/eval-tally.test.ts +139 -0
- package/src/memory/v3-eval/eval-packets.ts +197 -12
- package/src/memory/v3-eval/eval-tally.ts +234 -0
- package/src/memory/worker-control.ts +118 -0
- package/src/memory/worker-process.ts +72 -0
- package/src/messaging/provider.ts +10 -0
- package/src/messaging/providers/gmail/adapter.ts +1 -0
- package/src/messaging/providers/gmail/client.ts +13 -0
- package/src/messaging/providers/index.ts +1 -1
- package/src/messaging/providers/slack/send.test.ts +87 -39
- package/src/messaging/providers/slack/send.ts +84 -105
- package/src/notifications/README.md +9 -5
- package/src/notifications/__tests__/broadcaster.test.ts +16 -8
- package/src/notifications/__tests__/connected-channels.test.ts +114 -0
- package/src/notifications/__tests__/decision-engine.test.ts +78 -9
- package/src/notifications/__tests__/destination-resolver.test.ts +256 -0
- package/src/notifications/__tests__/deterministic-checks.test.ts +43 -1
- package/src/notifications/adapters/slack.ts +12 -10
- package/src/notifications/approval-card-builder.ts +81 -20
- package/src/notifications/approval-card-data.ts +8 -5
- package/src/notifications/broadcaster.ts +8 -1
- package/src/notifications/canonical-delivery-recorder.ts +7 -5
- package/src/notifications/conversation-candidates.ts +24 -59
- package/src/notifications/copy-composer.ts +48 -68
- package/src/notifications/decision-engine.ts +15 -7
- package/src/notifications/destination-resolver.ts +68 -24
- package/src/notifications/deterministic-checks.ts +19 -16
- package/src/notifications/emit-signal.ts +68 -15
- package/src/notifications/trusted-contact-payloads.ts +70 -0
- package/src/oauth/byo-connection.test.ts +9 -0
- package/src/oauth/connection-resolver.test.ts +174 -6
- package/src/oauth/connection-resolver.ts +132 -5
- package/src/oauth/oauth-store.ts +16 -3
- package/src/oauth/scope-utils.ts +39 -0
- package/src/permissions/question-prompter.test.ts +1 -1
- package/src/permissions/question-prompter.ts +7 -4
- package/src/plugin-api/index.ts +9 -4
- package/src/plugin-api/model-profiles.test.ts +123 -0
- package/src/plugin-api/model-profiles.ts +5 -1
- package/src/plugin-api/vision-support.test.ts +173 -0
- package/src/plugin-api/vision-support.ts +113 -0
- package/src/plugins/defaults/advisor/__tests__/consult.test.ts +90 -0
- package/src/plugins/defaults/advisor/__tests__/context-pack-gating.test.ts +106 -0
- package/src/plugins/defaults/advisor/__tests__/context-pack.test.ts +60 -0
- package/src/plugins/defaults/advisor/consult.ts +65 -6
- package/src/plugins/defaults/advisor/context-pack.ts +288 -0
- package/src/plugins/defaults/advisor/steering.ts +14 -2
- package/src/plugins/defaults/advisor/tools/advisor.ts +32 -5
- package/src/plugins/defaults/compaction/window-manager.ts +45 -64
- package/src/plugins/defaults/empty-response/hooks/post-model-call.ts +13 -4
- package/src/plugins/defaults/image-fallback/__tests__/image-fallback.test.ts +441 -0
- package/src/plugins/defaults/image-fallback/hooks/post-tool-use.ts +57 -0
- package/src/plugins/defaults/image-fallback/hooks/user-prompt-submit.ts +61 -0
- package/src/plugins/defaults/image-fallback/package.json +14 -0
- package/src/plugins/defaults/image-fallback/src/caption-blocks.ts +108 -0
- package/src/plugins/defaults/image-fallback/src/caption-cache.ts +49 -0
- package/src/plugins/defaults/image-fallback/src/image-persist.ts +56 -0
- package/src/plugins/defaults/image-fallback/src/vision-caption.ts +120 -0
- package/src/plugins/defaults/index.ts +27 -0
- package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +14 -1
- package/src/plugins/defaults/memory-retrieval/injectors.ts +4 -4
- package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +134 -5
- package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +11 -2
- package/src/plugins/defaults/memory-v3-shadow/pool-select.test.ts +146 -0
- package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +246 -19
- package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +8 -1
- package/src/plugins/external-plugin-loader.ts +47 -6
- package/src/plugins/mtime-cache.ts +772 -0
- package/src/plugins/pipeline.ts +7 -2
- package/src/plugins/registry.ts +16 -5
- package/src/plugins/user-loader.ts +22 -76
- package/src/prompts/persona-resolver.ts +29 -11
- package/src/prompts/system-prompt.ts +1 -1
- package/src/prompts/templates/system-sections.ts +4 -4
- package/src/providers/__tests__/count-tokens-forwarding.test.ts +98 -0
- package/src/providers/anthropic/client.ts +290 -185
- package/src/providers/call-site-routing.ts +14 -0
- package/src/providers/gemini/client.ts +43 -0
- package/src/providers/inference/adapter-factory.ts +6 -0
- package/src/providers/inference/connections.ts +6 -1
- package/src/providers/model-catalog.ts +53 -0
- package/src/providers/openai/responses-provider.ts +5 -0
- package/src/providers/openrouter/client.ts +5 -0
- package/src/providers/platform-proxy/constants.ts +5 -0
- package/src/providers/provider-send-message.ts +4 -0
- package/src/providers/ratelimit.ts +13 -0
- package/src/providers/retry.ts +14 -0
- package/src/providers/together/client.ts +35 -0
- package/src/providers/types.ts +25 -0
- package/src/providers/usage-tracking.ts +11 -0
- package/src/runtime/AGENTS.md +9 -1
- package/src/runtime/__tests__/agent-wake.test.ts +259 -4
- package/src/runtime/__tests__/guardian-vellum-migration.test.ts +181 -0
- package/src/runtime/__tests__/is-guardian-bound-for-channel.test.ts +64 -0
- package/src/runtime/__tests__/local-principal-trust.test.ts +164 -0
- package/src/runtime/__tests__/slack-block-formatting.test.ts +39 -10
- package/src/runtime/__tests__/trust-verdict-consumer.test.ts +670 -0
- package/src/runtime/access-request-helper.ts +19 -39
- package/src/runtime/actor-trust-resolver.ts +8 -16
- package/src/runtime/agent-wake.ts +183 -60
- package/src/runtime/anchored-guardian.test.ts +156 -0
- package/src/runtime/anchored-guardian.ts +135 -0
- package/src/runtime/assistant-stream-state.ts +9 -2
- package/src/runtime/auth/__tests__/require-bound-guardian.test.ts +99 -0
- package/src/runtime/auth/require-bound-guardian.ts +21 -11
- package/src/runtime/channel-reply-delivery.ts +6 -3
- package/src/runtime/channel-verification-service.ts +24 -0
- package/src/runtime/guardian-decision-types.ts +3 -22
- package/src/runtime/guardian-vellum-migration.ts +66 -7
- package/src/runtime/http-server.ts +1 -15
- package/src/runtime/invite-redemption-service.ts +155 -6
- package/src/runtime/invite-service.ts +113 -62
- package/src/runtime/local-actor-identity.ts +76 -11
- package/src/runtime/local-principal-trust.ts +52 -0
- package/src/runtime/migrations/__tests__/vbundle-builder-fd-leak.test.ts +3 -0
- package/src/runtime/pending-interactions.ts +11 -1
- package/src/runtime/routes/__tests__/acp-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/bookmark-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/channel-verification-revoke.test.ts +277 -0
- package/src/runtime/routes/__tests__/channel-verification-routes.test.ts +140 -0
- package/src/runtime/routes/__tests__/connection-routes-vs-cli-parity.test.ts +26 -7
- package/src/runtime/routes/__tests__/consolidation-routes.test.ts +14 -10
- package/src/runtime/routes/__tests__/contact-routes-update-channel-relay.test.ts +164 -0
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +8 -8
- package/src/runtime/routes/__tests__/conversation-surface-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +1 -3
- package/src/runtime/routes/__tests__/invite-relay-routes.test.ts +240 -0
- package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +4 -0
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +143 -0
- package/src/runtime/routes/__tests__/retrospective-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +163 -0
- package/src/runtime/routes/acp-routes-list.test.ts +4 -0
- package/src/runtime/routes/acp-routes.test.ts +5 -6
- package/src/runtime/routes/attachment-routes.ts +21 -17
- package/src/runtime/routes/browser-routes.ts +19 -1
- package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +5 -9
- package/src/runtime/routes/channel-verification-routes.ts +13 -2
- package/src/runtime/routes/contact-routes.ts +275 -164
- package/src/runtime/routes/conversation-query-routes.ts +15 -5
- package/src/runtime/routes/conversation-routes.ts +80 -66
- package/src/runtime/routes/conversation-starter-routes.ts +7 -8
- package/src/runtime/routes/events-routes.ts +2 -2
- package/src/runtime/routes/guardian-approval-interception.ts +13 -274
- package/src/runtime/routes/host-app-control-routes.ts +5 -4
- package/src/runtime/routes/host-bash-routes.ts +5 -4
- package/src/runtime/routes/host-browser-routes.ts +9 -11
- package/src/runtime/routes/host-cu-routes.ts +5 -4
- package/src/runtime/routes/host-file-routes.ts +5 -4
- package/src/runtime/routes/host-transfer-routes.ts +6 -6
- package/src/runtime/routes/http-adapter.ts +1 -1
- package/src/runtime/routes/inbound-message-handler.ts +21 -16
- package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +376 -0
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +86 -64
- package/src/runtime/routes/inbound-stages/admission-policy.ts +20 -5
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +16 -4
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +21 -8
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +14 -3
- package/src/runtime/routes/llm-context-normalization.ts +71 -0
- package/src/runtime/routes/log-export-routes.ts +2 -2
- package/src/runtime/routes/mcp-auth-routes.ts +38 -15
- package/src/runtime/routes/memory-eval-routes.ts +92 -0
- package/src/runtime/routes/memory-item-routes.test.ts +12 -11
- package/src/runtime/routes/migration-routes.ts +51 -40
- package/src/runtime/routes/plugins-routes.ts +164 -8
- package/src/runtime/routes/schedule-routes.ts +1 -0
- package/src/runtime/routes/subagents-routes.ts +5 -0
- package/src/runtime/routes/surface-action-routes.ts +39 -51
- package/src/runtime/routes/usage-routes.ts +3 -0
- package/src/runtime/routes/work-items-routes.test.ts +1 -1
- package/src/runtime/slack-block-formatting.ts +46 -48
- package/src/runtime/trust-verdict-consumer.ts +210 -0
- package/src/schedule/scheduler.ts +6 -9
- package/src/signals/user-message.ts +16 -0
- package/src/subagent/manager.ts +9 -0
- package/src/telemetry/usage-telemetry-reporter.test.ts +1 -1
- package/src/tools/ask-question/ask-question-tool.test.ts +89 -52
- package/src/tools/ask-question/ask-question-tool.ts +27 -73
- package/src/tools/browser/__tests__/browser-status.test.ts +20 -0
- package/src/tools/browser/browser-execution.ts +16 -4
- package/src/tools/document/document-comment-tool.test.ts +1 -1
- package/src/tools/executor.ts +15 -3
- package/src/tools/host-terminal/host-shell.ts +28 -9
- package/src/tools/memory/register.test.ts +32 -0
- package/src/tools/skills/load.ts +43 -2
- package/src/tools/subagent/spawn.ts +4 -10
- package/src/tools/terminal/shell.ts +16 -5
- package/src/tools/tool-defaults.ts +2 -0
- package/src/tools/types.ts +18 -2
- package/src/tools/ui-surface/definitions.ts +0 -43
- package/src/util/fs-watcher-error.ts +36 -0
- package/src/util/log-redact.ts +2 -4
- package/src/util/logs-db-path.ts +22 -0
- package/src/util/memory-db-path.ts +23 -0
- package/src/util/platform.ts +5 -0
- package/src/watcher/providers/gmail.ts +7 -2
- package/src/workflows/engine-integration.test.ts +1 -1
- package/src/workflows/engine.test.ts +1 -1
- package/src/workflows/engine.ts +22 -0
- package/src/workflows/fanout-load.test.ts +1 -1
- package/src/workflows/journal-store.test.ts +1 -1
- package/src/workflows/leaf-runner.test.ts +40 -1
- package/src/workflows/leaf-runner.ts +26 -1
- package/src/workspace/git-service.ts +144 -29
- package/src/workspace/migrations/109-swap-quality-profile-to-glm-5p2.ts +121 -0
- package/src/workspace/migrations/110-flip-balanced-profile-to-together.ts +82 -0
- package/src/workspace/migrations/registry.ts +4 -0
- package/src/workspace/migrations/runner.ts +32 -2
- package/src/__tests__/access-request-decision.test.ts +0 -375
- package/src/__tests__/guardian-grant-minting.test.ts +0 -607
- package/src/__tests__/plugin-source-watcher.test.ts +0 -302
- package/src/api/events/turn-profile-auto-routed.ts +0 -28
- package/src/daemon/__tests__/switch-inference-profile-tool.test.ts +0 -107
- package/src/daemon/plugin-source-watcher.ts +0 -278
- package/src/daemon/switch-inference-profile-tool.ts +0 -62
- package/src/memory/guardian-approvals.ts +0 -361
- package/src/memory/migrations/010-ext-conv-bindings-channel-chat-unique.ts +0 -66
- package/src/memory/migrations/038-actor-token-records.ts +0 -45
- package/src/memory/migrations/039-actor-refresh-token-records.ts +0 -57
- package/src/memory/migrations/103-complex-migrations.ts +0 -23
- package/src/memory/migrations/113-late-migrations.ts +0 -30
- package/src/memory/migrations/index.ts +0 -301
- package/src/runtime/routes/access-request-decision.ts +0 -297
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +0 -963
- package/src/runtime/routes/channel-guardian-routes.ts +0 -19
- package/src/runtime/routes/guardian-expiry-sweep.ts +0 -132
|
@@ -13,10 +13,25 @@
|
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
16
|
-
import { join } from "node:path";
|
|
16
|
+
import { dirname, join } from "node:path";
|
|
17
17
|
|
|
18
18
|
import { getWorkspacePluginsDir } from "../../util/platform.js";
|
|
19
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Directory containing first-party default plugin packages. Each subdirectory
|
|
22
|
+
* has a `package.json` with `name` (prefixed `default-`) and `version`.
|
|
23
|
+
* Read from the filesystem at call time to avoid pulling hook/tool
|
|
24
|
+
* implementations into the CLI process (which would create circular
|
|
25
|
+
* dependencies in test environments).
|
|
26
|
+
*/
|
|
27
|
+
const DEFAULT_PLUGINS_DIR = join(
|
|
28
|
+
dirname(new URL(import.meta.url).pathname),
|
|
29
|
+
"..",
|
|
30
|
+
"..",
|
|
31
|
+
"plugins",
|
|
32
|
+
"defaults",
|
|
33
|
+
);
|
|
34
|
+
|
|
20
35
|
/** Minimal manifest fields surfaced to the CLI. */
|
|
21
36
|
export interface PluginPackageMetadata {
|
|
22
37
|
readonly name?: string;
|
|
@@ -40,6 +55,20 @@ export interface InstalledPluginInfo {
|
|
|
40
55
|
readonly issues: readonly string[];
|
|
41
56
|
}
|
|
42
57
|
|
|
58
|
+
/** Where the plugin comes from. */
|
|
59
|
+
export type PluginSource = "user" | "default";
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Extended plugin entry that includes source (`user` vs `default`) and
|
|
63
|
+
* disabled status. Used by {@link listAllPlugins}.
|
|
64
|
+
*/
|
|
65
|
+
export interface AllPluginInfo extends InstalledPluginInfo {
|
|
66
|
+
/** Whether this is a user-installed or first-party default plugin. */
|
|
67
|
+
readonly source: PluginSource;
|
|
68
|
+
/** Whether the plugin is disabled via a `.disabled` sentinel file. */
|
|
69
|
+
readonly disabled: boolean;
|
|
70
|
+
}
|
|
71
|
+
|
|
43
72
|
/** Options accepted by {@link listInstalledPlugins}. */
|
|
44
73
|
export interface ListInstalledPluginsOptions {
|
|
45
74
|
/** Override the workspace plugins directory. Falls back to {@link getWorkspacePluginsDir}. */
|
|
@@ -146,3 +175,152 @@ function readPluginEntry(
|
|
|
146
175
|
|
|
147
176
|
return { name, target, packageJson, issues };
|
|
148
177
|
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* List all plugins — both user-installed (from `<workspace>/plugins/`) and
|
|
181
|
+
* first-party defaults (from the source tree). Each entry is annotated with
|
|
182
|
+
* its `source` (`"user"` or `"default"`) and `disabled` status (whether a
|
|
183
|
+
* `.disabled` sentinel file exists in the plugin's workspace directory).
|
|
184
|
+
*
|
|
185
|
+
* For user plugins, the `.disabled` file lives in the plugin's own install
|
|
186
|
+
* directory. For default plugins, it lives in a stub directory at
|
|
187
|
+
* `<workspace>/plugins/<manifest-name>/` (created by `plugins disable`).
|
|
188
|
+
*
|
|
189
|
+
* Stub directories created by `plugins disable <default-name>` are excluded
|
|
190
|
+
* from the user listing so a disabled default plugin appears only once (as a
|
|
191
|
+
* default entry, not a duplicate user entry with "missing package.json").
|
|
192
|
+
*
|
|
193
|
+
* Sort order:
|
|
194
|
+
* 1. Enabled user plugins (by install date, oldest first — matches
|
|
195
|
+
* hook/tool resolution order)
|
|
196
|
+
* 2. Disabled user plugins (by install date)
|
|
197
|
+
* 3. Enabled default plugins (by repo array order — matches registration
|
|
198
|
+
* order which fixes hook-chain order)
|
|
199
|
+
* 4. Disabled default plugins (by repo array order)
|
|
200
|
+
*/
|
|
201
|
+
export function listAllPlugins(
|
|
202
|
+
opts: ListInstalledPluginsOptions = {},
|
|
203
|
+
): AllPluginInfo[] {
|
|
204
|
+
const pluginsDir = opts.workspacePluginsDir ?? getWorkspacePluginsDir();
|
|
205
|
+
|
|
206
|
+
// ── User plugins ───────────────────────────────────────────────────────
|
|
207
|
+
// Filter out default-plugin stub directories (created by `plugins disable
|
|
208
|
+
// default-<name>`) so they don't show up as duplicate user entries.
|
|
209
|
+
const defaultNames = new Set(
|
|
210
|
+
readDefaultPluginManifests().map((m) => m.name),
|
|
211
|
+
);
|
|
212
|
+
const userPlugins: AllPluginInfo[] = listInstalledPlugins(opts)
|
|
213
|
+
.filter((entry) => !defaultNames.has(entry.name))
|
|
214
|
+
.map((entry) => ({
|
|
215
|
+
...entry,
|
|
216
|
+
source: "user" as const,
|
|
217
|
+
disabled: existsSync(join(entry.target, ".disabled")),
|
|
218
|
+
}));
|
|
219
|
+
|
|
220
|
+
// ── Default plugins ────────────────────────────────────────────────────
|
|
221
|
+
// Default plugins live in the source tree at src/plugins/defaults/<name>/.
|
|
222
|
+
// Read each package.json from the filesystem to get name+version without
|
|
223
|
+
// importing hook/tool implementations (which would create circular
|
|
224
|
+
// dependencies in test environments). The .disabled sentinel lives in a
|
|
225
|
+
// stub directory at <workspace>/plugins/<manifest-name>/.
|
|
226
|
+
// readDefaultPluginManifests returns in repo array (registration) order.
|
|
227
|
+
const defaultPlugins: AllPluginInfo[] = readDefaultPluginManifests().map(
|
|
228
|
+
(manifest) => {
|
|
229
|
+
const target = join(pluginsDir, manifest.name);
|
|
230
|
+
const disabled = existsSync(join(target, ".disabled"));
|
|
231
|
+
return {
|
|
232
|
+
name: manifest.name,
|
|
233
|
+
target,
|
|
234
|
+
packageJson: {
|
|
235
|
+
name: manifest.name,
|
|
236
|
+
version: manifest.version,
|
|
237
|
+
},
|
|
238
|
+
issues: [],
|
|
239
|
+
source: "default" as const,
|
|
240
|
+
disabled,
|
|
241
|
+
};
|
|
242
|
+
},
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
// Sort: enabled user (install date), disabled user (install date),
|
|
246
|
+
// enabled default (repo order), disabled default (repo order).
|
|
247
|
+
const enabledUser = userPlugins.filter((p) => !p.disabled);
|
|
248
|
+
const disabledUser = userPlugins.filter((p) => p.disabled);
|
|
249
|
+
const enabledDefault = defaultPlugins.filter((p) => !p.disabled);
|
|
250
|
+
const disabledDefault = defaultPlugins.filter((p) => p.disabled);
|
|
251
|
+
|
|
252
|
+
enabledUser.sort((a, b) => getPluginInstallDate(a) - getPluginInstallDate(b));
|
|
253
|
+
disabledUser.sort(
|
|
254
|
+
(a, b) => getPluginInstallDate(a) - getPluginInstallDate(b),
|
|
255
|
+
);
|
|
256
|
+
// enabledDefault and disabledDefault keep repo array order (no sort).
|
|
257
|
+
|
|
258
|
+
return [...enabledUser, ...disabledUser, ...enabledDefault, ...disabledDefault];
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
interface DefaultPluginManifest {
|
|
262
|
+
readonly name: string;
|
|
263
|
+
readonly version?: string;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Read first-party default plugin manifests from the filesystem. Each
|
|
268
|
+
* subdirectory under {@link DEFAULT_PLUGINS_DIR} that has a `package.json`
|
|
269
|
+
* with a `name` field is included. This avoids importing `defaults/index.ts`
|
|
270
|
+
* (which would pull in hook/tool implementations and create circular
|
|
271
|
+
* dependencies in test environments).
|
|
272
|
+
*/
|
|
273
|
+
function readDefaultPluginManifests(): readonly DefaultPluginManifest[] {
|
|
274
|
+
if (!existsSync(DEFAULT_PLUGINS_DIR)) return [];
|
|
275
|
+
|
|
276
|
+
const entries = readdirSync(DEFAULT_PLUGINS_DIR, { withFileTypes: true })
|
|
277
|
+
.filter((e) => e.isDirectory())
|
|
278
|
+
.map((e) => e.name)
|
|
279
|
+
.sort();
|
|
280
|
+
|
|
281
|
+
const manifests: DefaultPluginManifest[] = [];
|
|
282
|
+
for (const name of entries) {
|
|
283
|
+
const pkgJsonPath = join(DEFAULT_PLUGINS_DIR, name, "package.json");
|
|
284
|
+
if (!existsSync(pkgJsonPath)) continue;
|
|
285
|
+
try {
|
|
286
|
+
const raw = readFileSync(pkgJsonPath, "utf8");
|
|
287
|
+
const parsed = JSON.parse(raw) as Record<string, unknown>;
|
|
288
|
+
if (typeof parsed.name === "string") {
|
|
289
|
+
manifests.push({
|
|
290
|
+
name: parsed.name,
|
|
291
|
+
version:
|
|
292
|
+
typeof parsed.version === "string" ? parsed.version : undefined,
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
} catch {
|
|
296
|
+
// Skip malformed entries — lenient like listInstalledPlugins.
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
return manifests;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Resolve the install date for a user plugin directory, in epoch ms.
|
|
304
|
+
* Reads `install-meta.json`'s `installedAt` field first, falling back to
|
|
305
|
+
* the directory's birthtime. Mirrors the logic in mtime-cache's
|
|
306
|
+
* `getInstallDate` so the sort order matches hook/tool resolution order.
|
|
307
|
+
*/
|
|
308
|
+
function getPluginInstallDate(plugin: AllPluginInfo): number {
|
|
309
|
+
const metaPath = join(plugin.target, "install-meta.json");
|
|
310
|
+
try {
|
|
311
|
+
if (existsSync(metaPath)) {
|
|
312
|
+
const raw = JSON.parse(readFileSync(metaPath, "utf8")) as Record<string, unknown>;
|
|
313
|
+
if (typeof raw.installedAt === "string") {
|
|
314
|
+
const ms = Date.parse(raw.installedAt);
|
|
315
|
+
if (Number.isFinite(ms)) return ms;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
} catch {
|
|
319
|
+
// Fall through to birthtime.
|
|
320
|
+
}
|
|
321
|
+
try {
|
|
322
|
+
return statSync(plugin.target).birthtimeMs;
|
|
323
|
+
} catch {
|
|
324
|
+
return 0;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
@@ -35,6 +35,17 @@ const MARKETPLACE_SOURCE_OWNER = "vellum-ai";
|
|
|
35
35
|
const MARKETPLACE_SOURCE_REPO = "vellum-assistant";
|
|
36
36
|
const MARKETPLACE_FILE_PATH = "plugins/marketplace.json";
|
|
37
37
|
|
|
38
|
+
/**
|
|
39
|
+
* Canonical GitHub coordinates of the marketplace manifest, exported so
|
|
40
|
+
* sibling readers (e.g. {@link ./plugin-pin-history}) resolve the same
|
|
41
|
+
* `owner/repo:path` rather than re-declaring it.
|
|
42
|
+
*/
|
|
43
|
+
export const MARKETPLACE_MANIFEST_LOCATION = {
|
|
44
|
+
owner: MARKETPLACE_SOURCE_OWNER,
|
|
45
|
+
repo: MARKETPLACE_SOURCE_REPO,
|
|
46
|
+
path: MARKETPLACE_FILE_PATH,
|
|
47
|
+
} as const;
|
|
48
|
+
|
|
38
49
|
// ---------------------------------------------------------------------------
|
|
39
50
|
// Manifest schema (subset of the Claude Code marketplace schema)
|
|
40
51
|
// ---------------------------------------------------------------------------
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reconstruct the history of marketplace pins for a single plugin.
|
|
3
|
+
*
|
|
4
|
+
* The curated `plugins/marketplace.json` manifest (see {@link ./plugin-marketplace})
|
|
5
|
+
* records only the *current* pin for each plugin — there is no stored version
|
|
6
|
+
* list. But the manifest is a file in a Git repo, and every time a curator bumps
|
|
7
|
+
* a plugin's pin, that is a commit to the manifest. So the history of reviewed
|
|
8
|
+
* pins already exists as the commit history of that one file: this module walks
|
|
9
|
+
* it (newest → oldest) via the GitHub API and reports the distinct pins a plugin
|
|
10
|
+
* has been promoted to over time, each tagged with the marketplace commit an
|
|
11
|
+
* install can reproduce it from.
|
|
12
|
+
*
|
|
13
|
+
* Why this is the safe source for "install an older version": every commit on
|
|
14
|
+
* the default branch was reviewed and merged, so a pin drawn from this history
|
|
15
|
+
* is a reviewed, known-good revision — unlike an arbitrary caller-supplied ref,
|
|
16
|
+
* which the install route deliberately refuses. Resolving an older pin to the
|
|
17
|
+
* marketplace commit that introduced it (rather than the plugin SHA directly)
|
|
18
|
+
* also means the install reads that era's manifest, so the curated adapter stub
|
|
19
|
+
* matches the pin and the historical version reproduces coherently.
|
|
20
|
+
*
|
|
21
|
+
* Designed for direct programmatic use with an injected `fetch`, mirroring the
|
|
22
|
+
* sibling plugin libraries.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import { type FetchLike, sanitizePluginName } from "./install-from-github.js";
|
|
26
|
+
import {
|
|
27
|
+
fetchMarketplaceEntries,
|
|
28
|
+
MARKETPLACE_MANIFEST_LOCATION,
|
|
29
|
+
} from "./plugin-marketplace.js";
|
|
30
|
+
|
|
31
|
+
/** Default number of distinct historical pins surfaced by `plugins versions`. */
|
|
32
|
+
export const DEFAULT_PIN_HISTORY_LIMIT = 5;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Cap on how many manifest-touching commits are inspected in one walk. Bounds
|
|
36
|
+
* the GitHub API cost: a plugin whose pin changes rarely could otherwise force
|
|
37
|
+
* a fetch of the manifest at every commit that touched it for *any* plugin.
|
|
38
|
+
* Well above {@link DEFAULT_PIN_HISTORY_LIMIT} so the default listing is
|
|
39
|
+
* complete in all but pathological histories.
|
|
40
|
+
*/
|
|
41
|
+
const MAX_MARKETPLACE_COMMITS_SCANNED = 100;
|
|
42
|
+
|
|
43
|
+
/** A single point in a plugin's marketplace-pin history. */
|
|
44
|
+
export interface PluginPinHistoryEntry {
|
|
45
|
+
/** Plugin commit SHA pinned at this point in history. */
|
|
46
|
+
readonly pin: string;
|
|
47
|
+
/**
|
|
48
|
+
* Marketplace-manifest commit to install this pin from — the newest commit
|
|
49
|
+
* that carries it. Installing with this as the marketplace ref reproduces the
|
|
50
|
+
* pin together with the curated adapter stub of the same era.
|
|
51
|
+
*/
|
|
52
|
+
readonly marketplaceCommit: string;
|
|
53
|
+
/**
|
|
54
|
+
* ISO-8601 committer date (UTC) of {@link PluginPinHistoryEntry.marketplaceCommit},
|
|
55
|
+
* i.e. when this pin was promoted; `null` when the date could not be read.
|
|
56
|
+
*/
|
|
57
|
+
readonly promotedAt: string | null;
|
|
58
|
+
/** True for the pin currently active on the default branch. */
|
|
59
|
+
readonly current: boolean;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Options controlling the pin-history walk. */
|
|
63
|
+
export interface ListPinHistoryOptions {
|
|
64
|
+
/** Max distinct pins to return (newest first). Defaults to {@link DEFAULT_PIN_HISTORY_LIMIT}. */
|
|
65
|
+
readonly limit?: number;
|
|
66
|
+
/** Marketplace branch to read history from. Defaults to `main`. */
|
|
67
|
+
readonly ref?: string;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Dependencies injected by the caller. */
|
|
71
|
+
export interface ListPinHistoryDeps {
|
|
72
|
+
/** HTTP client. Production callers pass `globalThis.fetch.bind(globalThis)`. */
|
|
73
|
+
readonly fetch: FetchLike;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Shape of a commit entry from the GitHub commits API. */
|
|
77
|
+
interface GitHubCommitListEntry {
|
|
78
|
+
readonly sha: string;
|
|
79
|
+
readonly commit: {
|
|
80
|
+
readonly committer?: { readonly date?: string } | null;
|
|
81
|
+
} | null;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** A manifest-touching commit and its committer date. */
|
|
85
|
+
interface ManifestCommit {
|
|
86
|
+
readonly sha: string;
|
|
87
|
+
readonly date: string | null;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** The pin-history walk could not read the marketplace commit list. */
|
|
91
|
+
export class PluginPinHistoryError extends Error {
|
|
92
|
+
constructor(message: string) {
|
|
93
|
+
super(message);
|
|
94
|
+
this.name = "PluginPinHistoryError";
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* List the commits that touched the marketplace manifest on `ref`, newest
|
|
100
|
+
* first, capped at {@link MAX_MARKETPLACE_COMMITS_SCANNED}. A 404 (the file
|
|
101
|
+
* never existed at this ref) yields an empty list.
|
|
102
|
+
*/
|
|
103
|
+
async function listManifestCommits(
|
|
104
|
+
ref: string,
|
|
105
|
+
fetchFn: FetchLike,
|
|
106
|
+
): Promise<ManifestCommit[]> {
|
|
107
|
+
const { owner, repo, path } = MARKETPLACE_MANIFEST_LOCATION;
|
|
108
|
+
const url =
|
|
109
|
+
`https://api.github.com/repos/${owner}/${repo}/commits` +
|
|
110
|
+
`?path=${encodeURIComponent(path)}` +
|
|
111
|
+
`&sha=${encodeURIComponent(ref)}` +
|
|
112
|
+
`&per_page=${MAX_MARKETPLACE_COMMITS_SCANNED}`;
|
|
113
|
+
|
|
114
|
+
const res = await fetchFn(url, {
|
|
115
|
+
headers: {
|
|
116
|
+
Accept: "application/vnd.github+json",
|
|
117
|
+
"User-Agent": "vellum-assistant-cli",
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
if (res.status === 404) return [];
|
|
121
|
+
if (!res.ok) {
|
|
122
|
+
throw new PluginPinHistoryError(
|
|
123
|
+
`Marketplace commit history fetch failed for ${path} @ ${ref}: HTTP ${res.status}`,
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
let body: unknown;
|
|
128
|
+
try {
|
|
129
|
+
body = JSON.parse(await res.text());
|
|
130
|
+
} catch (err) {
|
|
131
|
+
throw new PluginPinHistoryError(
|
|
132
|
+
`Marketplace commit history is not valid JSON: ${err instanceof Error ? err.message : String(err)}`,
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
if (!Array.isArray(body)) {
|
|
136
|
+
throw new PluginPinHistoryError(
|
|
137
|
+
"Marketplace commit history response was not an array",
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const commits: ManifestCommit[] = [];
|
|
142
|
+
for (const item of body as GitHubCommitListEntry[]) {
|
|
143
|
+
if (typeof item?.sha !== "string") continue;
|
|
144
|
+
const rawDate = item.commit?.committer?.date;
|
|
145
|
+
commits.push({
|
|
146
|
+
sha: item.sha,
|
|
147
|
+
date: typeof rawDate === "string" ? rawDate : null,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
return commits;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Resolve the plugin's pinned SHA in the manifest at a specific marketplace
|
|
155
|
+
* commit, or `null` when no entry claims the name at that revision.
|
|
156
|
+
*/
|
|
157
|
+
async function pinAtCommit(
|
|
158
|
+
name: string,
|
|
159
|
+
marketplaceCommit: string,
|
|
160
|
+
fetchFn: FetchLike,
|
|
161
|
+
): Promise<string | null> {
|
|
162
|
+
const entries = await fetchMarketplaceEntries(
|
|
163
|
+
{ fetch: fetchFn },
|
|
164
|
+
{ ref: marketplaceCommit },
|
|
165
|
+
);
|
|
166
|
+
return entries.find((e) => e.name === name)?.source.ref ?? null;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Walk a plugin's distinct marketplace pins, newest first. Each pin is yielded
|
|
171
|
+
* once, tagged with the newest marketplace commit carrying it. Revisions where
|
|
172
|
+
* the plugin is absent from the manifest are skipped (a gap, not a pin). The
|
|
173
|
+
* `current` flag is set against the pin live on `ref` today.
|
|
174
|
+
*
|
|
175
|
+
* Bounded by {@link MAX_MARKETPLACE_COMMITS_SCANNED} commits scanned.
|
|
176
|
+
*/
|
|
177
|
+
async function* iteratePinHistory(
|
|
178
|
+
name: string,
|
|
179
|
+
ref: string,
|
|
180
|
+
fetchFn: FetchLike,
|
|
181
|
+
): AsyncGenerator<PluginPinHistoryEntry> {
|
|
182
|
+
const commits = await listManifestCommits(ref, fetchFn);
|
|
183
|
+
if (commits.length === 0) return;
|
|
184
|
+
|
|
185
|
+
// The pin live on the branch today, used to flag the current entry. Reading
|
|
186
|
+
// it explicitly (rather than assuming the newest commit carries it) stays
|
|
187
|
+
// correct even if the plugin was just removed from the manifest at the tip.
|
|
188
|
+
const currentPin = await pinAtCommit(name, ref, fetchFn);
|
|
189
|
+
|
|
190
|
+
let lastPin: string | null = null;
|
|
191
|
+
for (const commit of commits) {
|
|
192
|
+
const pin = await pinAtCommit(name, commit.sha, fetchFn);
|
|
193
|
+
if (pin === null) continue;
|
|
194
|
+
if (pin === lastPin) continue;
|
|
195
|
+
lastPin = pin;
|
|
196
|
+
yield {
|
|
197
|
+
pin,
|
|
198
|
+
marketplaceCommit: commit.sha,
|
|
199
|
+
promotedAt: commit.date,
|
|
200
|
+
current: currentPin !== null && pin === currentPin,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* List a plugin's distinct marketplace pins, newest first, capped at
|
|
207
|
+
* `limit` (default {@link DEFAULT_PIN_HISTORY_LIMIT}). The first entry is the
|
|
208
|
+
* current pin. An empty list means the plugin has no resolvable history at this
|
|
209
|
+
* ref (never in the manifest, or the manifest does not exist).
|
|
210
|
+
*
|
|
211
|
+
* Throws {@link PluginPinHistoryError} when the commit list cannot be read, and
|
|
212
|
+
* propagates a `MarketplaceFetchError` if a manifest revision fails to parse.
|
|
213
|
+
*/
|
|
214
|
+
export async function listPinHistory(
|
|
215
|
+
name: string,
|
|
216
|
+
deps: ListPinHistoryDeps,
|
|
217
|
+
opts: ListPinHistoryOptions = {},
|
|
218
|
+
): Promise<PluginPinHistoryEntry[]> {
|
|
219
|
+
const sanitized = sanitizePluginName(name);
|
|
220
|
+
const ref = opts.ref ?? "main";
|
|
221
|
+
const limit = opts.limit ?? DEFAULT_PIN_HISTORY_LIMIT;
|
|
222
|
+
|
|
223
|
+
const out: PluginPinHistoryEntry[] = [];
|
|
224
|
+
for await (const entry of iteratePinHistory(sanitized, ref, deps.fetch)) {
|
|
225
|
+
out.push(entry);
|
|
226
|
+
if (out.length >= limit) break;
|
|
227
|
+
}
|
|
228
|
+
return out;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Resolve a plugin pin (a full commit SHA) to the marketplace commit it should
|
|
233
|
+
* be installed from, by searching the plugin's pin history. Returns `null` when
|
|
234
|
+
* the pin is not found in the scanned history — i.e. it is not a reviewed pin
|
|
235
|
+
* this plugin was ever promoted to (or it predates the scan window).
|
|
236
|
+
*
|
|
237
|
+
* Case-insensitive on the SHA, matching the rest of the install pipeline. The
|
|
238
|
+
* search walks the full scan window, not just the `limit` shown by
|
|
239
|
+
* {@link listPinHistory}, so a pin older than the default listing still
|
|
240
|
+
* resolves.
|
|
241
|
+
*/
|
|
242
|
+
export async function resolvePinToMarketplaceCommit(
|
|
243
|
+
name: string,
|
|
244
|
+
pin: string,
|
|
245
|
+
deps: ListPinHistoryDeps,
|
|
246
|
+
opts: { readonly ref?: string } = {},
|
|
247
|
+
): Promise<PluginPinHistoryEntry | null> {
|
|
248
|
+
const sanitized = sanitizePluginName(name);
|
|
249
|
+
const ref = opts.ref ?? "main";
|
|
250
|
+
const target = pin.trim().toLowerCase();
|
|
251
|
+
if (target.length === 0) return null;
|
|
252
|
+
|
|
253
|
+
for await (const entry of iteratePinHistory(sanitized, ref, deps.fetch)) {
|
|
254
|
+
if (entry.pin.toLowerCase() === target) return entry;
|
|
255
|
+
}
|
|
256
|
+
return null;
|
|
257
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enable / disable plugins by creating or removing a `.disabled` sentinel
|
|
3
|
+
* file inside the plugin's workspace directory.
|
|
4
|
+
*
|
|
5
|
+
* The sentinel is read by the daemon at boot:
|
|
6
|
+
* - User plugins: {@link ../../plugins/mtime-cache.ts} skips any plugin
|
|
7
|
+
* whose directory contains `.disabled`.
|
|
8
|
+
* - Default plugins: {@link ../../daemon/external-plugins-bootstrap.ts}
|
|
9
|
+
* checks `<workspace>/plugins/<manifest-name>/.disabled` before init.
|
|
10
|
+
*
|
|
11
|
+
* For user plugins the directory already exists (it is the install target).
|
|
12
|
+
* For default plugins (which live in the source tree) the directory may not
|
|
13
|
+
* exist yet, so `disable` creates a stub directory and drops the sentinel
|
|
14
|
+
* inside it. `enable` removes the sentinel and cleans up the stub directory
|
|
15
|
+
* if it becomes empty (so the workspace stays tidy when the only thing in
|
|
16
|
+
* it was the sentinel).
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { existsSync, mkdirSync, readdirSync, rmSync, unlinkSync } from "node:fs";
|
|
20
|
+
import { join } from "node:path";
|
|
21
|
+
|
|
22
|
+
import { getWorkspacePluginsDir } from "../../util/platform.js";
|
|
23
|
+
|
|
24
|
+
const DISABLED_FILE = ".disabled";
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Plugin name pattern: single path segment, kebab-case alphanumerics.
|
|
28
|
+
* Rejects path traversal (`../`, slashes, null bytes) and any name that
|
|
29
|
+
* is not a flat directory entry. Same pattern as {@link sanitizePluginName}
|
|
30
|
+
* but does NOT reject the `default-` prefix, since enable/disable must
|
|
31
|
+
* accept default plugin names.
|
|
32
|
+
*/
|
|
33
|
+
const PLUGIN_NAME_RE = /^[a-z0-9][a-z0-9_-]*$/;
|
|
34
|
+
|
|
35
|
+
/** The plugin is already in the requested state. */
|
|
36
|
+
export class PluginAlreadyInStateException extends Error {
|
|
37
|
+
constructor(
|
|
38
|
+
public readonly name: string,
|
|
39
|
+
public readonly action: "enable" | "disable",
|
|
40
|
+
) {
|
|
41
|
+
super(
|
|
42
|
+
`Plugin "${name}" is already ${action === "disable" ? "disabled" : "enabled"}.`,
|
|
43
|
+
);
|
|
44
|
+
this.name = "PluginAlreadyInStateException";
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** The plugin name contains invalid characters or path segments. */
|
|
49
|
+
export class InvalidPluginNameError extends Error {
|
|
50
|
+
constructor(public readonly name: string) {
|
|
51
|
+
super(
|
|
52
|
+
`Invalid plugin name "${name}". Names must be kebab-case alphanumerics (a-z, 0-9, -, _).`,
|
|
53
|
+
);
|
|
54
|
+
this.name = "InvalidPluginNameError";
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** No plugin directory found for the given name. */
|
|
59
|
+
export class PluginDirectoryNotFoundError extends Error {
|
|
60
|
+
constructor(public readonly name: string) {
|
|
61
|
+
super(
|
|
62
|
+
`No plugin directory found for "${name}". Run \`assistant plugins list\` to see installed plugins. To disable a default plugin, prefix the name with "default-" (e.g. "default-advisor").`,
|
|
63
|
+
);
|
|
64
|
+
this.name = "PluginDirectoryNotFoundError";
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface TogglePluginResult {
|
|
69
|
+
readonly name: string;
|
|
70
|
+
readonly action: "enable" | "disable";
|
|
71
|
+
readonly sentinelPath: string;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Validate a plugin name for enable/disable. Same kebab-case rule as
|
|
76
|
+
* {@link sanitizePluginName} but allows the `default-` prefix (needed for
|
|
77
|
+
* toggling default plugins).
|
|
78
|
+
*/
|
|
79
|
+
function validatePluginName(name: string): string {
|
|
80
|
+
const trimmed = name.trim();
|
|
81
|
+
if (!PLUGIN_NAME_RE.test(trimmed)) {
|
|
82
|
+
throw new InvalidPluginNameError(name);
|
|
83
|
+
}
|
|
84
|
+
return trimmed;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Disable a plugin by creating a `.disabled` sentinel file in its workspace
|
|
89
|
+
* directory. For default plugins (names starting with `default-`), creates a
|
|
90
|
+
* stub directory under `<workspace>/plugins/<name>/` if one does not exist.
|
|
91
|
+
* For user plugins, the directory must already exist.
|
|
92
|
+
*/
|
|
93
|
+
export function disablePlugin(name: string): TogglePluginResult {
|
|
94
|
+
const validated = validatePluginName(name);
|
|
95
|
+
const pluginsDir = getWorkspacePluginsDir();
|
|
96
|
+
const pluginDir = join(pluginsDir, validated);
|
|
97
|
+
const sentinelPath = join(pluginDir, DISABLED_FILE);
|
|
98
|
+
|
|
99
|
+
if (existsSync(sentinelPath)) {
|
|
100
|
+
throw new PluginAlreadyInStateException(validated, "disable");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (!existsSync(pluginDir)) {
|
|
104
|
+
// Only create stub directories for default plugins. User plugins must
|
|
105
|
+
// already be installed — creating a directory for a name that has no
|
|
106
|
+
// plugin would be misleading.
|
|
107
|
+
if (!validated.startsWith("default-")) {
|
|
108
|
+
throw new PluginDirectoryNotFoundError(validated);
|
|
109
|
+
}
|
|
110
|
+
mkdirSync(pluginDir, { recursive: true });
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Write empty sentinel file — content is irrelevant, existence is the signal.
|
|
114
|
+
Bun.write(sentinelPath, "");
|
|
115
|
+
return { name: validated, action: "disable", sentinelPath };
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Enable a plugin by removing the `.disabled` sentinel file from its
|
|
120
|
+
* workspace directory. If the directory was a stub created by `disable`
|
|
121
|
+
* (i.e. it contains nothing but the sentinel), it is removed entirely.
|
|
122
|
+
*/
|
|
123
|
+
export function enablePlugin(name: string): TogglePluginResult {
|
|
124
|
+
const validated = validatePluginName(name);
|
|
125
|
+
const pluginsDir = getWorkspacePluginsDir();
|
|
126
|
+
const pluginDir = join(pluginsDir, validated);
|
|
127
|
+
const sentinelPath = join(pluginDir, DISABLED_FILE);
|
|
128
|
+
|
|
129
|
+
if (!existsSync(sentinelPath)) {
|
|
130
|
+
throw new PluginAlreadyInStateException(validated, "enable");
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
unlinkSync(sentinelPath);
|
|
134
|
+
|
|
135
|
+
// Clean up the stub directory if it is now empty (default plugin case).
|
|
136
|
+
// A user plugin directory has package.json and source files, so it will
|
|
137
|
+
// never be empty after removing the sentinel.
|
|
138
|
+
if (existsSync(pluginDir)) {
|
|
139
|
+
const remaining = readdirSync(pluginDir);
|
|
140
|
+
if (remaining.length === 0) {
|
|
141
|
+
rmSync(pluginDir, { recursive: true });
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return { name: validated, action: "enable", sentinelPath };
|
|
146
|
+
}
|