@antelopejs/dms-ai 0.1.4 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (244) hide show
  1. package/README.md +48 -29
  2. package/dist/channels/bridge.d.ts +2 -8
  3. package/dist/channels/bridge.js +26 -42
  4. package/dist/channels/bridge.js.map +1 -1
  5. package/dist/channels/channel-service.d.ts +2 -2
  6. package/dist/channels/channel-service.js +12 -31
  7. package/dist/channels/channel-service.js.map +1 -1
  8. package/dist/channels/registry.d.ts +2 -2
  9. package/dist/channels/registry.js +7 -7
  10. package/dist/channels/registry.js.map +1 -1
  11. package/dist/config.d.ts +1 -0
  12. package/dist/config.js +8 -1
  13. package/dist/config.js.map +1 -1
  14. package/dist/constants/channels.d.ts +5 -10
  15. package/dist/constants/channels.js +6 -10
  16. package/dist/constants/channels.js.map +1 -1
  17. package/dist/constants/sidecar.d.ts +2 -1
  18. package/dist/constants/sidecar.js +3 -2
  19. package/dist/constants/sidecar.js.map +1 -1
  20. package/dist/index.js +8 -0
  21. package/dist/index.js.map +1 -1
  22. package/dist/lifecycle/build-id.d.ts +1 -0
  23. package/dist/lifecycle/build-id.js +32 -0
  24. package/dist/lifecycle/build-id.js.map +1 -0
  25. package/dist/lifecycle/sidecar-socket.d.ts +1 -1
  26. package/dist/lifecycle/sidecar-socket.js +2 -2
  27. package/dist/lifecycle/sidecar-socket.js.map +1 -1
  28. package/dist/lifecycle/spawn-sidecar.d.ts +0 -1
  29. package/dist/lifecycle/spawn-sidecar.js +5 -27
  30. package/dist/lifecycle/spawn-sidecar.js.map +1 -1
  31. package/dist/routes/channels.d.ts +3 -3
  32. package/dist/routes/channels.js +11 -12
  33. package/dist/routes/channels.js.map +1 -1
  34. package/dist/routes/index.d.ts +0 -1
  35. package/dist/routes/index.js +0 -1
  36. package/dist/routes/index.js.map +1 -1
  37. package/frontend-vue/.prettierignore +3 -0
  38. package/frontend-vue/.prettierrc +10 -0
  39. package/frontend-vue/app/chat/components/ChatView.vue +582 -0
  40. package/frontend-vue/app/chat/components/ComposerInput.vue +742 -0
  41. package/frontend-vue/app/chat/components/ConnectionBanner.vue +105 -0
  42. package/frontend-vue/app/chat/components/ConversationDrawer.vue +266 -0
  43. package/frontend-vue/app/chat/components/MarkdownContent.vue +196 -0
  44. package/frontend-vue/app/chat/components/MessageList.vue +474 -0
  45. package/frontend-vue/app/chat/components/PermissionRequests.vue +323 -0
  46. package/frontend-vue/app/chat/components/QuestionPrompt.vue +275 -0
  47. package/frontend-vue/app/chat/components/QueuedMessages.vue +109 -0
  48. package/frontend-vue/app/chat/components/TodoList.vue +291 -0
  49. package/frontend-vue/app/chat/components/ToolCallEntry.vue +218 -0
  50. package/frontend-vue/app/chat/components/ToolCluster.vue +282 -0
  51. package/frontend-vue/app/chat/composables/useChatChannel.ts +116 -0
  52. package/frontend-vue/app/chat/composables/useConversation.ts +838 -0
  53. package/frontend-vue/app/chat/composables/useConversationId.ts +34 -0
  54. package/frontend-vue/app/chat/composables/useConversationList.ts +56 -0
  55. package/frontend-vue/app/chat/composables/usePermissionQueue.ts +59 -0
  56. package/frontend-vue/app/chat/composables/useQuestionQueue.ts +50 -0
  57. package/frontend-vue/app/chat/composables/useRunClock.ts +28 -0
  58. package/frontend-vue/app/chat/composables/useSettings.ts +67 -0
  59. package/frontend-vue/app/chat/constants/attachments.ts +16 -0
  60. package/frontend-vue/app/chat/constants/connection-banner.ts +7 -0
  61. package/frontend-vue/app/chat/constants/conversation-drawer.ts +13 -0
  62. package/frontend-vue/app/chat/constants/conversation.ts +75 -0
  63. package/frontend-vue/app/chat/constants/permissions.ts +50 -0
  64. package/frontend-vue/app/chat/constants/protocol.ts +48 -0
  65. package/frontend-vue/app/chat/constants/run-status.ts +50 -0
  66. package/frontend-vue/app/chat/constants/settings.ts +60 -0
  67. package/frontend-vue/app/chat/types/conversation.ts +87 -0
  68. package/frontend-vue/app/chat/types/permission.ts +7 -0
  69. package/frontend-vue/app/chat/types/question.ts +17 -0
  70. package/frontend-vue/app/chat/types/settings.ts +27 -0
  71. package/frontend-vue/app/chat/utils/attachments.ts +62 -0
  72. package/frontend-vue/app/chat/utils/format.ts +14 -0
  73. package/frontend-vue/app/chat/utils/ids.ts +34 -0
  74. package/frontend-vue/app/chat/utils/markdown.ts +188 -0
  75. package/frontend-vue/app/chat/utils/run-status.ts +90 -0
  76. package/frontend-vue/app/chat/utils/todos.ts +64 -0
  77. package/frontend-vue/app/chat/utils/tool-summary.ts +53 -0
  78. package/frontend-vue/app/components/ActivityView.vue +34 -34
  79. package/frontend-vue/app/components/ChatPanel.vue +276 -0
  80. package/frontend-vue/app/components/SettingsView.vue +120 -112
  81. package/frontend-vue/app/components/SkillsView.vue +55 -53
  82. package/frontend-vue/app/plugins/ai.client.ts +145 -129
  83. package/frontend-vue/app/runtime/assistant-session.ts +21 -0
  84. package/frontend-vue/app/runtime/backoff.ts +11 -14
  85. package/frontend-vue/app/runtime/channel-client.ts +130 -141
  86. package/frontend-vue/app/runtime/chat-transport.ts +25 -55
  87. package/frontend-vue/app/runtime/constants.ts +69 -59
  88. package/frontend-vue/app/runtime/current-page.ts +49 -15
  89. package/frontend-vue/app/runtime/event-stream.ts +35 -35
  90. package/frontend-vue/app/runtime/frame-router.ts +30 -0
  91. package/frontend-vue/app/runtime/header-action.ts +18 -18
  92. package/frontend-vue/app/runtime/host-commands.ts +57 -56
  93. package/frontend-vue/app/runtime/listeners.ts +31 -0
  94. package/frontend-vue/app/runtime/navigation-complete.ts +7 -7
  95. package/frontend-vue/app/runtime/overlay-prefs.ts +36 -36
  96. package/frontend-vue/app/runtime/panel-state.ts +88 -0
  97. package/frontend-vue/app/runtime/session-gate.ts +8 -8
  98. package/frontend-vue/app/runtime/shortcuts.ts +12 -12
  99. package/frontend-vue/app/runtime/sidecar-status.ts +61 -61
  100. package/frontend-vue/app/runtime/typed-message.ts +11 -0
  101. package/frontend-vue/dms.frontend.ts +12 -12
  102. package/frontend-vue/eslint.config.mjs +13 -13
  103. package/frontend-vue/package.json +11 -4
  104. package/frontend-vue/pnpm-lock.yaml +298 -96
  105. package/frontend-vue/tests/backoff.test.ts +26 -30
  106. package/frontend-vue/tests/channel-client.test.ts +187 -188
  107. package/frontend-vue/tests/chat/markdown.test.ts +271 -0
  108. package/frontend-vue/tests/chat/useChatChannel.test.ts +124 -0
  109. package/frontend-vue/tests/chat/useConversation.test.ts +283 -0
  110. package/frontend-vue/tests/chat-panel.test.ts +354 -0
  111. package/frontend-vue/tests/chat-transport.test.ts +84 -57
  112. package/frontend-vue/tests/host-commands.test.ts +126 -87
  113. package/frontend-vue/tests/navigation.test.ts +65 -34
  114. package/frontend-vue/tests/overlay-prefs.test.ts +49 -49
  115. package/frontend-vue/tests/panel-state.test.ts +58 -0
  116. package/frontend-vue/tests/session-gate.test.ts +33 -33
  117. package/frontend-vue/tests/sidecar-guest.test.ts +46 -46
  118. package/frontend-vue/tests/sidecar-status.test.ts +29 -29
  119. package/frontend-vue/tsconfig.chat.json +16 -0
  120. package/frontend-vue/vitest.config.ts +6 -4
  121. package/package.json +5 -5
  122. package/sidecar/dist/agent/effective-mode.d.ts +2 -2
  123. package/sidecar/dist/agent/effective-mode.js +1 -1
  124. package/sidecar/dist/agent/effective-mode.js.map +1 -1
  125. package/sidecar/dist/agent/host-context.js +7 -9
  126. package/sidecar/dist/agent/host-context.js.map +1 -1
  127. package/sidecar/dist/agent/permission-bus.d.ts +1 -1
  128. package/sidecar/dist/agent/permission-bus.js +2 -2
  129. package/sidecar/dist/agent/permission-bus.js.map +1 -1
  130. package/sidecar/dist/agent/provider.d.ts +2 -2
  131. package/sidecar/dist/agent/question-bus.d.ts +1 -1
  132. package/sidecar/dist/agent/question-bus.js +2 -2
  133. package/sidecar/dist/agent/question-bus.js.map +1 -1
  134. package/sidecar/dist/agent/runner.d.ts +2 -2
  135. package/sidecar/dist/agent/runner.js +24 -8
  136. package/sidecar/dist/agent/runner.js.map +1 -1
  137. package/sidecar/dist/agent/session.d.ts +2 -2
  138. package/sidecar/dist/agent/session.js +49 -9
  139. package/sidecar/dist/agent/session.js.map +1 -1
  140. package/sidecar/dist/agent/switching-runner.js +10 -5
  141. package/sidecar/dist/agent/switching-runner.js.map +1 -1
  142. package/sidecar/dist/agent/turn-end-reasons.d.ts +2 -0
  143. package/sidecar/dist/agent/turn-end-reasons.js +6 -1
  144. package/sidecar/dist/agent/turn-end-reasons.js.map +1 -1
  145. package/sidecar/dist/constants/agent.d.ts +4 -1
  146. package/sidecar/dist/constants/agent.js +4 -1
  147. package/sidecar/dist/constants/agent.js.map +1 -1
  148. package/sidecar/dist/constants/cli.d.ts +0 -1
  149. package/sidecar/dist/constants/cli.js +0 -1
  150. package/sidecar/dist/constants/cli.js.map +1 -1
  151. package/sidecar/dist/constants/codex.d.ts +5 -2
  152. package/sidecar/dist/constants/codex.js +5 -2
  153. package/sidecar/dist/constants/codex.js.map +1 -1
  154. package/sidecar/dist/constants/http.d.ts +0 -9
  155. package/sidecar/dist/constants/http.js +0 -19
  156. package/sidecar/dist/constants/http.js.map +1 -1
  157. package/sidecar/dist/constants/mcp.d.ts +1 -1
  158. package/sidecar/dist/constants/mcp.js +1 -1
  159. package/sidecar/dist/constants/mcp.js.map +1 -1
  160. package/sidecar/dist/constants/paths.d.ts +0 -1
  161. package/sidecar/dist/constants/paths.js +0 -1
  162. package/sidecar/dist/constants/paths.js.map +1 -1
  163. package/sidecar/dist/constants/ws.d.ts +3 -4
  164. package/sidecar/dist/constants/ws.js +3 -4
  165. package/sidecar/dist/constants/ws.js.map +1 -1
  166. package/sidecar/dist/index.d.ts +0 -1
  167. package/sidecar/dist/index.js +6 -10
  168. package/sidecar/dist/index.js.map +1 -1
  169. package/sidecar/dist/mcp/tools/find-pages-using.js +5 -10
  170. package/sidecar/dist/mcp/tools/find-pages-using.js.map +1 -1
  171. package/sidecar/dist/mcp/types.d.ts +1 -1
  172. package/sidecar/dist/pages/page-filepath.d.ts +4 -0
  173. package/sidecar/dist/pages/page-filepath.js +28 -0
  174. package/sidecar/dist/pages/page-filepath.js.map +1 -0
  175. package/sidecar/dist/prompts/agent.d.ts +1 -1
  176. package/sidecar/dist/prompts/agent.js +1 -1
  177. package/sidecar/dist/prompts/agent.js.map +1 -1
  178. package/sidecar/dist/protocol/events.js +2 -2
  179. package/sidecar/dist/protocol/events.js.map +1 -1
  180. package/sidecar/dist/protocol/messages.d.ts +4 -15
  181. package/sidecar/dist/protocol/messages.js +4 -11
  182. package/sidecar/dist/protocol/messages.js.map +1 -1
  183. package/sidecar/dist/providers/claude/config.d.ts +2 -2
  184. package/sidecar/dist/providers/claude/config.js +2 -2
  185. package/sidecar/dist/providers/claude/config.js.map +1 -1
  186. package/sidecar/dist/providers/claude/provider.js +1 -1
  187. package/sidecar/dist/providers/claude/provider.js.map +1 -1
  188. package/sidecar/dist/providers/codex/config.d.ts +3 -2
  189. package/sidecar/dist/providers/codex/config.js +3 -3
  190. package/sidecar/dist/providers/codex/config.js.map +1 -1
  191. package/sidecar/dist/providers/codex/process.js +107 -74
  192. package/sidecar/dist/providers/codex/process.js.map +1 -1
  193. package/sidecar/dist/providers/codex/provider.js +68 -31
  194. package/sidecar/dist/providers/codex/provider.js.map +1 -1
  195. package/sidecar/dist/providers/codex/skills.d.ts +1 -0
  196. package/sidecar/dist/providers/codex/skills.js +4 -1
  197. package/sidecar/dist/providers/codex/skills.js.map +1 -1
  198. package/sidecar/dist/providers/codex/stop.d.ts +4 -0
  199. package/sidecar/dist/providers/codex/stop.js +71 -0
  200. package/sidecar/dist/providers/codex/stop.js.map +1 -0
  201. package/sidecar/dist/server/{iframe-socket-registry.d.ts → chat-socket-registry.d.ts} +3 -2
  202. package/sidecar/dist/server/{iframe-socket-registry.js → chat-socket-registry.js} +4 -3
  203. package/sidecar/dist/server/chat-socket-registry.js.map +1 -0
  204. package/sidecar/dist/server/client-auth.js +2 -14
  205. package/sidecar/dist/server/client-auth.js.map +1 -1
  206. package/sidecar/dist/server/host-command-router.d.ts +5 -0
  207. package/sidecar/dist/server/host-command-router.js +4 -0
  208. package/sidecar/dist/server/host-command-router.js.map +1 -0
  209. package/sidecar/dist/server/host-socket-registry.d.ts +1 -1
  210. package/sidecar/dist/server/host-socket-registry.js +16 -13
  211. package/sidecar/dist/server/host-socket-registry.js.map +1 -1
  212. package/sidecar/dist/server/http.d.ts +0 -1
  213. package/sidecar/dist/server/http.js +1 -44
  214. package/sidecar/dist/server/http.js.map +1 -1
  215. package/sidecar/dist/server/routing.d.ts +5 -6
  216. package/sidecar/dist/server/routing.js +18 -28
  217. package/sidecar/dist/server/routing.js.map +1 -1
  218. package/sidecar/dist/server/ws.d.ts +2 -2
  219. package/sidecar/dist/server/ws.js +41 -39
  220. package/sidecar/dist/server/ws.js.map +1 -1
  221. package/sidecar/dist/state/host-state.d.ts +10 -2
  222. package/sidecar/dist/state/host-state.js +13 -3
  223. package/sidecar/dist/state/host-state.js.map +1 -1
  224. package/sidecar/dist/state/settings-store.js +2 -2
  225. package/sidecar/dist/state/settings-store.js.map +1 -1
  226. package/sidecar/dist/state/settings-types.d.ts +3 -3
  227. package/sidecar/dist/state/settings-types.js +1 -1
  228. package/sidecar/dist/state/settings-types.js.map +1 -1
  229. package/sidecar/package.json +3 -5
  230. package/dist/chatbox/passthrough.d.ts +0 -3
  231. package/dist/chatbox/passthrough.js +0 -53
  232. package/dist/chatbox/passthrough.js.map +0 -1
  233. package/dist/constants/chatbox.d.ts +0 -10
  234. package/dist/constants/chatbox.js +0 -35
  235. package/dist/constants/chatbox.js.map +0 -1
  236. package/dist/routes/chatbox.d.ts +0 -7
  237. package/dist/routes/chatbox.js +0 -47
  238. package/dist/routes/chatbox.js.map +0 -1
  239. package/frontend-vue/app/runtime/overlay.ts +0 -400
  240. package/frontend-vue/app/runtime/theme-bridge.ts +0 -189
  241. package/sidecar/chatbox/dist/assets/index-C8u7mkHn.css +0 -1
  242. package/sidecar/chatbox/dist/assets/index-tdZvY7ee.js +0 -52
  243. package/sidecar/chatbox/dist/index.html +0 -13
  244. package/sidecar/dist/server/iframe-socket-registry.js.map +0 -1
@@ -1,188 +1,191 @@
1
1
  <script setup lang="ts">
2
- import { computed, onMounted, ref } from 'vue'
2
+ import { computed, onMounted, ref } from "vue";
3
3
 
4
- type Mode = 'normal' | 'acceptEdits' | 'plan' | 'auto'
5
- type Thinking = 'off' | 'low' | 'medium' | 'high'
6
- type GenerationMode = 'safe' | 'vibe'
7
- type ProviderName = 'claude' | 'codex'
4
+ type Mode = "normal" | "acceptEdits" | "plan" | "auto";
5
+ type Thinking = "off" | "low" | "medium" | "high";
6
+ type GenerationMode = "safe" | "vibe";
7
+ type ProviderName = "claude" | "codex";
8
8
 
9
9
  interface ProviderAvailability {
10
- available: boolean
11
- reason?: string
10
+ available: boolean;
11
+ reason?: string;
12
12
  }
13
13
 
14
14
  interface AiSettings {
15
- provider: ProviderName
16
- mode: Mode
17
- thinking: Thinking
18
- generationMode: GenerationMode
19
- allowLocalSkills: boolean
20
- builderAvailable: boolean
21
- providers: Record<ProviderName, ProviderAvailability>
15
+ provider: ProviderName;
16
+ mode: Mode;
17
+ thinking: Thinking;
18
+ generationMode: GenerationMode;
19
+ allowLocalSkills: boolean;
20
+ builderAvailable: boolean;
21
+ providers: Record<ProviderName, ProviderAvailability>;
22
22
  }
23
23
 
24
- const { $authFetch } = useAuthFetch()
24
+ const { $authFetch } = useAuthFetch();
25
25
 
26
26
  const settings = ref<AiSettings>({
27
- provider: 'claude',
28
- mode: 'normal',
29
- thinking: 'medium',
30
- generationMode: 'safe',
27
+ provider: "claude",
28
+ mode: "normal",
29
+ thinking: "medium",
30
+ generationMode: "safe",
31
31
  allowLocalSkills: false,
32
32
  builderAvailable: false,
33
33
  providers: { claude: { available: true }, codex: { available: false } },
34
- })
35
- const loading = ref(false)
36
- const saving = ref(false)
37
- const error = ref<string | null>(null)
34
+ });
35
+ const loading = ref(false);
36
+ const saving = ref(false);
37
+ const error = ref<string | null>(null);
38
38
 
39
39
  const MODE_OPTIONS: Array<{ value: Mode; label: string; hint: string }> = [
40
- { value: 'normal', label: 'Normal', hint: 'Ask before each tool action' },
40
+ { value: "normal", label: "Normal", hint: "Ask before each tool action" },
41
41
  {
42
- value: 'acceptEdits',
43
- label: 'Accept edits',
44
- hint: 'Auto-accept file edits, ask for the rest',
42
+ value: "acceptEdits",
43
+ label: "Accept edits",
44
+ hint: "Auto-accept file edits, ask for the rest",
45
45
  },
46
- { value: 'plan', label: 'Plan', hint: 'Plan only — propose without changes' },
47
- { value: 'auto', label: 'Auto', hint: 'Auto-approve every tool action' },
48
- ]
46
+ { value: "plan", label: "Plan", hint: "Plan only — propose without changes" },
47
+ { value: "auto", label: "Auto", hint: "Auto-approve every tool action" },
48
+ ];
49
49
 
50
50
  // Safe mode refuses raw edits whatever the mode, and Auto stops short of
51
51
  // approving everything there, so the mode hint says so while it is active.
52
52
  const SAFE_MODE_MODE_NOTE =
53
- 'Safe mode: raw edits and shell commands stay blocked, and Auto still asks before other actions.'
53
+ "Safe mode: raw edits and shell commands stay blocked, and Auto still asks before other actions.";
54
54
 
55
55
  interface ProviderOption {
56
- value: ProviderName
57
- label: string
56
+ value: ProviderName;
57
+ label: string;
58
58
  }
59
59
 
60
60
  const PROVIDER_OPTIONS: ProviderOption[] = [
61
- { value: 'claude', label: 'Anthropic (Claude)' },
62
- { value: 'codex', label: 'OpenAI (Codex)' },
63
- ]
61
+ { value: "claude", label: "Anthropic (Claude)" },
62
+ { value: "codex", label: "OpenAI (Codex)" },
63
+ ];
64
64
 
65
65
  // One control, two meanings: a token budget on Claude, a reasoning effort level
66
66
  // on Codex, which has no "off" and maps it to its lowest level.
67
67
  const THINKING_HINTS: Record<ProviderName, string> = {
68
- claude: 'Thinking budget handed to the model.',
68
+ claude: "Thinking budget handed to the model.",
69
69
  codex:
70
70
  'Reasoning effort handed to the model. Codex has no "off": it maps to the lowest level.',
71
- }
71
+ };
72
72
 
73
73
  const THINKING_OPTIONS: Array<{ value: Thinking; label: string }> = [
74
- { value: 'off', label: 'Off' },
75
- { value: 'low', label: 'Low' },
76
- { value: 'medium', label: 'Medium' },
77
- { value: 'high', label: 'High' },
78
- ]
74
+ { value: "off", label: "Off" },
75
+ { value: "low", label: "Low" },
76
+ { value: "medium", label: "Medium" },
77
+ { value: "high", label: "High" },
78
+ ];
79
79
 
80
80
  async function load(): Promise<void> {
81
- loading.value = true
82
- error.value = null
81
+ loading.value = true;
82
+ error.value = null;
83
83
  try {
84
- settings.value = await $authFetch<AiSettings>('/ai/settings')
84
+ settings.value = await $authFetch<AiSettings>("/ai/settings");
85
85
  } catch (e) {
86
- error.value = e instanceof Error ? e.message : String(e)
86
+ error.value = e instanceof Error ? e.message : String(e);
87
87
  } finally {
88
- loading.value = false
88
+ loading.value = false;
89
89
  }
90
90
  }
91
91
 
92
92
  async function persist(): Promise<void> {
93
- saving.value = true
94
- error.value = null
93
+ saving.value = true;
94
+ error.value = null;
95
95
  try {
96
- settings.value = await $authFetch<AiSettings>('/ai/settings', {
97
- method: 'PUT',
96
+ settings.value = await $authFetch<AiSettings>("/ai/settings", {
97
+ method: "PUT",
98
98
  body: settings.value,
99
- })
99
+ });
100
100
  } catch (e) {
101
- error.value = e instanceof Error ? e.message : String(e)
101
+ error.value = e instanceof Error ? e.message : String(e);
102
102
  } finally {
103
- saving.value = false
103
+ saving.value = false;
104
104
  }
105
105
  }
106
106
 
107
107
  function availabilityOf(name: ProviderName): ProviderAvailability {
108
- return settings.value.providers?.[name] ?? { available: false }
108
+ return settings.value.providers?.[name] ?? { available: false };
109
109
  }
110
110
 
111
111
  function providerLabel(option: ProviderOption): string {
112
112
  return availabilityOf(option.value).available
113
113
  ? option.label
114
- : `${option.label} — unavailable`
114
+ : `${option.label} — unavailable`;
115
115
  }
116
116
 
117
- const activeProvider = computed(() => settings.value.provider)
117
+ const activeProvider = computed(() => settings.value.provider);
118
118
 
119
119
  const providerReason = computed(
120
120
  () => availabilityOf(settings.value.provider).reason ?? null,
121
- )
121
+ );
122
122
 
123
123
  function onProvider(event: Event): void {
124
- const next = (event.target as HTMLSelectElement).value as ProviderName
124
+ const next = (event.target as HTMLSelectElement).value as ProviderName;
125
125
  if (!availabilityOf(next).available) {
126
126
  // The option is disabled, so this only fires on a stale DOM; snap back.
127
- ;(event.target as HTMLSelectElement).value = settings.value.provider
128
- return
127
+ (event.target as HTMLSelectElement).value = settings.value.provider;
128
+ return;
129
129
  }
130
- settings.value.provider = next
131
- void persist()
130
+ settings.value.provider = next;
131
+ void persist();
132
132
  }
133
133
 
134
134
  function onMode(event: Event): void {
135
- settings.value.mode = (event.target as HTMLSelectElement).value as Mode
136
- void persist()
135
+ settings.value.mode = (event.target as HTMLSelectElement).value as Mode;
136
+ void persist();
137
137
  }
138
138
 
139
139
  function onThinking(event: Event): void {
140
- settings.value.thinking = (event.target as HTMLSelectElement).value as Thinking
141
- void persist()
140
+ settings.value.thinking = (event.target as HTMLSelectElement)
141
+ .value as Thinking;
142
+ void persist();
142
143
  }
143
144
 
144
145
  function onAllowLocalSkills(event: Event): void {
145
- settings.value.allowLocalSkills = (event.target as HTMLInputElement).checked
146
- void persist()
146
+ settings.value.allowLocalSkills = (event.target as HTMLInputElement).checked;
147
+ void persist();
147
148
  }
148
149
 
149
150
  const activeMode = computed<GenerationMode>(() =>
150
- settings.value.generationMode === 'safe' && settings.value.builderAvailable
151
- ? 'safe'
152
- : 'vibe',
153
- )
151
+ settings.value.generationMode === "safe" && settings.value.builderAvailable
152
+ ? "safe"
153
+ : "vibe",
154
+ );
154
155
 
155
156
  function onGenerationMode(mode: GenerationMode): void {
156
- if (mode === 'safe' && !settings.value.builderAvailable) return
157
- if (mode === settings.value.generationMode) return
158
- settings.value.generationMode = mode
159
- void persist()
157
+ if (mode === "safe" && !settings.value.builderAvailable) return;
158
+ if (mode === settings.value.generationMode) return;
159
+ settings.value.generationMode = mode;
160
+ void persist();
160
161
  }
161
162
 
162
- onMounted(load)
163
+ onMounted(load);
163
164
 
164
165
  const SELECT_CLASS =
165
- 'w-full rounded-md border border-default bg-elevated px-3 py-2 text-sm'
166
+ "w-full rounded-md border border-default bg-elevated px-3 py-2 text-sm";
166
167
  </script>
167
168
 
168
169
  <template>
169
170
  <div class="flex w-full flex-col gap-5 pb-10">
170
171
  <div
171
172
  v-if="error"
172
- class="rounded-lg border border-error bg-error/10 p-4 text-sm text-error"
173
+ class="border-error bg-error/10 text-error rounded-lg border p-4 text-sm"
173
174
  >
174
175
  {{ error }}
175
176
  </div>
176
177
 
177
178
  <!-- Row 1: Provider (left) · Default behavior (right) -->
178
179
  <div class="grid gap-5 lg:grid-cols-2">
179
- <section class="rounded-xl border border-default bg-elevated/30">
180
- <header class="border-b border-default px-5 py-4">
181
- <h2 class="text-sm font-semibold text-highlighted">Provider</h2>
180
+ <section class="border-default bg-elevated/30 rounded-xl border">
181
+ <header class="border-default border-b px-5 py-4">
182
+ <h2 class="text-highlighted text-sm font-semibold">Provider</h2>
182
183
  </header>
183
184
  <div class="flex flex-col gap-4 p-5">
184
185
  <div>
185
- <label class="mb-1.5 block text-xs font-medium text-toned">Provider</label>
186
+ <label class="text-toned mb-1.5 block text-xs font-medium">
187
+ Provider
188
+ </label>
186
189
  <select
187
190
  :class="SELECT_CLASS"
188
191
  :value="activeProvider"
@@ -198,24 +201,27 @@ const SELECT_CLASS =
198
201
  {{ providerLabel(option) }}
199
202
  </option>
200
203
  </select>
201
- <p v-if="providerReason" class="mt-1.5 text-xs text-error">
204
+ <p v-if="providerReason" class="text-error mt-1.5 text-xs">
202
205
  {{ providerReason }}
203
206
  </p>
204
- <p class="mt-1.5 text-xs text-dimmed">
207
+ <p class="text-dimmed mt-1.5 text-xs">
205
208
  The provider runs its own default model. Switching provider ends
206
- the live context of open conversations; their transcripts are kept.
209
+ the live context of open conversations; their transcripts are
210
+ kept.
207
211
  </p>
208
212
  </div>
209
213
  </div>
210
214
  </section>
211
215
 
212
- <section class="rounded-xl border border-default bg-elevated/30">
213
- <header class="border-b border-default px-5 py-4">
214
- <h2 class="text-sm font-semibold text-highlighted">Default behavior</h2>
216
+ <section class="border-default bg-elevated/30 rounded-xl border">
217
+ <header class="border-default border-b px-5 py-4">
218
+ <h2 class="text-highlighted text-sm font-semibold">
219
+ Default behavior
220
+ </h2>
215
221
  </header>
216
222
  <div class="flex flex-col gap-4 p-5">
217
223
  <div>
218
- <label class="mb-1.5 block text-xs font-medium text-toned">
224
+ <label class="text-toned mb-1.5 block text-xs font-medium">
219
225
  Operating mode
220
226
  </label>
221
227
  <select
@@ -232,15 +238,15 @@ const SELECT_CLASS =
232
238
  {{ option.label }}
233
239
  </option>
234
240
  </select>
235
- <p class="mt-1.5 text-xs text-dimmed">
241
+ <p class="text-dimmed mt-1.5 text-xs">
236
242
  {{ MODE_OPTIONS.find((o) => o.value === settings.mode)?.hint }}
237
243
  </p>
238
- <p v-if="activeMode === 'safe'" class="mt-1 text-xs text-dimmed">
244
+ <p v-if="activeMode === 'safe'" class="text-dimmed mt-1 text-xs">
239
245
  {{ SAFE_MODE_MODE_NOTE }}
240
246
  </p>
241
247
  </div>
242
248
  <div>
243
- <label class="mb-1.5 block text-xs font-medium text-toned">
249
+ <label class="text-toned mb-1.5 block text-xs font-medium">
244
250
  Thinking
245
251
  </label>
246
252
  <select
@@ -257,7 +263,7 @@ const SELECT_CLASS =
257
263
  {{ option.label }}
258
264
  </option>
259
265
  </select>
260
- <p class="mt-1.5 text-xs text-dimmed">
266
+ <p class="text-dimmed mt-1.5 text-xs">
261
267
  {{ THINKING_HINTS[settings.provider] }}
262
268
  </p>
263
269
  </div>
@@ -265,20 +271,20 @@ const SELECT_CLASS =
265
271
  <label class="flex items-start gap-3">
266
272
  <input
267
273
  type="checkbox"
268
- class="mt-0.5 size-4 rounded border-default"
274
+ class="border-default mt-0.5 size-4 rounded"
269
275
  :checked="settings.allowLocalSkills"
270
276
  :disabled="loading || saving"
271
277
  @change="onAllowLocalSkills"
272
- >
278
+ />
273
279
  <span>
274
- <span class="block text-xs font-medium text-toned">
280
+ <span class="text-toned block text-xs font-medium">
275
281
  Use machine-local skills (~/.claude/skills)
276
282
  </span>
277
- <span class="mt-0.5 block text-xs text-dimmed">
278
- Adds the skills from your machine
279
- (<code>~/.claude/skills</code>) on top of the ones bundled by
280
- modules. Machine-local, so not shared with other environments.
281
- Off by default.
283
+ <span class="text-dimmed mt-0.5 block text-xs">
284
+ Adds the skills from your machine (
285
+ <code>~/.claude/skills</code>
286
+ ) on top of the ones bundled by modules. Machine-local, so not
287
+ shared with other environments. Off by default.
282
288
  </span>
283
289
  </span>
284
290
  </label>
@@ -288,10 +294,12 @@ const SELECT_CLASS =
288
294
  </div>
289
295
 
290
296
  <!-- Row 2: Generation mode (full width) -->
291
- <section class="rounded-xl border border-default bg-elevated/30">
292
- <header class="border-b border-default px-5 py-4">
293
- <h2 class="text-sm font-semibold text-highlighted">Generation mode</h2>
294
- <p class="mt-0.5 text-xs text-dimmed">Default mode applied to new prompts</p>
297
+ <section class="border-default bg-elevated/30 rounded-xl border">
298
+ <header class="border-default border-b px-5 py-4">
299
+ <h2 class="text-highlighted text-sm font-semibold">Generation mode</h2>
300
+ <p class="text-dimmed mt-0.5 text-xs">
301
+ Default mode applied to new prompts
302
+ </p>
295
303
  </header>
296
304
  <div class="grid gap-4 p-5 sm:grid-cols-2">
297
305
  <button
@@ -303,7 +311,7 @@ const SELECT_CLASS =
303
311
  ? 'border-primary bg-primary/10'
304
312
  : 'border-default',
305
313
  settings.builderAvailable
306
- ? 'cursor-pointer hover:border-primary/60'
314
+ ? 'hover:border-primary/60 cursor-pointer'
307
315
  : 'cursor-not-allowed opacity-60',
308
316
  ]"
309
317
  @click="onGenerationMode('safe')"
@@ -333,7 +341,7 @@ const SELECT_CLASS =
333
341
  Unavailable
334
342
  </UBadge>
335
343
  </div>
336
- <p class="text-xs leading-relaxed text-dimmed">
344
+ <p class="text-dimmed text-xs leading-relaxed">
337
345
  Acts only through the Builder (MCP) — emits accepted configurations,
338
346
  never raw code.
339
347
  <template v-if="!settings.builderAvailable">
@@ -348,7 +356,7 @@ const SELECT_CLASS =
348
356
  :class="
349
357
  activeMode === 'vibe'
350
358
  ? 'border-primary bg-primary/10'
351
- : 'cursor-pointer border-default hover:border-primary/60'
359
+ : 'border-default hover:border-primary/60 cursor-pointer'
352
360
  "
353
361
  @click="onGenerationMode('vibe')"
354
362
  >
@@ -368,7 +376,7 @@ const SELECT_CLASS =
368
376
  Active
369
377
  </UBadge>
370
378
  </div>
371
- <p class="text-xs leading-relaxed text-dimmed">
379
+ <p class="text-dimmed text-xs leading-relaxed">
372
380
  Free to write custom code and bespoke pages beyond the Builder
373
381
  blocks — full creative range.
374
382
  </p>
@@ -1,91 +1,91 @@
1
1
  <script setup lang="ts">
2
- import { computed, onMounted, ref } from 'vue'
2
+ import { computed, onMounted, ref } from "vue";
3
3
 
4
4
  interface SkillItem {
5
- id: string
6
- name: string
7
- description: string
8
- icon?: string
9
- category?: string
10
- tags: string[]
11
- provenance: string
12
- body: string
5
+ id: string;
6
+ name: string;
7
+ description: string;
8
+ icon?: string;
9
+ category?: string;
10
+ tags: string[];
11
+ provenance: string;
12
+ body: string;
13
13
  }
14
14
 
15
- const LOCAL_PROVENANCE = 'local'
15
+ const LOCAL_PROVENANCE = "local";
16
16
 
17
- const { $authFetch } = useAuthFetch()
17
+ const { $authFetch } = useAuthFetch();
18
18
 
19
- const items = ref<SkillItem[]>([])
20
- const loading = ref(false)
21
- const error = ref<string | null>(null)
22
- const search = ref('')
23
- const selected = ref<SkillItem | null>(null)
19
+ const items = ref<SkillItem[]>([]);
20
+ const loading = ref(false);
21
+ const error = ref<string | null>(null);
22
+ const search = ref("");
23
+ const selected = ref<SkillItem | null>(null);
24
24
 
25
25
  async function load(): Promise<void> {
26
- loading.value = true
27
- error.value = null
26
+ loading.value = true;
27
+ error.value = null;
28
28
  try {
29
- const res = await $authFetch<{ items: SkillItem[] }>('/ai/skills')
30
- items.value = res.items
29
+ const res = await $authFetch<{ items: SkillItem[] }>("/ai/skills");
30
+ items.value = res.items;
31
31
  } catch (e) {
32
- error.value = e instanceof Error ? e.message : String(e)
32
+ error.value = e instanceof Error ? e.message : String(e);
33
33
  } finally {
34
- loading.value = false
34
+ loading.value = false;
35
35
  }
36
36
  }
37
37
 
38
- onMounted(load)
38
+ onMounted(load);
39
39
 
40
40
  // Flat list, sorted by provenance then name so skills from the same package
41
41
  // stay adjacent without a grouping layer.
42
42
  const filtered = computed(() => {
43
- const q = search.value.trim().toLowerCase()
43
+ const q = search.value.trim().toLowerCase();
44
44
  return items.value
45
45
  .filter((s) => {
46
- if (q.length === 0) return true
47
- const haystack = [s.name, s.description, s.category ?? '', ...s.tags]
48
- .join(' ')
49
- .toLowerCase()
50
- return haystack.includes(q)
46
+ if (q.length === 0) return true;
47
+ const haystack = [s.name, s.description, s.category ?? "", ...s.tags]
48
+ .join(" ")
49
+ .toLowerCase();
50
+ return haystack.includes(q);
51
51
  })
52
52
  .sort(
53
53
  (a, b) =>
54
54
  a.provenance.localeCompare(b.provenance) ||
55
55
  a.name.localeCompare(b.name),
56
- )
57
- })
56
+ );
57
+ });
58
58
 
59
59
  function isLocal(provenance: string): boolean {
60
- return provenance === LOCAL_PROVENANCE
60
+ return provenance === LOCAL_PROVENANCE;
61
61
  }
62
62
 
63
63
  function open(skill: SkillItem): void {
64
- selected.value = skill
64
+ selected.value = skill;
65
65
  }
66
66
 
67
67
  function close(): void {
68
- selected.value = null
68
+ selected.value = null;
69
69
  }
70
70
 
71
71
  const CARD_CLASS =
72
- 'flex flex-col gap-2 rounded-xl border border-default bg-elevated/30 p-4 text-left transition-colors hover:border-primary'
72
+ "flex flex-col gap-2 rounded-xl border border-default bg-elevated/30 p-4 text-left transition-colors hover:border-primary";
73
73
  </script>
74
74
 
75
75
  <template>
76
76
  <div class="flex w-full flex-col gap-5 pb-10">
77
77
  <div
78
78
  v-if="error"
79
- class="rounded-lg border border-error bg-error/10 p-4 text-sm text-error"
79
+ class="border-error bg-error/10 text-error rounded-lg border p-4 text-sm"
80
80
  >
81
81
  {{ error }}
82
82
  </div>
83
83
 
84
84
  <!-- Stat row -->
85
85
  <div class="grid gap-4 sm:grid-cols-2">
86
- <div class="rounded-xl border border-default bg-elevated/30 p-4">
87
- <p class="text-xs font-medium text-toned">Total skills</p>
88
- <p class="mt-1 text-2xl font-semibold text-highlighted">
86
+ <div class="border-default bg-elevated/30 rounded-xl border p-4">
87
+ <p class="text-toned text-xs font-medium">Total skills</p>
88
+ <p class="text-highlighted mt-1 text-2xl font-semibold">
89
89
  {{ items.length }}
90
90
  </p>
91
91
  </div>
@@ -97,13 +97,13 @@ const CARD_CLASS =
97
97
  v-model="search"
98
98
  type="search"
99
99
  placeholder="Search skills…"
100
- class="w-full max-w-xs rounded-md border border-default bg-elevated px-3 py-2 text-sm"
101
- >
100
+ class="border-default bg-elevated w-full max-w-xs rounded-md border px-3 py-2 text-sm"
101
+ />
102
102
  </div>
103
103
 
104
104
  <p
105
105
  v-if="!loading && items.length === 0"
106
- class="rounded-lg border border-default bg-elevated/30 p-6 text-center text-sm text-dimmed"
106
+ class="border-default bg-elevated/30 text-dimmed rounded-lg border p-6 text-center text-sm"
107
107
  >
108
108
  No skills are loaded. Module-contributed skills appear here, plus
109
109
  machine-local skills when enabled in Settings.
@@ -121,13 +121,13 @@ const CARD_CLASS =
121
121
  <div class="flex items-start gap-2">
122
122
  <UIcon
123
123
  :name="skill.icon || 'i-ph-sparkle'"
124
- class="mt-0.5 shrink-0 text-primary"
124
+ class="text-primary mt-0.5 shrink-0"
125
125
  />
126
126
  <div class="min-w-0">
127
- <p class="truncate text-sm font-semibold text-highlighted">
127
+ <p class="text-highlighted truncate text-sm font-semibold">
128
128
  {{ skill.name }}
129
129
  </p>
130
- <p class="truncate text-xs text-dimmed">
130
+ <p class="text-dimmed truncate text-xs">
131
131
  {{ skill.provenance }}
132
132
  </p>
133
133
  </div>
@@ -141,7 +141,7 @@ const CARD_CLASS =
141
141
  Local
142
142
  </UBadge>
143
143
  </div>
144
- <p class="line-clamp-3 text-xs leading-relaxed text-toned">
144
+ <p class="text-toned line-clamp-3 text-xs leading-relaxed">
145
145
  {{ skill.description }}
146
146
  </p>
147
147
  <div v-if="skill.tags.length" class="mt-auto flex flex-wrap gap-1">
@@ -165,18 +165,18 @@ const CARD_CLASS =
165
165
  @click.self="close"
166
166
  >
167
167
  <div
168
- class="flex h-full w-full max-w-lg flex-col overflow-y-auto border-l border-default bg-default p-6 shadow-xl"
168
+ class="border-default bg-default flex h-full w-full max-w-lg flex-col overflow-y-auto border-l p-6 shadow-xl"
169
169
  >
170
170
  <div class="mb-4 flex items-start gap-3">
171
171
  <UIcon
172
172
  :name="selected.icon || 'i-ph-sparkle'"
173
- class="mt-1 shrink-0 text-xl text-primary"
173
+ class="text-primary mt-1 shrink-0 text-xl"
174
174
  />
175
175
  <div class="min-w-0 flex-1">
176
- <h2 class="text-lg font-semibold text-highlighted">
176
+ <h2 class="text-highlighted text-lg font-semibold">
177
177
  {{ selected.name }}
178
178
  </h2>
179
- <p class="text-xs text-dimmed">{{ selected.id }}</p>
179
+ <p class="text-dimmed text-xs">{{ selected.id }}</p>
180
180
  </div>
181
181
  <UButton
182
182
  icon="i-ph-x"
@@ -211,15 +211,17 @@ const CARD_CLASS =
211
211
  </UBadge>
212
212
  </div>
213
213
 
214
- <p class="mb-4 text-sm leading-relaxed text-toned">
214
+ <p class="text-toned mb-4 text-sm leading-relaxed">
215
215
  {{ selected.description }}
216
216
  </p>
217
217
 
218
- <h3 class="mb-2 text-xs font-semibold uppercase tracking-wide text-dimmed">
218
+ <h3
219
+ class="text-dimmed mb-2 text-xs font-semibold uppercase tracking-wide"
220
+ >
219
221
  Instructions (SKILL.md)
220
222
  </h3>
221
223
  <pre
222
- class="whitespace-pre-wrap rounded-lg border border-default bg-elevated/40 p-4 text-xs leading-relaxed text-toned"
224
+ class="border-default bg-elevated/40 text-toned whitespace-pre-wrap rounded-lg border p-4 text-xs leading-relaxed"
223
225
  >{{ selected.body }}</pre
224
226
  >
225
227
  </div>