( statusLineInput: StatusLineCommandInput, signal?: AbortSignal, timeoutMs: number = 5000, // Short timeout for status line logResult: boolean = false, )
| 4586 | * @returns The status line text to display, or undefined if no command configured |
| 4587 | */ |
| 4588 | export async function executeStatusLineCommand( |
| 4589 | statusLineInput: StatusLineCommandInput, |
| 4590 | signal?: AbortSignal, |
| 4591 | timeoutMs: number = 5000, // Short timeout for status line |
| 4592 | logResult: boolean = false, |
| 4593 | ): Promise<string | undefined> { |
| 4594 | // Check if all hooks (including statusLine) are disabled by managed settings |
| 4595 | if (shouldDisableAllHooksIncludingManaged()) { |
| 4596 | return undefined |
| 4597 | } |
| 4598 | |
| 4599 | // SECURITY: ALL hooks require workspace trust in interactive mode |
| 4600 | // This centralized check prevents RCE vulnerabilities for all current and future hooks |
| 4601 | if (shouldSkipHookDueToTrust()) { |
| 4602 | logForDebugging( |
| 4603 | `Skipping StatusLine command execution - workspace trust not accepted`, |
| 4604 | ) |
| 4605 | return undefined |
| 4606 | } |
| 4607 | |
| 4608 | // When disableAllHooks is set in non-managed settings, only managed statusLine runs |
| 4609 | // (non-managed settings cannot disable managed commands, but non-managed commands are disabled) |
| 4610 | let statusLine |
| 4611 | if (shouldAllowManagedHooksOnly()) { |
| 4612 | statusLine = getSettingsForSource('policySettings')?.statusLine |
| 4613 | } else { |
| 4614 | statusLine = getSettings_DEPRECATED()?.statusLine |
| 4615 | } |
| 4616 | |
| 4617 | if (!statusLine || statusLine.type !== 'command') { |
| 4618 | return undefined |
| 4619 | } |
| 4620 | |
| 4621 | // Use provided signal or create a default one |
| 4622 | const abortSignal = signal || AbortSignal.timeout(timeoutMs) |
| 4623 | |
| 4624 | try { |
| 4625 | // Convert status input to JSON |
| 4626 | const jsonInput = jsonStringify(statusLineInput) |
| 4627 | |
| 4628 | const result = await execCommandHook( |
| 4629 | statusLine, |
| 4630 | 'StatusLine', |
| 4631 | 'statusLine', |
| 4632 | jsonInput, |
| 4633 | abortSignal, |
| 4634 | randomUUID(), |
| 4635 | ) |
| 4636 | |
| 4637 | if (result.aborted) { |
| 4638 | return undefined |
| 4639 | } |
| 4640 | |
| 4641 | // For successful hooks (exit code 0), use stdout |
| 4642 | if (result.status === 0) { |
| 4643 | // Trim and split output into lines, then join with newlines |
| 4644 | const output = result.stdout |
| 4645 | .trim() |
no test coverage detected