( fileSuggestionInput: FileSuggestionCommandInput, signal?: AbortSignal, timeoutMs: number = 5000, // Short timeout for typeahead suggestions )
| 4841 | * @returns Array of file paths, or empty array if no command configured |
| 4842 | */ |
| 4843 | export async function executeFileSuggestionCommand( |
| 4844 | fileSuggestionInput: FileSuggestionCommandInput, |
| 4845 | signal?: AbortSignal, |
| 4846 | timeoutMs: number = 5000, // Short timeout for typeahead suggestions |
| 4847 | ): Promise<string[]> { |
| 4848 | // Check if all hooks are disabled by managed settings |
| 4849 | if (shouldDisableAllHooksIncludingManaged()) { |
| 4850 | return [] |
| 4851 | } |
| 4852 | |
| 4853 | // SECURITY: ALL hooks require workspace trust in interactive mode |
| 4854 | // This centralized check prevents RCE vulnerabilities for all current and future hooks |
| 4855 | if (shouldSkipHookDueToTrust()) { |
| 4856 | logForDebugging( |
| 4857 | `Skipping FileSuggestion command execution - workspace trust not accepted`, |
| 4858 | ) |
| 4859 | return [] |
| 4860 | } |
| 4861 | |
| 4862 | // When disableAllHooks is set in non-managed settings, only managed fileSuggestion runs |
| 4863 | // (non-managed settings cannot disable managed commands, but non-managed commands are disabled) |
| 4864 | let fileSuggestion |
| 4865 | if (shouldAllowManagedHooksOnly()) { |
| 4866 | fileSuggestion = getSettingsForSource('policySettings')?.fileSuggestion |
| 4867 | } else { |
| 4868 | fileSuggestion = getSettings_DEPRECATED()?.fileSuggestion |
| 4869 | } |
| 4870 | |
| 4871 | if (!fileSuggestion || fileSuggestion.type !== 'command') { |
| 4872 | return [] |
| 4873 | } |
| 4874 | |
| 4875 | // Use provided signal or create a default one |
| 4876 | const abortSignal = signal || AbortSignal.timeout(timeoutMs) |
| 4877 | |
| 4878 | try { |
| 4879 | const jsonInput = jsonStringify(fileSuggestionInput) |
| 4880 | |
| 4881 | const hook = { type: 'command' as const, command: fileSuggestion.command } |
| 4882 | |
| 4883 | const result = await execCommandHook( |
| 4884 | hook, |
| 4885 | 'FileSuggestion', |
| 4886 | 'FileSuggestion', |
| 4887 | jsonInput, |
| 4888 | abortSignal, |
| 4889 | randomUUID(), |
| 4890 | ) |
| 4891 | |
| 4892 | if (result.aborted || result.status !== 0) { |
| 4893 | return [] |
| 4894 | } |
| 4895 | |
| 4896 | return result.stdout |
| 4897 | .split('\n') |
| 4898 | .map(line => line.trim()) |
| 4899 | .filter(Boolean) |
| 4900 | } catch (error) { |
no test coverage detected