@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,109 @@
|
|
|
1
|
+
import { defineDmsPlugin, useDmsRouter } from '#dms-inertia/frontend-module'
|
|
2
|
+
import {
|
|
3
|
+
SIDECAR_HOST_NAME,
|
|
4
|
+
SIDECAR_INFO_PATH,
|
|
5
|
+
SIDECAR_PROBE_HOST,
|
|
6
|
+
SIDECAR_STATUS_CONNECTED,
|
|
7
|
+
SIDECAR_STATUS_REVIVING,
|
|
8
|
+
SIDECAR_STATUS_UNAVAILABLE,
|
|
9
|
+
WS_STATUS_CONNECTED,
|
|
10
|
+
WS_STATUS_CONNECTING,
|
|
11
|
+
} from '../runtime/constants'
|
|
12
|
+
import { installCurrentPageTracker } from '../runtime/current-page'
|
|
13
|
+
import { registerLauncherAction } from '../runtime/header-action'
|
|
14
|
+
import { createHostCommandDispatcher } from '../runtime/host-commands'
|
|
15
|
+
import { installNavigationCompleteEmitter } from '../runtime/navigation-complete'
|
|
16
|
+
import { injectOverlay } from '../runtime/overlay'
|
|
17
|
+
import { installToggleShortcut } from '../runtime/shortcuts'
|
|
18
|
+
import {
|
|
19
|
+
createSidecarStatusController,
|
|
20
|
+
type SidecarStatus,
|
|
21
|
+
} from '../runtime/sidecar-status'
|
|
22
|
+
import { createHostWsClient } from '../runtime/ws-client'
|
|
23
|
+
|
|
24
|
+
function buildIframeUrl(port: number, token: string): string {
|
|
25
|
+
// Seed the chatbox with the host's current light/dark mode so its very first
|
|
26
|
+
// paint matches; the theme bridge keeps it in sync from there on.
|
|
27
|
+
const mode = document.documentElement.classList.contains('dark')
|
|
28
|
+
? 'dark'
|
|
29
|
+
: 'light'
|
|
30
|
+
return `${SIDECAR_PROBE_HOST}:${port}/?theme=${mode}#token=${encodeURIComponent(token)}`
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export default defineDmsPlugin(async ({ vueApp }) => {
|
|
34
|
+
if (!import.meta.env.DEV) return
|
|
35
|
+
const { loggedIn } = useUserSession()
|
|
36
|
+
if (!loggedIn.value) return
|
|
37
|
+
const { $authFetch } = useAuthFetch()
|
|
38
|
+
const controller = createSidecarStatusController(() =>
|
|
39
|
+
$authFetch(SIDECAR_INFO_PATH),
|
|
40
|
+
)
|
|
41
|
+
// A null/disabled first probe means the assistant shouldn't appear at all —
|
|
42
|
+
// preserve the previous "no icon, no overlay" behavior in that case.
|
|
43
|
+
if (!(await controller.init())) return
|
|
44
|
+
const overlay = injectOverlay()
|
|
45
|
+
if (overlay === null) return
|
|
46
|
+
|
|
47
|
+
installToggleShortcut({ onToggle: () => overlay.toggleOpen() })
|
|
48
|
+
// Registered unconditionally (even while reviving) so the launcher is present
|
|
49
|
+
// through an outage; opening it surfaces the panel's own status placeholder.
|
|
50
|
+
registerLauncherAction(() => overlay.toggleFromLauncher())
|
|
51
|
+
|
|
52
|
+
const router = useDmsRouter()
|
|
53
|
+
// Host-side dev hot reload. A page the agent just wrote is re-registered
|
|
54
|
+
// asynchronously, so every overlay-driven navigation waits for the committed
|
|
55
|
+
// site layout to serve the route before pushing it.
|
|
56
|
+
const devReload = useDmsDevReload()
|
|
57
|
+
// Serialized so a burst of navigate commands cannot land out of order.
|
|
58
|
+
const dispatchHostCommand = createHostCommandDispatcher({ router, devReload })
|
|
59
|
+
const hostWs = createHostWsClient({
|
|
60
|
+
sidecarHost: SIDECAR_HOST_NAME,
|
|
61
|
+
getPort: () => controller.getPort(),
|
|
62
|
+
getClientToken: () => controller.getClientToken(),
|
|
63
|
+
onMessage: dispatchHostCommand,
|
|
64
|
+
onStatusChange: (status) => {
|
|
65
|
+
// A socket drop means the sidecar likely idle-exited/crashed: ask the
|
|
66
|
+
// controller to re-probe (relearning a possibly-new port) rather than let
|
|
67
|
+
// the socket keep retrying the dead one.
|
|
68
|
+
if (status !== WS_STATUS_CONNECTED && status !== WS_STATUS_CONNECTING) {
|
|
69
|
+
controller.reportWsDown()
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
let firstApply = true
|
|
75
|
+
const applyStatus = (status: SidecarStatus): void => {
|
|
76
|
+
if (status === SIDECAR_STATUS_CONNECTED) {
|
|
77
|
+
const port = controller.getPort()
|
|
78
|
+
const token = controller.getClientToken()
|
|
79
|
+
if (port !== null && token) overlay.repoint(buildIframeUrl(port, token))
|
|
80
|
+
// On the first apply the socket was just created and is connecting to the
|
|
81
|
+
// right port; only later connects (after a drop or port change) need a
|
|
82
|
+
// forced, backoff-skipping reconnect.
|
|
83
|
+
if (!firstApply) hostWs.reconnectNow()
|
|
84
|
+
} else if (status === SIDECAR_STATUS_REVIVING) {
|
|
85
|
+
overlay.showPlaceholder('reviving')
|
|
86
|
+
} else if (status === SIDECAR_STATUS_UNAVAILABLE) {
|
|
87
|
+
overlay.showPlaceholder('unavailable')
|
|
88
|
+
} else {
|
|
89
|
+
overlay.showPlaceholder('connecting')
|
|
90
|
+
}
|
|
91
|
+
firstApply = false
|
|
92
|
+
}
|
|
93
|
+
controller.subscribe(applyStatus)
|
|
94
|
+
|
|
95
|
+
const sendWhenConnected = (msg: unknown): void => {
|
|
96
|
+
if (!hostWs.isConnected()) return
|
|
97
|
+
hostWs.send(msg)
|
|
98
|
+
}
|
|
99
|
+
const stopTracking = installCurrentPageTracker({ send: sendWhenConnected })
|
|
100
|
+
const stopNavigation = installNavigationCompleteEmitter({
|
|
101
|
+
send: sendWhenConnected,
|
|
102
|
+
})
|
|
103
|
+
const stop = (): void => {
|
|
104
|
+
stopTracking()
|
|
105
|
+
stopNavigation()
|
|
106
|
+
}
|
|
107
|
+
vueApp.onUnmount(stop)
|
|
108
|
+
import.meta.hot?.dispose(stop)
|
|
109
|
+
})
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export interface BackoffState {
|
|
2
|
+
index: number
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export function createBackoff(): BackoffState {
|
|
6
|
+
return { index: 0 }
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function readScheduleAt(
|
|
10
|
+
schedule: readonly number[],
|
|
11
|
+
index: number,
|
|
12
|
+
): number {
|
|
13
|
+
const value = schedule[index]
|
|
14
|
+
if (value === undefined) return 0
|
|
15
|
+
return value
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function nextDelay(
|
|
19
|
+
state: BackoffState,
|
|
20
|
+
schedule: readonly number[],
|
|
21
|
+
): number {
|
|
22
|
+
const cappedIndex = Math.min(state.index, schedule.length - 1)
|
|
23
|
+
const delay = readScheduleAt(schedule, cappedIndex)
|
|
24
|
+
state.index += 1
|
|
25
|
+
return delay
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function resetBackoff(state: BackoffState): void {
|
|
29
|
+
state.index = 0
|
|
30
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
export const OVERLAY_DEFAULT_WIDTH_PX = 460
|
|
2
|
+
export const OVERLAY_Z_INDEX = 999_999
|
|
3
|
+
export const OVERLAY_DOM_ID = 'dms-ai-overlay-root'
|
|
4
|
+
export const OVERLAY_IFRAME_ID = 'dms-ai-overlay-iframe'
|
|
5
|
+
export const SIDECAR_INFO_PATH = '/ai/sidecar-info'
|
|
6
|
+
export const SIDECAR_PROBE_PORT = 5010
|
|
7
|
+
export const SIDECAR_PROBE_HOST = 'http://localhost'
|
|
8
|
+
export const OVERLAY_BOX_SHADOW = '0 8px 24px rgba(0, 0, 0, 0.18)'
|
|
9
|
+
export const SIDECAR_HOST_NAME = 'localhost'
|
|
10
|
+
export const WS_HOST_PATH = '/ws/host'
|
|
11
|
+
export const WS_RECONNECT_DELAYS_MS = [
|
|
12
|
+
1000, 2000, 4000, 8000, 15000, 30000,
|
|
13
|
+
] as const
|
|
14
|
+
// Sidecar reachability, as seen by the host. `reviving` is the self-healing
|
|
15
|
+
// state (idle-exited / crashed-respawning): the probe loop is relearning the new
|
|
16
|
+
// random port and will repoint the frame. `unavailable` is terminal (the crash
|
|
17
|
+
// budget is spent) and needs a reload.
|
|
18
|
+
export const SIDECAR_STATUS_CONNECTING = 'connecting'
|
|
19
|
+
export const SIDECAR_STATUS_CONNECTED = 'connected'
|
|
20
|
+
export const SIDECAR_STATUS_REVIVING = 'reviving'
|
|
21
|
+
export const SIDECAR_STATUS_UNAVAILABLE = 'unavailable'
|
|
22
|
+
// Re-probe cadence while reviving. Each probe also revives the daemon backend
|
|
23
|
+
// side, so this doubles as the respawn heartbeat; capped so a genuinely stuck
|
|
24
|
+
// sidecar is polled sparingly rather than hammered.
|
|
25
|
+
export const SIDECAR_POLL_DELAYS_MS = [
|
|
26
|
+
500, 1000, 2000, 4000, 8000,
|
|
27
|
+
] as const
|
|
28
|
+
export const OVERLAY_PLACEHOLDER_ID = 'dms-ai-overlay-placeholder'
|
|
29
|
+
export const PLACEHOLDER_CONNECTING_TEXT = 'Connecting the assistant…'
|
|
30
|
+
export const PLACEHOLDER_REVIVING_TEXT = 'Reconnecting the assistant…'
|
|
31
|
+
export const PLACEHOLDER_UNAVAILABLE_TITLE = 'Assistant unavailable'
|
|
32
|
+
export const PLACEHOLDER_UNAVAILABLE_TEXT = 'Reload the page to try again.'
|
|
33
|
+
|
|
34
|
+
export const WS_STATUS_CONNECTING = 'connecting'
|
|
35
|
+
export const WS_STATUS_CONNECTED = 'connected'
|
|
36
|
+
export const WS_STATUS_DISCONNECTED = 'disconnected'
|
|
37
|
+
export const WS_STATUS_RECONNECTING = 'reconnecting'
|
|
38
|
+
export const WS_PROTOCOL_SECURE = 'wss:'
|
|
39
|
+
export const WS_PROTOCOL_INSECURE = 'ws:'
|
|
40
|
+
export const PAGE_PROTOCOL_SECURE = 'https:'
|
|
41
|
+
export const HOST_ROLE = 'host'
|
|
42
|
+
export const HELLO_MESSAGE_TYPE = 'hello'
|
|
43
|
+
export const LOG_PREFIX = '[dms-ai]'
|
|
44
|
+
export const HOST_STATE_UPDATE_TYPE = 'host_state_update'
|
|
45
|
+
export const HOST_NAVIGATION_COMPLETE_TYPE = 'host_navigation_complete'
|
|
46
|
+
export const HOST_COMMAND_NAVIGATE_TYPE = 'host_command_navigate'
|
|
47
|
+
export const OVERLAY_RESIZE_HANDLE_SIZE_PX = 6
|
|
48
|
+
export const OVERLAY_MIN_WIDTH_PX = 320
|
|
49
|
+
export const OVERLAY_PREFS_STORAGE_KEY = 'dms-ai:overlay-prefs'
|
|
50
|
+
export const OVERLAY_OUTSIDE_TOGGLE_SUPPRESS_MS = 300
|
|
51
|
+
export const OVERLAY_PREFS_DEBOUNCE_MS = 300
|
|
52
|
+
export const TOGGLE_SHORTCUT_KEY = 'k'
|
|
53
|
+
export const MODAL_OPEN_SELECTOR = '[role="dialog"][aria-modal="true"]'
|
|
54
|
+
|
|
55
|
+
// Generic header-action registry exposed by the DMS core (dms-back). Any module
|
|
56
|
+
// can push a button by writing to this shared Nuxt state key; the core renders
|
|
57
|
+
// it with no knowledge of who registered it.
|
|
58
|
+
export const HEADER_ACTIONS_STATE_KEY = 'dms:header-actions'
|
|
59
|
+
export const LAUNCHER_ACTION_ID = 'dms-ai-launcher'
|
|
60
|
+
export const LAUNCHER_ICON = 'i-ph-robot'
|
|
61
|
+
export const LAUNCHER_LABEL = 'AI assistant'
|
|
62
|
+
export const LAUNCHER_ORDER = 50
|
|
63
|
+
// Toggle shortcut, shown in the launcher tooltip. The combo is meta/ctrl + shift
|
|
64
|
+
// + k, so render it the way each platform expects.
|
|
65
|
+
export const TOGGLE_SHORTCUT_LABEL_MAC = '⌘⇧K'
|
|
66
|
+
export const TOGGLE_SHORTCUT_LABEL_OTHER = 'Ctrl+Shift+K'
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { router } from '@inertiajs/vue3'
|
|
2
|
+
import { HOST_STATE_UPDATE_TYPE } from './constants'
|
|
3
|
+
|
|
4
|
+
interface CurrentPagePayload {
|
|
5
|
+
path: string
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
interface HostStateUpdateMessage {
|
|
9
|
+
type: typeof HOST_STATE_UPDATE_TYPE
|
|
10
|
+
currentPage: CurrentPagePayload
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface InstallCurrentPageTrackerOptions {
|
|
14
|
+
send: (msg: HostStateUpdateMessage) => void
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function installCurrentPageTracker(
|
|
18
|
+
options: InstallCurrentPageTrackerOptions,
|
|
19
|
+
): () => void {
|
|
20
|
+
const pushFor = (url: string): void =>
|
|
21
|
+
options.send({
|
|
22
|
+
type: HOST_STATE_UPDATE_TYPE,
|
|
23
|
+
currentPage: { path: new URL(url, window.location.origin).pathname },
|
|
24
|
+
})
|
|
25
|
+
const stop = router.on('navigate', (event) => pushFor(event.detail.page.url))
|
|
26
|
+
pushFor(window.location.href)
|
|
27
|
+
return stop
|
|
28
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { useDmsState as useState } from '#dms-inertia/frontend-module'
|
|
2
|
+
import {
|
|
3
|
+
HEADER_ACTIONS_STATE_KEY,
|
|
4
|
+
LAUNCHER_ACTION_ID,
|
|
5
|
+
LAUNCHER_ICON,
|
|
6
|
+
LAUNCHER_LABEL,
|
|
7
|
+
LAUNCHER_ORDER,
|
|
8
|
+
TOGGLE_SHORTCUT_LABEL_MAC,
|
|
9
|
+
TOGGLE_SHORTCUT_LABEL_OTHER,
|
|
10
|
+
} from './constants'
|
|
11
|
+
|
|
12
|
+
interface UserAgentData {
|
|
13
|
+
platform?: string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface NavigatorUserAgentData {
|
|
17
|
+
userAgentData?: UserAgentData
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// The shortcut combo accepts meta OR ctrl, so show the modifier each platform
|
|
21
|
+
// actually uses (⌘ on Apple, Ctrl elsewhere).
|
|
22
|
+
function isApplePlatform(): boolean {
|
|
23
|
+
const nav = globalThis.navigator as
|
|
24
|
+
| (Navigator & NavigatorUserAgentData)
|
|
25
|
+
| undefined
|
|
26
|
+
if (nav === undefined) return false
|
|
27
|
+
const platform = nav.userAgentData?.platform ?? nav.platform ?? ''
|
|
28
|
+
return /mac|iphone|ipad|ipod/i.test(platform)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function launcherLabel(): string {
|
|
32
|
+
const shortcut = isApplePlatform()
|
|
33
|
+
? TOGGLE_SHORTCUT_LABEL_MAC
|
|
34
|
+
: TOGGLE_SHORTCUT_LABEL_OTHER
|
|
35
|
+
return `${LAUNCHER_LABEL} (${shortcut})`
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Our view of the shared header-action shape the DMS core renders. Declared
|
|
39
|
+
// locally so this layer has no build-time dependency on the core layer; the
|
|
40
|
+
// only contract is the state key and these fields.
|
|
41
|
+
interface HeaderAction {
|
|
42
|
+
id: string
|
|
43
|
+
icon: string
|
|
44
|
+
label: string
|
|
45
|
+
onSelect: () => void
|
|
46
|
+
order?: number
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Register the assistant launcher in the core's generic header-action registry.
|
|
50
|
+
// Idempotent so a re-running plugin can't add a duplicate button.
|
|
51
|
+
export function registerLauncherAction(onSelect: () => void): void {
|
|
52
|
+
const actions = useState<HeaderAction[]>(HEADER_ACTIONS_STATE_KEY, () => [])
|
|
53
|
+
if (actions.value.some((action) => action.id === LAUNCHER_ACTION_ID)) return
|
|
54
|
+
actions.value = [
|
|
55
|
+
...actions.value,
|
|
56
|
+
{
|
|
57
|
+
id: LAUNCHER_ACTION_ID,
|
|
58
|
+
icon: LAUNCHER_ICON,
|
|
59
|
+
label: launcherLabel(),
|
|
60
|
+
order: LAUNCHER_ORDER,
|
|
61
|
+
onSelect,
|
|
62
|
+
},
|
|
63
|
+
]
|
|
64
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { HOST_COMMAND_NAVIGATE_TYPE, LOG_PREFIX } from './constants'
|
|
2
|
+
|
|
3
|
+
interface RouterLike {
|
|
4
|
+
push: (path: string) => unknown
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The slice of the host's `useDmsDevReload()` composable this module needs:
|
|
9
|
+
* resolve `true` once the committed site layout serves `path`, `false` on
|
|
10
|
+
* timeout.
|
|
11
|
+
*/
|
|
12
|
+
export interface DevReloadWaiter {
|
|
13
|
+
awaitRoute: (path: string) => Promise<boolean>
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface HostCommandContext {
|
|
17
|
+
router: RouterLike
|
|
18
|
+
devReload: DevReloadWaiter
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface HostCommandNavigateMessage {
|
|
22
|
+
type: typeof HOST_COMMAND_NAVIGATE_TYPE
|
|
23
|
+
path: string
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export type HostCommandMessage = HostCommandNavigateMessage
|
|
27
|
+
|
|
28
|
+
export type HostCommandDispatcher = (raw: unknown) => void
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Commands run one at a time on `tail`. `nextPath` holds the newest navigation
|
|
32
|
+
* target still waiting for a slot, so a burst collapses into a single trip to
|
|
33
|
+
* the latest path instead of racing and landing on the oldest one.
|
|
34
|
+
*/
|
|
35
|
+
interface DispatcherState {
|
|
36
|
+
ctx: HostCommandContext
|
|
37
|
+
tail: Promise<void>
|
|
38
|
+
nextPath: string | null
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
type HostCommandHandler = (
|
|
42
|
+
msg: HostCommandMessage,
|
|
43
|
+
state: DispatcherState,
|
|
44
|
+
) => void
|
|
45
|
+
|
|
46
|
+
function enqueue(state: DispatcherState, job: () => Promise<void>): void {
|
|
47
|
+
state.tail = state.tail.then(job).catch((err: unknown) => {
|
|
48
|
+
console.error(`${LOG_PREFIX} host command failed`, err)
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// The agent asks to navigate right after writing the page, while the host is
|
|
53
|
+
// still re-registering modules: the route can be momentarily unserved and
|
|
54
|
+
// pushing now would flash a 404. Wait for the committed layout to serve it.
|
|
55
|
+
// Navigate whatever the wait reports — a lapsed deadline or a broken waiter
|
|
56
|
+
// must not strand the user on the previous page; a genuinely missing page then
|
|
57
|
+
// 404s as it did before.
|
|
58
|
+
async function awaitRouteThenPush(
|
|
59
|
+
path: string,
|
|
60
|
+
ctx: HostCommandContext,
|
|
61
|
+
): Promise<void> {
|
|
62
|
+
try {
|
|
63
|
+
await ctx.devReload.awaitRoute(path)
|
|
64
|
+
} catch (err: unknown) {
|
|
65
|
+
console.error(`${LOG_PREFIX} dev reload wait failed for ${path}`, err)
|
|
66
|
+
}
|
|
67
|
+
void ctx.router.push(path)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function runNavigate(state: DispatcherState): Promise<void> {
|
|
71
|
+
const path = state.nextPath
|
|
72
|
+
// A newer navigate already claimed this slot's target: this one is superseded
|
|
73
|
+
// and must not drag the user back to the older path.
|
|
74
|
+
if (path === null) return
|
|
75
|
+
state.nextPath = null
|
|
76
|
+
await awaitRouteThenPush(path, state.ctx)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function handleNavigate(
|
|
80
|
+
msg: HostCommandMessage,
|
|
81
|
+
state: DispatcherState,
|
|
82
|
+
): void {
|
|
83
|
+
if (msg.type !== HOST_COMMAND_NAVIGATE_TYPE) return
|
|
84
|
+
state.nextPath = msg.path
|
|
85
|
+
enqueue(state, () => runNavigate(state))
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const COMMAND_HANDLERS: Record<string, HostCommandHandler> = {
|
|
89
|
+
[HOST_COMMAND_NAVIGATE_TYPE]: handleNavigate,
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function isHostCommand(value: unknown): value is HostCommandMessage {
|
|
93
|
+
if (value === null || typeof value !== 'object') return false
|
|
94
|
+
const candidate = value as { type?: unknown }
|
|
95
|
+
return typeof candidate.type === 'string'
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function parseRaw(raw: unknown): HostCommandMessage | null {
|
|
99
|
+
if (typeof raw !== 'string') return null
|
|
100
|
+
try {
|
|
101
|
+
const parsed = JSON.parse(raw) as unknown
|
|
102
|
+
if (!isHostCommand(parsed)) return null
|
|
103
|
+
return parsed
|
|
104
|
+
} catch {
|
|
105
|
+
return null
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function createHostCommandDispatcher(
|
|
110
|
+
ctx: HostCommandContext,
|
|
111
|
+
): HostCommandDispatcher {
|
|
112
|
+
const state: DispatcherState = {
|
|
113
|
+
ctx,
|
|
114
|
+
tail: Promise.resolve(),
|
|
115
|
+
nextPath: null,
|
|
116
|
+
}
|
|
117
|
+
return (raw: unknown): void => {
|
|
118
|
+
const msg = parseRaw(raw)
|
|
119
|
+
if (msg === null) return
|
|
120
|
+
const handler = COMMAND_HANDLERS[msg.type]
|
|
121
|
+
if (handler === undefined) {
|
|
122
|
+
console.warn(`${LOG_PREFIX} unknown host command type=${msg.type}`)
|
|
123
|
+
return
|
|
124
|
+
}
|
|
125
|
+
handler(msg, state)
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { router } from '@inertiajs/vue3'
|
|
2
|
+
import { HOST_NAVIGATION_COMPLETE_TYPE } from './constants'
|
|
3
|
+
|
|
4
|
+
export interface HostNavigationCompleteMessage {
|
|
5
|
+
type: typeof HOST_NAVIGATION_COMPLETE_TYPE
|
|
6
|
+
path: string
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
interface InstallNavigationCompleteEmitterOptions {
|
|
10
|
+
send: (msg: HostNavigationCompleteMessage) => void
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function installNavigationCompleteEmitter(
|
|
14
|
+
options: InstallNavigationCompleteEmitterOptions,
|
|
15
|
+
): () => void {
|
|
16
|
+
return router.on('navigate', (event) =>
|
|
17
|
+
options.send({
|
|
18
|
+
type: HOST_NAVIGATION_COMPLETE_TYPE,
|
|
19
|
+
path: new URL(event.detail.page.url, window.location.origin).pathname,
|
|
20
|
+
}),
|
|
21
|
+
)
|
|
22
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import {
|
|
2
|
+
OVERLAY_PREFS_DEBOUNCE_MS,
|
|
3
|
+
OVERLAY_PREFS_STORAGE_KEY,
|
|
4
|
+
} from './constants'
|
|
5
|
+
|
|
6
|
+
export interface OverlayPrefs {
|
|
7
|
+
width: number
|
|
8
|
+
isOpen: boolean
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
let pendingTimer: ReturnType<typeof setTimeout> | null = null
|
|
12
|
+
let pendingPrefs: OverlayPrefs | null = null
|
|
13
|
+
|
|
14
|
+
function tryReadStorage(): string | null {
|
|
15
|
+
try {
|
|
16
|
+
return globalThis.localStorage.getItem(OVERLAY_PREFS_STORAGE_KEY)
|
|
17
|
+
} catch {
|
|
18
|
+
return null
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function tryWriteStorage(payload: string): void {
|
|
23
|
+
try {
|
|
24
|
+
globalThis.localStorage.setItem(OVERLAY_PREFS_STORAGE_KEY, payload)
|
|
25
|
+
} catch {
|
|
26
|
+
return
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function isFiniteNumber(value: unknown): value is number {
|
|
31
|
+
return typeof value === 'number' && Number.isFinite(value)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function isValidPrefs(value: unknown): value is OverlayPrefs {
|
|
35
|
+
if (value === null || typeof value !== 'object') return false
|
|
36
|
+
const candidate = value as Record<string, unknown>
|
|
37
|
+
if (!isFiniteNumber(candidate.width)) return false
|
|
38
|
+
if (typeof candidate.isOpen !== 'boolean') return false
|
|
39
|
+
return true
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function parsePrefs(raw: string): OverlayPrefs | null {
|
|
43
|
+
try {
|
|
44
|
+
const parsed: unknown = JSON.parse(raw)
|
|
45
|
+
return isValidPrefs(parsed) ? parsed : null
|
|
46
|
+
} catch {
|
|
47
|
+
return null
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function readPrefs(): OverlayPrefs | null {
|
|
52
|
+
const raw = tryReadStorage()
|
|
53
|
+
if (raw === null) return null
|
|
54
|
+
return parsePrefs(raw)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function flushPending(): void {
|
|
58
|
+
if (pendingPrefs === null) return
|
|
59
|
+
tryWriteStorage(JSON.stringify(pendingPrefs))
|
|
60
|
+
pendingPrefs = null
|
|
61
|
+
pendingTimer = null
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function writePrefsDebounced(prefs: OverlayPrefs): void {
|
|
65
|
+
pendingPrefs = prefs
|
|
66
|
+
if (pendingTimer !== null) clearTimeout(pendingTimer)
|
|
67
|
+
pendingTimer = setTimeout(flushPending, OVERLAY_PREFS_DEBOUNCE_MS)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function flushPrefsForTesting(): void {
|
|
71
|
+
if (pendingTimer !== null) {
|
|
72
|
+
clearTimeout(pendingTimer)
|
|
73
|
+
pendingTimer = null
|
|
74
|
+
}
|
|
75
|
+
flushPending()
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function resetPrefsForTesting(): void {
|
|
79
|
+
if (pendingTimer !== null) {
|
|
80
|
+
clearTimeout(pendingTimer)
|
|
81
|
+
pendingTimer = null
|
|
82
|
+
}
|
|
83
|
+
pendingPrefs = null
|
|
84
|
+
try {
|
|
85
|
+
globalThis.localStorage.removeItem(OVERLAY_PREFS_STORAGE_KEY)
|
|
86
|
+
} catch {
|
|
87
|
+
return
|
|
88
|
+
}
|
|
89
|
+
}
|