@antelopejs/dms-ai 0.1.6 → 0.2.0

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 (560) hide show
  1. package/README.md +48 -12
  2. package/dist/channels/bridge.d.ts +6 -1
  3. package/dist/channels/bridge.js +29 -1
  4. package/dist/channels/bridge.js.map +1 -1
  5. package/dist/channels/channel-service.d.ts +2 -1
  6. package/dist/channels/channel-service.js +3 -2
  7. package/dist/channels/channel-service.js.map +1 -1
  8. package/dist/channels/sse-stream.d.ts +3 -2
  9. package/dist/config.d.ts +0 -2
  10. package/dist/config.js +0 -7
  11. package/dist/config.js.map +1 -1
  12. package/dist/constants/http.d.ts +9 -0
  13. package/dist/constants/http.js +14 -0
  14. package/dist/constants/http.js.map +1 -0
  15. package/dist/constants/i18n.d.ts +11 -0
  16. package/dist/constants/i18n.js +15 -0
  17. package/dist/constants/i18n.js.map +1 -0
  18. package/dist/constants/pages.d.ts +50 -0
  19. package/dist/constants/pages.js +58 -0
  20. package/dist/constants/pages.js.map +1 -0
  21. package/dist/constants/sidecar.d.ts +0 -1
  22. package/dist/constants/sidecar.js +1 -2
  23. package/dist/constants/sidecar.js.map +1 -1
  24. package/dist/index.js +0 -8
  25. package/dist/index.js.map +1 -1
  26. package/dist/lifecycle/sidecar-owner.d.ts +1 -0
  27. package/dist/lifecycle/sidecar-owner.js +13 -0
  28. package/dist/lifecycle/sidecar-owner.js.map +1 -1
  29. package/dist/lifecycle/spawn-sidecar.d.ts +1 -0
  30. package/dist/lifecycle/spawn-sidecar.js +10 -10
  31. package/dist/lifecycle/spawn-sidecar.js.map +1 -1
  32. package/dist/logging/log-buffer.d.ts +0 -6
  33. package/dist/logging/log-buffer.js +0 -1
  34. package/dist/logging/log-buffer.js.map +1 -1
  35. package/dist/pages/activity/columns.d.ts +2 -0
  36. package/dist/pages/activity/columns.js +103 -0
  37. package/dist/pages/activity/columns.js.map +1 -0
  38. package/dist/pages/activity/page.d.ts +1 -2
  39. package/dist/pages/activity/page.js +79 -44
  40. package/dist/pages/activity/page.js.map +1 -1
  41. package/dist/pages/all.d.ts +1 -0
  42. package/dist/pages/all.js +1 -0
  43. package/dist/pages/all.js.map +1 -1
  44. package/dist/pages/changes/page.d.ts +9 -0
  45. package/dist/pages/changes/page.js +22 -0
  46. package/dist/pages/changes/page.js.map +1 -0
  47. package/dist/pages/meta.d.ts +9 -0
  48. package/dist/pages/meta.js +31 -0
  49. package/dist/pages/meta.js.map +1 -0
  50. package/dist/pages/module.js +9 -5
  51. package/dist/pages/module.js.map +1 -1
  52. package/dist/pages/overview/insights.d.ts +3 -0
  53. package/dist/pages/overview/insights.js +77 -0
  54. package/dist/pages/overview/insights.js.map +1 -0
  55. package/dist/pages/overview/kpis.d.ts +2 -0
  56. package/dist/pages/overview/kpis.js +39 -0
  57. package/dist/pages/overview/kpis.js.map +1 -0
  58. package/dist/pages/overview/page.d.ts +6 -3
  59. package/dist/pages/overview/page.js +19 -62
  60. package/dist/pages/overview/page.js.map +1 -1
  61. package/dist/pages/overview/recent-changes.d.ts +2 -0
  62. package/dist/pages/overview/recent-changes.js +144 -0
  63. package/dist/pages/overview/recent-changes.js.map +1 -0
  64. package/dist/pages/overview/status.d.ts +3 -0
  65. package/dist/pages/overview/status.js +36 -0
  66. package/dist/pages/overview/status.js.map +1 -0
  67. package/dist/pages/settings/availability.d.ts +2 -0
  68. package/dist/pages/settings/availability.js +46 -0
  69. package/dist/pages/settings/availability.js.map +1 -0
  70. package/dist/pages/settings/options.d.ts +10 -0
  71. package/dist/pages/settings/options.js +58 -0
  72. package/dist/pages/settings/options.js.map +1 -0
  73. package/dist/pages/settings/page.d.ts +2 -1
  74. package/dist/pages/settings/page.js +39 -13
  75. package/dist/pages/settings/page.js.map +1 -1
  76. package/dist/pages/settings/sections.d.ts +2 -0
  77. package/dist/pages/settings/sections.js +164 -0
  78. package/dist/pages/settings/sections.js.map +1 -0
  79. package/dist/pages/skills/page.d.ts +2 -1
  80. package/dist/pages/skills/page.js +122 -12
  81. package/dist/pages/skills/page.js.map +1 -1
  82. package/dist/routes/activity-csv.d.ts +2 -0
  83. package/dist/routes/activity-csv.js +42 -0
  84. package/dist/routes/activity-csv.js.map +1 -0
  85. package/dist/routes/activity.d.ts +8 -0
  86. package/dist/routes/activity.js +105 -0
  87. package/dist/routes/activity.js.map +1 -0
  88. package/dist/routes/actor.d.ts +2 -0
  89. package/dist/routes/actor.js +8 -0
  90. package/dist/routes/actor.js.map +1 -0
  91. package/dist/routes/banner.d.ts +3 -0
  92. package/dist/routes/banner.js +9 -0
  93. package/dist/routes/banner.js.map +1 -0
  94. package/dist/routes/builder.js +1 -5
  95. package/dist/routes/builder.js.map +1 -1
  96. package/dist/routes/changes.d.ts +17 -0
  97. package/dist/routes/changes.js +152 -0
  98. package/dist/routes/changes.js.map +1 -0
  99. package/dist/routes/channels.js +2 -1
  100. package/dist/routes/channels.js.map +1 -1
  101. package/dist/routes/index.d.ts +3 -0
  102. package/dist/routes/index.js +3 -0
  103. package/dist/routes/index.js.map +1 -1
  104. package/dist/routes/list-query.d.ts +9 -0
  105. package/dist/routes/list-query.js +34 -0
  106. package/dist/routes/list-query.js.map +1 -0
  107. package/dist/routes/metric-shapes.d.ts +8 -0
  108. package/dist/routes/metric-shapes.js +107 -0
  109. package/dist/routes/metric-shapes.js.map +1 -0
  110. package/dist/routes/metrics.d.ts +5 -48
  111. package/dist/routes/metrics.js +52 -42
  112. package/dist/routes/metrics.js.map +1 -1
  113. package/dist/routes/settings.d.ts +3 -16
  114. package/dist/routes/settings.js +40 -14
  115. package/dist/routes/settings.js.map +1 -1
  116. package/dist/routes/sidecar-results.d.ts +6 -0
  117. package/dist/routes/sidecar-results.js +44 -0
  118. package/dist/routes/sidecar-results.js.map +1 -0
  119. package/dist/routes/skills.d.ts +4 -14
  120. package/dist/routes/skills.js +91 -6
  121. package/dist/routes/skills.js.map +1 -1
  122. package/dist/routes/status-shapes.d.ts +5 -0
  123. package/dist/routes/status-shapes.js +176 -0
  124. package/dist/routes/status-shapes.js.map +1 -0
  125. package/dist/routes/status.d.ts +9 -0
  126. package/dist/routes/status.js +92 -0
  127. package/dist/routes/status.js.map +1 -0
  128. package/dist/routes/undo-confirm.d.ts +3 -0
  129. package/dist/routes/undo-confirm.js +51 -0
  130. package/dist/routes/undo-confirm.js.map +1 -0
  131. package/dist/sidecar/http-client.d.ts +11 -0
  132. package/dist/sidecar/http-client.js +59 -0
  133. package/dist/sidecar/http-client.js.map +1 -0
  134. package/dist/sidecar/index.d.ts +2 -0
  135. package/dist/sidecar/index.js +19 -0
  136. package/dist/sidecar/index.js.map +1 -0
  137. package/dist/sidecar/query.d.ts +3 -0
  138. package/dist/sidecar/query.js +25 -0
  139. package/dist/sidecar/query.js.map +1 -0
  140. package/dist/types/activity.d.ts +31 -0
  141. package/dist/types/activity.js +3 -0
  142. package/dist/types/activity.js.map +1 -0
  143. package/dist/types/changes.d.ts +45 -0
  144. package/dist/types/changes.js +3 -0
  145. package/dist/types/changes.js.map +1 -0
  146. package/dist/types/index.d.ts +5 -0
  147. package/dist/types/index.js +5 -0
  148. package/dist/types/index.js.map +1 -1
  149. package/dist/types/metrics.d.ts +76 -0
  150. package/dist/types/metrics.js +3 -0
  151. package/dist/types/metrics.js.map +1 -0
  152. package/dist/types/skills.d.ts +51 -0
  153. package/dist/types/skills.js +3 -0
  154. package/dist/types/skills.js.map +1 -0
  155. package/dist/types/status.d.ts +16 -0
  156. package/dist/types/status.js +3 -0
  157. package/dist/types/status.js.map +1 -0
  158. package/dist/vocabulary/enumerations.d.ts +9 -0
  159. package/dist/vocabulary/enumerations.js +52 -0
  160. package/dist/vocabulary/enumerations.js.map +1 -0
  161. package/dist/vocabulary/index.d.ts +5 -0
  162. package/dist/vocabulary/index.js +22 -0
  163. package/dist/vocabulary/index.js.map +1 -0
  164. package/dist/vocabulary/keys.d.ts +1 -0
  165. package/dist/vocabulary/keys.js +8 -0
  166. package/dist/vocabulary/keys.js.map +1 -0
  167. package/dist/vocabulary/options.d.ts +7 -0
  168. package/dist/vocabulary/options.js +33 -0
  169. package/dist/vocabulary/options.js.map +1 -0
  170. package/dist/vocabulary/tools.d.ts +7 -0
  171. package/dist/vocabulary/tools.js +99 -0
  172. package/dist/vocabulary/tools.js.map +1 -0
  173. package/dist/vocabulary/types.d.ts +20 -0
  174. package/dist/vocabulary/types.js +3 -0
  175. package/dist/vocabulary/types.js.map +1 -0
  176. package/frontend-vue/app/chat/components/AnswerRecord.vue +95 -0
  177. package/frontend-vue/app/chat/components/ApprovalDock.vue +371 -0
  178. package/frontend-vue/app/chat/components/ChangeSetCard.vue +297 -0
  179. package/frontend-vue/app/chat/components/ChatEmpty.vue +142 -0
  180. package/frontend-vue/app/chat/components/ChatView.vue +664 -406
  181. package/frontend-vue/app/chat/components/Composer.vue +589 -0
  182. package/frontend-vue/app/chat/components/ConnectionBanner.vue +41 -65
  183. package/frontend-vue/app/chat/components/ConversationDrawer.vue +387 -177
  184. package/frontend-vue/app/chat/components/DiffView.vue +131 -0
  185. package/frontend-vue/app/chat/components/FullAutoBanner.vue +76 -0
  186. package/frontend-vue/app/chat/components/FullAutoDialog.vue +103 -0
  187. package/frontend-vue/app/chat/components/MarkdownContent.vue +15 -15
  188. package/frontend-vue/app/chat/components/MessageList.vue +389 -295
  189. package/frontend-vue/app/chat/components/NoticeCard.vue +193 -0
  190. package/frontend-vue/app/chat/components/PanelHeader.vue +242 -0
  191. package/frontend-vue/app/chat/components/PermissionCard.vue +470 -0
  192. package/frontend-vue/app/chat/components/PlanCard.vue +115 -0
  193. package/frontend-vue/app/chat/components/QuestionDock.vue +407 -0
  194. package/frontend-vue/app/chat/components/QueueDock.vue +310 -0
  195. package/frontend-vue/app/chat/components/RulesList.vue +97 -0
  196. package/frontend-vue/app/chat/components/StepsDock.vue +181 -0
  197. package/frontend-vue/app/chat/components/ToolCluster.vue +186 -178
  198. package/frontend-vue/app/chat/components/ToolRow.vue +251 -0
  199. package/frontend-vue/app/chat/components/TurnErrorCard.vue +135 -0
  200. package/frontend-vue/app/chat/composables/conversation-events.ts +404 -0
  201. package/frontend-vue/app/chat/composables/useChangeSetActions.ts +135 -0
  202. package/frontend-vue/app/chat/composables/useChatChannel.ts +11 -3
  203. package/frontend-vue/app/chat/composables/useChatI18n.ts +35 -0
  204. package/frontend-vue/app/chat/composables/useComposerAttachments.ts +111 -0
  205. package/frontend-vue/app/chat/composables/useConversation.ts +149 -651
  206. package/frontend-vue/app/chat/composables/useConversationId.ts +2 -10
  207. package/frontend-vue/app/chat/composables/useConversationList.ts +77 -21
  208. package/frontend-vue/app/chat/composables/useConversationMode.ts +73 -0
  209. package/frontend-vue/app/chat/composables/usePaletteTurn.ts +124 -0
  210. package/frontend-vue/app/chat/composables/usePermissionQueue.ts +211 -34
  211. package/frontend-vue/app/chat/composables/useQuestionQueue.ts +103 -21
  212. package/frontend-vue/app/chat/composables/useQueueActions.ts +55 -0
  213. package/frontend-vue/app/chat/composables/useSettings.ts +17 -34
  214. package/frontend-vue/app/chat/constants/attachments.ts +2 -1
  215. package/frontend-vue/app/chat/constants/conversation.ts +18 -32
  216. package/frontend-vue/app/chat/constants/protocol.ts +25 -2
  217. package/frontend-vue/app/chat/constants/run-status.ts +8 -14
  218. package/frontend-vue/app/chat/constants/settings.ts +5 -47
  219. package/frontend-vue/app/chat/types/conversation.ts +72 -2
  220. package/frontend-vue/app/chat/types/permission.ts +31 -0
  221. package/frontend-vue/app/chat/types/protocol.ts +226 -0
  222. package/frontend-vue/app/chat/types/question.ts +10 -1
  223. package/frontend-vue/app/chat/types/settings.ts +9 -5
  224. package/frontend-vue/app/chat/utils/approval-keyboard.ts +49 -0
  225. package/frontend-vue/app/chat/utils/arrays.ts +10 -0
  226. package/frontend-vue/app/chat/utils/conversation-groups.ts +96 -0
  227. package/frontend-vue/app/chat/utils/conversation-messages.ts +251 -0
  228. package/frontend-vue/app/chat/utils/diff.ts +78 -0
  229. package/frontend-vue/app/chat/utils/format.ts +43 -0
  230. package/frontend-vue/app/chat/utils/markdown.ts +1 -1
  231. package/frontend-vue/app/chat/utils/permission-view.ts +159 -0
  232. package/frontend-vue/app/chat/utils/platform.ts +34 -0
  233. package/frontend-vue/app/chat/utils/queue.ts +18 -0
  234. package/frontend-vue/app/chat/utils/render-items.ts +164 -0
  235. package/frontend-vue/app/chat/utils/run-status.ts +19 -23
  236. package/frontend-vue/app/chat/utils/suggestions.ts +101 -0
  237. package/frontend-vue/app/chat/utils/todos.ts +2 -2
  238. package/frontend-vue/app/chat/utils/tool-lexicon.ts +540 -0
  239. package/frontend-vue/app/chat/utils/tool-state.ts +60 -0
  240. package/frontend-vue/app/components/ActivityDetail.vue +235 -0
  241. package/frontend-vue/app/components/ChangesView.vue +249 -0
  242. package/frontend-vue/app/components/ChatPanel.vue +141 -196
  243. package/frontend-vue/app/components/PaletteAnswer.vue +185 -0
  244. package/frontend-vue/app/components/SkillCard.vue +77 -0
  245. package/frontend-vue/app/components/SkillDetail.vue +188 -0
  246. package/frontend-vue/app/plugins/ai.client.ts +349 -57
  247. package/frontend-vue/app/plugins/side-panel.ts +13 -0
  248. package/frontend-vue/app/runtime/assistant-activity.ts +105 -0
  249. package/frontend-vue/app/runtime/assistant-commands.ts +210 -0
  250. package/frontend-vue/app/runtime/assistant-notifications.ts +181 -0
  251. package/frontend-vue/app/runtime/assistant-session.ts +49 -6
  252. package/frontend-vue/app/runtime/channel-client.ts +3 -6
  253. package/frontend-vue/app/runtime/constants.ts +29 -35
  254. package/frontend-vue/app/runtime/host-commands.ts +4 -4
  255. package/frontend-vue/app/runtime/listeners.ts +1 -1
  256. package/frontend-vue/app/runtime/navigation-complete.ts +1 -1
  257. package/frontend-vue/app/runtime/panel-intents.ts +55 -0
  258. package/frontend-vue/app/runtime/shortcuts.ts +3 -1
  259. package/frontend-vue/app/runtime/sidecar-status.ts +9 -1
  260. package/frontend-vue/app/runtime/stream-holds.ts +24 -0
  261. package/frontend-vue/app/views/ChangeSetPanel.vue +222 -0
  262. package/frontend-vue/app/views/DecisionLabel.vue +30 -0
  263. package/frontend-vue/app/views/DiffView.vue +215 -0
  264. package/frontend-vue/app/views/ResultPill.vue +32 -0
  265. package/frontend-vue/app/views/RowStepper.vue +48 -0
  266. package/frontend-vue/app/views/UnavailableState.vue +66 -0
  267. package/frontend-vue/app/views/composables/useAiRequest.ts +89 -0
  268. package/frontend-vue/app/views/composables/useAssistant.ts +33 -0
  269. package/frontend-vue/app/views/composables/useChangeSetActions.ts +102 -0
  270. package/frontend-vue/app/views/composables/useViewFormat.ts +55 -0
  271. package/frontend-vue/app/views/constants.ts +43 -0
  272. package/frontend-vue/app/views/types.ts +189 -0
  273. package/frontend-vue/app/views/utils/activity.ts +77 -0
  274. package/frontend-vue/app/views/utils/change-sets.ts +44 -0
  275. package/frontend-vue/app/views/utils/diff.ts +98 -0
  276. package/frontend-vue/app/views/utils/moment.ts +92 -0
  277. package/frontend-vue/app/views/utils/skills.ts +27 -0
  278. package/frontend-vue/app/views/utils/tools.ts +73 -0
  279. package/frontend-vue/dms.frontend.ts +17 -5
  280. package/frontend-vue/i18n/locales/dms-ai-pages-en-GB.json +607 -0
  281. package/frontend-vue/i18n/locales/dms-ai-pages-fr-FR.json +607 -0
  282. package/frontend-vue/i18n/locales/dms-ai-panel-en-GB.json +425 -0
  283. package/frontend-vue/i18n/locales/dms-ai-panel-fr-FR.json +425 -0
  284. package/frontend-vue/i18n/locales/dms-ai-views-en-GB.json +142 -0
  285. package/frontend-vue/i18n/locales/dms-ai-views-fr-FR.json +142 -0
  286. package/frontend-vue/package.json +1 -1
  287. package/frontend-vue/tests/chat/conversation-events.test.ts +590 -0
  288. package/frontend-vue/tests/chat/diff-and-keys.test.ts +178 -0
  289. package/frontend-vue/tests/chat/tool-lexicon.test.ts +188 -0
  290. package/frontend-vue/tests/chat/useConversation.test.ts +36 -33
  291. package/frontend-vue/tests/chat-panel.test.ts +78 -131
  292. package/frontend-vue/tests/i18n-panel.test.ts +118 -0
  293. package/frontend-vue/tests/palette-assistant.test.ts +220 -0
  294. package/frontend-vue/tests/panel-states.test.ts +806 -0
  295. package/frontend-vue/tests/sidecar-guest.test.ts +35 -3
  296. package/frontend-vue/tests/support/i18n.ts +49 -0
  297. package/frontend-vue/tests/support/panel-harness.ts +198 -0
  298. package/frontend-vue/tests/support/stubs.ts +201 -0
  299. package/frontend-vue/tests/views/diff-view.test.ts +149 -0
  300. package/frontend-vue/tests/views/view-format.test.ts +59 -0
  301. package/package.json +4 -3
  302. package/sidecar/dist/agent/attachment-files.d.ts +0 -1
  303. package/sidecar/dist/agent/attachment-files.js +1 -1
  304. package/sidecar/dist/agent/attachment-files.js.map +1 -1
  305. package/sidecar/dist/agent/call-ledger.d.ts +6 -0
  306. package/sidecar/dist/agent/call-ledger.js +41 -0
  307. package/sidecar/dist/agent/call-ledger.js.map +1 -0
  308. package/sidecar/dist/agent/command-analysis.d.ts +9 -0
  309. package/sidecar/dist/agent/command-analysis.js +104 -0
  310. package/sidecar/dist/agent/command-analysis.js.map +1 -0
  311. package/sidecar/dist/agent/conversation-modes.d.ts +32 -0
  312. package/sidecar/dist/agent/conversation-modes.js +122 -0
  313. package/sidecar/dist/agent/conversation-modes.js.map +1 -0
  314. package/sidecar/dist/agent/edit-targets.d.ts +5 -0
  315. package/sidecar/dist/agent/edit-targets.js +41 -0
  316. package/sidecar/dist/agent/edit-targets.js.map +1 -0
  317. package/sidecar/dist/agent/effective-mode.d.ts +9 -2
  318. package/sidecar/dist/agent/effective-mode.js +14 -16
  319. package/sidecar/dist/agent/effective-mode.js.map +1 -1
  320. package/sidecar/dist/agent/host-context.js +2 -2
  321. package/sidecar/dist/agent/host-context.js.map +1 -1
  322. package/sidecar/dist/agent/line-diff.d.ts +8 -0
  323. package/sidecar/dist/agent/line-diff.js +204 -0
  324. package/sidecar/dist/agent/line-diff.js.map +1 -0
  325. package/sidecar/dist/agent/permission-bus.d.ts +55 -10
  326. package/sidecar/dist/agent/permission-bus.js +130 -100
  327. package/sidecar/dist/agent/permission-bus.js.map +1 -1
  328. package/sidecar/dist/agent/permission-preview.d.ts +20 -0
  329. package/sidecar/dist/agent/permission-preview.js +203 -0
  330. package/sidecar/dist/agent/permission-preview.js.map +1 -0
  331. package/sidecar/dist/agent/permission-rules.d.ts +17 -0
  332. package/sidecar/dist/agent/permission-rules.js +95 -0
  333. package/sidecar/dist/agent/permission-rules.js.map +1 -0
  334. package/sidecar/dist/agent/provider.d.ts +12 -4
  335. package/sidecar/dist/agent/question-bus.d.ts +14 -2
  336. package/sidecar/dist/agent/question-bus.js +30 -11
  337. package/sidecar/dist/agent/question-bus.js.map +1 -1
  338. package/sidecar/dist/agent/runner-events.d.ts +3 -1
  339. package/sidecar/dist/agent/runner.d.ts +6 -4
  340. package/sidecar/dist/agent/runner.js +24 -7
  341. package/sidecar/dist/agent/runner.js.map +1 -1
  342. package/sidecar/dist/agent/switching-runner.js +1 -0
  343. package/sidecar/dist/agent/switching-runner.js.map +1 -1
  344. package/sidecar/dist/agent/tool-kinds.d.ts +12 -0
  345. package/sidecar/dist/agent/tool-kinds.js +50 -0
  346. package/sidecar/dist/agent/tool-kinds.js.map +1 -0
  347. package/sidecar/dist/agent/typecheck.d.ts +2 -6
  348. package/sidecar/dist/audit/activity-query.d.ts +37 -0
  349. package/sidecar/dist/audit/activity-query.js +111 -0
  350. package/sidecar/dist/audit/activity-query.js.map +1 -0
  351. package/sidecar/dist/audit/activity-target.d.ts +2 -0
  352. package/sidecar/dist/audit/activity-target.js +46 -0
  353. package/sidecar/dist/audit/activity-target.js.map +1 -0
  354. package/sidecar/dist/audit/activity.d.ts +45 -0
  355. package/sidecar/dist/audit/activity.js +255 -0
  356. package/sidecar/dist/audit/activity.js.map +1 -0
  357. package/sidecar/dist/audit/call-audit.d.ts +11 -0
  358. package/sidecar/dist/audit/call-audit.js +23 -0
  359. package/sidecar/dist/audit/call-audit.js.map +1 -0
  360. package/sidecar/dist/checkpoints/checkpoints.d.ts +69 -0
  361. package/sidecar/dist/checkpoints/checkpoints.js +244 -0
  362. package/sidecar/dist/checkpoints/checkpoints.js.map +1 -0
  363. package/sidecar/dist/checkpoints/shadow-git.d.ts +23 -0
  364. package/sidecar/dist/checkpoints/shadow-git.js +173 -0
  365. package/sidecar/dist/checkpoints/shadow-git.js.map +1 -0
  366. package/sidecar/dist/constants/agent.d.ts +2 -0
  367. package/sidecar/dist/constants/agent.js +4 -0
  368. package/sidecar/dist/constants/agent.js.map +1 -1
  369. package/sidecar/dist/constants/audit.d.ts +22 -0
  370. package/sidecar/dist/constants/audit.js +49 -0
  371. package/sidecar/dist/constants/audit.js.map +1 -0
  372. package/sidecar/dist/constants/builder.d.ts +3 -0
  373. package/sidecar/dist/constants/builder.js +2 -0
  374. package/sidecar/dist/constants/builder.js.map +1 -1
  375. package/sidecar/dist/constants/checkpoints.d.ts +15 -0
  376. package/sidecar/dist/constants/checkpoints.js +26 -0
  377. package/sidecar/dist/constants/checkpoints.js.map +1 -0
  378. package/sidecar/dist/constants/claude.d.ts +1 -0
  379. package/sidecar/dist/constants/claude.js +1 -0
  380. package/sidecar/dist/constants/claude.js.map +1 -1
  381. package/sidecar/dist/constants/codex.d.ts +2 -4
  382. package/sidecar/dist/constants/codex.js +2 -4
  383. package/sidecar/dist/constants/codex.js.map +1 -1
  384. package/sidecar/dist/constants/http.d.ts +1 -0
  385. package/sidecar/dist/constants/http.js +1 -0
  386. package/sidecar/dist/constants/http.js.map +1 -1
  387. package/sidecar/dist/constants/mcp.d.ts +3 -0
  388. package/sidecar/dist/constants/mcp.js +9 -0
  389. package/sidecar/dist/constants/mcp.js.map +1 -1
  390. package/sidecar/dist/constants/permissions.d.ts +9 -3
  391. package/sidecar/dist/constants/permissions.js +9 -2
  392. package/sidecar/dist/constants/permissions.js.map +1 -1
  393. package/sidecar/dist/constants/settings.d.ts +2 -1
  394. package/sidecar/dist/constants/settings.js +7 -1
  395. package/sidecar/dist/constants/settings.js.map +1 -1
  396. package/sidecar/dist/constants/tool-kinds.d.ts +14 -0
  397. package/sidecar/dist/constants/tool-kinds.js +65 -0
  398. package/sidecar/dist/constants/tool-kinds.js.map +1 -0
  399. package/sidecar/dist/index.js +28 -2
  400. package/sidecar/dist/index.js.map +1 -1
  401. package/sidecar/dist/mcp/define-tool.d.ts +3 -2
  402. package/sidecar/dist/mcp/tool-definitions.js +4 -1
  403. package/sidecar/dist/mcp/tool-definitions.js.map +1 -1
  404. package/sidecar/dist/mcp/tools/ask-user.d.ts +2 -2
  405. package/sidecar/dist/mcp/tools/ask-user.js +7 -4
  406. package/sidecar/dist/mcp/tools/ask-user.js.map +1 -1
  407. package/sidecar/dist/mcp/tools/builder-catalog.d.ts +3 -0
  408. package/sidecar/dist/mcp/tools/builder-catalog.js +86 -0
  409. package/sidecar/dist/mcp/tools/builder-catalog.js.map +1 -0
  410. package/sidecar/dist/mcp/tools/builder-gate.d.ts +8 -0
  411. package/sidecar/dist/mcp/tools/builder-gate.js +22 -0
  412. package/sidecar/dist/mcp/tools/builder-gate.js.map +1 -0
  413. package/sidecar/dist/mcp/tools/builder.d.ts +7 -2
  414. package/sidecar/dist/mcp/tools/builder.js +48 -7
  415. package/sidecar/dist/mcp/tools/builder.js.map +1 -1
  416. package/sidecar/dist/mcp/types.d.ts +2 -0
  417. package/sidecar/dist/metrics/aggregate.d.ts +13 -10
  418. package/sidecar/dist/metrics/aggregate.js +140 -143
  419. package/sidecar/dist/metrics/aggregate.js.map +1 -1
  420. package/sidecar/dist/metrics/types.d.ts +36 -23
  421. package/sidecar/dist/metrics/types.js +3 -1
  422. package/sidecar/dist/metrics/types.js.map +1 -1
  423. package/sidecar/dist/pages/imports-scanner.d.ts +1 -1
  424. package/sidecar/dist/pages/imports-scanner.js +2 -5
  425. package/sidecar/dist/pages/imports-scanner.js.map +1 -1
  426. package/sidecar/dist/prompts/agent.d.ts +1 -3
  427. package/sidecar/dist/prompts/agent.js +4 -4
  428. package/sidecar/dist/prompts/agent.js.map +1 -1
  429. package/sidecar/dist/prompts/builder.d.ts +2 -2
  430. package/sidecar/dist/prompts/builder.js +2 -2
  431. package/sidecar/dist/protocol/events.d.ts +1084 -18
  432. package/sidecar/dist/protocol/events.js +239 -5
  433. package/sidecar/dist/protocol/events.js.map +1 -1
  434. package/sidecar/dist/protocol/messages.d.ts +273 -19
  435. package/sidecar/dist/protocol/messages.js +107 -7
  436. package/sidecar/dist/protocol/messages.js.map +1 -1
  437. package/sidecar/dist/providers/claude/config.d.ts +3 -2
  438. package/sidecar/dist/providers/claude/config.js +10 -4
  439. package/sidecar/dist/providers/claude/config.js.map +1 -1
  440. package/sidecar/dist/providers/claude/provider.d.ts +2 -8
  441. package/sidecar/dist/providers/claude/provider.js +37 -35
  442. package/sidecar/dist/providers/claude/provider.js.map +1 -1
  443. package/sidecar/dist/providers/claude/safe-mode.d.ts +6 -1
  444. package/sidecar/dist/providers/claude/safe-mode.js +13 -5
  445. package/sidecar/dist/providers/claude/safe-mode.js.map +1 -1
  446. package/sidecar/dist/providers/codex/adapter.d.ts +6 -0
  447. package/sidecar/dist/providers/codex/adapter.js +14 -4
  448. package/sidecar/dist/providers/codex/adapter.js.map +1 -1
  449. package/sidecar/dist/providers/codex/client.d.ts +0 -11
  450. package/sidecar/dist/providers/codex/config.d.ts +1 -3
  451. package/sidecar/dist/providers/codex/config.js +5 -11
  452. package/sidecar/dist/providers/codex/config.js.map +1 -1
  453. package/sidecar/dist/providers/codex/permissions.d.ts +7 -4
  454. package/sidecar/dist/providers/codex/permissions.js +32 -16
  455. package/sidecar/dist/providers/codex/permissions.js.map +1 -1
  456. package/sidecar/dist/providers/codex/process.js +1 -5
  457. package/sidecar/dist/providers/codex/process.js.map +1 -1
  458. package/sidecar/dist/providers/codex/provider.js +14 -3
  459. package/sidecar/dist/providers/codex/provider.js.map +1 -1
  460. package/sidecar/dist/providers/codex/skills.d.ts +0 -1
  461. package/sidecar/dist/providers/codex/skills.js +1 -1
  462. package/sidecar/dist/providers/codex/skills.js.map +1 -1
  463. package/sidecar/dist/providers/codex/stop.js +1 -10
  464. package/sidecar/dist/providers/codex/stop.js.map +1 -1
  465. package/sidecar/dist/server/change-set-actions.d.ts +10 -0
  466. package/sidecar/dist/server/change-set-actions.js +14 -0
  467. package/sidecar/dist/server/change-set-actions.js.map +1 -0
  468. package/sidecar/dist/server/chat-events.d.ts +15 -0
  469. package/sidecar/dist/server/chat-events.js +115 -0
  470. package/sidecar/dist/server/chat-events.js.map +1 -0
  471. package/sidecar/dist/server/chat-socket-registry.d.ts +2 -0
  472. package/sidecar/dist/server/chat-socket-registry.js +48 -37
  473. package/sidecar/dist/server/chat-socket-registry.js.map +1 -1
  474. package/sidecar/dist/server/conversation-runs.d.ts +13 -0
  475. package/sidecar/dist/server/conversation-runs.js +114 -0
  476. package/sidecar/dist/server/conversation-runs.js.map +1 -0
  477. package/sidecar/dist/server/http-io.d.ts +4 -0
  478. package/sidecar/dist/server/http-io.js +31 -0
  479. package/sidecar/dist/server/http-io.js.map +1 -0
  480. package/sidecar/dist/server/http-params.d.ts +9 -0
  481. package/sidecar/dist/server/http-params.js +79 -0
  482. package/sidecar/dist/server/http-params.js.map +1 -0
  483. package/sidecar/dist/server/http-routes.d.ts +27 -0
  484. package/sidecar/dist/server/http-routes.js +281 -0
  485. package/sidecar/dist/server/http-routes.js.map +1 -0
  486. package/sidecar/dist/server/http.d.ts +6 -1
  487. package/sidecar/dist/server/http.js +76 -164
  488. package/sidecar/dist/server/http.js.map +1 -1
  489. package/sidecar/dist/server/pending-queue.d.ts +2 -0
  490. package/sidecar/dist/server/pending-queue.js +16 -0
  491. package/sidecar/dist/server/pending-queue.js.map +1 -1
  492. package/sidecar/dist/server/permission-events.d.ts +15 -0
  493. package/sidecar/dist/server/permission-events.js +163 -0
  494. package/sidecar/dist/server/permission-events.js.map +1 -0
  495. package/sidecar/dist/server/routing.d.ts +4 -52
  496. package/sidecar/dist/server/routing.js +190 -501
  497. package/sidecar/dist/server/routing.js.map +1 -1
  498. package/sidecar/dist/server/safety-net.d.ts +7 -0
  499. package/sidecar/dist/server/safety-net.js +34 -6
  500. package/sidecar/dist/server/safety-net.js.map +1 -1
  501. package/sidecar/dist/server/services.d.ts +55 -0
  502. package/sidecar/dist/server/services.js +2 -0
  503. package/sidecar/dist/server/services.js.map +1 -0
  504. package/sidecar/dist/server/tool-calls.d.ts +6 -0
  505. package/sidecar/dist/server/tool-calls.js +134 -0
  506. package/sidecar/dist/server/tool-calls.js.map +1 -0
  507. package/sidecar/dist/server/turn-registry.d.ts +44 -0
  508. package/sidecar/dist/server/turn-registry.js +40 -0
  509. package/sidecar/dist/server/turn-registry.js.map +1 -0
  510. package/sidecar/dist/server/turns.d.ts +17 -0
  511. package/sidecar/dist/server/turns.js +335 -0
  512. package/sidecar/dist/server/turns.js.map +1 -0
  513. package/sidecar/dist/server/ws.d.ts +4 -1
  514. package/sidecar/dist/server/ws.js +102 -62
  515. package/sidecar/dist/server/ws.js.map +1 -1
  516. package/sidecar/dist/skills/build-catalog.d.ts +1 -0
  517. package/sidecar/dist/skills/build-catalog.js +14 -1
  518. package/sidecar/dist/skills/build-catalog.js.map +1 -1
  519. package/sidecar/dist/skills/skill-usage.d.ts +22 -0
  520. package/sidecar/dist/skills/skill-usage.js +97 -0
  521. package/sidecar/dist/skills/skill-usage.js.map +1 -0
  522. package/sidecar/dist/state/change-sets.d.ts +12 -0
  523. package/sidecar/dist/state/change-sets.js +77 -0
  524. package/sidecar/dist/state/change-sets.js.map +1 -0
  525. package/sidecar/dist/state/conversations.d.ts +19 -7
  526. package/sidecar/dist/state/conversations.js +61 -20
  527. package/sidecar/dist/state/conversations.js.map +1 -1
  528. package/sidecar/dist/state/host-state.d.ts +2 -1
  529. package/sidecar/dist/state/settings-store.d.ts +1 -0
  530. package/sidecar/dist/state/settings-store.js +27 -26
  531. package/sidecar/dist/state/settings-store.js.map +1 -1
  532. package/sidecar/dist/state/settings-types.d.ts +11 -1
  533. package/sidecar/dist/state/settings-types.js +3 -1
  534. package/sidecar/dist/state/settings-types.js.map +1 -1
  535. package/sidecar/dist/state/types.d.ts +114 -8
  536. package/sidecar/dist/state/types.js +6 -3
  537. package/sidecar/dist/state/types.js.map +1 -1
  538. package/skills/dms-builder-safe/REFERENCE.md +1 -1
  539. package/skills/dms-builder-safe/SKILL.md +12 -7
  540. package/dist/routes/proxy.d.ts +0 -4
  541. package/dist/routes/proxy.js +0 -55
  542. package/dist/routes/proxy.js.map +0 -1
  543. package/frontend-vue/app/chat/components/ComposerInput.vue +0 -742
  544. package/frontend-vue/app/chat/components/PermissionRequests.vue +0 -323
  545. package/frontend-vue/app/chat/components/QuestionPrompt.vue +0 -275
  546. package/frontend-vue/app/chat/components/QueuedMessages.vue +0 -109
  547. package/frontend-vue/app/chat/components/TodoList.vue +0 -291
  548. package/frontend-vue/app/chat/components/ToolCallEntry.vue +0 -218
  549. package/frontend-vue/app/chat/constants/connection-banner.ts +0 -7
  550. package/frontend-vue/app/chat/constants/conversation-drawer.ts +0 -13
  551. package/frontend-vue/app/chat/constants/permissions.ts +0 -50
  552. package/frontend-vue/app/chat/utils/tool-summary.ts +0 -53
  553. package/frontend-vue/app/components/ActivityView.vue +0 -94
  554. package/frontend-vue/app/components/SettingsView.vue +0 -387
  555. package/frontend-vue/app/components/SkillsView.vue +0 -230
  556. package/frontend-vue/app/runtime/header-action.ts +0 -64
  557. package/frontend-vue/app/runtime/overlay-prefs.ts +0 -89
  558. package/frontend-vue/app/runtime/panel-state.ts +0 -88
  559. package/frontend-vue/tests/overlay-prefs.test.ts +0 -91
  560. package/frontend-vue/tests/panel-state.test.ts +0 -58
@@ -1,107 +1,27 @@
1
- import { flushPromises, mount, type VueWrapper } from "@vue/test-utils";
1
+ import { flushPromises, mount } from "@vue/test-utils";
2
2
  import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
3
- import { nextTick, ref } from "vue";
3
+ import { nextTick } from "vue";
4
4
  import ChatPanel from "../app/components/ChatPanel.vue";
5
5
  import {
6
- ASSISTANT_SESSION_KEY,
7
- type AssistantSession,
8
- } from "../app/runtime/assistant-session";
9
- import type { ChannelStatus } from "../app/runtime/channel-client";
10
- import {
11
- type ChatTransportHub,
12
- createChatTransport,
13
- } from "../app/runtime/chat-transport";
14
- import { resetPrefsForTesting } from "../app/runtime/overlay-prefs";
15
- import { createChatPanelState } from "../app/runtime/panel-state";
16
- import type { SidecarStatus } from "../app/runtime/sidecar-status";
6
+ CONVERSATION_ID,
7
+ createHarness,
8
+ deliver,
9
+ openPanel,
10
+ sendMessage,
11
+ sentOfType,
12
+ unmountPanel,
13
+ providedSession,
14
+ } from "./support/panel-harness";
15
+ import { PANEL_STUBS } from "./support/stubs";
17
16
 
18
- const CONVERSATION_ID = "conv-native-1";
19
17
  const STALL_AFTER_MS = 20_000;
20
18
 
21
- interface Harness {
22
- session: AssistantSession;
23
- hub: ChatTransportHub;
24
- sent: Array<Record<string, unknown>>;
25
- reconnects: number;
26
- sidecarStatus: ReturnType<typeof ref<SidecarStatus>>;
27
- setChannelStatus: (status: ChannelStatus) => void;
28
- navigate: ReturnType<typeof vi.fn>;
29
- }
30
-
31
- function createHarness(): Harness {
32
- let channelStatus: ChannelStatus = "connected";
33
- const harness = {
34
- sent: [] as Array<Record<string, unknown>>,
35
- reconnects: 0,
36
- sidecarStatus: ref<SidecarStatus>("connected"),
37
- navigate: vi.fn(),
38
- } as Harness;
39
- harness.hub = createChatTransport({
40
- send: (msg) => {
41
- if (channelStatus !== "connected") return false;
42
- harness.sent.push(msg as Record<string, unknown>);
43
- return true;
44
- },
45
- reconnect: () => {
46
- harness.reconnects += 1;
47
- },
48
- getStatus: () => channelStatus,
49
- });
50
- harness.setChannelStatus = (status) => {
51
- channelStatus = status;
52
- harness.hub.announceStatus(status);
53
- };
54
- harness.session = {
55
- status: harness.sidecarStatus,
56
- chat: harness.hub.transport,
57
- panel: createChatPanelState(),
58
- navigate: harness.navigate,
59
- };
60
- return harness;
61
- }
62
-
63
- let wrapper: VueWrapper | null = null;
64
-
65
- function mountPanel(harness: Harness): VueWrapper {
66
- wrapper = mount(ChatPanel, {
67
- attachTo: document.body,
68
- global: {
69
- provide: { [ASSISTANT_SESSION_KEY as symbol]: harness.session },
70
- stubs: { UIcon: true, USelect: true },
71
- },
72
- });
73
- return wrapper;
74
- }
75
-
76
- async function openPanel(harness: Harness): Promise<VueWrapper> {
77
- const mounted = mountPanel(harness);
78
- harness.session.panel.toggle();
79
- await nextTick();
80
- await flushPromises();
81
- return mounted;
82
- }
83
-
84
- function deliver(harness: Harness, event: Record<string, unknown>): void {
85
- harness.hub.deliver({ conversationId: CONVERSATION_ID, ...event });
86
- }
87
-
88
- async function sendMessage(panel: VueWrapper, text: string): Promise<void> {
89
- await panel.find("textarea").setValue(text);
90
- await panel.find("form.composer").trigger("submit");
91
- }
92
-
93
- function sentOfType(harness: Harness, type: string) {
94
- return harness.sent.filter((msg) => msg.type === type);
95
- }
96
-
97
19
  beforeEach(() => {
98
20
  localStorage.setItem("dms-ai-conversation-id", CONVERSATION_ID);
99
21
  });
100
22
 
101
23
  afterEach(() => {
102
- wrapper?.unmount();
103
- wrapper = null;
104
- resetPrefsForTesting();
24
+ unmountPanel();
105
25
  localStorage.clear();
106
26
  vi.useRealTimers();
107
27
  });
@@ -111,7 +31,9 @@ describe("the chat as a component of the dashboard", () => {
111
31
  const harness = createHarness();
112
32
  const panel = await openPanel(harness);
113
33
  expect(document.querySelector("iframe")).toBeNull();
114
- expect(document.getElementById("dms-ai-overlay-root")).not.toBeNull();
34
+ expect(panel.find("[data-dms-side-panel] .dms-ai-panel").exists()).toBe(
35
+ true,
36
+ );
115
37
  expect(panel.find(".chat-view").exists()).toBe(true);
116
38
  expect(Reflect.has(globalThis, "dmsAiChatTransport")).toBe(false);
117
39
  });
@@ -124,13 +46,26 @@ describe("the chat as a component of the dashboard", () => {
124
46
  ]);
125
47
  });
126
48
 
127
- it("keeps its conversation when the panel is closed and opened again", async () => {
49
+ it("leaves its conversation when the panel closes, and picks it up again when it opens", async () => {
128
50
  const harness = createHarness();
129
51
  const panel = await openPanel(harness);
130
52
  await sendMessage(panel, "build me a page");
131
53
  harness.session.panel.close();
132
54
  await nextTick();
55
+ expect(panel.find(".chat-view").exists()).toBe(false);
56
+ expect(sentOfType(harness, "leave_conversation")).toEqual([
57
+ { type: "leave_conversation", conversationId: CONVERSATION_ID },
58
+ ]);
133
59
  harness.session.panel.toggle();
60
+ await flushPromises();
61
+ expect(sentOfType(harness, "hello")).toEqual([
62
+ { type: "hello", role: "chat", conversationId: CONVERSATION_ID },
63
+ { type: "hello", role: "chat", conversationId: CONVERSATION_ID },
64
+ ]);
65
+ deliver(harness, {
66
+ type: "conversation_snapshot",
67
+ messages: [{ role: "user", content: "build me a page", timestampMs: 1 }],
68
+ });
134
69
  await nextTick();
135
70
  expect(panel.text()).toContain("build me a page");
136
71
  });
@@ -138,61 +73,68 @@ describe("the chat as a component of the dashboard", () => {
138
73
  it("opens the settings page through the dashboard router, not the sidecar", async () => {
139
74
  const harness = createHarness();
140
75
  const panel = await openPanel(harness);
141
- await panel.find('button[aria-label="Settings"]').trigger("click");
76
+ const settings = panel
77
+ .findAll(".u-dropdown-item")
78
+ .find((item) => item.text() === "Settings");
79
+ await settings?.trigger("click");
142
80
  expect(harness.navigate).toHaveBeenCalledExactlyOnceWith(
143
81
  "/modules/ai/settings",
144
82
  );
145
83
  expect(sentOfType(harness, "request_host_navigate")).toEqual([]);
146
84
  });
147
85
 
148
- it("closes from its own button, and on a click elsewhere in the dashboard", async () => {
86
+ it("asks for the conversation list again once a stream that was down connects", async () => {
87
+ const harness = createHarness();
88
+ harness.setChannelStatus("connecting");
89
+ await openPanel(harness);
90
+ expect(sentOfType(harness, "list_conversations")).toEqual([]);
91
+ harness.setChannelStatus("connected");
92
+ await nextTick();
93
+ expect(sentOfType(harness, "list_conversations")).toHaveLength(1);
94
+ });
95
+
96
+ it("closes from its own button, and stays open on a click elsewhere: docked, it is part of the page", async () => {
149
97
  const harness = createHarness();
150
98
  const panel = await openPanel(harness);
151
- panel
152
- .find(".chat-view")
153
- .element.dispatchEvent(
154
- new PointerEvent("pointerdown", { bubbles: true, composed: true }),
155
- );
156
- expect(harness.session.panel.isOpen.value).toBe(true);
157
99
  document.body.dispatchEvent(
158
100
  new PointerEvent("pointerdown", { bubbles: true, composed: true }),
159
101
  );
160
- expect(harness.session.panel.isOpen.value).toBe(false);
161
- harness.session.panel.toggle();
162
- await nextTick();
102
+ expect(harness.session.panel.isOpen.value).toBe(true);
163
103
  await panel.find('button[aria-label="Close"]').trigger("click");
164
104
  expect(harness.session.panel.isOpen.value).toBe(false);
165
105
  });
166
106
 
167
- it("stays open on a click in what the dashboard portals out of the app", async () => {
168
- const harness = createHarness();
169
- await openPanel(harness);
170
- const overlays = document.createElement("div");
171
- overlays.id = "dms-overlays";
172
- const toast = document.createElement("button");
173
- overlays.append(toast);
174
- document.body.append(overlays);
175
- toast.dispatchEvent(
176
- new PointerEvent("pointerdown", { bubbles: true, composed: true }),
107
+ it("shows the first connection while the session is not there yet", async () => {
108
+ const panel = mount(ChatPanel, {
109
+ global: { provide: providedSession(null), stubs: PANEL_STUBS },
110
+ });
111
+ await nextTick();
112
+ expect(panel.find(".dms-ai-panel-status").text()).toContain(
113
+ "Connecting the assistant",
177
114
  );
178
- expect(harness.session.panel.isOpen.value).toBe(true);
179
- overlays.remove();
115
+ expect(panel.find(".chat-view").exists()).toBe(false);
116
+ panel.unmount();
180
117
  });
181
118
 
182
- it("covers the chat with the sidecar status while it is not reachable, and can still be closed", async () => {
119
+ it("keeps the transcript under a banner while the sidecar revives, and offers a restart once it gave up", async () => {
183
120
  const harness = createHarness();
121
+ harness.lastError.value = "EADDRINUSE: port 5010 is already in use";
184
122
  const panel = await openPanel(harness);
185
123
  harness.sidecarStatus.value = "reviving";
186
124
  await nextTick();
187
- expect(panel.find(".dms-ai-panel-status").text()).toContain(
188
- "Reconnecting the assistant",
189
- );
125
+ expect(panel.find(".dms-ai-panel-status").exists()).toBe(false);
126
+ expect(panel.find(".connection-banner").text()).toContain("restarting");
190
127
  harness.sidecarStatus.value = "unavailable";
191
128
  await nextTick();
192
- expect(panel.find(".dms-ai-panel-status").text()).toContain(
193
- "Assistant unavailable",
194
- );
195
- await panel.find(".dms-ai-panel-status button").trigger("click");
129
+ const screen = panel.find(".dms-ai-panel-status");
130
+ expect(screen.text()).toContain("The assistant isn't running");
131
+ expect(screen.text()).toContain("EADDRINUSE");
132
+ const restart = screen
133
+ .findAll("button")
134
+ .find((button) => button.text() === "Restart assistant");
135
+ await restart?.trigger("click");
136
+ expect(harness.restart).toHaveBeenCalledOnce();
137
+ await screen.find('button[aria-label="Close"]').trigger("click");
196
138
  expect(harness.session.panel.isOpen.value).toBe(false);
197
139
  harness.sidecarStatus.value = "connected";
198
140
  await nextTick();
@@ -271,7 +213,7 @@ describe("a running turn shows what it is doing, and never spins forever", () =>
271
213
  expect(panel.find(".thinking").exists()).toBe(true);
272
214
  });
273
215
 
274
- it("shows a run error with Retry, which sends the message again", async () => {
216
+ it("shows a run error with Retry turn, which asks the sidecar to run it again", async () => {
275
217
  const harness = createHarness();
276
218
  const panel = await openPanel(harness);
277
219
  await sendMessage(panel, "reproduce this page");
@@ -279,8 +221,11 @@ describe("a running turn shows what it is doing, and never spins forever", () =>
279
221
  await nextTick();
280
222
  const error = panel.find(".message-bubble-error");
281
223
  expect(error.text()).toContain("API Error: 529 overloaded");
282
- await error.find("button").trigger("click");
283
- expect(sentOfType(harness, "user_message")).toHaveLength(2);
224
+ const retry = error
225
+ .findAll("button")
226
+ .find((button) => button.text() === "Retry turn");
227
+ await retry?.trigger("click");
228
+ expect(sentOfType(harness, "retry_turn")).toHaveLength(1);
284
229
  });
285
230
 
286
231
  it("offers no Retry for a run error that sending again cannot fix", async () => {
@@ -295,7 +240,7 @@ describe("a running turn shows what it is doing, and never spins forever", () =>
295
240
  await nextTick();
296
241
  const error = panel.find(".message-bubble-error");
297
242
  expect(error.text()).toContain("Prompt is too long");
298
- expect(error.find("button").exists()).toBe(false);
243
+ expect(error.text()).not.toContain("Retry turn");
299
244
  });
300
245
 
301
246
  it("says a message was not sent when the stream dropped as it left", async () => {
@@ -333,7 +278,9 @@ describe("the shared stream going away and coming back", () => {
333
278
  const panel = await openPanel(harness);
334
279
  harness.setChannelStatus("reconnecting");
335
280
  await nextTick();
336
- expect(panel.find(".connection-banner").text()).toContain("Reconnecting");
281
+ expect(panel.find(".connection-banner").text()).toContain(
282
+ "Connection lost",
283
+ );
337
284
  expect(panel.find("textarea").attributes("disabled")).toBeDefined();
338
285
  harness.setChannelStatus("connected");
339
286
  harness.hub.announceReady();
@@ -0,0 +1,118 @@
1
+ import { readdirSync, readFileSync, statSync } from "node:fs";
2
+ import { join, resolve } from "node:path";
3
+ import { describe, expect, it } from "vitest";
4
+ import { TOOL_VERB_KEYS } from "../app/chat/utils/tool-lexicon";
5
+ import en from "../i18n/locales/dms-ai-panel-en-GB.json";
6
+ import fr from "../i18n/locales/dms-ai-panel-fr-FR.json";
7
+
8
+ type Tree = Record<string, unknown>;
9
+
10
+ const ROOT = resolve(__dirname, "..");
11
+ const SOURCES = [
12
+ "app/chat",
13
+ "app/runtime",
14
+ "app/plugins",
15
+ "app/components/ChatPanel.vue",
16
+ ];
17
+ const LITERAL_KEY =
18
+ /["'`](dms_ai\.(?:panel|tools|common)\.[A-Za-z0-9_.]+[A-Za-z0-9_])["'`]/g;
19
+ const OWNED_NAMESPACES = ["panel", "tools", "common"];
20
+
21
+ /** Keys built at run time from a value, each with every value it can take. */
22
+ const DYNAMIC_FAMILIES: Record<string, readonly string[]> = {
23
+ "dms_ai.panel.tool.state": [
24
+ "done",
25
+ "running",
26
+ "waiting",
27
+ "denied",
28
+ "blocked",
29
+ "failed",
30
+ "stopped",
31
+ ],
32
+ "dms_ai.panel.change.status": ["added", "modified", "deleted"],
33
+ "dms_ai.panel.change.typecheck": ["passed", "failed", "skipped"],
34
+ "dms_ai.common.scope": ["safe", "vibe"],
35
+ "dms_ai.common.agent": ["claude", "codex"],
36
+ "dms_ai.panel.composer.scope_desc": ["safe", "vibe"],
37
+ "dms_ai.panel.full_auto": [
38
+ "duration_turn",
39
+ "duration_30m",
40
+ "duration_chat",
41
+ "banner_turn",
42
+ "banner_30m",
43
+ "banner_chat",
44
+ ],
45
+ "dms_ai.panel.drawer": [
46
+ "group_active",
47
+ "group_today",
48
+ "group_week",
49
+ "group_older",
50
+ ],
51
+ "dms_ai.panel.empty": ["text_safe", "text_vibe"],
52
+ "dms_ai.panel.approvals": [
53
+ "why_deletes_data",
54
+ "why_removes_code",
55
+ "effect_adds_dependency",
56
+ "effect_removes_dependency",
57
+ ],
58
+ "dms_ai.panel.rules": [
59
+ "kind_file",
60
+ "kind_directory",
61
+ "kind_command",
62
+ "kind_domain",
63
+ ],
64
+ };
65
+
66
+ function files(path: string): string[] {
67
+ const full = join(ROOT, path);
68
+ if (!statSync(full).isDirectory()) return [full];
69
+ return readdirSync(full).flatMap((entry) => files(join(path, entry)));
70
+ }
71
+
72
+ function flatten(tree: Tree, prefix = ""): string[] {
73
+ return Object.entries(tree).flatMap(([key, value]) =>
74
+ value !== null && typeof value === "object"
75
+ ? flatten(value as Tree, `${prefix}${key}.`)
76
+ : [`${prefix}${key}`],
77
+ );
78
+ }
79
+
80
+ function usedKeys(): string[] {
81
+ const source = SOURCES.flatMap(files)
82
+ .map((file) => readFileSync(file, "utf8"))
83
+ .join("\n");
84
+ return [
85
+ ...new Set([...source.matchAll(LITERAL_KEY)].map((match) => match[1])),
86
+ ];
87
+ }
88
+
89
+ const dynamicKeys = Object.entries(DYNAMIC_FAMILIES).flatMap(
90
+ ([prefix, values]) => values.map((value) => `${prefix}.${value}`),
91
+ );
92
+
93
+ describe("the panel's strings", () => {
94
+ const english = new Set(flatten(en));
95
+ const french = new Set(flatten(fr));
96
+
97
+ it("exist in English and French alike", () => {
98
+ expect([...english].sort()).toEqual([...french].sort());
99
+ });
100
+
101
+ it("cover every key the panel uses", () => {
102
+ const keys = [
103
+ ...usedKeys(),
104
+ ...dynamicKeys,
105
+ ...TOOL_VERB_KEYS.map((verb) => `dms_ai.tools.${verb}`),
106
+ ];
107
+ expect(keys.filter((key) => !english.has(key))).toEqual([]);
108
+ });
109
+
110
+ it("stay in the panel's own namespaces", () => {
111
+ expect(Object.keys(en.dms_ai).sort()).toEqual([...OWNED_NAMESPACES].sort());
112
+ });
113
+
114
+ it("hold no character vue-i18n would read as syntax", () => {
115
+ const texts = [JSON.stringify(en), JSON.stringify(fr)];
116
+ for (const text of texts) expect(text).not.toMatch(/[@$]/);
117
+ });
118
+ });
@@ -0,0 +1,220 @@
1
+ import { flushPromises, mount, type VueWrapper } from "@vue/test-utils";
2
+ import { afterEach, describe, expect, it, vi } from "vitest";
3
+ import { nextTick, ref } from "vue";
4
+ import PaletteAnswer from "../app/components/PaletteAnswer.vue";
5
+ import type { CurrentPage } from "../app/chat/types/conversation";
6
+ import {
7
+ assistantSidePanel,
8
+ launcherAction,
9
+ paletteAssistant,
10
+ } from "../app/runtime/assistant-commands";
11
+ import {
12
+ createHarness,
13
+ type Harness,
14
+ providedSession,
15
+ sentOfType,
16
+ } from "./support/panel-harness";
17
+ import { createTestI18n } from "./support/i18n";
18
+ import { PANEL_STUBS } from "./support/stubs";
19
+
20
+ const PROMPT = "What does this page show?";
21
+
22
+ let answer: VueWrapper | null = null;
23
+
24
+ afterEach(() => {
25
+ answer?.unmount();
26
+ answer = null;
27
+ localStorage.clear();
28
+ });
29
+
30
+ function askFromPalette(harness: Harness, close = vi.fn()): VueWrapper {
31
+ answer = mount(PaletteAnswer, {
32
+ props: { prompt: PROMPT, close },
33
+ global: { provide: providedSession(harness.session), stubs: PANEL_STUBS },
34
+ });
35
+ return answer;
36
+ }
37
+
38
+ function paletteConversation(harness: Harness): string {
39
+ const hello = sentOfType(harness, "hello")[0];
40
+ return String(hello?.conversationId);
41
+ }
42
+
43
+ function deliverToPalette(
44
+ harness: Harness,
45
+ event: Record<string, unknown>,
46
+ ): void {
47
+ harness.hub.deliver({
48
+ conversationId: paletteConversation(harness),
49
+ ...event,
50
+ });
51
+ }
52
+
53
+ describe("the assistant's registrations in the dashboard", () => {
54
+ it("docks the panel by id, and lets the DMS toggle it from the launcher", () => {
55
+ const { t } = createTestI18n();
56
+ const panel = assistantSidePanel();
57
+ expect(panel).toMatchObject({
58
+ id: "dms-ai:assistant",
59
+ component: "DmsAiChatPanel",
60
+ ariaLabel: "$dms_ai.panel.launcher",
61
+ });
62
+ expect(panel.minWidth).toBeLessThan(panel.defaultWidth);
63
+ expect(panel.defaultWidth).toBeLessThan(panel.maxWidth);
64
+ const launcher = launcherAction(t);
65
+ expect(launcher.sidePanelId).toBe(panel.id);
66
+ expect(launcher).not.toHaveProperty("onSelect");
67
+ expect(launcher).not.toHaveProperty("isActive");
68
+ });
69
+
70
+ it("offers the palette prompts that fit the page on screen", () => {
71
+ const { t } = createTestI18n();
72
+ const page = ref<CurrentPage | null>({
73
+ path: "/sales/overview",
74
+ title: "Sales overview · DMS",
75
+ });
76
+ const assistant = paletteAssistant(t, page);
77
+ expect(assistant).toMatchObject({
78
+ id: "dms-ai:assistant",
79
+ answerComponent: "DmsAiPaletteAnswer",
80
+ label: "$dms_ai.panel.palette.assistant",
81
+ placeholder: "$dms_ai.panel.palette.placeholder",
82
+ });
83
+ expect(assistant.suggestions().map((item) => item.label)).toEqual([
84
+ "Explain what Sales overview shows",
85
+ "Add a chart to Sales overview",
86
+ "Add a filter to the table on Sales overview",
87
+ ]);
88
+ page.value = { path: "/home", title: "Home" };
89
+ expect(assistant.suggestions().map((item) => item.label)).toContain(
90
+ "Explain how this project is organised",
91
+ );
92
+ });
93
+ });
94
+
95
+ describe("an answer in the command palette", () => {
96
+ it("asks read-only, in a conversation of its own it follows next to the panel's", async () => {
97
+ const harness = createHarness();
98
+ askFromPalette(harness);
99
+ await flushPromises();
100
+ const conversationId = paletteConversation(harness);
101
+ expect(sentOfType(harness, "hello")).toEqual([
102
+ { type: "hello", role: "chat", conversationId, follow: true },
103
+ ]);
104
+ expect(sentOfType(harness, "set_conversation_mode")).toEqual([
105
+ {
106
+ type: "set_conversation_mode",
107
+ conversationId,
108
+ mode: "plan",
109
+ generationMode: "safe",
110
+ },
111
+ ]);
112
+ expect(sentOfType(harness, "user_message")).toMatchObject([
113
+ { conversationId, content: PROMPT },
114
+ ]);
115
+ expect(harness.streamHolds).toBe(1);
116
+ });
117
+
118
+ it("waits for the stream before it asks", async () => {
119
+ const harness = createHarness();
120
+ harness.setChannelStatus("connecting");
121
+ askFromPalette(harness);
122
+ await flushPromises();
123
+ expect(sentOfType(harness, "user_message")).toEqual([]);
124
+ harness.setChannelStatus("connected");
125
+ harness.hub.announceReady();
126
+ await flushPromises();
127
+ expect(sentOfType(harness, "user_message")).toHaveLength(1);
128
+ expect(sentOfType(harness, "hello")[0]).toMatchObject({ follow: true });
129
+ });
130
+
131
+ it("streams the answer, and ignores the panel's conversation", async () => {
132
+ const harness = createHarness();
133
+ const view = askFromPalette(harness);
134
+ await flushPromises();
135
+ harness.hub.deliver({
136
+ conversationId: "conv-of-the-panel",
137
+ type: "assistant_message_chunk",
138
+ text: "not for the palette",
139
+ });
140
+ deliverToPalette(harness, {
141
+ type: "assistant_message_chunk",
142
+ text: "It lists the **sales** of the quarter.",
143
+ });
144
+ deliverToPalette(harness, { type: "run_done" });
145
+ await flushPromises();
146
+ expect(view.text()).toContain("It lists the sales of the quarter.");
147
+ expect(view.text()).not.toContain("not for the palette");
148
+ expect(view.text()).not.toContain(PROMPT);
149
+ });
150
+
151
+ it("continues in the assistant: the panel opens on that conversation and the turn keeps running", async () => {
152
+ const harness = createHarness();
153
+ const close = vi.fn();
154
+ const view = askFromPalette(harness, close);
155
+ await flushPromises();
156
+ const conversationId = paletteConversation(harness);
157
+ const button = view
158
+ .findAll("button")
159
+ .find((item) => item.text() === "Continue in the assistant");
160
+ await button?.trigger("click");
161
+ expect(close).toHaveBeenCalledOnce();
162
+ expect(harness.session.panel.isOpen.value).toBe(true);
163
+ expect(harness.session.intents.pending.value).toEqual({
164
+ kind: "open",
165
+ conversationId,
166
+ });
167
+ view.unmount();
168
+ answer = null;
169
+ expect(sentOfType(harness, "interrupt_turn")).toEqual([]);
170
+ expect(harness.streamHolds).toBe(0);
171
+ });
172
+
173
+ it("stops its turn when the palette closes on it, and lets the stream go", async () => {
174
+ const harness = createHarness();
175
+ const view = askFromPalette(harness);
176
+ await flushPromises();
177
+ const conversationId = paletteConversation(harness);
178
+ view.unmount();
179
+ answer = null;
180
+ expect(sentOfType(harness, "interrupt_turn")).toEqual([
181
+ { type: "interrupt_turn", conversationId },
182
+ ]);
183
+ expect(harness.streamHolds).toBe(0);
184
+ });
185
+
186
+ it("says when the agent waits for the user, who answers in the assistant", async () => {
187
+ const harness = createHarness();
188
+ const view = askFromPalette(harness);
189
+ await flushPromises();
190
+ deliverToPalette(harness, {
191
+ type: "ask_question",
192
+ requestId: "q1",
193
+ questions: [
194
+ {
195
+ header: "Scope",
196
+ question: "Which table?",
197
+ options: [{ label: "Orders" }, { label: "Customers" }],
198
+ multiSelect: false,
199
+ },
200
+ ],
201
+ createdAtMs: Date.now(),
202
+ expiresAtMs: Date.now() + 60_000,
203
+ });
204
+ await nextTick();
205
+ expect(view.find('[role="alert"]').text()).toContain(
206
+ "The assistant is waiting for you",
207
+ );
208
+ });
209
+
210
+ it("says the assistant does not run in this tab without a session", () => {
211
+ answer = mount(PaletteAnswer, {
212
+ props: { prompt: PROMPT, close: vi.fn() },
213
+ global: { provide: providedSession(null), stubs: PANEL_STUBS },
214
+ });
215
+ expect(answer.text()).toContain("isn't running in this tab");
216
+ expect(answer.findAll("button").map((button) => button.text())).toEqual([
217
+ "Close",
218
+ ]);
219
+ });
220
+ });