( statusLineInput: StatusLineCommandInput, signal?: AbortSignal, timeoutMs: number = 5000, // Short timeout for status line logResult: boolean = false, )
| 4750 | * @returns The status line text to display, or undefined if no command configured |
| 4751 | */ |
| 4752 | export async function executeStatusLineCommand( |
| 4753 | statusLineInput: StatusLineCommandInput, |
| 4754 | signal?: AbortSignal, |
| 4755 | timeoutMs: number = 5000, // Short timeout for status line |
| 4756 | logResult: boolean = false, |
| 4757 | ): Promise<string | undefined> { |
| 4758 | // Check if all hooks (including statusLine) are disabled by managed settings |
| 4759 | if (shouldDisableAllHooksIncludingManaged()) { |
| 4760 | return undefined |
| 4761 | } |
| 4762 | |
| 4763 | // SECURITY: ALL hooks require workspace trust in interactive mode |
| 4764 | // This centralized check prevents RCE vulnerabilities for all current and future hooks |
| 4765 | if (shouldSkipHookDueToTrust()) { |
| 4766 | logForDebugging( |
| 4767 | `Skipping StatusLine command execution - workspace trust not accepted`, |
| 4768 | ) |
| 4769 | return undefined |
| 4770 | } |
| 4771 | |
| 4772 | // When disableAllHooks is set in non-managed settings, only managed statusLine runs |
| 4773 | // (non-managed settings cannot disable managed commands, but non-managed commands are disabled) |
| 4774 | let statusLine |
| 4775 | if (shouldAllowManagedHooksOnly()) { |
| 4776 | statusLine = getSettingsForSource('policySettings')?.statusLine |
| 4777 | } else { |
| 4778 | statusLine = getSettings_DEPRECATED()?.statusLine |
| 4779 | } |
| 4780 | |
| 4781 | if (!statusLine || statusLine.type !== 'command') { |
| 4782 | return undefined |
| 4783 | } |
| 4784 | |
| 4785 | // Use provided signal or create a default one |
| 4786 | const abortSignal = signal || AbortSignal.timeout(timeoutMs) |
| 4787 | |
| 4788 | try { |
| 4789 | // Convert status input to JSON |
| 4790 | const jsonInput = jsonStringify(statusLineInput) |
| 4791 | |
| 4792 | const result = await execCommandHook( |
| 4793 | statusLine, |
| 4794 | 'StatusLine', |
| 4795 | 'statusLine', |
| 4796 | jsonInput, |
| 4797 | abortSignal, |
| 4798 | randomUUID(), |
| 4799 | ) |
| 4800 | |
| 4801 | if (result.aborted) { |
| 4802 | return undefined |
| 4803 | } |
| 4804 | |
| 4805 | // For successful hooks (exit code 0), use stdout |
| 4806 | if (result.status === 0) { |
| 4807 | // Trim and split output into lines, then join with newlines |
| 4808 | const output = result.stdout |
| 4809 | .trim() |
no test coverage detected