@imdigitalashish/zpi 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +2801 -0
- package/README.md +95 -0
- package/dist/cli/args.d.ts +47 -0
- package/dist/cli/args.d.ts.map +1 -0
- package/dist/cli/args.js +293 -0
- package/dist/cli/args.js.map +1 -0
- package/dist/cli/config-selector.d.ts +14 -0
- package/dist/cli/config-selector.d.ts.map +1 -0
- package/dist/cli/config-selector.js +31 -0
- package/dist/cli/config-selector.js.map +1 -0
- package/dist/cli/file-processor.d.ts +15 -0
- package/dist/cli/file-processor.d.ts.map +1 -0
- package/dist/cli/file-processor.js +79 -0
- package/dist/cli/file-processor.js.map +1 -0
- package/dist/cli/list-models.d.ts +9 -0
- package/dist/cli/list-models.d.ts.map +1 -0
- package/dist/cli/list-models.js +92 -0
- package/dist/cli/list-models.js.map +1 -0
- package/dist/cli/session-picker.d.ts +9 -0
- package/dist/cli/session-picker.d.ts.map +1 -0
- package/dist/cli/session-picker.js +34 -0
- package/dist/cli/session-picker.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +11 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +68 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +203 -0
- package/dist/config.js.map +1 -0
- package/dist/core/agent-session.d.ts +571 -0
- package/dist/core/agent-session.d.ts.map +1 -0
- package/dist/core/agent-session.js +2353 -0
- package/dist/core/agent-session.js.map +1 -0
- package/dist/core/auth-storage.d.ts +129 -0
- package/dist/core/auth-storage.d.ts.map +1 -0
- package/dist/core/auth-storage.js +394 -0
- package/dist/core/auth-storage.js.map +1 -0
- package/dist/core/bash-executor.d.ts +47 -0
- package/dist/core/bash-executor.d.ts.map +1 -0
- package/dist/core/bash-executor.js +212 -0
- package/dist/core/bash-executor.js.map +1 -0
- package/dist/core/compaction/branch-summarization.d.ts +86 -0
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -0
- package/dist/core/compaction/branch-summarization.js +242 -0
- package/dist/core/compaction/branch-summarization.js.map +1 -0
- package/dist/core/compaction/compaction.d.ts +121 -0
- package/dist/core/compaction/compaction.d.ts.map +1 -0
- package/dist/core/compaction/compaction.js +607 -0
- package/dist/core/compaction/compaction.js.map +1 -0
- package/dist/core/compaction/index.d.ts +7 -0
- package/dist/core/compaction/index.d.ts.map +1 -0
- package/dist/core/compaction/index.js +7 -0
- package/dist/core/compaction/index.js.map +1 -0
- package/dist/core/compaction/utils.d.ts +35 -0
- package/dist/core/compaction/utils.d.ts.map +1 -0
- package/dist/core/compaction/utils.js +138 -0
- package/dist/core/compaction/utils.js.map +1 -0
- package/dist/core/defaults.d.ts +3 -0
- package/dist/core/defaults.d.ts.map +1 -0
- package/dist/core/defaults.js +2 -0
- package/dist/core/defaults.js.map +1 -0
- package/dist/core/diagnostics.d.ts +15 -0
- package/dist/core/diagnostics.d.ts.map +1 -0
- package/dist/core/diagnostics.js +2 -0
- package/dist/core/diagnostics.js.map +1 -0
- package/dist/core/event-bus.d.ts +9 -0
- package/dist/core/event-bus.d.ts.map +1 -0
- package/dist/core/event-bus.js +25 -0
- package/dist/core/event-bus.js.map +1 -0
- package/dist/core/exec.d.ts +29 -0
- package/dist/core/exec.d.ts.map +1 -0
- package/dist/core/exec.js +71 -0
- package/dist/core/exec.js.map +1 -0
- package/dist/core/export-html/ansi-to-html.d.ts +22 -0
- package/dist/core/export-html/ansi-to-html.d.ts.map +1 -0
- package/dist/core/export-html/ansi-to-html.js +249 -0
- package/dist/core/export-html/ansi-to-html.js.map +1 -0
- package/dist/core/export-html/index.d.ts +34 -0
- package/dist/core/export-html/index.d.ts.map +1 -0
- package/dist/core/export-html/index.js +222 -0
- package/dist/core/export-html/index.js.map +1 -0
- package/dist/core/export-html/template.css +971 -0
- package/dist/core/export-html/template.html +54 -0
- package/dist/core/export-html/template.js +1586 -0
- package/dist/core/export-html/tool-renderer.d.ts +35 -0
- package/dist/core/export-html/tool-renderer.d.ts.map +1 -0
- package/dist/core/export-html/tool-renderer.js +57 -0
- package/dist/core/export-html/tool-renderer.js.map +1 -0
- package/dist/core/export-html/vendor/highlight.min.js +1213 -0
- package/dist/core/export-html/vendor/marked.min.js +6 -0
- package/dist/core/extensions/index.d.ts +11 -0
- package/dist/core/extensions/index.d.ts.map +1 -0
- package/dist/core/extensions/index.js +9 -0
- package/dist/core/extensions/index.js.map +1 -0
- package/dist/core/extensions/loader.d.ts +25 -0
- package/dist/core/extensions/loader.d.ts.map +1 -0
- package/dist/core/extensions/loader.js +402 -0
- package/dist/core/extensions/loader.js.map +1 -0
- package/dist/core/extensions/runner.d.ts +146 -0
- package/dist/core/extensions/runner.d.ts.map +1 -0
- package/dist/core/extensions/runner.js +626 -0
- package/dist/core/extensions/runner.js.map +1 -0
- package/dist/core/extensions/types.d.ts +984 -0
- package/dist/core/extensions/types.d.ts.map +1 -0
- package/dist/core/extensions/types.js +35 -0
- package/dist/core/extensions/types.js.map +1 -0
- package/dist/core/extensions/wrapper.d.ts +27 -0
- package/dist/core/extensions/wrapper.d.ts.map +1 -0
- package/dist/core/extensions/wrapper.js +102 -0
- package/dist/core/extensions/wrapper.js.map +1 -0
- package/dist/core/footer-data-provider.d.ts +32 -0
- package/dist/core/footer-data-provider.d.ts.map +1 -0
- package/dist/core/footer-data-provider.js +134 -0
- package/dist/core/footer-data-provider.js.map +1 -0
- package/dist/core/index.d.ts +9 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +9 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/keybindings.d.ts +55 -0
- package/dist/core/keybindings.d.ts.map +1 -0
- package/dist/core/keybindings.js +153 -0
- package/dist/core/keybindings.js.map +1 -0
- package/dist/core/memory.d.ts +64 -0
- package/dist/core/memory.d.ts.map +1 -0
- package/dist/core/memory.js +247 -0
- package/dist/core/memory.js.map +1 -0
- package/dist/core/messages.d.ts +77 -0
- package/dist/core/messages.d.ts.map +1 -0
- package/dist/core/messages.js +149 -0
- package/dist/core/messages.js.map +1 -0
- package/dist/core/model-registry.d.ts +102 -0
- package/dist/core/model-registry.d.ts.map +1 -0
- package/dist/core/model-registry.js +515 -0
- package/dist/core/model-registry.js.map +1 -0
- package/dist/core/model-resolver.d.ts +104 -0
- package/dist/core/model-resolver.d.ts.map +1 -0
- package/dist/core/model-resolver.js +403 -0
- package/dist/core/model-resolver.js.map +1 -0
- package/dist/core/package-manager.d.ts +151 -0
- package/dist/core/package-manager.d.ts.map +1 -0
- package/dist/core/package-manager.js +1426 -0
- package/dist/core/package-manager.js.map +1 -0
- package/dist/core/prompt-templates.d.ts +50 -0
- package/dist/core/prompt-templates.d.ts.map +1 -0
- package/dist/core/prompt-templates.js +251 -0
- package/dist/core/prompt-templates.js.map +1 -0
- package/dist/core/resolve-config-value.d.ts +17 -0
- package/dist/core/resolve-config-value.d.ts.map +1 -0
- package/dist/core/resolve-config-value.js +59 -0
- package/dist/core/resolve-config-value.js.map +1 -0
- package/dist/core/resource-loader.d.ts +184 -0
- package/dist/core/resource-loader.d.ts.map +1 -0
- package/dist/core/resource-loader.js +673 -0
- package/dist/core/resource-loader.js.map +1 -0
- package/dist/core/sdk.d.ts +90 -0
- package/dist/core/sdk.d.ts.map +1 -0
- package/dist/core/sdk.js +238 -0
- package/dist/core/sdk.js.map +1 -0
- package/dist/core/session-manager.d.ts +323 -0
- package/dist/core/session-manager.d.ts.map +1 -0
- package/dist/core/session-manager.js +1091 -0
- package/dist/core/session-manager.js.map +1 -0
- package/dist/core/settings-manager.d.ts +230 -0
- package/dist/core/settings-manager.d.ts.map +1 -0
- package/dist/core/settings-manager.js +656 -0
- package/dist/core/settings-manager.js.map +1 -0
- package/dist/core/skills.d.ts +58 -0
- package/dist/core/skills.d.ts.map +1 -0
- package/dist/core/skills.js +364 -0
- package/dist/core/skills.js.map +1 -0
- package/dist/core/slash-commands.d.ts +15 -0
- package/dist/core/slash-commands.d.ts.map +1 -0
- package/dist/core/slash-commands.js +23 -0
- package/dist/core/slash-commands.js.map +1 -0
- package/dist/core/system-prompt.d.ts +26 -0
- package/dist/core/system-prompt.d.ts.map +1 -0
- package/dist/core/system-prompt.js +150 -0
- package/dist/core/system-prompt.js.map +1 -0
- package/dist/core/timings.d.ts +7 -0
- package/dist/core/timings.d.ts.map +1 -0
- package/dist/core/timings.js +25 -0
- package/dist/core/timings.js.map +1 -0
- package/dist/core/tools/bash.d.ts +55 -0
- package/dist/core/tools/bash.d.ts.map +1 -0
- package/dist/core/tools/bash.js +242 -0
- package/dist/core/tools/bash.js.map +1 -0
- package/dist/core/tools/edit-diff.d.ts +63 -0
- package/dist/core/tools/edit-diff.d.ts.map +1 -0
- package/dist/core/tools/edit-diff.js +243 -0
- package/dist/core/tools/edit-diff.js.map +1 -0
- package/dist/core/tools/edit.d.ts +39 -0
- package/dist/core/tools/edit.d.ts.map +1 -0
- package/dist/core/tools/edit.js +146 -0
- package/dist/core/tools/edit.js.map +1 -0
- package/dist/core/tools/find.d.ts +39 -0
- package/dist/core/tools/find.d.ts.map +1 -0
- package/dist/core/tools/find.js +206 -0
- package/dist/core/tools/find.js.map +1 -0
- package/dist/core/tools/grep.d.ts +45 -0
- package/dist/core/tools/grep.d.ts.map +1 -0
- package/dist/core/tools/grep.js +239 -0
- package/dist/core/tools/grep.js.map +1 -0
- package/dist/core/tools/index.d.ts +102 -0
- package/dist/core/tools/index.d.ts.map +1 -0
- package/dist/core/tools/index.js +71 -0
- package/dist/core/tools/index.js.map +1 -0
- package/dist/core/tools/ls.d.ts +40 -0
- package/dist/core/tools/ls.d.ts.map +1 -0
- package/dist/core/tools/ls.js +118 -0
- package/dist/core/tools/ls.js.map +1 -0
- package/dist/core/tools/memory.d.ts +45 -0
- package/dist/core/tools/memory.d.ts.map +1 -0
- package/dist/core/tools/memory.js +346 -0
- package/dist/core/tools/memory.js.map +1 -0
- package/dist/core/tools/path-utils.d.ts +8 -0
- package/dist/core/tools/path-utils.d.ts.map +1 -0
- package/dist/core/tools/path-utils.js +81 -0
- package/dist/core/tools/path-utils.js.map +1 -0
- package/dist/core/tools/read.d.ts +39 -0
- package/dist/core/tools/read.d.ts.map +1 -0
- package/dist/core/tools/read.js +166 -0
- package/dist/core/tools/read.js.map +1 -0
- package/dist/core/tools/truncate.d.ts +70 -0
- package/dist/core/tools/truncate.d.ts.map +1 -0
- package/dist/core/tools/truncate.js +205 -0
- package/dist/core/tools/truncate.js.map +1 -0
- package/dist/core/tools/write.d.ts +29 -0
- package/dist/core/tools/write.d.ts.map +1 -0
- package/dist/core/tools/write.js +78 -0
- package/dist/core/tools/write.js.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +43 -0
- package/dist/index.js.map +1 -0
- package/dist/main.d.ts +8 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +651 -0
- package/dist/main.js.map +1 -0
- package/dist/migrations.d.ts +33 -0
- package/dist/migrations.d.ts.map +1 -0
- package/dist/migrations.js +261 -0
- package/dist/migrations.js.map +1 -0
- package/dist/modes/index.d.ts +9 -0
- package/dist/modes/index.d.ts.map +1 -0
- package/dist/modes/index.js +8 -0
- package/dist/modes/index.js.map +1 -0
- package/dist/modes/interactive/components/armin.d.ts +34 -0
- package/dist/modes/interactive/components/armin.d.ts.map +1 -0
- package/dist/modes/interactive/components/armin.js +333 -0
- package/dist/modes/interactive/components/armin.js.map +1 -0
- package/dist/modes/interactive/components/assistant-message.d.ts +16 -0
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -0
- package/dist/modes/interactive/components/assistant-message.js +96 -0
- package/dist/modes/interactive/components/assistant-message.js.map +1 -0
- package/dist/modes/interactive/components/bash-execution.d.ts +35 -0
- package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -0
- package/dist/modes/interactive/components/bash-execution.js +162 -0
- package/dist/modes/interactive/components/bash-execution.js.map +1 -0
- package/dist/modes/interactive/components/bordered-loader.d.ts +16 -0
- package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -0
- package/dist/modes/interactive/components/bordered-loader.js +51 -0
- package/dist/modes/interactive/components/bordered-loader.js.map +1 -0
- package/dist/modes/interactive/components/branch-summary-message.d.ts +16 -0
- package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -0
- package/dist/modes/interactive/components/branch-summary-message.js +44 -0
- package/dist/modes/interactive/components/branch-summary-message.js.map +1 -0
- package/dist/modes/interactive/components/compaction-summary-message.d.ts +16 -0
- package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -0
- package/dist/modes/interactive/components/compaction-summary-message.js +45 -0
- package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -0
- package/dist/modes/interactive/components/config-selector.d.ts +71 -0
- package/dist/modes/interactive/components/config-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/config-selector.js +479 -0
- package/dist/modes/interactive/components/config-selector.js.map +1 -0
- package/dist/modes/interactive/components/countdown-timer.d.ts +14 -0
- package/dist/modes/interactive/components/countdown-timer.d.ts.map +1 -0
- package/dist/modes/interactive/components/countdown-timer.js +33 -0
- package/dist/modes/interactive/components/countdown-timer.js.map +1 -0
- package/dist/modes/interactive/components/custom-editor.d.ts +21 -0
- package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -0
- package/dist/modes/interactive/components/custom-editor.js +70 -0
- package/dist/modes/interactive/components/custom-editor.js.map +1 -0
- package/dist/modes/interactive/components/custom-message.d.ts +20 -0
- package/dist/modes/interactive/components/custom-message.d.ts.map +1 -0
- package/dist/modes/interactive/components/custom-message.js +79 -0
- package/dist/modes/interactive/components/custom-message.js.map +1 -0
- package/dist/modes/interactive/components/daxnuts.d.ts +23 -0
- package/dist/modes/interactive/components/daxnuts.d.ts.map +1 -0
- package/dist/modes/interactive/components/daxnuts.js +140 -0
- package/dist/modes/interactive/components/daxnuts.js.map +1 -0
- package/dist/modes/interactive/components/diff.d.ts +12 -0
- package/dist/modes/interactive/components/diff.d.ts.map +1 -0
- package/dist/modes/interactive/components/diff.js +133 -0
- package/dist/modes/interactive/components/diff.js.map +1 -0
- package/dist/modes/interactive/components/dynamic-border.d.ts +15 -0
- package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -0
- package/dist/modes/interactive/components/dynamic-border.js +21 -0
- package/dist/modes/interactive/components/dynamic-border.js.map +1 -0
- package/dist/modes/interactive/components/extension-editor.d.ts +17 -0
- package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -0
- package/dist/modes/interactive/components/extension-editor.js +102 -0
- package/dist/modes/interactive/components/extension-editor.js.map +1 -0
- package/dist/modes/interactive/components/extension-input.d.ts +23 -0
- package/dist/modes/interactive/components/extension-input.d.ts.map +1 -0
- package/dist/modes/interactive/components/extension-input.js +61 -0
- package/dist/modes/interactive/components/extension-input.js.map +1 -0
- package/dist/modes/interactive/components/extension-selector.d.ts +24 -0
- package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/extension-selector.js +78 -0
- package/dist/modes/interactive/components/extension-selector.js.map +1 -0
- package/dist/modes/interactive/components/footer.d.ts +26 -0
- package/dist/modes/interactive/components/footer.d.ts.map +1 -0
- package/dist/modes/interactive/components/footer.js +213 -0
- package/dist/modes/interactive/components/footer.js.map +1 -0
- package/dist/modes/interactive/components/index.d.ts +32 -0
- package/dist/modes/interactive/components/index.d.ts.map +1 -0
- package/dist/modes/interactive/components/index.js +33 -0
- package/dist/modes/interactive/components/index.js.map +1 -0
- package/dist/modes/interactive/components/keybinding-hints.d.ts +41 -0
- package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -0
- package/dist/modes/interactive/components/keybinding-hints.js +61 -0
- package/dist/modes/interactive/components/keybinding-hints.js.map +1 -0
- package/dist/modes/interactive/components/login-dialog.d.ts +42 -0
- package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -0
- package/dist/modes/interactive/components/login-dialog.js +145 -0
- package/dist/modes/interactive/components/login-dialog.js.map +1 -0
- package/dist/modes/interactive/components/model-selector.d.ts +47 -0
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/model-selector.js +271 -0
- package/dist/modes/interactive/components/model-selector.js.map +1 -0
- package/dist/modes/interactive/components/oauth-selector.d.ts +19 -0
- package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/oauth-selector.js +97 -0
- package/dist/modes/interactive/components/oauth-selector.js.map +1 -0
- package/dist/modes/interactive/components/scoped-models-selector.d.ts +49 -0
- package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/scoped-models-selector.js +275 -0
- package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -0
- package/dist/modes/interactive/components/session-selector-search.d.ts +23 -0
- package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -0
- package/dist/modes/interactive/components/session-selector-search.js +155 -0
- package/dist/modes/interactive/components/session-selector-search.js.map +1 -0
- package/dist/modes/interactive/components/session-selector.d.ts +95 -0
- package/dist/modes/interactive/components/session-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/session-selector.js +851 -0
- package/dist/modes/interactive/components/session-selector.js.map +1 -0
- package/dist/modes/interactive/components/settings-selector.d.ts +58 -0
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/settings-selector.js +299 -0
- package/dist/modes/interactive/components/settings-selector.js.map +1 -0
- package/dist/modes/interactive/components/show-images-selector.d.ts +10 -0
- package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/show-images-selector.js +35 -0
- package/dist/modes/interactive/components/show-images-selector.js.map +1 -0
- package/dist/modes/interactive/components/skill-invocation-message.d.ts +17 -0
- package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -0
- package/dist/modes/interactive/components/skill-invocation-message.js +47 -0
- package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -0
- package/dist/modes/interactive/components/theme-selector.d.ts +11 -0
- package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/theme-selector.js +46 -0
- package/dist/modes/interactive/components/theme-selector.js.map +1 -0
- package/dist/modes/interactive/components/thinking-selector.d.ts +11 -0
- package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/thinking-selector.js +47 -0
- package/dist/modes/interactive/components/thinking-selector.js.map +1 -0
- package/dist/modes/interactive/components/tool-execution.d.ts +70 -0
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -0
- package/dist/modes/interactive/components/tool-execution.js +636 -0
- package/dist/modes/interactive/components/tool-execution.js.map +1 -0
- package/dist/modes/interactive/components/tree-selector.d.ts +68 -0
- package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/tree-selector.js +934 -0
- package/dist/modes/interactive/components/tree-selector.js.map +1 -0
- package/dist/modes/interactive/components/user-message-selector.d.ts +30 -0
- package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/user-message-selector.js +113 -0
- package/dist/modes/interactive/components/user-message-selector.js.map +1 -0
- package/dist/modes/interactive/components/user-message.d.ts +8 -0
- package/dist/modes/interactive/components/user-message.d.ts.map +1 -0
- package/dist/modes/interactive/components/user-message.js +16 -0
- package/dist/modes/interactive/components/user-message.js.map +1 -0
- package/dist/modes/interactive/components/visual-truncate.d.ts +24 -0
- package/dist/modes/interactive/components/visual-truncate.d.ts.map +1 -0
- package/dist/modes/interactive/components/visual-truncate.js +33 -0
- package/dist/modes/interactive/components/visual-truncate.js.map +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts +316 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-mode.js +3848 -0
- package/dist/modes/interactive/interactive-mode.js.map +1 -0
- package/dist/modes/interactive/theme/dark.json +85 -0
- package/dist/modes/interactive/theme/light.json +84 -0
- package/dist/modes/interactive/theme/theme-schema.json +335 -0
- package/dist/modes/interactive/theme/theme.d.ts +78 -0
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -0
- package/dist/modes/interactive/theme/theme.js +944 -0
- package/dist/modes/interactive/theme/theme.js.map +1 -0
- package/dist/modes/print-mode.d.ts +28 -0
- package/dist/modes/print-mode.d.ts.map +1 -0
- package/dist/modes/print-mode.js +101 -0
- package/dist/modes/print-mode.js.map +1 -0
- package/dist/modes/rpc/rpc-client.d.ts +217 -0
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -0
- package/dist/modes/rpc/rpc-client.js +405 -0
- package/dist/modes/rpc/rpc-client.js.map +1 -0
- package/dist/modes/rpc/rpc-mode.d.ts +20 -0
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -0
- package/dist/modes/rpc/rpc-mode.js +511 -0
- package/dist/modes/rpc/rpc-mode.js.map +1 -0
- package/dist/modes/rpc/rpc-types.d.ts +409 -0
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -0
- package/dist/modes/rpc/rpc-types.js +8 -0
- package/dist/modes/rpc/rpc-types.js.map +1 -0
- package/dist/utils/changelog.d.ts +21 -0
- package/dist/utils/changelog.d.ts.map +1 -0
- package/dist/utils/changelog.js +87 -0
- package/dist/utils/changelog.js.map +1 -0
- package/dist/utils/clipboard-image.d.ts +11 -0
- package/dist/utils/clipboard-image.d.ts.map +1 -0
- package/dist/utils/clipboard-image.js +162 -0
- package/dist/utils/clipboard-image.js.map +1 -0
- package/dist/utils/clipboard-native.d.ts +7 -0
- package/dist/utils/clipboard-native.d.ts.map +1 -0
- package/dist/utils/clipboard-native.js +14 -0
- package/dist/utils/clipboard-native.js.map +1 -0
- package/dist/utils/clipboard.d.ts +2 -0
- package/dist/utils/clipboard.d.ts.map +1 -0
- package/dist/utils/clipboard.js +67 -0
- package/dist/utils/clipboard.js.map +1 -0
- package/dist/utils/frontmatter.d.ts +8 -0
- package/dist/utils/frontmatter.d.ts.map +1 -0
- package/dist/utils/frontmatter.js +26 -0
- package/dist/utils/frontmatter.js.map +1 -0
- package/dist/utils/git.d.ts +26 -0
- package/dist/utils/git.d.ts.map +1 -0
- package/dist/utils/git.js +163 -0
- package/dist/utils/git.js.map +1 -0
- package/dist/utils/image-convert.d.ts +9 -0
- package/dist/utils/image-convert.d.ts.map +1 -0
- package/dist/utils/image-convert.js +35 -0
- package/dist/utils/image-convert.js.map +1 -0
- package/dist/utils/image-resize.d.ts +36 -0
- package/dist/utils/image-resize.d.ts.map +1 -0
- package/dist/utils/image-resize.js +181 -0
- package/dist/utils/image-resize.js.map +1 -0
- package/dist/utils/mime.d.ts +2 -0
- package/dist/utils/mime.d.ts.map +1 -0
- package/dist/utils/mime.js +26 -0
- package/dist/utils/mime.js.map +1 -0
- package/dist/utils/photon.d.ts +21 -0
- package/dist/utils/photon.d.ts.map +1 -0
- package/dist/utils/photon.js +121 -0
- package/dist/utils/photon.js.map +1 -0
- package/dist/utils/shell.d.ts +26 -0
- package/dist/utils/shell.d.ts.map +1 -0
- package/dist/utils/shell.js +186 -0
- package/dist/utils/shell.js.map +1 -0
- package/dist/utils/sleep.d.ts +5 -0
- package/dist/utils/sleep.d.ts.map +1 -0
- package/dist/utils/sleep.js +17 -0
- package/dist/utils/sleep.js.map +1 -0
- package/dist/utils/tools-manager.d.ts +3 -0
- package/dist/utils/tools-manager.d.ts.map +1 -0
- package/dist/utils/tools-manager.js +207 -0
- package/dist/utils/tools-manager.js.map +1 -0
- package/docs/compaction.md +390 -0
- package/docs/custom-provider.md +548 -0
- package/docs/development.md +69 -0
- package/docs/extensions.md +1935 -0
- package/docs/images/doom-extension.png +0 -0
- package/docs/images/exy.png +0 -0
- package/docs/images/interactive-mode.png +0 -0
- package/docs/images/tree-view.png +0 -0
- package/docs/json.md +79 -0
- package/docs/keybindings.md +174 -0
- package/docs/models.md +293 -0
- package/docs/packages.md +209 -0
- package/docs/prompt-templates.md +67 -0
- package/docs/providers.md +186 -0
- package/docs/rpc.md +1317 -0
- package/docs/sdk.md +968 -0
- package/docs/session.md +412 -0
- package/docs/settings.md +223 -0
- package/docs/shell-aliases.md +13 -0
- package/docs/skills.md +231 -0
- package/docs/terminal-setup.md +70 -0
- package/docs/termux.md +127 -0
- package/docs/themes.md +295 -0
- package/docs/tree.md +219 -0
- package/docs/tui.md +887 -0
- package/docs/windows.md +17 -0
- package/examples/README.md +25 -0
- package/examples/extensions/README.md +203 -0
- package/examples/extensions/antigravity-image-gen.ts +413 -0
- package/examples/extensions/auto-commit-on-exit.ts +49 -0
- package/examples/extensions/bash-spawn-hook.ts +30 -0
- package/examples/extensions/bookmark.ts +50 -0
- package/examples/extensions/claude-rules.ts +86 -0
- package/examples/extensions/commands.ts +72 -0
- package/examples/extensions/confirm-destructive.ts +59 -0
- package/examples/extensions/custom-compaction.ts +114 -0
- package/examples/extensions/custom-footer.ts +64 -0
- package/examples/extensions/custom-header.ts +73 -0
- package/examples/extensions/custom-provider-anthropic/index.ts +604 -0
- package/examples/extensions/custom-provider-anthropic/package-lock.json +24 -0
- package/examples/extensions/custom-provider-anthropic/package.json +19 -0
- package/examples/extensions/custom-provider-gitlab-duo/index.ts +349 -0
- package/examples/extensions/custom-provider-gitlab-duo/package.json +16 -0
- package/examples/extensions/custom-provider-gitlab-duo/test.ts +82 -0
- package/examples/extensions/custom-provider-qwen-cli/index.ts +345 -0
- package/examples/extensions/custom-provider-qwen-cli/package.json +16 -0
- package/examples/extensions/dirty-repo-guard.ts +56 -0
- package/examples/extensions/doom-overlay/README.md +46 -0
- package/examples/extensions/doom-overlay/doom/build/doom.js +21 -0
- package/examples/extensions/doom-overlay/doom/build/doom.wasm +0 -0
- package/examples/extensions/doom-overlay/doom/build.sh +152 -0
- package/examples/extensions/doom-overlay/doom/doomgeneric_pi.c +72 -0
- package/examples/extensions/doom-overlay/doom-component.ts +132 -0
- package/examples/extensions/doom-overlay/doom-engine.ts +173 -0
- package/examples/extensions/doom-overlay/doom-keys.ts +104 -0
- package/examples/extensions/doom-overlay/index.ts +74 -0
- package/examples/extensions/doom-overlay/wad-finder.ts +51 -0
- package/examples/extensions/dynamic-resources/SKILL.md +8 -0
- package/examples/extensions/dynamic-resources/dynamic.json +79 -0
- package/examples/extensions/dynamic-resources/dynamic.md +5 -0
- package/examples/extensions/dynamic-resources/index.ts +15 -0
- package/examples/extensions/event-bus.ts +43 -0
- package/examples/extensions/file-trigger.ts +41 -0
- package/examples/extensions/git-checkpoint.ts +53 -0
- package/examples/extensions/handoff.ts +150 -0
- package/examples/extensions/hello.ts +25 -0
- package/examples/extensions/inline-bash.ts +94 -0
- package/examples/extensions/input-transform.ts +43 -0
- package/examples/extensions/interactive-shell.ts +196 -0
- package/examples/extensions/mac-system-theme.ts +47 -0
- package/examples/extensions/message-renderer.ts +59 -0
- package/examples/extensions/minimal-mode.ts +426 -0
- package/examples/extensions/modal-editor.ts +85 -0
- package/examples/extensions/model-status.ts +31 -0
- package/examples/extensions/notify.ts +55 -0
- package/examples/extensions/overlay-qa-tests.ts +881 -0
- package/examples/extensions/overlay-test.ts +150 -0
- package/examples/extensions/permission-gate.ts +34 -0
- package/examples/extensions/pirate.ts +47 -0
- package/examples/extensions/plan-mode/README.md +65 -0
- package/examples/extensions/plan-mode/index.ts +340 -0
- package/examples/extensions/plan-mode/utils.ts +168 -0
- package/examples/extensions/preset.ts +398 -0
- package/examples/extensions/protected-paths.ts +30 -0
- package/examples/extensions/qna.ts +119 -0
- package/examples/extensions/question.ts +264 -0
- package/examples/extensions/questionnaire.ts +427 -0
- package/examples/extensions/rainbow-editor.ts +88 -0
- package/examples/extensions/reload-runtime.ts +37 -0
- package/examples/extensions/rpc-demo.ts +124 -0
- package/examples/extensions/sandbox/index.ts +318 -0
- package/examples/extensions/sandbox/package-lock.json +92 -0
- package/examples/extensions/sandbox/package.json +19 -0
- package/examples/extensions/send-user-message.ts +97 -0
- package/examples/extensions/session-name.ts +27 -0
- package/examples/extensions/shutdown-command.ts +63 -0
- package/examples/extensions/snake.ts +343 -0
- package/examples/extensions/space-invaders.ts +560 -0
- package/examples/extensions/ssh.ts +220 -0
- package/examples/extensions/status-line.ts +40 -0
- package/examples/extensions/subagent/README.md +172 -0
- package/examples/extensions/subagent/agents/planner.md +37 -0
- package/examples/extensions/subagent/agents/reviewer.md +35 -0
- package/examples/extensions/subagent/agents/scout.md +50 -0
- package/examples/extensions/subagent/agents/worker.md +24 -0
- package/examples/extensions/subagent/agents.ts +127 -0
- package/examples/extensions/subagent/index.ts +964 -0
- package/examples/extensions/subagent/prompts/implement-and-review.md +10 -0
- package/examples/extensions/subagent/prompts/implement.md +10 -0
- package/examples/extensions/subagent/prompts/scout-and-plan.md +9 -0
- package/examples/extensions/summarize.ts +195 -0
- package/examples/extensions/system-prompt-header.ts +17 -0
- package/examples/extensions/timed-confirm.ts +70 -0
- package/examples/extensions/titlebar-spinner.ts +58 -0
- package/examples/extensions/todo.ts +299 -0
- package/examples/extensions/tool-override.ts +143 -0
- package/examples/extensions/tools.ts +146 -0
- package/examples/extensions/trigger-compact.ts +40 -0
- package/examples/extensions/truncated-tool.ts +192 -0
- package/examples/extensions/widget-placement.ts +17 -0
- package/examples/extensions/with-deps/index.ts +36 -0
- package/examples/extensions/with-deps/package-lock.json +31 -0
- package/examples/extensions/with-deps/package.json +22 -0
- package/examples/rpc-extension-ui.ts +632 -0
- package/examples/sdk/01-minimal.ts +22 -0
- package/examples/sdk/02-custom-model.ts +49 -0
- package/examples/sdk/03-custom-prompt.ts +55 -0
- package/examples/sdk/04-skills.ts +46 -0
- package/examples/sdk/05-tools.ts +56 -0
- package/examples/sdk/06-extensions.ts +88 -0
- package/examples/sdk/07-context-files.ts +40 -0
- package/examples/sdk/08-prompt-templates.ts +47 -0
- package/examples/sdk/09-api-keys-and-oauth.ts +48 -0
- package/examples/sdk/10-settings.ts +51 -0
- package/examples/sdk/11-sessions.ts +48 -0
- package/examples/sdk/12-full-control.ts +82 -0
- package/examples/sdk/README.md +144 -0
- package/package.json +96 -0
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Credential storage for API keys and OAuth tokens.
|
|
3
|
+
* Handles loading, saving, and refreshing credentials from auth.json.
|
|
4
|
+
*
|
|
5
|
+
* Uses file locking to prevent race conditions when multiple pi instances
|
|
6
|
+
* try to refresh tokens simultaneously.
|
|
7
|
+
*/
|
|
8
|
+
import { getEnvApiKey, getOAuthApiKey, getOAuthProvider, getOAuthProviders, } from "@mariozechner/pi-ai";
|
|
9
|
+
import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
10
|
+
import { dirname, join } from "path";
|
|
11
|
+
import lockfile from "proper-lockfile";
|
|
12
|
+
import { getAgentDir } from "../config.js";
|
|
13
|
+
import { resolveConfigValue } from "./resolve-config-value.js";
|
|
14
|
+
export class FileAuthStorageBackend {
|
|
15
|
+
authPath;
|
|
16
|
+
constructor(authPath = join(getAgentDir(), "auth.json")) {
|
|
17
|
+
this.authPath = authPath;
|
|
18
|
+
}
|
|
19
|
+
ensureParentDir() {
|
|
20
|
+
const dir = dirname(this.authPath);
|
|
21
|
+
if (!existsSync(dir)) {
|
|
22
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
ensureFileExists() {
|
|
26
|
+
if (!existsSync(this.authPath)) {
|
|
27
|
+
writeFileSync(this.authPath, "{}", "utf-8");
|
|
28
|
+
chmodSync(this.authPath, 0o600);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
withLock(fn) {
|
|
32
|
+
this.ensureParentDir();
|
|
33
|
+
this.ensureFileExists();
|
|
34
|
+
let release;
|
|
35
|
+
try {
|
|
36
|
+
release = lockfile.lockSync(this.authPath, { realpath: false });
|
|
37
|
+
const current = existsSync(this.authPath) ? readFileSync(this.authPath, "utf-8") : undefined;
|
|
38
|
+
const { result, next } = fn(current);
|
|
39
|
+
if (next !== undefined) {
|
|
40
|
+
writeFileSync(this.authPath, next, "utf-8");
|
|
41
|
+
chmodSync(this.authPath, 0o600);
|
|
42
|
+
}
|
|
43
|
+
return result;
|
|
44
|
+
}
|
|
45
|
+
finally {
|
|
46
|
+
if (release) {
|
|
47
|
+
release();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
async withLockAsync(fn) {
|
|
52
|
+
this.ensureParentDir();
|
|
53
|
+
this.ensureFileExists();
|
|
54
|
+
let release;
|
|
55
|
+
let lockCompromised = false;
|
|
56
|
+
let lockCompromisedError;
|
|
57
|
+
const throwIfCompromised = () => {
|
|
58
|
+
if (lockCompromised) {
|
|
59
|
+
throw lockCompromisedError ?? new Error("Auth storage lock was compromised");
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
try {
|
|
63
|
+
release = await lockfile.lock(this.authPath, {
|
|
64
|
+
retries: {
|
|
65
|
+
retries: 10,
|
|
66
|
+
factor: 2,
|
|
67
|
+
minTimeout: 100,
|
|
68
|
+
maxTimeout: 10000,
|
|
69
|
+
randomize: true,
|
|
70
|
+
},
|
|
71
|
+
stale: 30000,
|
|
72
|
+
onCompromised: (err) => {
|
|
73
|
+
lockCompromised = true;
|
|
74
|
+
lockCompromisedError = err;
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
throwIfCompromised();
|
|
78
|
+
const current = existsSync(this.authPath) ? readFileSync(this.authPath, "utf-8") : undefined;
|
|
79
|
+
const { result, next } = await fn(current);
|
|
80
|
+
throwIfCompromised();
|
|
81
|
+
if (next !== undefined) {
|
|
82
|
+
writeFileSync(this.authPath, next, "utf-8");
|
|
83
|
+
chmodSync(this.authPath, 0o600);
|
|
84
|
+
}
|
|
85
|
+
throwIfCompromised();
|
|
86
|
+
return result;
|
|
87
|
+
}
|
|
88
|
+
finally {
|
|
89
|
+
if (release) {
|
|
90
|
+
try {
|
|
91
|
+
await release();
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
// Ignore unlock errors when lock is compromised.
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
export class InMemoryAuthStorageBackend {
|
|
101
|
+
value;
|
|
102
|
+
withLock(fn) {
|
|
103
|
+
const { result, next } = fn(this.value);
|
|
104
|
+
if (next !== undefined) {
|
|
105
|
+
this.value = next;
|
|
106
|
+
}
|
|
107
|
+
return result;
|
|
108
|
+
}
|
|
109
|
+
async withLockAsync(fn) {
|
|
110
|
+
const { result, next } = await fn(this.value);
|
|
111
|
+
if (next !== undefined) {
|
|
112
|
+
this.value = next;
|
|
113
|
+
}
|
|
114
|
+
return result;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Credential storage backed by a JSON file.
|
|
119
|
+
*/
|
|
120
|
+
export class AuthStorage {
|
|
121
|
+
storage;
|
|
122
|
+
data = {};
|
|
123
|
+
runtimeOverrides = new Map();
|
|
124
|
+
fallbackResolver;
|
|
125
|
+
loadError = null;
|
|
126
|
+
errors = [];
|
|
127
|
+
constructor(storage) {
|
|
128
|
+
this.storage = storage;
|
|
129
|
+
this.reload();
|
|
130
|
+
}
|
|
131
|
+
static create(authPath) {
|
|
132
|
+
return new AuthStorage(new FileAuthStorageBackend(authPath ?? join(getAgentDir(), "auth.json")));
|
|
133
|
+
}
|
|
134
|
+
static fromStorage(storage) {
|
|
135
|
+
return new AuthStorage(storage);
|
|
136
|
+
}
|
|
137
|
+
static inMemory(data = {}) {
|
|
138
|
+
const storage = new InMemoryAuthStorageBackend();
|
|
139
|
+
storage.withLock(() => ({ result: undefined, next: JSON.stringify(data, null, 2) }));
|
|
140
|
+
return AuthStorage.fromStorage(storage);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Set a runtime API key override (not persisted to disk).
|
|
144
|
+
* Used for CLI --api-key flag.
|
|
145
|
+
*/
|
|
146
|
+
setRuntimeApiKey(provider, apiKey) {
|
|
147
|
+
this.runtimeOverrides.set(provider, apiKey);
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Remove a runtime API key override.
|
|
151
|
+
*/
|
|
152
|
+
removeRuntimeApiKey(provider) {
|
|
153
|
+
this.runtimeOverrides.delete(provider);
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Set a fallback resolver for API keys not found in auth.json or env vars.
|
|
157
|
+
* Used for custom provider keys from models.json.
|
|
158
|
+
*/
|
|
159
|
+
setFallbackResolver(resolver) {
|
|
160
|
+
this.fallbackResolver = resolver;
|
|
161
|
+
}
|
|
162
|
+
recordError(error) {
|
|
163
|
+
const normalizedError = error instanceof Error ? error : new Error(String(error));
|
|
164
|
+
this.errors.push(normalizedError);
|
|
165
|
+
}
|
|
166
|
+
parseStorageData(content) {
|
|
167
|
+
if (!content) {
|
|
168
|
+
return {};
|
|
169
|
+
}
|
|
170
|
+
return JSON.parse(content);
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Reload credentials from storage.
|
|
174
|
+
*/
|
|
175
|
+
reload() {
|
|
176
|
+
let content;
|
|
177
|
+
try {
|
|
178
|
+
this.storage.withLock((current) => {
|
|
179
|
+
content = current;
|
|
180
|
+
return { result: undefined };
|
|
181
|
+
});
|
|
182
|
+
this.data = this.parseStorageData(content);
|
|
183
|
+
this.loadError = null;
|
|
184
|
+
}
|
|
185
|
+
catch (error) {
|
|
186
|
+
this.loadError = error;
|
|
187
|
+
this.recordError(error);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
persistProviderChange(provider, credential) {
|
|
191
|
+
if (this.loadError) {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
try {
|
|
195
|
+
this.storage.withLock((current) => {
|
|
196
|
+
const currentData = this.parseStorageData(current);
|
|
197
|
+
const merged = { ...currentData };
|
|
198
|
+
if (credential) {
|
|
199
|
+
merged[provider] = credential;
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
delete merged[provider];
|
|
203
|
+
}
|
|
204
|
+
return { result: undefined, next: JSON.stringify(merged, null, 2) };
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
catch (error) {
|
|
208
|
+
this.recordError(error);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Get credential for a provider.
|
|
213
|
+
*/
|
|
214
|
+
get(provider) {
|
|
215
|
+
return this.data[provider] ?? undefined;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Set credential for a provider.
|
|
219
|
+
*/
|
|
220
|
+
set(provider, credential) {
|
|
221
|
+
this.data[provider] = credential;
|
|
222
|
+
this.persistProviderChange(provider, credential);
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Remove credential for a provider.
|
|
226
|
+
*/
|
|
227
|
+
remove(provider) {
|
|
228
|
+
delete this.data[provider];
|
|
229
|
+
this.persistProviderChange(provider, undefined);
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* List all providers with credentials.
|
|
233
|
+
*/
|
|
234
|
+
list() {
|
|
235
|
+
return Object.keys(this.data);
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Check if credentials exist for a provider in auth.json.
|
|
239
|
+
*/
|
|
240
|
+
has(provider) {
|
|
241
|
+
return provider in this.data;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Check if any form of auth is configured for a provider.
|
|
245
|
+
* Unlike getApiKey(), this doesn't refresh OAuth tokens.
|
|
246
|
+
*/
|
|
247
|
+
hasAuth(provider) {
|
|
248
|
+
if (this.runtimeOverrides.has(provider))
|
|
249
|
+
return true;
|
|
250
|
+
if (this.data[provider])
|
|
251
|
+
return true;
|
|
252
|
+
if (getEnvApiKey(provider))
|
|
253
|
+
return true;
|
|
254
|
+
if (this.fallbackResolver?.(provider))
|
|
255
|
+
return true;
|
|
256
|
+
return false;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Get all credentials (for passing to getOAuthApiKey).
|
|
260
|
+
*/
|
|
261
|
+
getAll() {
|
|
262
|
+
return { ...this.data };
|
|
263
|
+
}
|
|
264
|
+
drainErrors() {
|
|
265
|
+
const drained = [...this.errors];
|
|
266
|
+
this.errors = [];
|
|
267
|
+
return drained;
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Login to an OAuth provider.
|
|
271
|
+
*/
|
|
272
|
+
async login(providerId, callbacks) {
|
|
273
|
+
const provider = getOAuthProvider(providerId);
|
|
274
|
+
if (!provider) {
|
|
275
|
+
throw new Error(`Unknown OAuth provider: ${providerId}`);
|
|
276
|
+
}
|
|
277
|
+
const credentials = await provider.login(callbacks);
|
|
278
|
+
this.set(providerId, { type: "oauth", ...credentials });
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Logout from a provider.
|
|
282
|
+
*/
|
|
283
|
+
logout(provider) {
|
|
284
|
+
this.remove(provider);
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Refresh OAuth token with backend locking to prevent race conditions.
|
|
288
|
+
* Multiple pi instances may try to refresh simultaneously when tokens expire.
|
|
289
|
+
*/
|
|
290
|
+
async refreshOAuthTokenWithLock(providerId) {
|
|
291
|
+
const provider = getOAuthProvider(providerId);
|
|
292
|
+
if (!provider) {
|
|
293
|
+
return null;
|
|
294
|
+
}
|
|
295
|
+
const result = await this.storage.withLockAsync(async (current) => {
|
|
296
|
+
const currentData = this.parseStorageData(current);
|
|
297
|
+
this.data = currentData;
|
|
298
|
+
this.loadError = null;
|
|
299
|
+
const cred = currentData[providerId];
|
|
300
|
+
if (cred?.type !== "oauth") {
|
|
301
|
+
return { result: null };
|
|
302
|
+
}
|
|
303
|
+
if (Date.now() < cred.expires) {
|
|
304
|
+
return { result: { apiKey: provider.getApiKey(cred), newCredentials: cred } };
|
|
305
|
+
}
|
|
306
|
+
const oauthCreds = {};
|
|
307
|
+
for (const [key, value] of Object.entries(currentData)) {
|
|
308
|
+
if (value.type === "oauth") {
|
|
309
|
+
oauthCreds[key] = value;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
const refreshed = await getOAuthApiKey(providerId, oauthCreds);
|
|
313
|
+
if (!refreshed) {
|
|
314
|
+
return { result: null };
|
|
315
|
+
}
|
|
316
|
+
const merged = {
|
|
317
|
+
...currentData,
|
|
318
|
+
[providerId]: { type: "oauth", ...refreshed.newCredentials },
|
|
319
|
+
};
|
|
320
|
+
this.data = merged;
|
|
321
|
+
this.loadError = null;
|
|
322
|
+
return { result: refreshed, next: JSON.stringify(merged, null, 2) };
|
|
323
|
+
});
|
|
324
|
+
return result;
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Get API key for a provider.
|
|
328
|
+
* Priority:
|
|
329
|
+
* 1. Runtime override (CLI --api-key)
|
|
330
|
+
* 2. API key from auth.json
|
|
331
|
+
* 3. OAuth token from auth.json (auto-refreshed with locking)
|
|
332
|
+
* 4. Environment variable
|
|
333
|
+
* 5. Fallback resolver (models.json custom providers)
|
|
334
|
+
*/
|
|
335
|
+
async getApiKey(providerId) {
|
|
336
|
+
// Runtime override takes highest priority
|
|
337
|
+
const runtimeKey = this.runtimeOverrides.get(providerId);
|
|
338
|
+
if (runtimeKey) {
|
|
339
|
+
return runtimeKey;
|
|
340
|
+
}
|
|
341
|
+
const cred = this.data[providerId];
|
|
342
|
+
if (cred?.type === "api_key") {
|
|
343
|
+
return resolveConfigValue(cred.key);
|
|
344
|
+
}
|
|
345
|
+
if (cred?.type === "oauth") {
|
|
346
|
+
const provider = getOAuthProvider(providerId);
|
|
347
|
+
if (!provider) {
|
|
348
|
+
// Unknown OAuth provider, can't get API key
|
|
349
|
+
return undefined;
|
|
350
|
+
}
|
|
351
|
+
// Check if token needs refresh
|
|
352
|
+
const needsRefresh = Date.now() >= cred.expires;
|
|
353
|
+
if (needsRefresh) {
|
|
354
|
+
// Use locked refresh to prevent race conditions
|
|
355
|
+
try {
|
|
356
|
+
const result = await this.refreshOAuthTokenWithLock(providerId);
|
|
357
|
+
if (result) {
|
|
358
|
+
return result.apiKey;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
catch (error) {
|
|
362
|
+
this.recordError(error);
|
|
363
|
+
// Refresh failed - re-read file to check if another instance succeeded
|
|
364
|
+
this.reload();
|
|
365
|
+
const updatedCred = this.data[providerId];
|
|
366
|
+
if (updatedCred?.type === "oauth" && Date.now() < updatedCred.expires) {
|
|
367
|
+
// Another instance refreshed successfully, use those credentials
|
|
368
|
+
return provider.getApiKey(updatedCred);
|
|
369
|
+
}
|
|
370
|
+
// Refresh truly failed - return undefined so model discovery skips this provider
|
|
371
|
+
// User can /login to re-authenticate (credentials preserved for retry)
|
|
372
|
+
return undefined;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
else {
|
|
376
|
+
// Token not expired, use current access token
|
|
377
|
+
return provider.getApiKey(cred);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
// Fall back to environment variable
|
|
381
|
+
const envKey = getEnvApiKey(providerId);
|
|
382
|
+
if (envKey)
|
|
383
|
+
return envKey;
|
|
384
|
+
// Fall back to custom resolver (e.g., models.json custom providers)
|
|
385
|
+
return this.fallbackResolver?.(providerId) ?? undefined;
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Get all registered OAuth providers
|
|
389
|
+
*/
|
|
390
|
+
getOAuthProviders() {
|
|
391
|
+
return getOAuthProviders();
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
//# sourceMappingURL=auth-storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-storage.js","sourceRoot":"","sources":["../../src/core/auth-storage.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACN,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,iBAAiB,GAIjB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AACnF,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,QAAQ,MAAM,iBAAiB,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAyB/D,MAAM,OAAO,sBAAsB;IACd,QAAQ;IAA5B,YAAoB,QAAQ,GAAW,IAAI,CAAC,WAAW,EAAE,EAAE,WAAW,CAAC,EAAE;wBAArD,QAAQ;IAA8C,CAAC;IAEnE,eAAe,GAAS;QAC/B,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACnC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACtB,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAClD,CAAC;IAAA,CACD;IAEO,gBAAgB,GAAS;QAChC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YAChC,aAAa,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;YAC5C,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QACjC,CAAC;IAAA,CACD;IAED,QAAQ,CAAI,EAAkD,EAAK;QAClE,IAAI,CAAC,eAAe,EAAE,CAAC;QACvB,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAExB,IAAI,OAAiC,CAAC;QACtC,IAAI,CAAC;YACJ,OAAO,GAAG,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;YAChE,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YAC7F,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC;YACrC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;gBACxB,aAAa,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;gBAC5C,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;YACjC,CAAC;YACD,OAAO,MAAM,CAAC;QACf,CAAC;gBAAS,CAAC;YACV,IAAI,OAAO,EAAE,CAAC;gBACb,OAAO,EAAE,CAAC;YACX,CAAC;QACF,CAAC;IAAA,CACD;IAED,KAAK,CAAC,aAAa,CAAI,EAA2D,EAAc;QAC/F,IAAI,CAAC,eAAe,EAAE,CAAC;QACvB,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAExB,IAAI,OAA0C,CAAC;QAC/C,IAAI,eAAe,GAAG,KAAK,CAAC;QAC5B,IAAI,oBAAuC,CAAC;QAC5C,MAAM,kBAAkB,GAAG,GAAG,EAAE,CAAC;YAChC,IAAI,eAAe,EAAE,CAAC;gBACrB,MAAM,oBAAoB,IAAI,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;YAC9E,CAAC;QAAA,CACD,CAAC;QAEF,IAAI,CAAC;YACJ,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;gBAC5C,OAAO,EAAE;oBACR,OAAO,EAAE,EAAE;oBACX,MAAM,EAAE,CAAC;oBACT,UAAU,EAAE,GAAG;oBACf,UAAU,EAAE,KAAK;oBACjB,SAAS,EAAE,IAAI;iBACf;gBACD,KAAK,EAAE,KAAK;gBACZ,aAAa,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC;oBACvB,eAAe,GAAG,IAAI,CAAC;oBACvB,oBAAoB,GAAG,GAAG,CAAC;gBAAA,CAC3B;aACD,CAAC,CAAC;YAEH,kBAAkB,EAAE,CAAC;YACrB,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YAC7F,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,CAAC;YAC3C,kBAAkB,EAAE,CAAC;YACrB,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;gBACxB,aAAa,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;gBAC5C,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;YACjC,CAAC;YACD,kBAAkB,EAAE,CAAC;YACrB,OAAO,MAAM,CAAC;QACf,CAAC;gBAAS,CAAC;YACV,IAAI,OAAO,EAAE,CAAC;gBACb,IAAI,CAAC;oBACJ,MAAM,OAAO,EAAE,CAAC;gBACjB,CAAC;gBAAC,MAAM,CAAC;oBACR,iDAAiD;gBAClD,CAAC;YACF,CAAC;QACF,CAAC;IAAA,CACD;CACD;AAED,MAAM,OAAO,0BAA0B;IAC9B,KAAK,CAAqB;IAElC,QAAQ,CAAI,EAAkD,EAAK;QAClE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACxB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QACnB,CAAC;QACD,OAAO,MAAM,CAAC;IAAA,CACd;IAED,KAAK,CAAC,aAAa,CAAI,EAA2D,EAAc;QAC/F,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC9C,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACxB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QACnB,CAAC;QACD,OAAO,MAAM,CAAC;IAAA,CACd;CACD;AAED;;GAEG;AACH,MAAM,OAAO,WAAW;IAOK,OAAO;IAN3B,IAAI,GAAoB,EAAE,CAAC;IAC3B,gBAAgB,GAAwB,IAAI,GAAG,EAAE,CAAC;IAClD,gBAAgB,CAA4C;IAC5D,SAAS,GAAiB,IAAI,CAAC;IAC/B,MAAM,GAAY,EAAE,CAAC;IAE7B,YAA4B,OAA2B,EAAE;uBAA7B,OAAO;QAClC,IAAI,CAAC,MAAM,EAAE,CAAC;IAAA,CACd;IAED,MAAM,CAAC,MAAM,CAAC,QAAiB,EAAe;QAC7C,OAAO,IAAI,WAAW,CAAC,IAAI,sBAAsB,CAAC,QAAQ,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;IAAA,CACjG;IAED,MAAM,CAAC,WAAW,CAAC,OAA2B,EAAe;QAC5D,OAAO,IAAI,WAAW,CAAC,OAAO,CAAC,CAAC;IAAA,CAChC;IAED,MAAM,CAAC,QAAQ,CAAC,IAAI,GAAoB,EAAE,EAAe;QACxD,MAAM,OAAO,GAAG,IAAI,0BAA0B,EAAE,CAAC;QACjD,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACrF,OAAO,WAAW,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IAAA,CACxC;IAED;;;OAGG;IACH,gBAAgB,CAAC,QAAgB,EAAE,MAAc,EAAQ;QACxD,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAAA,CAC5C;IAED;;OAEG;IACH,mBAAmB,CAAC,QAAgB,EAAQ;QAC3C,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAAA,CACvC;IAED;;;OAGG;IACH,mBAAmB,CAAC,QAAkD,EAAQ;QAC7E,IAAI,CAAC,gBAAgB,GAAG,QAAQ,CAAC;IAAA,CACjC;IAEO,WAAW,CAAC,KAAc,EAAQ;QACzC,MAAM,eAAe,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAClF,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IAAA,CAClC;IAEO,gBAAgB,CAAC,OAA2B,EAAmB;QACtE,IAAI,CAAC,OAAO,EAAE,CAAC;YACd,OAAO,EAAE,CAAC;QACX,CAAC;QACD,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAoB,CAAC;IAAA,CAC9C;IAED;;OAEG;IACH,MAAM,GAAS;QACd,IAAI,OAA2B,CAAC;QAChC,IAAI,CAAC;YACJ,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC;gBAClC,OAAO,GAAG,OAAO,CAAC;gBAClB,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;YAAA,CAC7B,CAAC,CAAC;YACH,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;YAC3C,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACvB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,IAAI,CAAC,SAAS,GAAG,KAAc,CAAC;YAChC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QACzB,CAAC;IAAA,CACD;IAEO,qBAAqB,CAAC,QAAgB,EAAE,UAAsC,EAAQ;QAC7F,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACpB,OAAO;QACR,CAAC;QAED,IAAI,CAAC;YACJ,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC;gBAClC,MAAM,WAAW,GAAG,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;gBACnD,MAAM,MAAM,GAAoB,EAAE,GAAG,WAAW,EAAE,CAAC;gBACnD,IAAI,UAAU,EAAE,CAAC;oBAChB,MAAM,CAAC,QAAQ,CAAC,GAAG,UAAU,CAAC;gBAC/B,CAAC;qBAAM,CAAC;oBACP,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC;gBACzB,CAAC;gBACD,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;YAAA,CACpE,CAAC,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QACzB,CAAC;IAAA,CACD;IAED;;OAEG;IACH,GAAG,CAAC,QAAgB,EAA8B;QACjD,OAAO,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,SAAS,CAAC;IAAA,CACxC;IAED;;OAEG;IACH,GAAG,CAAC,QAAgB,EAAE,UAA0B,EAAQ;QACvD,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,UAAU,CAAC;QACjC,IAAI,CAAC,qBAAqB,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IAAA,CACjD;IAED;;OAEG;IACH,MAAM,CAAC,QAAgB,EAAQ;QAC9B,OAAO,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC3B,IAAI,CAAC,qBAAqB,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;IAAA,CAChD;IAED;;OAEG;IACH,IAAI,GAAa;QAChB,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAAA,CAC9B;IAED;;OAEG;IACH,GAAG,CAAC,QAAgB,EAAW;QAC9B,OAAO,QAAQ,IAAI,IAAI,CAAC,IAAI,CAAC;IAAA,CAC7B;IAED;;;OAGG;IACH,OAAO,CAAC,QAAgB,EAAW;QAClC,IAAI,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,QAAQ,CAAC;YAAE,OAAO,IAAI,CAAC;QACrD,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC;YAAE,OAAO,IAAI,CAAC;QACrC,IAAI,YAAY,CAAC,QAAQ,CAAC;YAAE,OAAO,IAAI,CAAC;QACxC,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC,QAAQ,CAAC;YAAE,OAAO,IAAI,CAAC;QACnD,OAAO,KAAK,CAAC;IAAA,CACb;IAED;;OAEG;IACH,MAAM,GAAoB;QACzB,OAAO,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAAA,CACxB;IAED,WAAW,GAAY;QACtB,MAAM,OAAO,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;QACjC,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;QACjB,OAAO,OAAO,CAAC;IAAA,CACf;IAED;;OAEG;IACH,KAAK,CAAC,KAAK,CAAC,UAA2B,EAAE,SAA8B,EAAiB;QACvF,MAAM,QAAQ,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAC;QAC9C,IAAI,CAAC,QAAQ,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,2BAA2B,UAAU,EAAE,CAAC,CAAC;QAC1D,CAAC;QAED,MAAM,WAAW,GAAG,MAAM,QAAQ,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QACpD,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,WAAW,EAAE,CAAC,CAAC;IAAA,CACxD;IAED;;OAEG;IACH,MAAM,CAAC,QAAgB,EAAQ;QAC9B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAAA,CACtB;IAED;;;OAGG;IACK,KAAK,CAAC,yBAAyB,CACtC,UAA2B,EAC4C;QACvE,MAAM,QAAQ,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAC;QAC9C,IAAI,CAAC,QAAQ,EAAE,CAAC;YACf,OAAO,IAAI,CAAC;QACb,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC;YAClE,MAAM,WAAW,GAAG,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;YACnD,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;YACxB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;YAEtB,MAAM,IAAI,GAAG,WAAW,CAAC,UAAU,CAAC,CAAC;YACrC,IAAI,IAAI,EAAE,IAAI,KAAK,OAAO,EAAE,CAAC;gBAC5B,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;YACzB,CAAC;YAED,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;gBAC/B,OAAO,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,cAAc,EAAE,IAAI,EAAE,EAAE,CAAC;YAC/E,CAAC;YAED,MAAM,UAAU,GAAqC,EAAE,CAAC;YACxD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;gBACxD,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;oBAC5B,UAAU,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;gBACzB,CAAC;YACF,CAAC;YAED,MAAM,SAAS,GAAG,MAAM,cAAc,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;YAC/D,IAAI,CAAC,SAAS,EAAE,CAAC;gBAChB,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;YACzB,CAAC;YAED,MAAM,MAAM,GAAoB;gBAC/B,GAAG,WAAW;gBACd,CAAC,UAAU,CAAC,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,SAAS,CAAC,cAAc,EAAE;aAC5D,CAAC;YACF,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC;YACnB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;YACtB,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;QAAA,CACpE,CAAC,CAAC;QAEH,OAAO,MAAM,CAAC;IAAA,CACd;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,SAAS,CAAC,UAAkB,EAA+B;QAChE,0CAA0C;QAC1C,MAAM,UAAU,GAAG,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QACzD,IAAI,UAAU,EAAE,CAAC;YAChB,OAAO,UAAU,CAAC;QACnB,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAEnC,IAAI,IAAI,EAAE,IAAI,KAAK,SAAS,EAAE,CAAC;YAC9B,OAAO,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACrC,CAAC;QAED,IAAI,IAAI,EAAE,IAAI,KAAK,OAAO,EAAE,CAAC;YAC5B,MAAM,QAAQ,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAC;YAC9C,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACf,4CAA4C;gBAC5C,OAAO,SAAS,CAAC;YAClB,CAAC;YAED,+BAA+B;YAC/B,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,OAAO,CAAC;YAEhD,IAAI,YAAY,EAAE,CAAC;gBAClB,gDAAgD;gBAChD,IAAI,CAAC;oBACJ,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,yBAAyB,CAAC,UAAU,CAAC,CAAC;oBAChE,IAAI,MAAM,EAAE,CAAC;wBACZ,OAAO,MAAM,CAAC,MAAM,CAAC;oBACtB,CAAC;gBACF,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBAChB,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;oBACxB,uEAAuE;oBACvE,IAAI,CAAC,MAAM,EAAE,CAAC;oBACd,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;oBAE1C,IAAI,WAAW,EAAE,IAAI,KAAK,OAAO,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,WAAW,CAAC,OAAO,EAAE,CAAC;wBACvE,iEAAiE;wBACjE,OAAO,QAAQ,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;oBACxC,CAAC;oBAED,iFAAiF;oBACjF,uEAAuE;oBACvE,OAAO,SAAS,CAAC;gBAClB,CAAC;YACF,CAAC;iBAAM,CAAC;gBACP,8CAA8C;gBAC9C,OAAO,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YACjC,CAAC;QACF,CAAC;QAED,oCAAoC;QACpC,MAAM,MAAM,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC;QACxC,IAAI,MAAM;YAAE,OAAO,MAAM,CAAC;QAE1B,oEAAoE;QACpE,OAAO,IAAI,CAAC,gBAAgB,EAAE,CAAC,UAAU,CAAC,IAAI,SAAS,CAAC;IAAA,CACxD;IAED;;OAEG;IACH,iBAAiB,GAAG;QACnB,OAAO,iBAAiB,EAAE,CAAC;IAAA,CAC3B;CACD","sourcesContent":["/**\r\n * Credential storage for API keys and OAuth tokens.\r\n * Handles loading, saving, and refreshing credentials from auth.json.\r\n *\r\n * Uses file locking to prevent race conditions when multiple pi instances\r\n * try to refresh tokens simultaneously.\r\n */\r\n\r\nimport {\r\n\tgetEnvApiKey,\r\n\tgetOAuthApiKey,\r\n\tgetOAuthProvider,\r\n\tgetOAuthProviders,\r\n\ttype OAuthCredentials,\r\n\ttype OAuthLoginCallbacks,\r\n\ttype OAuthProviderId,\r\n} from \"@mariozechner/pi-ai\";\r\nimport { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\r\nimport { dirname, join } from \"path\";\r\nimport lockfile from \"proper-lockfile\";\r\nimport { getAgentDir } from \"../config.js\";\r\nimport { resolveConfigValue } from \"./resolve-config-value.js\";\r\n\r\nexport type ApiKeyCredential = {\r\n\ttype: \"api_key\";\r\n\tkey: string;\r\n};\r\n\r\nexport type OAuthCredential = {\r\n\ttype: \"oauth\";\r\n} & OAuthCredentials;\r\n\r\nexport type AuthCredential = ApiKeyCredential | OAuthCredential;\r\n\r\nexport type AuthStorageData = Record<string, AuthCredential>;\r\n\r\ntype LockResult<T> = {\r\n\tresult: T;\r\n\tnext?: string;\r\n};\r\n\r\nexport interface AuthStorageBackend {\r\n\twithLock<T>(fn: (current: string | undefined) => LockResult<T>): T;\r\n\twithLockAsync<T>(fn: (current: string | undefined) => Promise<LockResult<T>>): Promise<T>;\r\n}\r\n\r\nexport class FileAuthStorageBackend implements AuthStorageBackend {\r\n\tconstructor(private authPath: string = join(getAgentDir(), \"auth.json\")) {}\r\n\r\n\tprivate ensureParentDir(): void {\r\n\t\tconst dir = dirname(this.authPath);\r\n\t\tif (!existsSync(dir)) {\r\n\t\t\tmkdirSync(dir, { recursive: true, mode: 0o700 });\r\n\t\t}\r\n\t}\r\n\r\n\tprivate ensureFileExists(): void {\r\n\t\tif (!existsSync(this.authPath)) {\r\n\t\t\twriteFileSync(this.authPath, \"{}\", \"utf-8\");\r\n\t\t\tchmodSync(this.authPath, 0o600);\r\n\t\t}\r\n\t}\r\n\r\n\twithLock<T>(fn: (current: string | undefined) => LockResult<T>): T {\r\n\t\tthis.ensureParentDir();\r\n\t\tthis.ensureFileExists();\r\n\r\n\t\tlet release: (() => void) | undefined;\r\n\t\ttry {\r\n\t\t\trelease = lockfile.lockSync(this.authPath, { realpath: false });\r\n\t\t\tconst current = existsSync(this.authPath) ? readFileSync(this.authPath, \"utf-8\") : undefined;\r\n\t\t\tconst { result, next } = fn(current);\r\n\t\t\tif (next !== undefined) {\r\n\t\t\t\twriteFileSync(this.authPath, next, \"utf-8\");\r\n\t\t\t\tchmodSync(this.authPath, 0o600);\r\n\t\t\t}\r\n\t\t\treturn result;\r\n\t\t} finally {\r\n\t\t\tif (release) {\r\n\t\t\t\trelease();\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tasync withLockAsync<T>(fn: (current: string | undefined) => Promise<LockResult<T>>): Promise<T> {\r\n\t\tthis.ensureParentDir();\r\n\t\tthis.ensureFileExists();\r\n\r\n\t\tlet release: (() => Promise<void>) | undefined;\r\n\t\tlet lockCompromised = false;\r\n\t\tlet lockCompromisedError: Error | undefined;\r\n\t\tconst throwIfCompromised = () => {\r\n\t\t\tif (lockCompromised) {\r\n\t\t\t\tthrow lockCompromisedError ?? new Error(\"Auth storage lock was compromised\");\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\ttry {\r\n\t\t\trelease = await lockfile.lock(this.authPath, {\r\n\t\t\t\tretries: {\r\n\t\t\t\t\tretries: 10,\r\n\t\t\t\t\tfactor: 2,\r\n\t\t\t\t\tminTimeout: 100,\r\n\t\t\t\t\tmaxTimeout: 10000,\r\n\t\t\t\t\trandomize: true,\r\n\t\t\t\t},\r\n\t\t\t\tstale: 30000,\r\n\t\t\t\tonCompromised: (err) => {\r\n\t\t\t\t\tlockCompromised = true;\r\n\t\t\t\t\tlockCompromisedError = err;\r\n\t\t\t\t},\r\n\t\t\t});\r\n\r\n\t\t\tthrowIfCompromised();\r\n\t\t\tconst current = existsSync(this.authPath) ? readFileSync(this.authPath, \"utf-8\") : undefined;\r\n\t\t\tconst { result, next } = await fn(current);\r\n\t\t\tthrowIfCompromised();\r\n\t\t\tif (next !== undefined) {\r\n\t\t\t\twriteFileSync(this.authPath, next, \"utf-8\");\r\n\t\t\t\tchmodSync(this.authPath, 0o600);\r\n\t\t\t}\r\n\t\t\tthrowIfCompromised();\r\n\t\t\treturn result;\r\n\t\t} finally {\r\n\t\t\tif (release) {\r\n\t\t\t\ttry {\r\n\t\t\t\t\tawait release();\r\n\t\t\t\t} catch {\r\n\t\t\t\t\t// Ignore unlock errors when lock is compromised.\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport class InMemoryAuthStorageBackend implements AuthStorageBackend {\r\n\tprivate value: string | undefined;\r\n\r\n\twithLock<T>(fn: (current: string | undefined) => LockResult<T>): T {\r\n\t\tconst { result, next } = fn(this.value);\r\n\t\tif (next !== undefined) {\r\n\t\t\tthis.value = next;\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tasync withLockAsync<T>(fn: (current: string | undefined) => Promise<LockResult<T>>): Promise<T> {\r\n\t\tconst { result, next } = await fn(this.value);\r\n\t\tif (next !== undefined) {\r\n\t\t\tthis.value = next;\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n}\r\n\r\n/**\r\n * Credential storage backed by a JSON file.\r\n */\r\nexport class AuthStorage {\r\n\tprivate data: AuthStorageData = {};\r\n\tprivate runtimeOverrides: Map<string, string> = new Map();\r\n\tprivate fallbackResolver?: (provider: string) => string | undefined;\r\n\tprivate loadError: Error | null = null;\r\n\tprivate errors: Error[] = [];\r\n\r\n\tprivate constructor(private storage: AuthStorageBackend) {\r\n\t\tthis.reload();\r\n\t}\r\n\r\n\tstatic create(authPath?: string): AuthStorage {\r\n\t\treturn new AuthStorage(new FileAuthStorageBackend(authPath ?? join(getAgentDir(), \"auth.json\")));\r\n\t}\r\n\r\n\tstatic fromStorage(storage: AuthStorageBackend): AuthStorage {\r\n\t\treturn new AuthStorage(storage);\r\n\t}\r\n\r\n\tstatic inMemory(data: AuthStorageData = {}): AuthStorage {\r\n\t\tconst storage = new InMemoryAuthStorageBackend();\r\n\t\tstorage.withLock(() => ({ result: undefined, next: JSON.stringify(data, null, 2) }));\r\n\t\treturn AuthStorage.fromStorage(storage);\r\n\t}\r\n\r\n\t/**\r\n\t * Set a runtime API key override (not persisted to disk).\r\n\t * Used for CLI --api-key flag.\r\n\t */\r\n\tsetRuntimeApiKey(provider: string, apiKey: string): void {\r\n\t\tthis.runtimeOverrides.set(provider, apiKey);\r\n\t}\r\n\r\n\t/**\r\n\t * Remove a runtime API key override.\r\n\t */\r\n\tremoveRuntimeApiKey(provider: string): void {\r\n\t\tthis.runtimeOverrides.delete(provider);\r\n\t}\r\n\r\n\t/**\r\n\t * Set a fallback resolver for API keys not found in auth.json or env vars.\r\n\t * Used for custom provider keys from models.json.\r\n\t */\r\n\tsetFallbackResolver(resolver: (provider: string) => string | undefined): void {\r\n\t\tthis.fallbackResolver = resolver;\r\n\t}\r\n\r\n\tprivate recordError(error: unknown): void {\r\n\t\tconst normalizedError = error instanceof Error ? error : new Error(String(error));\r\n\t\tthis.errors.push(normalizedError);\r\n\t}\r\n\r\n\tprivate parseStorageData(content: string | undefined): AuthStorageData {\r\n\t\tif (!content) {\r\n\t\t\treturn {};\r\n\t\t}\r\n\t\treturn JSON.parse(content) as AuthStorageData;\r\n\t}\r\n\r\n\t/**\r\n\t * Reload credentials from storage.\r\n\t */\r\n\treload(): void {\r\n\t\tlet content: string | undefined;\r\n\t\ttry {\r\n\t\t\tthis.storage.withLock((current) => {\r\n\t\t\t\tcontent = current;\r\n\t\t\t\treturn { result: undefined };\r\n\t\t\t});\r\n\t\t\tthis.data = this.parseStorageData(content);\r\n\t\t\tthis.loadError = null;\r\n\t\t} catch (error) {\r\n\t\t\tthis.loadError = error as Error;\r\n\t\t\tthis.recordError(error);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate persistProviderChange(provider: string, credential: AuthCredential | undefined): void {\r\n\t\tif (this.loadError) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\ttry {\r\n\t\t\tthis.storage.withLock((current) => {\r\n\t\t\t\tconst currentData = this.parseStorageData(current);\r\n\t\t\t\tconst merged: AuthStorageData = { ...currentData };\r\n\t\t\t\tif (credential) {\r\n\t\t\t\t\tmerged[provider] = credential;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tdelete merged[provider];\r\n\t\t\t\t}\r\n\t\t\t\treturn { result: undefined, next: JSON.stringify(merged, null, 2) };\r\n\t\t\t});\r\n\t\t} catch (error) {\r\n\t\t\tthis.recordError(error);\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Get credential for a provider.\r\n\t */\r\n\tget(provider: string): AuthCredential | undefined {\r\n\t\treturn this.data[provider] ?? undefined;\r\n\t}\r\n\r\n\t/**\r\n\t * Set credential for a provider.\r\n\t */\r\n\tset(provider: string, credential: AuthCredential): void {\r\n\t\tthis.data[provider] = credential;\r\n\t\tthis.persistProviderChange(provider, credential);\r\n\t}\r\n\r\n\t/**\r\n\t * Remove credential for a provider.\r\n\t */\r\n\tremove(provider: string): void {\r\n\t\tdelete this.data[provider];\r\n\t\tthis.persistProviderChange(provider, undefined);\r\n\t}\r\n\r\n\t/**\r\n\t * List all providers with credentials.\r\n\t */\r\n\tlist(): string[] {\r\n\t\treturn Object.keys(this.data);\r\n\t}\r\n\r\n\t/**\r\n\t * Check if credentials exist for a provider in auth.json.\r\n\t */\r\n\thas(provider: string): boolean {\r\n\t\treturn provider in this.data;\r\n\t}\r\n\r\n\t/**\r\n\t * Check if any form of auth is configured for a provider.\r\n\t * Unlike getApiKey(), this doesn't refresh OAuth tokens.\r\n\t */\r\n\thasAuth(provider: string): boolean {\r\n\t\tif (this.runtimeOverrides.has(provider)) return true;\r\n\t\tif (this.data[provider]) return true;\r\n\t\tif (getEnvApiKey(provider)) return true;\r\n\t\tif (this.fallbackResolver?.(provider)) return true;\r\n\t\treturn false;\r\n\t}\r\n\r\n\t/**\r\n\t * Get all credentials (for passing to getOAuthApiKey).\r\n\t */\r\n\tgetAll(): AuthStorageData {\r\n\t\treturn { ...this.data };\r\n\t}\r\n\r\n\tdrainErrors(): Error[] {\r\n\t\tconst drained = [...this.errors];\r\n\t\tthis.errors = [];\r\n\t\treturn drained;\r\n\t}\r\n\r\n\t/**\r\n\t * Login to an OAuth provider.\r\n\t */\r\n\tasync login(providerId: OAuthProviderId, callbacks: OAuthLoginCallbacks): Promise<void> {\r\n\t\tconst provider = getOAuthProvider(providerId);\r\n\t\tif (!provider) {\r\n\t\t\tthrow new Error(`Unknown OAuth provider: ${providerId}`);\r\n\t\t}\r\n\r\n\t\tconst credentials = await provider.login(callbacks);\r\n\t\tthis.set(providerId, { type: \"oauth\", ...credentials });\r\n\t}\r\n\r\n\t/**\r\n\t * Logout from a provider.\r\n\t */\r\n\tlogout(provider: string): void {\r\n\t\tthis.remove(provider);\r\n\t}\r\n\r\n\t/**\r\n\t * Refresh OAuth token with backend locking to prevent race conditions.\r\n\t * Multiple pi instances may try to refresh simultaneously when tokens expire.\r\n\t */\r\n\tprivate async refreshOAuthTokenWithLock(\r\n\t\tproviderId: OAuthProviderId,\r\n\t): Promise<{ apiKey: string; newCredentials: OAuthCredentials } | null> {\r\n\t\tconst provider = getOAuthProvider(providerId);\r\n\t\tif (!provider) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tconst result = await this.storage.withLockAsync(async (current) => {\r\n\t\t\tconst currentData = this.parseStorageData(current);\r\n\t\t\tthis.data = currentData;\r\n\t\t\tthis.loadError = null;\r\n\r\n\t\t\tconst cred = currentData[providerId];\r\n\t\t\tif (cred?.type !== \"oauth\") {\r\n\t\t\t\treturn { result: null };\r\n\t\t\t}\r\n\r\n\t\t\tif (Date.now() < cred.expires) {\r\n\t\t\t\treturn { result: { apiKey: provider.getApiKey(cred), newCredentials: cred } };\r\n\t\t\t}\r\n\r\n\t\t\tconst oauthCreds: Record<string, OAuthCredentials> = {};\r\n\t\t\tfor (const [key, value] of Object.entries(currentData)) {\r\n\t\t\t\tif (value.type === \"oauth\") {\r\n\t\t\t\t\toauthCreds[key] = value;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tconst refreshed = await getOAuthApiKey(providerId, oauthCreds);\r\n\t\t\tif (!refreshed) {\r\n\t\t\t\treturn { result: null };\r\n\t\t\t}\r\n\r\n\t\t\tconst merged: AuthStorageData = {\r\n\t\t\t\t...currentData,\r\n\t\t\t\t[providerId]: { type: \"oauth\", ...refreshed.newCredentials },\r\n\t\t\t};\r\n\t\t\tthis.data = merged;\r\n\t\t\tthis.loadError = null;\r\n\t\t\treturn { result: refreshed, next: JSON.stringify(merged, null, 2) };\r\n\t\t});\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\t/**\r\n\t * Get API key for a provider.\r\n\t * Priority:\r\n\t * 1. Runtime override (CLI --api-key)\r\n\t * 2. API key from auth.json\r\n\t * 3. OAuth token from auth.json (auto-refreshed with locking)\r\n\t * 4. Environment variable\r\n\t * 5. Fallback resolver (models.json custom providers)\r\n\t */\r\n\tasync getApiKey(providerId: string): Promise<string | undefined> {\r\n\t\t// Runtime override takes highest priority\r\n\t\tconst runtimeKey = this.runtimeOverrides.get(providerId);\r\n\t\tif (runtimeKey) {\r\n\t\t\treturn runtimeKey;\r\n\t\t}\r\n\r\n\t\tconst cred = this.data[providerId];\r\n\r\n\t\tif (cred?.type === \"api_key\") {\r\n\t\t\treturn resolveConfigValue(cred.key);\r\n\t\t}\r\n\r\n\t\tif (cred?.type === \"oauth\") {\r\n\t\t\tconst provider = getOAuthProvider(providerId);\r\n\t\t\tif (!provider) {\r\n\t\t\t\t// Unknown OAuth provider, can't get API key\r\n\t\t\t\treturn undefined;\r\n\t\t\t}\r\n\r\n\t\t\t// Check if token needs refresh\r\n\t\t\tconst needsRefresh = Date.now() >= cred.expires;\r\n\r\n\t\t\tif (needsRefresh) {\r\n\t\t\t\t// Use locked refresh to prevent race conditions\r\n\t\t\t\ttry {\r\n\t\t\t\t\tconst result = await this.refreshOAuthTokenWithLock(providerId);\r\n\t\t\t\t\tif (result) {\r\n\t\t\t\t\t\treturn result.apiKey;\r\n\t\t\t\t\t}\r\n\t\t\t\t} catch (error) {\r\n\t\t\t\t\tthis.recordError(error);\r\n\t\t\t\t\t// Refresh failed - re-read file to check if another instance succeeded\r\n\t\t\t\t\tthis.reload();\r\n\t\t\t\t\tconst updatedCred = this.data[providerId];\r\n\r\n\t\t\t\t\tif (updatedCred?.type === \"oauth\" && Date.now() < updatedCred.expires) {\r\n\t\t\t\t\t\t// Another instance refreshed successfully, use those credentials\r\n\t\t\t\t\t\treturn provider.getApiKey(updatedCred);\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t// Refresh truly failed - return undefined so model discovery skips this provider\r\n\t\t\t\t\t// User can /login to re-authenticate (credentials preserved for retry)\r\n\t\t\t\t\treturn undefined;\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\t// Token not expired, use current access token\r\n\t\t\t\treturn provider.getApiKey(cred);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// Fall back to environment variable\r\n\t\tconst envKey = getEnvApiKey(providerId);\r\n\t\tif (envKey) return envKey;\r\n\r\n\t\t// Fall back to custom resolver (e.g., models.json custom providers)\r\n\t\treturn this.fallbackResolver?.(providerId) ?? undefined;\r\n\t}\r\n\r\n\t/**\r\n\t * Get all registered OAuth providers\r\n\t */\r\n\tgetOAuthProviders() {\r\n\t\treturn getOAuthProviders();\r\n\t}\r\n}\r\n"]}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bash command execution with streaming support and cancellation.
|
|
3
|
+
*
|
|
4
|
+
* This module provides a unified bash execution implementation used by:
|
|
5
|
+
* - AgentSession.executeBash() for interactive and RPC modes
|
|
6
|
+
* - Direct calls from modes that need bash execution
|
|
7
|
+
*/
|
|
8
|
+
import type { BashOperations } from "./tools/bash.js";
|
|
9
|
+
export interface BashExecutorOptions {
|
|
10
|
+
/** Callback for streaming output chunks (already sanitized) */
|
|
11
|
+
onChunk?: (chunk: string) => void;
|
|
12
|
+
/** AbortSignal for cancellation */
|
|
13
|
+
signal?: AbortSignal;
|
|
14
|
+
}
|
|
15
|
+
export interface BashResult {
|
|
16
|
+
/** Combined stdout + stderr output (sanitized, possibly truncated) */
|
|
17
|
+
output: string;
|
|
18
|
+
/** Process exit code (undefined if killed/cancelled) */
|
|
19
|
+
exitCode: number | undefined;
|
|
20
|
+
/** Whether the command was cancelled via signal */
|
|
21
|
+
cancelled: boolean;
|
|
22
|
+
/** Whether the output was truncated */
|
|
23
|
+
truncated: boolean;
|
|
24
|
+
/** Path to temp file containing full output (if output exceeded truncation threshold) */
|
|
25
|
+
fullOutputPath?: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Execute a bash command with optional streaming and cancellation support.
|
|
29
|
+
*
|
|
30
|
+
* Features:
|
|
31
|
+
* - Streams sanitized output via onChunk callback
|
|
32
|
+
* - Writes large output to temp file for later retrieval
|
|
33
|
+
* - Supports cancellation via AbortSignal
|
|
34
|
+
* - Sanitizes output (strips ANSI, removes binary garbage, normalizes newlines)
|
|
35
|
+
* - Truncates output if it exceeds the default max bytes
|
|
36
|
+
*
|
|
37
|
+
* @param command - The bash command to execute
|
|
38
|
+
* @param options - Optional streaming callback and abort signal
|
|
39
|
+
* @returns Promise resolving to execution result
|
|
40
|
+
*/
|
|
41
|
+
export declare function executeBash(command: string, options?: BashExecutorOptions): Promise<BashResult>;
|
|
42
|
+
/**
|
|
43
|
+
* Execute a bash command using custom BashOperations.
|
|
44
|
+
* Used for remote execution (SSH, containers, etc.).
|
|
45
|
+
*/
|
|
46
|
+
export declare function executeBashWithOperations(command: string, cwd: string, operations: BashOperations, options?: BashExecutorOptions): Promise<BashResult>;
|
|
47
|
+
//# sourceMappingURL=bash-executor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bash-executor.d.ts","sourceRoot":"","sources":["../../src/core/bash-executor.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AASH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAOtD,MAAM,WAAW,mBAAmB;IACnC,+DAA+D;IAC/D,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,mCAAmC;IACnC,MAAM,CAAC,EAAE,WAAW,CAAC;CACrB;AAED,MAAM,WAAW,UAAU;IAC1B,sEAAsE;IACtE,MAAM,EAAE,MAAM,CAAC;IACf,wDAAwD;IACxD,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,mDAAmD;IACnD,SAAS,EAAE,OAAO,CAAC;IACnB,uCAAuC;IACvC,SAAS,EAAE,OAAO,CAAC;IACnB,yFAAyF;IACzF,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAMD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,UAAU,CAAC,CAwH/F;AAED;;;GAGG;AACH,wBAAsB,yBAAyB,CAC9C,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,cAAc,EAC1B,OAAO,CAAC,EAAE,mBAAmB,GAC3B,OAAO,CAAC,UAAU,CAAC,CAsFrB","sourcesContent":["/**\r\n * Bash command execution with streaming support and cancellation.\r\n *\r\n * This module provides a unified bash execution implementation used by:\r\n * - AgentSession.executeBash() for interactive and RPC modes\r\n * - Direct calls from modes that need bash execution\r\n */\r\n\r\nimport { randomBytes } from \"node:crypto\";\r\nimport { createWriteStream, type WriteStream } from \"node:fs\";\r\nimport { tmpdir } from \"node:os\";\r\nimport { join } from \"node:path\";\r\nimport { type ChildProcess, spawn } from \"child_process\";\r\nimport stripAnsi from \"strip-ansi\";\r\nimport { getShellConfig, getShellEnv, killProcessTree, sanitizeBinaryOutput } from \"../utils/shell.js\";\r\nimport type { BashOperations } from \"./tools/bash.js\";\r\nimport { DEFAULT_MAX_BYTES, truncateTail } from \"./tools/truncate.js\";\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\nexport interface BashExecutorOptions {\r\n\t/** Callback for streaming output chunks (already sanitized) */\r\n\tonChunk?: (chunk: string) => void;\r\n\t/** AbortSignal for cancellation */\r\n\tsignal?: AbortSignal;\r\n}\r\n\r\nexport interface BashResult {\r\n\t/** Combined stdout + stderr output (sanitized, possibly truncated) */\r\n\toutput: string;\r\n\t/** Process exit code (undefined if killed/cancelled) */\r\n\texitCode: number | undefined;\r\n\t/** Whether the command was cancelled via signal */\r\n\tcancelled: boolean;\r\n\t/** Whether the output was truncated */\r\n\ttruncated: boolean;\r\n\t/** Path to temp file containing full output (if output exceeded truncation threshold) */\r\n\tfullOutputPath?: string;\r\n}\r\n\r\n// ============================================================================\r\n// Implementation\r\n// ============================================================================\r\n\r\n/**\r\n * Execute a bash command with optional streaming and cancellation support.\r\n *\r\n * Features:\r\n * - Streams sanitized output via onChunk callback\r\n * - Writes large output to temp file for later retrieval\r\n * - Supports cancellation via AbortSignal\r\n * - Sanitizes output (strips ANSI, removes binary garbage, normalizes newlines)\r\n * - Truncates output if it exceeds the default max bytes\r\n *\r\n * @param command - The bash command to execute\r\n * @param options - Optional streaming callback and abort signal\r\n * @returns Promise resolving to execution result\r\n */\r\nexport function executeBash(command: string, options?: BashExecutorOptions): Promise<BashResult> {\r\n\treturn new Promise((resolve, reject) => {\r\n\t\tconst { shell, args } = getShellConfig();\r\n\t\tconst child: ChildProcess = spawn(shell, [...args, command], {\r\n\t\t\tdetached: true,\r\n\t\t\tenv: getShellEnv(),\r\n\t\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\r\n\t\t});\r\n\r\n\t\t// Track sanitized output for truncation\r\n\t\tconst outputChunks: string[] = [];\r\n\t\tlet outputBytes = 0;\r\n\t\tconst maxOutputBytes = DEFAULT_MAX_BYTES * 2;\r\n\r\n\t\t// Temp file for large output\r\n\t\tlet tempFilePath: string | undefined;\r\n\t\tlet tempFileStream: WriteStream | undefined;\r\n\t\tlet totalBytes = 0;\r\n\r\n\t\t// Handle abort signal\r\n\t\tconst abortHandler = () => {\r\n\t\t\tif (child.pid) {\r\n\t\t\t\tkillProcessTree(child.pid);\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\tif (options?.signal) {\r\n\t\t\tif (options.signal.aborted) {\r\n\t\t\t\t// Already aborted, don't even start\r\n\t\t\t\tchild.kill();\r\n\t\t\t\tresolve({\r\n\t\t\t\t\toutput: \"\",\r\n\t\t\t\t\texitCode: undefined,\r\n\t\t\t\t\tcancelled: true,\r\n\t\t\t\t\ttruncated: false,\r\n\t\t\t\t});\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\toptions.signal.addEventListener(\"abort\", abortHandler, { once: true });\r\n\t\t}\r\n\r\n\t\tconst decoder = new TextDecoder();\r\n\r\n\t\tconst handleData = (data: Buffer) => {\r\n\t\t\ttotalBytes += data.length;\r\n\r\n\t\t\t// Sanitize once at the source: strip ANSI, replace binary garbage, normalize newlines\r\n\t\t\tconst text = sanitizeBinaryOutput(stripAnsi(decoder.decode(data, { stream: true }))).replace(/\\r/g, \"\");\r\n\r\n\t\t\t// Start writing to temp file if exceeds threshold\r\n\t\t\tif (totalBytes > DEFAULT_MAX_BYTES && !tempFilePath) {\r\n\t\t\t\tconst id = randomBytes(8).toString(\"hex\");\r\n\t\t\t\ttempFilePath = join(tmpdir(), `pi-bash-${id}.log`);\r\n\t\t\t\ttempFileStream = createWriteStream(tempFilePath);\r\n\t\t\t\t// Write already-buffered chunks to temp file\r\n\t\t\t\tfor (const chunk of outputChunks) {\r\n\t\t\t\t\ttempFileStream.write(chunk);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (tempFileStream) {\r\n\t\t\t\ttempFileStream.write(text);\r\n\t\t\t}\r\n\r\n\t\t\t// Keep rolling buffer of sanitized text\r\n\t\t\toutputChunks.push(text);\r\n\t\t\toutputBytes += text.length;\r\n\t\t\twhile (outputBytes > maxOutputBytes && outputChunks.length > 1) {\r\n\t\t\t\tconst removed = outputChunks.shift()!;\r\n\t\t\t\toutputBytes -= removed.length;\r\n\t\t\t}\r\n\r\n\t\t\t// Stream to callback if provided\r\n\t\t\tif (options?.onChunk) {\r\n\t\t\t\toptions.onChunk(text);\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\tchild.stdout?.on(\"data\", handleData);\r\n\t\tchild.stderr?.on(\"data\", handleData);\r\n\r\n\t\tchild.on(\"close\", (code) => {\r\n\t\t\t// Clean up abort listener\r\n\t\t\tif (options?.signal) {\r\n\t\t\t\toptions.signal.removeEventListener(\"abort\", abortHandler);\r\n\t\t\t}\r\n\r\n\t\t\tif (tempFileStream) {\r\n\t\t\t\ttempFileStream.end();\r\n\t\t\t}\r\n\r\n\t\t\t// Combine buffered chunks for truncation (already sanitized)\r\n\t\t\tconst fullOutput = outputChunks.join(\"\");\r\n\t\t\tconst truncationResult = truncateTail(fullOutput);\r\n\r\n\t\t\t// code === null means killed (cancelled)\r\n\t\t\tconst cancelled = code === null;\r\n\r\n\t\t\tresolve({\r\n\t\t\t\toutput: truncationResult.truncated ? truncationResult.content : fullOutput,\r\n\t\t\t\texitCode: cancelled ? undefined : code,\r\n\t\t\t\tcancelled,\r\n\t\t\t\ttruncated: truncationResult.truncated,\r\n\t\t\t\tfullOutputPath: tempFilePath,\r\n\t\t\t});\r\n\t\t});\r\n\r\n\t\tchild.on(\"error\", (err) => {\r\n\t\t\t// Clean up abort listener\r\n\t\t\tif (options?.signal) {\r\n\t\t\t\toptions.signal.removeEventListener(\"abort\", abortHandler);\r\n\t\t\t}\r\n\r\n\t\t\tif (tempFileStream) {\r\n\t\t\t\ttempFileStream.end();\r\n\t\t\t}\r\n\r\n\t\t\treject(err);\r\n\t\t});\r\n\t});\r\n}\r\n\r\n/**\r\n * Execute a bash command using custom BashOperations.\r\n * Used for remote execution (SSH, containers, etc.).\r\n */\r\nexport async function executeBashWithOperations(\r\n\tcommand: string,\r\n\tcwd: string,\r\n\toperations: BashOperations,\r\n\toptions?: BashExecutorOptions,\r\n): Promise<BashResult> {\r\n\tconst outputChunks: string[] = [];\r\n\tlet outputBytes = 0;\r\n\tconst maxOutputBytes = DEFAULT_MAX_BYTES * 2;\r\n\r\n\tlet tempFilePath: string | undefined;\r\n\tlet tempFileStream: WriteStream | undefined;\r\n\tlet totalBytes = 0;\r\n\r\n\tconst decoder = new TextDecoder();\r\n\r\n\tconst onData = (data: Buffer) => {\r\n\t\ttotalBytes += data.length;\r\n\r\n\t\t// Sanitize: strip ANSI, replace binary garbage, normalize newlines\r\n\t\tconst text = sanitizeBinaryOutput(stripAnsi(decoder.decode(data, { stream: true }))).replace(/\\r/g, \"\");\r\n\r\n\t\t// Start writing to temp file if exceeds threshold\r\n\t\tif (totalBytes > DEFAULT_MAX_BYTES && !tempFilePath) {\r\n\t\t\tconst id = randomBytes(8).toString(\"hex\");\r\n\t\t\ttempFilePath = join(tmpdir(), `pi-bash-${id}.log`);\r\n\t\t\ttempFileStream = createWriteStream(tempFilePath);\r\n\t\t\tfor (const chunk of outputChunks) {\r\n\t\t\t\ttempFileStream.write(chunk);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (tempFileStream) {\r\n\t\t\ttempFileStream.write(text);\r\n\t\t}\r\n\r\n\t\t// Keep rolling buffer\r\n\t\toutputChunks.push(text);\r\n\t\toutputBytes += text.length;\r\n\t\twhile (outputBytes > maxOutputBytes && outputChunks.length > 1) {\r\n\t\t\tconst removed = outputChunks.shift()!;\r\n\t\t\toutputBytes -= removed.length;\r\n\t\t}\r\n\r\n\t\t// Stream to callback\r\n\t\tif (options?.onChunk) {\r\n\t\t\toptions.onChunk(text);\r\n\t\t}\r\n\t};\r\n\r\n\ttry {\r\n\t\tconst result = await operations.exec(command, cwd, {\r\n\t\t\tonData,\r\n\t\t\tsignal: options?.signal,\r\n\t\t});\r\n\r\n\t\tif (tempFileStream) {\r\n\t\t\ttempFileStream.end();\r\n\t\t}\r\n\r\n\t\tconst fullOutput = outputChunks.join(\"\");\r\n\t\tconst truncationResult = truncateTail(fullOutput);\r\n\t\tconst cancelled = options?.signal?.aborted ?? false;\r\n\r\n\t\treturn {\r\n\t\t\toutput: truncationResult.truncated ? truncationResult.content : fullOutput,\r\n\t\t\texitCode: cancelled ? undefined : (result.exitCode ?? undefined),\r\n\t\t\tcancelled,\r\n\t\t\ttruncated: truncationResult.truncated,\r\n\t\t\tfullOutputPath: tempFilePath,\r\n\t\t};\r\n\t} catch (err) {\r\n\t\tif (tempFileStream) {\r\n\t\t\ttempFileStream.end();\r\n\t\t}\r\n\r\n\t\t// Check if it was an abort\r\n\t\tif (options?.signal?.aborted) {\r\n\t\t\tconst fullOutput = outputChunks.join(\"\");\r\n\t\t\tconst truncationResult = truncateTail(fullOutput);\r\n\t\t\treturn {\r\n\t\t\t\toutput: truncationResult.truncated ? truncationResult.content : fullOutput,\r\n\t\t\t\texitCode: undefined,\r\n\t\t\t\tcancelled: true,\r\n\t\t\t\ttruncated: truncationResult.truncated,\r\n\t\t\t\tfullOutputPath: tempFilePath,\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\tthrow err;\r\n\t}\r\n}\r\n"]}
|