feat: simplify chord guide feature; updated help doc; added hotkeys doc
This commit is contained in:
@@ -49,7 +49,7 @@ vi.mock('../localLLMConfig', async () => {
|
||||
};
|
||||
});
|
||||
|
||||
describe('processUserMessage /welcome', () => {
|
||||
describe('processUserMessage slash commands', () => {
|
||||
beforeEach(() => {
|
||||
configState.clear();
|
||||
configState.set('general.llm_provider', 'local_browser');
|
||||
@@ -132,6 +132,49 @@ describe('processUserMessage /welcome', () => {
|
||||
expect(message?.content).toContain('welcome_local_llm.md');
|
||||
});
|
||||
|
||||
it('fetches the hotkeys guide for /hotkeys', async () => {
|
||||
const result = await processUserMessage('/hotkeys');
|
||||
|
||||
expect(fetch).toHaveBeenCalledWith(expect.stringContaining('chat/hotkeys.md'));
|
||||
expect(result).toMatchObject({
|
||||
displayUserMessage: false,
|
||||
sendToLLM: false,
|
||||
finalMessageForLLM: null,
|
||||
metadata: { command: 'hotkeys' },
|
||||
});
|
||||
expect(result.pseudoAssistantResponse).toContain('chat/hotkeys.md');
|
||||
});
|
||||
|
||||
it('supports /hotkey as an alias of /hotkeys', async () => {
|
||||
const result = await processUserMessage('/hotkey');
|
||||
|
||||
expect(fetch).toHaveBeenCalledWith(expect.stringContaining('chat/hotkeys.md'));
|
||||
expect(result).toMatchObject({
|
||||
displayUserMessage: false,
|
||||
sendToLLM: false,
|
||||
finalMessageForLLM: null,
|
||||
metadata: { command: 'hotkeys' },
|
||||
});
|
||||
expect(result.pseudoAssistantResponse).toContain('chat/hotkeys.md');
|
||||
});
|
||||
|
||||
it('lists the new hotkeys commands for unknown slash commands', async () => {
|
||||
const result = await processUserMessage('/unknown foo');
|
||||
|
||||
expect(storeState.setStatus).toHaveBeenCalledWith(
|
||||
'Unknown command: /unknown. Available commands: /clear, /welcome, /help, /hotkeys, /hotkey'
|
||||
);
|
||||
expect(result.pseudoAssistantResponse).toBe(
|
||||
'Unknown command: /unknown foo.\nAvailable commands: /clear, /welcome, /help, /hotkeys, /hotkey'
|
||||
);
|
||||
expect(result).toMatchObject({
|
||||
displayUserMessage: false,
|
||||
sendToLLM: false,
|
||||
finalMessageForLLM: null,
|
||||
metadata: { command: 'unknown' },
|
||||
});
|
||||
});
|
||||
|
||||
it('blocks local-browser messages when the runtime is hard unsupported', async () => {
|
||||
detectLocalLLMRuntimeSupportMock.mockReturnValue({
|
||||
supported: false,
|
||||
|
||||
@@ -148,9 +148,37 @@ export async function processUserMessage(originalMessage: string): Promise<UserM
|
||||
}
|
||||
}
|
||||
|
||||
case '/hotkeys':
|
||||
case '/hotkey': {
|
||||
try {
|
||||
const url = `${import.meta.env.BASE_URL}chat/hotkeys.md`;
|
||||
const resp = await fetch(url);
|
||||
if (!resp.ok) {
|
||||
throw new Error(`Failed to fetch ${url}: ${resp.status}`);
|
||||
}
|
||||
const md = await resp.text();
|
||||
return {
|
||||
displayUserMessage: false,
|
||||
sendToLLM: false,
|
||||
finalMessageForLLM: null,
|
||||
pseudoAssistantResponse: md,
|
||||
metadata: { command: 'hotkeys' }
|
||||
};
|
||||
} catch (err) {
|
||||
const fallback = 'Hotkeys guide is currently unavailable.';
|
||||
return {
|
||||
displayUserMessage: false,
|
||||
sendToLLM: false,
|
||||
finalMessageForLLM: null,
|
||||
pseudoAssistantResponse: fallback,
|
||||
metadata: { command: 'hotkeys', error: String(err) }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
default: {
|
||||
const { setStatus } = useProjectStore.getState();
|
||||
const help = 'Available commands: /clear, /welcome, /help';
|
||||
const help = 'Available commands: /clear, /welcome, /help, /hotkeys, /hotkey';
|
||||
setStatus(`Unknown command: ${command}. ${help}`);
|
||||
return {
|
||||
displayUserMessage: false,
|
||||
|
||||
@@ -17,6 +17,14 @@ export const getRootNoteFromKeySignature = (keySignature: KeySignature): string
|
||||
return match[1];
|
||||
};
|
||||
|
||||
/**
|
||||
* Resolves the chord-guide mode from a key signature.
|
||||
* Chord guiding only supports major/minor quality and maps them to Ionian/Aeolian.
|
||||
*/
|
||||
export const getChordGuideModeFromKeySignature = (keySignature: KeySignature): 'ionian' | 'aeolian' => {
|
||||
return keySignature.endsWith(' minor') ? 'aeolian' : 'ionian';
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts a note name (without octave) to pitch class (0-11)
|
||||
* @param noteName - Note name like "C", "C#", "Db", "F#"
|
||||
|
||||
Reference in New Issue
Block a user