pi-ui-extend 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/README.md +307 -0
- package/bin/pix.mjs +219 -0
- package/dist/app/app.d.ts +96 -0
- package/dist/app/app.js +871 -0
- package/dist/app/blink-controller.d.ts +23 -0
- package/dist/app/blink-controller.js +82 -0
- package/dist/app/cli.d.ts +8 -0
- package/dist/app/cli.js +83 -0
- package/dist/app/clipboard.d.ts +1 -0
- package/dist/app/clipboard.js +24 -0
- package/dist/app/command-controller.d.ts +18 -0
- package/dist/app/command-controller.js +58 -0
- package/dist/app/command-host.d.ts +44 -0
- package/dist/app/command-host.js +1 -0
- package/dist/app/command-model-actions.d.ts +12 -0
- package/dist/app/command-model-actions.js +176 -0
- package/dist/app/command-navigation-actions.d.ts +19 -0
- package/dist/app/command-navigation-actions.js +267 -0
- package/dist/app/command-registry.d.ts +32 -0
- package/dist/app/command-registry.js +225 -0
- package/dist/app/command-runtime.d.ts +5 -0
- package/dist/app/command-runtime.js +32 -0
- package/dist/app/command-session-actions.d.ts +20 -0
- package/dist/app/command-session-actions.js +295 -0
- package/dist/app/constants.d.ts +52 -0
- package/dist/app/constants.js +103 -0
- package/dist/app/conversation-entry-renderer.d.ts +21 -0
- package/dist/app/conversation-entry-renderer.js +81 -0
- package/dist/app/conversation-shell-renderer.d.ts +5 -0
- package/dist/app/conversation-shell-renderer.js +43 -0
- package/dist/app/conversation-tool-renderer.d.ts +16 -0
- package/dist/app/conversation-tool-renderer.js +216 -0
- package/dist/app/conversation-viewport.d.ts +55 -0
- package/dist/app/conversation-viewport.js +252 -0
- package/dist/app/dcp-stats.d.ts +2 -0
- package/dist/app/dcp-stats.js +116 -0
- package/dist/app/editor-layout-renderer.d.ts +31 -0
- package/dist/app/editor-layout-renderer.js +211 -0
- package/dist/app/editor-panels.d.ts +4 -0
- package/dist/app/editor-panels.js +130 -0
- package/dist/app/extension-actions-controller.d.ts +22 -0
- package/dist/app/extension-actions-controller.js +60 -0
- package/dist/app/extension-event-bus.d.ts +3 -0
- package/dist/app/extension-event-bus.js +23 -0
- package/dist/app/extension-ui-controller.d.ts +57 -0
- package/dist/app/extension-ui-controller.js +532 -0
- package/dist/app/file-link-opener.d.ts +2 -0
- package/dist/app/file-link-opener.js +66 -0
- package/dist/app/file-links.d.ts +10 -0
- package/dist/app/file-links.js +117 -0
- package/dist/app/guards.d.ts +3 -0
- package/dist/app/guards.js +9 -0
- package/dist/app/icons.d.ts +37 -0
- package/dist/app/icons.js +97 -0
- package/dist/app/id.d.ts +1 -0
- package/dist/app/id.js +4 -0
- package/dist/app/image-click-targets.d.ts +5 -0
- package/dist/app/image-click-targets.js +32 -0
- package/dist/app/image-opener.d.ts +2 -0
- package/dist/app/image-opener.js +64 -0
- package/dist/app/input-action-controller.d.ts +47 -0
- package/dist/app/input-action-controller.js +209 -0
- package/dist/app/input-controller.d.ts +60 -0
- package/dist/app/input-controller.js +425 -0
- package/dist/app/input-paste-handler.d.ts +27 -0
- package/dist/app/input-paste-handler.js +146 -0
- package/dist/app/menu-items-controller.d.ts +32 -0
- package/dist/app/menu-items-controller.js +182 -0
- package/dist/app/message-content.d.ts +8 -0
- package/dist/app/message-content.js +115 -0
- package/dist/app/model-ref.d.ts +13 -0
- package/dist/app/model-ref.js +50 -0
- package/dist/app/model-usage-controller.d.ts +35 -0
- package/dist/app/model-usage-controller.js +99 -0
- package/dist/app/model-usage-status.d.ts +125 -0
- package/dist/app/model-usage-status.js +749 -0
- package/dist/app/mouse-controller.d.ts +182 -0
- package/dist/app/mouse-controller.js +968 -0
- package/dist/app/native-modifiers.d.ts +3 -0
- package/dist/app/native-modifiers.js +60 -0
- package/dist/app/nerd-font-controller.d.ts +11 -0
- package/dist/app/nerd-font-controller.js +90 -0
- package/dist/app/popup-action-controller.d.ts +44 -0
- package/dist/app/popup-action-controller.js +278 -0
- package/dist/app/popup-menu-controller.d.ts +183 -0
- package/dist/app/popup-menu-controller.js +1070 -0
- package/dist/app/prompt-enhancer-controller.d.ts +40 -0
- package/dist/app/prompt-enhancer-controller.js +215 -0
- package/dist/app/queued-message-controller.d.ts +62 -0
- package/dist/app/queued-message-controller.js +377 -0
- package/dist/app/render-controller.d.ts +41 -0
- package/dist/app/render-controller.js +378 -0
- package/dist/app/render-text.d.ts +19 -0
- package/dist/app/render-text.js +67 -0
- package/dist/app/request-history.d.ts +23 -0
- package/dist/app/request-history.js +131 -0
- package/dist/app/runtime.d.ts +39 -0
- package/dist/app/runtime.js +195 -0
- package/dist/app/screen-selection.d.ts +6 -0
- package/dist/app/screen-selection.js +9 -0
- package/dist/app/screen-styler.d.ts +34 -0
- package/dist/app/screen-styler.js +168 -0
- package/dist/app/scroll-controller.d.ts +51 -0
- package/dist/app/scroll-controller.js +207 -0
- package/dist/app/session-event-controller.d.ts +69 -0
- package/dist/app/session-event-controller.js +338 -0
- package/dist/app/session-history.d.ts +23 -0
- package/dist/app/session-history.js +164 -0
- package/dist/app/session-lifecycle-controller.d.ts +55 -0
- package/dist/app/session-lifecycle-controller.js +116 -0
- package/dist/app/session-search.d.ts +24 -0
- package/dist/app/session-search.js +215 -0
- package/dist/app/shell-command.d.ts +27 -0
- package/dist/app/shell-command.js +176 -0
- package/dist/app/shell-controller.d.ts +28 -0
- package/dist/app/shell-controller.js +124 -0
- package/dist/app/slash-commands.d.ts +6 -0
- package/dist/app/slash-commands.js +75 -0
- package/dist/app/startup-checks.d.ts +8 -0
- package/dist/app/startup-checks.js +59 -0
- package/dist/app/startup-info.d.ts +3 -0
- package/dist/app/startup-info.js +176 -0
- package/dist/app/status-controller.d.ts +35 -0
- package/dist/app/status-controller.js +105 -0
- package/dist/app/status-line-renderer.d.ts +68 -0
- package/dist/app/status-line-renderer.js +453 -0
- package/dist/app/subagents-files.d.ts +10 -0
- package/dist/app/subagents-files.js +193 -0
- package/dist/app/subagents-model.d.ts +23 -0
- package/dist/app/subagents-model.js +224 -0
- package/dist/app/subagents-widget-controller.d.ts +43 -0
- package/dist/app/subagents-widget-controller.js +311 -0
- package/dist/app/tab-line-renderer.d.ts +26 -0
- package/dist/app/tab-line-renderer.js +222 -0
- package/dist/app/tabs-controller.d.ts +100 -0
- package/dist/app/tabs-controller.js +885 -0
- package/dist/app/terminal-controller.d.ts +40 -0
- package/dist/app/terminal-controller.js +135 -0
- package/dist/app/terminal-edit-shortcuts.d.ts +23 -0
- package/dist/app/terminal-edit-shortcuts.js +138 -0
- package/dist/app/terminal-output-buffer.d.ts +20 -0
- package/dist/app/terminal-output-buffer.js +52 -0
- package/dist/app/toast-controller.d.ts +13 -0
- package/dist/app/toast-controller.js +40 -0
- package/dist/app/toast-renderer.d.ts +9 -0
- package/dist/app/toast-renderer.js +79 -0
- package/dist/app/todo-model.d.ts +22 -0
- package/dist/app/todo-model.js +179 -0
- package/dist/app/todo-widget-controller.d.ts +21 -0
- package/dist/app/todo-widget-controller.js +59 -0
- package/dist/app/tool-block-renderer.d.ts +26 -0
- package/dist/app/tool-block-renderer.js +439 -0
- package/dist/app/types.d.ts +550 -0
- package/dist/app/types.js +1 -0
- package/dist/app/update.d.ts +36 -0
- package/dist/app/update.js +315 -0
- package/dist/app/voice-controller.d.ts +52 -0
- package/dist/app/voice-controller.js +600 -0
- package/dist/app/workspace-actions-controller.d.ts +40 -0
- package/dist/app/workspace-actions-controller.js +215 -0
- package/dist/app/workspace-undo.d.ts +44 -0
- package/dist/app/workspace-undo.js +215 -0
- package/dist/config.d.ts +62 -0
- package/dist/config.js +527 -0
- package/dist/context-progress-bar.d.ts +17 -0
- package/dist/context-progress-bar.js +48 -0
- package/dist/default-pix-config.d.ts +1 -0
- package/dist/default-pix-config.js +375 -0
- package/dist/fuzzy.d.ts +23 -0
- package/dist/fuzzy.js +165 -0
- package/dist/input-editor-files.d.ts +15 -0
- package/dist/input-editor-files.js +62 -0
- package/dist/input-editor.d.ts +186 -0
- package/dist/input-editor.js +835 -0
- package/dist/main.d.ts +1 -0
- package/dist/main.js +12 -0
- package/dist/markdown-format.d.ts +22 -0
- package/dist/markdown-format.js +542 -0
- package/dist/sdk.d.ts +3 -0
- package/dist/sdk.js +1 -0
- package/dist/syntax-highlight.d.ts +22 -0
- package/dist/syntax-highlight.js +528 -0
- package/dist/terminal-width.d.ts +6 -0
- package/dist/terminal-width.js +245 -0
- package/dist/theme.d.ts +56 -0
- package/dist/theme.js +118 -0
- package/dist/tool-renderers/apply-patch.d.ts +2 -0
- package/dist/tool-renderers/apply-patch.js +36 -0
- package/dist/tool-renderers/ast.d.ts +2 -0
- package/dist/tool-renderers/ast.js +5 -0
- package/dist/tool-renderers/compress.d.ts +2 -0
- package/dist/tool-renderers/compress.js +126 -0
- package/dist/tool-renderers/index.d.ts +3 -0
- package/dist/tool-renderers/index.js +44 -0
- package/dist/tool-renderers/question.d.ts +2 -0
- package/dist/tool-renderers/question.js +88 -0
- package/dist/tool-renderers/read.d.ts +2 -0
- package/dist/tool-renderers/read.js +36 -0
- package/dist/tool-renderers/repo.d.ts +2 -0
- package/dist/tool-renderers/repo.js +13 -0
- package/dist/tool-renderers/shell.d.ts +3 -0
- package/dist/tool-renderers/shell.js +27 -0
- package/dist/tool-renderers/skill.d.ts +2 -0
- package/dist/tool-renderers/skill.js +132 -0
- package/dist/tool-renderers/subagents.d.ts +2 -0
- package/dist/tool-renderers/subagents.js +51 -0
- package/dist/tool-renderers/todo.d.ts +2 -0
- package/dist/tool-renderers/todo.js +9 -0
- package/dist/tool-renderers/types.d.ts +42 -0
- package/dist/tool-renderers/types.js +1 -0
- package/dist/tool-renderers/utils.d.ts +31 -0
- package/dist/tool-renderers/utils.js +230 -0
- package/dist/tool-renderers/web.d.ts +3 -0
- package/dist/tool-renderers/web.js +9 -0
- package/dist/tool-renderers/write.d.ts +2 -0
- package/dist/tool-renderers/write.js +42 -0
- package/dist/ui.d.ts +56 -0
- package/dist/ui.js +94 -0
- package/docs/release.md +81 -0
- package/extensions/question/contract.ts +100 -0
- package/extensions/question/index.ts +34 -0
- package/extensions/question/render.ts +28 -0
- package/extensions/question/result.ts +86 -0
- package/extensions/question/tool-description.ts +11 -0
- package/extensions/question/tui.ts +629 -0
- package/extensions/question/types.ts +123 -0
- package/extensions/session-title/config.ts +169 -0
- package/extensions/session-title/index.ts +459 -0
- package/extensions/terminal-bell/index.ts +315 -0
- package/external/pi-tools-suite/README.md +242 -0
- package/external/pi-tools-suite/index.ts +1 -0
- package/external/pi-tools-suite/licenses/ollama-pi-web-search.MIT +21 -0
- package/external/pi-tools-suite/licenses/opencode-mystatus-MIT.txt +21 -0
- package/external/pi-tools-suite/package.json +53 -0
- package/external/pi-tools-suite/src/antigravity-auth/auth-store.ts +194 -0
- package/external/pi-tools-suite/src/antigravity-auth/commands.ts +80 -0
- package/external/pi-tools-suite/src/antigravity-auth/constants.ts +26 -0
- package/external/pi-tools-suite/src/antigravity-auth/headers.ts +20 -0
- package/external/pi-tools-suite/src/antigravity-auth/index.ts +104 -0
- package/external/pi-tools-suite/src/antigravity-auth/models.ts +86 -0
- package/external/pi-tools-suite/src/antigravity-auth/oauth.ts +305 -0
- package/external/pi-tools-suite/src/antigravity-auth/payload.ts +423 -0
- package/external/pi-tools-suite/src/antigravity-auth/status.ts +78 -0
- package/external/pi-tools-suite/src/antigravity-auth/stream.ts +302 -0
- package/external/pi-tools-suite/src/antigravity-auth/types.ts +113 -0
- package/external/pi-tools-suite/src/ast-grep/index.ts +6 -0
- package/external/pi-tools-suite/src/ast-grep/render.ts +70 -0
- package/external/pi-tools-suite/src/ast-grep/schema.ts +109 -0
- package/external/pi-tools-suite/src/ast-grep/tool.ts +345 -0
- package/external/pi-tools-suite/src/ast-grep/types.ts +55 -0
- package/external/pi-tools-suite/src/ast-grep/utils.ts +65 -0
- package/external/pi-tools-suite/src/async-subagents/async-subagents.sample.jsonc +222 -0
- package/external/pi-tools-suite/src/async-subagents/commands.ts +518 -0
- package/external/pi-tools-suite/src/async-subagents/constants.ts +11 -0
- package/external/pi-tools-suite/src/async-subagents/core/agent-strategy.ts +74 -0
- package/external/pi-tools-suite/src/async-subagents/core/attachment-bridge.ts +133 -0
- package/external/pi-tools-suite/src/async-subagents/core/cleanup.ts +66 -0
- package/external/pi-tools-suite/src/async-subagents/core/concurrency.ts +90 -0
- package/external/pi-tools-suite/src/async-subagents/core/config.ts +819 -0
- package/external/pi-tools-suite/src/async-subagents/core/log-limits.ts +166 -0
- package/external/pi-tools-suite/src/async-subagents/core/model-fallback.ts +133 -0
- package/external/pi-tools-suite/src/async-subagents/core/paths.ts +47 -0
- package/external/pi-tools-suite/src/async-subagents/core/pi-invocation.ts +35 -0
- package/external/pi-tools-suite/src/async-subagents/core/presets.ts +67 -0
- package/external/pi-tools-suite/src/async-subagents/core/process.ts +15 -0
- package/external/pi-tools-suite/src/async-subagents/core/prompt.ts +66 -0
- package/external/pi-tools-suite/src/async-subagents/core/registry.ts +224 -0
- package/external/pi-tools-suite/src/async-subagents/core/retry.ts +191 -0
- package/external/pi-tools-suite/src/async-subagents/core/routing.ts +259 -0
- package/external/pi-tools-suite/src/async-subagents/core/sessions.ts +138 -0
- package/external/pi-tools-suite/src/async-subagents/core/spawn.ts +688 -0
- package/external/pi-tools-suite/src/async-subagents/core/state.ts +281 -0
- package/external/pi-tools-suite/src/async-subagents/core/stop.ts +131 -0
- package/external/pi-tools-suite/src/async-subagents/core/structured-result.ts +237 -0
- package/external/pi-tools-suite/src/async-subagents/core/tool-guard.ts +34 -0
- package/external/pi-tools-suite/src/async-subagents/core/types.ts +150 -0
- package/external/pi-tools-suite/src/async-subagents/core/ultrawork-auto.ts +184 -0
- package/external/pi-tools-suite/src/async-subagents/core/utils.ts +11 -0
- package/external/pi-tools-suite/src/async-subagents/format.ts +41 -0
- package/external/pi-tools-suite/src/async-subagents/index.ts +422 -0
- package/external/pi-tools-suite/src/async-subagents/lib.ts +88 -0
- package/external/pi-tools-suite/src/async-subagents/live.ts +10 -0
- package/external/pi-tools-suite/src/async-subagents/polling.ts +83 -0
- package/external/pi-tools-suite/src/async-subagents/render.ts +230 -0
- package/external/pi-tools-suite/src/async-subagents/subagent-overlay.ts +77 -0
- package/external/pi-tools-suite/src/async-subagents/tasks.ts +120 -0
- package/external/pi-tools-suite/src/async-subagents/tools/cleanup.ts +99 -0
- package/external/pi-tools-suite/src/async-subagents/tools/result.ts +179 -0
- package/external/pi-tools-suite/src/async-subagents/tools/spawn.ts +372 -0
- package/external/pi-tools-suite/src/async-subagents/tools/status.ts +60 -0
- package/external/pi-tools-suite/src/async-subagents/tools/stop.ts +79 -0
- package/external/pi-tools-suite/src/async-subagents/tools/subagents.ts +152 -0
- package/external/pi-tools-suite/src/async-subagents/tools/wait.ts +67 -0
- package/external/pi-tools-suite/src/async-subagents/types.ts +45 -0
- package/external/pi-tools-suite/src/async-subagents/ui.ts +5 -0
- package/external/pi-tools-suite/src/compress/commands.ts +440 -0
- package/external/pi-tools-suite/src/compress/compress-tool.ts +368 -0
- package/external/pi-tools-suite/src/compress/compression-blocks.ts +524 -0
- package/external/pi-tools-suite/src/compress/config.ts +310 -0
- package/external/pi-tools-suite/src/compress/dcp-tui-filter.ts +498 -0
- package/external/pi-tools-suite/src/compress/index.ts +397 -0
- package/external/pi-tools-suite/src/compress/prompts.ts +269 -0
- package/external/pi-tools-suite/src/compress/pruner-candidates.ts +176 -0
- package/external/pi-tools-suite/src/compress/pruner-compression-blocks.ts +260 -0
- package/external/pi-tools-suite/src/compress/pruner-message-ids.ts +147 -0
- package/external/pi-tools-suite/src/compress/pruner-metadata.ts +268 -0
- package/external/pi-tools-suite/src/compress/pruner-nudge.ts +315 -0
- package/external/pi-tools-suite/src/compress/pruner-tools.ts +263 -0
- package/external/pi-tools-suite/src/compress/pruner-types.ts +25 -0
- package/external/pi-tools-suite/src/compress/pruner.ts +92 -0
- package/external/pi-tools-suite/src/compress/state.ts +486 -0
- package/external/pi-tools-suite/src/compress/ui.ts +308 -0
- package/external/pi-tools-suite/src/config.ts +176 -0
- package/external/pi-tools-suite/src/context-usage.ts +31 -0
- package/external/pi-tools-suite/src/default-pi-tools-suite-config.ts +355 -0
- package/external/pi-tools-suite/src/index.ts +46 -0
- package/external/pi-tools-suite/src/lib/lsp.ts +62 -0
- package/external/pi-tools-suite/src/lib/project.ts +42 -0
- package/external/pi-tools-suite/src/lib/tool-args.ts +137 -0
- package/external/pi-tools-suite/src/lsp/_shared/config.ts +156 -0
- package/external/pi-tools-suite/src/lsp/_shared/glob.ts +60 -0
- package/external/pi-tools-suite/src/lsp/_shared/output.ts +102 -0
- package/external/pi-tools-suite/src/lsp/_shared/paths.ts +138 -0
- package/external/pi-tools-suite/src/lsp/_shared/runner.ts +64 -0
- package/external/pi-tools-suite/src/lsp/_shared/template.ts +23 -0
- package/external/pi-tools-suite/src/lsp/_shared/trust.ts +116 -0
- package/external/pi-tools-suite/src/lsp/_shared/types.ts +98 -0
- package/external/pi-tools-suite/src/lsp/async.ts +29 -0
- package/external/pi-tools-suite/src/lsp/child-process.ts +81 -0
- package/external/pi-tools-suite/src/lsp/client.ts +340 -0
- package/external/pi-tools-suite/src/lsp/constants.ts +9 -0
- package/external/pi-tools-suite/src/lsp/diagnostics-store.ts +64 -0
- package/external/pi-tools-suite/src/lsp/documents.ts +24 -0
- package/external/pi-tools-suite/src/lsp/index.ts +31 -0
- package/external/pi-tools-suite/src/lsp/lsp-utils.ts +37 -0
- package/external/pi-tools-suite/src/lsp/manager.ts +190 -0
- package/external/pi-tools-suite/src/lsp/mutation-events.ts +78 -0
- package/external/pi-tools-suite/src/lsp/renderer.ts +1 -0
- package/external/pi-tools-suite/src/lsp/tool-result.ts +6 -0
- package/external/pi-tools-suite/src/lsp/tsserver.ts +107 -0
- package/external/pi-tools-suite/src/lsp/types.ts +15 -0
- package/external/pi-tools-suite/src/model-tools/apply-patch.ts +590 -0
- package/external/pi-tools-suite/src/model-tools/index.ts +430 -0
- package/external/pi-tools-suite/src/model-tools/path-utils.ts +6 -0
- package/external/pi-tools-suite/src/model-tools/tool-args.ts +11 -0
- package/external/pi-tools-suite/src/prompt-commands/index.ts +349 -0
- package/external/pi-tools-suite/src/repo-discovery/index.ts +384 -0
- package/external/pi-tools-suite/src/repo-discovery/project.ts +7 -0
- package/external/pi-tools-suite/src/startup-section.ts +13 -0
- package/external/pi-tools-suite/src/terminal-bell/index.ts +309 -0
- package/external/pi-tools-suite/src/todo/index.ts +201 -0
- package/external/pi-tools-suite/src/todo/state/auto-clear.ts +13 -0
- package/external/pi-tools-suite/src/todo/state/invariants.ts +21 -0
- package/external/pi-tools-suite/src/todo/state/persistence.ts +94 -0
- package/external/pi-tools-suite/src/todo/state/replay.ts +38 -0
- package/external/pi-tools-suite/src/todo/state/selectors.ts +49 -0
- package/external/pi-tools-suite/src/todo/state/state-reducer.ts +362 -0
- package/external/pi-tools-suite/src/todo/state/state.ts +18 -0
- package/external/pi-tools-suite/src/todo/state/store.ts +52 -0
- package/external/pi-tools-suite/src/todo/state/task-graph.ts +57 -0
- package/external/pi-tools-suite/src/todo/todo.ts +487 -0
- package/external/pi-tools-suite/src/todo/tool/response-envelope.ts +143 -0
- package/external/pi-tools-suite/src/todo/tool/types.ts +188 -0
- package/external/pi-tools-suite/src/todo/view/format.ts +18 -0
- package/external/pi-tools-suite/src/todo/view/labels.ts +13 -0
- package/external/pi-tools-suite/src/tool-descriptions.ts +369 -0
- package/external/pi-tools-suite/src/usage/index.ts +152 -0
- package/external/pi-tools-suite/src/usage/lib/copilot.ts +535 -0
- package/external/pi-tools-suite/src/usage/lib/google.ts +478 -0
- package/external/pi-tools-suite/src/usage/lib/openai.ts +268 -0
- package/external/pi-tools-suite/src/usage/lib/types.ts +114 -0
- package/external/pi-tools-suite/src/usage/lib/utils.ts +134 -0
- package/external/pi-tools-suite/src/usage/lib/zhipu.ts +228 -0
- package/external/pi-tools-suite/src/web-search/index.ts +397 -0
- package/package.json +89 -0
- package/skills/context7/SKILL.md +69 -0
- package/skills/context7/scripts/context7.sh +73 -0
- package/skills/handoff/SKILL.md +15 -0
- package/skills/pdf/LICENSE.txt +30 -0
- package/skills/pdf/SKILL.md +314 -0
- package/skills/pdf/forms.md +294 -0
- package/skills/pdf/reference.md +612 -0
- package/skills/pdf/scripts/check_bounding_boxes.py +65 -0
- package/skills/pdf/scripts/check_fillable_fields.py +11 -0
- package/skills/pdf/scripts/convert_pdf_to_images.py +33 -0
- package/skills/pdf/scripts/create_validation_image.py +37 -0
- package/skills/pdf/scripts/extract_form_field_info.py +122 -0
- package/skills/pdf/scripts/extract_form_structure.py +115 -0
- package/skills/pdf/scripts/fill_fillable_fields.py +98 -0
- package/skills/pdf/scripts/fill_pdf_form_with_annotations.py +107 -0
- package/skills/playwright-cli/SKILL.md +388 -0
- package/skills/playwright-cli/references/element-attributes.md +23 -0
- package/skills/playwright-cli/references/playwright-tests.md +39 -0
- package/skills/playwright-cli/references/request-mocking.md +87 -0
- package/skills/playwright-cli/references/running-code.md +241 -0
- package/skills/playwright-cli/references/session-management.md +225 -0
- package/skills/playwright-cli/references/spec-driven-testing.md +305 -0
- package/skills/playwright-cli/references/storage-state.md +275 -0
- package/skills/playwright-cli/references/test-generation.md +134 -0
- package/skills/playwright-cli/references/tracing.md +139 -0
- package/skills/playwright-cli/references/video-recording.md +143 -0
- package/skills/simplify/SKILL.md +51 -0
- package/skills/skill-creator/LICENSE.txt +202 -0
- package/skills/skill-creator/SKILL.md +485 -0
- package/skills/skill-creator/agents/analyzer.md +274 -0
- package/skills/skill-creator/agents/comparator.md +202 -0
- package/skills/skill-creator/agents/grader.md +223 -0
- package/skills/skill-creator/assets/eval_review.html +146 -0
- package/skills/skill-creator/eval-viewer/generate_review.py +471 -0
- package/skills/skill-creator/eval-viewer/viewer.html +1325 -0
- package/skills/skill-creator/references/schemas.md +430 -0
- package/skills/skill-creator/scripts/__init__.py +0 -0
- package/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
- package/skills/skill-creator/scripts/generate_report.py +326 -0
- package/skills/skill-creator/scripts/improve_description.py +247 -0
- package/skills/skill-creator/scripts/package_skill.py +136 -0
- package/skills/skill-creator/scripts/quick_validate.py +103 -0
- package/skills/skill-creator/scripts/run_eval.py +310 -0
- package/skills/skill-creator/scripts/run_loop.py +328 -0
- package/skills/skill-creator/scripts/utils.py +47 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { getAgentDir, type ExtensionAPI, type ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
|
|
6
|
+
import { publishStartupSection } from "../startup-section";
|
|
7
|
+
import { queryGoogleUsage } from "./lib/google";
|
|
8
|
+
import { queryOpenAIUsage } from "./lib/openai";
|
|
9
|
+
import { type AuthData, type QueryResult } from "./lib/types";
|
|
10
|
+
import { queryZaiUsage, queryZhipuUsage } from "./lib/zhipu";
|
|
11
|
+
|
|
12
|
+
const CUSTOM_MESSAGE_TYPE = "usage";
|
|
13
|
+
|
|
14
|
+
type PiAuthCredential = {
|
|
15
|
+
type?: string;
|
|
16
|
+
access?: string;
|
|
17
|
+
refresh?: string;
|
|
18
|
+
expires?: number;
|
|
19
|
+
key?: string;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
type PiAuthData = Record<string, PiAuthCredential | undefined>;
|
|
23
|
+
|
|
24
|
+
async function readOpenCodeAuth(): Promise<{ authData: AuthData; error?: string }> {
|
|
25
|
+
const authPath = join(homedir(), ".local/share/opencode/auth.json");
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
const content = await readFile(authPath, "utf-8");
|
|
29
|
+
return { authData: JSON.parse(content) as AuthData };
|
|
30
|
+
} catch (error) {
|
|
31
|
+
return {
|
|
32
|
+
authData: {},
|
|
33
|
+
error: `❌ Failed to read auth file: ${authPath}\nError: ${error instanceof Error ? error.message : String(error)}`,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async function readPiAuth(): Promise<PiAuthData> {
|
|
39
|
+
try {
|
|
40
|
+
const content = await readFile(join(getAgentDir(), "auth.json"), "utf-8");
|
|
41
|
+
return JSON.parse(content) as PiAuthData;
|
|
42
|
+
} catch {
|
|
43
|
+
return {};
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function isExpired(credential: { expires?: number } | undefined): boolean {
|
|
48
|
+
return typeof credential?.expires === "number" && credential.expires < Date.now();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async function readAuthData(): Promise<{ authData: AuthData; error?: string }> {
|
|
52
|
+
const { authData, error } = await readOpenCodeAuth();
|
|
53
|
+
const piAuth = await readPiAuth();
|
|
54
|
+
|
|
55
|
+
const piOpenAI = piAuth["openai-codex"];
|
|
56
|
+
if ((!authData.openai || isExpired(authData.openai)) && piOpenAI?.type === "oauth" && piOpenAI.access) {
|
|
57
|
+
authData.openai = {
|
|
58
|
+
type: "oauth",
|
|
59
|
+
access: piOpenAI.access,
|
|
60
|
+
refresh: piOpenAI.refresh,
|
|
61
|
+
expires: piOpenAI.expires,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const piZai = piAuth.zai;
|
|
66
|
+
if (!authData["zai-coding-plan"] && piZai?.key && (piZai.type === "api" || piZai.type === "api_key")) {
|
|
67
|
+
authData["zai-coding-plan"] = { type: "api", key: piZai.key };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return { authData, error };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function collectResult(result: QueryResult | null, title: string, results: string[], errors: string[]): void {
|
|
74
|
+
if (!result) return;
|
|
75
|
+
|
|
76
|
+
if (result.success && result.output) {
|
|
77
|
+
if (results.length > 0) results.push("");
|
|
78
|
+
results.push(title);
|
|
79
|
+
results.push("");
|
|
80
|
+
results.push(result.output);
|
|
81
|
+
} else if (result.error) {
|
|
82
|
+
errors.push(result.error);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export async function queryUsage(): Promise<string> {
|
|
87
|
+
const { authData, error: authReadError } = await readAuthData();
|
|
88
|
+
|
|
89
|
+
const [openaiResult, zhipuResult, zaiResult, googleResult] = await Promise.all([
|
|
90
|
+
queryOpenAIUsage(authData.openai),
|
|
91
|
+
queryZhipuUsage(authData["zhipuai-coding-plan"]),
|
|
92
|
+
queryZaiUsage(authData["zai-coding-plan"]),
|
|
93
|
+
queryGoogleUsage(),
|
|
94
|
+
]);
|
|
95
|
+
|
|
96
|
+
const results: string[] = [];
|
|
97
|
+
const errors: string[] = [];
|
|
98
|
+
|
|
99
|
+
collectResult(openaiResult, "## OpenAI Account Quota", results, errors);
|
|
100
|
+
collectResult(zhipuResult, "## Zhipu AI Account Quota", results, errors);
|
|
101
|
+
collectResult(zaiResult, "## Z.ai Account Quota", results, errors);
|
|
102
|
+
collectResult(googleResult, "## Google Cloud Account Quota", results, errors);
|
|
103
|
+
|
|
104
|
+
if (results.length === 0 && errors.length === 0) {
|
|
105
|
+
const noAccounts = "No configured accounts found.\n\nSupported account types:\n- OpenAI (Plus/Team/Pro subscribers)\n- Zhipu AI (Coding Plan)\n- Z.ai (Coding Plan)\n- Google Cloud (Antigravity)";
|
|
106
|
+
return authReadError ? `${noAccounts}\n\n${authReadError}` : noAccounts;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
let output = results.join("\n");
|
|
110
|
+
if (errors.length > 0) {
|
|
111
|
+
if (output) output += "\n\n";
|
|
112
|
+
output += "❌ Failed to query accounts:\n" + errors.join("\n");
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return output;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function sendStatusMessage(pi: ExtensionAPI, text: string): void {
|
|
119
|
+
pi.sendMessage({
|
|
120
|
+
customType: CUSTOM_MESSAGE_TYPE,
|
|
121
|
+
content: text,
|
|
122
|
+
display: true,
|
|
123
|
+
details: { generatedAt: new Date().toISOString() },
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export default function usage(pi: ExtensionAPI) {
|
|
128
|
+
publishStartupSection({
|
|
129
|
+
id: "usage",
|
|
130
|
+
title: "usage",
|
|
131
|
+
body: "/usage — query quota usage for configured AI accounts",
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
async function showStatusFromCommand(ctx: ExtensionCommandContext): Promise<void> {
|
|
135
|
+
const text = await queryUsage();
|
|
136
|
+
|
|
137
|
+
if (ctx.hasUI) {
|
|
138
|
+
ctx.ui.notify("usage: quota usage refreshed", "info");
|
|
139
|
+
} else {
|
|
140
|
+
console.log(text);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
sendStatusMessage(pi, text);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
pi.registerCommand("usage", {
|
|
147
|
+
description: "Query quota usage for configured AI accounts, including per-model Antigravity/Gemini usage where available.",
|
|
148
|
+
handler: async (_args, ctx) => {
|
|
149
|
+
await showStatusFromCommand(ctx);
|
|
150
|
+
},
|
|
151
|
+
});
|
|
152
|
+
}
|
|
@@ -0,0 +1,535 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHub Copilot Premium Requests Quota Module
|
|
3
|
+
*
|
|
4
|
+
* [Input]: GitHub token from ~/.local/share/opencode/auth.json (github-copilot provider)
|
|
5
|
+
* [Output]: Formatted quota usage information with progress bars
|
|
6
|
+
* [Location]: Called by usage.ts to handle GitHub Copilot accounts
|
|
7
|
+
* [Sync]: usage.ts, types.ts, utils.ts
|
|
8
|
+
*
|
|
9
|
+
* [Updated]: Jan 2026 - Handle new OpenCode official partnership auth flow
|
|
10
|
+
* The new OAuth tokens (gho_) need to be exchanged for Copilot session tokens
|
|
11
|
+
* before calling the internal quota API.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import {
|
|
15
|
+
type QueryResult,
|
|
16
|
+
type CopilotAuthData,
|
|
17
|
+
type CopilotQuotaConfig,
|
|
18
|
+
type CopilotTier,
|
|
19
|
+
} from "./types";
|
|
20
|
+
import { createProgressBar, fetchWithTimeout } from "./utils";
|
|
21
|
+
import * as fs from "fs";
|
|
22
|
+
import * as path from "path";
|
|
23
|
+
import * as os from "os";
|
|
24
|
+
|
|
25
|
+
// ============================================================================
|
|
26
|
+
// Type Definitions
|
|
27
|
+
// ============================================================================
|
|
28
|
+
|
|
29
|
+
interface QuotaDetail {
|
|
30
|
+
entitlement: number;
|
|
31
|
+
overage_count: number;
|
|
32
|
+
overage_permitted: boolean;
|
|
33
|
+
percent_remaining: number;
|
|
34
|
+
quota_id: string;
|
|
35
|
+
quota_remaining: number;
|
|
36
|
+
remaining: number;
|
|
37
|
+
unlimited: boolean;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
interface QuotaSnapshots {
|
|
41
|
+
chat?: QuotaDetail;
|
|
42
|
+
completions?: QuotaDetail;
|
|
43
|
+
premium_interactions: QuotaDetail;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
interface CopilotUsageResponse {
|
|
47
|
+
access_type_sku: string;
|
|
48
|
+
analytics_tracking_id: string;
|
|
49
|
+
assigned_date: string;
|
|
50
|
+
can_signup_for_limited: boolean;
|
|
51
|
+
chat_enabled: boolean;
|
|
52
|
+
copilot_plan: string;
|
|
53
|
+
organization_login_list: unknown[];
|
|
54
|
+
organization_list: unknown[];
|
|
55
|
+
quota_reset_date: string;
|
|
56
|
+
quota_snapshots: QuotaSnapshots;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
interface CopilotTokenResponse {
|
|
60
|
+
token: string;
|
|
61
|
+
expires_at: number;
|
|
62
|
+
refresh_in: number;
|
|
63
|
+
endpoints: {
|
|
64
|
+
api: string;
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Public Billing API response types
|
|
69
|
+
interface BillingUsageItem {
|
|
70
|
+
product: string;
|
|
71
|
+
sku: string;
|
|
72
|
+
model?: string;
|
|
73
|
+
unitType: string;
|
|
74
|
+
grossQuantity: number;
|
|
75
|
+
netQuantity: number;
|
|
76
|
+
limit?: number;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
interface BillingUsageResponse {
|
|
80
|
+
timePeriod: { year: number; month?: number };
|
|
81
|
+
user: string;
|
|
82
|
+
usageItems: BillingUsageItem[];
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// ============================================================================
|
|
86
|
+
// Constants
|
|
87
|
+
// ============================================================================
|
|
88
|
+
|
|
89
|
+
const GITHUB_API_BASE_URL = "https://api.github.com";
|
|
90
|
+
|
|
91
|
+
// Config file path for user's fine-grained PAT
|
|
92
|
+
const COPILOT_QUOTA_CONFIG_PATH = path.join(
|
|
93
|
+
os.homedir(),
|
|
94
|
+
".config",
|
|
95
|
+
"opencode",
|
|
96
|
+
"copilot-quota-token.json",
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
// Updated to match current VS Code Copilot extension version
|
|
100
|
+
const COPILOT_VERSION = "0.35.0";
|
|
101
|
+
const EDITOR_VERSION = "vscode/1.107.0";
|
|
102
|
+
const EDITOR_PLUGIN_VERSION = `copilot-chat/${COPILOT_VERSION}`;
|
|
103
|
+
const USER_AGENT = `GitHubCopilotChat/${COPILOT_VERSION}`;
|
|
104
|
+
|
|
105
|
+
// Headers matching opencode-copilot-auth plugin (required for token exchange)
|
|
106
|
+
const COPILOT_HEADERS = {
|
|
107
|
+
"User-Agent": USER_AGENT,
|
|
108
|
+
"Editor-Version": EDITOR_VERSION,
|
|
109
|
+
"Editor-Plugin-Version": EDITOR_PLUGIN_VERSION,
|
|
110
|
+
"Copilot-Integration-Id": "vscode-chat",
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const COPILOT_QUOTA_UNAVAILABLE =
|
|
114
|
+
"⚠️ GitHub Copilot quota query unavailable.\n" +
|
|
115
|
+
"OpenCode's new OAuth integration doesn't support quota API access.";
|
|
116
|
+
|
|
117
|
+
const COPILOT_QUOTA_WORKAROUND =
|
|
118
|
+
"Solution:\n" +
|
|
119
|
+
"1. Create a fine-grained PAT (visit https://github.com/settings/tokens?type=beta)\n" +
|
|
120
|
+
"2. Under 'Account permissions', set 'Plan' to 'Read-only'\n" +
|
|
121
|
+
"3. Create config file ~/.config/opencode/copilot-quota-token.json:\n" +
|
|
122
|
+
' {"token": "github_pat_xxx...", "username": "YourUsername", "tier": "pro"}\n\n' +
|
|
123
|
+
"Alternatives:\n" +
|
|
124
|
+
"• Click the Copilot icon in VS Code status bar to view quota\n" +
|
|
125
|
+
"• Visit https://github.com/settings/billing for usage info";
|
|
126
|
+
|
|
127
|
+
// ============================================================================
|
|
128
|
+
// Token Exchange (New auth flow for official OpenCode partnership)
|
|
129
|
+
// ============================================================================
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Read optional Copilot quota config from user's config file
|
|
133
|
+
* Returns null if file doesn't exist or is invalid
|
|
134
|
+
*/
|
|
135
|
+
function readQuotaConfig(): CopilotQuotaConfig | null {
|
|
136
|
+
try {
|
|
137
|
+
if (!fs.existsSync(COPILOT_QUOTA_CONFIG_PATH)) {
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
const content = fs.readFileSync(COPILOT_QUOTA_CONFIG_PATH, "utf-8");
|
|
141
|
+
const config = JSON.parse(content) as CopilotQuotaConfig;
|
|
142
|
+
|
|
143
|
+
// Validate required fields
|
|
144
|
+
if (!config.token || !config.username || !config.tier) {
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Validate tier is valid
|
|
149
|
+
const validTiers: CopilotTier[] = [
|
|
150
|
+
"free",
|
|
151
|
+
"pro",
|
|
152
|
+
"pro+",
|
|
153
|
+
"business",
|
|
154
|
+
"enterprise",
|
|
155
|
+
];
|
|
156
|
+
if (!validTiers.includes(config.tier)) {
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return config;
|
|
161
|
+
} catch {
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Fetch quota using the public GitHub REST API
|
|
168
|
+
* Requires a fine-grained PAT with "Plan" read permission
|
|
169
|
+
*/
|
|
170
|
+
async function fetchPublicBillingUsage(
|
|
171
|
+
config: CopilotQuotaConfig,
|
|
172
|
+
): Promise<BillingUsageResponse> {
|
|
173
|
+
const response = await fetchWithTimeout(
|
|
174
|
+
`${GITHUB_API_BASE_URL}/users/${config.username}/settings/billing/premium_request/usage`,
|
|
175
|
+
{
|
|
176
|
+
headers: {
|
|
177
|
+
Accept: "application/vnd.github+json",
|
|
178
|
+
Authorization: `Bearer ${config.token}`,
|
|
179
|
+
"X-GitHub-Api-Version": "2022-11-28",
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
if (!response.ok) {
|
|
185
|
+
const errorText = await response.text();
|
|
186
|
+
throw new Error(`GitHub Copilot API request failed (${response.status}): ${errorText}`);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return response.json() as Promise<BillingUsageResponse>;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Exchange OAuth token for a Copilot session token
|
|
194
|
+
* Required for the new OpenCode official partnership auth flow (Jan 2026+)
|
|
195
|
+
*/
|
|
196
|
+
async function exchangeForCopilotToken(
|
|
197
|
+
oauthToken: string,
|
|
198
|
+
): Promise<string | null> {
|
|
199
|
+
try {
|
|
200
|
+
const response = await fetchWithTimeout(
|
|
201
|
+
`${GITHUB_API_BASE_URL}/copilot_internal/v2/token`,
|
|
202
|
+
{
|
|
203
|
+
headers: {
|
|
204
|
+
Accept: "application/json",
|
|
205
|
+
Authorization: `Bearer ${oauthToken}`,
|
|
206
|
+
...COPILOT_HEADERS,
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
);
|
|
210
|
+
|
|
211
|
+
if (!response.ok) {
|
|
212
|
+
// Token exchange failed - might be old token format or API change
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const tokenData: CopilotTokenResponse = await response.json();
|
|
217
|
+
return tokenData.token;
|
|
218
|
+
} catch {
|
|
219
|
+
return null;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// ============================================================================
|
|
224
|
+
// API Call
|
|
225
|
+
// ============================================================================
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Build headers for GitHub API requests (quota endpoint)
|
|
229
|
+
*/
|
|
230
|
+
function buildGitHubHeaders(token: string): Record<string, string> {
|
|
231
|
+
return {
|
|
232
|
+
"Content-Type": "application/json",
|
|
233
|
+
Accept: "application/json",
|
|
234
|
+
Authorization: `Bearer ${token}`,
|
|
235
|
+
...COPILOT_HEADERS,
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Build headers for legacy token format
|
|
241
|
+
*/
|
|
242
|
+
function buildLegacyHeaders(token: string): Record<string, string> {
|
|
243
|
+
return {
|
|
244
|
+
"Content-Type": "application/json",
|
|
245
|
+
Accept: "application/json",
|
|
246
|
+
Authorization: `token ${token}`,
|
|
247
|
+
...COPILOT_HEADERS,
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Fetch GitHub Copilot usage data
|
|
253
|
+
* Tries multiple authentication methods to handle both old and new token formats
|
|
254
|
+
*/
|
|
255
|
+
async function fetchCopilotUsage(
|
|
256
|
+
authData: CopilotAuthData,
|
|
257
|
+
): Promise<CopilotUsageResponse> {
|
|
258
|
+
// Use refresh token as the OAuth token (required)
|
|
259
|
+
// In new auth flow, access === refresh (both are the OAuth token)
|
|
260
|
+
const oauthToken = authData.refresh || authData.access;
|
|
261
|
+
if (!oauthToken) {
|
|
262
|
+
throw new Error("No OAuth token found in auth data");
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const cachedAccessToken = authData.access;
|
|
266
|
+
const tokenExpiry = authData.expires || 0;
|
|
267
|
+
|
|
268
|
+
// Strategy 1: If we have a valid cached access token (from previous exchange), use it
|
|
269
|
+
if (
|
|
270
|
+
cachedAccessToken &&
|
|
271
|
+
cachedAccessToken !== oauthToken &&
|
|
272
|
+
tokenExpiry > Date.now()
|
|
273
|
+
) {
|
|
274
|
+
const response = await fetchWithTimeout(
|
|
275
|
+
`${GITHUB_API_BASE_URL}/copilot_internal/user`,
|
|
276
|
+
{ headers: buildGitHubHeaders(cachedAccessToken) },
|
|
277
|
+
);
|
|
278
|
+
|
|
279
|
+
if (response.ok) {
|
|
280
|
+
return response.json() as Promise<CopilotUsageResponse>;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Strategy 2: Try direct call with OAuth token (works with older token formats)
|
|
285
|
+
const directResponse = await fetchWithTimeout(
|
|
286
|
+
`${GITHUB_API_BASE_URL}/copilot_internal/user`,
|
|
287
|
+
{ headers: buildLegacyHeaders(oauthToken) },
|
|
288
|
+
);
|
|
289
|
+
|
|
290
|
+
if (directResponse.ok) {
|
|
291
|
+
return directResponse.json() as Promise<CopilotUsageResponse>;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Strategy 3: Exchange OAuth token for Copilot session token (new auth flow)
|
|
295
|
+
const copilotToken = await exchangeForCopilotToken(oauthToken);
|
|
296
|
+
|
|
297
|
+
if (copilotToken) {
|
|
298
|
+
const exchangedResponse = await fetchWithTimeout(
|
|
299
|
+
`${GITHUB_API_BASE_URL}/copilot_internal/user`,
|
|
300
|
+
{ headers: buildGitHubHeaders(copilotToken) },
|
|
301
|
+
);
|
|
302
|
+
|
|
303
|
+
if (exchangedResponse.ok) {
|
|
304
|
+
return exchangedResponse.json() as Promise<CopilotUsageResponse>;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
const errorText = await exchangedResponse.text();
|
|
308
|
+
throw new Error(`GitHub Copilot API request failed (${exchangedResponse.status}): ${errorText}`);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// All strategies failed - likely due to OpenCode's OAuth token lacking copilot scope
|
|
312
|
+
// The new OpenCode partnership uses a different OAuth client that doesn't grant
|
|
313
|
+
// access to the /copilot_internal/* endpoints
|
|
314
|
+
throw new Error(`${COPILOT_QUOTA_UNAVAILABLE}\n\n${COPILOT_QUOTA_WORKAROUND}`);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// ============================================================================
|
|
318
|
+
// Formatting
|
|
319
|
+
// ============================================================================
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Format a single quota line
|
|
323
|
+
*/
|
|
324
|
+
function formatQuotaLine(
|
|
325
|
+
name: string,
|
|
326
|
+
quota: QuotaDetail | undefined,
|
|
327
|
+
width: number = 20,
|
|
328
|
+
): string {
|
|
329
|
+
if (!quota) return "";
|
|
330
|
+
|
|
331
|
+
if (quota.unlimited) {
|
|
332
|
+
return `${name.padEnd(14)} Unlimited`;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
const total = quota.entitlement;
|
|
336
|
+
const used = total - quota.remaining;
|
|
337
|
+
const percentRemaining = Math.round(quota.percent_remaining);
|
|
338
|
+
const progressBar = createProgressBar(percentRemaining, width);
|
|
339
|
+
|
|
340
|
+
return `${name.padEnd(14)} ${progressBar} ${percentRemaining}% (${used}/${total})`;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Calculate days until reset
|
|
345
|
+
*/
|
|
346
|
+
function getResetCountdown(resetDate: string): string {
|
|
347
|
+
const reset = new Date(resetDate);
|
|
348
|
+
const now = new Date();
|
|
349
|
+
const diffMs = reset.getTime() - now.getTime();
|
|
350
|
+
|
|
351
|
+
if (diffMs <= 0) return "Resets soon";
|
|
352
|
+
|
|
353
|
+
const days = Math.floor(diffMs / (1000 * 60 * 60 * 24));
|
|
354
|
+
const hours = Math.floor((diffMs % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
|
|
355
|
+
|
|
356
|
+
if (days > 0) {
|
|
357
|
+
return `${days}d ${hours}h`;
|
|
358
|
+
}
|
|
359
|
+
return `${hours}h`;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Format GitHub Copilot usage information
|
|
364
|
+
*/
|
|
365
|
+
function formatCopilotUsage(data: CopilotUsageResponse): string {
|
|
366
|
+
const lines: string[] = [];
|
|
367
|
+
|
|
368
|
+
// Account info
|
|
369
|
+
lines.push(`Account: GitHub Copilot (${data.copilot_plan})`);
|
|
370
|
+
lines.push("");
|
|
371
|
+
|
|
372
|
+
// Premium requests (main quota)
|
|
373
|
+
const premium = data.quota_snapshots.premium_interactions;
|
|
374
|
+
if (premium) {
|
|
375
|
+
const premiumLine = formatQuotaLine("Premium", premium);
|
|
376
|
+
if (premiumLine) lines.push(premiumLine);
|
|
377
|
+
|
|
378
|
+
// Show overage info if applicable
|
|
379
|
+
if (premium.overage_count > 0) {
|
|
380
|
+
lines.push(`Overage: ${premium.overage_count} requests`);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// Chat quota (if separate)
|
|
385
|
+
const chat = data.quota_snapshots.chat;
|
|
386
|
+
if (chat && !chat.unlimited) {
|
|
387
|
+
const chatLine = formatQuotaLine("Chat", chat);
|
|
388
|
+
if (chatLine) lines.push(chatLine);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// Completions quota (if separate)
|
|
392
|
+
const completions = data.quota_snapshots.completions;
|
|
393
|
+
if (completions && !completions.unlimited) {
|
|
394
|
+
const completionsLine = formatQuotaLine("Completions", completions);
|
|
395
|
+
if (completionsLine) lines.push(completionsLine);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// Reset date
|
|
399
|
+
lines.push("");
|
|
400
|
+
const resetCountdown = getResetCountdown(data.quota_reset_date);
|
|
401
|
+
lines.push(`Quota resets: ${resetCountdown} (${data.quota_reset_date})`);
|
|
402
|
+
|
|
403
|
+
return lines.join("\n");
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// Copilot plan limits (premium requests per month)
|
|
407
|
+
// Source: https://docs.github.com/en/copilot/about-github-copilot/subscription-plans-for-github-copilot
|
|
408
|
+
const COPILOT_PLAN_LIMITS: Record<CopilotTier, number> = {
|
|
409
|
+
free: 50, // Copilot Free: 50 premium requests/month
|
|
410
|
+
pro: 300, // Copilot Pro: 300 premium requests/month
|
|
411
|
+
"pro+": 1500, // Copilot Pro+: 1500 premium requests/month
|
|
412
|
+
business: 300, // Copilot Business: 300 premium requests/month
|
|
413
|
+
enterprise: 1000, // Copilot Enterprise: 1000 premium requests/month
|
|
414
|
+
};
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* Format public billing API response
|
|
418
|
+
* Different structure from internal API - aggregates usage items
|
|
419
|
+
* Uses grossQuantity (total requests made) since netQuantity shows post-discount amount
|
|
420
|
+
*/
|
|
421
|
+
function formatPublicBillingUsage(
|
|
422
|
+
data: BillingUsageResponse,
|
|
423
|
+
tier: CopilotTier,
|
|
424
|
+
): string {
|
|
425
|
+
const lines: string[] = [];
|
|
426
|
+
|
|
427
|
+
// Account info
|
|
428
|
+
lines.push(`Account: GitHub Copilot (@${data.user})`);
|
|
429
|
+
lines.push("");
|
|
430
|
+
|
|
431
|
+
// Aggregate all premium request usage (sum grossQuantity across all models)
|
|
432
|
+
const premiumItems = data.usageItems.filter(
|
|
433
|
+
(item) =>
|
|
434
|
+
item.sku === "Copilot Premium Request" || item.sku.includes("Premium"),
|
|
435
|
+
);
|
|
436
|
+
|
|
437
|
+
const totalUsed = premiumItems.reduce(
|
|
438
|
+
(sum, item) => sum + item.grossQuantity,
|
|
439
|
+
0,
|
|
440
|
+
);
|
|
441
|
+
|
|
442
|
+
// Get limit from tier
|
|
443
|
+
const limit = COPILOT_PLAN_LIMITS[tier];
|
|
444
|
+
|
|
445
|
+
const remaining = Math.max(0, limit - totalUsed);
|
|
446
|
+
const percentRemaining = Math.round((remaining / limit) * 100);
|
|
447
|
+
const progressBar = createProgressBar(percentRemaining, 20);
|
|
448
|
+
lines.push(
|
|
449
|
+
`${"Premium".padEnd(14)} ${progressBar} ${percentRemaining}% (${totalUsed}/${limit})`,
|
|
450
|
+
);
|
|
451
|
+
|
|
452
|
+
// Show model breakdown
|
|
453
|
+
const modelItems = data.usageItems.filter(
|
|
454
|
+
(item) => item.model && item.grossQuantity > 0,
|
|
455
|
+
);
|
|
456
|
+
|
|
457
|
+
if (modelItems.length > 0) {
|
|
458
|
+
lines.push("");
|
|
459
|
+
lines.push("Model breakdown:");
|
|
460
|
+
// Sort by usage descending
|
|
461
|
+
const sortedItems = [...modelItems].sort(
|
|
462
|
+
(a, b) => b.grossQuantity - a.grossQuantity,
|
|
463
|
+
);
|
|
464
|
+
for (const item of sortedItems.slice(0, 5)) {
|
|
465
|
+
// Show top 5 models
|
|
466
|
+
lines.push(` ${item.model}: ${item.grossQuantity} ${item.unitType}`);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
// Time period info
|
|
471
|
+
lines.push("");
|
|
472
|
+
const period = data.timePeriod;
|
|
473
|
+
const periodStr = period.month
|
|
474
|
+
? `${period.year}-${String(period.month).padStart(2, "0")}`
|
|
475
|
+
: `${period.year}`;
|
|
476
|
+
lines.push(`Period: ${periodStr}`);
|
|
477
|
+
|
|
478
|
+
return lines.join("\n");
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// ============================================================================
|
|
482
|
+
// Export Interface
|
|
483
|
+
// ============================================================================
|
|
484
|
+
|
|
485
|
+
export type { CopilotAuthData };
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* Query GitHub Copilot account quota
|
|
489
|
+
* @param authData GitHub Copilot authentication data (optional if using PAT config)
|
|
490
|
+
* @returns Query result, null if no account configured
|
|
491
|
+
*/
|
|
492
|
+
export async function queryCopilotUsage(
|
|
493
|
+
authData: CopilotAuthData | undefined,
|
|
494
|
+
): Promise<QueryResult | null> {
|
|
495
|
+
// Strategy 1: Try public billing API with user's fine-grained PAT
|
|
496
|
+
const quotaConfig = readQuotaConfig();
|
|
497
|
+
if (quotaConfig) {
|
|
498
|
+
try {
|
|
499
|
+
const billingUsage = await fetchPublicBillingUsage(quotaConfig);
|
|
500
|
+
return {
|
|
501
|
+
success: true,
|
|
502
|
+
output: formatPublicBillingUsage(billingUsage, quotaConfig.tier),
|
|
503
|
+
};
|
|
504
|
+
} catch (err) {
|
|
505
|
+
// PAT config exists but failed - report the error
|
|
506
|
+
return {
|
|
507
|
+
success: false,
|
|
508
|
+
error: err instanceof Error ? err.message : String(err),
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
// Strategy 2: Try internal API with OAuth token (legacy, may not work with new OpenCode auth)
|
|
514
|
+
// Check if account exists and has a refresh token (the GitHub OAuth token)
|
|
515
|
+
if (!authData || authData.type !== "oauth" || !authData.refresh) {
|
|
516
|
+
// No auth data and no PAT config - show setup instructions
|
|
517
|
+
return {
|
|
518
|
+
success: false,
|
|
519
|
+
error: `${COPILOT_QUOTA_UNAVAILABLE}\n\n${COPILOT_QUOTA_WORKAROUND}`,
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
try {
|
|
524
|
+
const usage = await fetchCopilotUsage(authData);
|
|
525
|
+
return {
|
|
526
|
+
success: true,
|
|
527
|
+
output: formatCopilotUsage(usage),
|
|
528
|
+
};
|
|
529
|
+
} catch (err) {
|
|
530
|
+
return {
|
|
531
|
+
success: false,
|
|
532
|
+
error: err instanceof Error ? err.message : String(err),
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
}
|