@antelopejs/dms-ai 0.1.3 → 0.1.5

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.
Files changed (245) hide show
  1. package/README.md +48 -29
  2. package/dist/channels/bridge.d.ts +2 -8
  3. package/dist/channels/bridge.js +26 -42
  4. package/dist/channels/bridge.js.map +1 -1
  5. package/dist/channels/channel-service.d.ts +2 -2
  6. package/dist/channels/channel-service.js +12 -31
  7. package/dist/channels/channel-service.js.map +1 -1
  8. package/dist/channels/registry.d.ts +2 -2
  9. package/dist/channels/registry.js +7 -7
  10. package/dist/channels/registry.js.map +1 -1
  11. package/dist/config.d.ts +1 -0
  12. package/dist/config.js +8 -1
  13. package/dist/config.js.map +1 -1
  14. package/dist/constants/channels.d.ts +5 -10
  15. package/dist/constants/channels.js +6 -10
  16. package/dist/constants/channels.js.map +1 -1
  17. package/dist/constants/sidecar.d.ts +2 -1
  18. package/dist/constants/sidecar.js +3 -2
  19. package/dist/constants/sidecar.js.map +1 -1
  20. package/dist/index.js +8 -0
  21. package/dist/index.js.map +1 -1
  22. package/dist/lifecycle/build-id.d.ts +1 -0
  23. package/dist/lifecycle/build-id.js +32 -0
  24. package/dist/lifecycle/build-id.js.map +1 -0
  25. package/dist/lifecycle/sidecar-socket.d.ts +1 -1
  26. package/dist/lifecycle/sidecar-socket.js +2 -2
  27. package/dist/lifecycle/sidecar-socket.js.map +1 -1
  28. package/dist/lifecycle/spawn-sidecar.d.ts +0 -1
  29. package/dist/lifecycle/spawn-sidecar.js +5 -27
  30. package/dist/lifecycle/spawn-sidecar.js.map +1 -1
  31. package/dist/pages/settings/page.js.map +1 -1
  32. package/dist/routes/channels.d.ts +3 -3
  33. package/dist/routes/channels.js +11 -12
  34. package/dist/routes/channels.js.map +1 -1
  35. package/dist/routes/index.d.ts +0 -1
  36. package/dist/routes/index.js +0 -1
  37. package/dist/routes/index.js.map +1 -1
  38. package/frontend-vue/.prettierignore +3 -0
  39. package/frontend-vue/.prettierrc +10 -0
  40. package/frontend-vue/app/chat/components/ChatView.vue +582 -0
  41. package/frontend-vue/app/chat/components/ComposerInput.vue +742 -0
  42. package/frontend-vue/app/chat/components/ConnectionBanner.vue +105 -0
  43. package/frontend-vue/app/chat/components/ConversationDrawer.vue +266 -0
  44. package/frontend-vue/app/chat/components/MarkdownContent.vue +196 -0
  45. package/frontend-vue/app/chat/components/MessageList.vue +474 -0
  46. package/frontend-vue/app/chat/components/PermissionRequests.vue +323 -0
  47. package/frontend-vue/app/chat/components/QuestionPrompt.vue +275 -0
  48. package/frontend-vue/app/chat/components/QueuedMessages.vue +109 -0
  49. package/frontend-vue/app/chat/components/TodoList.vue +291 -0
  50. package/frontend-vue/app/chat/components/ToolCallEntry.vue +218 -0
  51. package/frontend-vue/app/chat/components/ToolCluster.vue +282 -0
  52. package/frontend-vue/app/chat/composables/useChatChannel.ts +116 -0
  53. package/frontend-vue/app/chat/composables/useConversation.ts +838 -0
  54. package/frontend-vue/app/chat/composables/useConversationId.ts +34 -0
  55. package/frontend-vue/app/chat/composables/useConversationList.ts +56 -0
  56. package/frontend-vue/app/chat/composables/usePermissionQueue.ts +59 -0
  57. package/frontend-vue/app/chat/composables/useQuestionQueue.ts +50 -0
  58. package/frontend-vue/app/chat/composables/useRunClock.ts +28 -0
  59. package/frontend-vue/app/chat/composables/useSettings.ts +67 -0
  60. package/frontend-vue/app/chat/constants/attachments.ts +16 -0
  61. package/frontend-vue/app/chat/constants/connection-banner.ts +7 -0
  62. package/frontend-vue/app/chat/constants/conversation-drawer.ts +13 -0
  63. package/frontend-vue/app/chat/constants/conversation.ts +75 -0
  64. package/frontend-vue/app/chat/constants/permissions.ts +50 -0
  65. package/frontend-vue/app/chat/constants/protocol.ts +48 -0
  66. package/frontend-vue/app/chat/constants/run-status.ts +50 -0
  67. package/frontend-vue/app/chat/constants/settings.ts +60 -0
  68. package/frontend-vue/app/chat/types/conversation.ts +87 -0
  69. package/frontend-vue/app/chat/types/permission.ts +7 -0
  70. package/frontend-vue/app/chat/types/question.ts +17 -0
  71. package/frontend-vue/app/chat/types/settings.ts +27 -0
  72. package/frontend-vue/app/chat/utils/attachments.ts +62 -0
  73. package/frontend-vue/app/chat/utils/format.ts +14 -0
  74. package/frontend-vue/app/chat/utils/ids.ts +34 -0
  75. package/frontend-vue/app/chat/utils/markdown.ts +188 -0
  76. package/frontend-vue/app/chat/utils/run-status.ts +90 -0
  77. package/frontend-vue/app/chat/utils/todos.ts +64 -0
  78. package/frontend-vue/app/chat/utils/tool-summary.ts +53 -0
  79. package/frontend-vue/app/components/ActivityView.vue +34 -34
  80. package/frontend-vue/app/components/ChatPanel.vue +276 -0
  81. package/frontend-vue/app/components/SettingsView.vue +127 -130
  82. package/frontend-vue/app/components/SkillsView.vue +55 -53
  83. package/frontend-vue/app/plugins/ai.client.ts +145 -129
  84. package/frontend-vue/app/runtime/assistant-session.ts +21 -0
  85. package/frontend-vue/app/runtime/backoff.ts +11 -14
  86. package/frontend-vue/app/runtime/channel-client.ts +130 -141
  87. package/frontend-vue/app/runtime/chat-transport.ts +25 -55
  88. package/frontend-vue/app/runtime/constants.ts +70 -60
  89. package/frontend-vue/app/runtime/current-page.ts +49 -15
  90. package/frontend-vue/app/runtime/event-stream.ts +35 -35
  91. package/frontend-vue/app/runtime/frame-router.ts +30 -0
  92. package/frontend-vue/app/runtime/header-action.ts +18 -18
  93. package/frontend-vue/app/runtime/host-commands.ts +57 -56
  94. package/frontend-vue/app/runtime/listeners.ts +31 -0
  95. package/frontend-vue/app/runtime/navigation-complete.ts +7 -7
  96. package/frontend-vue/app/runtime/overlay-prefs.ts +36 -36
  97. package/frontend-vue/app/runtime/panel-state.ts +88 -0
  98. package/frontend-vue/app/runtime/session-gate.ts +8 -8
  99. package/frontend-vue/app/runtime/shortcuts.ts +12 -12
  100. package/frontend-vue/app/runtime/sidecar-status.ts +61 -61
  101. package/frontend-vue/app/runtime/typed-message.ts +11 -0
  102. package/frontend-vue/dms.frontend.ts +12 -12
  103. package/frontend-vue/eslint.config.mjs +13 -13
  104. package/frontend-vue/package.json +11 -4
  105. package/frontend-vue/pnpm-lock.yaml +298 -96
  106. package/frontend-vue/tests/backoff.test.ts +26 -30
  107. package/frontend-vue/tests/channel-client.test.ts +187 -188
  108. package/frontend-vue/tests/chat/markdown.test.ts +271 -0
  109. package/frontend-vue/tests/chat/useChatChannel.test.ts +124 -0
  110. package/frontend-vue/tests/chat/useConversation.test.ts +283 -0
  111. package/frontend-vue/tests/chat-panel.test.ts +354 -0
  112. package/frontend-vue/tests/chat-transport.test.ts +84 -57
  113. package/frontend-vue/tests/host-commands.test.ts +126 -87
  114. package/frontend-vue/tests/navigation.test.ts +65 -34
  115. package/frontend-vue/tests/overlay-prefs.test.ts +49 -49
  116. package/frontend-vue/tests/panel-state.test.ts +58 -0
  117. package/frontend-vue/tests/session-gate.test.ts +33 -33
  118. package/frontend-vue/tests/sidecar-guest.test.ts +46 -46
  119. package/frontend-vue/tests/sidecar-status.test.ts +29 -29
  120. package/frontend-vue/tsconfig.chat.json +16 -0
  121. package/frontend-vue/vitest.config.ts +6 -4
  122. package/package.json +5 -5
  123. package/sidecar/dist/agent/effective-mode.d.ts +2 -2
  124. package/sidecar/dist/agent/effective-mode.js +1 -1
  125. package/sidecar/dist/agent/effective-mode.js.map +1 -1
  126. package/sidecar/dist/agent/host-context.js +7 -9
  127. package/sidecar/dist/agent/host-context.js.map +1 -1
  128. package/sidecar/dist/agent/permission-bus.d.ts +1 -1
  129. package/sidecar/dist/agent/permission-bus.js +2 -2
  130. package/sidecar/dist/agent/permission-bus.js.map +1 -1
  131. package/sidecar/dist/agent/provider.d.ts +2 -2
  132. package/sidecar/dist/agent/question-bus.d.ts +1 -1
  133. package/sidecar/dist/agent/question-bus.js +2 -2
  134. package/sidecar/dist/agent/question-bus.js.map +1 -1
  135. package/sidecar/dist/agent/runner.d.ts +2 -2
  136. package/sidecar/dist/agent/runner.js +24 -8
  137. package/sidecar/dist/agent/runner.js.map +1 -1
  138. package/sidecar/dist/agent/session.d.ts +2 -2
  139. package/sidecar/dist/agent/session.js +49 -9
  140. package/sidecar/dist/agent/session.js.map +1 -1
  141. package/sidecar/dist/agent/switching-runner.js +10 -5
  142. package/sidecar/dist/agent/switching-runner.js.map +1 -1
  143. package/sidecar/dist/agent/turn-end-reasons.d.ts +2 -0
  144. package/sidecar/dist/agent/turn-end-reasons.js +6 -1
  145. package/sidecar/dist/agent/turn-end-reasons.js.map +1 -1
  146. package/sidecar/dist/constants/agent.d.ts +4 -1
  147. package/sidecar/dist/constants/agent.js +4 -1
  148. package/sidecar/dist/constants/agent.js.map +1 -1
  149. package/sidecar/dist/constants/cli.d.ts +0 -1
  150. package/sidecar/dist/constants/cli.js +0 -1
  151. package/sidecar/dist/constants/cli.js.map +1 -1
  152. package/sidecar/dist/constants/codex.d.ts +5 -2
  153. package/sidecar/dist/constants/codex.js +5 -2
  154. package/sidecar/dist/constants/codex.js.map +1 -1
  155. package/sidecar/dist/constants/http.d.ts +0 -9
  156. package/sidecar/dist/constants/http.js +0 -19
  157. package/sidecar/dist/constants/http.js.map +1 -1
  158. package/sidecar/dist/constants/mcp.d.ts +1 -1
  159. package/sidecar/dist/constants/mcp.js +1 -1
  160. package/sidecar/dist/constants/mcp.js.map +1 -1
  161. package/sidecar/dist/constants/paths.d.ts +0 -1
  162. package/sidecar/dist/constants/paths.js +0 -1
  163. package/sidecar/dist/constants/paths.js.map +1 -1
  164. package/sidecar/dist/constants/ws.d.ts +3 -4
  165. package/sidecar/dist/constants/ws.js +3 -4
  166. package/sidecar/dist/constants/ws.js.map +1 -1
  167. package/sidecar/dist/index.d.ts +0 -1
  168. package/sidecar/dist/index.js +6 -10
  169. package/sidecar/dist/index.js.map +1 -1
  170. package/sidecar/dist/mcp/tools/find-pages-using.js +5 -10
  171. package/sidecar/dist/mcp/tools/find-pages-using.js.map +1 -1
  172. package/sidecar/dist/mcp/types.d.ts +1 -1
  173. package/sidecar/dist/pages/page-filepath.d.ts +4 -0
  174. package/sidecar/dist/pages/page-filepath.js +28 -0
  175. package/sidecar/dist/pages/page-filepath.js.map +1 -0
  176. package/sidecar/dist/prompts/agent.d.ts +1 -1
  177. package/sidecar/dist/prompts/agent.js +1 -1
  178. package/sidecar/dist/prompts/agent.js.map +1 -1
  179. package/sidecar/dist/protocol/events.js +2 -2
  180. package/sidecar/dist/protocol/events.js.map +1 -1
  181. package/sidecar/dist/protocol/messages.d.ts +4 -15
  182. package/sidecar/dist/protocol/messages.js +4 -11
  183. package/sidecar/dist/protocol/messages.js.map +1 -1
  184. package/sidecar/dist/providers/claude/config.d.ts +2 -2
  185. package/sidecar/dist/providers/claude/config.js +2 -2
  186. package/sidecar/dist/providers/claude/config.js.map +1 -1
  187. package/sidecar/dist/providers/claude/provider.js +1 -1
  188. package/sidecar/dist/providers/claude/provider.js.map +1 -1
  189. package/sidecar/dist/providers/codex/config.d.ts +3 -2
  190. package/sidecar/dist/providers/codex/config.js +3 -3
  191. package/sidecar/dist/providers/codex/config.js.map +1 -1
  192. package/sidecar/dist/providers/codex/process.js +107 -74
  193. package/sidecar/dist/providers/codex/process.js.map +1 -1
  194. package/sidecar/dist/providers/codex/provider.js +68 -31
  195. package/sidecar/dist/providers/codex/provider.js.map +1 -1
  196. package/sidecar/dist/providers/codex/skills.d.ts +1 -0
  197. package/sidecar/dist/providers/codex/skills.js +4 -1
  198. package/sidecar/dist/providers/codex/skills.js.map +1 -1
  199. package/sidecar/dist/providers/codex/stop.d.ts +4 -0
  200. package/sidecar/dist/providers/codex/stop.js +71 -0
  201. package/sidecar/dist/providers/codex/stop.js.map +1 -0
  202. package/sidecar/dist/server/{iframe-socket-registry.d.ts → chat-socket-registry.d.ts} +3 -2
  203. package/sidecar/dist/server/{iframe-socket-registry.js → chat-socket-registry.js} +4 -3
  204. package/sidecar/dist/server/chat-socket-registry.js.map +1 -0
  205. package/sidecar/dist/server/client-auth.js +2 -14
  206. package/sidecar/dist/server/client-auth.js.map +1 -1
  207. package/sidecar/dist/server/host-command-router.d.ts +5 -0
  208. package/sidecar/dist/server/host-command-router.js +4 -0
  209. package/sidecar/dist/server/host-command-router.js.map +1 -0
  210. package/sidecar/dist/server/host-socket-registry.d.ts +1 -1
  211. package/sidecar/dist/server/host-socket-registry.js +16 -13
  212. package/sidecar/dist/server/host-socket-registry.js.map +1 -1
  213. package/sidecar/dist/server/http.d.ts +0 -1
  214. package/sidecar/dist/server/http.js +1 -44
  215. package/sidecar/dist/server/http.js.map +1 -1
  216. package/sidecar/dist/server/routing.d.ts +5 -6
  217. package/sidecar/dist/server/routing.js +18 -28
  218. package/sidecar/dist/server/routing.js.map +1 -1
  219. package/sidecar/dist/server/ws.d.ts +2 -2
  220. package/sidecar/dist/server/ws.js +41 -39
  221. package/sidecar/dist/server/ws.js.map +1 -1
  222. package/sidecar/dist/state/host-state.d.ts +10 -2
  223. package/sidecar/dist/state/host-state.js +13 -3
  224. package/sidecar/dist/state/host-state.js.map +1 -1
  225. package/sidecar/dist/state/settings-store.js +2 -2
  226. package/sidecar/dist/state/settings-store.js.map +1 -1
  227. package/sidecar/dist/state/settings-types.d.ts +3 -3
  228. package/sidecar/dist/state/settings-types.js +1 -1
  229. package/sidecar/dist/state/settings-types.js.map +1 -1
  230. package/sidecar/package.json +3 -5
  231. package/dist/chatbox/passthrough.d.ts +0 -3
  232. package/dist/chatbox/passthrough.js +0 -53
  233. package/dist/chatbox/passthrough.js.map +0 -1
  234. package/dist/constants/chatbox.d.ts +0 -10
  235. package/dist/constants/chatbox.js +0 -35
  236. package/dist/constants/chatbox.js.map +0 -1
  237. package/dist/routes/chatbox.d.ts +0 -7
  238. package/dist/routes/chatbox.js +0 -47
  239. package/dist/routes/chatbox.js.map +0 -1
  240. package/frontend-vue/app/runtime/overlay.ts +0 -400
  241. package/frontend-vue/app/runtime/theme-bridge.ts +0 -189
  242. package/sidecar/chatbox/dist/assets/index-C8u7mkHn.css +0 -1
  243. package/sidecar/chatbox/dist/assets/index-tdZvY7ee.js +0 -52
  244. package/sidecar/chatbox/dist/index.html +0 -13
  245. package/sidecar/dist/server/iframe-socket-registry.js.map +0 -1
@@ -1,47 +1,47 @@
1
1
  <script setup lang="ts">
2
- import { onMounted, ref } from 'vue'
2
+ import { onMounted, ref } from "vue";
3
3
 
4
4
  interface ActivityItem {
5
- id: string
6
- timestampMs: number
7
- toolName: string
8
- status: 'success' | 'error' | 'pending'
9
- conversationId: string
10
- conversationTitle: string
11
- summary: string
5
+ id: string;
6
+ timestampMs: number;
7
+ toolName: string;
8
+ status: "success" | "error" | "pending";
9
+ conversationId: string;
10
+ conversationTitle: string;
11
+ summary: string;
12
12
  }
13
13
 
14
- const { $authFetch } = useAuthFetch()
14
+ const { $authFetch } = useAuthFetch();
15
15
 
16
- const items = ref<ActivityItem[]>([])
17
- const loading = ref(false)
18
- const error = ref<string | null>(null)
16
+ const items = ref<ActivityItem[]>([]);
17
+ const loading = ref(false);
18
+ const error = ref<string | null>(null);
19
19
 
20
20
  async function load(): Promise<void> {
21
- loading.value = true
22
- error.value = null
21
+ loading.value = true;
22
+ error.value = null;
23
23
  try {
24
24
  const activity = await $authFetch<{ items: ActivityItem[] }>(
25
- '/ai/activity?limit=50',
26
- )
27
- items.value = activity.items ?? []
25
+ "/ai/activity?limit=50",
26
+ );
27
+ items.value = activity.items ?? [];
28
28
  } catch (e) {
29
- error.value = e instanceof Error ? e.message : String(e)
29
+ error.value = e instanceof Error ? e.message : String(e);
30
30
  } finally {
31
- loading.value = false
31
+ loading.value = false;
32
32
  }
33
33
  }
34
34
 
35
- onMounted(load)
35
+ onMounted(load);
36
36
 
37
- const STATUS_COLOR: Record<ActivityItem['status'], string> = {
38
- success: 'success',
39
- error: 'error',
40
- pending: 'warning',
41
- }
37
+ const STATUS_COLOR: Record<ActivityItem["status"], string> = {
38
+ success: "success",
39
+ error: "error",
40
+ pending: "warning",
41
+ };
42
42
 
43
43
  function formatTime(ms: number): string {
44
- return new Date(ms).toLocaleString()
44
+ return new Date(ms).toLocaleString();
45
45
  }
46
46
  </script>
47
47
 
@@ -49,28 +49,28 @@ function formatTime(ms: number): string {
49
49
  <div class="flex w-full flex-col gap-4 pb-10">
50
50
  <div
51
51
  v-if="error"
52
- class="rounded border border-error bg-error/10 p-4 text-sm text-error"
52
+ class="border-error bg-error/10 text-error rounded border p-4 text-sm"
53
53
  >
54
54
  {{ error }}
55
55
  </div>
56
56
 
57
- <div v-else class="rounded border border-default">
58
- <div v-if="loading" class="p-4 text-sm text-dimmed">
57
+ <div v-else class="border-default rounded border">
58
+ <div v-if="loading" class="text-dimmed p-4 text-sm">
59
59
  Loading activity…
60
60
  </div>
61
61
  <div
62
62
  v-else-if="items.length === 0"
63
- class="p-6 text-center text-sm text-dimmed"
63
+ class="text-dimmed p-6 text-center text-sm"
64
64
  >
65
65
  No AI actions recorded yet.
66
66
  </div>
67
- <ul v-else class="divide-y divide-default">
67
+ <ul v-else class="divide-default divide-y">
68
68
  <li
69
69
  v-for="item in items"
70
70
  :key="item.id"
71
71
  class="flex items-start gap-3 p-3"
72
72
  >
73
- <UIcon name="i-ph-wrench" class="mt-1 text-dimmed" />
73
+ <UIcon name="i-ph-wrench" class="text-dimmed mt-1" />
74
74
  <div class="min-w-0 flex-1">
75
75
  <div class="flex items-center gap-2">
76
76
  <span class="font-medium">{{ item.toolName }}</span>
@@ -82,8 +82,8 @@ function formatTime(ms: number): string {
82
82
  {{ item.status }}
83
83
  </UBadge>
84
84
  </div>
85
- <p class="truncate text-sm text-muted">{{ item.summary }}</p>
86
- <p class="text-xs text-dimmed">
85
+ <p class="text-muted truncate text-sm">{{ item.summary }}</p>
86
+ <p class="text-dimmed text-xs">
87
87
  {{ item.conversationTitle }} · {{ formatTime(item.timestampMs) }}
88
88
  </p>
89
89
  </div>
@@ -0,0 +1,276 @@
1
+ <script setup lang="ts">
2
+ import { computed, inject, onBeforeUnmount, onMounted, ref, watch } from "vue";
3
+ import ChatView from "../chat/components/ChatView.vue";
4
+ import { ASSISTANT_SESSION_KEY } from "../runtime/assistant-session";
5
+ import {
6
+ DMS_OVERLAYS_DOM_ID,
7
+ OVERLAY_DOM_ID,
8
+ PANEL_LABEL,
9
+ OVERLAY_Z_INDEX,
10
+ PLACEHOLDER_CONNECTING_TEXT,
11
+ PLACEHOLDER_REVIVING_TEXT,
12
+ PLACEHOLDER_UNAVAILABLE_TEXT,
13
+ PLACEHOLDER_UNAVAILABLE_TITLE,
14
+ SIDECAR_STATUS_CONNECTED,
15
+ SIDECAR_STATUS_CONNECTING,
16
+ SIDECAR_STATUS_REVIVING,
17
+ SIDECAR_STATUS_UNAVAILABLE,
18
+ } from "../runtime/constants";
19
+
20
+ interface StatusScreen {
21
+ title: string;
22
+ text: string;
23
+ isBusy: boolean;
24
+ }
25
+
26
+ interface ResizeStart {
27
+ x: number;
28
+ width: number;
29
+ }
30
+
31
+ const CLOSE_ICON = "i-ph-x-light";
32
+ const CLOSE_LABEL = "Close";
33
+
34
+ const STATUS_SCREENS: Record<string, StatusScreen> = {
35
+ [SIDECAR_STATUS_CONNECTING]: {
36
+ title: "",
37
+ text: PLACEHOLDER_CONNECTING_TEXT,
38
+ isBusy: true,
39
+ },
40
+ [SIDECAR_STATUS_REVIVING]: {
41
+ title: "",
42
+ text: PLACEHOLDER_REVIVING_TEXT,
43
+ isBusy: true,
44
+ },
45
+ [SIDECAR_STATUS_UNAVAILABLE]: {
46
+ title: PLACEHOLDER_UNAVAILABLE_TITLE,
47
+ text: PLACEHOLDER_UNAVAILABLE_TEXT,
48
+ isBusy: false,
49
+ },
50
+ };
51
+
52
+ const session = inject(ASSISTANT_SESSION_KEY, null);
53
+ const panelEl = ref<HTMLElement | null>(null);
54
+ const isOpen = computed(() => session?.panel.isOpen.value === true);
55
+ const hasOpened = ref(isOpen.value);
56
+ const isResizing = ref(false);
57
+ let resizeStart: ResizeStart | null = null;
58
+
59
+ const statusScreen = computed<StatusScreen | null>(() => {
60
+ const status = session?.status.value ?? SIDECAR_STATUS_CONNECTING;
61
+ if (status === SIDECAR_STATUS_CONNECTED) return null;
62
+ return STATUS_SCREENS[status] ?? null;
63
+ });
64
+
65
+ const panelStyle = computed(() => ({
66
+ width: `${session?.panel.width.value ?? 0}px`,
67
+ zIndex: OVERLAY_Z_INDEX,
68
+ }));
69
+
70
+ watch(isOpen, (open) => {
71
+ if (open) hasOpened.value = true;
72
+ });
73
+
74
+ function onResizeMove(event: PointerEvent): void {
75
+ if (resizeStart === null) return;
76
+ session?.panel.resize(resizeStart.width + (resizeStart.x - event.clientX));
77
+ }
78
+
79
+ function stopResizing(): void {
80
+ resizeStart = null;
81
+ isResizing.value = false;
82
+ globalThis.removeEventListener("pointermove", onResizeMove);
83
+ globalThis.removeEventListener("pointerup", onResizeEnd);
84
+ }
85
+
86
+ function onResizeEnd(): void {
87
+ stopResizing();
88
+ session?.panel.commitWidth();
89
+ }
90
+
91
+ function startResize(event: PointerEvent): void {
92
+ if (session === null) return;
93
+ event.preventDefault();
94
+ resizeStart = { x: event.clientX, width: session.panel.width.value };
95
+ isResizing.value = true;
96
+ globalThis.addEventListener("pointermove", onResizeMove);
97
+ globalThis.addEventListener("pointerup", onResizeEnd);
98
+ }
99
+
100
+ function isInside(event: Event, element: HTMLElement | null): boolean {
101
+ return element !== null && event.composedPath().includes(element);
102
+ }
103
+
104
+ function isInsidePanelOrDmsOverlays(event: Event): boolean {
105
+ return (
106
+ isInside(event, panelEl.value) ||
107
+ isInside(event, document.getElementById(DMS_OVERLAYS_DOM_ID))
108
+ );
109
+ }
110
+
111
+ function onDocumentPointerDown(event: PointerEvent): void {
112
+ if (!isOpen.value || panelEl.value === null) return;
113
+ if (isInsidePanelOrDmsOverlays(event)) return;
114
+ session?.panel.closeFromOutside(event.timeStamp);
115
+ }
116
+
117
+ function close(): void {
118
+ session?.panel.close();
119
+ }
120
+
121
+ function navigate(path: string): void {
122
+ session?.navigate(path);
123
+ }
124
+
125
+ onMounted(() => {
126
+ document.addEventListener("pointerdown", onDocumentPointerDown, {
127
+ capture: true,
128
+ });
129
+ });
130
+
131
+ onBeforeUnmount(() => {
132
+ document.removeEventListener("pointerdown", onDocumentPointerDown, {
133
+ capture: true,
134
+ });
135
+ stopResizing();
136
+ });
137
+ </script>
138
+
139
+ <template>
140
+ <aside
141
+ v-if="session"
142
+ :id="OVERLAY_DOM_ID"
143
+ ref="panelEl"
144
+ class="dms-ai-panel"
145
+ :data-open="isOpen"
146
+ :data-resizing="isResizing"
147
+ :style="panelStyle"
148
+ :inert="!isOpen"
149
+ :aria-label="PANEL_LABEL"
150
+ >
151
+ <div class="dms-ai-panel-resize" @pointerdown="startResize" />
152
+ <ChatView
153
+ v-if="hasOpened"
154
+ class="dms-ai-panel-chat"
155
+ :transport="session.chat"
156
+ @close="close"
157
+ @navigate="navigate"
158
+ />
159
+ <div v-if="statusScreen" class="dms-ai-panel-status" role="status">
160
+ <button
161
+ type="button"
162
+ class="dms-ai-panel-close"
163
+ :aria-label="CLOSE_LABEL"
164
+ :title="CLOSE_LABEL"
165
+ @click="close"
166
+ >
167
+ <UIcon :name="CLOSE_ICON" class="size-[18px]" />
168
+ </button>
169
+ <span v-if="statusScreen.isBusy" class="dms-ai-panel-spinner" />
170
+ <b v-if="statusScreen.title" class="dms-ai-panel-status-title">
171
+ {{ statusScreen.title }}
172
+ </b>
173
+ <span class="dms-ai-panel-status-text">{{ statusScreen.text }}</span>
174
+ </div>
175
+ </aside>
176
+ </template>
177
+
178
+ <style scoped>
179
+ .dms-ai-panel {
180
+ position: fixed;
181
+ top: 0;
182
+ right: 0;
183
+ bottom: 0;
184
+ display: flex;
185
+ overflow: hidden;
186
+ background: var(--ui-bg);
187
+ color: var(--ui-text);
188
+ border-left: 1px solid var(--ui-border);
189
+ box-shadow: 0 8px 24px rgb(0 0 0 / 0.18);
190
+ transform: translateX(100%);
191
+ transition: transform 220ms cubic-bezier(0.16, 1, 0.3, 1);
192
+ }
193
+
194
+ .dms-ai-panel[data-open="true"] {
195
+ transform: none;
196
+ }
197
+
198
+ .dms-ai-panel[data-resizing="true"] {
199
+ user-select: none;
200
+ }
201
+
202
+ .dms-ai-panel-chat {
203
+ flex: 1 1 auto;
204
+ min-width: 0;
205
+ }
206
+
207
+ .dms-ai-panel-resize {
208
+ position: absolute;
209
+ top: 0;
210
+ left: 0;
211
+ z-index: 3;
212
+ width: 6px;
213
+ height: 100%;
214
+ cursor: ew-resize;
215
+ touch-action: none;
216
+ }
217
+
218
+ .dms-ai-panel-status {
219
+ position: absolute;
220
+ inset: 0;
221
+ z-index: 2;
222
+ display: flex;
223
+ flex-direction: column;
224
+ align-items: center;
225
+ justify-content: center;
226
+ gap: 14px;
227
+ padding: 24px;
228
+ text-align: center;
229
+ font-size: 13px;
230
+ font-weight: 500;
231
+ line-height: 1.5;
232
+ background: var(--ui-bg);
233
+ }
234
+
235
+ .dms-ai-panel-status-title {
236
+ font-size: 15px;
237
+ font-weight: 600;
238
+ }
239
+
240
+ .dms-ai-panel-status-text {
241
+ color: var(--ui-text-muted);
242
+ }
243
+
244
+ .dms-ai-panel-close {
245
+ position: absolute;
246
+ top: 14px;
247
+ right: 14px;
248
+ display: grid;
249
+ place-items: center;
250
+ width: 30px;
251
+ height: 30px;
252
+ border-radius: 7px;
253
+ color: var(--ui-text-dimmed);
254
+ cursor: pointer;
255
+ }
256
+
257
+ .dms-ai-panel-close:hover {
258
+ background: var(--ui-bg-muted);
259
+ color: var(--ui-text);
260
+ }
261
+
262
+ .dms-ai-panel-spinner {
263
+ width: 22px;
264
+ height: 22px;
265
+ border: 2.5px solid color-mix(in oklab, currentColor 20%, transparent);
266
+ border-top-color: currentColor;
267
+ border-radius: 50%;
268
+ animation: dms-ai-spin 0.7s linear infinite;
269
+ }
270
+
271
+ @keyframes dms-ai-spin {
272
+ to {
273
+ transform: rotate(360deg);
274
+ }
275
+ }
276
+ </style>