@antelopejs/dms-ai 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +190 -0
- package/README.md +46 -0
- package/dist/builder/presence.d.ts +1 -0
- package/dist/builder/presence.js +22 -0
- package/dist/builder/presence.js.map +1 -0
- package/dist/constants/builder.d.ts +7 -0
- package/dist/constants/builder.js +11 -0
- package/dist/constants/builder.js.map +1 -0
- package/dist/constants/frontend-module.d.ts +3 -0
- package/dist/constants/frontend-module.js +7 -0
- package/dist/constants/frontend-module.js.map +1 -0
- package/dist/constants/logs.d.ts +3 -0
- package/dist/constants/logs.js +7 -0
- package/dist/constants/logs.js.map +1 -0
- package/dist/constants/module.d.ts +3 -0
- package/dist/constants/module.js +7 -0
- package/dist/constants/module.js.map +1 -0
- package/dist/constants/pages-registry.d.ts +2 -0
- package/dist/constants/pages-registry.js +6 -0
- package/dist/constants/pages-registry.js.map +1 -0
- package/dist/constants/sidecar.d.ts +24 -0
- package/dist/constants/sidecar.js +32 -0
- package/dist/constants/sidecar.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +41 -0
- package/dist/index.js.map +1 -0
- package/dist/lifecycle/module-roots.d.ts +1 -0
- package/dist/lifecycle/module-roots.js +52 -0
- package/dist/lifecycle/module-roots.js.map +1 -0
- package/dist/lifecycle/respawn-tracker.d.ts +5 -0
- package/dist/lifecycle/respawn-tracker.js +20 -0
- package/dist/lifecycle/respawn-tracker.js.map +1 -0
- package/dist/lifecycle/skill-sources.d.ts +5 -0
- package/dist/lifecycle/skill-sources.js +181 -0
- package/dist/lifecycle/skill-sources.js.map +1 -0
- package/dist/lifecycle/spawn-sidecar.d.ts +17 -0
- package/dist/lifecycle/spawn-sidecar.js +299 -0
- package/dist/lifecycle/spawn-sidecar.js.map +1 -0
- package/dist/logging/log-buffer.d.ts +9 -0
- package/dist/logging/log-buffer.js +76 -0
- package/dist/logging/log-buffer.js.map +1 -0
- package/dist/pages/activity/page.d.ts +10 -0
- package/dist/pages/activity/page.js +62 -0
- package/dist/pages/activity/page.js.map +1 -0
- package/dist/pages/all.d.ts +4 -0
- package/dist/pages/all.js +21 -0
- package/dist/pages/all.js.map +1 -0
- package/dist/pages/index.d.ts +4 -0
- package/dist/pages/index.js +21 -0
- package/dist/pages/index.js.map +1 -0
- package/dist/pages/module.d.ts +1 -0
- package/dist/pages/module.js +11 -0
- package/dist/pages/module.js.map +1 -0
- package/dist/pages/overview/page.d.ts +11 -0
- package/dist/pages/overview/page.js +82 -0
- package/dist/pages/overview/page.js.map +1 -0
- package/dist/pages/settings/page.d.ts +9 -0
- package/dist/pages/settings/page.js +29 -0
- package/dist/pages/settings/page.js.map +1 -0
- package/dist/pages/skills/page.d.ts +9 -0
- package/dist/pages/skills/page.js +29 -0
- package/dist/pages/skills/page.js.map +1 -0
- package/dist/pages-registry.d.ts +2 -0
- package/dist/pages-registry.js +41 -0
- package/dist/pages-registry.js.map +1 -0
- package/dist/routes/builder.d.ts +11 -0
- package/dist/routes/builder.js +135 -0
- package/dist/routes/builder.js.map +1 -0
- package/dist/routes/health.d.ts +8 -0
- package/dist/routes/health.js +27 -0
- package/dist/routes/health.js.map +1 -0
- package/dist/routes/index.d.ts +8 -0
- package/dist/routes/index.js +25 -0
- package/dist/routes/index.js.map +1 -0
- package/dist/routes/logs.d.ts +7 -0
- package/dist/routes/logs.js +51 -0
- package/dist/routes/logs.js.map +1 -0
- package/dist/routes/metrics.d.ts +54 -0
- package/dist/routes/metrics.js +104 -0
- package/dist/routes/metrics.js.map +1 -0
- package/dist/routes/pages-registry.d.ts +7 -0
- package/dist/routes/pages-registry.js +86 -0
- package/dist/routes/pages-registry.js.map +1 -0
- package/dist/routes/proxy.d.ts +4 -0
- package/dist/routes/proxy.js +55 -0
- package/dist/routes/proxy.js.map +1 -0
- package/dist/routes/settings.d.ts +13 -0
- package/dist/routes/settings.js +52 -0
- package/dist/routes/settings.js.map +1 -0
- package/dist/routes/sidecar-auth.d.ts +3 -0
- package/dist/routes/sidecar-auth.js +27 -0
- package/dist/routes/sidecar-auth.js.map +1 -0
- package/dist/routes/sidecar-info.d.ts +6 -0
- package/dist/routes/sidecar-info.js +39 -0
- package/dist/routes/sidecar-info.js.map +1 -0
- package/dist/routes/skills.d.ts +18 -0
- package/dist/routes/skills.js +33 -0
- package/dist/routes/skills.js.map +1 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.js +19 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/logs.d.ts +12 -0
- package/dist/types/logs.js +3 -0
- package/dist/types/logs.js.map +1 -0
- package/dist/types/pages-registry.d.ts +6 -0
- package/dist/types/pages-registry.js +3 -0
- package/dist/types/pages-registry.js.map +1 -0
- package/frontend-vue/.editorconfig +12 -0
- package/frontend-vue/app/components/ActivityView.vue +94 -0
- package/frontend-vue/app/components/SettingsView.vue +300 -0
- package/frontend-vue/app/components/SkillsView.vue +228 -0
- package/frontend-vue/app/plugins/ai.client.ts +109 -0
- package/frontend-vue/app/runtime/backoff.ts +30 -0
- package/frontend-vue/app/runtime/constants.ts +66 -0
- package/frontend-vue/app/runtime/current-page.ts +28 -0
- package/frontend-vue/app/runtime/header-action.ts +64 -0
- package/frontend-vue/app/runtime/host-commands.ts +127 -0
- package/frontend-vue/app/runtime/navigation-complete.ts +22 -0
- package/frontend-vue/app/runtime/overlay-prefs.ts +89 -0
- package/frontend-vue/app/runtime/overlay.ts +383 -0
- package/frontend-vue/app/runtime/shortcuts.ts +28 -0
- package/frontend-vue/app/runtime/sidecar-status.ts +163 -0
- package/frontend-vue/app/runtime/theme-bridge.ts +177 -0
- package/frontend-vue/app/runtime/ws-client.ts +196 -0
- package/frontend-vue/dms.frontend.ts +26 -0
- package/frontend-vue/eslint.config.mjs +24 -0
- package/frontend-vue/package.json +33 -0
- package/frontend-vue/pnpm-lock.yaml +2723 -0
- package/frontend-vue/tests/backoff.test.ts +44 -0
- package/frontend-vue/tests/host-commands.test.ts +142 -0
- package/frontend-vue/tests/navigation.test.ts +45 -0
- package/frontend-vue/tests/overlay-prefs.test.ts +91 -0
- package/frontend-vue/tests/sidecar-auth.test.ts +87 -0
- package/frontend-vue/tests/sidecar-guest.test.ts +45 -0
- package/frontend-vue/vitest.config.ts +8 -0
- package/package.json +79 -0
- package/sidecar/chatbox/dist/assets/index-Cy2BwTG0.js +50 -0
- package/sidecar/chatbox/dist/assets/index-pP_KOHIn.css +1 -0
- package/sidecar/chatbox/dist/index.html +13 -0
- package/sidecar/dist/agent/attachments.d.ts +8 -0
- package/sidecar/dist/agent/attachments.js +85 -0
- package/sidecar/dist/agent/attachments.js.map +1 -0
- package/sidecar/dist/agent/claude-runner.d.ts +33 -0
- package/sidecar/dist/agent/claude-runner.js +264 -0
- package/sidecar/dist/agent/claude-runner.js.map +1 -0
- package/sidecar/dist/agent/claude-session.d.ts +18 -0
- package/sidecar/dist/agent/claude-session.js +155 -0
- package/sidecar/dist/agent/claude-session.js.map +1 -0
- package/sidecar/dist/agent/edit-tracker.d.ts +9 -0
- package/sidecar/dist/agent/edit-tracker.js +34 -0
- package/sidecar/dist/agent/edit-tracker.js.map +1 -0
- package/sidecar/dist/agent/host-context.d.ts +4 -0
- package/sidecar/dist/agent/host-context.js +16 -0
- package/sidecar/dist/agent/host-context.js.map +1 -0
- package/sidecar/dist/agent/input-queue.d.ts +7 -0
- package/sidecar/dist/agent/input-queue.js +39 -0
- package/sidecar/dist/agent/input-queue.js.map +1 -0
- package/sidecar/dist/agent/permission-bus.d.ts +26 -0
- package/sidecar/dist/agent/permission-bus.js +138 -0
- package/sidecar/dist/agent/permission-bus.js.map +1 -0
- package/sidecar/dist/agent/question-bus.d.ts +22 -0
- package/sidecar/dist/agent/question-bus.js +91 -0
- package/sidecar/dist/agent/question-bus.js.map +1 -0
- package/sidecar/dist/agent/read-access.d.ts +2 -0
- package/sidecar/dist/agent/read-access.js +33 -0
- package/sidecar/dist/agent/read-access.js.map +1 -0
- package/sidecar/dist/agent/resolve-claude-binary.d.ts +1 -0
- package/sidecar/dist/agent/resolve-claude-binary.js +43 -0
- package/sidecar/dist/agent/resolve-claude-binary.js.map +1 -0
- package/sidecar/dist/agent/runner-events.d.ts +28 -0
- package/sidecar/dist/agent/runner-events.js +2 -0
- package/sidecar/dist/agent/runner-events.js.map +1 -0
- package/sidecar/dist/agent/sdk-adapter.d.ts +3 -0
- package/sidecar/dist/agent/sdk-adapter.js +106 -0
- package/sidecar/dist/agent/sdk-adapter.js.map +1 -0
- package/sidecar/dist/agent/sdk-loader.d.ts +5 -0
- package/sidecar/dist/agent/sdk-loader.js +14 -0
- package/sidecar/dist/agent/sdk-loader.js.map +1 -0
- package/sidecar/dist/agent/system-prompt.d.ts +6 -0
- package/sidecar/dist/agent/system-prompt.js +29 -0
- package/sidecar/dist/agent/system-prompt.js.map +1 -0
- package/sidecar/dist/agent/tool-summary.d.ts +1 -0
- package/sidecar/dist/agent/tool-summary.js +46 -0
- package/sidecar/dist/agent/tool-summary.js.map +1 -0
- package/sidecar/dist/agent/typecheck.d.ts +36 -0
- package/sidecar/dist/agent/typecheck.js +104 -0
- package/sidecar/dist/agent/typecheck.js.map +1 -0
- package/sidecar/dist/builder/builder-client.d.ts +10 -0
- package/sidecar/dist/builder/builder-client.js +52 -0
- package/sidecar/dist/builder/builder-client.js.map +1 -0
- package/sidecar/dist/builder/capability.d.ts +4 -0
- package/sidecar/dist/builder/capability.js +11 -0
- package/sidecar/dist/builder/capability.js.map +1 -0
- package/sidecar/dist/constants/agent.d.ts +25 -0
- package/sidecar/dist/constants/agent.js +25 -0
- package/sidecar/dist/constants/agent.js.map +1 -0
- package/sidecar/dist/constants/attachments.d.ts +7 -0
- package/sidecar/dist/constants/attachments.js +12 -0
- package/sidecar/dist/constants/attachments.js.map +1 -0
- package/sidecar/dist/constants/builder.d.ts +5 -0
- package/sidecar/dist/constants/builder.js +32 -0
- package/sidecar/dist/constants/builder.js.map +1 -0
- package/sidecar/dist/constants/daemon.d.ts +7 -0
- package/sidecar/dist/constants/daemon.js +8 -0
- package/sidecar/dist/constants/daemon.js.map +1 -0
- package/sidecar/dist/constants/env.d.ts +3 -0
- package/sidecar/dist/constants/env.js +4 -0
- package/sidecar/dist/constants/env.js.map +1 -0
- package/sidecar/dist/constants/host-state.d.ts +1 -0
- package/sidecar/dist/constants/host-state.js +2 -0
- package/sidecar/dist/constants/host-state.js.map +1 -0
- package/sidecar/dist/constants/http.d.ts +20 -0
- package/sidecar/dist/constants/http.js +31 -0
- package/sidecar/dist/constants/http.js.map +1 -0
- package/sidecar/dist/constants/logs.d.ts +11 -0
- package/sidecar/dist/constants/logs.js +16 -0
- package/sidecar/dist/constants/logs.js.map +1 -0
- package/sidecar/dist/constants/mcp.d.ts +24 -0
- package/sidecar/dist/constants/mcp.js +38 -0
- package/sidecar/dist/constants/mcp.js.map +1 -0
- package/sidecar/dist/constants/native-binary.d.ts +4 -0
- package/sidecar/dist/constants/native-binary.js +5 -0
- package/sidecar/dist/constants/native-binary.js.map +1 -0
- package/sidecar/dist/constants/pages.d.ts +16 -0
- package/sidecar/dist/constants/pages.js +24 -0
- package/sidecar/dist/constants/pages.js.map +1 -0
- package/sidecar/dist/constants/paths.d.ts +3 -0
- package/sidecar/dist/constants/paths.js +7 -0
- package/sidecar/dist/constants/paths.js.map +1 -0
- package/sidecar/dist/constants/permissions.d.ts +15 -0
- package/sidecar/dist/constants/permissions.js +15 -0
- package/sidecar/dist/constants/permissions.js.map +1 -0
- package/sidecar/dist/constants/ports.d.ts +3 -0
- package/sidecar/dist/constants/ports.js +4 -0
- package/sidecar/dist/constants/ports.js.map +1 -0
- package/sidecar/dist/constants/project.d.ts +8 -0
- package/sidecar/dist/constants/project.js +12 -0
- package/sidecar/dist/constants/project.js.map +1 -0
- package/sidecar/dist/constants/questions.d.ts +4 -0
- package/sidecar/dist/constants/questions.js +5 -0
- package/sidecar/dist/constants/questions.js.map +1 -0
- package/sidecar/dist/constants/read-access.d.ts +1 -0
- package/sidecar/dist/constants/read-access.js +8 -0
- package/sidecar/dist/constants/read-access.js.map +1 -0
- package/sidecar/dist/constants/safety-net.d.ts +5 -0
- package/sidecar/dist/constants/safety-net.js +6 -0
- package/sidecar/dist/constants/safety-net.js.map +1 -0
- package/sidecar/dist/constants/settings.d.ts +9 -0
- package/sidecar/dist/constants/settings.js +29 -0
- package/sidecar/dist/constants/settings.js.map +1 -0
- package/sidecar/dist/constants/state.d.ts +7 -0
- package/sidecar/dist/constants/state.js +7 -0
- package/sidecar/dist/constants/state.js.map +1 -0
- package/sidecar/dist/constants/timing.d.ts +1 -0
- package/sidecar/dist/constants/timing.js +2 -0
- package/sidecar/dist/constants/timing.js.map +1 -0
- package/sidecar/dist/constants/tool-summary.d.ts +20 -0
- package/sidecar/dist/constants/tool-summary.js +21 -0
- package/sidecar/dist/constants/tool-summary.js.map +1 -0
- package/sidecar/dist/constants/typecheck.d.ts +16 -0
- package/sidecar/dist/constants/typecheck.js +23 -0
- package/sidecar/dist/constants/typecheck.js.map +1 -0
- package/sidecar/dist/constants/ws.d.ts +5 -0
- package/sidecar/dist/constants/ws.js +6 -0
- package/sidecar/dist/constants/ws.js.map +1 -0
- package/sidecar/dist/host/project-info.d.ts +6 -0
- package/sidecar/dist/host/project-info.js +51 -0
- package/sidecar/dist/host/project-info.js.map +1 -0
- package/sidecar/dist/index.d.ts +3 -0
- package/sidecar/dist/index.js +280 -0
- package/sidecar/dist/index.js.map +1 -0
- package/sidecar/dist/logs/logs-client.d.ts +11 -0
- package/sidecar/dist/logs/logs-client.js +52 -0
- package/sidecar/dist/logs/logs-client.js.map +1 -0
- package/sidecar/dist/logs/types.d.ts +12 -0
- package/sidecar/dist/logs/types.js +2 -0
- package/sidecar/dist/logs/types.js.map +1 -0
- package/sidecar/dist/mcp/server.d.ts +2 -0
- package/sidecar/dist/mcp/server.js +50 -0
- package/sidecar/dist/mcp/server.js.map +1 -0
- package/sidecar/dist/mcp/tools/ask-user.d.ts +41 -0
- package/sidecar/dist/mcp/tools/ask-user.js +29 -0
- package/sidecar/dist/mcp/tools/ask-user.js.map +1 -0
- package/sidecar/dist/mcp/tools/builder.d.ts +259 -0
- package/sidecar/dist/mcp/tools/builder.js +216 -0
- package/sidecar/dist/mcp/tools/builder.js.map +1 -0
- package/sidecar/dist/mcp/tools/find-pages-using.d.ts +15 -0
- package/sidecar/dist/mcp/tools/find-pages-using.js +108 -0
- package/sidecar/dist/mcp/tools/find-pages-using.js.map +1 -0
- package/sidecar/dist/mcp/tools/get-current-page.d.ts +4 -0
- package/sidecar/dist/mcp/tools/get-current-page.js +12 -0
- package/sidecar/dist/mcp/tools/get-current-page.js.map +1 -0
- package/sidecar/dist/mcp/tools/list-pages.d.ts +8 -0
- package/sidecar/dist/mcp/tools/list-pages.js +29 -0
- package/sidecar/dist/mcp/tools/list-pages.js.map +1 -0
- package/sidecar/dist/mcp/tools/navigate-to-page.d.ts +14 -0
- package/sidecar/dist/mcp/tools/navigate-to-page.js +66 -0
- package/sidecar/dist/mcp/tools/navigate-to-page.js.map +1 -0
- package/sidecar/dist/mcp/tools/query-logs.d.ts +11 -0
- package/sidecar/dist/mcp/tools/query-logs.js +32 -0
- package/sidecar/dist/mcp/tools/query-logs.js.map +1 -0
- package/sidecar/dist/mcp/tools/typecheck.d.ts +9 -0
- package/sidecar/dist/mcp/tools/typecheck.js +20 -0
- package/sidecar/dist/mcp/tools/typecheck.js.map +1 -0
- package/sidecar/dist/mcp/types.d.ts +27 -0
- package/sidecar/dist/mcp/types.js +2 -0
- package/sidecar/dist/mcp/types.js.map +1 -0
- package/sidecar/dist/metrics/aggregate.d.ts +11 -0
- package/sidecar/dist/metrics/aggregate.js +189 -0
- package/sidecar/dist/metrics/aggregate.js.map +1 -0
- package/sidecar/dist/metrics/types.d.ts +53 -0
- package/sidecar/dist/metrics/types.js +8 -0
- package/sidecar/dist/metrics/types.js.map +1 -0
- package/sidecar/dist/pages/imports-scanner.d.ts +9 -0
- package/sidecar/dist/pages/imports-scanner.js +143 -0
- package/sidecar/dist/pages/imports-scanner.js.map +1 -0
- package/sidecar/dist/pages/registry-client.d.ts +15 -0
- package/sidecar/dist/pages/registry-client.js +83 -0
- package/sidecar/dist/pages/registry-client.js.map +1 -0
- package/sidecar/dist/pages/route-match.d.ts +2 -0
- package/sidecar/dist/pages/route-match.js +10 -0
- package/sidecar/dist/pages/route-match.js.map +1 -0
- package/sidecar/dist/pages/types.d.ts +11 -0
- package/sidecar/dist/pages/types.js +2 -0
- package/sidecar/dist/pages/types.js.map +1 -0
- package/sidecar/dist/prompts/agent.d.ts +3 -0
- package/sidecar/dist/prompts/agent.js +40 -0
- package/sidecar/dist/prompts/agent.js.map +1 -0
- package/sidecar/dist/prompts/builder.d.ts +3 -0
- package/sidecar/dist/prompts/builder.js +4 -0
- package/sidecar/dist/prompts/builder.js.map +1 -0
- package/sidecar/dist/protocol/events.d.ts +1050 -0
- package/sidecar/dist/protocol/events.js +154 -0
- package/sidecar/dist/protocol/events.js.map +1 -0
- package/sidecar/dist/protocol/messages.d.ts +644 -0
- package/sidecar/dist/protocol/messages.js +139 -0
- package/sidecar/dist/protocol/messages.js.map +1 -0
- package/sidecar/dist/server/client-auth.d.ts +2 -0
- package/sidecar/dist/server/client-auth.js +25 -0
- package/sidecar/dist/server/client-auth.js.map +1 -0
- package/sidecar/dist/server/host-socket-registry.d.ts +9 -0
- package/sidecar/dist/server/host-socket-registry.js +42 -0
- package/sidecar/dist/server/host-socket-registry.js.map +1 -0
- package/sidecar/dist/server/http.d.ts +25 -0
- package/sidecar/dist/server/http.js +263 -0
- package/sidecar/dist/server/http.js.map +1 -0
- package/sidecar/dist/server/idle-shutdown.d.ts +10 -0
- package/sidecar/dist/server/idle-shutdown.js +35 -0
- package/sidecar/dist/server/idle-shutdown.js.map +1 -0
- package/sidecar/dist/server/iframe-socket-registry.d.ts +10 -0
- package/sidecar/dist/server/iframe-socket-registry.js +57 -0
- package/sidecar/dist/server/iframe-socket-registry.js.map +1 -0
- package/sidecar/dist/server/live-turns.d.ts +8 -0
- package/sidecar/dist/server/live-turns.js +16 -0
- package/sidecar/dist/server/live-turns.js.map +1 -0
- package/sidecar/dist/server/navigation-completer.d.ts +5 -0
- package/sidecar/dist/server/navigation-completer.js +49 -0
- package/sidecar/dist/server/navigation-completer.js.map +1 -0
- package/sidecar/dist/server/pending-queue.d.ts +11 -0
- package/sidecar/dist/server/pending-queue.js +54 -0
- package/sidecar/dist/server/pending-queue.js.map +1 -0
- package/sidecar/dist/server/raw-data.d.ts +2 -0
- package/sidecar/dist/server/raw-data.js +13 -0
- package/sidecar/dist/server/raw-data.js.map +1 -0
- package/sidecar/dist/server/routing.d.ts +64 -0
- package/sidecar/dist/server/routing.js +571 -0
- package/sidecar/dist/server/routing.js.map +1 -0
- package/sidecar/dist/server/safety-net.d.ts +16 -0
- package/sidecar/dist/server/safety-net.js +76 -0
- package/sidecar/dist/server/safety-net.js.map +1 -0
- package/sidecar/dist/server/ws.d.ts +33 -0
- package/sidecar/dist/server/ws.js +182 -0
- package/sidecar/dist/server/ws.js.map +1 -0
- package/sidecar/dist/skills/build-catalog.d.ts +15 -0
- package/sidecar/dist/skills/build-catalog.js +39 -0
- package/sidecar/dist/skills/build-catalog.js.map +1 -0
- package/sidecar/dist/skills/frontmatter.d.ts +9 -0
- package/sidecar/dist/skills/frontmatter.js +50 -0
- package/sidecar/dist/skills/frontmatter.js.map +1 -0
- package/sidecar/dist/skills/plugin-wrapper.d.ts +6 -0
- package/sidecar/dist/skills/plugin-wrapper.js +37 -0
- package/sidecar/dist/skills/plugin-wrapper.js.map +1 -0
- package/sidecar/dist/skills/resolve-sources.d.ts +3 -0
- package/sidecar/dist/skills/resolve-sources.js +14 -0
- package/sidecar/dist/skills/resolve-sources.js.map +1 -0
- package/sidecar/dist/skills/types.d.ts +4 -0
- package/sidecar/dist/skills/types.js +2 -0
- package/sidecar/dist/skills/types.js.map +1 -0
- package/sidecar/dist/state/conversations.d.ts +20 -0
- package/sidecar/dist/state/conversations.js +93 -0
- package/sidecar/dist/state/conversations.js.map +1 -0
- package/sidecar/dist/state/host-state.d.ts +10 -0
- package/sidecar/dist/state/host-state.js +14 -0
- package/sidecar/dist/state/host-state.js.map +1 -0
- package/sidecar/dist/state/lock.d.ts +12 -0
- package/sidecar/dist/state/lock.js +43 -0
- package/sidecar/dist/state/lock.js.map +1 -0
- package/sidecar/dist/state/settings-store.d.ts +12 -0
- package/sidecar/dist/state/settings-store.js +82 -0
- package/sidecar/dist/state/settings-store.js.map +1 -0
- package/sidecar/dist/state/settings-types.d.ts +12 -0
- package/sidecar/dist/state/settings-types.js +4 -0
- package/sidecar/dist/state/settings-types.js.map +1 -0
- package/sidecar/dist/state/sidecar-version.d.ts +1 -0
- package/sidecar/dist/state/sidecar-version.js +14 -0
- package/sidecar/dist/state/sidecar-version.js.map +1 -0
- package/sidecar/dist/state/store.d.ts +11 -0
- package/sidecar/dist/state/store.js +89 -0
- package/sidecar/dist/state/store.js.map +1 -0
- package/sidecar/dist/state/types.d.ts +36 -0
- package/sidecar/dist/state/types.js +10 -0
- package/sidecar/dist/state/types.js.map +1 -0
- package/sidecar/package.json +42 -0
- package/skills/dms-builder-page/SKILL.md +80 -0
- package/skills/dms-builder-safe/REFERENCE.md +111 -0
- package/skills/dms-builder-safe/SKILL.md +118 -0
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
import {
|
|
2
|
+
OVERLAY_BOX_SHADOW,
|
|
3
|
+
OVERLAY_DEFAULT_WIDTH_PX,
|
|
4
|
+
OVERLAY_DOM_ID,
|
|
5
|
+
OVERLAY_IFRAME_ID,
|
|
6
|
+
OVERLAY_MIN_WIDTH_PX,
|
|
7
|
+
OVERLAY_OUTSIDE_TOGGLE_SUPPRESS_MS,
|
|
8
|
+
OVERLAY_PLACEHOLDER_ID,
|
|
9
|
+
OVERLAY_RESIZE_HANDLE_SIZE_PX,
|
|
10
|
+
OVERLAY_Z_INDEX,
|
|
11
|
+
PLACEHOLDER_CONNECTING_TEXT,
|
|
12
|
+
PLACEHOLDER_REVIVING_TEXT,
|
|
13
|
+
PLACEHOLDER_UNAVAILABLE_TEXT,
|
|
14
|
+
PLACEHOLDER_UNAVAILABLE_TITLE,
|
|
15
|
+
} from './constants'
|
|
16
|
+
import {
|
|
17
|
+
type OverlayPrefs,
|
|
18
|
+
readPrefs,
|
|
19
|
+
writePrefsDebounced,
|
|
20
|
+
} from './overlay-prefs'
|
|
21
|
+
import {
|
|
22
|
+
type HostTheme,
|
|
23
|
+
installThemeBridge,
|
|
24
|
+
readHostMode,
|
|
25
|
+
} from './theme-bridge'
|
|
26
|
+
|
|
27
|
+
// What the host-origin placeholder shows while the sidecar frame can't be shown.
|
|
28
|
+
// `connecting`/`reviving` are transient (spinner); `unavailable` is terminal.
|
|
29
|
+
export type PlaceholderKind = 'connecting' | 'reviving' | 'unavailable'
|
|
30
|
+
|
|
31
|
+
export interface OverlayHandle {
|
|
32
|
+
// Toggle the docked panel's slide-in open/closed state.
|
|
33
|
+
toggleOpen: () => void
|
|
34
|
+
// Launcher-specific toggle: ignores an open request that immediately follows
|
|
35
|
+
// an outside-click close, since the launcher's `click` fires after the same
|
|
36
|
+
// `pointerdown` that already closed the panel. The keyboard shortcut must
|
|
37
|
+
// use `toggleOpen` so it is never suppressed.
|
|
38
|
+
toggleFromLauncher: () => void
|
|
39
|
+
isOpen: () => boolean
|
|
40
|
+
// Point the frame at a (possibly new) sidecar URL. A no-op when the URL is
|
|
41
|
+
// unchanged and already loaded, so a redundant `connected` notify won't reload
|
|
42
|
+
// the chatbox; otherwise it reloads and shows a connecting placeholder until
|
|
43
|
+
// the frame paints.
|
|
44
|
+
repoint: (url: string) => void
|
|
45
|
+
// Cover the frame with the host-origin status panel (never the browser's raw
|
|
46
|
+
// error page) while the sidecar is unreachable.
|
|
47
|
+
showPlaceholder: (kind: PlaceholderKind) => void
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
interface OverlayElements {
|
|
51
|
+
container: HTMLDivElement
|
|
52
|
+
iframe: HTMLIFrameElement
|
|
53
|
+
resizeHandle: HTMLDivElement
|
|
54
|
+
placeholder: HTMLDivElement
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
interface OverlayPrefsRef {
|
|
58
|
+
value: OverlayPrefs
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
interface MessageData {
|
|
62
|
+
type?: unknown
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const MAX_WIDTH_VW_RATIO = 0.94
|
|
66
|
+
// Message types accepted from the chatbox iframe to close the panel.
|
|
67
|
+
const CLOSE_MESSAGE_TYPES = new Set(['dms-ai:close'])
|
|
68
|
+
|
|
69
|
+
// Fallback backdrop shown behind the iframe while it slides in, before the
|
|
70
|
+
// bridge reports the host's real `--ui-bg`. Only briefly visible.
|
|
71
|
+
const BACKDROP_DARK = '#0a0b12'
|
|
72
|
+
const BACKDROP_LIGHT = '#ffffff'
|
|
73
|
+
|
|
74
|
+
function backdropFor(mode: 'dark' | 'light'): string {
|
|
75
|
+
return mode === 'dark' ? BACKDROP_DARK : BACKDROP_LIGHT
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function maxWidth(): number {
|
|
79
|
+
const vw = globalThis.innerWidth ?? OVERLAY_DEFAULT_WIDTH_PX * 3
|
|
80
|
+
return Math.max(OVERLAY_MIN_WIDTH_PX, Math.round(vw * MAX_WIDTH_VW_RATIO))
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function clampWidth(width: number): number {
|
|
84
|
+
return Math.min(Math.max(width, OVERLAY_MIN_WIDTH_PX), maxWidth())
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function buildContainer(): HTMLDivElement {
|
|
88
|
+
const container = document.createElement('div')
|
|
89
|
+
container.id = OVERLAY_DOM_ID
|
|
90
|
+
const style = container.style
|
|
91
|
+
style.position = 'fixed'
|
|
92
|
+
style.top = '0'
|
|
93
|
+
style.right = '0'
|
|
94
|
+
style.height = '100vh'
|
|
95
|
+
style.zIndex = String(OVERLAY_Z_INDEX)
|
|
96
|
+
style.boxShadow = OVERLAY_BOX_SHADOW
|
|
97
|
+
// Backdrop behind the iframe while it slides in — follow the host mode so a
|
|
98
|
+
// light-mode host doesn't flash a dark sheet. The iframe fills the container
|
|
99
|
+
// once painted, so this is only ever briefly visible.
|
|
100
|
+
style.background = backdropFor(readHostMode())
|
|
101
|
+
style.borderLeft = '1px solid rgba(140,160,220,0.20)'
|
|
102
|
+
style.overflow = 'hidden'
|
|
103
|
+
style.display = 'flex'
|
|
104
|
+
style.transition = 'transform 220ms cubic-bezier(0.16, 1, 0.3, 1)'
|
|
105
|
+
style.willChange = 'transform'
|
|
106
|
+
return container
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Built with no `src`: the frame is only pointed at the sidecar via `repoint`
|
|
110
|
+
// once the status controller confirms a reachable port, so the browser never
|
|
111
|
+
// renders its native "can't reach" page for a dead port.
|
|
112
|
+
function buildIframe(): HTMLIFrameElement {
|
|
113
|
+
const iframe = document.createElement('iframe')
|
|
114
|
+
iframe.id = OVERLAY_IFRAME_ID
|
|
115
|
+
iframe.style.flex = '1 1 auto'
|
|
116
|
+
iframe.style.width = '100%'
|
|
117
|
+
iframe.style.height = '100%'
|
|
118
|
+
iframe.style.border = '0'
|
|
119
|
+
iframe.style.colorScheme = readHostMode()
|
|
120
|
+
return iframe
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const SPINNER_STYLE_ID = 'dms-ai-overlay-spinner-style'
|
|
124
|
+
|
|
125
|
+
function ensureSpinnerKeyframes(): void {
|
|
126
|
+
if (document.getElementById(SPINNER_STYLE_ID) !== null) return
|
|
127
|
+
const style = document.createElement('style')
|
|
128
|
+
style.id = SPINNER_STYLE_ID
|
|
129
|
+
style.textContent =
|
|
130
|
+
'@keyframes dms-ai-spin{to{transform:rotate(360deg)}}'
|
|
131
|
+
document.head.appendChild(style)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function buildPlaceholder(): HTMLDivElement {
|
|
135
|
+
const placeholder = document.createElement('div')
|
|
136
|
+
placeholder.id = OVERLAY_PLACEHOLDER_ID
|
|
137
|
+
const style = placeholder.style
|
|
138
|
+
style.position = 'absolute'
|
|
139
|
+
style.inset = '0'
|
|
140
|
+
// Above the iframe, but transparent to pointers so the resize handle and the
|
|
141
|
+
// (harmless) dead frame beneath stay reachable.
|
|
142
|
+
style.zIndex = '2'
|
|
143
|
+
style.pointerEvents = 'none'
|
|
144
|
+
style.display = 'none'
|
|
145
|
+
style.flexDirection = 'column'
|
|
146
|
+
style.alignItems = 'center'
|
|
147
|
+
style.justifyContent = 'center'
|
|
148
|
+
style.gap = '14px'
|
|
149
|
+
style.padding = '24px'
|
|
150
|
+
style.textAlign = 'center'
|
|
151
|
+
style.font =
|
|
152
|
+
'500 13px/1.5 system-ui, -apple-system, Segoe UI, Roboto, sans-serif'
|
|
153
|
+
style.background = backdropFor(readHostMode())
|
|
154
|
+
return placeholder
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function spinnerHtml(color: string): string {
|
|
158
|
+
return `<span style="width:22px;height:22px;border:2.5px solid ${color}33;border-top-color:${color};border-radius:50%;animation:dms-ai-spin 0.7s linear infinite;"></span>`
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function placeholderContent(kind: PlaceholderKind): string {
|
|
162
|
+
if (kind === 'unavailable') {
|
|
163
|
+
return `<div style="font-size:15px;font-weight:600;">${PLACEHOLDER_UNAVAILABLE_TITLE}</div><div style="opacity:0.7;">${PLACEHOLDER_UNAVAILABLE_TEXT}</div>`
|
|
164
|
+
}
|
|
165
|
+
const text =
|
|
166
|
+
kind === 'reviving'
|
|
167
|
+
? PLACEHOLDER_REVIVING_TEXT
|
|
168
|
+
: PLACEHOLDER_CONNECTING_TEXT
|
|
169
|
+
return `${spinnerHtml('currentColor')}<div style="opacity:0.75;">${text}</div>`
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function buildResizeHandle(): HTMLDivElement {
|
|
173
|
+
const handle = document.createElement('div')
|
|
174
|
+
const style = handle.style
|
|
175
|
+
style.position = 'absolute'
|
|
176
|
+
style.left = '0'
|
|
177
|
+
style.top = '0'
|
|
178
|
+
style.width = `${OVERLAY_RESIZE_HANDLE_SIZE_PX}px`
|
|
179
|
+
style.height = '100%'
|
|
180
|
+
style.cursor = 'ew-resize'
|
|
181
|
+
style.touchAction = 'none'
|
|
182
|
+
style.zIndex = '1'
|
|
183
|
+
return handle
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function applyPrefs(elements: OverlayElements, prefs: OverlayPrefs): void {
|
|
187
|
+
const width = clampWidth(prefs.width)
|
|
188
|
+
elements.container.style.width = `${width}px`
|
|
189
|
+
elements.container.style.transform = prefs.isOpen
|
|
190
|
+
? 'translateX(0)'
|
|
191
|
+
: 'translateX(100%)'
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function resolveInitialPrefs(): OverlayPrefs {
|
|
195
|
+
const stored = readPrefs()
|
|
196
|
+
if (stored !== null)
|
|
197
|
+
return { width: clampWidth(stored.width), isOpen: stored.isOpen }
|
|
198
|
+
return { width: OVERLAY_DEFAULT_WIDTH_PX, isOpen: false }
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
interface InteractionContext {
|
|
202
|
+
elements: OverlayElements
|
|
203
|
+
stateRef: OverlayPrefsRef
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function installWidthResize(ctx: InteractionContext): void {
|
|
207
|
+
const { resizeHandle, container, iframe } = ctx.elements
|
|
208
|
+
let startX = 0
|
|
209
|
+
let startWidth = 0
|
|
210
|
+
|
|
211
|
+
const onMove = (event: PointerEvent): void => {
|
|
212
|
+
// Panel is pinned right, so dragging left (smaller clientX) grows it.
|
|
213
|
+
const next = clampWidth(startWidth + (startX - event.clientX))
|
|
214
|
+
ctx.stateRef.value = { ...ctx.stateRef.value, width: next }
|
|
215
|
+
container.style.width = `${next}px`
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const onUp = (): void => {
|
|
219
|
+
globalThis.removeEventListener('pointermove', onMove)
|
|
220
|
+
globalThis.removeEventListener('pointerup', onUp)
|
|
221
|
+
// Restore the iframe's pointer capture now the drag is over.
|
|
222
|
+
iframe.style.pointerEvents = ''
|
|
223
|
+
writePrefsDebounced(ctx.stateRef.value)
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
resizeHandle.addEventListener('pointerdown', (event: PointerEvent) => {
|
|
227
|
+
event.preventDefault()
|
|
228
|
+
startX = event.clientX
|
|
229
|
+
startWidth = ctx.stateRef.value.width
|
|
230
|
+
// While dragging, dragging over the iframe would let it swallow the
|
|
231
|
+
// pointer stream, so the parent never sees pointermove/up and the drag
|
|
232
|
+
// sticks. Make the iframe transparent to pointers for the drag's duration.
|
|
233
|
+
iframe.style.pointerEvents = 'none'
|
|
234
|
+
globalThis.addEventListener('pointermove', onMove)
|
|
235
|
+
globalThis.addEventListener('pointerup', onUp)
|
|
236
|
+
})
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Close the panel when the user clicks anywhere in the host page outside it.
|
|
240
|
+
// Clicks inside the iframe never reach the host document, so they can't close
|
|
241
|
+
// the panel. Returns a predicate telling whether an outside click just closed
|
|
242
|
+
// the panel: the header launcher toggles on `click`, which follows the same
|
|
243
|
+
// `pointerdown` that closed the panel — without this guard, clicking the
|
|
244
|
+
// launcher while open would close then immediately re-open it.
|
|
245
|
+
function installOutsideClickClose(ctx: InteractionContext): () => boolean {
|
|
246
|
+
let lastCloseAt = Number.NEGATIVE_INFINITY
|
|
247
|
+
document.addEventListener(
|
|
248
|
+
'pointerdown',
|
|
249
|
+
(event: PointerEvent) => {
|
|
250
|
+
if (!ctx.stateRef.value.isOpen) return
|
|
251
|
+
if (event.composedPath().includes(ctx.elements.container)) return
|
|
252
|
+
lastCloseAt = event.timeStamp
|
|
253
|
+
setOpen(ctx.elements, ctx.stateRef, false)
|
|
254
|
+
},
|
|
255
|
+
{ capture: true },
|
|
256
|
+
)
|
|
257
|
+
return (): boolean =>
|
|
258
|
+
performance.now() - lastCloseAt < OVERLAY_OUTSIDE_TOGGLE_SUPPRESS_MS
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function appendElements(elements: OverlayElements): void {
|
|
262
|
+
elements.container.appendChild(elements.iframe)
|
|
263
|
+
elements.container.appendChild(elements.placeholder)
|
|
264
|
+
elements.container.appendChild(elements.resizeHandle)
|
|
265
|
+
document.body.appendChild(elements.container)
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
interface PlaceholderController {
|
|
269
|
+
show: (kind: PlaceholderKind) => void
|
|
270
|
+
hide: () => void
|
|
271
|
+
recolor: (theme: HostTheme) => void
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function createPlaceholderController(
|
|
275
|
+
placeholder: HTMLDivElement,
|
|
276
|
+
): PlaceholderController {
|
|
277
|
+
return {
|
|
278
|
+
show: (kind) => {
|
|
279
|
+
placeholder.innerHTML = placeholderContent(kind)
|
|
280
|
+
placeholder.style.display = 'flex'
|
|
281
|
+
},
|
|
282
|
+
hide: () => {
|
|
283
|
+
placeholder.style.display = 'none'
|
|
284
|
+
},
|
|
285
|
+
recolor: (theme) => {
|
|
286
|
+
placeholder.style.background =
|
|
287
|
+
theme.tokens['--ui-bg'] || backdropFor(theme.mode)
|
|
288
|
+
placeholder.style.color = theme.tokens['--ui-text'] || ''
|
|
289
|
+
},
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Repoint the frame at `url`, deferring the placeholder-hide until it paints so a
|
|
294
|
+
// port change reloads the chatbox without flashing the previous dead frame. A
|
|
295
|
+
// no-op reload when the URL is already loaded.
|
|
296
|
+
function createRepointer(
|
|
297
|
+
iframe: HTMLIFrameElement,
|
|
298
|
+
placeholder: PlaceholderController,
|
|
299
|
+
): (url: string) => void {
|
|
300
|
+
let currentUrl = ''
|
|
301
|
+
let loaded = false
|
|
302
|
+
iframe.addEventListener('load', () => {
|
|
303
|
+
if (iframe.src === '') return
|
|
304
|
+
loaded = true
|
|
305
|
+
placeholder.hide()
|
|
306
|
+
})
|
|
307
|
+
return (url: string): void => {
|
|
308
|
+
if (url === currentUrl && loaded) {
|
|
309
|
+
placeholder.hide()
|
|
310
|
+
return
|
|
311
|
+
}
|
|
312
|
+
currentUrl = url
|
|
313
|
+
loaded = false
|
|
314
|
+
placeholder.show('connecting')
|
|
315
|
+
iframe.src = url
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
function setOpen(
|
|
320
|
+
elements: OverlayElements,
|
|
321
|
+
stateRef: OverlayPrefsRef,
|
|
322
|
+
isOpen: boolean,
|
|
323
|
+
): void {
|
|
324
|
+
stateRef.value = { ...stateRef.value, isOpen }
|
|
325
|
+
applyPrefs(elements, stateRef.value)
|
|
326
|
+
writePrefsDebounced(stateRef.value)
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
export function injectOverlay(): OverlayHandle | null {
|
|
330
|
+
const isAlreadyInjected = document.getElementById(OVERLAY_DOM_ID) !== null
|
|
331
|
+
if (isAlreadyInjected) return null
|
|
332
|
+
ensureSpinnerKeyframes()
|
|
333
|
+
const elements: OverlayElements = {
|
|
334
|
+
container: buildContainer(),
|
|
335
|
+
iframe: buildIframe(),
|
|
336
|
+
resizeHandle: buildResizeHandle(),
|
|
337
|
+
placeholder: buildPlaceholder(),
|
|
338
|
+
}
|
|
339
|
+
appendElements(elements)
|
|
340
|
+
const placeholder = createPlaceholderController(elements.placeholder)
|
|
341
|
+
const repoint = createRepointer(elements.iframe, placeholder)
|
|
342
|
+
const stateRef = { value: resolveInitialPrefs() }
|
|
343
|
+
applyPrefs(elements, stateRef.value)
|
|
344
|
+
installWidthResize({ elements, stateRef })
|
|
345
|
+
const wasJustClosedByOutsideClick = installOutsideClickClose({
|
|
346
|
+
elements,
|
|
347
|
+
stateRef,
|
|
348
|
+
})
|
|
349
|
+
// Mirror the host's primary palette + light/dark mode into the iframe, and
|
|
350
|
+
// keep the panel backdrop / iframe color-scheme (and the status placeholder)
|
|
351
|
+
// following live mode changes (e.g. an OS-driven dark switch) so no light edge
|
|
352
|
+
// lingers until a reload.
|
|
353
|
+
installThemeBridge(elements.iframe, (theme) => {
|
|
354
|
+
elements.container.style.background =
|
|
355
|
+
theme.tokens['--ui-bg'] || backdropFor(theme.mode)
|
|
356
|
+
elements.iframe.style.colorScheme = theme.mode
|
|
357
|
+
placeholder.recolor(theme)
|
|
358
|
+
})
|
|
359
|
+
|
|
360
|
+
// The chatbox header's close button lives inside the iframe; it asks the
|
|
361
|
+
// host to slide the panel away via postMessage.
|
|
362
|
+
globalThis.addEventListener('message', (event: MessageEvent) => {
|
|
363
|
+
const type = (event.data as MessageData)?.type
|
|
364
|
+
if (typeof type === 'string' && CLOSE_MESSAGE_TYPES.has(type)) {
|
|
365
|
+
setOpen(elements, stateRef, false)
|
|
366
|
+
}
|
|
367
|
+
})
|
|
368
|
+
|
|
369
|
+
const toggle = (): void =>
|
|
370
|
+
setOpen(elements, stateRef, !stateRef.value.isOpen)
|
|
371
|
+
|
|
372
|
+
return {
|
|
373
|
+
toggleOpen: toggle,
|
|
374
|
+
toggleFromLauncher: (): void => {
|
|
375
|
+
const wouldOpen = !stateRef.value.isOpen
|
|
376
|
+
if (wouldOpen && wasJustClosedByOutsideClick()) return
|
|
377
|
+
toggle()
|
|
378
|
+
},
|
|
379
|
+
isOpen: (): boolean => stateRef.value.isOpen,
|
|
380
|
+
repoint,
|
|
381
|
+
showPlaceholder: (kind) => placeholder.show(kind),
|
|
382
|
+
}
|
|
383
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { MODAL_OPEN_SELECTOR, TOGGLE_SHORTCUT_KEY } from './constants'
|
|
2
|
+
|
|
3
|
+
export interface InstallToggleShortcutOptions {
|
|
4
|
+
onToggle: () => void
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
function isModalOpen(): boolean {
|
|
8
|
+
return document.querySelector(MODAL_OPEN_SELECTOR) !== null
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function isToggleCombo(event: KeyboardEvent): boolean {
|
|
12
|
+
const isModifierPressed = event.metaKey || event.ctrlKey
|
|
13
|
+
const isTargetKey = event.key.toLowerCase() === TOGGLE_SHORTCUT_KEY
|
|
14
|
+
// Require shift too — plain ctrl/cmd + k is the DMS search palette.
|
|
15
|
+
return isModifierPressed && event.shiftKey && isTargetKey
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function installToggleShortcut(
|
|
19
|
+
options: InstallToggleShortcutOptions,
|
|
20
|
+
): void {
|
|
21
|
+
const handler = (event: KeyboardEvent): void => {
|
|
22
|
+
if (!isToggleCombo(event)) return
|
|
23
|
+
if (isModalOpen()) return
|
|
24
|
+
event.preventDefault()
|
|
25
|
+
options.onToggle()
|
|
26
|
+
}
|
|
27
|
+
document.addEventListener('keydown', handler)
|
|
28
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { createBackoff, nextDelay, resetBackoff } from './backoff'
|
|
2
|
+
import {
|
|
3
|
+
SIDECAR_POLL_DELAYS_MS,
|
|
4
|
+
SIDECAR_STATUS_CONNECTED,
|
|
5
|
+
SIDECAR_STATUS_CONNECTING,
|
|
6
|
+
SIDECAR_STATUS_REVIVING,
|
|
7
|
+
SIDECAR_STATUS_UNAVAILABLE,
|
|
8
|
+
} from './constants'
|
|
9
|
+
|
|
10
|
+
export type SidecarStatus =
|
|
11
|
+
| typeof SIDECAR_STATUS_CONNECTING
|
|
12
|
+
| typeof SIDECAR_STATUS_CONNECTED
|
|
13
|
+
| typeof SIDECAR_STATUS_REVIVING
|
|
14
|
+
| typeof SIDECAR_STATUS_UNAVAILABLE
|
|
15
|
+
|
|
16
|
+
interface SidecarInfo {
|
|
17
|
+
port: number | null
|
|
18
|
+
clientToken: string | null
|
|
19
|
+
isRunning: boolean
|
|
20
|
+
hasGivenUp: boolean
|
|
21
|
+
disabled: boolean
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface SidecarStatusController {
|
|
25
|
+
// Runs the first probe. Returns false when the assistant should not be shown
|
|
26
|
+
// at all — the dms-ai backend route is absent (probe unreachable) or spawning
|
|
27
|
+
// is disabled for this process — so the caller skips injection entirely.
|
|
28
|
+
init: () => Promise<boolean>
|
|
29
|
+
getStatus: () => SidecarStatus
|
|
30
|
+
getPort: () => number | null
|
|
31
|
+
getClientToken: () => string | null
|
|
32
|
+
// Subscribe to status changes; fires immediately with the current status so a
|
|
33
|
+
// late subscriber (overlay/icon injected after init) reflects it right away.
|
|
34
|
+
subscribe: (cb: (status: SidecarStatus) => void) => () => void
|
|
35
|
+
// The host WebSocket dropped: re-probe now to relearn a possibly-new port
|
|
36
|
+
// rather than let the socket keep retrying the dead one.
|
|
37
|
+
reportWsDown: () => void
|
|
38
|
+
dispose: () => void
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export type FetchSidecarInfo = () => Promise<Partial<SidecarInfo>>
|
|
42
|
+
|
|
43
|
+
async function fetchInfo(
|
|
44
|
+
fetchDetails: FetchSidecarInfo,
|
|
45
|
+
): Promise<SidecarInfo | null> {
|
|
46
|
+
try {
|
|
47
|
+
const body = await fetchDetails()
|
|
48
|
+
return {
|
|
49
|
+
port: typeof body.port === 'number' ? body.port : null,
|
|
50
|
+
clientToken:
|
|
51
|
+
typeof body.clientToken === 'string' ? body.clientToken : null,
|
|
52
|
+
isRunning: body.isRunning === true,
|
|
53
|
+
hasGivenUp: body.hasGivenUp === true,
|
|
54
|
+
disabled: body.disabled === true,
|
|
55
|
+
}
|
|
56
|
+
} catch {
|
|
57
|
+
return null
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function createSidecarStatusController(
|
|
62
|
+
fetchDetails: FetchSidecarInfo,
|
|
63
|
+
): SidecarStatusController {
|
|
64
|
+
const backoff = createBackoff()
|
|
65
|
+
const subscribers = new Set<(status: SidecarStatus) => void>()
|
|
66
|
+
let status: SidecarStatus = SIDECAR_STATUS_CONNECTING
|
|
67
|
+
let port: number | null = null
|
|
68
|
+
let clientToken: string | null = null
|
|
69
|
+
let pollTimer: ReturnType<typeof setTimeout> | null = null
|
|
70
|
+
let disposed = false
|
|
71
|
+
|
|
72
|
+
function notify(): void {
|
|
73
|
+
for (const cb of subscribers) cb(status)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function setStatus(next: SidecarStatus): void {
|
|
77
|
+
if (status === next) return
|
|
78
|
+
status = next
|
|
79
|
+
notify()
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function schedulePoll(): void {
|
|
83
|
+
if (disposed || pollTimer !== null) return
|
|
84
|
+
const delay = nextDelay(backoff, SIDECAR_POLL_DELAYS_MS)
|
|
85
|
+
pollTimer = setTimeout(() => {
|
|
86
|
+
pollTimer = null
|
|
87
|
+
void poll()
|
|
88
|
+
}, delay)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async function poll(): Promise<void> {
|
|
92
|
+
if (disposed) return
|
|
93
|
+
handleInfo(await fetchInfo(fetchDetails))
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function handleInfo(info: SidecarInfo | null): void {
|
|
97
|
+
if (disposed) return
|
|
98
|
+
// Probe itself failed (backend momentarily unreachable): keep waiting.
|
|
99
|
+
if (info === null) {
|
|
100
|
+
setStatus(SIDECAR_STATUS_REVIVING)
|
|
101
|
+
schedulePoll()
|
|
102
|
+
return
|
|
103
|
+
}
|
|
104
|
+
if (info.hasGivenUp) {
|
|
105
|
+
setStatus(SIDECAR_STATUS_UNAVAILABLE)
|
|
106
|
+
return
|
|
107
|
+
}
|
|
108
|
+
if (info.isRunning && info.port !== null && info.clientToken) {
|
|
109
|
+
port = info.port
|
|
110
|
+
clientToken = info.clientToken
|
|
111
|
+
resetBackoff(backoff)
|
|
112
|
+
// A reviving→connected transition notifies via setStatus; a port change
|
|
113
|
+
// while already connected leaves the status word unchanged, so force a
|
|
114
|
+
// notify there too to drive the overlay/WS onto the new port.
|
|
115
|
+
if (status === SIDECAR_STATUS_CONNECTED) notify()
|
|
116
|
+
else setStatus(SIDECAR_STATUS_CONNECTED)
|
|
117
|
+
return
|
|
118
|
+
}
|
|
119
|
+
// Down but not terminal — the probe already asked the backend to respawn;
|
|
120
|
+
// keep polling until it reports a port.
|
|
121
|
+
setStatus(SIDECAR_STATUS_REVIVING)
|
|
122
|
+
schedulePoll()
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return {
|
|
126
|
+
init: async (): Promise<boolean> => {
|
|
127
|
+
const info = await fetchInfo(fetchDetails)
|
|
128
|
+
if (info === null) return false
|
|
129
|
+
if (info.disabled) return false
|
|
130
|
+
handleInfo(info)
|
|
131
|
+
return true
|
|
132
|
+
},
|
|
133
|
+
getStatus: () => status,
|
|
134
|
+
getPort: () => port,
|
|
135
|
+
getClientToken: () => clientToken,
|
|
136
|
+
subscribe: (cb) => {
|
|
137
|
+
subscribers.add(cb)
|
|
138
|
+
cb(status)
|
|
139
|
+
return () => {
|
|
140
|
+
subscribers.delete(cb)
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
reportWsDown: () => {
|
|
144
|
+
if (disposed) return
|
|
145
|
+
if (status !== SIDECAR_STATUS_CONNECTED) return
|
|
146
|
+
// Surface the drop right away (amber dot + spinner) instead of waiting on
|
|
147
|
+
// the re-probe: that probe awaits a respawn and can take a second or two,
|
|
148
|
+
// during which the icon would otherwise look healthy. poll() flips back
|
|
149
|
+
// to connected once the new port is live.
|
|
150
|
+
resetBackoff(backoff)
|
|
151
|
+
setStatus(SIDECAR_STATUS_REVIVING)
|
|
152
|
+
void poll()
|
|
153
|
+
},
|
|
154
|
+
dispose: () => {
|
|
155
|
+
disposed = true
|
|
156
|
+
if (pollTimer !== null) {
|
|
157
|
+
clearTimeout(pollTimer)
|
|
158
|
+
pollTimer = null
|
|
159
|
+
}
|
|
160
|
+
subscribers.clear()
|
|
161
|
+
},
|
|
162
|
+
}
|
|
163
|
+
}
|