dexto 1.6.0 → 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.
- package/dist/agents/coding-agent/coding-agent.yml +3 -1
- package/dist/cli/assets/sounds/SOURCES.md +35 -0
- package/dist/cli/assets/sounds/boot.wav +0 -0
- package/dist/cli/assets/sounds/chime.wav +0 -0
- package/dist/cli/assets/sounds/coin.wav +0 -0
- package/dist/cli/assets/sounds/confirm.wav +0 -0
- package/dist/cli/assets/sounds/levelup.wav +0 -0
- package/dist/cli/assets/sounds/ping.wav +0 -0
- package/dist/cli/assets/sounds/powerup.wav +0 -0
- package/dist/cli/assets/sounds/startup.wav +0 -0
- package/dist/cli/assets/sounds/success.wav +0 -0
- package/dist/cli/assets/sounds/treasure.wav +0 -0
- package/dist/cli/assets/sounds/win.wav +0 -0
- package/dist/cli/commands/interactive-commands/exit-handler.d.ts +12 -0
- package/dist/cli/commands/interactive-commands/exit-handler.d.ts.map +1 -0
- package/dist/cli/commands/interactive-commands/exit-handler.js +20 -0
- package/dist/cli/commands/interactive-commands/exit-stats.d.ts +24 -0
- package/dist/cli/commands/interactive-commands/exit-stats.d.ts.map +1 -0
- package/dist/cli/commands/interactive-commands/exit-stats.js +17 -0
- package/dist/cli/commands/interactive-commands/general-commands.d.ts.map +1 -1
- package/dist/cli/commands/interactive-commands/general-commands.js +53 -3
- package/dist/cli/commands/interactive-commands/prompt-commands.d.ts.map +1 -1
- package/dist/cli/commands/interactive-commands/prompt-commands.js +12 -67
- package/dist/cli/commands/interactive-commands/session/session-commands.d.ts.map +1 -1
- package/dist/cli/commands/interactive-commands/session/session-commands.js +0 -2
- package/dist/cli/commands/interactive-commands/system/system-commands.d.ts +1 -13
- package/dist/cli/commands/interactive-commands/system/system-commands.d.ts.map +1 -1
- package/dist/cli/commands/interactive-commands/system/system-commands.js +45 -54
- package/dist/cli/ink-cli/InkCLIRefactored.d.ts.map +1 -1
- package/dist/cli/ink-cli/InkCLIRefactored.js +132 -21
- package/dist/cli/ink-cli/components/ApprovalPrompt.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/ApprovalPrompt.js +74 -20
- package/dist/cli/ink-cli/components/ElicitationForm.d.ts +5 -3
- package/dist/cli/ink-cli/components/ElicitationForm.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/ElicitationForm.js +414 -180
- package/dist/cli/ink-cli/components/ResourceAutocomplete.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/ResourceAutocomplete.js +20 -11
- package/dist/cli/ink-cli/components/SlashCommandAutocomplete.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/SlashCommandAutocomplete.js +47 -67
- package/dist/cli/ink-cli/components/StatusBar.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/StatusBar.js +10 -4
- package/dist/cli/ink-cli/components/base/BaseSelector.d.ts +2 -1
- package/dist/cli/ink-cli/components/base/BaseSelector.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/base/BaseSelector.js +37 -27
- package/dist/cli/ink-cli/components/chat/Header.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/chat/Header.js +1 -1
- package/dist/cli/ink-cli/components/chat/MessageItem.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/chat/MessageItem.js +3 -1
- package/dist/cli/ink-cli/components/chat/ToolIcon.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/chat/ToolIcon.js +5 -15
- package/dist/cli/ink-cli/components/chat/styled-boxes/LogConfigBox.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/chat/styled-boxes/LogConfigBox.js +1 -1
- package/dist/cli/ink-cli/components/modes/AlternateBufferCLI.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/modes/AlternateBufferCLI.js +4 -2
- package/dist/cli/ink-cli/components/modes/StaticCLI.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/modes/StaticCLI.js +9 -2
- package/dist/cli/ink-cli/components/overlays/CommandOutputOverlay.d.ts +13 -0
- package/dist/cli/ink-cli/components/overlays/CommandOutputOverlay.d.ts.map +1 -0
- package/dist/cli/ink-cli/components/overlays/CommandOutputOverlay.js +60 -0
- package/dist/cli/ink-cli/components/overlays/LogLevelSelector.js +1 -1
- package/dist/cli/ink-cli/components/overlays/ModelSelectorRefactored.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/overlays/ModelSelectorRefactored.js +213 -100
- package/dist/cli/ink-cli/components/overlays/PromptList.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/overlays/PromptList.js +12 -16
- package/dist/cli/ink-cli/components/overlays/SoundsSelector.d.ts +21 -0
- package/dist/cli/ink-cli/components/overlays/SoundsSelector.d.ts.map +1 -0
- package/dist/cli/ink-cli/components/overlays/SoundsSelector.js +566 -0
- package/dist/cli/ink-cli/components/overlays/ToolBrowser.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/overlays/ToolBrowser.js +94 -39
- package/dist/cli/ink-cli/components/overlays/custom-model-wizard/LocalModelWizard.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/overlays/custom-model-wizard/LocalModelWizard.js +8 -13
- package/dist/cli/ink-cli/components/renderers/FilePreviewRenderer.d.ts +3 -3
- package/dist/cli/ink-cli/components/renderers/FilePreviewRenderer.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/renderers/FilePreviewRenderer.js +6 -5
- package/dist/cli/ink-cli/components/renderers/FileRenderer.d.ts +3 -1
- package/dist/cli/ink-cli/components/renderers/FileRenderer.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/renderers/FileRenderer.js +18 -7
- package/dist/cli/ink-cli/components/renderers/ShellRenderer.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/renderers/ShellRenderer.js +7 -17
- package/dist/cli/ink-cli/components/renderers/index.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/renderers/index.js +1 -1
- package/dist/cli/ink-cli/components/shared/FocusOverlayFrame.d.ts +7 -0
- package/dist/cli/ink-cli/components/shared/FocusOverlayFrame.d.ts.map +1 -0
- package/dist/cli/ink-cli/components/shared/FocusOverlayFrame.js +8 -0
- package/dist/cli/ink-cli/components/shared/HintBar.d.ts +6 -0
- package/dist/cli/ink-cli/components/shared/HintBar.d.ts.map +1 -0
- package/dist/cli/ink-cli/components/shared/HintBar.js +6 -0
- package/dist/cli/ink-cli/constants/spinnerFrames.d.ts +2 -0
- package/dist/cli/ink-cli/constants/spinnerFrames.d.ts.map +1 -0
- package/dist/cli/ink-cli/constants/spinnerFrames.js +1 -0
- package/dist/cli/ink-cli/constants/tips.d.ts.map +1 -1
- package/dist/cli/ink-cli/constants/tips.js +1 -0
- package/dist/cli/ink-cli/containers/InputContainer.d.ts.map +1 -1
- package/dist/cli/ink-cli/containers/InputContainer.js +19 -15
- package/dist/cli/ink-cli/containers/OverlayContainer.d.ts.map +1 -1
- package/dist/cli/ink-cli/containers/OverlayContainer.js +21 -5
- package/dist/cli/ink-cli/hooks/useAnimationTick.d.ts +11 -0
- package/dist/cli/ink-cli/hooks/useAnimationTick.d.ts.map +1 -0
- package/dist/cli/ink-cli/hooks/useAnimationTick.js +54 -0
- package/dist/cli/ink-cli/hooks/useCLIState.d.ts.map +1 -1
- package/dist/cli/ink-cli/hooks/useCLIState.js +1 -0
- package/dist/cli/ink-cli/services/processStream.d.ts.map +1 -1
- package/dist/cli/ink-cli/services/processStream.js +17 -8
- package/dist/cli/ink-cli/state/initialState.d.ts.map +1 -1
- package/dist/cli/ink-cli/state/initialState.js +1 -0
- package/dist/cli/ink-cli/state/types.d.ts +13 -1
- package/dist/cli/ink-cli/state/types.d.ts.map +1 -1
- package/dist/cli/ink-cli/utils/commandOverlays.d.ts.map +1 -1
- package/dist/cli/ink-cli/utils/commandOverlays.js +1 -0
- package/dist/cli/ink-cli/utils/elicitationSchema.d.ts +11 -0
- package/dist/cli/ink-cli/utils/elicitationSchema.d.ts.map +1 -0
- package/dist/cli/ink-cli/utils/elicitationSchema.js +80 -0
- package/dist/cli/ink-cli/utils/index.d.ts +1 -1
- package/dist/cli/ink-cli/utils/index.d.ts.map +1 -1
- package/dist/cli/ink-cli/utils/index.js +1 -1
- package/dist/cli/ink-cli/utils/messageFormatting.d.ts +2 -17
- package/dist/cli/ink-cli/utils/messageFormatting.d.ts.map +1 -1
- package/dist/cli/ink-cli/utils/messageFormatting.js +22 -128
- package/dist/cli/ink-cli/utils/overlayPresentation.d.ts +19 -0
- package/dist/cli/ink-cli/utils/overlayPresentation.d.ts.map +1 -0
- package/dist/cli/ink-cli/utils/overlayPresentation.js +33 -0
- package/dist/cli/ink-cli/utils/overlaySizing.d.ts +19 -0
- package/dist/cli/ink-cli/utils/overlaySizing.d.ts.map +1 -0
- package/dist/cli/ink-cli/utils/overlaySizing.js +11 -0
- package/dist/cli/ink-cli/utils/soundNotification.d.ts +19 -13
- package/dist/cli/ink-cli/utils/soundNotification.d.ts.map +1 -1
- package/dist/cli/ink-cli/utils/soundNotification.js +120 -97
- package/dist/utils/session-logger-factory.d.ts.map +1 -1
- package/dist/utils/session-logger-factory.js +17 -2
- package/dist/webui/assets/{index-DwtueA8l.js → index-CKhumsZA.js} +135 -135
- package/dist/webui/index.html +1 -1
- package/package.json +11 -11
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PromptList.d.ts","sourceRoot":"","sources":["../../../../../src/cli/ink-cli/components/overlays/PromptList.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAQN,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,qCAAqC,CAAC;AAC/D,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAG1D,MAAM,MAAM,gBAAgB,GACtB;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,MAAM,EAAE,UAAU,CAAA;CAAE,GAC7C;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,GACtB;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,CAAC;AAEhC,UAAU,eAAe;IACrB,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAC7C,eAAe,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,KAAK,EAAE,UAAU,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC7B,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC;IAClD,OAAO,EAAE,MAAM,IAAI,CAAC;CACvB;AAuCD;;GAEG;AACH,QAAA,MAAM,UAAU,
|
|
1
|
+
{"version":3,"file":"PromptList.d.ts","sourceRoot":"","sources":["../../../../../src/cli/ink-cli/components/overlays/PromptList.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAQN,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,qCAAqC,CAAC;AAC/D,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAG1D,MAAM,MAAM,gBAAgB,GACtB;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,MAAM,EAAE,UAAU,CAAA;CAAE,GAC7C;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,GACtB;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,CAAC;AAEhC,UAAU,eAAe;IACrB,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAC7C,eAAe,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,KAAK,EAAE,UAAU,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC7B,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC;IAClD,OAAO,EAAE,MAAM,IAAI,CAAC;CACvB;AAuCD;;GAEG;AACH,QAAA,MAAM,UAAU,0FAgKd,CAAC;AAEH,eAAe,UAAU,CAAC"}
|
|
@@ -66,7 +66,7 @@ const PromptList = forwardRef(function PromptList({ isVisible, onAction, onLoadI
|
|
|
66
66
|
setIsLoading(false);
|
|
67
67
|
})
|
|
68
68
|
.catch((err) => {
|
|
69
|
-
|
|
69
|
+
agent.logger.error(`PromptList: Failed to load prompts: ${err instanceof Error ? err.message : String(err)}`);
|
|
70
70
|
setPrompts([]);
|
|
71
71
|
setIsLoading(false);
|
|
72
72
|
});
|
|
@@ -88,21 +88,17 @@ const PromptList = forwardRef(function PromptList({ isVisible, onAction, onLoadI
|
|
|
88
88
|
}, [isVisible, refreshKey, loadPrompts]);
|
|
89
89
|
// Build list items: prompts + Add/Delete actions
|
|
90
90
|
const items = useMemo(() => {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
type: '
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
id: '__delete__',
|
|
103
|
-
type: 'delete',
|
|
104
|
-
});
|
|
105
|
-
return list;
|
|
91
|
+
return [
|
|
92
|
+
// Action items at the top
|
|
93
|
+
{ id: '__add__', type: 'add' },
|
|
94
|
+
{ id: '__delete__', type: 'delete' },
|
|
95
|
+
// Prompts list
|
|
96
|
+
...prompts.map((prompt) => ({
|
|
97
|
+
id: prompt.name,
|
|
98
|
+
type: 'prompt',
|
|
99
|
+
prompt,
|
|
100
|
+
})),
|
|
101
|
+
];
|
|
106
102
|
}, [prompts]);
|
|
107
103
|
// Format item for display
|
|
108
104
|
const formatItem = (item, isSelected) => {
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SoundsSelector Component
|
|
3
|
+
* Interactive overlay for configuring sound notifications and selecting built-in sounds.
|
|
4
|
+
*
|
|
5
|
+
* Built-in sounds are copied into the Dexto sounds directory (typically ~/.dexto/sounds/builtins/)
|
|
6
|
+
* and selected via preferences.yml using paths relative to that directory (e.g., builtins/coin.wav).
|
|
7
|
+
*
|
|
8
|
+
* This reuses the existing sound resolution logic in soundNotification.ts.
|
|
9
|
+
*/
|
|
10
|
+
import React from 'react';
|
|
11
|
+
import type { Key } from '../../hooks/useInputOrchestrator.js';
|
|
12
|
+
interface SoundsSelectorProps {
|
|
13
|
+
isVisible: boolean;
|
|
14
|
+
onClose: () => void;
|
|
15
|
+
}
|
|
16
|
+
export interface SoundsSelectorHandle {
|
|
17
|
+
handleInput: (input: string, key: Key) => boolean;
|
|
18
|
+
}
|
|
19
|
+
declare const SoundsSelector: React.ForwardRefExoticComponent<SoundsSelectorProps & React.RefAttributes<SoundsSelectorHandle>>;
|
|
20
|
+
export default SoundsSelector;
|
|
21
|
+
//# sourceMappingURL=SoundsSelector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SoundsSelector.d.ts","sourceRoot":"","sources":["../../../../../src/cli/ink-cli/components/overlays/SoundsSelector.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAQN,MAAM,OAAO,CAAC;AAKf,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,qCAAqC,CAAC;AAkB/D,UAAU,mBAAmB;IACzB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,MAAM,IAAI,CAAC;CACvB;AAED,MAAM,WAAW,oBAAoB;IACjC,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC;CACrD;AAuMD,QAAA,MAAM,cAAc,kGAsiBnB,CAAC;AAEF,eAAe,cAAc,CAAC"}
|
|
@@ -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;
|
|
@@ -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;
|
|
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"}
|