@antelopejs/dms-ai 0.6.1 → 0.8.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 (360) hide show
  1. package/README.md +17 -7
  2. package/dist/builder/presence.js.map +1 -1
  3. package/dist/channels/bridge.js +4 -2
  4. package/dist/channels/bridge.js.map +1 -1
  5. package/dist/channels/sse-stream.d.ts +1 -1
  6. package/dist/config.d.ts +6 -1
  7. package/dist/config.js +9 -21
  8. package/dist/config.js.map +1 -1
  9. package/dist/constants/channels.d.ts +5 -1
  10. package/dist/constants/channels.js.map +1 -1
  11. package/dist/index.js +1 -1
  12. package/dist/index.js.map +1 -1
  13. package/dist/lifecycle/build-id.js +1 -1
  14. package/dist/lifecycle/build-id.js.map +1 -1
  15. package/dist/lifecycle/module-roots.js +12 -14
  16. package/dist/lifecycle/module-roots.js.map +1 -1
  17. package/dist/lifecycle/sidecar-owner.js.map +1 -1
  18. package/dist/lifecycle/skill-sources.js +45 -32
  19. package/dist/lifecycle/skill-sources.js.map +1 -1
  20. package/dist/lifecycle/spawn-sidecar.js +11 -6
  21. package/dist/lifecycle/spawn-sidecar.js.map +1 -1
  22. package/dist/logging/log-buffer.js +6 -2
  23. package/dist/logging/log-buffer.js.map +1 -1
  24. package/dist/pages/activity/columns.d.ts +66 -2
  25. package/dist/pages/activity/columns.js.map +1 -1
  26. package/dist/pages/activity/page.js.map +1 -1
  27. package/dist/pages/index.js.map +1 -1
  28. package/dist/pages/overview/page.js.map +1 -1
  29. package/dist/pages/overview/recent-changes.js.map +1 -1
  30. package/dist/pages/settings/availability.js.map +1 -1
  31. package/dist/pages/skills/page.js.map +1 -1
  32. package/dist/pages-registry.js +9 -10
  33. package/dist/pages-registry.js.map +1 -1
  34. package/dist/routes/activity.d.ts +5 -4
  35. package/dist/routes/activity.js.map +1 -1
  36. package/dist/routes/builder.d.ts +7 -1
  37. package/dist/routes/builder.js.map +1 -1
  38. package/dist/routes/changes.d.ts +11 -8
  39. package/dist/routes/changes.js.map +1 -1
  40. package/dist/routes/codex-account.d.ts +7 -2
  41. package/dist/routes/codex-account.js +2 -2
  42. package/dist/routes/codex-account.js.map +1 -1
  43. package/dist/routes/database.d.ts +21 -4
  44. package/dist/routes/database.js.map +1 -1
  45. package/dist/routes/metric-shapes.js +8 -5
  46. package/dist/routes/metric-shapes.js.map +1 -1
  47. package/dist/routes/metrics.d.ts +4 -2
  48. package/dist/routes/metrics.js +2 -2
  49. package/dist/routes/metrics.js.map +1 -1
  50. package/dist/routes/pages-registry.js.map +1 -1
  51. package/dist/routes/settings.d.ts +3 -2
  52. package/dist/routes/settings.js.map +1 -1
  53. package/dist/routes/sidecar-info.js.map +1 -1
  54. package/dist/routes/sidecar-results.d.ts +4 -4
  55. package/dist/routes/sidecar-results.js +10 -10
  56. package/dist/routes/sidecar-results.js.map +1 -1
  57. package/dist/routes/skills.d.ts +2 -1
  58. package/dist/routes/skills.js +6 -4
  59. package/dist/routes/skills.js.map +1 -1
  60. package/dist/routes/status-shapes.js +12 -12
  61. package/dist/routes/status-shapes.js.map +1 -1
  62. package/dist/routes/status.js.map +1 -1
  63. package/dist/routes/undo-confirm.js.map +1 -1
  64. package/dist/sidecar/http-client.js +3 -1
  65. package/dist/sidecar/http-client.js.map +1 -1
  66. package/dist/sidecar/index.d.ts +1 -0
  67. package/dist/sidecar/index.js +1 -0
  68. package/dist/sidecar/index.js.map +1 -1
  69. package/dist/sidecar/json-body.d.ts +4 -0
  70. package/dist/sidecar/json-body.js +33 -0
  71. package/dist/sidecar/json-body.js.map +1 -0
  72. package/dist/sidecar/settings-values.d.ts +5 -2
  73. package/dist/sidecar/settings-values.js.map +1 -1
  74. package/dist/vocabulary/tools.js.map +1 -1
  75. package/frontend-vue/app/chat/components/ChatView.vue +33 -133
  76. package/frontend-vue/app/chat/components/ProviderNotice.vue +77 -0
  77. package/frontend-vue/app/chat/components/UndoConflictModal.vue +98 -0
  78. package/frontend-vue/app/chat/composables/useChangeSetActions.ts +1 -1
  79. package/frontend-vue/app/components/SkillDetail.vue +1 -1
  80. package/frontend-vue/app/plugins/ai.client.ts +10 -2
  81. package/frontend-vue/app/runtime/assistant-actions.ts +41 -0
  82. package/frontend-vue/app/runtime/assistant-session.ts +8 -2
  83. package/frontend-vue/app/runtime/panel-intents.ts +3 -1
  84. package/frontend-vue/app/views/ChangeSetPanel.vue +1 -1
  85. package/frontend-vue/app/views/composables/useAiData.ts +10 -18
  86. package/frontend-vue/app/views/composables/useChangeSetActions.ts +5 -15
  87. package/frontend-vue/app/views/constants.ts +1 -1
  88. package/frontend-vue/app/views/types.ts +1 -1
  89. package/frontend-vue/build/backend-boundary.ts +122 -0
  90. package/frontend-vue/dms.frontend.build.ts +6 -0
  91. package/frontend-vue/package.json +2 -1
  92. package/frontend-vue/pnpm-lock.yaml +3 -0
  93. package/frontend-vue/tests/assistant-actions.test.ts +72 -0
  94. package/frontend-vue/tests/backend-boundary.test.ts +130 -0
  95. package/frontend-vue/tests/panel-approvals.test.ts +190 -0
  96. package/frontend-vue/tests/panel-questions.test.ts +169 -0
  97. package/frontend-vue/tests/panel-states.test.ts +1 -556
  98. package/frontend-vue/tests/panel-tools.test.ts +165 -0
  99. package/frontend-vue/tests/sidecar-guest.test.ts +39 -71
  100. package/frontend-vue/tests/support/api-error-presenter.ts +28 -0
  101. package/frontend-vue/tests/support/panel-fixtures.ts +110 -0
  102. package/frontend-vue/tests/support/panel-harness.ts +2 -2
  103. package/frontend-vue/tests/views/api-data-reads.test.ts +2 -0
  104. package/frontend-vue/tests/views/api-error-presentation.test.ts +89 -0
  105. package/frontend-vue/vitest.config.ts +2 -1
  106. package/package.json +21 -9
  107. package/sidecar/dist/agent/attachment-files.js.map +1 -1
  108. package/sidecar/dist/agent/call-ledger.d.ts +3 -2
  109. package/sidecar/dist/agent/call-ledger.js +1 -1
  110. package/sidecar/dist/agent/call-ledger.js.map +1 -1
  111. package/sidecar/dist/agent/command-analysis.js +13 -14
  112. package/sidecar/dist/agent/command-analysis.js.map +1 -1
  113. package/sidecar/dist/agent/conversation-modes.js.map +1 -1
  114. package/sidecar/dist/agent/edit-targets.d.ts +5 -1
  115. package/sidecar/dist/agent/edit-targets.js +8 -6
  116. package/sidecar/dist/agent/edit-targets.js.map +1 -1
  117. package/sidecar/dist/agent/edit-tracker.d.ts +2 -1
  118. package/sidecar/dist/agent/edit-tracker.js +3 -4
  119. package/sidecar/dist/agent/edit-tracker.js.map +1 -1
  120. package/sidecar/dist/agent/effective-mode.js.map +1 -1
  121. package/sidecar/dist/agent/line-diff.js +10 -8
  122. package/sidecar/dist/agent/line-diff.js.map +1 -1
  123. package/sidecar/dist/agent/permission-bus.js +2 -1
  124. package/sidecar/dist/agent/permission-bus.js.map +1 -1
  125. package/sidecar/dist/agent/permission-preview.d.ts +1 -1
  126. package/sidecar/dist/agent/permission-preview.js +54 -37
  127. package/sidecar/dist/agent/permission-preview.js.map +1 -1
  128. package/sidecar/dist/agent/permission-rules.js +4 -6
  129. package/sidecar/dist/agent/permission-rules.js.map +1 -1
  130. package/sidecar/dist/agent/provider.d.ts +2 -1
  131. package/sidecar/dist/agent/question-bus.js.map +1 -1
  132. package/sidecar/dist/agent/read-access.d.ts +2 -1
  133. package/sidecar/dist/agent/read-access.js +4 -7
  134. package/sidecar/dist/agent/read-access.js.map +1 -1
  135. package/sidecar/dist/agent/runner.js.map +1 -1
  136. package/sidecar/dist/agent/session.js +2 -6
  137. package/sidecar/dist/agent/session.js.map +1 -1
  138. package/sidecar/dist/agent/switching-runner.js.map +1 -1
  139. package/sidecar/dist/agent/system-prompt.js.map +1 -1
  140. package/sidecar/dist/agent/tool-summary.d.ts +2 -1
  141. package/sidecar/dist/agent/tool-summary.js +26 -13
  142. package/sidecar/dist/agent/tool-summary.js.map +1 -1
  143. package/sidecar/dist/agent/typecheck.d.ts +1 -4
  144. package/sidecar/dist/agent/typecheck.js +3 -2
  145. package/sidecar/dist/agent/typecheck.js.map +1 -1
  146. package/sidecar/dist/audit/activity-query.js +4 -8
  147. package/sidecar/dist/audit/activity-query.js.map +1 -1
  148. package/sidecar/dist/audit/activity-target.d.ts +4 -2
  149. package/sidecar/dist/audit/activity-target.js +10 -9
  150. package/sidecar/dist/audit/activity-target.js.map +1 -1
  151. package/sidecar/dist/audit/activity.js +4 -3
  152. package/sidecar/dist/audit/activity.js.map +1 -1
  153. package/sidecar/dist/audit/call-audit.js.map +1 -1
  154. package/sidecar/dist/builder/builder-client.d.ts +2 -1
  155. package/sidecar/dist/builder/builder-client.js +6 -8
  156. package/sidecar/dist/builder/builder-client.js.map +1 -1
  157. package/sidecar/dist/builder/capability.js.map +1 -1
  158. package/sidecar/dist/checkpoints/checkpoints.js.map +1 -1
  159. package/sidecar/dist/checkpoints/shadow-git.js +6 -2
  160. package/sidecar/dist/checkpoints/shadow-git.js.map +1 -1
  161. package/sidecar/dist/constants/agent.js.map +1 -1
  162. package/sidecar/dist/constants/attachments.js.map +1 -1
  163. package/sidecar/dist/constants/builder.js.map +1 -1
  164. package/sidecar/dist/constants/chatgpt.js.map +1 -1
  165. package/sidecar/dist/constants/checkpoints.d.ts +1 -1
  166. package/sidecar/dist/constants/checkpoints.js +6 -6
  167. package/sidecar/dist/constants/checkpoints.js.map +1 -1
  168. package/sidecar/dist/constants/claude.d.ts +3 -4
  169. package/sidecar/dist/constants/claude.js +16 -16
  170. package/sidecar/dist/constants/claude.js.map +1 -1
  171. package/sidecar/dist/constants/cli.js.map +1 -1
  172. package/sidecar/dist/constants/codex.d.ts +4 -5
  173. package/sidecar/dist/constants/codex.js +25 -25
  174. package/sidecar/dist/constants/codex.js.map +1 -1
  175. package/sidecar/dist/constants/database.js.map +1 -1
  176. package/sidecar/dist/constants/mcp.js.map +1 -1
  177. package/sidecar/dist/constants/paths.js.map +1 -1
  178. package/sidecar/dist/constants/project.d.ts +1 -1
  179. package/sidecar/dist/constants/project.js.map +1 -1
  180. package/sidecar/dist/constants/providers.js.map +1 -1
  181. package/sidecar/dist/constants/questions.js.map +1 -1
  182. package/sidecar/dist/constants/read-access.d.ts +1 -1
  183. package/sidecar/dist/constants/read-access.js +7 -7
  184. package/sidecar/dist/constants/read-access.js.map +1 -1
  185. package/sidecar/dist/constants/timing.js.map +1 -1
  186. package/sidecar/dist/database/database-client.d.ts +3 -2
  187. package/sidecar/dist/database/database-client.js +13 -9
  188. package/sidecar/dist/database/database-client.js.map +1 -1
  189. package/sidecar/dist/host/project-info.js +13 -7
  190. package/sidecar/dist/host/project-info.js.map +1 -1
  191. package/sidecar/dist/index.d.ts +1 -1
  192. package/sidecar/dist/index.js +60 -34
  193. package/sidecar/dist/index.js.map +1 -1
  194. package/sidecar/dist/logs/logs-client.js +13 -2
  195. package/sidecar/dist/logs/logs-client.js.map +1 -1
  196. package/sidecar/dist/logs/types.d.ts +2 -1
  197. package/sidecar/dist/mcp/define-tool.d.ts +9 -8
  198. package/sidecar/dist/mcp/define-tool.js.map +1 -1
  199. package/sidecar/dist/mcp/http-binding.js.map +1 -1
  200. package/sidecar/dist/mcp/tools/ask-user.js.map +1 -1
  201. package/sidecar/dist/mcp/tools/builder-catalog.d.ts +6 -1
  202. package/sidecar/dist/mcp/tools/builder-catalog.js +32 -24
  203. package/sidecar/dist/mcp/tools/builder-catalog.js.map +1 -1
  204. package/sidecar/dist/mcp/tools/builder-expr.d.ts +5 -0
  205. package/sidecar/dist/mcp/tools/builder-expr.js +25 -0
  206. package/sidecar/dist/mcp/tools/builder-expr.js.map +1 -0
  207. package/sidecar/dist/mcp/tools/builder-gate.js +2 -2
  208. package/sidecar/dist/mcp/tools/builder-gate.js.map +1 -1
  209. package/sidecar/dist/mcp/tools/builder-project.d.ts +2 -1
  210. package/sidecar/dist/mcp/tools/builder-project.js +60 -43
  211. package/sidecar/dist/mcp/tools/builder-project.js.map +1 -1
  212. package/sidecar/dist/mcp/tools/builder-queries.d.ts +34 -0
  213. package/sidecar/dist/mcp/tools/builder-queries.js +56 -0
  214. package/sidecar/dist/mcp/tools/builder-queries.js.map +1 -0
  215. package/sidecar/dist/mcp/tools/builder.d.ts +31 -19
  216. package/sidecar/dist/mcp/tools/builder.js +5 -72
  217. package/sidecar/dist/mcp/tools/builder.js.map +1 -1
  218. package/sidecar/dist/mcp/tools/database.js +5 -9
  219. package/sidecar/dist/mcp/tools/database.js.map +1 -1
  220. package/sidecar/dist/mcp/tools/find-pages-using.js.map +1 -1
  221. package/sidecar/dist/mcp/tools/get-current-page.js.map +1 -1
  222. package/sidecar/dist/mcp/tools/list-pages.js.map +1 -1
  223. package/sidecar/dist/mcp/tools/navigate-to-page.js +6 -6
  224. package/sidecar/dist/mcp/tools/navigate-to-page.js.map +1 -1
  225. package/sidecar/dist/mcp/tools/preview-blocks.js +15 -11
  226. package/sidecar/dist/mcp/tools/preview-blocks.js.map +1 -1
  227. package/sidecar/dist/mcp/tools/query-logs.js.map +1 -1
  228. package/sidecar/dist/mcp/tools/typecheck.js.map +1 -1
  229. package/sidecar/dist/mcp/types.d.ts +2 -1
  230. package/sidecar/dist/metrics/aggregate.js.map +1 -1
  231. package/sidecar/dist/metrics/types.js.map +1 -1
  232. package/sidecar/dist/pages/registry-client.js +14 -5
  233. package/sidecar/dist/pages/registry-client.js.map +1 -1
  234. package/sidecar/dist/pages/route-match.js.map +1 -1
  235. package/sidecar/dist/protocol/events.d.ts +7 -7
  236. package/sidecar/dist/protocol/events.js.map +1 -1
  237. package/sidecar/dist/protocol/json.d.ts +9 -0
  238. package/sidecar/dist/protocol/json.js +32 -0
  239. package/sidecar/dist/protocol/json.js.map +1 -0
  240. package/sidecar/dist/protocol/messages.d.ts +4 -4
  241. package/sidecar/dist/protocol/messages.js +3 -3
  242. package/sidecar/dist/protocol/messages.js.map +1 -1
  243. package/sidecar/dist/providers/claude/activity.d.ts +4 -2
  244. package/sidecar/dist/providers/claude/activity.js +29 -38
  245. package/sidecar/dist/providers/claude/activity.js.map +1 -1
  246. package/sidecar/dist/providers/claude/adapter.js +62 -91
  247. package/sidecar/dist/providers/claude/adapter.js.map +1 -1
  248. package/sidecar/dist/providers/claude/attachments.js +4 -4
  249. package/sidecar/dist/providers/claude/attachments.js.map +1 -1
  250. package/sidecar/dist/providers/claude/config.d.ts +4 -1
  251. package/sidecar/dist/providers/claude/config.js.map +1 -1
  252. package/sidecar/dist/providers/claude/module.js.map +1 -1
  253. package/sidecar/dist/providers/claude/provider.d.ts +4 -2
  254. package/sidecar/dist/providers/claude/provider.js.map +1 -1
  255. package/sidecar/dist/providers/claude/resolve-binary.js +6 -4
  256. package/sidecar/dist/providers/claude/resolve-binary.js.map +1 -1
  257. package/sidecar/dist/providers/claude/safe-mode.js +14 -3
  258. package/sidecar/dist/providers/claude/safe-mode.js.map +1 -1
  259. package/sidecar/dist/providers/codex/adapter.js +124 -46
  260. package/sidecar/dist/providers/codex/adapter.js.map +1 -1
  261. package/sidecar/dist/providers/codex/attachments.js +1 -1
  262. package/sidecar/dist/providers/codex/attachments.js.map +1 -1
  263. package/sidecar/dist/providers/codex/chatgpt/credentials.js.map +1 -1
  264. package/sidecar/dist/providers/codex/chatgpt/http.js +8 -5
  265. package/sidecar/dist/providers/codex/chatgpt/http.js.map +1 -1
  266. package/sidecar/dist/providers/codex/chatgpt/lock.js +3 -3
  267. package/sidecar/dist/providers/codex/chatgpt/lock.js.map +1 -1
  268. package/sidecar/dist/providers/codex/chatgpt/login.js.map +1 -1
  269. package/sidecar/dist/providers/codex/chatgpt/oauth.js +51 -8
  270. package/sidecar/dist/providers/codex/chatgpt/oauth.js.map +1 -1
  271. package/sidecar/dist/providers/codex/chatgpt/store.js +23 -23
  272. package/sidecar/dist/providers/codex/chatgpt/store.js.map +1 -1
  273. package/sidecar/dist/providers/codex/client.d.ts +4 -3
  274. package/sidecar/dist/providers/codex/client.js +10 -3
  275. package/sidecar/dist/providers/codex/client.js.map +1 -1
  276. package/sidecar/dist/providers/codex/config.js.map +1 -1
  277. package/sidecar/dist/providers/codex/module.js.map +1 -1
  278. package/sidecar/dist/providers/codex/permissions.d.ts +2 -2
  279. package/sidecar/dist/providers/codex/permissions.js +20 -6
  280. package/sidecar/dist/providers/codex/permissions.js.map +1 -1
  281. package/sidecar/dist/providers/codex/process.d.ts +3 -1
  282. package/sidecar/dist/providers/codex/process.js +35 -36
  283. package/sidecar/dist/providers/codex/process.js.map +1 -1
  284. package/sidecar/dist/providers/codex/provider.d.ts +2 -0
  285. package/sidecar/dist/providers/codex/provider.js +23 -7
  286. package/sidecar/dist/providers/codex/provider.js.map +1 -1
  287. package/sidecar/dist/providers/codex/resolve-binary.js +2 -2
  288. package/sidecar/dist/providers/codex/resolve-binary.js.map +1 -1
  289. package/sidecar/dist/providers/codex/stop.d.ts +6 -1
  290. package/sidecar/dist/providers/codex/stop.js +29 -22
  291. package/sidecar/dist/providers/codex/stop.js.map +1 -1
  292. package/sidecar/dist/providers/registry.js +4 -5
  293. package/sidecar/dist/providers/registry.js.map +1 -1
  294. package/sidecar/dist/server/chat-events.d.ts +16 -3
  295. package/sidecar/dist/server/chat-events.js.map +1 -1
  296. package/sidecar/dist/server/chat-socket-registry.d.ts +6 -6
  297. package/sidecar/dist/server/chat-socket-registry.js.map +1 -1
  298. package/sidecar/dist/server/conversation-runs.d.ts +1 -1
  299. package/sidecar/dist/server/conversation-runs.js +4 -5
  300. package/sidecar/dist/server/conversation-runs.js.map +1 -1
  301. package/sidecar/dist/server/host-socket-registry.d.ts +4 -3
  302. package/sidecar/dist/server/host-socket-registry.js.map +1 -1
  303. package/sidecar/dist/server/http-io.d.ts +3 -2
  304. package/sidecar/dist/server/http-io.js +2 -3
  305. package/sidecar/dist/server/http-io.js.map +1 -1
  306. package/sidecar/dist/server/http-params.js.map +1 -1
  307. package/sidecar/dist/server/http-routes.d.ts +9 -2
  308. package/sidecar/dist/server/http-routes.js +19 -15
  309. package/sidecar/dist/server/http-routes.js.map +1 -1
  310. package/sidecar/dist/server/http.js +19 -10
  311. package/sidecar/dist/server/http.js.map +1 -1
  312. package/sidecar/dist/server/pending-queue.js +4 -1
  313. package/sidecar/dist/server/pending-queue.js.map +1 -1
  314. package/sidecar/dist/server/permission-events.d.ts +8 -4
  315. package/sidecar/dist/server/permission-events.js.map +1 -1
  316. package/sidecar/dist/server/raw-data.js +2 -1
  317. package/sidecar/dist/server/raw-data.js.map +1 -1
  318. package/sidecar/dist/server/routing.js +5 -2
  319. package/sidecar/dist/server/routing.js.map +1 -1
  320. package/sidecar/dist/server/safety-net.js +20 -9
  321. package/sidecar/dist/server/safety-net.js.map +1 -1
  322. package/sidecar/dist/server/tool-calls.d.ts +13 -4
  323. package/sidecar/dist/server/tool-calls.js +7 -5
  324. package/sidecar/dist/server/tool-calls.js.map +1 -1
  325. package/sidecar/dist/server/turns.d.ts +16 -2
  326. package/sidecar/dist/server/turns.js +7 -4
  327. package/sidecar/dist/server/turns.js.map +1 -1
  328. package/sidecar/dist/server/ws.js +2 -6
  329. package/sidecar/dist/server/ws.js.map +1 -1
  330. package/sidecar/dist/skills/build-catalog.js.map +1 -1
  331. package/sidecar/dist/skills/frontmatter.js.map +1 -1
  332. package/sidecar/dist/skills/plugin-wrapper.js.map +1 -1
  333. package/sidecar/dist/skills/resolve-sources.js.map +1 -1
  334. package/sidecar/dist/skills/skill-usage.js +18 -12
  335. package/sidecar/dist/skills/skill-usage.js.map +1 -1
  336. package/sidecar/dist/state/change-sets.js +4 -1
  337. package/sidecar/dist/state/change-sets.js.map +1 -1
  338. package/sidecar/dist/state/conversations.js.map +1 -1
  339. package/sidecar/dist/state/lock.js +6 -2
  340. package/sidecar/dist/state/lock.js.map +1 -1
  341. package/sidecar/dist/state/settings-store.d.ts +31 -1
  342. package/sidecar/dist/state/settings-store.js +23 -24
  343. package/sidecar/dist/state/settings-store.js.map +1 -1
  344. package/sidecar/dist/state/settings-types.js.map +1 -1
  345. package/sidecar/dist/state/sidecar-version.js +3 -1
  346. package/sidecar/dist/state/sidecar-version.js.map +1 -1
  347. package/sidecar/dist/state/store.js +9 -3
  348. package/sidecar/dist/state/store.js.map +1 -1
  349. package/sidecar/dist/state/types.js.map +1 -1
  350. package/sidecar/package.json +1 -7
  351. package/skills/dms-ai/SKILL.md +1 -1
  352. package/skills/dms-ai/cases.json +47 -0
  353. package/skills/dms-ai-code-mode/cases.json +38 -0
  354. package/skills/dms-builder-safe/cases.json +67 -0
  355. package/skills/dms-external-database/REFERENCE.md +34 -9
  356. package/skills/dms-external-database/SKILL.md +24 -11
  357. package/skills/dms-external-database/cases.json +47 -0
  358. package/frontend-vue/tests/i18n-panel.test.ts +0 -118
  359. package/frontend-vue/tests/i18n-views.test.ts +0 -63
  360. package/frontend-vue/tests/panel-header-height.test.ts +0 -40
@@ -0,0 +1,77 @@
1
+ <script setup lang="ts">
2
+ import { useChatI18n } from "../composables/useChatI18n";
3
+
4
+ interface Props {
5
+ agentName: string;
6
+ /** Why the provider cannot run, as the sidecar reported it. */
7
+ reason: string;
8
+ }
9
+
10
+ interface Emits {
11
+ openSettings: [];
12
+ }
13
+
14
+ defineProps<Props>();
15
+ const emit = defineEmits<Emits>();
16
+ const { t } = useChatI18n();
17
+ </script>
18
+
19
+ <template>
20
+ <div class="chat-view-provider">
21
+ <div class="cb-provider" role="alert">
22
+ <UIcon name="i-ph-key" class="cb-provider__icon" />
23
+ <div>
24
+ <b>
25
+ {{ t("dms_ai.panel.errors.agent_cant_run", { agent: agentName }) }}
26
+ </b>
27
+ {{ reason }}
28
+ {{ t("dms_ai.panel.errors.agent_no_fallback") }}
29
+ <div class="cb-provider__row">
30
+ <UButton
31
+ size="xs"
32
+ color="neutral"
33
+ variant="outline"
34
+ icon="i-ph-gear-six"
35
+ :label="t('dms_ai.panel.errors.open_settings')"
36
+ @click="emit('openSettings')"
37
+ />
38
+ </div>
39
+ </div>
40
+ </div>
41
+ </div>
42
+ </template>
43
+
44
+ <style scoped>
45
+ .chat-view-provider {
46
+ padding: 0 14px 16px;
47
+ }
48
+
49
+ .cb-provider {
50
+ display: flex;
51
+ gap: 10px;
52
+ padding: 10px 12px;
53
+ border: 1px solid var(--dms-error-line);
54
+ border-radius: var(--ai-radius-md);
55
+ background: var(--dms-error-tint);
56
+ font-size: 12.5px;
57
+ line-height: 1.5;
58
+ color: var(--ui-text-toned);
59
+ }
60
+
61
+ .cb-provider__icon {
62
+ width: 16px;
63
+ height: 16px;
64
+ flex: none;
65
+ margin-top: 1px;
66
+ color: var(--ui-error);
67
+ }
68
+
69
+ .cb-provider b {
70
+ font-weight: 600;
71
+ color: var(--ui-text-highlighted);
72
+ }
73
+
74
+ .cb-provider__row {
75
+ margin-top: 8px;
76
+ }
77
+ </style>
@@ -0,0 +1,98 @@
1
+ <script setup lang="ts">
2
+ import type { PendingUndo } from "../composables/useChangeSetActions";
3
+ import { useChatI18n } from "../composables/useChatI18n";
4
+
5
+ interface Props {
6
+ /** The undo waiting on the user; the modal is open while there is one. */
7
+ pending: PendingUndo | null;
8
+ }
9
+
10
+ interface Emits {
11
+ confirm: [includeLater: boolean];
12
+ cancel: [];
13
+ }
14
+
15
+ defineProps<Props>();
16
+ const emit = defineEmits<Emits>();
17
+ const { t } = useChatI18n();
18
+
19
+ function onOpenChange(isOpen: boolean): void {
20
+ if (!isOpen) emit("cancel");
21
+ }
22
+ </script>
23
+
24
+ <template>
25
+ <UModal
26
+ :open="pending !== null"
27
+ :title="t('dms_ai.panel.change.conflict_title')"
28
+ @update:open="onOpenChange"
29
+ >
30
+ <template #body>
31
+ <p class="chat-view-conflict">
32
+ {{
33
+ t("dms_ai.panel.change.conflict_text", {
34
+ number: pending?.number ?? 0,
35
+ })
36
+ }}
37
+ </p>
38
+ <ul class="chat-view-conflicts">
39
+ <li
40
+ v-for="conflict in pending?.conflicts ?? []"
41
+ :key="conflict.changeSetId"
42
+ >
43
+ <b>#{{ conflict.number }}</b>
44
+ {{ conflict.title }}
45
+ <span>{{ conflict.files.join(", ") }}</span>
46
+ </li>
47
+ </ul>
48
+ </template>
49
+ <template #footer>
50
+ <div class="chat-view-conflict-foot">
51
+ <UButton
52
+ color="neutral"
53
+ variant="ghost"
54
+ :label="t('dms_ai.panel.change.undo_only')"
55
+ @click="emit('confirm', false)"
56
+ />
57
+ <UButton
58
+ color="secondary"
59
+ :label="t('dms_ai.panel.change.undo_together')"
60
+ @click="emit('confirm', true)"
61
+ />
62
+ </div>
63
+ </template>
64
+ </UModal>
65
+ </template>
66
+
67
+ <style scoped>
68
+ .chat-view-conflict {
69
+ margin: 0 0 10px;
70
+ font-size: 13px;
71
+ line-height: 1.5;
72
+ color: var(--ui-text-muted);
73
+ }
74
+
75
+ .chat-view-conflicts {
76
+ display: grid;
77
+ gap: 6px;
78
+ margin: 0;
79
+ padding: 0;
80
+ list-style: none;
81
+ font-size: 12.5px;
82
+ }
83
+
84
+ .chat-view-conflicts span {
85
+ display: block;
86
+ font-family: var(--ai-font-mono, ui-monospace, monospace);
87
+ font-size: 11px;
88
+ color: var(--ui-text-muted);
89
+ overflow-wrap: anywhere;
90
+ }
91
+
92
+ .chat-view-conflict-foot {
93
+ display: flex;
94
+ justify-content: flex-end;
95
+ gap: 8px;
96
+ width: 100%;
97
+ }
98
+ </style>
@@ -20,7 +20,7 @@ interface UndoPreview {
20
20
  }
21
21
 
22
22
  /** An undo waiting on the user: later sets touch the same files. */
23
- interface PendingUndo {
23
+ export interface PendingUndo {
24
24
  changeSetId: string;
25
25
  number: number;
26
26
  conflicts: UndoConflict[];
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import type { Tone } from "#dms-ui/app/types/tone";
2
+ import type { Tone } from "#dms-core/app/types/tone";
3
3
  import { computed } from "vue";
4
4
  import { renderDocument } from "../chat/utils/markdown";
5
5
  import { useAssistant } from "../views/composables/useAssistant";
@@ -26,6 +26,10 @@ import {
26
26
  paletteAssistant,
27
27
  paletteSource,
28
28
  } from "../runtime/assistant-commands";
29
+ import {
30
+ ASSISTANT_ACTIONS_KEY,
31
+ publicAssistantActions,
32
+ } from "../runtime/assistant-actions";
29
33
  import { installAssistantNotifications } from "../runtime/assistant-notifications";
30
34
  import {
31
35
  ASSISTANT_SESSION_KEY,
@@ -264,8 +268,8 @@ function createSession(parts: SessionParts): AssistantSession {
264
268
  intents.push({ kind: "open", conversationId });
265
269
  panel.open();
266
270
  },
267
- startConversation: (prompt) => {
268
- intents.push({ kind: "start", prompt });
271
+ startConversation: (prompt, mode) => {
272
+ intents.push({ kind: "start", prompt, mode });
269
273
  panel.open();
270
274
  },
271
275
  holdStream: parts.holds.hold,
@@ -502,6 +506,10 @@ export default defineDmsPlugin((context) => {
502
506
  i18n: createChatI18n(context.$i18n),
503
507
  };
504
508
  context.vueApp.provide(ASSISTANT_SESSION_KEY, provided.session);
509
+ context.vueApp.provide(
510
+ ASSISTANT_ACTIONS_KEY,
511
+ publicAssistantActions(provided.session),
512
+ );
505
513
  context.vueApp.provide(CHAT_I18N_KEY, provided.i18n);
506
514
  const appMounted = new Promise<void>((resolve) =>
507
515
  context.hook("app:mounted", resolve),
@@ -0,0 +1,41 @@
1
+ import type {
2
+ AssistantSessionRef,
3
+ ConversationStartMode,
4
+ } from "./assistant-session";
5
+
6
+ /**
7
+ * The assistant as another module's layer may use it, without depending on dms-ai: injected under
8
+ * {@link ASSISTANT_ACTIONS_KEY} with a `null` default, which is what a project without dms-ai, or
9
+ * outside development, answers.
10
+ */
11
+ export interface PublicAssistantActions {
12
+ /** The assistant runs in this tab, so a button that starts a conversation can be offered. Reactive. */
13
+ readonly isAvailable: boolean;
14
+ /**
15
+ * Opens the assistant panel on a new conversation with `prompt` in the composer, unsent. With
16
+ * `mode`, the conversation is set to it first: `plan` makes the agent end with a plan to approve.
17
+ */
18
+ startConversation: (
19
+ prompt: string,
20
+ options?: { mode?: ConversationStartMode },
21
+ ) => void;
22
+ }
23
+
24
+ /**
25
+ * The global key of {@link PublicAssistantActions}: `Symbol.for` resolves to the same symbol in
26
+ * every layer, so another module's layer injects it without importing dms-ai.
27
+ */
28
+ export const ASSISTANT_ACTIONS_KEY = Symbol.for("dms-ai:assistant-actions");
29
+
30
+ /** The public actions over the tab's assistant session, which may not run yet, or ever. */
31
+ export function publicAssistantActions(
32
+ session: AssistantSessionRef,
33
+ ): PublicAssistantActions {
34
+ return {
35
+ get isAvailable() {
36
+ return session.value !== null;
37
+ },
38
+ startConversation: (prompt, options) =>
39
+ session.value?.startConversation(prompt, options?.mode),
40
+ };
41
+ }
@@ -17,6 +17,9 @@ export interface ChatPanelState {
17
17
  toggle: () => void;
18
18
  }
19
19
 
20
+ /** The approval modes a conversation can be started in from outside the panel. */
21
+ export type ConversationStartMode = "plan" | "normal";
22
+
20
23
  /**
21
24
  * The tab's assistant, as the plugin that owns it hands it to the panel, the
22
25
  * command palette's answer and the workspace pages: the sidecar's
@@ -31,8 +34,11 @@ export interface AssistantSession {
31
34
  navigate: (path: string) => void;
32
35
  /** Opens the panel on that conversation. */
33
36
  openConversation: (conversationId: string) => void;
34
- /** Opens the panel on a new conversation, the composer optionally prefilled. */
35
- startConversation: (prompt?: string) => void;
37
+ /**
38
+ * Opens the panel on a new conversation, the composer optionally prefilled, and the
39
+ * conversation set to `mode` first when one is given.
40
+ */
41
+ startConversation: (prompt?: string, mode?: ConversationStartMode) => void;
36
42
  /**
37
43
  * Keeps the tab's stream open while the panel is closed, until the returned
38
44
  * function releases it: the command palette's answer streams through it.
@@ -1,4 +1,5 @@
1
1
  import { type Ref, ref } from "vue";
2
+ import type { ConversationStartMode } from "./assistant-session";
2
3
 
3
4
  /** Opens the panel on a stored conversation. */
4
5
  interface OpenConversationIntent {
@@ -6,10 +7,11 @@ interface OpenConversationIntent {
6
7
  conversationId: string;
7
8
  }
8
9
 
9
- /** Opens the panel on a new conversation, the composer optionally prefilled. */
10
+ /** Opens the panel on a new conversation, the composer optionally prefilled, in `mode` when given. */
10
11
  interface StartConversationIntent {
11
12
  kind: "start";
12
13
  prompt?: string;
14
+ mode?: ConversationStartMode;
13
15
  }
14
16
 
15
17
  /** Puts the caret in the composer of the current conversation. */
@@ -7,7 +7,7 @@ import { useAssistant } from "./composables/useAssistant";
7
7
  import { useChangeSetActions } from "./composables/useChangeSetActions";
8
8
  import { useViewFormat } from "./composables/useViewFormat";
9
9
  import { AI_ROUTES } from "./constants";
10
- import type { Tone } from "#dms-ui/app/types/tone";
10
+ import type { Tone } from "#dms-core/app/types/tone";
11
11
  import type {
12
12
  ChangeSetDetail,
13
13
  ChangeSetSummary,
@@ -40,16 +40,10 @@ interface FetchErrorResponse {
40
40
  status?: number;
41
41
  }
42
42
 
43
- interface FetchErrorBody {
44
- message?: unknown;
45
- }
46
-
47
43
  interface FetchErrorLike {
48
44
  status?: number;
49
45
  statusCode?: number;
50
46
  response?: FetchErrorResponse;
51
- data?: FetchErrorBody;
52
- message?: string;
53
47
  }
54
48
 
55
49
  /** The HTTP status of a `$authFetch` rejection, if it got an answer. */
@@ -60,14 +54,6 @@ function errorStatus(error: unknown): number | undefined {
60
54
  );
61
55
  }
62
56
 
63
- /** The server's `{ message }`, else the error's own text. */
64
- export function errorMessage(error: unknown): string {
65
- const candidate = error as FetchErrorLike | null;
66
- const serverMessage = candidate?.data?.message;
67
- if (typeof serverMessage === "string") return serverMessage;
68
- return candidate?.message ?? String(error);
69
- }
70
-
71
57
  export function classifyFailure(error: unknown): RequestFailure {
72
58
  return errorStatus(error) === HTTP_SERVICE_UNAVAILABLE
73
59
  ? "unavailable"
@@ -80,15 +66,21 @@ export function classifyFailure(error: unknown): RequestFailure {
80
66
  * whether the assistant isn't running (503) rather than an error.
81
67
  */
82
68
  function describeFailure(result: FailingRead): FailureDescription {
69
+ const { resolveError } = useApiErrorPresenter();
70
+ const notice = computed(() =>
71
+ result.error.value
72
+ ? resolveError(result.error.value, {
73
+ fallbackKey: `dms_ai.views.${classifyFailure(result.error.value)}.description`,
74
+ })
75
+ : null,
76
+ );
83
77
  return {
84
78
  failure: computed(() =>
85
- result.error.value && result.status.value !== "pending"
79
+ notice.value && result.status.value !== "pending"
86
80
  ? classifyFailure(result.error.value)
87
81
  : null,
88
82
  ),
89
- message: computed(() =>
90
- result.error.value ? errorMessage(result.error.value) : "",
91
- ),
83
+ message: computed(() => notice.value?.message ?? ""),
92
84
  };
93
85
  }
94
86
 
@@ -1,7 +1,7 @@
1
1
  import { ref, type Ref } from "vue";
2
2
  import { AI_ROUTES } from "../constants";
3
3
  import type { ChangeSetSummary } from "../types";
4
- import { classifyFailure, errorMessage } from "./useAiData";
4
+ import { classifyFailure } from "./useAiData";
5
5
 
6
6
  export interface ChangeSetActions {
7
7
  isBusy: Ref<boolean>;
@@ -28,23 +28,11 @@ function changeSetPath(changeSetId: string, action: string): string {
28
28
  export function useChangeSetActions(): ChangeSetActions {
29
29
  const { t } = useI18n();
30
30
  const toast = useToast();
31
+ const { presentError } = useApiErrorPresenter();
31
32
  const { $authFetch } = useAuthFetch();
32
33
  const { confirmFrom } = useConfirmFrom();
33
34
  const isBusy = ref(false);
34
35
 
35
- function failureToast(error: unknown): void {
36
- const failure = classifyFailure(error);
37
- toast.add({
38
- title: t(`dms_ai.views.${failure}.title`),
39
- description:
40
- failure === "error"
41
- ? errorMessage(error)
42
- : t("dms_ai.views.unavailable.description"),
43
- color: "error",
44
- icon: "i-ph-warning-circle",
45
- });
46
- }
47
-
48
36
  async function redo(changeSet: ChangeSetSummary): Promise<void> {
49
37
  isBusy.value = true;
50
38
  try {
@@ -59,7 +47,9 @@ export function useChangeSetActions(): ChangeSetActions {
59
47
  });
60
48
  await refreshPageBlocks();
61
49
  } catch (error) {
62
- failureToast(error);
50
+ presentError(error, {
51
+ fallbackKey: `dms_ai.views.${classifyFailure(error)}.description`,
52
+ });
63
53
  } finally {
64
54
  isBusy.value = false;
65
55
  }
@@ -1,5 +1,5 @@
1
1
  import type { ActivityResult, AllowedBy } from "./types";
2
- import type { Tone } from "#dms-ui/app/types/tone";
2
+ import type { Tone } from "#dms-core/app/types/tone";
3
3
 
4
4
  export const AI_ROUTES = {
5
5
  status: "/ai/status",
@@ -1,4 +1,4 @@
1
- import type { Tone } from "#dms-ui/app/types/tone";
1
+ import type { Tone } from "#dms-core/app/types/tone";
2
2
 
3
3
  type AgentId = "claude" | "codex";
4
4
  export type ScopeId = "safe" | "vibe";
@@ -0,0 +1,122 @@
1
+ import { existsSync, readFileSync, realpathSync } from "node:fs";
2
+ import { dirname, isAbsolute, join, relative, sep } from "node:path";
3
+ import type { DmsVitePluginEntry } from "#dms/frontend-build";
4
+
5
+ type VitePlugin = Extract<DmsVitePluginEntry, { name: string }>;
6
+
7
+ const BACKEND_PACKAGE = "@antelopejs/dms-ai";
8
+ const BACKEND_SOURCE = "src";
9
+ const QUERY_OR_HASH = /[?#].*$/;
10
+
11
+ const backendRoots = new Map<string, string | null>();
12
+
13
+ /** Whether a parsed manifest names its package. */
14
+ function isNamedManifest(value: unknown): value is { name: string } {
15
+ return (
16
+ typeof value === "object" &&
17
+ value !== null &&
18
+ "name" in value &&
19
+ typeof value.name === "string"
20
+ );
21
+ }
22
+
23
+ /** The package name a `package.json` declares, or `undefined`. */
24
+ function packageName(manifest: string): string | undefined {
25
+ try {
26
+ const parsed: unknown = JSON.parse(readFileSync(manifest, "utf8"));
27
+ return isNamedManifest(parsed) ? parsed.name : undefined;
28
+ } catch {
29
+ return undefined;
30
+ }
31
+ }
32
+
33
+ /** The directory of the backend package that holds `directory`, or null. */
34
+ function backendRoot(directory: string): string | null {
35
+ const known = backendRoots.get(directory);
36
+ if (known !== undefined) {
37
+ return known;
38
+ }
39
+ const manifest = join(directory, "package.json");
40
+ const parent = dirname(directory);
41
+ let root: string | null = null;
42
+ if (existsSync(manifest)) {
43
+ root = packageName(manifest) === BACKEND_PACKAGE ? directory : null;
44
+ } else if (parent !== directory) {
45
+ root = backendRoot(parent);
46
+ }
47
+ backendRoots.set(directory, root);
48
+ return root;
49
+ }
50
+
51
+ /**
52
+ * The real path of a resolved module id when it lies under the `src`
53
+ * directory of the backend package, or `undefined`. The package that owns the
54
+ * file decides, not a path, so the answer is the same in the repository and in
55
+ * the build workspace. Virtual ids and ids that are not files are ignored.
56
+ */
57
+ function backendSourceFile(id: string): string | undefined {
58
+ const path = id.replace(QUERY_OR_HASH, "");
59
+ if (!isAbsolute(path)) {
60
+ return undefined;
61
+ }
62
+ let real: string;
63
+ try {
64
+ real = realpathSync(path);
65
+ } catch {
66
+ return undefined;
67
+ }
68
+ const root = backendRoot(dirname(real));
69
+ if (root === null) {
70
+ return undefined;
71
+ }
72
+ return relative(root, real).split(sep)[0] === BACKEND_SOURCE
73
+ ? real
74
+ : undefined;
75
+ }
76
+
77
+ /**
78
+ * Fails the build and the dev server when a module of the frontend resolves to
79
+ * a file under the `src` of the backend package: the browser reaches the
80
+ * backend only through its HTTP interface. It checks what the whole resolution
81
+ * chain returns, an id marked external included, so an alias is seen through
82
+ * and a symlink the resolver returns is followed to its real path, and it runs
83
+ * before the other plugins (`enforce: "pre"`). Vite builds workers with their
84
+ * own plugin list, so the plugin adds itself there too.
85
+ *
86
+ * antelopejs-sync writes this file from `@antelopejs/tooling-configs` and
87
+ * restores it on every run: change the plugin in the pack, not here.
88
+ */
89
+ export function backendBoundary(): VitePlugin {
90
+ return {
91
+ ...boundaryCheck(),
92
+ config: () => ({ worker: { plugins: () => [boundaryCheck()] } }),
93
+ };
94
+ }
95
+
96
+ /** The check alone, as a worker build runs it. */
97
+ function boundaryCheck(): VitePlugin {
98
+ return {
99
+ name: `${BACKEND_PACKAGE}:backend-boundary`,
100
+ enforce: "pre",
101
+ async resolveId(source, importer, options) {
102
+ const resolved = await this.resolve(source, importer, {
103
+ ...options,
104
+ skipSelf: true,
105
+ });
106
+ if (resolved === null) {
107
+ return resolved;
108
+ }
109
+ const file = backendSourceFile(resolved.id);
110
+ if (file === undefined) {
111
+ return resolved;
112
+ }
113
+ const from =
114
+ importer === undefined
115
+ ? "an entry point"
116
+ : importer.replace(QUERY_OR_HASH, "");
117
+ return this.error(
118
+ `Backend boundary: ${from} imports ${file}, which is under the src of ${BACKEND_PACKAGE}. The frontend reaches the backend only through its HTTP interface.`,
119
+ );
120
+ },
121
+ };
122
+ }
@@ -0,0 +1,6 @@
1
+ import { defineDmsFrontendBuild } from "#dms/frontend-build";
2
+ import { backendBoundary } from "./build/backend-boundary.ts";
3
+
4
+ export default defineDmsFrontendBuild((build) => {
5
+ build.registerVitePlugins(() => [backendBoundary()]);
6
+ });
@@ -6,7 +6,7 @@
6
6
  "license": "Apache-2.0",
7
7
  "packageManager": "pnpm@10.6.5",
8
8
  "engines": {
9
- "@antelopejs/dms-frontend": ">=0.9.0 <0.10.0"
9
+ "@antelopejs/dms-frontend": ">=0.9.1 <0.10.0"
10
10
  },
11
11
  "scripts": {
12
12
  "build": "pnpm --dir \"${DMS_FRONTEND_WORKSPACE:?Set DMS_FRONTEND_WORKSPACE to the generated Inertia workspace}\" build",
@@ -37,6 +37,7 @@
37
37
  "prettier-plugin-tailwindcss": "^0.6.11",
38
38
  "typescript": "^5.8.2",
39
39
  "typescript-eslint": "^8.0.0",
40
+ "vite": "^7.3.2",
40
41
  "vitest": "^4.1.5",
41
42
  "vue-tsc": "^3.1.1"
42
43
  }
@@ -60,6 +60,9 @@ importers:
60
60
  typescript-eslint:
61
61
  specifier: ^8.0.0
62
62
  version: 8.70.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)
63
+ vite:
64
+ specifier: ^7.3.2
65
+ version: 7.3.2(jiti@2.7.0)(terser@5.46.2)(yaml@2.8.4)
63
66
  vitest:
64
67
  specifier: ^4.1.5
65
68
  version: 4.1.5(jsdom@29.1.1)(vite@7.3.2(jiti@2.7.0)(terser@5.46.2)(yaml@2.8.4))
@@ -0,0 +1,72 @@
1
+ // @vitest-environment jsdom
2
+ import { flushPromises } from "@vue/test-utils";
3
+ import { afterEach, describe, expect, it } from "vitest";
4
+ import { shallowRef } from "vue";
5
+ import { publicAssistantActions } from "../app/runtime/assistant-actions";
6
+ import {
7
+ createHarness,
8
+ openPanel,
9
+ sentOfType,
10
+ unmountPanel,
11
+ } from "./support/panel-harness";
12
+
13
+ afterEach(() => {
14
+ unmountPanel();
15
+ });
16
+
17
+ const PROMPT =
18
+ "Use dms-external-database on connection roaster, module builder-db-roaster-tables.";
19
+
20
+ describe("the assistant actions another module's layer injects", () => {
21
+ it("start a new conversation with the composer prefilled and nothing sent", async () => {
22
+ const harness = createHarness();
23
+ const panel = await openPanel(harness);
24
+ const actions = publicAssistantActions(shallowRef(harness.session));
25
+ expect(actions.isAvailable).toBe(true);
26
+ actions.startConversation(PROMPT);
27
+ await flushPromises();
28
+ expect((panel.find("textarea").element as HTMLTextAreaElement).value).toBe(
29
+ PROMPT,
30
+ );
31
+ expect(sentOfType(harness, "user_message")).toEqual([]);
32
+ expect(sentOfType(harness, "set_conversation_mode")).toEqual([]);
33
+ });
34
+
35
+ it("set the new conversation to plan mode before prefilling it, when asked", async () => {
36
+ const harness = createHarness();
37
+ const panel = await openPanel(harness);
38
+ const actions = publicAssistantActions(shallowRef(harness.session));
39
+ actions.startConversation(PROMPT, { mode: "plan" });
40
+ await flushPromises();
41
+ const started = sentOfType(harness, "hello").at(-1)?.conversationId;
42
+ expect(sentOfType(harness, "set_conversation_mode")).toEqual([
43
+ expect.objectContaining({ conversationId: started, mode: "plan" }),
44
+ ]);
45
+ expect((panel.find("textarea").element as HTMLTextAreaElement).value).toBe(
46
+ PROMPT,
47
+ );
48
+ });
49
+
50
+ it("set plan mode once the stream is up, when the panel opens before it", async () => {
51
+ const harness = createHarness();
52
+ await openPanel(harness);
53
+ harness.setChannelStatus("disconnected");
54
+ publicAssistantActions(shallowRef(harness.session)).startConversation(
55
+ PROMPT,
56
+ { mode: "plan" },
57
+ );
58
+ await flushPromises();
59
+ expect(sentOfType(harness, "set_conversation_mode")).toEqual([]);
60
+ harness.setChannelStatus("connected");
61
+ await flushPromises();
62
+ expect(sentOfType(harness, "set_conversation_mode")).toEqual([
63
+ expect.objectContaining({ mode: "plan" }),
64
+ ]);
65
+ });
66
+
67
+ it("are unavailable without a session, and starting then does nothing", () => {
68
+ const actions = publicAssistantActions(shallowRef(null));
69
+ expect(actions.isAvailable).toBe(false);
70
+ expect(() => actions.startConversation(PROMPT)).not.toThrow();
71
+ });
72
+ });