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