| 556 | * @returns Sorted array of key paths |
| 557 | */ |
| 558 | export function getManagedSettingsKeysForLogging( |
| 559 | settings: SettingsJson, |
| 560 | ): string[] { |
| 561 | // Use .strip() to get only valid schema keys |
| 562 | const validSettings = SettingsSchema().strip().parse(settings) as Record< |
| 563 | string, |
| 564 | unknown |
| 565 | > |
| 566 | const keysToExpand = ['permissions', 'sandbox', 'hooks'] |
| 567 | const allKeys: string[] = [] |
| 568 | |
| 569 | // Define valid nested keys for each nested setting we expand |
| 570 | const validNestedKeys: Record<string, Set<string>> = { |
| 571 | permissions: new Set([ |
| 572 | 'allow', |
| 573 | 'deny', |
| 574 | 'ask', |
| 575 | 'defaultMode', |
| 576 | 'disableBypassPermissionsMode', |
| 577 | ...(feature('TRANSCRIPT_CLASSIFIER') ? ['disableAutoMode'] : []), |
| 578 | 'additionalDirectories', |
| 579 | ]), |
| 580 | sandbox: new Set([ |
| 581 | 'enabled', |
| 582 | 'failIfUnavailable', |
| 583 | 'allowUnsandboxedCommands', |
| 584 | 'network', |
| 585 | 'filesystem', |
| 586 | 'ignoreViolations', |
| 587 | 'excludedCommands', |
| 588 | 'autoAllowBashIfSandboxed', |
| 589 | 'enableWeakerNestedSandbox', |
| 590 | 'enableWeakerNetworkIsolation', |
| 591 | 'ripgrep', |
| 592 | ]), |
| 593 | // For hooks, we use z.record with enum keys, so we validate separately |
| 594 | hooks: new Set([ |
| 595 | 'PreToolUse', |
| 596 | 'PostToolUse', |
| 597 | 'Notification', |
| 598 | 'UserPromptSubmit', |
| 599 | 'SessionStart', |
| 600 | 'SessionEnd', |
| 601 | 'Stop', |
| 602 | 'SubagentStop', |
| 603 | 'PreCompact', |
| 604 | 'PostCompact', |
| 605 | 'TeammateIdle', |
| 606 | 'TaskCreated', |
| 607 | 'TaskCompleted', |
| 608 | ]), |
| 609 | } |
| 610 | |
| 611 | for (const key of Object.keys(validSettings)) { |
| 612 | if ( |
| 613 | keysToExpand.includes(key) && |
| 614 | validSettings[key] && |
| 615 | typeof validSettings[key] === 'object' |