@vellumai/assistant 0.5.1 → 0.5.2
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 +54 -54
- package/docs/architecture/integrations.md +62 -67
- package/docs/credential-execution-service.md +3 -3
- package/package.json +1 -1
- package/src/__tests__/agent-loop.test.ts +111 -0
- package/src/__tests__/always-loaded-tools-guard.test.ts +3 -4
- package/src/__tests__/app-builder-tool-scripts.test.ts +13 -151
- package/src/__tests__/app-dir-path-guard.test.ts +78 -0
- package/src/__tests__/app-executors.test.ts +1 -291
- package/src/__tests__/app-git-history.test.ts +4 -4
- package/src/__tests__/app-routes-csp.test.ts +1 -0
- package/src/__tests__/app-store-dir-names.test.ts +426 -0
- package/src/__tests__/attachments-store.test.ts +169 -21
- package/src/__tests__/attachments.test.ts +115 -1
- package/src/__tests__/btw-routes.test.ts +1 -0
- package/src/__tests__/canonical-guardian-store.test.ts +38 -0
- package/src/__tests__/channel-reply-delivery.test.ts +55 -0
- package/src/__tests__/checker.test.ts +54 -0
- package/src/__tests__/claude-code-skill-regression.test.ts +2 -0
- package/src/__tests__/claude-code-tool-profiles.test.ts +2 -0
- package/src/__tests__/compaction.benchmark.test.ts +2 -1
- package/src/__tests__/config-schema-cmd.test.ts +68 -21
- package/src/__tests__/config-schema.test.ts +1 -1
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +149 -5
- package/src/__tests__/conversation-agent-loop.test.ts +290 -2
- package/src/__tests__/conversation-attachments.test.ts +17 -19
- package/src/__tests__/conversation-disk-view-integration.test.ts +277 -0
- package/src/__tests__/conversation-disk-view.test.ts +810 -0
- package/src/__tests__/conversation-error.test.ts +1 -1
- package/src/__tests__/conversation-fork-crud.test.ts +551 -0
- package/src/__tests__/conversation-fork-route.test.ts +386 -0
- package/src/__tests__/conversation-history-web-search.test.ts +1 -1
- package/src/__tests__/conversation-key-store-disk-view.test.ts +130 -0
- package/src/__tests__/conversation-media-retry.test.ts +8 -2
- package/src/__tests__/conversation-queue.test.ts +36 -1
- package/src/__tests__/conversation-routes-disk-view.test.ts +439 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +2 -2
- package/src/__tests__/conversation-routes-slash-commands.test.ts +2 -7
- package/src/__tests__/conversation-runtime-assembly.test.ts +17 -2
- package/src/__tests__/conversation-skill-tools.test.ts +4 -9
- package/src/__tests__/conversation-slash-commands.test.ts +149 -0
- package/src/__tests__/conversation-store.test.ts +24 -21
- package/src/__tests__/conversation-surfaces-state-update.test.ts +246 -0
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +1 -0
- package/src/__tests__/conversation-title-service.test.ts +137 -0
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +25 -315
- package/src/__tests__/conversation-tool-setup-memory-scope.test.ts +1 -0
- package/src/__tests__/conversation-tool-setup-side-effect-flag.test.ts +1 -0
- package/src/__tests__/conversation-workspace-cache-state.test.ts +44 -2
- package/src/__tests__/conversation-workspace-injection.test.ts +11 -0
- package/src/__tests__/credential-security-invariants.test.ts +3 -0
- package/src/__tests__/credential-vault-unit.test.ts +5 -10
- package/src/__tests__/cu-unified-flow.test.ts +1 -0
- package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +241 -0
- package/src/__tests__/db-llm-request-log-provider-migration.test.ts +214 -0
- package/src/__tests__/diagnostics-export.test.ts +70 -1
- package/src/__tests__/first-greeting.test.ts +80 -0
- package/src/__tests__/gateway-only-guard.test.ts +1 -0
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +3 -7
- package/src/__tests__/history-repair.test.ts +32 -10
- package/src/__tests__/http-conversation-lineage.test.ts +251 -0
- package/src/__tests__/image-source-path-reinject.test.ts +136 -0
- package/src/__tests__/llm-context-normalization.test.ts +1116 -0
- package/src/__tests__/llm-context-route-provider.test.ts +217 -0
- package/src/__tests__/llm-request-log-turn-query.test.ts +270 -0
- package/src/__tests__/media-generate-image.test.ts +47 -94
- package/src/__tests__/memory-lifecycle-e2e.test.ts +3 -1
- package/src/__tests__/memory-recall-quality.test.ts +5 -5
- package/src/__tests__/migration-cross-version-compatibility.test.ts +4 -1
- package/src/__tests__/migration-export-http.test.ts +3 -1
- package/src/__tests__/migration-import-commit-http.test.ts +18 -4
- package/src/__tests__/migration-import-preflight-http.test.ts +1 -3
- package/src/__tests__/mime-builder.test.ts +3 -2
- package/src/__tests__/non-member-access-request.test.ts +12 -1
- package/src/__tests__/notification-decision-identity.test.ts +52 -0
- package/src/__tests__/oauth-apps-routes.test.ts +103 -0
- package/src/__tests__/oauth-store.test.ts +115 -0
- package/src/__tests__/provider-error-scenarios.test.ts +1 -3
- package/src/__tests__/provider-failover-actual-provider.test.ts +66 -0
- package/src/__tests__/recording-handler.test.ts +17 -0
- package/src/__tests__/registry.test.ts +3 -8
- package/src/__tests__/relay-server.test.ts +1 -1
- package/src/__tests__/runtime-attachment-metadata.test.ts +7 -3
- package/src/__tests__/schema-transforms.test.ts +165 -5
- package/src/__tests__/server-history-render.test.ts +2 -2
- package/src/__tests__/slack-app-setup-skill-regression.test.ts +3 -1
- package/src/__tests__/slack-inbound-verification.test.ts +2 -2
- package/src/__tests__/starter-task-flow.test.ts +1 -0
- package/src/__tests__/suggestion-routes.test.ts +443 -0
- package/src/__tests__/swarm-conversation-integration.test.ts +1 -0
- package/src/__tests__/swarm-recursion.test.ts +1 -0
- package/src/__tests__/swarm-tool.test.ts +1 -0
- package/src/__tests__/tool-execution-abort-cleanup.test.ts +1 -0
- package/src/__tests__/tool-preview-lifecycle.test.ts +32 -5
- package/src/__tests__/top-level-renderer.test.ts +22 -0
- package/src/__tests__/turn-boundary-resolution.test.ts +243 -0
- package/src/__tests__/web-fetch.test.ts +6 -2
- package/src/__tests__/workspace-migration-006-services-config.test.ts +335 -0
- package/src/__tests__/workspace-migration-007-web-search-provider-rename.test.ts +312 -0
- package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +278 -0
- package/src/__tests__/workspace-migration-010-app-dir-rename.test.ts +275 -0
- package/src/__tests__/workspace-migration-012-rename-conversation-disk-view-dirs.test.ts +77 -0
- package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +401 -0
- package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +328 -0
- package/src/__tests__/workspace-migration-seed-device-id.test.ts +6 -10
- package/src/agent/attachments.ts +27 -1
- package/src/agent/loop.ts +29 -1
- package/src/avatar/traits-png-sync.ts +80 -25
- package/src/bundler/app-bundler.ts +4 -4
- package/src/calls/call-domain.ts +1 -0
- package/src/calls/voice-session-bridge.ts +1 -0
- package/src/cli/commands/auth.ts +92 -0
- package/src/cli/commands/avatar.ts +7 -6
- package/src/cli/commands/config.ts +2 -0
- package/src/cli/commands/oauth/providers.ts +29 -0
- package/src/cli/program.ts +12 -0
- package/src/cli.ts +15 -48
- package/src/config/bundled-skills/app-builder/SKILL.md +103 -28
- package/src/config/bundled-skills/app-builder/TOOLS.json +5 -199
- package/src/config/bundled-skills/app-builder/tools/{app-query.ts → app-refresh.ts} +2 -2
- package/src/config/bundled-skills/contacts/tools/google-contacts.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +6 -9
- package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +4 -6
- package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-label.ts +4 -6
- package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +2 -3
- package/src/config/bundled-skills/google-calendar/tools/shared.ts +1 -1
- package/src/config/bundled-skills/image-studio/SKILL.md +2 -2
- package/src/config/bundled-skills/image-studio/TOOLS.json +2 -2
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +45 -72
- package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +2 -2
- package/src/config/bundled-skills/messaging/tools/shared.ts +1 -1
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +19 -3
- package/src/config/bundled-skills/skill-management/TOOLS.json +2 -2
- package/src/config/bundled-skills/slack/tools/shared.ts +19 -4
- package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +2 -3
- package/src/config/bundled-skills/transcribe/SKILL.md +1 -1
- package/src/config/bundled-skills/transcribe/TOOLS.json +2 -6
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +19 -83
- package/src/config/bundled-tool-registry.ts +2 -14
- package/src/config/feature-flag-registry.json +8 -0
- package/src/config/loader.ts +64 -0
- package/src/config/raw-config-utils.ts +30 -0
- package/src/config/schema-utils.ts +28 -7
- package/src/config/schema.ts +8 -0
- package/src/config/schemas/elevenlabs.ts +18 -0
- package/src/config/schemas/memory-lifecycle.ts +4 -2
- package/src/config/schemas/memory-storage.ts +1 -1
- package/src/config/schemas/services.ts +8 -6
- package/src/contacts/contact-store.ts +13 -6
- package/src/contacts/contacts-write.ts +0 -1
- package/src/context/window-manager.ts +13 -2
- package/src/daemon/conversation-agent-loop-handlers.ts +48 -7
- package/src/daemon/conversation-agent-loop.ts +56 -19
- package/src/daemon/conversation-attachments.ts +18 -36
- package/src/daemon/conversation-error.ts +2 -1
- package/src/daemon/conversation-history.ts +18 -4
- package/src/daemon/conversation-lifecycle.ts +39 -15
- package/src/daemon/conversation-messaging.ts +70 -26
- package/src/daemon/conversation-process.ts +58 -34
- package/src/daemon/conversation-runtime-assembly.ts +21 -38
- package/src/daemon/conversation-slash.ts +121 -256
- package/src/daemon/conversation-surfaces.ts +143 -20
- package/src/daemon/conversation-tool-setup.ts +0 -6
- package/src/daemon/conversation-workspace.ts +21 -1
- package/src/daemon/conversation.ts +51 -29
- package/src/daemon/first-greeting.ts +35 -0
- package/src/daemon/handlers/config-embeddings.ts +148 -0
- package/src/daemon/handlers/config-model.ts +71 -26
- package/src/daemon/handlers/conversations.ts +0 -23
- package/src/daemon/handlers/recording.ts +26 -21
- package/src/daemon/host-cu-proxy.ts +2 -2
- package/src/daemon/lifecycle.ts +106 -64
- package/src/daemon/message-protocol.ts +3 -0
- package/src/daemon/message-types/conversations.ts +19 -0
- package/src/daemon/message-types/messages.ts +1 -0
- package/src/daemon/message-types/shared.ts +2 -0
- package/src/daemon/message-types/surfaces.ts +2 -0
- package/src/daemon/message-types/upgrades.ts +23 -0
- package/src/daemon/server.ts +83 -12
- package/src/daemon/shutdown-handlers.ts +8 -5
- package/src/daemon/startup-error.ts +9 -0
- package/src/daemon/tool-side-effects.ts +11 -28
- package/src/events/tool-permission-telemetry-listener.ts +1 -3
- package/src/instrument.ts +0 -4
- package/src/media/app-icon-generator.ts +2 -2
- package/src/memory/app-git-service.ts +28 -16
- package/src/memory/app-store.ts +230 -41
- package/src/memory/attachments-store.ts +558 -130
- package/src/memory/conversation-attention-store.ts +70 -0
- package/src/memory/conversation-crud.ts +442 -3
- package/src/memory/conversation-directories.ts +125 -0
- package/src/memory/conversation-disk-view.ts +390 -0
- package/src/memory/conversation-key-store.ts +17 -5
- package/src/memory/conversation-queries.ts +5 -1
- package/src/memory/conversation-title-service.ts +21 -49
- package/src/memory/db-init.ts +28 -0
- package/src/memory/embedding-backend.ts +42 -53
- package/src/memory/embedding-gemini.test.ts +4 -4
- package/src/memory/embedding-local.ts +1 -3
- package/src/memory/embedding-ollama.ts +1 -3
- package/src/memory/embedding-openai.ts +1 -3
- package/src/memory/indexer.ts +9 -7
- package/src/memory/items-extractor.ts +42 -13
- package/src/memory/job-handlers/conversation-starters.ts +6 -1
- package/src/memory/job-handlers/embedding.test.ts +1 -4
- package/src/memory/llm-request-log-store.ts +100 -1
- package/src/memory/migrations/102-alter-table-columns.ts +5 -0
- package/src/memory/migrations/146-schedule-oneshot-routing.ts +3 -3
- package/src/memory/migrations/147-migrate-reminders-to-schedules.ts +66 -70
- package/src/memory/migrations/148-drop-reminders-table.ts +5 -9
- package/src/memory/migrations/160-drop-loopback-port-column.ts +1 -3
- package/src/memory/migrations/174-rename-thread-starters-table.ts +0 -7
- package/src/memory/migrations/178-oauth-providers-managed-service-config-key.ts +15 -0
- package/src/memory/migrations/179-llm-request-log-message-id.ts +16 -0
- package/src/memory/migrations/180-backfill-inline-attachments-to-disk.ts +66 -0
- package/src/memory/migrations/181-rename-thread-starters-checkpoints.ts +46 -0
- package/src/memory/migrations/182-oauth-providers-display-metadata.ts +20 -0
- package/src/memory/migrations/183-add-conversation-fork-lineage.ts +22 -0
- package/src/memory/migrations/184-llm-request-log-provider.ts +12 -0
- package/src/memory/migrations/index.ts +7 -0
- package/src/memory/migrations/registry.ts +13 -0
- package/src/memory/retriever.test.ts +601 -2
- package/src/memory/retriever.ts +85 -9
- package/src/memory/schema/conversations.ts +6 -0
- package/src/memory/schema/infrastructure.ts +13 -7
- package/src/memory/schema/oauth.ts +6 -0
- package/src/messaging/providers/gmail/mime-builder.ts +3 -1
- package/src/notifications/copy-composer.ts +26 -0
- package/src/notifications/decision-engine.ts +14 -1
- package/src/notifications/emit-signal.ts +1 -1
- package/src/notifications/signal.ts +36 -0
- package/src/oauth/byo-connection.test.ts +1 -45
- package/src/oauth/byo-connection.ts +2 -8
- package/src/oauth/connect-orchestrator.ts +15 -11
- package/src/oauth/connection-resolver.test.ts +191 -0
- package/src/oauth/connection-resolver.ts +66 -38
- package/src/oauth/connection.ts +0 -1
- package/src/oauth/oauth-store.ts +97 -47
- package/src/oauth/platform-connection.test.ts +0 -1
- package/src/oauth/platform-connection.ts +11 -3
- package/src/oauth/seed-providers.ts +78 -3
- package/src/oauth/token-persistence.ts +16 -10
- package/src/permissions/checker.ts +71 -8
- package/src/prompts/templates/BOOTSTRAP.md +2 -0
- package/src/providers/anthropic/client.ts +8 -1
- package/src/providers/failover.ts +4 -1
- package/src/providers/gemini/client.ts +50 -0
- package/src/providers/model-catalog.ts +92 -0
- package/src/providers/model-intents.ts +29 -20
- package/src/providers/openai/client.ts +49 -0
- package/src/providers/types.ts +2 -0
- package/src/runtime/access-request-helper.ts +16 -7
- package/src/runtime/auth/credential-service.ts +3 -1
- package/src/runtime/auth/route-policy.ts +14 -1
- package/src/runtime/btw-sidechain.ts +101 -0
- package/src/runtime/channel-reply-delivery.ts +17 -1
- package/src/runtime/http-router.ts +3 -1
- package/src/runtime/http-server.ts +196 -141
- package/src/runtime/http-types.ts +1 -0
- package/src/runtime/migrations/vbundle-builder.ts +5 -1
- package/src/runtime/routes/access-request-decision.ts +41 -0
- package/src/runtime/routes/app-management-routes.ts +6 -3
- package/src/runtime/routes/app-routes.ts +7 -3
- package/src/runtime/routes/approval-routes.ts +1 -0
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +34 -2
- package/src/runtime/routes/attachment-routes.ts +45 -15
- package/src/runtime/routes/btw-routes.ts +21 -61
- package/src/runtime/routes/conversation-management-routes.ts +68 -0
- package/src/runtime/routes/conversation-query-routes.ts +180 -10
- package/src/runtime/routes/conversation-routes.ts +222 -28
- package/src/runtime/routes/conversation-starter-routes.ts +9 -11
- package/src/runtime/routes/diagnostics-routes.ts +1 -0
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +2 -2
- package/src/runtime/routes/llm-context-normalization.ts +1199 -0
- package/src/runtime/routes/log-export-routes.ts +3 -0
- package/src/runtime/routes/memory-item-routes.test.ts +34 -0
- package/src/runtime/routes/memory-item-routes.ts +4 -0
- package/src/runtime/routes/migration-routes.ts +4 -1
- package/src/runtime/routes/oauth-apps.ts +291 -0
- package/src/runtime/routes/secret-routes.ts +28 -1
- package/src/runtime/routes/settings-routes.ts +14 -0
- package/src/runtime/routes/trace-event-routes.ts +4 -1
- package/src/schedule/schedule-store.ts +9 -21
- package/src/security/secure-keys.ts +21 -0
- package/src/signals/bash.ts +1 -1
- package/src/swarm/backend-claude-code.ts +3 -6
- package/src/telemetry/usage-telemetry-reporter.test.ts +3 -2
- package/src/telemetry/usage-telemetry-reporter.ts +3 -1
- package/src/tools/AGENTS.md +6 -10
- package/src/tools/apps/executors.ts +17 -232
- package/src/tools/claude-code/claude-code.ts +2 -3
- package/src/tools/credentials/vault.ts +7 -12
- package/src/tools/host-filesystem/read.ts +13 -10
- package/src/tools/network/__tests__/web-search.test.ts +4 -2
- package/src/tools/schedule/list.ts +2 -7
- package/src/tools/schema-transforms.ts +5 -0
- package/src/tools/shared/filesystem/format-diff.ts +2 -7
- package/src/tools/skills/execute.ts +1 -1
- package/src/tools/tool-manifest.ts +0 -6
- package/src/tools/ui-surface/definitions.ts +2 -2
- package/src/util/device-id.ts +28 -5
- package/src/util/platform.ts +6 -0
- package/src/util/pricing.ts +1 -0
- package/src/util/retry.ts +1 -3
- package/src/workspace/migrations/002-backfill-installation-id.ts +23 -12
- package/src/workspace/migrations/003-seed-device-id.ts +3 -4
- package/src/workspace/migrations/006-services-config.ts +5 -0
- package/src/workspace/migrations/008-voice-timeout-and-max-steps.ts +12 -0
- package/src/workspace/migrations/009-backfill-conversation-disk-view.ts +10 -0
- package/src/workspace/migrations/010-app-dir-rename.ts +223 -0
- package/src/workspace/migrations/012-rename-conversation-disk-view-dirs.ts +64 -0
- package/src/workspace/migrations/013-repair-conversation-disk-view.ts +11 -0
- package/src/workspace/migrations/rebuild-conversation-disk-view.ts +186 -0
- package/src/workspace/migrations/registry.ts +10 -0
- package/src/workspace/top-level-renderer.ts +12 -0
- package/src/__tests__/asset-materialize-tool.test.ts +0 -523
- package/src/__tests__/asset-search-tool.test.ts +0 -536
- package/src/__tests__/fixtures/media-reuse-fixtures.ts +0 -56
- package/src/__tests__/media-reuse-story.e2e.test.ts +0 -762
- package/src/__tests__/media-visibility-policy.test.ts +0 -190
- package/src/config/bundled-skills/app-builder/tools/app-file-edit.ts +0 -14
- package/src/config/bundled-skills/app-builder/tools/app-file-list.ts +0 -13
- package/src/config/bundled-skills/app-builder/tools/app-file-read.ts +0 -21
- package/src/config/bundled-skills/app-builder/tools/app-file-write.ts +0 -14
- package/src/config/bundled-skills/app-builder/tools/app-list.ts +0 -13
- package/src/config/bundled-skills/app-builder/tools/app-update.ts +0 -23
- package/src/daemon/media-visibility-policy.ts +0 -59
- package/src/tools/assets/materialize.ts +0 -248
- package/src/tools/assets/search.ts +0 -400
|
@@ -100,6 +100,8 @@ export interface DynamicPageSurfaceData {
|
|
|
100
100
|
width?: number;
|
|
101
101
|
height?: number;
|
|
102
102
|
appId?: string;
|
|
103
|
+
/** Filesystem directory name for this app (may differ from `appId`). */
|
|
104
|
+
dirName?: string;
|
|
103
105
|
reloadGeneration?: number;
|
|
104
106
|
status?: string;
|
|
105
107
|
preview?: DynamicPagePreview;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** Broadcast to connected clients when a service group update is about to begin. */
|
|
2
|
+
export interface ServiceGroupUpdateStarting {
|
|
3
|
+
type: "service_group_update_starting";
|
|
4
|
+
/** The version being upgraded to. */
|
|
5
|
+
targetVersion: string;
|
|
6
|
+
/** Estimated seconds of downtime. */
|
|
7
|
+
expectedDowntimeSeconds: number;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/** Broadcast to connected clients when a service group update has completed. */
|
|
11
|
+
export interface ServiceGroupUpdateComplete {
|
|
12
|
+
type: "service_group_update_complete";
|
|
13
|
+
/** The version that was installed (may differ from target if rolled back). */
|
|
14
|
+
installedVersion: string;
|
|
15
|
+
/** Whether the update succeeded or rolled back. */
|
|
16
|
+
success: boolean;
|
|
17
|
+
/** If rolled back, the version reverted to. */
|
|
18
|
+
rolledBackToVersion?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type _UpgradesServerMessages =
|
|
22
|
+
| ServiceGroupUpdateStarting
|
|
23
|
+
| ServiceGroupUpdateComplete;
|
package/src/daemon/server.ts
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
getAcpSessionManager,
|
|
7
7
|
setBroadcastToAllClients,
|
|
8
8
|
} from "../acp/index.js";
|
|
9
|
+
import { enrichMessageWithSourcePaths } from "../agent/attachments.js";
|
|
9
10
|
import {
|
|
10
11
|
createAssistantMessage,
|
|
11
12
|
createUserMessage,
|
|
@@ -34,12 +35,14 @@ import {
|
|
|
34
35
|
} from "../memory/canonical-guardian-store.js";
|
|
35
36
|
import {
|
|
36
37
|
addMessage,
|
|
38
|
+
getConversation,
|
|
37
39
|
getConversationMemoryScopeId,
|
|
38
40
|
getConversationType,
|
|
39
41
|
provenanceFromTrustContext,
|
|
40
42
|
setConversationOriginChannelIfUnset,
|
|
41
43
|
setConversationOriginInterfaceIfUnset,
|
|
42
44
|
} from "../memory/conversation-crud.js";
|
|
45
|
+
import { updateMetaFile } from "../memory/conversation-disk-view.js";
|
|
43
46
|
import { getOrCreateConversation } from "../memory/conversation-key-store.js";
|
|
44
47
|
import { buildSystemPrompt } from "../prompts/system-prompt.js";
|
|
45
48
|
import { resolveManagedProxyContext } from "../providers/managed-proxy/context.js";
|
|
@@ -75,7 +78,7 @@ import {
|
|
|
75
78
|
} from "./conversation.js";
|
|
76
79
|
import { ConversationEvictor } from "./conversation-evictor.js";
|
|
77
80
|
import { resolveChannelCapabilities } from "./conversation-runtime-assembly.js";
|
|
78
|
-
import { resolveSlash } from "./conversation-slash.js";
|
|
81
|
+
import { resolveSlash, type SlashContext } from "./conversation-slash.js";
|
|
79
82
|
import { undoLastMessage } from "./handlers/conversations.js";
|
|
80
83
|
import { parseIdentityFields } from "./handlers/identity.js";
|
|
81
84
|
import type {
|
|
@@ -878,6 +881,7 @@ export class DaemonServer {
|
|
|
878
881
|
filename: string;
|
|
879
882
|
mimeType: string;
|
|
880
883
|
data: string;
|
|
884
|
+
filePath?: string;
|
|
881
885
|
}[];
|
|
882
886
|
}> {
|
|
883
887
|
const ingressCheck = checkIngressForSecrets(content);
|
|
@@ -960,12 +964,22 @@ export class DaemonServer {
|
|
|
960
964
|
});
|
|
961
965
|
|
|
962
966
|
const attachments = attachmentIds
|
|
963
|
-
?
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
967
|
+
? (() => {
|
|
968
|
+
const resolved = attachmentsStore.getAttachmentsByIds(attachmentIds, {
|
|
969
|
+
hydrateFileData: true,
|
|
970
|
+
});
|
|
971
|
+
const sourcePaths =
|
|
972
|
+
attachmentsStore.getSourcePathsForAttachments(attachmentIds);
|
|
973
|
+
return resolved.map((a) => ({
|
|
974
|
+
id: a.id,
|
|
975
|
+
filename: a.originalFilename,
|
|
976
|
+
mimeType: a.mimeType,
|
|
977
|
+
data: a.dataBase64,
|
|
978
|
+
...(sourcePaths.has(a.id)
|
|
979
|
+
? { filePath: sourcePaths.get(a.id) }
|
|
980
|
+
: {}),
|
|
981
|
+
}));
|
|
982
|
+
})()
|
|
969
983
|
: [];
|
|
970
984
|
|
|
971
985
|
return { conversation, attachments };
|
|
@@ -1057,14 +1071,32 @@ export class DaemonServer {
|
|
|
1057
1071
|
sourceInterface,
|
|
1058
1072
|
);
|
|
1059
1073
|
|
|
1060
|
-
const
|
|
1074
|
+
const config = getConfig();
|
|
1075
|
+
const serverInterfaceCtx = conversation.getTurnInterfaceContext();
|
|
1076
|
+
const slashContext: SlashContext = {
|
|
1077
|
+
messageCount: conversation.getMessages().length,
|
|
1078
|
+
inputTokens: conversation.usageStats.inputTokens,
|
|
1079
|
+
outputTokens: conversation.usageStats.outputTokens,
|
|
1080
|
+
maxInputTokens: config.contextWindow.maxInputTokens,
|
|
1081
|
+
model: config.services.inference.model,
|
|
1082
|
+
provider: config.services.inference.provider,
|
|
1083
|
+
estimatedCost: conversation.usageStats.estimatedCost,
|
|
1084
|
+
userMessageInterface: serverInterfaceCtx?.userMessageInterface,
|
|
1085
|
+
};
|
|
1086
|
+
const slashResult = await resolveSlash(content, slashContext);
|
|
1061
1087
|
|
|
1062
1088
|
if (slashResult.kind === "unknown") {
|
|
1063
1089
|
const serverTurnCtx = conversation.getTurnChannelContext();
|
|
1064
|
-
const serverInterfaceCtx = conversation.getTurnInterfaceContext();
|
|
1065
1090
|
const serverProvenance = provenanceFromTrustContext(
|
|
1066
1091
|
conversation.trustContext,
|
|
1067
1092
|
);
|
|
1093
|
+
const imageSourcePaths: Record<string, string> = {};
|
|
1094
|
+
for (let i = 0; i < attachments.length; i++) {
|
|
1095
|
+
const a = attachments[i];
|
|
1096
|
+
if (a.filePath && a.mimeType.toLowerCase().startsWith("image/")) {
|
|
1097
|
+
imageSourcePaths[`${i}:${a.filename}`] = a.filePath;
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1068
1100
|
const serverChannelMeta = {
|
|
1069
1101
|
...serverProvenance,
|
|
1070
1102
|
...(serverTurnCtx
|
|
@@ -1080,15 +1112,19 @@ export class DaemonServer {
|
|
|
1080
1112
|
serverInterfaceCtx.assistantMessageInterface,
|
|
1081
1113
|
}
|
|
1082
1114
|
: {}),
|
|
1115
|
+
...(Object.keys(imageSourcePaths).length > 0
|
|
1116
|
+
? { imageSourcePaths }
|
|
1117
|
+
: {}),
|
|
1083
1118
|
};
|
|
1084
|
-
const
|
|
1119
|
+
const cleanMsg = createUserMessage(content, attachments);
|
|
1120
|
+
const llmMsg = enrichMessageWithSourcePaths(cleanMsg, attachments);
|
|
1085
1121
|
const persisted = await addMessage(
|
|
1086
1122
|
conversationId,
|
|
1087
1123
|
"user",
|
|
1088
|
-
JSON.stringify(
|
|
1124
|
+
JSON.stringify(cleanMsg.content),
|
|
1089
1125
|
serverChannelMeta,
|
|
1090
1126
|
);
|
|
1091
|
-
conversation.getMessages().push(
|
|
1127
|
+
conversation.getMessages().push(llmMsg);
|
|
1092
1128
|
|
|
1093
1129
|
if (serverTurnCtx) {
|
|
1094
1130
|
try {
|
|
@@ -1117,6 +1153,21 @@ export class DaemonServer {
|
|
|
1117
1153
|
}
|
|
1118
1154
|
}
|
|
1119
1155
|
|
|
1156
|
+
// Rewrite meta.json so the on-disk metadata reflects the origin channel
|
|
1157
|
+
if (serverTurnCtx || serverInterfaceCtx) {
|
|
1158
|
+
try {
|
|
1159
|
+
const convForMeta = getConversation(conversationId);
|
|
1160
|
+
if (convForMeta) {
|
|
1161
|
+
updateMetaFile(convForMeta);
|
|
1162
|
+
}
|
|
1163
|
+
} catch (err) {
|
|
1164
|
+
log.warn(
|
|
1165
|
+
{ err, conversationId },
|
|
1166
|
+
"Failed to update disk meta (best-effort)",
|
|
1167
|
+
);
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1120
1171
|
const assistantMsg = createAssistantMessage(slashResult.message);
|
|
1121
1172
|
await addMessage(
|
|
1122
1173
|
conversationId,
|
|
@@ -1198,9 +1249,29 @@ export class DaemonServer {
|
|
|
1198
1249
|
* Look up an active conversation that owns a given surfaceId.
|
|
1199
1250
|
*/
|
|
1200
1251
|
findConversationBySurfaceId(surfaceId: string): Conversation | undefined {
|
|
1252
|
+
// Fast path: exact surfaceId match in surfaceState
|
|
1201
1253
|
for (const c of this.conversations.values()) {
|
|
1202
1254
|
if (c.surfaceState.has(surfaceId)) return c;
|
|
1203
1255
|
}
|
|
1256
|
+
|
|
1257
|
+
// Fallback: standalone app surfaces use "app-open-{appId}" IDs that
|
|
1258
|
+
// were never part of any conversation. Extract the appId and find
|
|
1259
|
+
// a conversation whose surfaceState has a surface for that app.
|
|
1260
|
+
const appOpenPrefix = "app-open-";
|
|
1261
|
+
if (surfaceId.startsWith(appOpenPrefix)) {
|
|
1262
|
+
const appId = surfaceId.slice(appOpenPrefix.length);
|
|
1263
|
+
for (const c of this.conversations.values()) {
|
|
1264
|
+
for (const [, state] of c.surfaceState.entries()) {
|
|
1265
|
+
const data = state.data as Record<string, unknown>;
|
|
1266
|
+
if (data?.appId === appId) {
|
|
1267
|
+
// Register this surfaceId so subsequent lookups are O(1)
|
|
1268
|
+
c.surfaceState.set(surfaceId, state);
|
|
1269
|
+
return c;
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1204
1275
|
return undefined;
|
|
1205
1276
|
}
|
|
1206
1277
|
|
|
@@ -21,8 +21,8 @@ export interface ShutdownDeps {
|
|
|
21
21
|
hookManager: HookManager;
|
|
22
22
|
runtimeHttp: RuntimeHttpServer | null;
|
|
23
23
|
scheduler: { stop(): void };
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
getMemoryWorker: () => { stop(): void } | null;
|
|
25
|
+
getQdrantManager: () => QdrantManager | null;
|
|
26
26
|
mcpManager: McpServerManager | null;
|
|
27
27
|
telemetryReporter: { stop(): Promise<void> } | null;
|
|
28
28
|
cleanupPidFile: () => void;
|
|
@@ -106,7 +106,7 @@ export function installShutdownHandlers(deps: ShutdownDeps): void {
|
|
|
106
106
|
if (deps.runtimeHttp) await deps.runtimeHttp.stop();
|
|
107
107
|
await browserManager.closeAllPages();
|
|
108
108
|
deps.scheduler.stop();
|
|
109
|
-
deps.
|
|
109
|
+
deps.getMemoryWorker()?.stop();
|
|
110
110
|
|
|
111
111
|
if (deps.mcpManager) {
|
|
112
112
|
try {
|
|
@@ -116,7 +116,7 @@ export function installShutdownHandlers(deps: ShutdownDeps): void {
|
|
|
116
116
|
}
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
-
await deps.
|
|
119
|
+
await deps.getQdrantManager()?.stop();
|
|
120
120
|
|
|
121
121
|
// Checkpoint WAL and close SQLite so no writes are lost on exit.
|
|
122
122
|
// Checkpoint and close are in separate try blocks so that close()
|
|
@@ -143,7 +143,10 @@ export function installShutdownHandlers(deps: ShutdownDeps): void {
|
|
|
143
143
|
process.on("SIGHUP", shutdown);
|
|
144
144
|
|
|
145
145
|
process.on("unhandledRejection", (reason) => {
|
|
146
|
-
log.error(
|
|
146
|
+
log.error(
|
|
147
|
+
{ err: reason },
|
|
148
|
+
"Unhandled promise rejection — initiating shutdown",
|
|
149
|
+
);
|
|
147
150
|
Sentry.captureException(reason);
|
|
148
151
|
exitCode = 1;
|
|
149
152
|
void shutdown();
|
|
@@ -27,6 +27,14 @@ const DAEMON_ERROR_PREFIX = "DAEMON_ERROR:";
|
|
|
27
27
|
* Inspect an error and return a categorized {@link DaemonStartupError}.
|
|
28
28
|
*/
|
|
29
29
|
export function categorizeDaemonError(err: unknown): DaemonStartupError {
|
|
30
|
+
if (err == null) {
|
|
31
|
+
return {
|
|
32
|
+
error: "UNKNOWN",
|
|
33
|
+
message: String(err),
|
|
34
|
+
detail: "An unexpected error occurred during startup.",
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
30
38
|
const code = (err as { code?: string }).code ?? "";
|
|
31
39
|
const name = (err as { name?: string }).name ?? "";
|
|
32
40
|
const message =
|
|
@@ -96,6 +104,7 @@ export function categorizeDaemonError(err: unknown): DaemonStartupError {
|
|
|
96
104
|
message.startsWith("Invalid RUNTIME_HTTP_PORT") ||
|
|
97
105
|
message.startsWith("Invalid integer for GATEWAY_PORT") ||
|
|
98
106
|
message.startsWith("Invalid integer for RUNTIME_HTTP_PORT") ||
|
|
107
|
+
message.startsWith("Invalid integer for QDRANT_HTTP_PORT") ||
|
|
99
108
|
/\benv\b.*\bvalidat/i.test(message) ||
|
|
100
109
|
/\bvalidat.*\benv\b/i.test(message)
|
|
101
110
|
) {
|
|
@@ -7,11 +7,9 @@
|
|
|
7
7
|
* registry entry instead of another if/else branch.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import { join } from "node:path";
|
|
11
|
-
|
|
12
10
|
import { compileApp } from "../bundler/app-compiler.js";
|
|
13
11
|
import { generateAppIcon } from "../media/app-icon-generator.js";
|
|
14
|
-
import { getApp,
|
|
12
|
+
import { getApp, getAppDirPath, isMultifileApp } from "../memory/app-store.js";
|
|
15
13
|
import { deliverVerificationSlack } from "../runtime/verification-outbound-actions.js";
|
|
16
14
|
import { updatePublishedAppDeployment } from "../services/published-app-updater.js";
|
|
17
15
|
import type { ToolExecutionResult } from "../tools/types.js";
|
|
@@ -51,7 +49,7 @@ function handleAppChange(
|
|
|
51
49
|
// Multifile apps need a recompile before refreshing surfaces so the
|
|
52
50
|
// WebView picks up the latest compiled output.
|
|
53
51
|
if (app && isMultifileApp(app)) {
|
|
54
|
-
const appDir =
|
|
52
|
+
const appDir = getAppDirPath(appId);
|
|
55
53
|
void compileApp(appDir)
|
|
56
54
|
.then((result) => {
|
|
57
55
|
if (!result.ok) {
|
|
@@ -147,25 +145,25 @@ registerHook(
|
|
|
147
145
|
},
|
|
148
146
|
);
|
|
149
147
|
|
|
150
|
-
//
|
|
148
|
+
// Broadcast app_files_changed when an app is deleted so clients remove it
|
|
149
|
+
// from their cached app lists.
|
|
151
150
|
registerHook(
|
|
152
|
-
"
|
|
153
|
-
(_name, input, _result, {
|
|
151
|
+
"app_delete",
|
|
152
|
+
(_name, input, _result, { broadcastToAllClients }) => {
|
|
154
153
|
const appId = input.app_id as string | undefined;
|
|
155
154
|
if (appId) {
|
|
156
|
-
|
|
155
|
+
broadcastToAllClients?.({ type: "app_files_changed", appId });
|
|
157
156
|
}
|
|
158
157
|
},
|
|
159
158
|
);
|
|
160
159
|
|
|
161
|
-
//
|
|
162
|
-
// from their cached app lists.
|
|
160
|
+
// Trigger compilation + surface refresh + broadcast when an app is refreshed.
|
|
163
161
|
registerHook(
|
|
164
|
-
"
|
|
165
|
-
(_name, input, _result, { broadcastToAllClients }) => {
|
|
162
|
+
"app_refresh",
|
|
163
|
+
(_name, input, _result, { ctx, broadcastToAllClients }) => {
|
|
166
164
|
const appId = input.app_id as string | undefined;
|
|
167
165
|
if (appId) {
|
|
168
|
-
broadcastToAllClients
|
|
166
|
+
handleAppChange(ctx, appId, broadcastToAllClients, { fileChange: true });
|
|
169
167
|
}
|
|
170
168
|
},
|
|
171
169
|
);
|
|
@@ -179,21 +177,6 @@ registerHook(
|
|
|
179
177
|
},
|
|
180
178
|
);
|
|
181
179
|
|
|
182
|
-
// Auto-refresh workspace surfaces when app files are edited.
|
|
183
|
-
registerHook(
|
|
184
|
-
["app_file_edit", "app_file_write"],
|
|
185
|
-
(_name, input, _result, { ctx, broadcastToAllClients }) => {
|
|
186
|
-
const appId = input.app_id as string | undefined;
|
|
187
|
-
const status = input.status as string | undefined;
|
|
188
|
-
if (appId) {
|
|
189
|
-
handleAppChange(ctx, appId, broadcastToAllClients, {
|
|
190
|
-
fileChange: true,
|
|
191
|
-
status,
|
|
192
|
-
});
|
|
193
|
-
}
|
|
194
|
-
},
|
|
195
|
-
);
|
|
196
|
-
|
|
197
180
|
// Broadcast voice config changes to all connected clients so every window
|
|
198
181
|
// picks up the updated UserDefaults value immediately.
|
|
199
182
|
registerHook(
|
|
@@ -30,9 +30,7 @@ export function registerToolPermissionTelemetryListener(
|
|
|
30
30
|
const key = requestId ? `${requestId}:${toolName}` : undefined;
|
|
31
31
|
if (key && promptedToolCalls.has(key)) {
|
|
32
32
|
promptedToolCalls.delete(key);
|
|
33
|
-
recordLifecycleEvent(
|
|
34
|
-
`permission_decided:${toolName}:${decision}`,
|
|
35
|
-
);
|
|
33
|
+
recordLifecycleEvent(`permission_decided:${toolName}:${decision}`);
|
|
36
34
|
}
|
|
37
35
|
return;
|
|
38
36
|
}
|
package/src/instrument.ts
CHANGED
|
@@ -121,7 +121,6 @@ export function setSentryOrganizationId(
|
|
|
121
121
|
const CONVERSATION_TAG_KEYS = [
|
|
122
122
|
"assistant_id",
|
|
123
123
|
"conversation_id",
|
|
124
|
-
"session_id",
|
|
125
124
|
"message_count",
|
|
126
125
|
"user_identifier",
|
|
127
126
|
] as const;
|
|
@@ -148,9 +147,6 @@ export function setSentryConversationContext(
|
|
|
148
147
|
): void {
|
|
149
148
|
Sentry.setTag("assistant_id", ctx.assistantId);
|
|
150
149
|
Sentry.setTag("conversation_id", ctx.conversationId);
|
|
151
|
-
// session_id mirrors conversation_id — downstream Sentry dashboards and
|
|
152
|
-
// alerts may still filter by the legacy tag name.
|
|
153
|
-
Sentry.setTag("session_id", ctx.conversationId);
|
|
154
150
|
Sentry.setTag("message_count", String(ctx.messageCount));
|
|
155
151
|
if (ctx.userIdentifier) {
|
|
156
152
|
Sentry.setTag("user_identifier", ctx.userIdentifier);
|
|
@@ -10,7 +10,7 @@ import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
|
10
10
|
import { join } from "node:path";
|
|
11
11
|
|
|
12
12
|
import { getConfig } from "../config/loader.js";
|
|
13
|
-
import {
|
|
13
|
+
import { getAppDirPath } from "../memory/app-store.js";
|
|
14
14
|
import {
|
|
15
15
|
buildManagedBaseUrl,
|
|
16
16
|
resolveManagedProxyContext,
|
|
@@ -68,7 +68,7 @@ export async function generateAppIcon(
|
|
|
68
68
|
return;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
const appDir =
|
|
71
|
+
const appDir = getAppDirPath(appId);
|
|
72
72
|
const iconPath = join(appDir, "icon.png");
|
|
73
73
|
|
|
74
74
|
// Don't regenerate if icon already exists
|
|
@@ -3,13 +3,18 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Initializes a git repository in the apps directory (~/.vellum/apps/) and
|
|
5
5
|
* commits after every app mutation (create, update, delete, file write/edit).
|
|
6
|
-
* Commits are fire-and-forget
|
|
6
|
+
* Commits are fire-and-forget -- they never block the caller.
|
|
7
7
|
*
|
|
8
8
|
* Also exposes query methods (history, diff, file-at-version, restore) for
|
|
9
9
|
* browsing and reverting app version history.
|
|
10
10
|
*
|
|
11
11
|
* Reuses WorkspaceGitService for all git operations (mutex, circuit breaker,
|
|
12
12
|
* lazy init, etc.).
|
|
13
|
+
*
|
|
14
|
+
* NOTE: After the 010-app-dir-rename migration, git pathspecs use dirName
|
|
15
|
+
* (slug) instead of appId (UUID). History queries will only return commits
|
|
16
|
+
* made after the migration rename. Commits before the migration used UUID-
|
|
17
|
+
* based paths and are not visible through the current slug-based pathspecs.
|
|
13
18
|
*/
|
|
14
19
|
|
|
15
20
|
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
@@ -17,7 +22,7 @@ import { join } from "node:path";
|
|
|
17
22
|
|
|
18
23
|
import { getLogger } from "../util/logger.js";
|
|
19
24
|
import { getWorkspaceGitService } from "../workspace/git-service.js";
|
|
20
|
-
import { getAppsDir } from "./app-store.js";
|
|
25
|
+
import { getAppsDir, resolveAppDir } from "./app-store.js";
|
|
21
26
|
|
|
22
27
|
const log = getLogger("app-git");
|
|
23
28
|
|
|
@@ -38,8 +43,8 @@ export interface AppVersion {
|
|
|
38
43
|
|
|
39
44
|
/**
|
|
40
45
|
* Patterns excluded from app version tracking.
|
|
41
|
-
* - *.preview
|
|
42
|
-
* - records directories
|
|
46
|
+
* - *.preview -- large base64 preview images
|
|
47
|
+
* - records directories -- user data (form submissions), not app code
|
|
43
48
|
*/
|
|
44
49
|
const APP_GITIGNORE_RULES = ["*.preview", "*/records/"];
|
|
45
50
|
|
|
@@ -116,7 +121,7 @@ function validateRelativePath(path: string): void {
|
|
|
116
121
|
* mutation's files get absorbed into WorkspaceGitService's bootstrap
|
|
117
122
|
* commit and the "Create app: ..." commit ends up empty.
|
|
118
123
|
*
|
|
119
|
-
* Safe to call multiple times
|
|
124
|
+
* Safe to call multiple times -- ensureInitialized() is idempotent.
|
|
120
125
|
* Fire-and-forget: errors are logged but never thrown.
|
|
121
126
|
*/
|
|
122
127
|
export async function initAppGit(): Promise<void> {
|
|
@@ -189,14 +194,18 @@ export async function commitAppTurnChanges(
|
|
|
189
194
|
/**
|
|
190
195
|
* Get the commit history for a specific app.
|
|
191
196
|
*
|
|
192
|
-
* Scopes `git log` to files belonging to this app
|
|
193
|
-
*
|
|
197
|
+
* Scopes `git log` to files belonging to this app using dirName-based
|
|
198
|
+
* pathspecs: {dirName}.json, {dirName}/.
|
|
199
|
+
*
|
|
200
|
+
* Note: After the 010 migration, only commits made after the rename are
|
|
201
|
+
* visible. Pre-migration commits used UUID-based paths.
|
|
194
202
|
*/
|
|
195
203
|
export async function getAppHistory(
|
|
196
204
|
appId: string,
|
|
197
205
|
limit = 50,
|
|
198
206
|
): Promise<AppVersion[]> {
|
|
199
207
|
validateAppId(appId);
|
|
208
|
+
const { dirName } = resolveAppDir(appId);
|
|
200
209
|
const safeLimit = Math.max(1, Math.min(Math.floor(limit) || 50, 500));
|
|
201
210
|
const appsDir = getAppsDir();
|
|
202
211
|
const gitService = getWorkspaceGitService(appsDir);
|
|
@@ -207,8 +216,8 @@ export async function getAppHistory(
|
|
|
207
216
|
`--max-count=${safeLimit}`,
|
|
208
217
|
"--format=%H\t%at\t%s",
|
|
209
218
|
"--",
|
|
210
|
-
`${
|
|
211
|
-
`${
|
|
219
|
+
`${dirName}.json`,
|
|
220
|
+
`${dirName}/`,
|
|
212
221
|
]);
|
|
213
222
|
|
|
214
223
|
if (!stdout.trim()) return [];
|
|
@@ -239,6 +248,7 @@ export async function getAppDiff(
|
|
|
239
248
|
validateCommitHash(fromCommit);
|
|
240
249
|
if (toCommit) validateCommitHash(toCommit);
|
|
241
250
|
|
|
251
|
+
const { dirName } = resolveAppDir(appId);
|
|
242
252
|
const appsDir = getAppsDir();
|
|
243
253
|
const gitService = getWorkspaceGitService(appsDir);
|
|
244
254
|
|
|
@@ -247,8 +257,8 @@ export async function getAppDiff(
|
|
|
247
257
|
"diff",
|
|
248
258
|
range,
|
|
249
259
|
"--",
|
|
250
|
-
`${
|
|
251
|
-
`${
|
|
260
|
+
`${dirName}.json`,
|
|
261
|
+
`${dirName}/`,
|
|
252
262
|
]);
|
|
253
263
|
|
|
254
264
|
return stdout;
|
|
@@ -266,12 +276,13 @@ export async function getAppFileAtVersion(
|
|
|
266
276
|
validateRelativePath(path);
|
|
267
277
|
validateCommitHash(commitHash);
|
|
268
278
|
|
|
279
|
+
const { dirName } = resolveAppDir(appId);
|
|
269
280
|
const appsDir = getAppsDir();
|
|
270
281
|
const gitService = getWorkspaceGitService(appsDir);
|
|
271
282
|
|
|
272
283
|
const { stdout } = await gitService.runReadOnlyGit([
|
|
273
284
|
"show",
|
|
274
|
-
`${commitHash}:${
|
|
285
|
+
`${commitHash}:${dirName}/${path}`,
|
|
275
286
|
]);
|
|
276
287
|
|
|
277
288
|
return stdout;
|
|
@@ -294,6 +305,7 @@ export async function restoreAppVersion(
|
|
|
294
305
|
validateAppId(appId);
|
|
295
306
|
validateCommitHash(commitHash);
|
|
296
307
|
|
|
308
|
+
const { dirName } = resolveAppDir(appId);
|
|
297
309
|
const appsDir = getAppsDir();
|
|
298
310
|
const gitService = getWorkspaceGitService(appsDir);
|
|
299
311
|
|
|
@@ -305,14 +317,14 @@ export async function restoreAppVersion(
|
|
|
305
317
|
commitHash,
|
|
306
318
|
"--no-overlay",
|
|
307
319
|
"--",
|
|
308
|
-
`${
|
|
309
|
-
`${
|
|
320
|
+
`${dirName}.json`,
|
|
321
|
+
`${dirName}/`,
|
|
310
322
|
]);
|
|
311
323
|
|
|
312
324
|
// Read the app name and refresh updatedAt so the restored app
|
|
313
325
|
// doesn't appear stale in recency ordering.
|
|
314
326
|
let appName = appId;
|
|
315
|
-
const jsonPath = join(appsDir, `${
|
|
327
|
+
const jsonPath = join(appsDir, `${dirName}.json`);
|
|
316
328
|
if (existsSync(jsonPath)) {
|
|
317
329
|
try {
|
|
318
330
|
const raw = readFileSync(jsonPath, "utf-8");
|
|
@@ -328,7 +340,7 @@ export async function restoreAppVersion(
|
|
|
328
340
|
const shortHash = commitHash.substring(0, 7);
|
|
329
341
|
|
|
330
342
|
// Stage only this app's files and commit atomically within the same mutex lock
|
|
331
|
-
await exec(["add", "--", `${
|
|
343
|
+
await exec(["add", "--", `${dirName}.json`, `${dirName}/`]);
|
|
332
344
|
await exec([
|
|
333
345
|
"commit",
|
|
334
346
|
"-m",
|