( statusLineInput: StatusLineCommandInput, signal?: AbortSignal, timeoutMs: number = 5000, // Short timeout for status line logResult: boolean = false, )
| 4681 | * @returns The status line text to display, or undefined if no command configured |
| 4682 | */ |
| 4683 | export async function executeStatusLineCommand( |
| 4684 | statusLineInput: StatusLineCommandInput, |
| 4685 | signal?: AbortSignal, |
| 4686 | timeoutMs: number = 5000, // Short timeout for status line |
| 4687 | logResult: boolean = false, |
| 4688 | ): Promise<string | undefined> { |
| 4689 | // Check if all hooks (including statusLine) are disabled by managed settings |
| 4690 | if (shouldDisableAllHooksIncludingManaged()) { |
| 4691 | return undefined |
| 4692 | } |
| 4693 | |
| 4694 | // SECURITY: ALL hooks require workspace trust in interactive mode |
| 4695 | // This centralized check prevents RCE vulnerabilities for all current and future hooks |
| 4696 | if (shouldSkipHookDueToTrust()) { |
| 4697 | logForDebugging( |
| 4698 | `Skipping StatusLine command execution - workspace trust not accepted`, |
| 4699 | ) |
| 4700 | return undefined |
| 4701 | } |
| 4702 | |
| 4703 | // When disableAllHooks is set in non-managed settings, only managed statusLine runs |
| 4704 | // (non-managed settings cannot disable managed commands, but non-managed commands are disabled) |
| 4705 | let statusLine |
| 4706 | if (shouldAllowManagedHooksOnly()) { |
| 4707 | statusLine = getSettingsForSource('policySettings')?.statusLine |
| 4708 | } else { |
| 4709 | statusLine = getSettings_DEPRECATED()?.statusLine |
| 4710 | } |
| 4711 | |
| 4712 | if (!statusLine || statusLine.type !== 'command') { |
| 4713 | return undefined |
| 4714 | } |
| 4715 | |
| 4716 | // Use provided signal or create a default one |
| 4717 | const abortSignal = signal || AbortSignal.timeout(timeoutMs) |
| 4718 | |
| 4719 | try { |
| 4720 | // Convert status input to JSON |
| 4721 | const jsonInput = jsonStringify(statusLineInput) |
| 4722 | |
| 4723 | const result = await execCommandHook( |
| 4724 | statusLine, |
| 4725 | 'StatusLine', |
| 4726 | 'statusLine', |
| 4727 | jsonInput, |
| 4728 | abortSignal, |
| 4729 | randomUUID(), |
| 4730 | ) |
| 4731 | |
| 4732 | if (result.aborted) { |
| 4733 | return undefined |
| 4734 | } |
| 4735 | |
| 4736 | // For successful hooks (exit code 0), use stdout |
| 4737 | if (result.status === 0) { |
| 4738 | // Trim and split output into lines, then join with newlines |
| 4739 | const output = result.stdout |
| 4740 | .trim() |
no test coverage detected