@ashx-j/lunr 0.2.11 → 0.2.13
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 +13 -0
- package/README.md +211 -236
- package/dist/builtin-extensions/ashxj-tui.d.ts +3 -0
- package/dist/builtin-extensions/ashxj-tui.d.ts.map +1 -1
- package/dist/builtin-extensions/ashxj-tui.js +28 -11
- package/dist/builtin-extensions/ashxj-tui.js.map +1 -1
- package/dist/builtin-extensions/index.d.ts.map +1 -1
- package/dist/builtin-extensions/index.js +0 -2
- package/dist/builtin-extensions/index.js.map +1 -1
- package/dist/builtin-extensions/lunr-cron.d.ts +1 -1
- package/dist/builtin-extensions/lunr-cron.d.ts.map +1 -1
- package/dist/builtin-extensions/lunr-cron.js +1 -1
- package/dist/builtin-extensions/lunr-cron.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/chain-validation.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/chain-validation.js +3 -3
- package/dist/builtin-extensions/pi-subagents/src/extension/chain-validation.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/doctor.d.ts +0 -2
- package/dist/builtin-extensions/pi-subagents/src/extension/doctor.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/doctor.js +1 -23
- package/dist/builtin-extensions/pi-subagents/src/extension/doctor.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/fanout-child.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/fanout-child.js +6 -7
- package/dist/builtin-extensions/pi-subagents/src/extension/fanout-child.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/index.d.ts +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/index.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/index.js +7 -14
- package/dist/builtin-extensions/pi-subagents/src/extension/index.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/schemas.d.ts +12 -9
- package/dist/builtin-extensions/pi-subagents/src/extension/schemas.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/schemas.js +38 -34
- package/dist/builtin-extensions/pi-subagents/src/extension/schemas.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.d.ts +3 -3
- package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.js +32 -47
- package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/intercom/intercom-bridge.d.ts +2 -2
- package/dist/builtin-extensions/pi-subagents/src/intercom/intercom-bridge.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/intercom/intercom-bridge.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.d.ts +7 -10
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.js +90 -109
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-resume.d.ts +3 -2
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-resume.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-resume.js +37 -50
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-resume.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/run-status.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/run-status.js +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/run-status.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/scheduled-runs.d.ts +4 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/background/scheduled-runs.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/scheduled-runs.js +5 -5
- package/dist/builtin-extensions/pi-subagents/src/runs/background/scheduled-runs.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-runner.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-runner.js +31 -13
- package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-runner.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-clarify.d.ts +2 -2
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-clarify.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-clarify.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.d.ts +4 -3
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.js +48 -20
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.d.ts +2 -2
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.js +90 -64
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.d.ts +6 -8
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.js +262 -161
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/acceptance.d.ts +2 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/acceptance.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/acceptance.js +24 -33
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/acceptance.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/child-tools.d.ts +25 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/child-tools.d.ts.map +1 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/child-tools.js +51 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/child-tools.js.map +1 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/dynamic-fanout.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/dynamic-fanout.js +20 -3
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/dynamic-fanout.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.d.ts +4 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/pi-args.d.ts +5 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/pi-args.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/pi-args.js +9 -3
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/pi-args.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.js +2 -2
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/task-intent.d.ts +2 -2
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/task-intent.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/task-intent.js +20 -17
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/task-intent.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.d.ts +70 -0
- package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.d.ts.map +1 -0
- package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.js +153 -0
- package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.js.map +1 -0
- package/dist/builtin-extensions/pi-subagents/src/shared/settings.d.ts +13 -8
- package/dist/builtin-extensions/pi-subagents/src/shared/settings.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/settings.js +20 -51
- package/dist/builtin-extensions/pi-subagents/src/shared/settings.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/types.d.ts +80 -20
- package/dist/builtin-extensions/pi-subagents/src/shared/types.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/types.js +10 -2
- package/dist/builtin-extensions/pi-subagents/src/shared/types.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/slash/prompt-workflows.d.ts +2 -2
- package/dist/builtin-extensions/pi-subagents/src/slash/prompt-workflows.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/slash/prompt-workflows.js +20 -32
- package/dist/builtin-extensions/pi-subagents/src/slash/prompt-workflows.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.d.ts +2 -1
- package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.js +23 -449
- package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts +2 -1
- package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/tui/render.js +13 -11
- package/dist/builtin-extensions/pi-subagents/src/tui/render.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/watchdog/runtime.d.ts +2 -1
- package/dist/builtin-extensions/pi-subagents/src/watchdog/runtime.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/watchdog/runtime.js +18 -17
- package/dist/builtin-extensions/pi-subagents/src/watchdog/runtime.js.map +1 -1
- package/dist/builtin-extensions/simple-pi-memory.d.ts +2 -2
- package/dist/builtin-extensions/simple-pi-memory.d.ts.map +1 -1
- package/dist/builtin-extensions/simple-pi-memory.js +41 -17
- package/dist/builtin-extensions/simple-pi-memory.js.map +1 -1
- package/dist/catalog/models.json +1 -1
- package/dist/catalog/providers/amazon-bedrock.json +1 -1
- package/dist/catalog/providers/azure-openai-responses.json +1 -1
- package/dist/catalog/providers/cloudflare-ai-gateway.json +1 -1
- package/dist/catalog/providers/cloudflare-workers-ai.json +1 -1
- package/dist/catalog/providers/fireworks.json +1 -1
- package/dist/catalog/providers/github-copilot.json +1 -1
- package/dist/catalog/providers/huggingface.json +1 -1
- package/dist/catalog/providers/minimax-cn.json +1 -1
- package/dist/catalog/providers/minimax.json +1 -1
- package/dist/catalog/providers/mistral.json +1 -1
- package/dist/catalog/providers/nvidia.json +1 -1
- package/dist/catalog/providers/openai.json +1 -1
- package/dist/catalog/providers/opencode-go.json +1 -1
- package/dist/catalog/providers/opencode.json +1 -1
- package/dist/catalog/providers/openrouter.json +1 -1
- package/dist/catalog/providers/qwen-cloud-cn.json +1 -1
- package/dist/catalog/providers/qwen-cloud.json +1 -1
- package/dist/catalog/providers/qwen-token-plan-cn.json +1 -1
- package/dist/catalog/providers/qwen-token-plan.json +1 -1
- package/dist/catalog/providers/together.json +1 -1
- package/dist/catalog/providers/vercel-ai-gateway.json +1 -1
- package/dist/catalog/providers/zai-coding-cn.json +1 -1
- package/dist/catalog/providers/zai.json +1 -1
- package/dist/catalog/publication.json +3 -3
- package/dist/core/agent-session.d.ts +7 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +34 -4
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/context-breakdown.d.ts +3 -1
- package/dist/core/context-breakdown.d.ts.map +1 -1
- package/dist/core/context-breakdown.js +5 -2
- package/dist/core/context-breakdown.js.map +1 -1
- package/dist/core/customize.d.ts +2 -0
- package/dist/core/customize.d.ts.map +1 -1
- package/dist/core/customize.js +6 -0
- package/dist/core/customize.js.map +1 -1
- package/dist/core/memory-cap.d.ts +4 -8
- package/dist/core/memory-cap.d.ts.map +1 -1
- package/dist/core/memory-cap.js +8 -8
- package/dist/core/memory-cap.js.map +1 -1
- package/dist/core/permissions.d.ts +2 -0
- package/dist/core/permissions.d.ts.map +1 -1
- package/dist/core/permissions.js +30 -14
- package/dist/core/permissions.js.map +1 -1
- package/dist/core/plan-mode.d.ts.map +1 -1
- package/dist/core/plan-mode.js +1 -9
- package/dist/core/plan-mode.js.map +1 -1
- package/dist/core/rollback.d.ts.map +1 -1
- package/dist/core/rollback.js +1 -1
- package/dist/core/rollback.js.map +1 -1
- package/dist/core/settings-manager.d.ts +16 -5
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +37 -10
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +1 -5
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/subagent-permission-inherit.d.ts +34 -22
- package/dist/core/subagent-permission-inherit.d.ts.map +1 -1
- package/dist/core/subagent-permission-inherit.js +37 -80
- package/dist/core/subagent-permission-inherit.js.map +1 -1
- package/dist/core/swarm.d.ts.map +1 -1
- package/dist/core/swarm.js +13 -7
- package/dist/core/swarm.js.map +1 -1
- package/dist/core/system-prompt.d.ts +6 -4
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +38 -48
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/usage-adapters/openai-codex.d.ts +1 -1
- package/dist/core/usage-adapters/openai-codex.d.ts.map +1 -1
- package/dist/core/usage-adapters/openai-codex.js +22 -17
- package/dist/core/usage-adapters/openai-codex.js.map +1 -1
- package/dist/core/usage-service.d.ts +10 -1
- package/dist/core/usage-service.d.ts.map +1 -1
- package/dist/core/usage-service.js +17 -6
- package/dist/core/usage-service.js.map +1 -1
- package/dist/gateway/agent-bridge.d.ts.map +1 -1
- package/dist/gateway/agent-bridge.js +1 -4
- package/dist/gateway/agent-bridge.js.map +1 -1
- package/dist/gateway/cron.d.ts.map +1 -1
- package/dist/gateway/cron.js +1 -4
- package/dist/gateway/cron.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +0 -5
- package/dist/main.js.map +1 -1
- package/dist/migrations.d.ts +2 -0
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +21 -0
- package/dist/migrations.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +7 -4
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +122 -162
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/usage-view.d.ts +1 -1
- package/dist/modes/interactive/components/usage-view.d.ts.map +1 -1
- package/dist/modes/interactive/components/usage-view.js +7 -4
- package/dist/modes/interactive/components/usage-view.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +1 -2
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +55 -96
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/skill-tag-autocomplete.d.ts +13 -0
- package/dist/modes/interactive/skill-tag-autocomplete.d.ts.map +1 -0
- package/dist/modes/interactive/skill-tag-autocomplete.js +72 -0
- package/dist/modes/interactive/skill-tag-autocomplete.js.map +1 -0
- package/docs/compaction.md +23 -23
- package/docs/containerization.md +24 -24
- package/docs/custom-provider.md +18 -18
- package/docs/development.md +16 -15
- package/docs/docs.json +6 -2
- package/docs/extensions.md +82 -80
- package/docs/features.md +102 -0
- package/docs/index.md +25 -19
- package/docs/json.md +7 -7
- package/docs/keybindings.md +4 -4
- package/docs/models.md +2 -2
- package/docs/packages.md +38 -42
- package/docs/prompt-templates.md +4 -4
- package/docs/providers.md +22 -10
- package/docs/quickstart.md +81 -46
- package/docs/rpc.md +7 -13
- package/docs/sdk.md +43 -41
- package/docs/security.md +18 -18
- package/docs/session-format.md +9 -9
- package/docs/sessions.md +13 -12
- package/docs/settings.md +63 -24
- package/docs/shell-aliases.md +2 -2
- package/docs/skills.md +21 -11
- package/docs/terminal-setup.md +5 -5
- package/docs/termux.md +7 -7
- package/docs/themes.md +12 -14
- package/docs/tmux.md +4 -4
- package/docs/tui.md +23 -23
- package/docs/usage.md +112 -87
- package/docs/windows.md +10 -2
- package/examples/README.md +3 -1
- package/examples/extensions/README.md +6 -6
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/doom-overlay/README.md +2 -2
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/plan-mode/README.md +3 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/subagent/README.md +13 -11
- package/examples/extensions/todo.ts +2 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/examples/sdk/README.md +9 -5
- package/package.json +6 -7
- package/dist/builtin-extensions/lunr-behavior.d.ts +0 -44
- package/dist/builtin-extensions/lunr-behavior.d.ts.map +0 -1
- package/dist/builtin-extensions/lunr-behavior.js +0 -213
- package/dist/builtin-extensions/lunr-behavior.js.map +0 -1
- package/dist/builtin-extensions/pi-subagents/agents/context-builder.md +0 -46
- package/dist/builtin-extensions/pi-subagents/agents/deep-researcher.md +0 -36
- package/dist/builtin-extensions/pi-subagents/agents/delegate.md +0 -12
- package/dist/builtin-extensions/pi-subagents/agents/oracle.md +0 -73
- package/dist/builtin-extensions/pi-subagents/agents/planner.md +0 -55
- package/dist/builtin-extensions/pi-subagents/agents/research-writer.md +0 -37
- package/dist/builtin-extensions/pi-subagents/agents/researcher.md +0 -52
- package/dist/builtin-extensions/pi-subagents/agents/reviewer.md +0 -79
- package/dist/builtin-extensions/pi-subagents/agents/scout.md +0 -50
- package/dist/builtin-extensions/pi-subagents/agents/worker.md +0 -55
- package/dist/builtin-extensions/pi-subagents/src/agents/agent-management.d.ts +0 -20
- package/dist/builtin-extensions/pi-subagents/src/agents/agent-management.d.ts.map +0 -1
- package/dist/builtin-extensions/pi-subagents/src/agents/agent-management.js +0 -1273
- package/dist/builtin-extensions/pi-subagents/src/agents/agent-management.js.map +0 -1
- package/dist/builtin-extensions/pi-subagents/src/agents/agent-memory.d.ts +0 -49
- package/dist/builtin-extensions/pi-subagents/src/agents/agent-memory.d.ts.map +0 -1
- package/dist/builtin-extensions/pi-subagents/src/agents/agent-memory.js +0 -252
- package/dist/builtin-extensions/pi-subagents/src/agents/agent-memory.js.map +0 -1
- package/dist/builtin-extensions/pi-subagents/src/agents/agent-scope.d.ts +0 -3
- package/dist/builtin-extensions/pi-subagents/src/agents/agent-scope.d.ts.map +0 -1
- package/dist/builtin-extensions/pi-subagents/src/agents/agent-scope.js +0 -6
- package/dist/builtin-extensions/pi-subagents/src/agents/agent-scope.js.map +0 -1
- package/dist/builtin-extensions/pi-subagents/src/agents/agent-selection.d.ts +0 -3
- package/dist/builtin-extensions/pi-subagents/src/agents/agent-selection.d.ts.map +0 -1
- package/dist/builtin-extensions/pi-subagents/src/agents/agent-selection.js +0 -23
- package/dist/builtin-extensions/pi-subagents/src/agents/agent-selection.js.map +0 -1
- package/dist/builtin-extensions/pi-subagents/src/agents/agent-serializer.d.ts +0 -8
- package/dist/builtin-extensions/pi-subagents/src/agents/agent-serializer.d.ts.map +0 -1
- package/dist/builtin-extensions/pi-subagents/src/agents/agent-serializer.js +0 -143
- package/dist/builtin-extensions/pi-subagents/src/agents/agent-serializer.js.map +0 -1
- package/dist/builtin-extensions/pi-subagents/src/agents/agents.d.ts +0 -176
- package/dist/builtin-extensions/pi-subagents/src/agents/agents.d.ts.map +0 -1
- package/dist/builtin-extensions/pi-subagents/src/agents/agents.js +0 -1326
- package/dist/builtin-extensions/pi-subagents/src/agents/agents.js.map +0 -1
- package/dist/builtin-extensions/pi-subagents/src/agents/chain-serializer.d.ts +0 -7
- package/dist/builtin-extensions/pi-subagents/src/agents/chain-serializer.d.ts.map +0 -1
- package/dist/builtin-extensions/pi-subagents/src/agents/chain-serializer.js +0 -307
- package/dist/builtin-extensions/pi-subagents/src/agents/chain-serializer.js.map +0 -1
- package/dist/builtin-extensions/pi-subagents/src/agents/identity.d.ts +0 -8
- package/dist/builtin-extensions/pi-subagents/src/agents/identity.d.ts.map +0 -1
- package/dist/builtin-extensions/pi-subagents/src/agents/identity.js +0 -30
- package/dist/builtin-extensions/pi-subagents/src/agents/identity.js.map +0 -1
- package/dist/builtin-extensions/pi-subagents/src/agents/proactive-skills.d.ts +0 -35
- package/dist/builtin-extensions/pi-subagents/src/agents/proactive-skills.d.ts.map +0 -1
- package/dist/builtin-extensions/pi-subagents/src/agents/proactive-skills.js +0 -151
- package/dist/builtin-extensions/pi-subagents/src/agents/proactive-skills.js.map +0 -1
- package/dist/builtin-extensions/pi-subagents/src/profiles/profiles.d.ts +0 -131
- package/dist/builtin-extensions/pi-subagents/src/profiles/profiles.d.ts.map +0 -1
- package/dist/builtin-extensions/pi-subagents/src/profiles/profiles.js +0 -491
- package/dist/builtin-extensions/pi-subagents/src/profiles/profiles.js.map +0 -1
- package/dist/core/behavior-preset.d.ts +0 -60
- package/dist/core/behavior-preset.d.ts.map +0 -1
- package/dist/core/behavior-preset.js +0 -257
- package/dist/core/behavior-preset.js.map +0 -1
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { getDocsPath, getExamplesPath, getReadmePath } from "../config.js";
|
|
5
5
|
import { formatSkillsForPrompt } from "./skills.js";
|
|
6
|
-
/** Build the system prompt
|
|
6
|
+
/** Build the base system prompt and append configured context. */
|
|
7
7
|
export function buildSystemPrompt(options) {
|
|
8
|
-
const { customPrompt,
|
|
8
|
+
const { customPrompt, modelSlug, selectedTools, appendSystemPrompt, cwd, contextFiles: providedContextFiles, skills: providedSkills, } = options;
|
|
9
9
|
const promptCwd = cwd.replace(/\\/g, "/");
|
|
10
10
|
const appendSection = appendSystemPrompt ? `\n\n${appendSystemPrompt}` : "";
|
|
11
11
|
const contextFiles = providedContextFiles ?? [];
|
|
@@ -36,55 +36,46 @@ export function buildSystemPrompt(options) {
|
|
|
36
36
|
const readmePath = getReadmePath();
|
|
37
37
|
const docsPath = getDocsPath();
|
|
38
38
|
const examplesPath = getExamplesPath();
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
const hasBash = tools.includes("bash");
|
|
55
|
-
const hasGrep = tools.includes("grep");
|
|
56
|
-
const hasFind = tools.includes("find");
|
|
57
|
-
const hasLs = tools.includes("ls");
|
|
58
|
-
const hasRead = tools.includes("read");
|
|
59
|
-
// File exploration guidelines
|
|
60
|
-
if (hasBash && !hasGrep && !hasFind && !hasLs) {
|
|
61
|
-
addGuideline("Use bash for file operations like ls, rg, find");
|
|
62
|
-
}
|
|
63
|
-
for (const guideline of promptGuidelines ?? []) {
|
|
64
|
-
const normalized = guideline.trim();
|
|
65
|
-
if (normalized.length > 0) {
|
|
66
|
-
addGuideline(normalized);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
const guidelines = guidelinesList.map((g) => `- ${g}`).join("\n");
|
|
70
|
-
const guidelinesSection = guidelines ? `Guidelines:\n${guidelines}\n\n` : "";
|
|
71
|
-
let prompt = `You are an expert coding assistant operating inside pi, a coding agent harness. You help users by reading files, executing commands, editing code, and writing new files.
|
|
39
|
+
const currentModel = modelSlug?.trim() || "no model selected";
|
|
40
|
+
const hasRead = !selectedTools || selectedTools.includes("read");
|
|
41
|
+
let prompt = `You are an expert coding assistant currently running ''${currentModel}'', operating inside lunR, a coding agent harness. You help users by reading files, executing commands, editing code, and writing new files.
|
|
42
|
+
Current working directory: ''${promptCwd}''
|
|
43
|
+
|
|
44
|
+
Behavior guidelines:
|
|
45
|
+
- Default to writing no comments. Only add one if the why is non-obvious: a hidden constraint, a subtle invariant, a workaround for a specific bug, something that would surprise the reader. If removing the comment wouldn't confuse a future reader, don't write it.
|
|
46
|
+
- Keep comments up to date! When making changes, it's important to keep things in sync. An outdated comment is worse than no comment at all.
|
|
47
|
+
- Carefully consider the reversibility and blast radius of actions. Generally you can freely take local, reversible actions like editing files or running tests. But for actions that are hard to reverse, affect shared systems beyond your local environment, or could otherwise be risky or destructive, check with the user before proceeding.
|
|
48
|
+
- Orchestrate subagents with intent! Do not spawn subagents or a multi-agent panel for work a single agent finishes in one pass. Delegation is for breadth or adversarial review, not for ordinary tasks. Use subagents as a tool when there is genuine benefit to it or the user explicitly asks for it.
|
|
49
|
+
- When several agents work in parallel, state file ownership up front so they do not collide.
|
|
50
|
+
- Tests are good! Endless smoke tests, regressions tests for feature deletions, etc, much less good. Tests should be focused, not slop.
|
|
51
|
+
- Prefer editing existing files to creating new ones.
|
|
52
|
+
- Only use emojis if the user explicitly requests it.
|
|
53
|
+
- Never exfil private data on public platforms like github or any other services under any circumstances.
|
|
72
54
|
|
|
73
|
-
Available tools:
|
|
74
|
-
${toolsList}
|
|
75
55
|
|
|
76
|
-
|
|
56
|
+
Guidelines:
|
|
57
|
+
- Use bash for file operations like ls, rg, find
|
|
58
|
+
- Use read to examine files instead of cat or sed.
|
|
59
|
+
- Use edit for precise changes (edits[].oldText must match exactly)
|
|
60
|
+
- When changing multiple separate locations in one file, use one edit call with multiple entries in edits[] instead of multiple edit calls
|
|
61
|
+
- Each edits[].oldText is matched against the original file, not after earlier edits are applied. Do not emit overlapping or nested edits. Merge nearby changes into one edit.
|
|
62
|
+
- Keep edits[].oldText as small as possible while still being unique in the file. Do not pad with large unchanged regions.
|
|
63
|
+
- Use write only for new files or complete rewrites.
|
|
64
|
+
- Use todo for meaningful multi-step work. Every update must send the complete list, with exactly one item in progress at a time.
|
|
65
|
+
- Use subagents for independent parallel work, specialist analysis, or substantial research. Subagents start with fresh sessions. Use intercom instead to coordinate with an existing lunR session.
|
|
66
|
+
- Use ast_search for structural code matches.
|
|
67
|
+
- Use cron only when the user asks to schedule or manage unattended prompts.
|
|
68
|
+
- Memory stores established, durable facts and stable preferences. Do not store behavior instructions, transient task details, transcripts, guesses, or secrets. Change memory only with the memory tools.
|
|
69
|
+
- ~/.lunr/agent/AGENTS.md contains optional global instructions written by the user. Never modify it, including through shell commands.
|
|
70
|
+
- Use web search when information is current, uncertain, externally referenced, or research-heavy, and cite the sources used.
|
|
71
|
+
- Use MCP only for capabilities exposed by configured MCP servers. Call native lunR tools directly.
|
|
77
72
|
|
|
78
|
-
${guidelinesSection}Plan mode: the user toggles it with /plan. While active, investigate read-only and present a concrete plan before any file changes.
|
|
79
73
|
|
|
80
|
-
|
|
81
|
-
-
|
|
82
|
-
-
|
|
83
|
-
- Examples: ${examplesPath}
|
|
84
|
-
-
|
|
85
|
-
- When asked about: extensions (docs/extensions.md, examples/extensions/), themes (docs/themes.md), skills (docs/skills.md), prompt templates (docs/prompt-templates.md), TUI components (docs/tui.md), keybindings (docs/keybindings.md), SDK integrations (docs/sdk.md), custom providers (docs/custom-provider.md), adding models (docs/models.md), pi packages (docs/packages.md)
|
|
86
|
-
- When working on pi topics, read the docs and examples, and follow .md cross-references before implementing
|
|
87
|
-
- Always read pi .md files completely and follow links to related docs (e.g., tui.md for TUI API details)`;
|
|
74
|
+
lunR documentation (read only when the user asks about lunR itself, or the task concerns lunR itself, its SDK, extensions, themes, skills, or TUI):
|
|
75
|
+
- README: ${readmePath}
|
|
76
|
+
- Documentation: ${docsPath}
|
|
77
|
+
- Examples: ${examplesPath}
|
|
78
|
+
- Always read lunR .md files completely and follow links to related docs (e.g., tui.md for TUI API details)`;
|
|
88
79
|
if (appendSection) {
|
|
89
80
|
prompt += appendSection;
|
|
90
81
|
}
|
|
@@ -101,7 +92,6 @@ Pi documentation (read only when the user asks about pi itself, its SDK, extensi
|
|
|
101
92
|
if (hasRead && skills.length > 0) {
|
|
102
93
|
prompt += formatSkillsForPrompt(skills);
|
|
103
94
|
}
|
|
104
|
-
prompt += `\nCurrent working directory: ${promptCwd}`;
|
|
105
95
|
return prompt;
|
|
106
96
|
}
|
|
107
97
|
//# sourceMappingURL=system-prompt.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"system-prompt.js","sourceRoot":"","sources":["../../src/core/system-prompt.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC3E,OAAO,EAAE,qBAAqB,EAAc,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"system-prompt.js","sourceRoot":"","sources":["../../src/core/system-prompt.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * System prompt construction and project context loading\n */\n\nimport { getDocsPath, getExamplesPath, getReadmePath } from \"../config.ts\";\nimport { formatSkillsForPrompt, type Skill } from \"./skills.ts\";\n\nexport interface BuildSystemPromptOptions {\n\t/** Custom system prompt (replaces default). */\n\tcustomPrompt?: string;\n\t/** Current model in provider/id form. */\n\tmodelSlug?: string;\n\t/** Active tools; used to decide whether read-dependent skill metadata is visible. */\n\tselectedTools?: string[];\n\t/** Legacy extension metadata retained for API compatibility; tool definitions are sent separately. */\n\ttoolSnippets?: Record<string, string>;\n\t/** Legacy extension metadata retained for API compatibility; not appended to the default prompt. */\n\tpromptGuidelines?: string[];\n\t/** Text to append to system prompt. */\n\tappendSystemPrompt?: string;\n\t/** Working directory. */\n\tcwd: string;\n\t/** Pre-loaded context files. */\n\tcontextFiles?: Array<{ path: string; content: string }>;\n\t/** Pre-loaded skills. */\n\tskills?: Skill[];\n}\n\n/** Build the base system prompt and append configured context. */\nexport function buildSystemPrompt(options: BuildSystemPromptOptions): string {\n\tconst {\n\t\tcustomPrompt,\n\t\tmodelSlug,\n\t\tselectedTools,\n\t\tappendSystemPrompt,\n\t\tcwd,\n\t\tcontextFiles: providedContextFiles,\n\t\tskills: providedSkills,\n\t} = options;\n\tconst promptCwd = cwd.replace(/\\\\/g, \"/\");\n\n\tconst appendSection = appendSystemPrompt ? `\\n\\n${appendSystemPrompt}` : \"\";\n\n\tconst contextFiles = providedContextFiles ?? [];\n\tconst skills = providedSkills ?? [];\n\n\tif (customPrompt) {\n\t\tlet prompt = customPrompt;\n\n\t\tif (appendSection) {\n\t\t\tprompt += appendSection;\n\t\t}\n\n\t\t// Append project context files\n\t\tif (contextFiles.length > 0) {\n\t\t\tprompt += \"\\n\\n<project_context>\\n\\n\";\n\t\t\tprompt += \"Project-specific instructions and guidelines:\\n\\n\";\n\t\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\t\tprompt += `<project_instructions path=\"${filePath}\">\\n${content}\\n</project_instructions>\\n\\n`;\n\t\t\t}\n\t\t\tprompt += \"</project_context>\\n\";\n\t\t}\n\n\t\t// Append skills section (only if read tool is available)\n\t\tconst customPromptHasRead = !selectedTools || selectedTools.includes(\"read\");\n\t\tif (customPromptHasRead && skills.length > 0) {\n\t\t\tprompt += formatSkillsForPrompt(skills);\n\t\t}\n\n\t\tprompt += `\\nCurrent working directory: ${promptCwd}`;\n\n\t\treturn prompt;\n\t}\n\n\t// Get absolute paths to documentation and examples\n\tconst readmePath = getReadmePath();\n\tconst docsPath = getDocsPath();\n\tconst examplesPath = getExamplesPath();\n\n\tconst currentModel = modelSlug?.trim() || \"no model selected\";\n\tconst hasRead = !selectedTools || selectedTools.includes(\"read\");\n\n\tlet prompt = `You are an expert coding assistant currently running ''${currentModel}'', operating inside lunR, a coding agent harness. You help users by reading files, executing commands, editing code, and writing new files.\nCurrent working directory: ''${promptCwd}''\n\nBehavior guidelines:\n- Default to writing no comments. Only add one if the why is non-obvious: a hidden constraint, a subtle invariant, a workaround for a specific bug, something that would surprise the reader. If removing the comment wouldn't confuse a future reader, don't write it.\n- Keep comments up to date! When making changes, it's important to keep things in sync. An outdated comment is worse than no comment at all.\n- Carefully consider the reversibility and blast radius of actions. Generally you can freely take local, reversible actions like editing files or running tests. But for actions that are hard to reverse, affect shared systems beyond your local environment, or could otherwise be risky or destructive, check with the user before proceeding.\n- Orchestrate subagents with intent! Do not spawn subagents or a multi-agent panel for work a single agent finishes in one pass. Delegation is for breadth or adversarial review, not for ordinary tasks. Use subagents as a tool when there is genuine benefit to it or the user explicitly asks for it.\n- When several agents work in parallel, state file ownership up front so they do not collide.\n- Tests are good! Endless smoke tests, regressions tests for feature deletions, etc, much less good. Tests should be focused, not slop.\n- Prefer editing existing files to creating new ones.\n- Only use emojis if the user explicitly requests it.\n- Never exfil private data on public platforms like github or any other services under any circumstances.\n\n\nGuidelines:\n- Use bash for file operations like ls, rg, find\n- Use read to examine files instead of cat or sed.\n- Use edit for precise changes (edits[].oldText must match exactly)\n- When changing multiple separate locations in one file, use one edit call with multiple entries in edits[] instead of multiple edit calls\n- Each edits[].oldText is matched against the original file, not after earlier edits are applied. Do not emit overlapping or nested edits. Merge nearby changes into one edit.\n- Keep edits[].oldText as small as possible while still being unique in the file. Do not pad with large unchanged regions.\n- Use write only for new files or complete rewrites.\n- Use todo for meaningful multi-step work. Every update must send the complete list, with exactly one item in progress at a time.\n- Use subagents for independent parallel work, specialist analysis, or substantial research. Subagents start with fresh sessions. Use intercom instead to coordinate with an existing lunR session.\n- Use ast_search for structural code matches.\n- Use cron only when the user asks to schedule or manage unattended prompts.\n- Memory stores established, durable facts and stable preferences. Do not store behavior instructions, transient task details, transcripts, guesses, or secrets. Change memory only with the memory tools.\n- ~/.lunr/agent/AGENTS.md contains optional global instructions written by the user. Never modify it, including through shell commands.\n- Use web search when information is current, uncertain, externally referenced, or research-heavy, and cite the sources used.\n- Use MCP only for capabilities exposed by configured MCP servers. Call native lunR tools directly.\n\n\nlunR documentation (read only when the user asks about lunR itself, or the task concerns lunR itself, its SDK, extensions, themes, skills, or TUI):\n- README: ${readmePath}\n- Documentation: ${docsPath}\n- Examples: ${examplesPath}\n- Always read lunR .md files completely and follow links to related docs (e.g., tui.md for TUI API details)`;\n\n\tif (appendSection) {\n\t\tprompt += appendSection;\n\t}\n\n\t// Append project context files\n\tif (contextFiles.length > 0) {\n\t\tprompt += \"\\n\\n<project_context>\\n\\n\";\n\t\tprompt += \"Project-specific instructions and guidelines:\\n\\n\";\n\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\tprompt += `<project_instructions path=\"${filePath}\">\\n${content}\\n</project_instructions>\\n\\n`;\n\t\t}\n\t\tprompt += \"</project_context>\\n\";\n\t}\n\n\t// Append skills section (only if read tool is available)\n\tif (hasRead && skills.length > 0) {\n\t\tprompt += formatSkillsForPrompt(skills);\n\t}\n\n\treturn prompt;\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { ModelRuntime } from "../model-runtime.ts";
|
|
2
2
|
import type { PlanUsage } from "../usage-service.ts";
|
|
3
|
-
export declare function fetchCodexPlanUsage(runtime: ModelRuntime): Promise<PlanUsage | undefined>;
|
|
3
|
+
export declare function fetchCodexPlanUsage(runtime: ModelRuntime): Promise<PlanUsage[] | undefined>;
|
|
4
4
|
//# sourceMappingURL=openai-codex.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openai-codex.d.ts","sourceRoot":"","sources":["../../../src/core/usage-adapters/openai-codex.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,SAAS,EAAmB,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"openai-codex.d.ts","sourceRoot":"","sources":["../../../src/core/usage-adapters/openai-codex.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,SAAS,EAAmB,MAAM,qBAAqB,CAAC;AA4NtE,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,SAAS,EAAE,GAAG,SAAS,CAAC,CAYjG","sourcesContent":["// Vendored from narumiruna-pi-codex-usage (deleted in Phase 1 of the lunr-ux plan):\n// the pi-auth HTTP query path of `query.ts` plus `normalize.ts` and the backend\n// types from `types.ts`, consolidated into one core module. The codex app-server\n// fallback was dropped; extension-API imports (ExtensionContext, modelRegistry)\n// were rewired to core's ModelRuntime. No runtime dependency on the deleted\n// extension or on extension-repos remains.\n\nimport type { Api, AuthResult, Model } from \"@ashx-j/lunr-ai\";\nimport type { ModelRuntime } from \"../model-runtime.ts\";\nimport type { PlanUsage, PlanUsageWindow } from \"../usage-service.ts\";\nimport { asNumber, asObject, asString, fetchWithTimeout, toEpochMs } from \"./shared.ts\";\n\nconst CODEX_PROVIDER_ID = \"openai-codex\";\nconst CODEX_USAGE_URL = \"https://chatgpt.com/backend-api/wham/usage\";\nconst MAX_ERROR_BODY_CHARS = 600;\n\n// ---------------------------------------------------------------------------\n// Backend payload types (vendored from types.ts)\n// ---------------------------------------------------------------------------\n\ntype RateLimitStatusPayload = {\n\tplan_type?: unknown;\n\trate_limit?: unknown;\n\tadditional_rate_limits?: unknown;\n\tcredits?: unknown;\n\trate_limit_reset_credits?: unknown;\n};\n\ntype BackendRateLimitDetails = {\n\tprimary_window?: unknown;\n\tsecondary_window?: unknown;\n};\n\ntype BackendWindowSnapshot = {\n\tused_percent?: unknown;\n\tlimit_window_seconds?: unknown;\n\treset_at?: unknown;\n};\n\ntype BackendAdditionalRateLimit = {\n\tlimit_name?: unknown;\n\tmetered_feature?: unknown;\n\trate_limit?: unknown;\n};\n\ntype BackendCreditsSnapshot = {\n\thas_credits?: unknown;\n\tunlimited?: unknown;\n\tbalance?: unknown;\n};\n\ntype NormalizedWindow = {\n\tusedPercent: number;\n\twindowMinutes?: number;\n\tresetsAt?: number;\n};\n\ntype NormalizedSnapshot = {\n\tlimitId: string;\n\tlimitName?: string;\n\tprimary?: NormalizedWindow;\n\tsecondary?: NormalizedWindow;\n};\n\ntype CodexUsageReport = {\n\tplanType?: string;\n\tsnapshots: NormalizedSnapshot[];\n};\n\n// ---------------------------------------------------------------------------\n// Payload normalization (vendored from normalize.ts, backend path only)\n// ---------------------------------------------------------------------------\n\nfunction normalizeBackendPayload(payload: RateLimitStatusPayload): CodexUsageReport {\n\tconst snapshots: NormalizedSnapshot[] = [];\n\tconst planType = asString(payload.plan_type);\n\tconst primary = normalizeBackendSnapshot(\"codex\", undefined, payload.rate_limit, payload.credits);\n\tif (primary) snapshots.push(primary);\n\n\tconst additional = Array.isArray(payload.additional_rate_limits) ? payload.additional_rate_limits : [];\n\tfor (const item of additional) {\n\t\tconst additionalLimit = asObject(item) as BackendAdditionalRateLimit | undefined;\n\t\tif (!additionalLimit) continue;\n\t\tconst limitId = asString(additionalLimit.metered_feature) ?? asString(additionalLimit.limit_name);\n\t\tif (!limitId) continue;\n\t\ttry {\n\t\t\tconst snapshot = normalizeBackendSnapshot(\n\t\t\t\tlimitId,\n\t\t\t\tasString(additionalLimit.limit_name),\n\t\t\t\tadditionalLimit.rate_limit,\n\t\t\t\tundefined,\n\t\t\t);\n\t\t\tif (snapshot) snapshots.push(snapshot);\n\t\t} catch {\n\t\t\t// Optional additional buckets must not hide otherwise usable primary usage.\n\t\t}\n\t}\n\n\tif (snapshots.length === 0) {\n\t\tthrow new Error(\"Codex usage endpoint returned no displayable usage data.\");\n\t}\n\treturn { planType, snapshots };\n}\n\nfunction normalizeBackendSnapshot(\n\tlimitId: string,\n\tlimitName: string | undefined,\n\trateLimit: unknown,\n\tcredits: unknown,\n): NormalizedSnapshot | undefined {\n\tif (rateLimit === null || rateLimit === undefined) {\n\t\treturn normalizeBackendCredits(credits) ? { limitId, limitName } : undefined;\n\t}\n\tconst details = asObject(rateLimit) as BackendRateLimitDetails | undefined;\n\tif (!details) throw new Error(\"rate limit was not an object.\");\n\tconst primary = normalizeBackendWindow(details.primary_window);\n\tconst secondary = normalizeBackendWindow(details.secondary_window);\n\tif (!primary && !secondary && !normalizeBackendCredits(credits)) return undefined;\n\treturn { limitId, limitName, primary, secondary };\n}\n\nfunction normalizeBackendWindow(value: unknown): NormalizedWindow | undefined {\n\tif (value === null || value === undefined) return undefined;\n\tconst window = asObject(value) as BackendWindowSnapshot | undefined;\n\tif (!window) throw new Error(\"rate-limit window was not an object.\");\n\tconst usedPercent = asNumber(window.used_percent);\n\tif (usedPercent === undefined) return undefined;\n\tconst limitSeconds = asNumber(window.limit_window_seconds);\n\treturn {\n\t\tusedPercent,\n\t\twindowMinutes: limitSeconds && limitSeconds > 0 ? Math.ceil(limitSeconds / 60) : undefined,\n\t\tresetsAt: toEpochMs(window.reset_at),\n\t};\n}\n\nfunction normalizeBackendCredits(value: unknown): boolean {\n\tconst credits = asObject(value) as BackendCreditsSnapshot | undefined;\n\tif (!credits) return false;\n\treturn credits.has_credits !== undefined && credits.unlimited !== undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Auth resolution via core ModelRuntime (rewired from ctx.modelRegistry)\n// ---------------------------------------------------------------------------\n\nasync function resolveCodexHeaders(runtime: ModelRuntime): Promise<Record<string, string> | undefined> {\n\tconst candidates: Model<Api>[] = [];\n\tconst seen = new Set<string>();\n\tconst add = (model: Model<Api> | undefined) => {\n\t\tif (!model || model.provider !== CODEX_PROVIDER_ID) return;\n\t\tconst key = `${model.provider}/${model.id}`;\n\t\tif (seen.has(key)) return;\n\t\tseen.add(key);\n\t\tcandidates.push(model);\n\t};\n\tfor (const model of runtime.getAvailableSnapshot()) add(model);\n\tfor (const model of runtime.getModels()) add(model);\n\n\tfor (const model of candidates) {\n\t\tlet resolution: AuthResult | undefined;\n\t\ttry {\n\t\t\tresolution = await runtime.getAuth(model);\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\t\tif (!resolution) continue;\n\t\tconst headers: Record<string, string> = {};\n\t\tfor (const [name, value] of Object.entries(resolution.auth.headers ?? {})) {\n\t\t\tif (value !== null && value !== undefined) headers[name] = String(value);\n\t\t}\n\t\tif (!hasHeader(headers, \"Authorization\") && resolution.auth.apiKey) {\n\t\t\theaders.Authorization = `Bearer ${resolution.auth.apiKey}`;\n\t\t}\n\t\tif (!hasHeader(headers, \"User-Agent\")) {\n\t\t\theaders[\"User-Agent\"] = \"lunr-usage-service\";\n\t\t}\n\t\tif (hasHeader(headers, \"Authorization\")) return headers;\n\t}\n\treturn undefined;\n}\n\nfunction hasHeader(headers: Record<string, string>, name: string): boolean {\n\treturn Object.keys(headers).some((key) => key.toLowerCase() === name.toLowerCase());\n}\n\nfunction redactErrorBody(body: string): string {\n\tconst redacted = body\n\t\t.replace(/Bearer\\s+[A-Za-z0-9._~+/=-]+/gi, \"Bearer <redacted>\")\n\t\t.replace(/\"access_token\"\\s*:\\s*\"[^\"]+\"/gi, '\"access_token\":\"<redacted>\"')\n\t\t.trim();\n\treturn redacted.length > MAX_ERROR_BODY_CHARS ? `${redacted.slice(0, MAX_ERROR_BODY_CHARS - 1)}…` : redacted;\n}\n\n// ---------------------------------------------------------------------------\n// PlanUsage mapping\n// ---------------------------------------------------------------------------\n\nfunction windowLabel(window: NormalizedWindow, fallback: string | undefined): string {\n\tconst minutes = window.windowMinutes;\n\tif (minutes === undefined) return fallback ?? \"Limit\";\n\tif (minutes >= 7 * 24 * 60) return \"Weekly\";\n\tif (minutes >= 24 * 60) return `${Math.round(minutes / (24 * 60))}d`;\n\tif (minutes >= 60) return `${Math.round(minutes / 60)}h`;\n\treturn `${minutes}m`;\n}\n\nfunction toPlanUsage(report: CodexUsageReport): PlanUsage[] {\n\treturn report.snapshots.flatMap((snapshot, index) => {\n\t\t// Longer window (weekly) first, shorter (5h) second — matches /usage layout.\n\t\tconst windows: PlanUsageWindow[] = [];\n\t\tfor (const window of [snapshot.secondary, snapshot.primary]) {\n\t\t\tif (!window) continue;\n\t\t\twindows.push({\n\t\t\t\tlabel: windowLabel(window, snapshot.limitName),\n\t\t\t\tusedPercent: window.usedPercent,\n\t\t\t\tresetsAt: window.resetsAt,\n\t\t\t});\n\t\t}\n\t\tif (windows.length === 0) return [];\n\t\treturn [\n\t\t\t{\n\t\t\t\tprovider: CODEX_PROVIDER_ID,\n\t\t\t\tplanLabel: index === 0 ? report.planType : (snapshot.limitName ?? snapshot.limitId),\n\t\t\t\twindows,\n\t\t\t},\n\t\t];\n\t});\n}\n\nexport async function fetchCodexPlanUsage(runtime: ModelRuntime): Promise<PlanUsage[] | undefined> {\n\tconst headers = await resolveCodexHeaders(runtime);\n\tif (!headers) return undefined;\n\n\tconst response = await fetchWithTimeout(CODEX_USAGE_URL, { headers });\n\tconst text = await response.text();\n\tif (!response.ok) {\n\t\tthrow new Error(`Codex usage endpoint returned ${response.status}: ${redactErrorBody(text)}`);\n\t}\n\tconst payload = asObject(JSON.parse(text)) as RateLimitStatusPayload | undefined;\n\tif (!payload) return undefined;\n\treturn toPlanUsage(normalizeBackendPayload(payload));\n}\n"]}
|
|
@@ -145,23 +145,28 @@ function windowLabel(window, fallback) {
|
|
|
145
145
|
return `${minutes}m`;
|
|
146
146
|
}
|
|
147
147
|
function toPlanUsage(report) {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
148
|
+
return report.snapshots.flatMap((snapshot, index) => {
|
|
149
|
+
// Longer window (weekly) first, shorter (5h) second — matches /usage layout.
|
|
150
|
+
const windows = [];
|
|
151
|
+
for (const window of [snapshot.secondary, snapshot.primary]) {
|
|
152
|
+
if (!window)
|
|
153
|
+
continue;
|
|
154
|
+
windows.push({
|
|
155
|
+
label: windowLabel(window, snapshot.limitName),
|
|
156
|
+
usedPercent: window.usedPercent,
|
|
157
|
+
resetsAt: window.resetsAt,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
if (windows.length === 0)
|
|
161
|
+
return [];
|
|
162
|
+
return [
|
|
163
|
+
{
|
|
164
|
+
provider: CODEX_PROVIDER_ID,
|
|
165
|
+
planLabel: index === 0 ? report.planType : (snapshot.limitName ?? snapshot.limitId),
|
|
166
|
+
windows,
|
|
167
|
+
},
|
|
168
|
+
];
|
|
169
|
+
});
|
|
165
170
|
}
|
|
166
171
|
export async function fetchCodexPlanUsage(runtime) {
|
|
167
172
|
const headers = await resolveCodexHeaders(runtime);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openai-codex.js","sourceRoot":"","sources":["../../../src/core/usage-adapters/openai-codex.ts"],"names":[],"mappings":"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","sourcesContent":["// Vendored from narumiruna-pi-codex-usage (deleted in Phase 1 of the lunr-ux plan):\n// the pi-auth HTTP query path of `query.ts` plus `normalize.ts` and the backend\n// types from `types.ts`, consolidated into one core module. The codex app-server\n// fallback was dropped; extension-API imports (ExtensionContext, modelRegistry)\n// were rewired to core's ModelRuntime. No runtime dependency on the deleted\n// extension or on extension-repos remains.\n\nimport type { Api, AuthResult, Model } from \"@ashx-j/lunr-ai\";\nimport type { ModelRuntime } from \"../model-runtime.ts\";\nimport type { PlanUsage, PlanUsageWindow } from \"../usage-service.ts\";\nimport { asNumber, asObject, asString, fetchWithTimeout, toEpochMs } from \"./shared.ts\";\n\nconst CODEX_PROVIDER_ID = \"openai-codex\";\nconst CODEX_USAGE_URL = \"https://chatgpt.com/backend-api/wham/usage\";\nconst MAX_ERROR_BODY_CHARS = 600;\n\n// ---------------------------------------------------------------------------\n// Backend payload types (vendored from types.ts)\n// ---------------------------------------------------------------------------\n\ntype RateLimitStatusPayload = {\n\tplan_type?: unknown;\n\trate_limit?: unknown;\n\tadditional_rate_limits?: unknown;\n\tcredits?: unknown;\n\trate_limit_reset_credits?: unknown;\n};\n\ntype BackendRateLimitDetails = {\n\tprimary_window?: unknown;\n\tsecondary_window?: unknown;\n};\n\ntype BackendWindowSnapshot = {\n\tused_percent?: unknown;\n\tlimit_window_seconds?: unknown;\n\treset_at?: unknown;\n};\n\ntype BackendAdditionalRateLimit = {\n\tlimit_name?: unknown;\n\tmetered_feature?: unknown;\n\trate_limit?: unknown;\n};\n\ntype BackendCreditsSnapshot = {\n\thas_credits?: unknown;\n\tunlimited?: unknown;\n\tbalance?: unknown;\n};\n\ntype NormalizedWindow = {\n\tusedPercent: number;\n\twindowMinutes?: number;\n\tresetsAt?: number;\n};\n\ntype NormalizedSnapshot = {\n\tlimitId: string;\n\tlimitName?: string;\n\tprimary?: NormalizedWindow;\n\tsecondary?: NormalizedWindow;\n};\n\ntype CodexUsageReport = {\n\tplanType?: string;\n\tsnapshots: NormalizedSnapshot[];\n};\n\n// ---------------------------------------------------------------------------\n// Payload normalization (vendored from normalize.ts, backend path only)\n// ---------------------------------------------------------------------------\n\nfunction normalizeBackendPayload(payload: RateLimitStatusPayload): CodexUsageReport {\n\tconst snapshots: NormalizedSnapshot[] = [];\n\tconst planType = asString(payload.plan_type);\n\tconst primary = normalizeBackendSnapshot(\"codex\", undefined, payload.rate_limit, payload.credits);\n\tif (primary) snapshots.push(primary);\n\n\tconst additional = Array.isArray(payload.additional_rate_limits) ? payload.additional_rate_limits : [];\n\tfor (const item of additional) {\n\t\tconst additionalLimit = asObject(item) as BackendAdditionalRateLimit | undefined;\n\t\tif (!additionalLimit) continue;\n\t\tconst limitId = asString(additionalLimit.metered_feature) ?? asString(additionalLimit.limit_name);\n\t\tif (!limitId) continue;\n\t\ttry {\n\t\t\tconst snapshot = normalizeBackendSnapshot(\n\t\t\t\tlimitId,\n\t\t\t\tasString(additionalLimit.limit_name),\n\t\t\t\tadditionalLimit.rate_limit,\n\t\t\t\tundefined,\n\t\t\t);\n\t\t\tif (snapshot) snapshots.push(snapshot);\n\t\t} catch {\n\t\t\t// Optional additional buckets must not hide otherwise usable primary usage.\n\t\t}\n\t}\n\n\tif (snapshots.length === 0) {\n\t\tthrow new Error(\"Codex usage endpoint returned no displayable usage data.\");\n\t}\n\treturn { planType, snapshots };\n}\n\nfunction normalizeBackendSnapshot(\n\tlimitId: string,\n\tlimitName: string | undefined,\n\trateLimit: unknown,\n\tcredits: unknown,\n): NormalizedSnapshot | undefined {\n\tif (rateLimit === null || rateLimit === undefined) {\n\t\treturn normalizeBackendCredits(credits) ? { limitId, limitName } : undefined;\n\t}\n\tconst details = asObject(rateLimit) as BackendRateLimitDetails | undefined;\n\tif (!details) throw new Error(\"rate limit was not an object.\");\n\tconst primary = normalizeBackendWindow(details.primary_window);\n\tconst secondary = normalizeBackendWindow(details.secondary_window);\n\tif (!primary && !secondary && !normalizeBackendCredits(credits)) return undefined;\n\treturn { limitId, limitName, primary, secondary };\n}\n\nfunction normalizeBackendWindow(value: unknown): NormalizedWindow | undefined {\n\tif (value === null || value === undefined) return undefined;\n\tconst window = asObject(value) as BackendWindowSnapshot | undefined;\n\tif (!window) throw new Error(\"rate-limit window was not an object.\");\n\tconst usedPercent = asNumber(window.used_percent);\n\tif (usedPercent === undefined) return undefined;\n\tconst limitSeconds = asNumber(window.limit_window_seconds);\n\treturn {\n\t\tusedPercent,\n\t\twindowMinutes: limitSeconds && limitSeconds > 0 ? Math.ceil(limitSeconds / 60) : undefined,\n\t\tresetsAt: toEpochMs(window.reset_at),\n\t};\n}\n\nfunction normalizeBackendCredits(value: unknown): boolean {\n\tconst credits = asObject(value) as BackendCreditsSnapshot | undefined;\n\tif (!credits) return false;\n\treturn credits.has_credits !== undefined && credits.unlimited !== undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Auth resolution via core ModelRuntime (rewired from ctx.modelRegistry)\n// ---------------------------------------------------------------------------\n\nasync function resolveCodexHeaders(runtime: ModelRuntime): Promise<Record<string, string> | undefined> {\n\tconst candidates: Model<Api>[] = [];\n\tconst seen = new Set<string>();\n\tconst add = (model: Model<Api> | undefined) => {\n\t\tif (!model || model.provider !== CODEX_PROVIDER_ID) return;\n\t\tconst key = `${model.provider}/${model.id}`;\n\t\tif (seen.has(key)) return;\n\t\tseen.add(key);\n\t\tcandidates.push(model);\n\t};\n\tfor (const model of runtime.getAvailableSnapshot()) add(model);\n\tfor (const model of runtime.getModels()) add(model);\n\n\tfor (const model of candidates) {\n\t\tlet resolution: AuthResult | undefined;\n\t\ttry {\n\t\t\tresolution = await runtime.getAuth(model);\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\t\tif (!resolution) continue;\n\t\tconst headers: Record<string, string> = {};\n\t\tfor (const [name, value] of Object.entries(resolution.auth.headers ?? {})) {\n\t\t\tif (value !== null && value !== undefined) headers[name] = String(value);\n\t\t}\n\t\tif (!hasHeader(headers, \"Authorization\") && resolution.auth.apiKey) {\n\t\t\theaders.Authorization = `Bearer ${resolution.auth.apiKey}`;\n\t\t}\n\t\tif (!hasHeader(headers, \"User-Agent\")) {\n\t\t\theaders[\"User-Agent\"] = \"lunr-usage-service\";\n\t\t}\n\t\tif (hasHeader(headers, \"Authorization\")) return headers;\n\t}\n\treturn undefined;\n}\n\nfunction hasHeader(headers: Record<string, string>, name: string): boolean {\n\treturn Object.keys(headers).some((key) => key.toLowerCase() === name.toLowerCase());\n}\n\nfunction redactErrorBody(body: string): string {\n\tconst redacted = body\n\t\t.replace(/Bearer\\s+[A-Za-z0-9._~+/=-]+/gi, \"Bearer <redacted>\")\n\t\t.replace(/\"access_token\"\\s*:\\s*\"[^\"]+\"/gi, '\"access_token\":\"<redacted>\"')\n\t\t.trim();\n\treturn redacted.length > MAX_ERROR_BODY_CHARS ? `${redacted.slice(0, MAX_ERROR_BODY_CHARS - 1)}…` : redacted;\n}\n\n// ---------------------------------------------------------------------------\n// PlanUsage mapping\n// ---------------------------------------------------------------------------\n\nfunction windowLabel(window: NormalizedWindow, fallback: string | undefined): string {\n\tconst minutes = window.windowMinutes;\n\tif (minutes === undefined) return fallback ?? \"Limit\";\n\tif (minutes >= 7 * 24 * 60) return \"Weekly\";\n\tif (minutes >= 24 * 60) return `${Math.round(minutes / (24 * 60))}d`;\n\tif (minutes >= 60) return `${Math.round(minutes / 60)}h`;\n\treturn `${minutes}m`;\n}\n\nfunction toPlanUsage(report: CodexUsageReport): PlanUsage | undefined {\n\tconst snapshot = report.snapshots[0];\n\tif (!snapshot) return undefined;\n\t// Longer window (weekly) first, shorter (5h) second — matches /usage layout.\n\tconst windows: PlanUsageWindow[] = [];\n\tfor (const window of [snapshot.secondary, snapshot.primary]) {\n\t\tif (!window) continue;\n\t\twindows.push({\n\t\t\tlabel: windowLabel(window, snapshot.limitName),\n\t\t\tusedPercent: window.usedPercent,\n\t\t\tresetsAt: window.resetsAt,\n\t\t});\n\t}\n\tif (windows.length === 0) return undefined;\n\treturn { provider: CODEX_PROVIDER_ID, planLabel: report.planType, windows };\n}\n\nexport async function fetchCodexPlanUsage(runtime: ModelRuntime): Promise<PlanUsage | undefined> {\n\tconst headers = await resolveCodexHeaders(runtime);\n\tif (!headers) return undefined;\n\n\tconst response = await fetchWithTimeout(CODEX_USAGE_URL, { headers });\n\tconst text = await response.text();\n\tif (!response.ok) {\n\t\tthrow new Error(`Codex usage endpoint returned ${response.status}: ${redactErrorBody(text)}`);\n\t}\n\tconst payload = asObject(JSON.parse(text)) as RateLimitStatusPayload | undefined;\n\tif (!payload) return undefined;\n\treturn toPlanUsage(normalizeBackendPayload(payload));\n}\n"]}
|
|
1
|
+
{"version":3,"file":"openai-codex.js","sourceRoot":"","sources":["../../../src/core/usage-adapters/openai-codex.ts"],"names":[],"mappings":"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","sourcesContent":["// Vendored from narumiruna-pi-codex-usage (deleted in Phase 1 of the lunr-ux plan):\n// the pi-auth HTTP query path of `query.ts` plus `normalize.ts` and the backend\n// types from `types.ts`, consolidated into one core module. The codex app-server\n// fallback was dropped; extension-API imports (ExtensionContext, modelRegistry)\n// were rewired to core's ModelRuntime. No runtime dependency on the deleted\n// extension or on extension-repos remains.\n\nimport type { Api, AuthResult, Model } from \"@ashx-j/lunr-ai\";\nimport type { ModelRuntime } from \"../model-runtime.ts\";\nimport type { PlanUsage, PlanUsageWindow } from \"../usage-service.ts\";\nimport { asNumber, asObject, asString, fetchWithTimeout, toEpochMs } from \"./shared.ts\";\n\nconst CODEX_PROVIDER_ID = \"openai-codex\";\nconst CODEX_USAGE_URL = \"https://chatgpt.com/backend-api/wham/usage\";\nconst MAX_ERROR_BODY_CHARS = 600;\n\n// ---------------------------------------------------------------------------\n// Backend payload types (vendored from types.ts)\n// ---------------------------------------------------------------------------\n\ntype RateLimitStatusPayload = {\n\tplan_type?: unknown;\n\trate_limit?: unknown;\n\tadditional_rate_limits?: unknown;\n\tcredits?: unknown;\n\trate_limit_reset_credits?: unknown;\n};\n\ntype BackendRateLimitDetails = {\n\tprimary_window?: unknown;\n\tsecondary_window?: unknown;\n};\n\ntype BackendWindowSnapshot = {\n\tused_percent?: unknown;\n\tlimit_window_seconds?: unknown;\n\treset_at?: unknown;\n};\n\ntype BackendAdditionalRateLimit = {\n\tlimit_name?: unknown;\n\tmetered_feature?: unknown;\n\trate_limit?: unknown;\n};\n\ntype BackendCreditsSnapshot = {\n\thas_credits?: unknown;\n\tunlimited?: unknown;\n\tbalance?: unknown;\n};\n\ntype NormalizedWindow = {\n\tusedPercent: number;\n\twindowMinutes?: number;\n\tresetsAt?: number;\n};\n\ntype NormalizedSnapshot = {\n\tlimitId: string;\n\tlimitName?: string;\n\tprimary?: NormalizedWindow;\n\tsecondary?: NormalizedWindow;\n};\n\ntype CodexUsageReport = {\n\tplanType?: string;\n\tsnapshots: NormalizedSnapshot[];\n};\n\n// ---------------------------------------------------------------------------\n// Payload normalization (vendored from normalize.ts, backend path only)\n// ---------------------------------------------------------------------------\n\nfunction normalizeBackendPayload(payload: RateLimitStatusPayload): CodexUsageReport {\n\tconst snapshots: NormalizedSnapshot[] = [];\n\tconst planType = asString(payload.plan_type);\n\tconst primary = normalizeBackendSnapshot(\"codex\", undefined, payload.rate_limit, payload.credits);\n\tif (primary) snapshots.push(primary);\n\n\tconst additional = Array.isArray(payload.additional_rate_limits) ? payload.additional_rate_limits : [];\n\tfor (const item of additional) {\n\t\tconst additionalLimit = asObject(item) as BackendAdditionalRateLimit | undefined;\n\t\tif (!additionalLimit) continue;\n\t\tconst limitId = asString(additionalLimit.metered_feature) ?? asString(additionalLimit.limit_name);\n\t\tif (!limitId) continue;\n\t\ttry {\n\t\t\tconst snapshot = normalizeBackendSnapshot(\n\t\t\t\tlimitId,\n\t\t\t\tasString(additionalLimit.limit_name),\n\t\t\t\tadditionalLimit.rate_limit,\n\t\t\t\tundefined,\n\t\t\t);\n\t\t\tif (snapshot) snapshots.push(snapshot);\n\t\t} catch {\n\t\t\t// Optional additional buckets must not hide otherwise usable primary usage.\n\t\t}\n\t}\n\n\tif (snapshots.length === 0) {\n\t\tthrow new Error(\"Codex usage endpoint returned no displayable usage data.\");\n\t}\n\treturn { planType, snapshots };\n}\n\nfunction normalizeBackendSnapshot(\n\tlimitId: string,\n\tlimitName: string | undefined,\n\trateLimit: unknown,\n\tcredits: unknown,\n): NormalizedSnapshot | undefined {\n\tif (rateLimit === null || rateLimit === undefined) {\n\t\treturn normalizeBackendCredits(credits) ? { limitId, limitName } : undefined;\n\t}\n\tconst details = asObject(rateLimit) as BackendRateLimitDetails | undefined;\n\tif (!details) throw new Error(\"rate limit was not an object.\");\n\tconst primary = normalizeBackendWindow(details.primary_window);\n\tconst secondary = normalizeBackendWindow(details.secondary_window);\n\tif (!primary && !secondary && !normalizeBackendCredits(credits)) return undefined;\n\treturn { limitId, limitName, primary, secondary };\n}\n\nfunction normalizeBackendWindow(value: unknown): NormalizedWindow | undefined {\n\tif (value === null || value === undefined) return undefined;\n\tconst window = asObject(value) as BackendWindowSnapshot | undefined;\n\tif (!window) throw new Error(\"rate-limit window was not an object.\");\n\tconst usedPercent = asNumber(window.used_percent);\n\tif (usedPercent === undefined) return undefined;\n\tconst limitSeconds = asNumber(window.limit_window_seconds);\n\treturn {\n\t\tusedPercent,\n\t\twindowMinutes: limitSeconds && limitSeconds > 0 ? Math.ceil(limitSeconds / 60) : undefined,\n\t\tresetsAt: toEpochMs(window.reset_at),\n\t};\n}\n\nfunction normalizeBackendCredits(value: unknown): boolean {\n\tconst credits = asObject(value) as BackendCreditsSnapshot | undefined;\n\tif (!credits) return false;\n\treturn credits.has_credits !== undefined && credits.unlimited !== undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Auth resolution via core ModelRuntime (rewired from ctx.modelRegistry)\n// ---------------------------------------------------------------------------\n\nasync function resolveCodexHeaders(runtime: ModelRuntime): Promise<Record<string, string> | undefined> {\n\tconst candidates: Model<Api>[] = [];\n\tconst seen = new Set<string>();\n\tconst add = (model: Model<Api> | undefined) => {\n\t\tif (!model || model.provider !== CODEX_PROVIDER_ID) return;\n\t\tconst key = `${model.provider}/${model.id}`;\n\t\tif (seen.has(key)) return;\n\t\tseen.add(key);\n\t\tcandidates.push(model);\n\t};\n\tfor (const model of runtime.getAvailableSnapshot()) add(model);\n\tfor (const model of runtime.getModels()) add(model);\n\n\tfor (const model of candidates) {\n\t\tlet resolution: AuthResult | undefined;\n\t\ttry {\n\t\t\tresolution = await runtime.getAuth(model);\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\t\tif (!resolution) continue;\n\t\tconst headers: Record<string, string> = {};\n\t\tfor (const [name, value] of Object.entries(resolution.auth.headers ?? {})) {\n\t\t\tif (value !== null && value !== undefined) headers[name] = String(value);\n\t\t}\n\t\tif (!hasHeader(headers, \"Authorization\") && resolution.auth.apiKey) {\n\t\t\theaders.Authorization = `Bearer ${resolution.auth.apiKey}`;\n\t\t}\n\t\tif (!hasHeader(headers, \"User-Agent\")) {\n\t\t\theaders[\"User-Agent\"] = \"lunr-usage-service\";\n\t\t}\n\t\tif (hasHeader(headers, \"Authorization\")) return headers;\n\t}\n\treturn undefined;\n}\n\nfunction hasHeader(headers: Record<string, string>, name: string): boolean {\n\treturn Object.keys(headers).some((key) => key.toLowerCase() === name.toLowerCase());\n}\n\nfunction redactErrorBody(body: string): string {\n\tconst redacted = body\n\t\t.replace(/Bearer\\s+[A-Za-z0-9._~+/=-]+/gi, \"Bearer <redacted>\")\n\t\t.replace(/\"access_token\"\\s*:\\s*\"[^\"]+\"/gi, '\"access_token\":\"<redacted>\"')\n\t\t.trim();\n\treturn redacted.length > MAX_ERROR_BODY_CHARS ? `${redacted.slice(0, MAX_ERROR_BODY_CHARS - 1)}…` : redacted;\n}\n\n// ---------------------------------------------------------------------------\n// PlanUsage mapping\n// ---------------------------------------------------------------------------\n\nfunction windowLabel(window: NormalizedWindow, fallback: string | undefined): string {\n\tconst minutes = window.windowMinutes;\n\tif (minutes === undefined) return fallback ?? \"Limit\";\n\tif (minutes >= 7 * 24 * 60) return \"Weekly\";\n\tif (minutes >= 24 * 60) return `${Math.round(minutes / (24 * 60))}d`;\n\tif (minutes >= 60) return `${Math.round(minutes / 60)}h`;\n\treturn `${minutes}m`;\n}\n\nfunction toPlanUsage(report: CodexUsageReport): PlanUsage[] {\n\treturn report.snapshots.flatMap((snapshot, index) => {\n\t\t// Longer window (weekly) first, shorter (5h) second — matches /usage layout.\n\t\tconst windows: PlanUsageWindow[] = [];\n\t\tfor (const window of [snapshot.secondary, snapshot.primary]) {\n\t\t\tif (!window) continue;\n\t\t\twindows.push({\n\t\t\t\tlabel: windowLabel(window, snapshot.limitName),\n\t\t\t\tusedPercent: window.usedPercent,\n\t\t\t\tresetsAt: window.resetsAt,\n\t\t\t});\n\t\t}\n\t\tif (windows.length === 0) return [];\n\t\treturn [\n\t\t\t{\n\t\t\t\tprovider: CODEX_PROVIDER_ID,\n\t\t\t\tplanLabel: index === 0 ? report.planType : (snapshot.limitName ?? snapshot.limitId),\n\t\t\t\twindows,\n\t\t\t},\n\t\t];\n\t});\n}\n\nexport async function fetchCodexPlanUsage(runtime: ModelRuntime): Promise<PlanUsage[] | undefined> {\n\tconst headers = await resolveCodexHeaders(runtime);\n\tif (!headers) return undefined;\n\n\tconst response = await fetchWithTimeout(CODEX_USAGE_URL, { headers });\n\tconst text = await response.text();\n\tif (!response.ok) {\n\t\tthrow new Error(`Codex usage endpoint returned ${response.status}: ${redactErrorBody(text)}`);\n\t}\n\tconst payload = asObject(JSON.parse(text)) as RateLimitStatusPayload | undefined;\n\tif (!payload) return undefined;\n\treturn toPlanUsage(normalizeBackendPayload(payload));\n}\n"]}
|
|
@@ -26,10 +26,17 @@ export interface PlanUsage {
|
|
|
26
26
|
windows: PlanUsageWindow[];
|
|
27
27
|
}
|
|
28
28
|
export interface PlanUsageResult {
|
|
29
|
+
/** First plan, kept for footer and compatibility callers. */
|
|
29
30
|
usage?: PlanUsage;
|
|
31
|
+
/** Every plan returned by the provider. */
|
|
32
|
+
usages?: PlanUsage[];
|
|
30
33
|
/** Actionable auth failure. Not cached as an empty success. */
|
|
31
34
|
error?: string;
|
|
32
35
|
}
|
|
36
|
+
export interface AllPlanUsageResult {
|
|
37
|
+
usages: PlanUsage[];
|
|
38
|
+
errors: string[];
|
|
39
|
+
}
|
|
33
40
|
/** Classify adapter/getAuth failures that mean the SuperGrok session is dead. */
|
|
34
41
|
export declare function planUsageAuthError(error: unknown): string | undefined;
|
|
35
42
|
export declare const PLAN_USAGE_CACHE_TTL_MS: number;
|
|
@@ -43,8 +50,10 @@ export declare function footerPlanLabel(window: PlanUsageWindow): string;
|
|
|
43
50
|
export declare function hasPlanUsageAdapter(providerId: string): boolean;
|
|
44
51
|
/** Plan usage for a provider, or undefined when unsupported/unavailable. Never throws. */
|
|
45
52
|
export declare function getPlanUsage(providerId: string, runtime: ModelRuntime): Promise<PlanUsage | undefined>;
|
|
46
|
-
/** Like getPlanUsage, but surfaces
|
|
53
|
+
/** Like getPlanUsage, but surfaces auth failures instead of hiding them. */
|
|
47
54
|
export declare function getPlanUsageResult(providerId: string, runtime: ModelRuntime): Promise<PlanUsageResult>;
|
|
55
|
+
/** Fetch every stored-credential plan plus the current provider, in parallel. */
|
|
56
|
+
export declare function getAllPlanUsageResults(currentProvider: string | undefined, runtime: ModelRuntime): Promise<AllPlanUsageResult>;
|
|
48
57
|
/** Last fetched usage, including expired cache (footer can show stale while refetching). */
|
|
49
58
|
export declare function peekPlanUsage(providerId: string): PlanUsage | undefined;
|
|
50
59
|
/** Clear the adapter cache (tests, /login changes). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usage-service.d.ts","sourceRoot":"","sources":["../../src/core/usage-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAM7D,MAAM,WAAW,eAAe;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,uCAAuC;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,SAAS;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,eAAe,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,eAAe;IAC/B,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,+DAA+D;IAC/D,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAoBD,iFAAiF;AACjF,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAOrE;AAWD,eAAO,MAAM,uBAAuB,QAAY,CAAC;AAEjD,MAAM,MAAM,yBAAyB,GAAG,IAAI,GAAG,QAAQ,CAAC;AAExD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAEnE;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAErE;AAED,6EAA6E;AAC7E,wBAAgB,cAAc,CAC7B,KAAK,EAAE,SAAS,GAAG,SAAS,EAC5B,SAAS,EAAE,yBAAyB,GAClC,eAAe,GAAG,SAAS,CAO7B;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,CAI/D;AAKD,6DAA6D;AAC7D,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAE/D;AAED,0FAA0F;AAC1F,wBAAsB,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CAE5G;AAED,sFAAsF;AACtF,wBAAsB,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,eAAe,CAAC,CAwB5G;AAED,4FAA4F;AAC5F,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAEvE;AAED,uDAAuD;AACvD,wBAAgB,mBAAmB,IAAI,IAAI,CAG1C;AAMD,eAAO,MAAM,2BAA2B,eAAoC,CAAC;AAE7E,MAAM,WAAW,iBAAiB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,kBAAkB;IAClC,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAAC;IAChD,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,kBAAkB,IAAI,yBAAyB,CAAC;IAChD,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS,CAAC;IACjE,WAAW,CAAC,EAAE,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,GAAG,IAAI,CAAC;CAChD;AA+BD,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,eAAe,GAAG,IAAI,CAIxG;AAED,wBAAgB,qBAAqB,IAAI,kBAAkB,GAAG,SAAS,CAEtE","sourcesContent":["/**\n * Plan/subscription usage service. Per-provider adapters query provider quota\n * endpoints (60-second cache each) so /usage and the footer can show subscription windows\n * alongside session/context totals.\n *\n * Deliberately absent adapters:\n * - anthropic: Anthropic policy prohibits subscription usage tracking in\n * third-party coding agents (2026-07-18 decision). OAuth Anthropic sessions\n * fall back to hiding the cost meter.\n * - ollama-cloud: no usage API exists.\n *\n * Adapter/network errors resolve to `undefined` (callers omit the plan UI).\n * Auth failures are different: they return `error` and are not cached as empty.\n */\n\nimport { ModelsError } from \"@ashx-j/lunr-ai\";\nimport type { ModelRuntime } from \"./model-runtime.ts\";\nimport type { SettingsManager } from \"./settings-manager.ts\";\nimport { fetchKimiPlanUsage } from \"./usage-adapters/kimi-coding.ts\";\nimport { fetchCodexPlanUsage } from \"./usage-adapters/openai-codex.ts\";\nimport { fetchXaiPlanUsage } from \"./usage-adapters/xai.ts\";\nimport { fetchZaiPlanUsage } from \"./usage-adapters/zai.ts\";\n\nexport interface PlanUsageWindow {\n\tlabel: string;\n\tusedPercent: number;\n\t/** Epoch ms when the window resets. */\n\tresetsAt?: number;\n}\n\nexport interface PlanUsage {\n\tprovider: string;\n\tplanLabel?: string;\n\twindows: PlanUsageWindow[];\n}\n\nexport interface PlanUsageResult {\n\tusage?: PlanUsage;\n\t/** Actionable auth failure. Not cached as an empty success. */\n\terror?: string;\n}\n\nconst XAI_RELOGIN = \"xAI login expired. Run /login xai.\";\n\nfunction errorChain(error: unknown): string {\n\tconst parts: string[] = [];\n\tlet current: unknown = error;\n\tconst seen = new Set<unknown>();\n\twhile (current && typeof current === \"object\" && !seen.has(current)) {\n\t\tseen.add(current);\n\t\tif (current instanceof Error) {\n\t\t\tparts.push(current.message);\n\t\t\tcurrent = current.cause;\n\t\t\tcontinue;\n\t\t}\n\t\tbreak;\n\t}\n\treturn parts.join(\" \");\n}\n\n/** Classify adapter/getAuth failures that mean the SuperGrok session is dead. */\nexport function planUsageAuthError(error: unknown): string | undefined {\n\tconst chain = errorChain(error);\n\tif (/timed out|aborted|cancelled|ECONN|ENOTFOUND|network/i.test(chain)) return undefined;\n\t// 403 on billing is often entitlement, not a dead refresh token.\n\tif (/xai billing rejected the session \\(HTTP 401\\)/i.test(chain)) return XAI_RELOGIN;\n\tif (/invalid_grant|refresh token revoked/i.test(chain)) return XAI_RELOGIN;\n\treturn undefined;\n}\n\ntype UsageAdapter = (runtime: ModelRuntime) => Promise<PlanUsage | undefined>;\n\nconst ADAPTERS: Readonly<Record<string, UsageAdapter>> = {\n\t\"openai-codex\": fetchCodexPlanUsage,\n\t\"kimi-coding\": fetchKimiPlanUsage,\n\tzai: fetchZaiPlanUsage,\n\txai: fetchXaiPlanUsage,\n};\n\nexport const PLAN_USAGE_CACHE_TTL_MS = 60 * 1000;\n\nexport type PlanUsageWindowPreference = \"5h\" | \"weekly\";\n\nexport function isWeeklyPlanWindow(window: PlanUsageWindow): boolean {\n\treturn /week/i.test(window.label);\n}\n\nexport function isFiveHourPlanWindow(window: PlanUsageWindow): boolean {\n\treturn /5h/i.test(window.label) || window.label === \"5h\";\n}\n\n/** Preferred window, falling back to the other, skipping Extra/on-demand. */\nexport function pickPlanWindow(\n\tusage: PlanUsage | undefined,\n\tpreferred: PlanUsageWindowPreference,\n): PlanUsageWindow | undefined {\n\tif (!usage?.windows.length) return undefined;\n\tconst usable = usage.windows.filter((w) => !/extra/i.test(w.label));\n\tconst weekly = usable.find(isWeeklyPlanWindow);\n\tconst fiveH = usable.find(isFiveHourPlanWindow);\n\tif (preferred === \"5h\") return fiveH ?? weekly ?? usable[0] ?? usage.windows[0];\n\treturn weekly ?? fiveH ?? usable[0] ?? usage.windows[0];\n}\n\nexport function footerPlanLabel(window: PlanUsageWindow): string {\n\tif (isFiveHourPlanWindow(window)) return \"5h\";\n\tif (isWeeklyPlanWindow(window)) return \"wk\";\n\treturn window.label.length <= 4 ? window.label : window.label.slice(0, 4);\n}\n\nconst cache = new Map<string, { expiresAt: number; value: PlanUsage | undefined }>();\nconst inflight = new Map<string, Promise<PlanUsageResult>>();\n\n/** Whether a plan-usage adapter exists for this provider. */\nexport function hasPlanUsageAdapter(providerId: string): boolean {\n\treturn providerId in ADAPTERS;\n}\n\n/** Plan usage for a provider, or undefined when unsupported/unavailable. Never throws. */\nexport async function getPlanUsage(providerId: string, runtime: ModelRuntime): Promise<PlanUsage | undefined> {\n\treturn (await getPlanUsageResult(providerId, runtime)).usage;\n}\n\n/** Like getPlanUsage, but surfaces SuperGrok/auth failures instead of hiding them. */\nexport async function getPlanUsageResult(providerId: string, runtime: ModelRuntime): Promise<PlanUsageResult> {\n\tconst adapter = ADAPTERS[providerId];\n\tif (!adapter) return {};\n\tconst now = Date.now();\n\tconst cached = cache.get(providerId);\n\tif (cached && cached.expiresAt > now) return { usage: cached.value };\n\tconst pending = inflight.get(providerId);\n\tif (pending) return pending;\n\tconst task = (async (): Promise<PlanUsageResult> => {\n\t\ttry {\n\t\t\tconst value = await adapter(runtime);\n\t\t\tcache.set(providerId, { expiresAt: Date.now() + PLAN_USAGE_CACHE_TTL_MS, value });\n\t\t\treturn { usage: value };\n\t\t} catch (error) {\n\t\t\tconst authError = planUsageAuthError(error);\n\t\t\tif (authError) return { error: authError };\n\t\t\tcache.set(providerId, { expiresAt: Date.now() + PLAN_USAGE_CACHE_TTL_MS, value: undefined });\n\t\t\treturn {};\n\t\t} finally {\n\t\t\tinflight.delete(providerId);\n\t\t}\n\t})();\n\tinflight.set(providerId, task);\n\treturn task;\n}\n\n/** Last fetched usage, including expired cache (footer can show stale while refetching). */\nexport function peekPlanUsage(providerId: string): PlanUsage | undefined {\n\treturn cache.get(providerId)?.value;\n}\n\n/** Clear the adapter cache (tests, /login changes). */\nexport function clearPlanUsageCache(): void {\n\tcache.clear();\n\tinflight.clear();\n}\n\n// ---------------------------------------------------------------------------\n// Extension bridge\n// ---------------------------------------------------------------------------\n\nexport const USAGE_SERVICE_BRIDGE_SYMBOL = Symbol.for(\"@lunr/usage-service\");\n\nexport interface FooterPlanSegment {\n\tlabel: string;\n\tusedPercent: number;\n}\n\nexport interface UsageServiceBridge {\n\tpeek(providerId: string): PlanUsage | undefined;\n\tprefetch(providerId: string): void;\n\tgetPreferredWindow(): PlanUsageWindowPreference;\n\tpickForFooter(providerId: string): FooterPlanSegment | undefined;\n\tsetOnUpdate(fn: (() => void) | undefined): void;\n}\n\nlet activeRuntime: ModelRuntime | undefined;\nlet activeUsageSettings: SettingsManager | undefined;\nlet onUsageUpdate: (() => void) | undefined;\n\nfunction preferredWindow(): PlanUsageWindowPreference {\n\treturn activeUsageSettings?.getPlanUsageWindow() ?? \"weekly\";\n}\n\nconst usageBridge: UsageServiceBridge = {\n\tpeek(providerId: string): PlanUsage | undefined {\n\t\treturn peekPlanUsage(providerId);\n\t},\n\tprefetch(providerId: string): void {\n\t\tif (!activeRuntime || !hasPlanUsageAdapter(providerId)) return;\n\t\tvoid getPlanUsage(providerId, activeRuntime).then(() => onUsageUpdate?.());\n\t},\n\tsetOnUpdate(fn: (() => void) | undefined): void {\n\t\tonUsageUpdate = fn;\n\t},\n\tgetPreferredWindow(): PlanUsageWindowPreference {\n\t\treturn preferredWindow();\n\t},\n\tpickForFooter(providerId: string): FooterPlanSegment | undefined {\n\t\tconst window = pickPlanWindow(peekPlanUsage(providerId), preferredWindow());\n\t\tif (!window) return undefined;\n\t\treturn { label: footerPlanLabel(window), usedPercent: window.usedPercent };\n\t},\n};\n\nexport function registerUsageServiceBridge(runtime: ModelRuntime, settingsManager: SettingsManager): void {\n\tactiveRuntime = runtime;\n\tactiveUsageSettings = settingsManager;\n\t(globalThis as Record<symbol, unknown>)[USAGE_SERVICE_BRIDGE_SYMBOL] = usageBridge;\n}\n\nexport function getUsageServiceBridge(): UsageServiceBridge | undefined {\n\treturn (globalThis as Record<symbol, unknown>)[USAGE_SERVICE_BRIDGE_SYMBOL] as UsageServiceBridge | undefined;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"usage-service.d.ts","sourceRoot":"","sources":["../../src/core/usage-service.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Plan/subscription usage service. Per-provider adapters query provider quota\n * endpoints (60-second cache each) so /usage and the footer can show subscription windows\n * alongside session/context totals.\n *\n * Deliberately absent adapters:\n * - anthropic: Anthropic policy prohibits subscription usage tracking in\n * third-party coding agents (2026-07-18 decision). OAuth Anthropic sessions\n * fall back to hiding the cost meter.\n * - ollama-cloud: no usage API exists.\n *\n * Adapter/network errors resolve to `undefined` (callers omit the plan UI).\n * Auth failures are different: they return `error` and are not cached as empty.\n */\n\nimport type { ModelRuntime } from \"./model-runtime.ts\";\nimport type { SettingsManager } from \"./settings-manager.ts\";\nimport { fetchKimiPlanUsage } from \"./usage-adapters/kimi-coding.ts\";\nimport { fetchCodexPlanUsage } from \"./usage-adapters/openai-codex.ts\";\nimport { fetchXaiPlanUsage } from \"./usage-adapters/xai.ts\";\nimport { fetchZaiPlanUsage } from \"./usage-adapters/zai.ts\";\n\nexport interface PlanUsageWindow {\n\tlabel: string;\n\tusedPercent: number;\n\t/** Epoch ms when the window resets. */\n\tresetsAt?: number;\n}\n\nexport interface PlanUsage {\n\tprovider: string;\n\tplanLabel?: string;\n\twindows: PlanUsageWindow[];\n}\n\nexport interface PlanUsageResult {\n\t/** First plan, kept for footer and compatibility callers. */\n\tusage?: PlanUsage;\n\t/** Every plan returned by the provider. */\n\tusages?: PlanUsage[];\n\t/** Actionable auth failure. Not cached as an empty success. */\n\terror?: string;\n}\n\nexport interface AllPlanUsageResult {\n\tusages: PlanUsage[];\n\terrors: string[];\n}\n\nconst XAI_RELOGIN = \"xAI login expired. Run /login xai.\";\n\nfunction errorChain(error: unknown): string {\n\tconst parts: string[] = [];\n\tlet current: unknown = error;\n\tconst seen = new Set<unknown>();\n\twhile (current && typeof current === \"object\" && !seen.has(current)) {\n\t\tseen.add(current);\n\t\tif (current instanceof Error) {\n\t\t\tparts.push(current.message);\n\t\t\tcurrent = current.cause;\n\t\t\tcontinue;\n\t\t}\n\t\tbreak;\n\t}\n\treturn parts.join(\" \");\n}\n\n/** Classify adapter/getAuth failures that mean the SuperGrok session is dead. */\nexport function planUsageAuthError(error: unknown): string | undefined {\n\tconst chain = errorChain(error);\n\tif (/timed out|aborted|cancelled|ECONN|ENOTFOUND|network/i.test(chain)) return undefined;\n\t// 403 on billing is often entitlement, not a dead refresh token.\n\tif (/xai billing rejected the session \\(HTTP 401\\)/i.test(chain)) return XAI_RELOGIN;\n\tif (/invalid_grant|refresh token revoked/i.test(chain)) return XAI_RELOGIN;\n\treturn undefined;\n}\n\ntype UsageAdapter = (runtime: ModelRuntime) => Promise<PlanUsage | PlanUsage[] | undefined>;\n\nconst ADAPTERS: Readonly<Record<string, UsageAdapter>> = {\n\t\"openai-codex\": fetchCodexPlanUsage,\n\t\"kimi-coding\": fetchKimiPlanUsage,\n\tzai: fetchZaiPlanUsage,\n\txai: fetchXaiPlanUsage,\n};\n\nexport const PLAN_USAGE_CACHE_TTL_MS = 60 * 1000;\n\nexport type PlanUsageWindowPreference = \"5h\" | \"weekly\";\n\nexport function isWeeklyPlanWindow(window: PlanUsageWindow): boolean {\n\treturn /week/i.test(window.label);\n}\n\nexport function isFiveHourPlanWindow(window: PlanUsageWindow): boolean {\n\treturn /5h/i.test(window.label) || window.label === \"5h\";\n}\n\n/** Preferred window, falling back to the other, skipping Extra/on-demand. */\nexport function pickPlanWindow(\n\tusage: PlanUsage | undefined,\n\tpreferred: PlanUsageWindowPreference,\n): PlanUsageWindow | undefined {\n\tif (!usage?.windows.length) return undefined;\n\tconst usable = usage.windows.filter((w) => !/extra/i.test(w.label));\n\tconst weekly = usable.find(isWeeklyPlanWindow);\n\tconst fiveH = usable.find(isFiveHourPlanWindow);\n\tif (preferred === \"5h\") return fiveH ?? weekly ?? usable[0] ?? usage.windows[0];\n\treturn weekly ?? fiveH ?? usable[0] ?? usage.windows[0];\n}\n\nexport function footerPlanLabel(window: PlanUsageWindow): string {\n\tif (isFiveHourPlanWindow(window)) return \"5h\";\n\tif (isWeeklyPlanWindow(window)) return \"wk\";\n\treturn window.label.length <= 4 ? window.label : window.label.slice(0, 4);\n}\n\nconst cache = new Map<string, { expiresAt: number; value: PlanUsage[] }>();\nconst inflight = new Map<string, Promise<PlanUsageResult>>();\n\n/** Whether a plan-usage adapter exists for this provider. */\nexport function hasPlanUsageAdapter(providerId: string): boolean {\n\treturn providerId in ADAPTERS;\n}\n\n/** Plan usage for a provider, or undefined when unsupported/unavailable. Never throws. */\nexport async function getPlanUsage(providerId: string, runtime: ModelRuntime): Promise<PlanUsage | undefined> {\n\treturn (await getPlanUsageResult(providerId, runtime)).usage;\n}\n\n/** Like getPlanUsage, but surfaces auth failures instead of hiding them. */\nexport async function getPlanUsageResult(providerId: string, runtime: ModelRuntime): Promise<PlanUsageResult> {\n\tconst adapter = ADAPTERS[providerId];\n\tif (!adapter) return {};\n\tconst now = Date.now();\n\tconst cached = cache.get(providerId);\n\tif (cached && cached.expiresAt > now) return { usage: cached.value[0], usages: cached.value };\n\tconst pending = inflight.get(providerId);\n\tif (pending) return pending;\n\tconst task = (async (): Promise<PlanUsageResult> => {\n\t\ttry {\n\t\t\tconst value = await adapter(runtime);\n\t\t\tconst usages = value === undefined ? [] : Array.isArray(value) ? value : [value];\n\t\t\tcache.set(providerId, { expiresAt: Date.now() + PLAN_USAGE_CACHE_TTL_MS, value: usages });\n\t\t\treturn { usage: usages[0], usages };\n\t\t} catch (error) {\n\t\t\tconst authError = planUsageAuthError(error);\n\t\t\tif (authError) return { error: authError };\n\t\t\tcache.set(providerId, { expiresAt: Date.now() + PLAN_USAGE_CACHE_TTL_MS, value: [] });\n\t\t\treturn {};\n\t\t} finally {\n\t\t\tinflight.delete(providerId);\n\t\t}\n\t})();\n\tinflight.set(providerId, task);\n\treturn task;\n}\n\n/** Fetch every stored-credential plan plus the current provider, in parallel. */\nexport async function getAllPlanUsageResults(\n\tcurrentProvider: string | undefined,\n\truntime: ModelRuntime,\n): Promise<AllPlanUsageResult> {\n\tconst stored = new Set((await runtime.listCredentials()).map((credential) => credential.providerId));\n\tconst providers = Object.keys(ADAPTERS).filter(\n\t\t(providerId) => stored.has(providerId) || providerId === currentProvider,\n\t);\n\tconst results = await Promise.all(providers.map((providerId) => getPlanUsageResult(providerId, runtime)));\n\treturn {\n\t\tusages: results.flatMap((result) => result.usages ?? []),\n\t\terrors: results.flatMap((result) => (result.error ? [`${result.error}`] : [])),\n\t};\n}\n\n/** Last fetched usage, including expired cache (footer can show stale while refetching). */\nexport function peekPlanUsage(providerId: string): PlanUsage | undefined {\n\treturn cache.get(providerId)?.value[0];\n}\n\n/** Clear the adapter cache (tests, /login changes). */\nexport function clearPlanUsageCache(): void {\n\tcache.clear();\n\tinflight.clear();\n}\n\n// ---------------------------------------------------------------------------\n// Extension bridge\n// ---------------------------------------------------------------------------\n\nexport const USAGE_SERVICE_BRIDGE_SYMBOL = Symbol.for(\"@lunr/usage-service\");\n\nexport interface FooterPlanSegment {\n\tlabel: string;\n\tusedPercent: number;\n}\n\nexport interface UsageServiceBridge {\n\tpeek(providerId: string): PlanUsage | undefined;\n\tprefetch(providerId: string): void;\n\tgetPreferredWindow(): PlanUsageWindowPreference;\n\tpickForFooter(providerId: string): FooterPlanSegment | undefined;\n\tsetOnUpdate(fn: (() => void) | undefined): void;\n}\n\nlet activeRuntime: ModelRuntime | undefined;\nlet activeUsageSettings: SettingsManager | undefined;\nlet onUsageUpdate: (() => void) | undefined;\n\nfunction preferredWindow(): PlanUsageWindowPreference {\n\treturn activeUsageSettings?.getPlanUsageWindow() ?? \"weekly\";\n}\n\nconst usageBridge: UsageServiceBridge = {\n\tpeek(providerId: string): PlanUsage | undefined {\n\t\treturn peekPlanUsage(providerId);\n\t},\n\tprefetch(providerId: string): void {\n\t\tif (!activeRuntime || !hasPlanUsageAdapter(providerId)) return;\n\t\tvoid getPlanUsage(providerId, activeRuntime).then(() => onUsageUpdate?.());\n\t},\n\tsetOnUpdate(fn: (() => void) | undefined): void {\n\t\tonUsageUpdate = fn;\n\t},\n\tgetPreferredWindow(): PlanUsageWindowPreference {\n\t\treturn preferredWindow();\n\t},\n\tpickForFooter(providerId: string): FooterPlanSegment | undefined {\n\t\tconst window = pickPlanWindow(peekPlanUsage(providerId), preferredWindow());\n\t\tif (!window) return undefined;\n\t\treturn { label: footerPlanLabel(window), usedPercent: window.usedPercent };\n\t},\n};\n\nexport function registerUsageServiceBridge(runtime: ModelRuntime, settingsManager: SettingsManager): void {\n\tactiveRuntime = runtime;\n\tactiveUsageSettings = settingsManager;\n\t(globalThis as Record<symbol, unknown>)[USAGE_SERVICE_BRIDGE_SYMBOL] = usageBridge;\n}\n\nexport function getUsageServiceBridge(): UsageServiceBridge | undefined {\n\treturn (globalThis as Record<symbol, unknown>)[USAGE_SERVICE_BRIDGE_SYMBOL] as UsageServiceBridge | undefined;\n}\n"]}
|
|
@@ -85,7 +85,7 @@ export function hasPlanUsageAdapter(providerId) {
|
|
|
85
85
|
export async function getPlanUsage(providerId, runtime) {
|
|
86
86
|
return (await getPlanUsageResult(providerId, runtime)).usage;
|
|
87
87
|
}
|
|
88
|
-
/** Like getPlanUsage, but surfaces
|
|
88
|
+
/** Like getPlanUsage, but surfaces auth failures instead of hiding them. */
|
|
89
89
|
export async function getPlanUsageResult(providerId, runtime) {
|
|
90
90
|
const adapter = ADAPTERS[providerId];
|
|
91
91
|
if (!adapter)
|
|
@@ -93,21 +93,22 @@ export async function getPlanUsageResult(providerId, runtime) {
|
|
|
93
93
|
const now = Date.now();
|
|
94
94
|
const cached = cache.get(providerId);
|
|
95
95
|
if (cached && cached.expiresAt > now)
|
|
96
|
-
return { usage: cached.value };
|
|
96
|
+
return { usage: cached.value[0], usages: cached.value };
|
|
97
97
|
const pending = inflight.get(providerId);
|
|
98
98
|
if (pending)
|
|
99
99
|
return pending;
|
|
100
100
|
const task = (async () => {
|
|
101
101
|
try {
|
|
102
102
|
const value = await adapter(runtime);
|
|
103
|
-
|
|
104
|
-
|
|
103
|
+
const usages = value === undefined ? [] : Array.isArray(value) ? value : [value];
|
|
104
|
+
cache.set(providerId, { expiresAt: Date.now() + PLAN_USAGE_CACHE_TTL_MS, value: usages });
|
|
105
|
+
return { usage: usages[0], usages };
|
|
105
106
|
}
|
|
106
107
|
catch (error) {
|
|
107
108
|
const authError = planUsageAuthError(error);
|
|
108
109
|
if (authError)
|
|
109
110
|
return { error: authError };
|
|
110
|
-
cache.set(providerId, { expiresAt: Date.now() + PLAN_USAGE_CACHE_TTL_MS, value:
|
|
111
|
+
cache.set(providerId, { expiresAt: Date.now() + PLAN_USAGE_CACHE_TTL_MS, value: [] });
|
|
111
112
|
return {};
|
|
112
113
|
}
|
|
113
114
|
finally {
|
|
@@ -117,9 +118,19 @@ export async function getPlanUsageResult(providerId, runtime) {
|
|
|
117
118
|
inflight.set(providerId, task);
|
|
118
119
|
return task;
|
|
119
120
|
}
|
|
121
|
+
/** Fetch every stored-credential plan plus the current provider, in parallel. */
|
|
122
|
+
export async function getAllPlanUsageResults(currentProvider, runtime) {
|
|
123
|
+
const stored = new Set((await runtime.listCredentials()).map((credential) => credential.providerId));
|
|
124
|
+
const providers = Object.keys(ADAPTERS).filter((providerId) => stored.has(providerId) || providerId === currentProvider);
|
|
125
|
+
const results = await Promise.all(providers.map((providerId) => getPlanUsageResult(providerId, runtime)));
|
|
126
|
+
return {
|
|
127
|
+
usages: results.flatMap((result) => result.usages ?? []),
|
|
128
|
+
errors: results.flatMap((result) => (result.error ? [`${result.error}`] : [])),
|
|
129
|
+
};
|
|
130
|
+
}
|
|
120
131
|
/** Last fetched usage, including expired cache (footer can show stale while refetching). */
|
|
121
132
|
export function peekPlanUsage(providerId) {
|
|
122
|
-
return cache.get(providerId)?.value;
|
|
133
|
+
return cache.get(providerId)?.value[0];
|
|
123
134
|
}
|
|
124
135
|
/** Clear the adapter cache (tests, /login changes). */
|
|
125
136
|
export function clearPlanUsageCache() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usage-service.js","sourceRoot":"","sources":["../../src/core/usage-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAqB5D,MAAM,WAAW,GAAG,oCAAoC,CAAC;AAEzD,SAAS,UAAU,CAAC,KAAc,EAAU;IAC3C,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,OAAO,GAAY,KAAK,CAAC;IAC7B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAW,CAAC;IAChC,OAAO,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;QACrE,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAClB,IAAI,OAAO,YAAY,KAAK,EAAE,CAAC;YAC9B,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YAC5B,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC;YACxB,SAAS;QACV,CAAC;QACD,MAAM;IACP,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAAA,CACvB;AAED,iFAAiF;AACjF,MAAM,UAAU,kBAAkB,CAAC,KAAc,EAAsB;IACtE,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IAChC,IAAI,sDAAsD,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IACzF,iEAAiE;IACjE,IAAI,gDAAgD,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,WAAW,CAAC;IACrF,IAAI,sCAAsC,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,WAAW,CAAC;IAC3E,OAAO,SAAS,CAAC;AAAA,CACjB;AAID,MAAM,QAAQ,GAA2C;IACxD,cAAc,EAAE,mBAAmB;IACnC,aAAa,EAAE,kBAAkB;IACjC,GAAG,EAAE,iBAAiB;IACtB,GAAG,EAAE,iBAAiB;CACtB,CAAC;AAEF,MAAM,CAAC,MAAM,uBAAuB,GAAG,EAAE,GAAG,IAAI,CAAC;AAIjD,MAAM,UAAU,kBAAkB,CAAC,MAAuB,EAAW;IACpE,OAAO,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAAA,CAClC;AAED,MAAM,UAAU,oBAAoB,CAAC,MAAuB,EAAW;IACtE,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,KAAK,KAAK,IAAI,CAAC;AAAA,CACzD;AAED,6EAA6E;AAC7E,MAAM,UAAU,cAAc,CAC7B,KAA4B,EAC5B,SAAoC,EACN;IAC9B,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM;QAAE,OAAO,SAAS,CAAC;IAC7C,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;IACpE,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IAC/C,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;IAChD,IAAI,SAAS,KAAK,IAAI;QAAE,OAAO,KAAK,IAAI,MAAM,IAAI,MAAM,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAChF,OAAO,MAAM,IAAI,KAAK,IAAI,MAAM,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAAA,CACxD;AAED,MAAM,UAAU,eAAe,CAAC,MAAuB,EAAU;IAChE,IAAI,oBAAoB,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IAC9C,IAAI,kBAAkB,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IAC5C,OAAO,MAAM,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAAA,CAC1E;AAED,MAAM,KAAK,GAAG,IAAI,GAAG,EAA+D,CAAC;AACrF,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAoC,CAAC;AAE7D,6DAA6D;AAC7D,MAAM,UAAU,mBAAmB,CAAC,UAAkB,EAAW;IAChE,OAAO,UAAU,IAAI,QAAQ,CAAC;AAAA,CAC9B;AAED,0FAA0F;AAC1F,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,UAAkB,EAAE,OAAqB,EAAkC;IAC7G,OAAO,CAAC,MAAM,kBAAkB,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;AAAA,CAC7D;AAED,sFAAsF;AACtF,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,UAAkB,EAAE,OAAqB,EAA4B;IAC7G,MAAM,OAAO,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC;IACrC,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,CAAC;IACxB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACrC,IAAI,MAAM,IAAI,MAAM,CAAC,SAAS,GAAG,GAAG;QAAE,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC;IACrE,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACzC,IAAI,OAAO;QAAE,OAAO,OAAO,CAAC;IAC5B,MAAM,IAAI,GAAG,CAAC,KAAK,IAA8B,EAAE,CAAC;QACnD,IAAI,CAAC;YACJ,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;YACrC,KAAK,CAAC,GAAG,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,uBAAuB,EAAE,KAAK,EAAE,CAAC,CAAC;YAClF,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;QACzB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,MAAM,SAAS,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;YAC5C,IAAI,SAAS;gBAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;YAC3C,KAAK,CAAC,GAAG,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,uBAAuB,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;YAC7F,OAAO,EAAE,CAAC;QACX,CAAC;gBAAS,CAAC;YACV,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAC7B,CAAC;IAAA,CACD,CAAC,EAAE,CAAC;IACL,QAAQ,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;IAC/B,OAAO,IAAI,CAAC;AAAA,CACZ;AAED,4FAA4F;AAC5F,MAAM,UAAU,aAAa,CAAC,UAAkB,EAAyB;IACxE,OAAO,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,KAAK,CAAC;AAAA,CACpC;AAED,uDAAuD;AACvD,MAAM,UAAU,mBAAmB,GAAS;IAC3C,KAAK,CAAC,KAAK,EAAE,CAAC;IACd,QAAQ,CAAC,KAAK,EAAE,CAAC;AAAA,CACjB;AAED,8EAA8E;AAC9E,mBAAmB;AACnB,8EAA8E;AAE9E,MAAM,CAAC,MAAM,2BAA2B,GAAG,MAAM,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;AAe7E,IAAI,aAAuC,CAAC;AAC5C,IAAI,mBAAgD,CAAC;AACrD,IAAI,aAAuC,CAAC;AAE5C,SAAS,eAAe,GAA8B;IACrD,OAAO,mBAAmB,EAAE,kBAAkB,EAAE,IAAI,QAAQ,CAAC;AAAA,CAC7D;AAED,MAAM,WAAW,GAAuB;IACvC,IAAI,CAAC,UAAkB,EAAyB;QAC/C,OAAO,aAAa,CAAC,UAAU,CAAC,CAAC;IAAA,CACjC;IACD,QAAQ,CAAC,UAAkB,EAAQ;QAClC,IAAI,CAAC,aAAa,IAAI,CAAC,mBAAmB,CAAC,UAAU,CAAC;YAAE,OAAO;QAC/D,KAAK,YAAY,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;IAAA,CAC3E;IACD,WAAW,CAAC,EAA4B,EAAQ;QAC/C,aAAa,GAAG,EAAE,CAAC;IAAA,CACnB;IACD,kBAAkB,GAA8B;QAC/C,OAAO,eAAe,EAAE,CAAC;IAAA,CACzB;IACD,aAAa,CAAC,UAAkB,EAAiC;QAChE,MAAM,MAAM,GAAG,cAAc,CAAC,aAAa,CAAC,UAAU,CAAC,EAAE,eAAe,EAAE,CAAC,CAAC;QAC5E,IAAI,CAAC,MAAM;YAAE,OAAO,SAAS,CAAC;QAC9B,OAAO,EAAE,KAAK,EAAE,eAAe,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,CAAC;IAAA,CAC3E;CACD,CAAC;AAEF,MAAM,UAAU,0BAA0B,CAAC,OAAqB,EAAE,eAAgC,EAAQ;IACzG,aAAa,GAAG,OAAO,CAAC;IACxB,mBAAmB,GAAG,eAAe,CAAC;IACrC,UAAsC,CAAC,2BAA2B,CAAC,GAAG,WAAW,CAAC;AAAA,CACnF;AAED,MAAM,UAAU,qBAAqB,GAAmC;IACvE,OAAQ,UAAsC,CAAC,2BAA2B,CAAmC,CAAC;AAAA,CAC9G","sourcesContent":["/**\n * Plan/subscription usage service. Per-provider adapters query provider quota\n * endpoints (60-second cache each) so /usage and the footer can show subscription windows\n * alongside session/context totals.\n *\n * Deliberately absent adapters:\n * - anthropic: Anthropic policy prohibits subscription usage tracking in\n * third-party coding agents (2026-07-18 decision). OAuth Anthropic sessions\n * fall back to hiding the cost meter.\n * - ollama-cloud: no usage API exists.\n *\n * Adapter/network errors resolve to `undefined` (callers omit the plan UI).\n * Auth failures are different: they return `error` and are not cached as empty.\n */\n\nimport { ModelsError } from \"@ashx-j/lunr-ai\";\nimport type { ModelRuntime } from \"./model-runtime.ts\";\nimport type { SettingsManager } from \"./settings-manager.ts\";\nimport { fetchKimiPlanUsage } from \"./usage-adapters/kimi-coding.ts\";\nimport { fetchCodexPlanUsage } from \"./usage-adapters/openai-codex.ts\";\nimport { fetchXaiPlanUsage } from \"./usage-adapters/xai.ts\";\nimport { fetchZaiPlanUsage } from \"./usage-adapters/zai.ts\";\n\nexport interface PlanUsageWindow {\n\tlabel: string;\n\tusedPercent: number;\n\t/** Epoch ms when the window resets. */\n\tresetsAt?: number;\n}\n\nexport interface PlanUsage {\n\tprovider: string;\n\tplanLabel?: string;\n\twindows: PlanUsageWindow[];\n}\n\nexport interface PlanUsageResult {\n\tusage?: PlanUsage;\n\t/** Actionable auth failure. Not cached as an empty success. */\n\terror?: string;\n}\n\nconst XAI_RELOGIN = \"xAI login expired. Run /login xai.\";\n\nfunction errorChain(error: unknown): string {\n\tconst parts: string[] = [];\n\tlet current: unknown = error;\n\tconst seen = new Set<unknown>();\n\twhile (current && typeof current === \"object\" && !seen.has(current)) {\n\t\tseen.add(current);\n\t\tif (current instanceof Error) {\n\t\t\tparts.push(current.message);\n\t\t\tcurrent = current.cause;\n\t\t\tcontinue;\n\t\t}\n\t\tbreak;\n\t}\n\treturn parts.join(\" \");\n}\n\n/** Classify adapter/getAuth failures that mean the SuperGrok session is dead. */\nexport function planUsageAuthError(error: unknown): string | undefined {\n\tconst chain = errorChain(error);\n\tif (/timed out|aborted|cancelled|ECONN|ENOTFOUND|network/i.test(chain)) return undefined;\n\t// 403 on billing is often entitlement, not a dead refresh token.\n\tif (/xai billing rejected the session \\(HTTP 401\\)/i.test(chain)) return XAI_RELOGIN;\n\tif (/invalid_grant|refresh token revoked/i.test(chain)) return XAI_RELOGIN;\n\treturn undefined;\n}\n\ntype UsageAdapter = (runtime: ModelRuntime) => Promise<PlanUsage | undefined>;\n\nconst ADAPTERS: Readonly<Record<string, UsageAdapter>> = {\n\t\"openai-codex\": fetchCodexPlanUsage,\n\t\"kimi-coding\": fetchKimiPlanUsage,\n\tzai: fetchZaiPlanUsage,\n\txai: fetchXaiPlanUsage,\n};\n\nexport const PLAN_USAGE_CACHE_TTL_MS = 60 * 1000;\n\nexport type PlanUsageWindowPreference = \"5h\" | \"weekly\";\n\nexport function isWeeklyPlanWindow(window: PlanUsageWindow): boolean {\n\treturn /week/i.test(window.label);\n}\n\nexport function isFiveHourPlanWindow(window: PlanUsageWindow): boolean {\n\treturn /5h/i.test(window.label) || window.label === \"5h\";\n}\n\n/** Preferred window, falling back to the other, skipping Extra/on-demand. */\nexport function pickPlanWindow(\n\tusage: PlanUsage | undefined,\n\tpreferred: PlanUsageWindowPreference,\n): PlanUsageWindow | undefined {\n\tif (!usage?.windows.length) return undefined;\n\tconst usable = usage.windows.filter((w) => !/extra/i.test(w.label));\n\tconst weekly = usable.find(isWeeklyPlanWindow);\n\tconst fiveH = usable.find(isFiveHourPlanWindow);\n\tif (preferred === \"5h\") return fiveH ?? weekly ?? usable[0] ?? usage.windows[0];\n\treturn weekly ?? fiveH ?? usable[0] ?? usage.windows[0];\n}\n\nexport function footerPlanLabel(window: PlanUsageWindow): string {\n\tif (isFiveHourPlanWindow(window)) return \"5h\";\n\tif (isWeeklyPlanWindow(window)) return \"wk\";\n\treturn window.label.length <= 4 ? window.label : window.label.slice(0, 4);\n}\n\nconst cache = new Map<string, { expiresAt: number; value: PlanUsage | undefined }>();\nconst inflight = new Map<string, Promise<PlanUsageResult>>();\n\n/** Whether a plan-usage adapter exists for this provider. */\nexport function hasPlanUsageAdapter(providerId: string): boolean {\n\treturn providerId in ADAPTERS;\n}\n\n/** Plan usage for a provider, or undefined when unsupported/unavailable. Never throws. */\nexport async function getPlanUsage(providerId: string, runtime: ModelRuntime): Promise<PlanUsage | undefined> {\n\treturn (await getPlanUsageResult(providerId, runtime)).usage;\n}\n\n/** Like getPlanUsage, but surfaces SuperGrok/auth failures instead of hiding them. */\nexport async function getPlanUsageResult(providerId: string, runtime: ModelRuntime): Promise<PlanUsageResult> {\n\tconst adapter = ADAPTERS[providerId];\n\tif (!adapter) return {};\n\tconst now = Date.now();\n\tconst cached = cache.get(providerId);\n\tif (cached && cached.expiresAt > now) return { usage: cached.value };\n\tconst pending = inflight.get(providerId);\n\tif (pending) return pending;\n\tconst task = (async (): Promise<PlanUsageResult> => {\n\t\ttry {\n\t\t\tconst value = await adapter(runtime);\n\t\t\tcache.set(providerId, { expiresAt: Date.now() + PLAN_USAGE_CACHE_TTL_MS, value });\n\t\t\treturn { usage: value };\n\t\t} catch (error) {\n\t\t\tconst authError = planUsageAuthError(error);\n\t\t\tif (authError) return { error: authError };\n\t\t\tcache.set(providerId, { expiresAt: Date.now() + PLAN_USAGE_CACHE_TTL_MS, value: undefined });\n\t\t\treturn {};\n\t\t} finally {\n\t\t\tinflight.delete(providerId);\n\t\t}\n\t})();\n\tinflight.set(providerId, task);\n\treturn task;\n}\n\n/** Last fetched usage, including expired cache (footer can show stale while refetching). */\nexport function peekPlanUsage(providerId: string): PlanUsage | undefined {\n\treturn cache.get(providerId)?.value;\n}\n\n/** Clear the adapter cache (tests, /login changes). */\nexport function clearPlanUsageCache(): void {\n\tcache.clear();\n\tinflight.clear();\n}\n\n// ---------------------------------------------------------------------------\n// Extension bridge\n// ---------------------------------------------------------------------------\n\nexport const USAGE_SERVICE_BRIDGE_SYMBOL = Symbol.for(\"@lunr/usage-service\");\n\nexport interface FooterPlanSegment {\n\tlabel: string;\n\tusedPercent: number;\n}\n\nexport interface UsageServiceBridge {\n\tpeek(providerId: string): PlanUsage | undefined;\n\tprefetch(providerId: string): void;\n\tgetPreferredWindow(): PlanUsageWindowPreference;\n\tpickForFooter(providerId: string): FooterPlanSegment | undefined;\n\tsetOnUpdate(fn: (() => void) | undefined): void;\n}\n\nlet activeRuntime: ModelRuntime | undefined;\nlet activeUsageSettings: SettingsManager | undefined;\nlet onUsageUpdate: (() => void) | undefined;\n\nfunction preferredWindow(): PlanUsageWindowPreference {\n\treturn activeUsageSettings?.getPlanUsageWindow() ?? \"weekly\";\n}\n\nconst usageBridge: UsageServiceBridge = {\n\tpeek(providerId: string): PlanUsage | undefined {\n\t\treturn peekPlanUsage(providerId);\n\t},\n\tprefetch(providerId: string): void {\n\t\tif (!activeRuntime || !hasPlanUsageAdapter(providerId)) return;\n\t\tvoid getPlanUsage(providerId, activeRuntime).then(() => onUsageUpdate?.());\n\t},\n\tsetOnUpdate(fn: (() => void) | undefined): void {\n\t\tonUsageUpdate = fn;\n\t},\n\tgetPreferredWindow(): PlanUsageWindowPreference {\n\t\treturn preferredWindow();\n\t},\n\tpickForFooter(providerId: string): FooterPlanSegment | undefined {\n\t\tconst window = pickPlanWindow(peekPlanUsage(providerId), preferredWindow());\n\t\tif (!window) return undefined;\n\t\treturn { label: footerPlanLabel(window), usedPercent: window.usedPercent };\n\t},\n};\n\nexport function registerUsageServiceBridge(runtime: ModelRuntime, settingsManager: SettingsManager): void {\n\tactiveRuntime = runtime;\n\tactiveUsageSettings = settingsManager;\n\t(globalThis as Record<symbol, unknown>)[USAGE_SERVICE_BRIDGE_SYMBOL] = usageBridge;\n}\n\nexport function getUsageServiceBridge(): UsageServiceBridge | undefined {\n\treturn (globalThis as Record<symbol, unknown>)[USAGE_SERVICE_BRIDGE_SYMBOL] as UsageServiceBridge | undefined;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"usage-service.js","sourceRoot":"","sources":["../../src/core/usage-service.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Plan/subscription usage service. Per-provider adapters query provider quota\n * endpoints (60-second cache each) so /usage and the footer can show subscription windows\n * alongside session/context totals.\n *\n * Deliberately absent adapters:\n * - anthropic: Anthropic policy prohibits subscription usage tracking in\n * third-party coding agents (2026-07-18 decision). OAuth Anthropic sessions\n * fall back to hiding the cost meter.\n * - ollama-cloud: no usage API exists.\n *\n * Adapter/network errors resolve to `undefined` (callers omit the plan UI).\n * Auth failures are different: they return `error` and are not cached as empty.\n */\n\nimport type { ModelRuntime } from \"./model-runtime.ts\";\nimport type { SettingsManager } from \"./settings-manager.ts\";\nimport { fetchKimiPlanUsage } from \"./usage-adapters/kimi-coding.ts\";\nimport { fetchCodexPlanUsage } from \"./usage-adapters/openai-codex.ts\";\nimport { fetchXaiPlanUsage } from \"./usage-adapters/xai.ts\";\nimport { fetchZaiPlanUsage } from \"./usage-adapters/zai.ts\";\n\nexport interface PlanUsageWindow {\n\tlabel: string;\n\tusedPercent: number;\n\t/** Epoch ms when the window resets. */\n\tresetsAt?: number;\n}\n\nexport interface PlanUsage {\n\tprovider: string;\n\tplanLabel?: string;\n\twindows: PlanUsageWindow[];\n}\n\nexport interface PlanUsageResult {\n\t/** First plan, kept for footer and compatibility callers. */\n\tusage?: PlanUsage;\n\t/** Every plan returned by the provider. */\n\tusages?: PlanUsage[];\n\t/** Actionable auth failure. Not cached as an empty success. */\n\terror?: string;\n}\n\nexport interface AllPlanUsageResult {\n\tusages: PlanUsage[];\n\terrors: string[];\n}\n\nconst XAI_RELOGIN = \"xAI login expired. Run /login xai.\";\n\nfunction errorChain(error: unknown): string {\n\tconst parts: string[] = [];\n\tlet current: unknown = error;\n\tconst seen = new Set<unknown>();\n\twhile (current && typeof current === \"object\" && !seen.has(current)) {\n\t\tseen.add(current);\n\t\tif (current instanceof Error) {\n\t\t\tparts.push(current.message);\n\t\t\tcurrent = current.cause;\n\t\t\tcontinue;\n\t\t}\n\t\tbreak;\n\t}\n\treturn parts.join(\" \");\n}\n\n/** Classify adapter/getAuth failures that mean the SuperGrok session is dead. */\nexport function planUsageAuthError(error: unknown): string | undefined {\n\tconst chain = errorChain(error);\n\tif (/timed out|aborted|cancelled|ECONN|ENOTFOUND|network/i.test(chain)) return undefined;\n\t// 403 on billing is often entitlement, not a dead refresh token.\n\tif (/xai billing rejected the session \\(HTTP 401\\)/i.test(chain)) return XAI_RELOGIN;\n\tif (/invalid_grant|refresh token revoked/i.test(chain)) return XAI_RELOGIN;\n\treturn undefined;\n}\n\ntype UsageAdapter = (runtime: ModelRuntime) => Promise<PlanUsage | PlanUsage[] | undefined>;\n\nconst ADAPTERS: Readonly<Record<string, UsageAdapter>> = {\n\t\"openai-codex\": fetchCodexPlanUsage,\n\t\"kimi-coding\": fetchKimiPlanUsage,\n\tzai: fetchZaiPlanUsage,\n\txai: fetchXaiPlanUsage,\n};\n\nexport const PLAN_USAGE_CACHE_TTL_MS = 60 * 1000;\n\nexport type PlanUsageWindowPreference = \"5h\" | \"weekly\";\n\nexport function isWeeklyPlanWindow(window: PlanUsageWindow): boolean {\n\treturn /week/i.test(window.label);\n}\n\nexport function isFiveHourPlanWindow(window: PlanUsageWindow): boolean {\n\treturn /5h/i.test(window.label) || window.label === \"5h\";\n}\n\n/** Preferred window, falling back to the other, skipping Extra/on-demand. */\nexport function pickPlanWindow(\n\tusage: PlanUsage | undefined,\n\tpreferred: PlanUsageWindowPreference,\n): PlanUsageWindow | undefined {\n\tif (!usage?.windows.length) return undefined;\n\tconst usable = usage.windows.filter((w) => !/extra/i.test(w.label));\n\tconst weekly = usable.find(isWeeklyPlanWindow);\n\tconst fiveH = usable.find(isFiveHourPlanWindow);\n\tif (preferred === \"5h\") return fiveH ?? weekly ?? usable[0] ?? usage.windows[0];\n\treturn weekly ?? fiveH ?? usable[0] ?? usage.windows[0];\n}\n\nexport function footerPlanLabel(window: PlanUsageWindow): string {\n\tif (isFiveHourPlanWindow(window)) return \"5h\";\n\tif (isWeeklyPlanWindow(window)) return \"wk\";\n\treturn window.label.length <= 4 ? window.label : window.label.slice(0, 4);\n}\n\nconst cache = new Map<string, { expiresAt: number; value: PlanUsage[] }>();\nconst inflight = new Map<string, Promise<PlanUsageResult>>();\n\n/** Whether a plan-usage adapter exists for this provider. */\nexport function hasPlanUsageAdapter(providerId: string): boolean {\n\treturn providerId in ADAPTERS;\n}\n\n/** Plan usage for a provider, or undefined when unsupported/unavailable. Never throws. */\nexport async function getPlanUsage(providerId: string, runtime: ModelRuntime): Promise<PlanUsage | undefined> {\n\treturn (await getPlanUsageResult(providerId, runtime)).usage;\n}\n\n/** Like getPlanUsage, but surfaces auth failures instead of hiding them. */\nexport async function getPlanUsageResult(providerId: string, runtime: ModelRuntime): Promise<PlanUsageResult> {\n\tconst adapter = ADAPTERS[providerId];\n\tif (!adapter) return {};\n\tconst now = Date.now();\n\tconst cached = cache.get(providerId);\n\tif (cached && cached.expiresAt > now) return { usage: cached.value[0], usages: cached.value };\n\tconst pending = inflight.get(providerId);\n\tif (pending) return pending;\n\tconst task = (async (): Promise<PlanUsageResult> => {\n\t\ttry {\n\t\t\tconst value = await adapter(runtime);\n\t\t\tconst usages = value === undefined ? [] : Array.isArray(value) ? value : [value];\n\t\t\tcache.set(providerId, { expiresAt: Date.now() + PLAN_USAGE_CACHE_TTL_MS, value: usages });\n\t\t\treturn { usage: usages[0], usages };\n\t\t} catch (error) {\n\t\t\tconst authError = planUsageAuthError(error);\n\t\t\tif (authError) return { error: authError };\n\t\t\tcache.set(providerId, { expiresAt: Date.now() + PLAN_USAGE_CACHE_TTL_MS, value: [] });\n\t\t\treturn {};\n\t\t} finally {\n\t\t\tinflight.delete(providerId);\n\t\t}\n\t})();\n\tinflight.set(providerId, task);\n\treturn task;\n}\n\n/** Fetch every stored-credential plan plus the current provider, in parallel. */\nexport async function getAllPlanUsageResults(\n\tcurrentProvider: string | undefined,\n\truntime: ModelRuntime,\n): Promise<AllPlanUsageResult> {\n\tconst stored = new Set((await runtime.listCredentials()).map((credential) => credential.providerId));\n\tconst providers = Object.keys(ADAPTERS).filter(\n\t\t(providerId) => stored.has(providerId) || providerId === currentProvider,\n\t);\n\tconst results = await Promise.all(providers.map((providerId) => getPlanUsageResult(providerId, runtime)));\n\treturn {\n\t\tusages: results.flatMap((result) => result.usages ?? []),\n\t\terrors: results.flatMap((result) => (result.error ? [`${result.error}`] : [])),\n\t};\n}\n\n/** Last fetched usage, including expired cache (footer can show stale while refetching). */\nexport function peekPlanUsage(providerId: string): PlanUsage | undefined {\n\treturn cache.get(providerId)?.value[0];\n}\n\n/** Clear the adapter cache (tests, /login changes). */\nexport function clearPlanUsageCache(): void {\n\tcache.clear();\n\tinflight.clear();\n}\n\n// ---------------------------------------------------------------------------\n// Extension bridge\n// ---------------------------------------------------------------------------\n\nexport const USAGE_SERVICE_BRIDGE_SYMBOL = Symbol.for(\"@lunr/usage-service\");\n\nexport interface FooterPlanSegment {\n\tlabel: string;\n\tusedPercent: number;\n}\n\nexport interface UsageServiceBridge {\n\tpeek(providerId: string): PlanUsage | undefined;\n\tprefetch(providerId: string): void;\n\tgetPreferredWindow(): PlanUsageWindowPreference;\n\tpickForFooter(providerId: string): FooterPlanSegment | undefined;\n\tsetOnUpdate(fn: (() => void) | undefined): void;\n}\n\nlet activeRuntime: ModelRuntime | undefined;\nlet activeUsageSettings: SettingsManager | undefined;\nlet onUsageUpdate: (() => void) | undefined;\n\nfunction preferredWindow(): PlanUsageWindowPreference {\n\treturn activeUsageSettings?.getPlanUsageWindow() ?? \"weekly\";\n}\n\nconst usageBridge: UsageServiceBridge = {\n\tpeek(providerId: string): PlanUsage | undefined {\n\t\treturn peekPlanUsage(providerId);\n\t},\n\tprefetch(providerId: string): void {\n\t\tif (!activeRuntime || !hasPlanUsageAdapter(providerId)) return;\n\t\tvoid getPlanUsage(providerId, activeRuntime).then(() => onUsageUpdate?.());\n\t},\n\tsetOnUpdate(fn: (() => void) | undefined): void {\n\t\tonUsageUpdate = fn;\n\t},\n\tgetPreferredWindow(): PlanUsageWindowPreference {\n\t\treturn preferredWindow();\n\t},\n\tpickForFooter(providerId: string): FooterPlanSegment | undefined {\n\t\tconst window = pickPlanWindow(peekPlanUsage(providerId), preferredWindow());\n\t\tif (!window) return undefined;\n\t\treturn { label: footerPlanLabel(window), usedPercent: window.usedPercent };\n\t},\n};\n\nexport function registerUsageServiceBridge(runtime: ModelRuntime, settingsManager: SettingsManager): void {\n\tactiveRuntime = runtime;\n\tactiveUsageSettings = settingsManager;\n\t(globalThis as Record<symbol, unknown>)[USAGE_SERVICE_BRIDGE_SYMBOL] = usageBridge;\n}\n\nexport function getUsageServiceBridge(): UsageServiceBridge | undefined {\n\treturn (globalThis as Record<symbol, unknown>)[USAGE_SERVICE_BRIDGE_SYMBOL] as UsageServiceBridge | undefined;\n}\n"]}
|