dexto 1.5.8 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (224) hide show
  1. package/README.md +3 -3
  2. package/dist/agents/agent-template.yml +2 -2
  3. package/dist/agents/coding-agent/README.md +10 -10
  4. package/dist/agents/coding-agent/coding-agent.yml +84 -83
  5. package/dist/agents/default-agent.yml +32 -47
  6. package/dist/agents/explore-agent/explore-agent.yml +3 -6
  7. package/dist/agents/image-editor-agent/image-editor-agent.yml +1 -1
  8. package/dist/agents/nano-banana-agent/nano-banana-agent.yml +1 -1
  9. package/dist/agents/podcast-agent/podcast-agent.yml +1 -1
  10. package/dist/agents/product-name-researcher/product-name-researcher.yml +1 -1
  11. package/dist/agents/sora-video-agent/sora-video-agent.yml +4 -6
  12. package/dist/agents/triage-demo/triage-agent.yml +1 -1
  13. package/dist/analytics/events.d.ts +1 -1
  14. package/dist/analytics/events.d.ts.map +1 -1
  15. package/dist/api/mcp/tool-aggregation-handler.d.ts +2 -2
  16. package/dist/api/server-hono.d.ts +2 -2
  17. package/dist/api/server-hono.d.ts.map +1 -1
  18. package/dist/api/server-hono.js +37 -60
  19. package/dist/cli/approval/cli-approval-handler.d.ts +10 -3
  20. package/dist/cli/approval/cli-approval-handler.d.ts.map +1 -1
  21. package/dist/cli/approval/cli-approval-handler.js +1 -1
  22. package/dist/cli/assets/sounds/SOURCES.md +35 -0
  23. package/dist/cli/assets/sounds/boot.wav +0 -0
  24. package/dist/cli/assets/sounds/chime.wav +0 -0
  25. package/dist/cli/assets/sounds/coin.wav +0 -0
  26. package/dist/cli/assets/sounds/confirm.wav +0 -0
  27. package/dist/cli/assets/sounds/levelup.wav +0 -0
  28. package/dist/cli/assets/sounds/ping.wav +0 -0
  29. package/dist/cli/assets/sounds/powerup.wav +0 -0
  30. package/dist/cli/assets/sounds/startup.wav +0 -0
  31. package/dist/cli/assets/sounds/success.wav +0 -0
  32. package/dist/cli/assets/sounds/treasure.wav +0 -0
  33. package/dist/cli/assets/sounds/win.wav +0 -0
  34. package/dist/cli/commands/create-app.d.ts +1 -11
  35. package/dist/cli/commands/create-app.d.ts.map +1 -1
  36. package/dist/cli/commands/create-app.js +21 -545
  37. package/dist/cli/commands/create-image.d.ts.map +1 -1
  38. package/dist/cli/commands/create-image.js +54 -53
  39. package/dist/cli/commands/image.d.ts +52 -0
  40. package/dist/cli/commands/image.d.ts.map +1 -0
  41. package/dist/cli/commands/image.js +118 -0
  42. package/dist/cli/commands/index.d.ts +2 -1
  43. package/dist/cli/commands/index.d.ts.map +1 -1
  44. package/dist/cli/commands/index.js +3 -1
  45. package/dist/cli/commands/init-app.d.ts +4 -8
  46. package/dist/cli/commands/init-app.d.ts.map +1 -1
  47. package/dist/cli/commands/init-app.js +37 -161
  48. package/dist/cli/commands/interactive-commands/command-parser.d.ts +2 -0
  49. package/dist/cli/commands/interactive-commands/command-parser.d.ts.map +1 -1
  50. package/dist/cli/commands/interactive-commands/commands.d.ts +1 -1
  51. package/dist/cli/commands/interactive-commands/commands.d.ts.map +1 -1
  52. package/dist/cli/commands/interactive-commands/commands.js +2 -2
  53. package/dist/cli/commands/interactive-commands/exit-handler.d.ts +12 -0
  54. package/dist/cli/commands/interactive-commands/exit-handler.d.ts.map +1 -0
  55. package/dist/cli/commands/interactive-commands/exit-handler.js +20 -0
  56. package/dist/cli/commands/interactive-commands/exit-stats.d.ts +24 -0
  57. package/dist/cli/commands/interactive-commands/exit-stats.d.ts.map +1 -0
  58. package/dist/cli/commands/interactive-commands/exit-stats.js +17 -0
  59. package/dist/cli/commands/interactive-commands/general-commands.d.ts.map +1 -1
  60. package/dist/cli/commands/interactive-commands/general-commands.js +55 -5
  61. package/dist/cli/commands/interactive-commands/prompt-commands.d.ts.map +1 -1
  62. package/dist/cli/commands/interactive-commands/prompt-commands.js +14 -74
  63. package/dist/cli/commands/interactive-commands/session/index.d.ts +2 -1
  64. package/dist/cli/commands/interactive-commands/session/index.d.ts.map +1 -1
  65. package/dist/cli/commands/interactive-commands/session/index.js +2 -1
  66. package/dist/cli/commands/interactive-commands/session/session-commands.d.ts +2 -2
  67. package/dist/cli/commands/interactive-commands/session/session-commands.d.ts.map +1 -1
  68. package/dist/cli/commands/interactive-commands/session/session-commands.js +2 -4
  69. package/dist/cli/commands/interactive-commands/system/system-commands.d.ts +1 -13
  70. package/dist/cli/commands/interactive-commands/system/system-commands.d.ts.map +1 -1
  71. package/dist/cli/commands/interactive-commands/system/system-commands.js +52 -83
  72. package/dist/cli/commands/plugin.d.ts +4 -4
  73. package/dist/cli/commands/sync-agents.d.ts +2 -12
  74. package/dist/cli/commands/sync-agents.d.ts.map +1 -1
  75. package/dist/cli/commands/sync-agents.js +2 -50
  76. package/dist/cli/ink-cli/InkCLIRefactored.d.ts +7 -1
  77. package/dist/cli/ink-cli/InkCLIRefactored.d.ts.map +1 -1
  78. package/dist/cli/ink-cli/InkCLIRefactored.js +138 -27
  79. package/dist/cli/ink-cli/components/ApprovalPrompt.d.ts +2 -2
  80. package/dist/cli/ink-cli/components/ApprovalPrompt.d.ts.map +1 -1
  81. package/dist/cli/ink-cli/components/ApprovalPrompt.js +85 -30
  82. package/dist/cli/ink-cli/components/BackgroundTasksPanel.js +1 -1
  83. package/dist/cli/ink-cli/components/ElicitationForm.d.ts +5 -3
  84. package/dist/cli/ink-cli/components/ElicitationForm.d.ts.map +1 -1
  85. package/dist/cli/ink-cli/components/ElicitationForm.js +414 -180
  86. package/dist/cli/ink-cli/components/Footer.d.ts.map +1 -1
  87. package/dist/cli/ink-cli/components/Footer.js +1 -2
  88. package/dist/cli/ink-cli/components/ResourceAutocomplete.d.ts.map +1 -1
  89. package/dist/cli/ink-cli/components/ResourceAutocomplete.js +20 -11
  90. package/dist/cli/ink-cli/components/SlashCommandAutocomplete.d.ts.map +1 -1
  91. package/dist/cli/ink-cli/components/SlashCommandAutocomplete.js +47 -67
  92. package/dist/cli/ink-cli/components/StatusBar.d.ts.map +1 -1
  93. package/dist/cli/ink-cli/components/StatusBar.js +20 -10
  94. package/dist/cli/ink-cli/components/TodoPanel.js +1 -1
  95. package/dist/cli/ink-cli/components/base/BaseSelector.d.ts +2 -1
  96. package/dist/cli/ink-cli/components/base/BaseSelector.d.ts.map +1 -1
  97. package/dist/cli/ink-cli/components/base/BaseSelector.js +37 -27
  98. package/dist/cli/ink-cli/components/chat/Header.d.ts.map +1 -1
  99. package/dist/cli/ink-cli/components/chat/Header.js +1 -1
  100. package/dist/cli/ink-cli/components/chat/MessageItem.d.ts.map +1 -1
  101. package/dist/cli/ink-cli/components/chat/MessageItem.js +3 -1
  102. package/dist/cli/ink-cli/components/chat/ToolIcon.d.ts.map +1 -1
  103. package/dist/cli/ink-cli/components/chat/ToolIcon.js +5 -15
  104. package/dist/cli/ink-cli/components/chat/styled-boxes/ConfigBox.js +1 -1
  105. package/dist/cli/ink-cli/components/chat/styled-boxes/LogConfigBox.d.ts.map +1 -1
  106. package/dist/cli/ink-cli/components/chat/styled-boxes/LogConfigBox.js +1 -1
  107. package/dist/cli/ink-cli/components/modes/AlternateBufferCLI.d.ts +3 -1
  108. package/dist/cli/ink-cli/components/modes/AlternateBufferCLI.d.ts.map +1 -1
  109. package/dist/cli/ink-cli/components/modes/AlternateBufferCLI.js +5 -3
  110. package/dist/cli/ink-cli/components/modes/StaticCLI.d.ts +3 -1
  111. package/dist/cli/ink-cli/components/modes/StaticCLI.d.ts.map +1 -1
  112. package/dist/cli/ink-cli/components/modes/StaticCLI.js +10 -3
  113. package/dist/cli/ink-cli/components/overlays/CommandOutputOverlay.d.ts +13 -0
  114. package/dist/cli/ink-cli/components/overlays/CommandOutputOverlay.d.ts.map +1 -0
  115. package/dist/cli/ink-cli/components/overlays/CommandOutputOverlay.js +60 -0
  116. package/dist/cli/ink-cli/components/overlays/LogLevelSelector.js +1 -1
  117. package/dist/cli/ink-cli/components/overlays/ModelSelectorRefactored.d.ts.map +1 -1
  118. package/dist/cli/ink-cli/components/overlays/ModelSelectorRefactored.js +213 -100
  119. package/dist/cli/ink-cli/components/overlays/PromptList.d.ts.map +1 -1
  120. package/dist/cli/ink-cli/components/overlays/PromptList.js +12 -16
  121. package/dist/cli/ink-cli/components/overlays/SoundsSelector.d.ts +21 -0
  122. package/dist/cli/ink-cli/components/overlays/SoundsSelector.d.ts.map +1 -0
  123. package/dist/cli/ink-cli/components/overlays/SoundsSelector.js +566 -0
  124. package/dist/cli/ink-cli/components/overlays/ToolBrowser.d.ts +1 -1
  125. package/dist/cli/ink-cli/components/overlays/ToolBrowser.d.ts.map +1 -1
  126. package/dist/cli/ink-cli/components/overlays/ToolBrowser.js +100 -45
  127. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/LocalModelWizard.d.ts.map +1 -1
  128. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/LocalModelWizard.js +8 -13
  129. package/dist/cli/ink-cli/components/renderers/FilePreviewRenderer.d.ts +3 -3
  130. package/dist/cli/ink-cli/components/renderers/FilePreviewRenderer.d.ts.map +1 -1
  131. package/dist/cli/ink-cli/components/renderers/FilePreviewRenderer.js +6 -5
  132. package/dist/cli/ink-cli/components/renderers/FileRenderer.d.ts +3 -1
  133. package/dist/cli/ink-cli/components/renderers/FileRenderer.d.ts.map +1 -1
  134. package/dist/cli/ink-cli/components/renderers/FileRenderer.js +18 -7
  135. package/dist/cli/ink-cli/components/renderers/ShellRenderer.d.ts.map +1 -1
  136. package/dist/cli/ink-cli/components/renderers/ShellRenderer.js +7 -17
  137. package/dist/cli/ink-cli/components/renderers/index.d.ts.map +1 -1
  138. package/dist/cli/ink-cli/components/renderers/index.js +1 -1
  139. package/dist/cli/ink-cli/components/shared/FocusOverlayFrame.d.ts +7 -0
  140. package/dist/cli/ink-cli/components/shared/FocusOverlayFrame.d.ts.map +1 -0
  141. package/dist/cli/ink-cli/components/shared/FocusOverlayFrame.js +8 -0
  142. package/dist/cli/ink-cli/components/shared/HintBar.d.ts +6 -0
  143. package/dist/cli/ink-cli/components/shared/HintBar.d.ts.map +1 -0
  144. package/dist/cli/ink-cli/components/shared/HintBar.js +6 -0
  145. package/dist/cli/ink-cli/constants/spinnerFrames.d.ts +2 -0
  146. package/dist/cli/ink-cli/constants/spinnerFrames.d.ts.map +1 -0
  147. package/dist/cli/ink-cli/constants/spinnerFrames.js +1 -0
  148. package/dist/cli/ink-cli/constants/tips.d.ts.map +1 -1
  149. package/dist/cli/ink-cli/constants/tips.js +2 -1
  150. package/dist/cli/ink-cli/containers/InputContainer.d.ts +4 -0
  151. package/dist/cli/ink-cli/containers/InputContainer.d.ts.map +1 -1
  152. package/dist/cli/ink-cli/containers/InputContainer.js +47 -21
  153. package/dist/cli/ink-cli/containers/OverlayContainer.d.ts +2 -0
  154. package/dist/cli/ink-cli/containers/OverlayContainer.d.ts.map +1 -1
  155. package/dist/cli/ink-cli/containers/OverlayContainer.js +101 -40
  156. package/dist/cli/ink-cli/hooks/useAgentEvents.d.ts.map +1 -1
  157. package/dist/cli/ink-cli/hooks/useAgentEvents.js +15 -16
  158. package/dist/cli/ink-cli/hooks/useAnimationTick.d.ts +11 -0
  159. package/dist/cli/ink-cli/hooks/useAnimationTick.d.ts.map +1 -0
  160. package/dist/cli/ink-cli/hooks/useAnimationTick.js +54 -0
  161. package/dist/cli/ink-cli/hooks/useCLIState.d.ts.map +1 -1
  162. package/dist/cli/ink-cli/hooks/useCLIState.js +1 -0
  163. package/dist/cli/ink-cli/hooks/useTokenCounter.d.ts.map +1 -1
  164. package/dist/cli/ink-cli/hooks/useTokenCounter.js +7 -4
  165. package/dist/cli/ink-cli/services/CommandService.d.ts +1 -1
  166. package/dist/cli/ink-cli/services/CommandService.d.ts.map +1 -1
  167. package/dist/cli/ink-cli/services/CommandService.js +2 -2
  168. package/dist/cli/ink-cli/services/processStream.d.ts +2 -2
  169. package/dist/cli/ink-cli/services/processStream.d.ts.map +1 -1
  170. package/dist/cli/ink-cli/services/processStream.js +27 -19
  171. package/dist/cli/ink-cli/state/initialState.d.ts.map +1 -1
  172. package/dist/cli/ink-cli/state/initialState.js +1 -0
  173. package/dist/cli/ink-cli/state/types.d.ts +15 -3
  174. package/dist/cli/ink-cli/state/types.d.ts.map +1 -1
  175. package/dist/cli/ink-cli/utils/commandOverlays.d.ts.map +1 -1
  176. package/dist/cli/ink-cli/utils/commandOverlays.js +1 -0
  177. package/dist/cli/ink-cli/utils/elicitationSchema.d.ts +11 -0
  178. package/dist/cli/ink-cli/utils/elicitationSchema.d.ts.map +1 -0
  179. package/dist/cli/ink-cli/utils/elicitationSchema.js +80 -0
  180. package/dist/cli/ink-cli/utils/index.d.ts +1 -1
  181. package/dist/cli/ink-cli/utils/index.d.ts.map +1 -1
  182. package/dist/cli/ink-cli/utils/index.js +1 -1
  183. package/dist/cli/ink-cli/utils/messageFormatting.d.ts +10 -19
  184. package/dist/cli/ink-cli/utils/messageFormatting.d.ts.map +1 -1
  185. package/dist/cli/ink-cli/utils/messageFormatting.js +43 -262
  186. package/dist/cli/ink-cli/utils/overlayPresentation.d.ts +19 -0
  187. package/dist/cli/ink-cli/utils/overlayPresentation.d.ts.map +1 -0
  188. package/dist/cli/ink-cli/utils/overlayPresentation.js +33 -0
  189. package/dist/cli/ink-cli/utils/overlaySizing.d.ts +19 -0
  190. package/dist/cli/ink-cli/utils/overlaySizing.d.ts.map +1 -0
  191. package/dist/cli/ink-cli/utils/overlaySizing.js +11 -0
  192. package/dist/cli/ink-cli/utils/soundNotification.d.ts +19 -13
  193. package/dist/cli/ink-cli/utils/soundNotification.d.ts.map +1 -1
  194. package/dist/cli/ink-cli/utils/soundNotification.js +120 -97
  195. package/dist/cli/ink-cli/utils/toolUtils.d.ts.map +1 -1
  196. package/dist/cli/ink-cli/utils/toolUtils.js +2 -9
  197. package/dist/cli/utils/config-validation.d.ts +11 -11
  198. package/dist/cli/utils/config-validation.d.ts.map +1 -1
  199. package/dist/cli/utils/config-validation.js +56 -290
  200. package/dist/cli/utils/image-store.d.ts +16 -0
  201. package/dist/cli/utils/image-store.d.ts.map +1 -0
  202. package/dist/cli/utils/image-store.js +289 -0
  203. package/dist/cli/utils/scaffolding-utils.d.ts +5 -0
  204. package/dist/cli/utils/scaffolding-utils.d.ts.map +1 -1
  205. package/dist/cli/utils/scaffolding-utils.js +46 -4
  206. package/dist/cli/utils/template-engine.d.ts +28 -16
  207. package/dist/cli/utils/template-engine.d.ts.map +1 -1
  208. package/dist/cli/utils/template-engine.js +339 -479
  209. package/dist/config/cli-overrides.d.ts +4 -3
  210. package/dist/config/cli-overrides.d.ts.map +1 -1
  211. package/dist/config/cli-overrides.js +7 -9
  212. package/dist/index-main.d.ts +2 -0
  213. package/dist/index-main.d.ts.map +1 -0
  214. package/dist/index-main.js +1554 -0
  215. package/dist/index.js +2 -1589
  216. package/dist/utils/session-logger-factory.d.ts +3 -0
  217. package/dist/utils/session-logger-factory.d.ts.map +1 -0
  218. package/dist/utils/session-logger-factory.js +34 -0
  219. package/dist/webui/assets/{index-Cz2z7NQ8.js → index-CKhumsZA.js} +231 -231
  220. package/dist/webui/index.html +1 -1
  221. package/package.json +11 -8
  222. package/dist/cli/cli-subscriber.d.ts +0 -45
  223. package/dist/cli/cli-subscriber.d.ts.map +0 -1
  224. package/dist/cli/cli-subscriber.js +0 -204
@@ -0,0 +1,566 @@
1
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ /**
3
+ * SoundsSelector Component
4
+ * Interactive overlay for configuring sound notifications and selecting built-in sounds.
5
+ *
6
+ * Built-in sounds are copied into the Dexto sounds directory (typically ~/.dexto/sounds/builtins/)
7
+ * and selected via preferences.yml using paths relative to that directory (e.g., builtins/coin.wav).
8
+ *
9
+ * This reuses the existing sound resolution logic in soundNotification.ts.
10
+ */
11
+ import { useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState, forwardRef, } from 'react';
12
+ import { Box, Text } from 'ink';
13
+ import { fileURLToPath } from 'node:url';
14
+ import { promises as fs } from 'node:fs';
15
+ import path from 'node:path';
16
+ import { BaseSelector } from '../base/BaseSelector.js';
17
+ import { CUSTOM_SOUND_EXTENSIONS, getDefaultSoundSpec, playNotificationSound, playSoundFile, } from '../../utils/soundNotification.js';
18
+ import { useSoundService } from '../../contexts/index.js';
19
+ import { getDextoGlobalPath, globalPreferencesExist, loadGlobalPreferences, updateGlobalPreferences, } from '@dexto/agent-management';
20
+ const BUILTIN_SOUNDS = [
21
+ {
22
+ id: 'coin',
23
+ name: 'Coin',
24
+ filename: 'coin.wav',
25
+ },
26
+ {
27
+ id: 'confirm',
28
+ name: 'Confirm',
29
+ filename: 'confirm.wav',
30
+ },
31
+ {
32
+ id: 'ping',
33
+ name: 'Ping',
34
+ filename: 'ping.wav',
35
+ },
36
+ {
37
+ id: 'powerup',
38
+ name: 'Power Up',
39
+ filename: 'powerup.wav',
40
+ },
41
+ {
42
+ id: 'chime',
43
+ name: 'Chime',
44
+ filename: 'chime.wav',
45
+ },
46
+ {
47
+ id: 'levelup',
48
+ name: 'Level Up',
49
+ filename: 'levelup.wav',
50
+ },
51
+ {
52
+ id: 'boot',
53
+ name: 'Boot',
54
+ filename: 'boot.wav',
55
+ },
56
+ {
57
+ id: 'startup',
58
+ name: 'Startup',
59
+ filename: 'startup.wav',
60
+ },
61
+ {
62
+ id: 'success',
63
+ name: 'Success',
64
+ filename: 'success.wav',
65
+ },
66
+ {
67
+ id: 'win',
68
+ name: 'Win',
69
+ filename: 'win.wav',
70
+ },
71
+ {
72
+ id: 'treasure',
73
+ name: 'Treasure Chest',
74
+ filename: 'treasure.wav',
75
+ },
76
+ ];
77
+ const DEFAULT_CONFIG = {
78
+ enabled: true,
79
+ onStartup: false,
80
+ onApprovalRequired: true,
81
+ onTaskComplete: true,
82
+ };
83
+ function getSoundEnabledKey(soundType) {
84
+ switch (soundType) {
85
+ case 'startup':
86
+ return 'onStartup';
87
+ case 'approval':
88
+ return 'onApprovalRequired';
89
+ case 'complete':
90
+ return 'onTaskComplete';
91
+ }
92
+ }
93
+ function getSoundFileKey(soundType) {
94
+ switch (soundType) {
95
+ case 'startup':
96
+ return 'startupSoundFile';
97
+ case 'approval':
98
+ return 'approvalSoundFile';
99
+ case 'complete':
100
+ return 'completeSoundFile';
101
+ }
102
+ }
103
+ function selectionLabel(soundType, selection) {
104
+ if (selection.kind === 'system')
105
+ return soundType === 'startup' ? 'Startup' : 'System';
106
+ const normalizedRelative = selection.relativePath.replaceAll('\\', '/');
107
+ const builtinFilename = normalizedRelative.startsWith('builtins/')
108
+ ? normalizedRelative.slice('builtins/'.length)
109
+ : null;
110
+ if (builtinFilename) {
111
+ const builtin = BUILTIN_SOUNDS.find((s) => s.filename === builtinFilename);
112
+ if (builtin)
113
+ return builtin.name;
114
+ }
115
+ return normalizedRelative.replace(/\.[^/.]+$/, '');
116
+ }
117
+ function getAllowedCustomSoundExtensions() {
118
+ switch (process.platform) {
119
+ case 'win32':
120
+ return new Set(['.wav']);
121
+ case 'linux':
122
+ return new Set(['.wav', '.ogg', '.oga']);
123
+ default:
124
+ return new Set(CUSTOM_SOUND_EXTENSIONS);
125
+ }
126
+ }
127
+ async function listCustomSoundFiles(soundsDir) {
128
+ const allowedExtensions = getAllowedCustomSoundExtensions();
129
+ const results = [];
130
+ const walk = async (dir) => {
131
+ let entries;
132
+ try {
133
+ entries = await fs.readdir(dir, { withFileTypes: true });
134
+ }
135
+ catch (error) {
136
+ if (error.code === 'ENOENT')
137
+ return;
138
+ throw error;
139
+ }
140
+ for (const entry of entries) {
141
+ if (entry.name.startsWith('.'))
142
+ continue;
143
+ const absPath = path.join(dir, entry.name);
144
+ if (entry.isDirectory()) {
145
+ if (dir === soundsDir && entry.name === 'builtins')
146
+ continue;
147
+ await walk(absPath);
148
+ continue;
149
+ }
150
+ if (!entry.isFile())
151
+ continue;
152
+ const ext = path.extname(entry.name).toLowerCase();
153
+ if (!allowedExtensions.has(ext))
154
+ continue;
155
+ const relative = path.relative(soundsDir, absPath);
156
+ if (relative.startsWith('..') || path.isAbsolute(relative))
157
+ continue;
158
+ results.push(relative.split(path.sep).join('/'));
159
+ }
160
+ };
161
+ await walk(soundsDir);
162
+ return results.sort((a, b) => a.localeCompare(b));
163
+ }
164
+ function formatCustomSoundLabel(relativePath) {
165
+ return relativePath.replaceAll('\\', '/').replace(/\.[^/.]+$/, '');
166
+ }
167
+ function resolveSelection(soundType, config) {
168
+ const configuredRelativePath = config[getSoundFileKey(soundType)];
169
+ if (configuredRelativePath) {
170
+ return { kind: 'file', relativePath: configuredRelativePath };
171
+ }
172
+ return { kind: 'system' };
173
+ }
174
+ const SoundsSelector = forwardRef(function SoundsSelector({ isVisible, onClose }, ref) {
175
+ const soundService = useSoundService();
176
+ const baseSelectorRef = useRef(null);
177
+ const [viewMode, setViewMode] = useState('main');
178
+ const [selectedIndex, setSelectedIndex] = useState(0);
179
+ const [pickAction, setPickAction] = useState('listen');
180
+ const [isLoading, setIsLoading] = useState(false);
181
+ const [isApplying, setIsApplying] = useState(false);
182
+ const [error, setError] = useState(null);
183
+ const [canPersistPreferences, setCanPersistPreferences] = useState(false);
184
+ const [config, setConfig] = useState(DEFAULT_CONFIG);
185
+ const [customSoundFiles, setCustomSoundFiles] = useState([]);
186
+ const [approvalSelection, setApprovalSelection] = useState({
187
+ kind: 'system',
188
+ });
189
+ const [completeSelection, setCompleteSelection] = useState({
190
+ kind: 'system',
191
+ });
192
+ const [startupSelection, setStartupSelection] = useState({
193
+ kind: 'system',
194
+ });
195
+ const configRef = useRef(config);
196
+ configRef.current = config;
197
+ const closeOrBack = useCallback(() => {
198
+ if (viewMode === 'main') {
199
+ onClose();
200
+ return;
201
+ }
202
+ setViewMode('main');
203
+ setSelectedIndex(0);
204
+ setError(null);
205
+ }, [onClose, viewMode]);
206
+ useImperativeHandle(ref, () => ({
207
+ handleInput: (input, key) => {
208
+ if (!isVisible)
209
+ return false;
210
+ if (viewMode !== 'main') {
211
+ if (key.leftArrow) {
212
+ setPickAction('listen');
213
+ return true;
214
+ }
215
+ if (key.rightArrow) {
216
+ setPickAction('select');
217
+ return true;
218
+ }
219
+ }
220
+ return baseSelectorRef.current?.handleInput(input, key) ?? false;
221
+ },
222
+ }), [isVisible, viewMode]);
223
+ const builtinSoundPaths = useMemo(() => {
224
+ return BUILTIN_SOUNDS.map((sound) => ({
225
+ ...sound,
226
+ absPath: fileURLToPath(new URL(`../../../assets/sounds/${sound.filename}`, import.meta.url)),
227
+ }));
228
+ }, []);
229
+ const refreshSelections = useCallback((nextConfig) => {
230
+ setStartupSelection(resolveSelection('startup', nextConfig));
231
+ setApprovalSelection(resolveSelection('approval', nextConfig));
232
+ setCompleteSelection(resolveSelection('complete', nextConfig));
233
+ }, []);
234
+ // Load preferences + built-in sounds when becoming visible
235
+ useEffect(() => {
236
+ if (!isVisible)
237
+ return;
238
+ let cancelled = false;
239
+ setIsLoading(true);
240
+ setIsApplying(false);
241
+ setError(null);
242
+ setViewMode('main');
243
+ setSelectedIndex(0);
244
+ const run = async () => {
245
+ // Load preferences (optional)
246
+ const prefsExist = globalPreferencesExist();
247
+ setCanPersistPreferences(prefsExist);
248
+ let nextConfig = DEFAULT_CONFIG;
249
+ if (prefsExist) {
250
+ try {
251
+ const preferences = await loadGlobalPreferences();
252
+ nextConfig = {
253
+ enabled: preferences.sounds?.enabled ?? nextConfig.enabled,
254
+ onStartup: preferences.sounds?.onStartup ?? nextConfig.onStartup,
255
+ startupSoundFile: preferences.sounds?.startupSoundFile,
256
+ onApprovalRequired: preferences.sounds?.onApprovalRequired ??
257
+ nextConfig.onApprovalRequired,
258
+ approvalSoundFile: preferences.sounds?.approvalSoundFile,
259
+ onTaskComplete: preferences.sounds?.onTaskComplete ?? nextConfig.onTaskComplete,
260
+ completeSoundFile: preferences.sounds?.completeSoundFile,
261
+ };
262
+ }
263
+ catch (err) {
264
+ // Non-fatal: allow selection changes, but toggles won't persist
265
+ setCanPersistPreferences(false);
266
+ if (!cancelled) {
267
+ setError(`Failed to load preferences: ${err instanceof Error ? err.message : String(err)}`);
268
+ }
269
+ }
270
+ }
271
+ if (!cancelled) {
272
+ setConfig(nextConfig);
273
+ soundService?.setConfig(nextConfig);
274
+ refreshSelections(nextConfig);
275
+ }
276
+ const soundsDir = getDextoGlobalPath('sounds');
277
+ try {
278
+ const files = await listCustomSoundFiles(soundsDir);
279
+ if (!cancelled)
280
+ setCustomSoundFiles(files);
281
+ }
282
+ catch (err) {
283
+ if (!cancelled) {
284
+ setCustomSoundFiles([]);
285
+ setError(`Failed to load custom sounds: ${err instanceof Error ? err.message : String(err)}`);
286
+ }
287
+ }
288
+ };
289
+ void run()
290
+ .catch((err) => {
291
+ if (!cancelled) {
292
+ setError(err instanceof Error ? err.message : String(err));
293
+ }
294
+ })
295
+ .finally(() => {
296
+ if (!cancelled)
297
+ setIsLoading(false);
298
+ });
299
+ return () => {
300
+ cancelled = true;
301
+ };
302
+ }, [isVisible, refreshSelections, soundService]);
303
+ const mainItems = useMemo(() => [
304
+ { type: 'enabled', id: 'enabled' },
305
+ {
306
+ type: 'pick',
307
+ id: 'pick-startup',
308
+ soundType: 'startup',
309
+ label: 'startup sound',
310
+ },
311
+ {
312
+ type: 'pick',
313
+ id: 'pick-approval',
314
+ soundType: 'approval',
315
+ label: 'approval sound',
316
+ },
317
+ {
318
+ type: 'pick',
319
+ id: 'pick-complete',
320
+ soundType: 'complete',
321
+ label: 'completion sound',
322
+ },
323
+ ], []);
324
+ const pickSoundType = viewMode === 'pick-startup'
325
+ ? 'startup'
326
+ : viewMode === 'pick-approval'
327
+ ? 'approval'
328
+ : viewMode === 'pick-complete'
329
+ ? 'complete'
330
+ : null;
331
+ const pickItems = useMemo(() => {
332
+ if (!pickSoundType)
333
+ return [];
334
+ const current = pickSoundType === 'startup'
335
+ ? startupSelection
336
+ : pickSoundType === 'approval'
337
+ ? approvalSelection
338
+ : completeSelection;
339
+ const enabledKey = getSoundEnabledKey(pickSoundType);
340
+ const isEnabled = config[enabledKey];
341
+ const normalizedRelative = current.kind === 'file' ? current.relativePath.replaceAll('\\', '/') : null;
342
+ const items = [
343
+ {
344
+ type: 'off',
345
+ id: 'off',
346
+ label: 'Off',
347
+ isCurrent: !isEnabled,
348
+ },
349
+ {
350
+ type: 'default',
351
+ id: 'default',
352
+ label: 'Default',
353
+ isCurrent: isEnabled && current.kind === 'system',
354
+ },
355
+ ...builtinSoundPaths.map((sound) => ({
356
+ type: 'builtin',
357
+ id: sound.id,
358
+ label: sound.name,
359
+ isCurrent: isEnabled &&
360
+ normalizedRelative === path.posix.join('builtins', sound.filename),
361
+ })),
362
+ ...customSoundFiles.map((relativePath) => ({
363
+ type: 'file',
364
+ id: relativePath,
365
+ relativePath,
366
+ label: formatCustomSoundLabel(relativePath),
367
+ isCurrent: isEnabled && normalizedRelative === relativePath.replaceAll('\\', '/'),
368
+ })),
369
+ ];
370
+ return items;
371
+ }, [
372
+ approvalSelection,
373
+ builtinSoundPaths,
374
+ customSoundFiles,
375
+ completeSelection,
376
+ config,
377
+ pickSoundType,
378
+ startupSelection,
379
+ ]);
380
+ const items = viewMode === 'main' ? mainItems : pickItems;
381
+ const applyConfigUpdate = useCallback(async (partial) => {
382
+ const previousConfig = configRef.current;
383
+ const nextConfig = { ...previousConfig, ...partial };
384
+ setConfig(nextConfig);
385
+ soundService?.setConfig(partial);
386
+ refreshSelections(nextConfig);
387
+ if (!canPersistPreferences) {
388
+ return;
389
+ }
390
+ try {
391
+ await updateGlobalPreferences({ sounds: partial });
392
+ }
393
+ catch (err) {
394
+ setConfig(previousConfig);
395
+ soundService?.setConfig(previousConfig);
396
+ refreshSelections(previousConfig);
397
+ setError(err instanceof Error ? err.message : String(err));
398
+ }
399
+ }, [canPersistPreferences, refreshSelections, soundService]);
400
+ const ensureBuiltinSoundFile = useCallback(async (soundId) => {
401
+ const soundsDir = getDextoGlobalPath('sounds');
402
+ const builtinsDir = path.join(soundsDir, 'builtins');
403
+ await fs.mkdir(builtinsDir, { recursive: true });
404
+ const builtin = builtinSoundPaths.find((s) => s.id === soundId);
405
+ if (!builtin) {
406
+ throw new Error(`Unknown built-in sound: ${soundId}`);
407
+ }
408
+ const destPath = path.join(builtinsDir, builtin.filename);
409
+ await fs.copyFile(builtin.absPath, destPath);
410
+ return path.posix.join('builtins', builtin.filename);
411
+ }, [builtinSoundPaths]);
412
+ const previewPickItem = useCallback((item) => {
413
+ if (!pickSoundType)
414
+ return;
415
+ if (item.type === 'off') {
416
+ return;
417
+ }
418
+ if (item.type === 'default') {
419
+ const spec = getDefaultSoundSpec(pickSoundType);
420
+ if (spec)
421
+ playSoundFile(spec);
422
+ return;
423
+ }
424
+ if (item.type === 'builtin') {
425
+ const builtin = builtinSoundPaths.find((s) => s.id === item.id);
426
+ if (builtin) {
427
+ playSoundFile(builtin.absPath);
428
+ }
429
+ return;
430
+ }
431
+ if (item.type === 'file') {
432
+ const soundsDir = path.normalize(getDextoGlobalPath('sounds'));
433
+ const resolved = path.normalize(path.resolve(soundsDir, item.relativePath));
434
+ if (resolved === soundsDir || resolved.startsWith(soundsDir + path.sep)) {
435
+ playSoundFile(resolved);
436
+ }
437
+ }
438
+ }, [builtinSoundPaths, pickSoundType]);
439
+ const handleSelect = useCallback(async (item) => {
440
+ if (isApplying || isLoading)
441
+ return;
442
+ setIsApplying(true);
443
+ setError(null);
444
+ try {
445
+ if (item.type === 'enabled') {
446
+ await applyConfigUpdate({ enabled: !configRef.current.enabled });
447
+ return;
448
+ }
449
+ if (item.type === 'pick') {
450
+ setPickAction('listen');
451
+ setViewMode(item.id);
452
+ setSelectedIndex(0);
453
+ return;
454
+ }
455
+ if (item.type === 'off' ||
456
+ item.type === 'default' ||
457
+ item.type === 'builtin' ||
458
+ item.type === 'file') {
459
+ if (!pickSoundType)
460
+ return;
461
+ const enabledKey = getSoundEnabledKey(pickSoundType);
462
+ const fileKey = getSoundFileKey(pickSoundType);
463
+ if (pickAction === 'listen') {
464
+ previewPickItem(item);
465
+ return;
466
+ }
467
+ if (item.type === 'off') {
468
+ await applyConfigUpdate({ [enabledKey]: false });
469
+ setViewMode('main');
470
+ setSelectedIndex(0);
471
+ return;
472
+ }
473
+ if (item.type === 'default') {
474
+ const partial = {
475
+ [enabledKey]: true,
476
+ [fileKey]: undefined,
477
+ };
478
+ await applyConfigUpdate(partial);
479
+ playNotificationSound(pickSoundType, {
480
+ ...configRef.current,
481
+ ...partial,
482
+ });
483
+ }
484
+ else if (item.type === 'builtin') {
485
+ const relativePath = await ensureBuiltinSoundFile(item.id);
486
+ const partial = {
487
+ [enabledKey]: true,
488
+ [fileKey]: relativePath,
489
+ };
490
+ await applyConfigUpdate(partial);
491
+ playNotificationSound(pickSoundType, {
492
+ ...configRef.current,
493
+ ...partial,
494
+ });
495
+ }
496
+ else {
497
+ const partial = {
498
+ [enabledKey]: true,
499
+ [fileKey]: item.relativePath,
500
+ };
501
+ await applyConfigUpdate(partial);
502
+ playNotificationSound(pickSoundType, {
503
+ ...configRef.current,
504
+ ...partial,
505
+ });
506
+ }
507
+ setViewMode('main');
508
+ setSelectedIndex(0);
509
+ return;
510
+ }
511
+ }
512
+ catch (err) {
513
+ setError(err instanceof Error ? err.message : String(err));
514
+ }
515
+ finally {
516
+ setIsApplying(false);
517
+ }
518
+ }, [
519
+ applyConfigUpdate,
520
+ isApplying,
521
+ isLoading,
522
+ pickAction,
523
+ pickSoundType,
524
+ previewPickItem,
525
+ ensureBuiltinSoundFile,
526
+ ]);
527
+ const formatItem = useCallback((item, isSelected) => {
528
+ if (item.type === 'enabled') {
529
+ return (_jsxs(Text, { wrap: "truncate-end", children: [_jsxs(Text, { color: isSelected ? 'cyan' : 'gray', bold: isSelected, children: ["sounds:", ' '] }), _jsx(Text, { color: config.enabled ? 'green' : 'gray', bold: isSelected, children: config.enabled ? 'On' : 'Off' })] }));
530
+ }
531
+ if (item.type === 'pick') {
532
+ const enabled = item.soundType === 'startup'
533
+ ? config.onStartup
534
+ : item.soundType === 'approval'
535
+ ? config.onApprovalRequired
536
+ : config.onTaskComplete;
537
+ const selection = item.soundType === 'startup'
538
+ ? startupSelection
539
+ : item.soundType === 'approval'
540
+ ? approvalSelection
541
+ : completeSelection;
542
+ const currentLabel = enabled
543
+ ? selectionLabel(item.soundType, selection)
544
+ : 'Off';
545
+ return (_jsxs(Text, { color: isSelected ? 'cyan' : 'gray', bold: isSelected, wrap: "truncate-end", children: [item.label, ": ", currentLabel] }));
546
+ }
547
+ if (item.type === 'off' ||
548
+ item.type === 'default' ||
549
+ item.type === 'builtin' ||
550
+ item.type === 'file') {
551
+ return (_jsxs(Box, { flexDirection: "row", children: [_jsxs(Box, { flexGrow: 1, flexDirection: "row", children: [_jsx(Text, { color: "green", children: item.isCurrent ? '* ' : ' ' }), _jsx(Text, { color: isSelected ? 'cyan' : 'gray', bold: isSelected, wrap: "truncate-end", children: item.label })] }), isSelected && (_jsxs(Box, { flexDirection: "row", marginLeft: 1, children: [_jsxs(Text, { inverse: pickAction === 'listen', bold: pickAction === 'listen', children: [' ', "Listen", ' '] }), _jsx(Text, { children: " " }), _jsxs(Text, { inverse: pickAction === 'select', bold: pickAction === 'select', children: [' ', "Select", ' '] })] }))] }));
552
+ }
553
+ return null;
554
+ }, [approvalSelection, completeSelection, config, pickAction, startupSelection]);
555
+ const title = viewMode === 'main'
556
+ ? 'Sounds'
557
+ : pickSoundType === 'startup'
558
+ ? 'Select Startup Sound'
559
+ : pickSoundType === 'approval'
560
+ ? 'Select Approval Sound'
561
+ : 'Select Completion Sound';
562
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(BaseSelector, { ref: baseSelectorRef, items: items, isVisible: isVisible, isLoading: isLoading, loadingMessage: "Loading sound settings...", selectedIndex: selectedIndex, onSelectIndex: setSelectedIndex, onSelect: (item) => void handleSelect(item), onClose: closeOrBack, formatItem: formatItem, title: title, instructionsOverride: viewMode === 'main'
563
+ ? '↑↓ navigate • Enter toggle/select • Esc close'
564
+ : `↑↓ navigate • ←/→ Listen/Select • Enter ${pickAction === 'listen' ? 'preview' : 'select'} • Esc back`, borderColor: "magenta", emptyMessage: "No options available" }), error && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "red", wrap: "wrap", children: error }) }))] }));
565
+ });
566
+ export default SoundsSelector;
@@ -4,7 +4,7 @@
4
4
  * Features:
5
5
  * - Search/filter tools by name
6
6
  * - View tool details (description, schema)
7
- * - Shows source (MCP server or Internal)
7
+ * - Shows source (MCP server or Local)
8
8
  */
9
9
  import React from 'react';
10
10
  import type { Key } from '../../hooks/useInputOrchestrator.js';
@@ -1 +1 @@
1
- {"version":3,"file":"ToolBrowser.d.ts","sourceRoot":"","sources":["../../../../../src/cli/ink-cli/components/overlays/ToolBrowser.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAON,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,qCAAqC,CAAC;AAC/D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAI9C,UAAU,gBAAgB;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,KAAK,EAAE,UAAU,CAAC;IAClB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,iBAAiB;IAC9B,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC;CACrD;AAmBD;;GAEG;AACH,QAAA,MAAM,WAAW,4FAspBf,CAAC;AAyZH,eAAe,WAAW,CAAC"}
1
+ {"version":3,"file":"ToolBrowser.d.ts","sourceRoot":"","sources":["../../../../../src/cli/ink-cli/components/overlays/ToolBrowser.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAON,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,qCAAqC,CAAC;AAC/D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAM9C,UAAU,gBAAgB;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,KAAK,EAAE,UAAU,CAAC;IAClB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,iBAAiB;IAC9B,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC;CACrD;AAkBD;;GAEG;AACH,QAAA,MAAM,WAAW,4FA8rBf,CAAC;AAyZH,eAAe,WAAW,CAAC"}