@hashimkarim/usagestat-linux-x64-gnu 2.0.0-alpha.1 → 2.0.0-alpha.4
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/LICENSE +0 -0
- package/native-manifest.json +1088 -134
- package/package.json +160 -1
- package/plugins/UPSTREAM-LICENSES.md +113 -0
- package/plugins/_provider-icons/LICENSE +21 -0
- package/plugins/_provider-icons/NOTICE +12 -0
- package/plugins/_provider-icons/licenses/CodexBar-MIT.txt +21 -0
- package/plugins/_provider-icons/licenses/LobeHub-MIT.txt +21 -0
- package/plugins/_provider-icons/licenses/UsageStat-Bar-MIT.txt +21 -0
- package/plugins/_provider-icons/manifest.json +1219 -0
- package/plugins/_provider-icons/provenance.json +269 -0
- package/plugins/_provider-icons/source.json +4 -0
- package/plugins/abacus-ai/icon-color.svg +18 -0
- package/plugins/abacus-ai/icon.svg +0 -0
- package/plugins/abacus-ai/plugin.js +0 -0
- package/plugins/abacus-ai/plugin.json +0 -0
- package/plugins/aiand/icon.svg +6 -0
- package/plugins/aiand/plugin.js +108 -0
- package/plugins/aiand/plugin.json +22 -0
- package/plugins/aixy/LICENSE +21 -0
- package/plugins/aixy/plugin.js +261 -0
- package/plugins/aixy/plugin.json +24 -0
- package/plugins/alibaba/icon-color.svg +0 -0
- package/plugins/alibaba/icon.svg +0 -0
- package/plugins/alibaba/plugin.js +0 -0
- package/plugins/alibaba/plugin.json +0 -0
- package/plugins/alibaba-token-plan/icon-color.svg +0 -0
- package/plugins/alibaba-token-plan/icon.svg +0 -0
- package/plugins/alibaba-token-plan/plugin.js +0 -0
- package/plugins/alibaba-token-plan/plugin.json +0 -0
- package/plugins/amp/icon-color.svg +0 -0
- package/plugins/amp/icon-conflict.svg +0 -0
- package/plugins/amp/icon.svg +0 -0
- package/plugins/amp/plugin.js +0 -0
- package/plugins/amp/plugin.json +0 -0
- package/plugins/antigravity/icon-color.svg +0 -0
- package/plugins/antigravity/icon-conflict.svg +0 -0
- package/plugins/antigravity/icon.svg +0 -0
- package/plugins/antigravity/plugin.js +136 -46
- package/plugins/antigravity/plugin.json +0 -0
- package/plugins/antigravity-cli/icon-color.svg +1 -0
- package/plugins/antigravity-cli/icon.svg +1 -3
- package/plugins/antigravity-cli/plugin.js +11 -15
- package/plugins/antigravity-cli/plugin.json +0 -0
- package/plugins/antigravity-ide/icon-color.svg +1 -0
- package/plugins/antigravity-ide/icon.svg +1 -3
- package/plugins/antigravity-ide/plugin.js +0 -0
- package/plugins/antigravity-ide/plugin.json +0 -0
- package/plugins/atlascloud/LICENSE +21 -0
- package/plugins/atlascloud/icon-color.svg +1 -0
- package/plugins/atlascloud/icon.svg +1 -0
- package/plugins/atlascloud/plugin.js +49 -0
- package/plugins/atlascloud/plugin.json +23 -0
- package/plugins/augment/icon-color.svg +14 -0
- package/plugins/augment/icon.svg +0 -0
- package/plugins/augment/plugin.js +0 -0
- package/plugins/augment/plugin.json +0 -0
- package/plugins/aws-bedrock/icon-color.svg +0 -0
- package/plugins/aws-bedrock/icon.svg +0 -0
- package/plugins/aws-bedrock/plugin.js +0 -0
- package/plugins/aws-bedrock/plugin.json +0 -0
- package/plugins/azure-openai/icon-color.svg +0 -0
- package/plugins/azure-openai/icon.svg +0 -0
- package/plugins/azure-openai/plugin.js +0 -0
- package/plugins/azure-openai/plugin.json +0 -0
- package/plugins/bifrost/LICENSE +21 -0
- package/plugins/bifrost/plugin.js +361 -0
- package/plugins/bifrost/plugin.json +23 -0
- package/plugins/chutes/icon.svg +0 -0
- package/plugins/chutes/plugin.js +0 -0
- package/plugins/chutes/plugin.json +0 -0
- package/plugins/claude/icon-color.svg +0 -0
- package/plugins/claude/icon.svg +0 -0
- package/plugins/claude/plugin.js +358 -161
- package/plugins/claude/plugin.json +1 -1
- package/plugins/clawrouter/icon.svg +7 -0
- package/plugins/clawrouter/plugin.js +45 -0
- package/plugins/clawrouter/plugin.json +22 -0
- package/plugins/clinepass/icon.svg +4 -0
- package/plugins/clinepass/plugin.js +87 -0
- package/plugins/clinepass/plugin.json +23 -0
- package/plugins/codebuddy/plugin.js +331 -0
- package/plugins/codebuddy/plugin.json +30 -0
- package/plugins/codebuff/icon-color.svg +92 -0
- package/plugins/codebuff/icon.svg +0 -0
- package/plugins/codebuff/plugin.js +0 -0
- package/plugins/codebuff/plugin.json +0 -0
- package/plugins/coderabbit/plugin.js +25 -0
- package/plugins/coderabbit/plugin.json +12 -0
- package/plugins/codex/icon-color.svg +0 -0
- package/plugins/codex/icon.svg +0 -0
- package/plugins/codex/plugin.js +8 -2
- package/plugins/codex/plugin.json +0 -0
- package/plugins/command-code/icon-color.svg +3 -0
- package/plugins/command-code/icon.svg +0 -0
- package/plugins/command-code/plugin.js +14 -3
- package/plugins/command-code/plugin.json +0 -0
- package/plugins/copilot/icon-color.svg +0 -0
- package/plugins/copilot/icon.svg +1 -1
- package/plugins/copilot/plugin.js +61 -9
- package/plugins/copilot/plugin.json +4 -1
- package/plugins/crof/icon-color.svg +3 -0
- package/plugins/crof/icon.svg +0 -0
- package/plugins/crof/plugin.js +0 -0
- package/plugins/crof/plugin.json +0 -0
- package/plugins/crofai/icon-color.svg +3 -0
- package/plugins/crofai/icon.svg +2 -15
- package/plugins/crofai/plugin.js +0 -0
- package/plugins/crofai/plugin.json +0 -0
- package/plugins/cursor/icon-color.svg +1 -0
- package/plugins/cursor/icon-conflict.svg +0 -0
- package/plugins/cursor/icon.svg +0 -0
- package/plugins/cursor/plugin.js +46 -9
- package/plugins/cursor/plugin.json +3 -2
- package/plugins/cursor-nightly/icon.png +0 -0
- package/plugins/cursor-nightly/plugin.js +45 -8
- package/plugins/cursor-nightly/plugin.json +3 -2
- package/plugins/deepgram/icon.svg +0 -0
- package/plugins/deepgram/plugin.js +0 -0
- package/plugins/deepgram/plugin.json +0 -0
- package/plugins/deepinfra/icon-color.svg +1 -0
- package/plugins/deepinfra/icon.svg +1 -0
- package/plugins/deepinfra/plugin.js +97 -0
- package/plugins/deepinfra/plugin.json +28 -0
- package/plugins/deepseek/icon-color.svg +0 -0
- package/plugins/deepseek/icon.svg +0 -0
- package/plugins/deepseek/plugin.js +150 -59
- package/plugins/deepseek/plugin.json +3 -1
- package/plugins/devin/icon.svg +0 -0
- package/plugins/devin/plugin.js +114 -0
- package/plugins/devin/plugin.json +2 -1
- package/plugins/devpass/LICENSE +21 -0
- package/plugins/devpass/plugin.js +115 -0
- package/plugins/devpass/plugin.json +23 -0
- package/plugins/doubao/icon-color.svg +0 -0
- package/plugins/doubao/icon.svg +0 -0
- package/plugins/doubao/plugin.js +0 -0
- package/plugins/doubao/plugin.json +0 -0
- package/plugins/droid/icon.svg +0 -0
- package/plugins/droid/plugin.json +2 -1
- package/plugins/elevenlabs/icon-color.svg +4 -0
- package/plugins/elevenlabs/icon.svg +0 -0
- package/plugins/elevenlabs/plugin.js +17 -2
- package/plugins/elevenlabs/plugin.json +0 -0
- package/plugins/factory/icon-color.svg +1 -0
- package/plugins/factory/icon-conflict.svg +0 -0
- package/plugins/factory/icon.svg +0 -0
- package/plugins/factory/plugin.js +38 -14
- package/plugins/factory/plugin.json +2 -1
- package/plugins/fireworks-ai/icon-color.svg +1 -0
- package/plugins/fireworks-ai/icon.svg +1 -6
- package/plugins/fireworks-ai/plugin.js +0 -0
- package/plugins/fireworks-ai/plugin.json +0 -0
- package/plugins/gemini/icon-color.svg +0 -0
- package/plugins/gemini/icon.svg +0 -0
- package/plugins/gemini/plugin.js +0 -0
- package/plugins/gemini/plugin.json +0 -0
- package/plugins/gemini-apps/LICENSE +22 -0
- package/plugins/gemini-apps/icon-color.svg +1 -0
- package/plugins/gemini-apps/icon.svg +1 -0
- package/plugins/gemini-apps/plugin.js +470 -0
- package/plugins/gemini-apps/plugin.json +19 -0
- package/plugins/gitkraken/LICENSE +21 -0
- package/plugins/gitkraken/plugin.js +153 -0
- package/plugins/gitkraken/plugin.json +24 -0
- package/plugins/grok/icon-color.svg +1 -0
- package/plugins/grok/icon.svg +0 -0
- package/plugins/grok/plugin.js +30 -5
- package/plugins/grok/plugin.json +3 -1
- package/plugins/groqcloud/icon-color.svg +1 -0
- package/plugins/groqcloud/icon.svg +0 -0
- package/plugins/groqcloud/plugin.js +0 -0
- package/plugins/groqcloud/plugin.json +0 -0
- package/plugins/helmcode/LICENSE +21 -0
- package/plugins/helmcode/plugin.js +188 -0
- package/plugins/helmcode/plugin.json +24 -0
- package/plugins/huggingface/LICENSE +21 -0
- package/plugins/huggingface/icon-color.svg +1 -0
- package/plugins/huggingface/icon.svg +1 -0
- package/plugins/huggingface/plugin.js +293 -0
- package/plugins/huggingface/plugin.json +25 -0
- package/plugins/hyper/LICENSE +21 -0
- package/plugins/hyper/plugin.js +131 -0
- package/plugins/hyper/plugin.json +26 -0
- package/plugins/ibmbob/icon.svg +23 -0
- package/plugins/ibmbob/plugin.js +61 -0
- package/plugins/ibmbob/plugin.json +22 -0
- package/plugins/jetbrains-ai-assistant/icon-color.svg +0 -0
- package/plugins/jetbrains-ai-assistant/icon-conflict.svg +0 -0
- package/plugins/jetbrains-ai-assistant/icon.svg +0 -0
- package/plugins/jetbrains-ai-assistant/plugin.js +0 -0
- package/plugins/jetbrains-ai-assistant/plugin.json +0 -0
- package/plugins/kilo/icon-color.svg +1 -0
- package/plugins/kilo/icon.svg +0 -0
- package/plugins/kilo/plugin.js +0 -0
- package/plugins/kilo/plugin.json +0 -0
- package/plugins/kimi/icon-color.svg +0 -0
- package/plugins/kimi/icon-conflict.svg +0 -0
- package/plugins/kimi/icon.svg +0 -0
- package/plugins/kimi/plugin.js +122 -141
- package/plugins/kimi/plugin.json +5 -2
- package/plugins/kimi-k2/icon-color.svg +0 -0
- package/plugins/kimi-k2/icon.svg +0 -0
- package/plugins/kimi-k2/plugin.js +0 -0
- package/plugins/kimi-k2/plugin.json +0 -0
- package/plugins/kiro/icon-color.svg +0 -0
- package/plugins/kiro/icon-conflict.svg +0 -0
- package/plugins/kiro/icon.svg +0 -0
- package/plugins/kiro/plugin.js +49 -10
- package/plugins/kiro/plugin.json +3 -1
- package/plugins/litellm/icon.svg +0 -0
- package/plugins/litellm/plugin.js +54 -3
- package/plugins/litellm/plugin.json +0 -0
- package/plugins/llm-proxy/icon.svg +0 -0
- package/plugins/llm-proxy/plugin.js +0 -0
- package/plugins/llm-proxy/plugin.json +0 -0
- package/plugins/llmman/LICENSE +21 -0
- package/plugins/llmman/plugin.js +133 -0
- package/plugins/llmman/plugin.json +23 -0
- package/plugins/longcat/icon-color.svg +1 -0
- package/plugins/longcat/icon.svg +1 -0
- package/plugins/longcat/plugin.js +182 -0
- package/plugins/longcat/plugin.json +23 -0
- package/plugins/manus/icon-color.svg +6 -0
- package/plugins/manus/icon.svg +0 -0
- package/plugins/manus/plugin.js +0 -0
- package/plugins/manus/plugin.json +0 -0
- package/plugins/mimo/icon-color.svg +4 -0
- package/plugins/mimo/icon.svg +4 -1
- package/plugins/mimo/plugin.js +0 -0
- package/plugins/mimo/plugin.json +0 -0
- package/plugins/minimax/icon-color.svg +0 -0
- package/plugins/minimax/icon-conflict.svg +0 -0
- package/plugins/minimax/icon.svg +0 -0
- package/plugins/minimax/plugin.js +25 -31
- package/plugins/minimax/plugin.json +0 -0
- package/plugins/mistral/icon-color.svg +0 -0
- package/plugins/mistral/icon.svg +0 -0
- package/plugins/mistral/plugin.js +110 -5
- package/plugins/mistral/plugin.json +0 -0
- package/plugins/moonshot/icon-color.svg +1 -0
- package/plugins/moonshot/icon.svg +0 -0
- package/plugins/moonshot/plugin.js +8 -6
- package/plugins/moonshot/plugin.json +0 -0
- package/plugins/muse/LICENSE +21 -0
- package/plugins/muse/plugin.js +319 -0
- package/plugins/muse/plugin.json +26 -0
- package/plugins/nanogpt/icon-color.svg +0 -0
- package/plugins/nanogpt/icon.svg +0 -0
- package/plugins/nanogpt/plugin.js +0 -0
- package/plugins/nanogpt/plugin.json +0 -0
- package/plugins/neuralwatt/icon.svg +0 -0
- package/plugins/neuralwatt/plugin.js +0 -0
- package/plugins/neuralwatt/plugin.json +0 -0
- package/plugins/notion/icon.svg +1 -0
- package/plugins/notion/plugin.js +282 -0
- package/plugins/notion/plugin.json +29 -0
- package/plugins/nous/LICENSE +21 -0
- package/plugins/nous/icon-color.svg +1 -0
- package/plugins/nous/icon.svg +1 -0
- package/plugins/nous/plugin.js +124 -0
- package/plugins/nous/plugin.json +24 -0
- package/plugins/ollama/icon-color.svg +1 -0
- package/plugins/ollama/icon.svg +0 -0
- package/plugins/ollama/plugin.js +257 -56
- package/plugins/ollama/plugin.json +6 -3
- package/plugins/openai-api/icon-color.svg +1 -0
- package/plugins/openai-api/icon.svg +0 -0
- package/plugins/openai-api/plugin.js +0 -0
- package/plugins/openai-api/plugin.json +0 -0
- package/plugins/opencode/icon-color.svg +1 -0
- package/plugins/opencode/icon.svg +0 -0
- package/plugins/opencode/plugin.js +0 -0
- package/plugins/opencode/plugin.json +0 -0
- package/plugins/opencode-go/icon-color.svg +1 -0
- package/plugins/opencode-go/icon-conflict.svg +0 -0
- package/plugins/opencode-go/icon.svg +0 -0
- package/plugins/opencode-go/plugin.js +103 -17
- package/plugins/opencode-go/plugin.json +5 -2
- package/plugins/openrouter/icon-color.svg +1 -0
- package/plugins/openrouter/icon.svg +0 -0
- package/plugins/openrouter/plugin.js +371 -114
- package/plugins/openrouter/plugin.json +6 -0
- package/plugins/perplexity/icon-color.svg +0 -0
- package/plugins/perplexity/icon-conflict.svg +0 -0
- package/plugins/perplexity/icon.svg +0 -0
- package/plugins/perplexity/plugin.js +0 -0
- package/plugins/perplexity/plugin.json +0 -0
- package/plugins/pi/plugin.js +113 -0
- package/plugins/pi/plugin.json +11 -0
- package/plugins/poe/icon.svg +0 -0
- package/plugins/poe/plugin.js +24 -18
- package/plugins/poe/plugin.json +2 -0
- package/plugins/qoder/icon.svg +3 -0
- package/plugins/qoder/plugin.js +227 -0
- package/plugins/qoder/plugin.json +23 -0
- package/plugins/qwencloud/icon-color.svg +1 -0
- package/plugins/qwencloud/icon.svg +1 -0
- package/plugins/qwencloud/plugin.js +677 -0
- package/plugins/qwencloud/plugin.json +29 -0
- package/plugins/raycast/LICENSE +21 -0
- package/plugins/raycast/plugin.js +174 -0
- package/plugins/raycast/plugin.json +24 -0
- package/plugins/replicate/LICENSE +21 -0
- package/plugins/replicate/icon-color.svg +1 -0
- package/plugins/replicate/icon.svg +1 -0
- package/plugins/replicate/plugin.js +165 -0
- package/plugins/replicate/plugin.json +24 -0
- package/plugins/sakana/icon.svg +5 -0
- package/plugins/sakana/plugin.js +156 -0
- package/plugins/sakana/plugin.json +23 -0
- package/plugins/stepfun/icon-color.svg +0 -0
- package/plugins/stepfun/icon.svg +0 -0
- package/plugins/stepfun/plugin.js +0 -0
- package/plugins/stepfun/plugin.json +0 -0
- package/plugins/sub2api/icon.svg +4 -0
- package/plugins/sub2api/plugin.js +191 -0
- package/plugins/sub2api/plugin.json +16 -0
- package/plugins/synthetic/icon-color.svg +14 -0
- package/plugins/synthetic/icon-conflict.svg +0 -0
- package/plugins/synthetic/icon.svg +0 -0
- package/plugins/synthetic/plugin.js +0 -0
- package/plugins/synthetic/plugin.json +0 -0
- package/plugins/t3chat/icon-color.svg +0 -0
- package/plugins/t3chat/icon.svg +0 -0
- package/plugins/t3chat/plugin.js +0 -0
- package/plugins/t3chat/plugin.json +0 -0
- package/plugins/typesafe/LICENSE +21 -0
- package/plugins/typesafe/plugin.js +225 -0
- package/plugins/typesafe/plugin.json +24 -0
- package/plugins/v0/LICENSE +21 -0
- package/plugins/v0/icon-color.svg +1 -0
- package/plugins/v0/icon.svg +1 -0
- package/plugins/v0/plugin.js +214 -0
- package/plugins/v0/plugin.json +24 -0
- package/plugins/venice/icon-color.svg +0 -0
- package/plugins/venice/icon.svg +0 -0
- package/plugins/venice/plugin.js +50 -1
- package/plugins/venice/plugin.json +2 -1
- package/plugins/vercel/LICENSE +21 -0
- package/plugins/vercel/icon-color.svg +1 -0
- package/plugins/vercel/icon.svg +1 -0
- package/plugins/vercel/plugin.js +55 -0
- package/plugins/vercel/plugin.json +23 -0
- package/plugins/vertex-ai/icon-color.svg +0 -0
- package/plugins/vertex-ai/icon.svg +0 -0
- package/plugins/vertex-ai/plugin.js +0 -0
- package/plugins/vertex-ai/plugin.json +0 -0
- package/plugins/warp/icon-color.svg +0 -0
- package/plugins/warp/icon.svg +0 -0
- package/plugins/warp/plugin.js +0 -0
- package/plugins/warp/plugin.json +0 -0
- package/plugins/wayfinder/icon.svg +5 -0
- package/plugins/wayfinder/plugin.js +47 -0
- package/plugins/wayfinder/plugin.json +16 -0
- package/plugins/windsurf/icon-color.svg +1 -0
- package/plugins/windsurf/icon-conflict.svg +0 -0
- package/plugins/windsurf/icon.svg +0 -0
- package/plugins/windsurf/plugin.js +0 -0
- package/plugins/windsurf/plugin.json +0 -0
- package/plugins/xai/icon-color.svg +1 -0
- package/plugins/xai/icon.svg +1 -0
- package/plugins/xai/plugin.js +162 -0
- package/plugins/xai/plugin.json +28 -0
- package/plugins/xkiro/LICENSE +21 -0
- package/plugins/xkiro/plugin.js +99 -0
- package/plugins/xkiro/plugin.json +23 -0
- package/plugins/zai/icon-color.svg +1 -0
- package/plugins/zai/icon-conflict.svg +0 -0
- package/plugins/zai/icon.svg +0 -0
- package/plugins/zai/plugin.js +111 -161
- package/plugins/zai/plugin.json +4 -1
- package/plugins/zed/icon.svg +0 -0
- package/plugins/zed/plugin.js +0 -0
- package/plugins/zed/plugin.json +0 -0
- package/plugins/zenmux/icon-color.svg +1 -0
- package/plugins/zenmux/icon.svg +1 -0
- package/plugins/zenmux/plugin.js +102 -0
- package/plugins/zenmux/plugin.json +23 -0
- package/plugins/zoommate/icon.svg +1 -0
- package/plugins/zoommate/plugin.js +244 -0
- package/plugins/zoommate/plugin.json +29 -0
- package/usagestat +0 -0
- package/usagestatd +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>DeepInfra</title><path d="M3.294 7.821A2.297 2.297 0 011 5.527a2.297 2.297 0 012.294-2.295A2.297 2.297 0 015.59 5.527 2.297 2.297 0 013.294 7.82zm0-3.688a1.396 1.396 0 000 2.79 1.396 1.396 0 000-2.79zM3.294 14.293A2.297 2.297 0 011 11.998a2.297 2.297 0 012.294-2.294 2.297 2.297 0 012.295 2.294 2.297 2.297 0 01-2.295 2.295zm0-3.688a1.395 1.395 0 000 2.788 1.395 1.395 0 100-2.788zM3.294 20.761A2.297 2.297 0 011 18.467a2.297 2.297 0 012.294-2.295 2.297 2.297 0 012.295 2.295 2.297 2.297 0 01-2.295 2.294zm0-3.688a1.396 1.396 0 000 2.79 1.396 1.396 0 000-2.79zM20.738 7.821a2.297 2.297 0 01-2.295-2.294 2.297 2.297 0 012.294-2.295 2.297 2.297 0 012.295 2.295 2.297 2.297 0 01-2.294 2.294zm0-3.688a1.396 1.396 0 101.395 1.395c0-.77-.626-1.395-1.395-1.395zM20.738 14.293a2.297 2.297 0 01-2.295-2.295 2.297 2.297 0 012.294-2.294 2.297 2.297 0 012.295 2.294 2.297 2.297 0 01-2.294 2.295zm0-3.688c-.769 0-1.395.625-1.395 1.393a1.396 1.396 0 002.79 0c0-.77-.626-1.393-1.395-1.393zM20.738 20.761a2.297 2.297 0 01-2.295-2.294 2.297 2.297 0 012.294-2.295 2.297 2.297 0 012.295 2.295 2.297 2.297 0 01-2.294 2.294zm0-3.688a1.396 1.396 0 101.395 1.395c0-.77-.626-1.395-1.395-1.395zM12.016 11.057a2.297 2.297 0 01-2.294-2.294 2.297 2.297 0 012.294-2.295 2.297 2.297 0 012.295 2.295 2.297 2.297 0 01-2.295 2.294zm0-3.688a1.396 1.396 0 101.395 1.395c0-.77-.625-1.395-1.395-1.395zM12.017 4.589a2.297 2.297 0 01-2.295-2.295A2.297 2.297 0 0112.017 0a2.297 2.297 0 012.294 2.294 2.297 2.297 0 01-2.294 2.295zm0-3.688a1.396 1.396 0 101.395 1.395c0-.77-.626-1.395-1.395-1.395zM12.017 17.529a2.297 2.297 0 01-2.295-2.295 2.297 2.297 0 012.295-2.294 2.297 2.297 0 012.294 2.294 2.297 2.297 0 01-2.294 2.295zm0-3.688a1.396 1.396 0 101.395 1.395c0-.77-.626-1.395-1.395-1.395zM12.016 24a2.297 2.297 0 01-2.294-2.295 2.297 2.297 0 012.294-2.294 2.297 2.297 0 012.295 2.294A2.297 2.297 0 0112.016 24zm0-3.688a1.396 1.396 0 101.395 1.395c0-.77-.625-1.395-1.395-1.395z" fill="#2A3275"></path><path d="M8.363 8.222a.742.742 0 01-.277-.053l-1.494-.596a.75.75 0 11.557-1.392l1.493.595a.75.75 0 01-.278 1.446h-.001zM8.363 14.566a.743.743 0 01-.277-.053l-1.494-.595a.75.75 0 11.557-1.393l1.493.596a.75.75 0 01-.278 1.445h-.001zM17.124 11.397a.741.741 0 01-.277-.054l-1.493-.595a.75.75 0 11.555-1.392l1.493.595a.75.75 0 01-.278 1.446zM17.124 5.05a.744.744 0 01-.277-.054L15.354 4.4a.75.75 0 01.555-1.392l1.493.596a.75.75 0 01-.278 1.445zM17.124 17.739a.743.743 0 01-.277-.053l-1.494-.596a.75.75 0 11.556-1.392l1.493.596a.75.75 0 01-.278 1.445zM6.91 17.966a.75.75 0 01-.279-1.445l1.494-.595a.749.749 0 11.556 1.392l-1.493.595a.743.743 0 01-.277.053H6.91zM6.91 11.66a.75.75 0 01-.279-1.446l1.494-.595a.75.75 0 01.556 1.392l-1.493.595a.743.743 0 01-.277.053H6.91zM6.91 5.033a.75.75 0 01-.279-1.446l1.494-.595a.75.75 0 01.556 1.392l-1.493.596a.744.744 0 01-.277.053H6.91zM8.363 21.364a.743.743 0 01-.277-.053l-1.494-.596a.75.75 0 01.555-1.392l1.494.595a.75.75 0 01-.278 1.446zM15.63 8.223a.75.75 0 01-.278-1.447l1.494-.595a.75.75 0 01.556 1.393l-1.494.595a.744.744 0 01-.276.054h-.002zM15.63 14.567a.75.75 0 01-.278-1.446l1.494-.596a.75.75 0 01.556 1.394l-1.494.595a.743.743 0 01-.276.053h-.002zM15.63 21.363a.749.749 0 01-.278-1.445l1.494-.595a.75.75 0 11.555 1.392l-1.494.595a.741.741 0 01-.277.053z" fill="#5699DB"></path></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>DeepInfra</title><path d="M3.294 7.821A2.297 2.297 0 011 5.527a2.297 2.297 0 012.294-2.295A2.297 2.297 0 015.59 5.527 2.297 2.297 0 013.294 7.82zm0-3.688a1.396 1.396 0 000 2.79 1.396 1.396 0 000-2.79zM3.294 14.293A2.297 2.297 0 011 11.998a2.297 2.297 0 012.294-2.294 2.297 2.297 0 012.295 2.294 2.297 2.297 0 01-2.295 2.295zm0-3.688a1.395 1.395 0 000 2.788 1.395 1.395 0 100-2.788zM3.294 20.761A2.297 2.297 0 011 18.467a2.297 2.297 0 012.294-2.295 2.297 2.297 0 012.295 2.295 2.297 2.297 0 01-2.295 2.294zm0-3.688a1.396 1.396 0 000 2.79 1.396 1.396 0 000-2.79zM20.738 7.821a2.297 2.297 0 01-2.295-2.294 2.297 2.297 0 012.294-2.295 2.297 2.297 0 012.295 2.295 2.297 2.297 0 01-2.294 2.294zm0-3.688a1.396 1.396 0 101.395 1.395c0-.77-.626-1.395-1.395-1.395zM20.738 14.293a2.297 2.297 0 01-2.295-2.295 2.297 2.297 0 012.294-2.294 2.297 2.297 0 012.295 2.294 2.297 2.297 0 01-2.294 2.295zm0-3.688c-.769 0-1.395.625-1.395 1.393a1.396 1.396 0 002.79 0c0-.77-.626-1.393-1.395-1.393zM20.738 20.761a2.297 2.297 0 01-2.295-2.294 2.297 2.297 0 012.294-2.295 2.297 2.297 0 012.295 2.295 2.297 2.297 0 01-2.294 2.294zm0-3.688a1.396 1.396 0 101.395 1.395c0-.77-.626-1.395-1.395-1.395zM12.016 11.057a2.297 2.297 0 01-2.294-2.294 2.297 2.297 0 012.294-2.295 2.297 2.297 0 012.295 2.295 2.297 2.297 0 01-2.295 2.294zm0-3.688a1.396 1.396 0 101.395 1.395c0-.77-.625-1.395-1.395-1.395zM12.017 4.589a2.297 2.297 0 01-2.295-2.295A2.297 2.297 0 0112.017 0a2.297 2.297 0 012.294 2.294 2.297 2.297 0 01-2.294 2.295zm0-3.688a1.396 1.396 0 101.395 1.395c0-.77-.626-1.395-1.395-1.395zM12.017 17.529a2.297 2.297 0 01-2.295-2.295 2.297 2.297 0 012.295-2.294 2.297 2.297 0 012.294 2.294 2.297 2.297 0 01-2.294 2.295zm0-3.688a1.396 1.396 0 101.395 1.395c0-.77-.626-1.395-1.395-1.395zM12.016 24a2.297 2.297 0 01-2.294-2.295 2.297 2.297 0 012.294-2.294 2.297 2.297 0 012.295 2.294A2.297 2.297 0 0112.016 24zm0-3.688a1.396 1.396 0 101.395 1.395c0-.77-.625-1.395-1.395-1.395z"></path><path d="M8.363 8.222a.742.742 0 01-.277-.053l-1.494-.596a.75.75 0 11.557-1.392l1.493.595a.75.75 0 01-.278 1.446h-.001zM8.363 14.566a.743.743 0 01-.277-.053l-1.494-.595a.75.75 0 11.557-1.393l1.493.596a.75.75 0 01-.278 1.445h-.001zM17.124 11.397a.741.741 0 01-.277-.054l-1.493-.595a.75.75 0 11.555-1.392l1.493.595a.75.75 0 01-.278 1.446zM17.124 5.05a.744.744 0 01-.277-.054L15.354 4.4a.75.75 0 01.555-1.392l1.493.596a.75.75 0 01-.278 1.445zM17.124 17.739a.743.743 0 01-.277-.053l-1.494-.596a.75.75 0 11.556-1.392l1.493.596a.75.75 0 01-.278 1.445zM6.91 17.966a.75.75 0 01-.279-1.445l1.494-.595a.749.749 0 11.556 1.392l-1.493.595a.743.743 0 01-.277.053H6.91zM6.91 11.66a.75.75 0 01-.279-1.446l1.494-.595a.75.75 0 01.556 1.392l-1.493.595a.743.743 0 01-.277.053H6.91zM6.91 5.033a.75.75 0 01-.279-1.446l1.494-.595a.75.75 0 01.556 1.392l-1.493.596a.744.744 0 01-.277.053H6.91zM8.363 21.364a.743.743 0 01-.277-.053l-1.494-.596a.75.75 0 01.555-1.392l1.494.595a.75.75 0 01-.278 1.446zM15.63 8.223a.75.75 0 01-.278-1.447l1.494-.595a.75.75 0 01.556 1.393l-1.494.595a.744.744 0 01-.276.054h-.002zM15.63 14.567a.75.75 0 01-.278-1.446l1.494-.596a.75.75 0 01.556 1.394l-1.494.595a.743.743 0 01-.276.053h-.002zM15.63 21.363a.749.749 0 01-.278-1.445l1.494-.595a.75.75 0 11.555 1.392l-1.494.595a.741.741 0 01-.277.053z"></path></svg>
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
(function () {
|
|
2
|
+
var CHECKLIST_URL = "https://api.deepinfra.com/payment/checklist?compute_owed=true";
|
|
3
|
+
var USAGE_URL = "https://api.deepinfra.com/payment/usage?from=current";
|
|
4
|
+
|
|
5
|
+
function clean(value) {
|
|
6
|
+
if (typeof value !== "string") return null;
|
|
7
|
+
var v = value.trim();
|
|
8
|
+
if (!v) return null;
|
|
9
|
+
if ((v[0] === "\"" && v[v.length - 1] === "\"") || (v[0] === "'" && v[v.length - 1] === "'")) v = v.slice(1, -1).trim();
|
|
10
|
+
if (v.slice(0, 7).toLowerCase() === "bearer ") v = v.slice(7).trim();
|
|
11
|
+
return v || null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function env(ctx, name) {
|
|
15
|
+
try {
|
|
16
|
+
return clean(ctx.host.env.get(name));
|
|
17
|
+
} catch (_) {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function apiKey(ctx) {
|
|
23
|
+
return clean(ctx.provider && ctx.provider.apiKey) || env(ctx, "DEEPINFRA_API_KEY") || env(ctx, "DEEPINFRA_TOKEN");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function requestJson(ctx, url, key, label, timeoutMs) {
|
|
27
|
+
var result = ctx.util.requestJson({
|
|
28
|
+
method: "GET",
|
|
29
|
+
url: url,
|
|
30
|
+
headers: { Authorization: "Bearer " + key, Accept: "application/json" },
|
|
31
|
+
timeoutMs: timeoutMs || 15000,
|
|
32
|
+
});
|
|
33
|
+
if (result.resp.status === 401) throw "DeepInfra API key rejected.";
|
|
34
|
+
if (result.resp.status === 403) throw "DeepInfra API key cannot access billing data.";
|
|
35
|
+
if (result.resp.status < 200 || result.resp.status >= 300) throw "DeepInfra " + label + " API error: HTTP " + result.resp.status + ".";
|
|
36
|
+
if (!result.json || typeof result.json !== "object") throw "Failed to parse DeepInfra " + label + " response.";
|
|
37
|
+
return result.json;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function number(value) {
|
|
41
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
42
|
+
if (typeof value === "string" && value.trim()) {
|
|
43
|
+
var parsed = Number(value.replace(/,/g, ""));
|
|
44
|
+
if (Number.isFinite(parsed)) return parsed;
|
|
45
|
+
}
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function probe(ctx) {
|
|
50
|
+
var key = apiKey(ctx);
|
|
51
|
+
if (!key) throw "DeepInfra API key not found. Set DEEPINFRA_API_KEY, DEEPINFRA_TOKEN, or provider apiKey.";
|
|
52
|
+
|
|
53
|
+
var checklist = requestJson(ctx, CHECKLIST_URL, key, "billing");
|
|
54
|
+
var recent = number(checklist.recent);
|
|
55
|
+
var stripeBalance = number(checklist.stripe_balance);
|
|
56
|
+
if (recent === null || recent < 0 || stripeBalance === null) throw "DeepInfra returned invalid billing amounts.";
|
|
57
|
+
var currentMonth = null;
|
|
58
|
+
try {
|
|
59
|
+
var usage = requestJson(ctx, USAGE_URL, key, "usage", 3000);
|
|
60
|
+
if (Array.isArray(usage.months) && usage.months.length) {
|
|
61
|
+
var cents = number(usage.months[usage.months.length - 1].total_cost);
|
|
62
|
+
if (cents !== null && cents >= 0) currentMonth = cents / 100;
|
|
63
|
+
}
|
|
64
|
+
} catch (error) {
|
|
65
|
+
ctx.host.log.warn("DeepInfra monthly usage unavailable: " + String(error));
|
|
66
|
+
}
|
|
67
|
+
var netBalance = stripeBalance + recent;
|
|
68
|
+
var available = Math.max(0, -netBalance);
|
|
69
|
+
var owed = Math.max(0, netBalance);
|
|
70
|
+
var limit = number(checklist.limit);
|
|
71
|
+
var suspended = checklist.suspended === true;
|
|
72
|
+
var balanceText = owed > 0 ? "$" + owed.toFixed(2) + " owed" : "$" + available.toFixed(2) + " available";
|
|
73
|
+
var detail = balanceText + (currentMonth === null ? "" : " · $" + currentMonth.toFixed(2) + " spent this month");
|
|
74
|
+
if (suspended) detail = "Suspended" + (checklist.suspend_reason ? ": " + checklist.suspend_reason : "") + " · " + detail;
|
|
75
|
+
|
|
76
|
+
var metrics = [];
|
|
77
|
+
if (limit > 0 && Number.isFinite(limit)) {
|
|
78
|
+
metrics.push(ctx.line.progress({
|
|
79
|
+
label: "Billing Cycle",
|
|
80
|
+
used: Math.max(0, recent),
|
|
81
|
+
limit: limit,
|
|
82
|
+
format: { kind: "dollars" },
|
|
83
|
+
detail: detail,
|
|
84
|
+
}));
|
|
85
|
+
} else {
|
|
86
|
+
metrics.push(ctx.line.text({ label: "Balance", value: balanceText }));
|
|
87
|
+
}
|
|
88
|
+
if (currentMonth !== null) metrics.push(ctx.line.text({ label: "Month Cost", value: "$" + currentMonth.toFixed(2) }));
|
|
89
|
+
if (suspended || owed > 0 || available <= 0) {
|
|
90
|
+
metrics.push(ctx.line.badge({ label: "Status", text: suspended ? "Suspended" : "No prepaid balance", color: "#ef4444" }));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return { displayName: "DeepInfra", source: "api", lines: metrics };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
globalThis.__openusage_plugin = { id: "deepinfra", probe: probe };
|
|
97
|
+
})();
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"id": "deepinfra",
|
|
4
|
+
"name": "DeepInfra",
|
|
5
|
+
"version": "0.1.0",
|
|
6
|
+
"entry": "plugin.js",
|
|
7
|
+
"enabledByDefault": false,
|
|
8
|
+
"supportedModes": [
|
|
9
|
+
"api"
|
|
10
|
+
],
|
|
11
|
+
"autoMode": "api",
|
|
12
|
+
"usageDashboardUrl": "https://deepinfra.com/dash",
|
|
13
|
+
"statusPageUrl": "https://status.deepinfra.com",
|
|
14
|
+
"links": [
|
|
15
|
+
{
|
|
16
|
+
"label": "Dashboard",
|
|
17
|
+
"url": "https://deepinfra.com/dash"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"label": "Status",
|
|
21
|
+
"url": "https://status.deepinfra.com"
|
|
22
|
+
}
|
|
23
|
+
],
|
|
24
|
+
"envVars": [
|
|
25
|
+
"DEEPINFRA_API_KEY",
|
|
26
|
+
"DEEPINFRA_TOKEN"
|
|
27
|
+
]
|
|
28
|
+
}
|
|
File without changes
|
|
File without changes
|
|
@@ -1,71 +1,162 @@
|
|
|
1
1
|
(function () {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
}
|
|
10
|
-
return null;
|
|
2
|
+
const PLATFORM = 'https://platform.deepseek.com/api/v0/';
|
|
3
|
+
const own = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
|
|
4
|
+
const clean = value => typeof value === 'string' && value.trim() ? value.trim().replace(/^Bearer\s+/i, '') : null;
|
|
5
|
+
function amount(value) {
|
|
6
|
+
if (typeof value !== 'number' && typeof value !== 'string' || typeof value === 'string' && !value.trim()) return null;
|
|
7
|
+
const n = Number(value);
|
|
8
|
+
return Number.isFinite(n) && n >= 0 ? n : null;
|
|
11
9
|
}
|
|
12
|
-
|
|
13
|
-
function
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
10
|
+
function fail(code, message) { throw {code, message}; }
|
|
11
|
+
function request(ctx, url, token, timeoutMs) {
|
|
12
|
+
const result = ctx.util.requestJson({method:'GET', url, timeoutMs,
|
|
13
|
+
headers:{Authorization:'Bearer '+token, Accept:'application/json', 'x-client-platform':'web'}});
|
|
14
|
+
const body = result.json;
|
|
15
|
+
if ([401,403].includes(result.resp.status) || [40002,40003].includes(body?.code) || [40002,40003].includes(body?.data?.biz_code))
|
|
16
|
+
fail('credential-rejected', 'DeepSeek credential expired. Sign in again.');
|
|
17
|
+
if (result.resp.status === 429) fail('failed', 'DeepSeek is rate limited.');
|
|
18
|
+
if (result.resp.status < 200 || result.resp.status >= 300 || !body || body.code && body.code !== 0 || body.data?.biz_code && body.data.biz_code !== 0)
|
|
19
|
+
fail('failed', 'DeepSeek request failed (HTTP '+result.resp.status+').');
|
|
20
|
+
return body;
|
|
21
|
+
}
|
|
22
|
+
function choose(values) {
|
|
23
|
+
return values.find(v => v.currency === 'USD' && v.total > 0) || values.find(v => v.total > 0) || values.find(v => v.currency === 'USD') || values[0];
|
|
24
|
+
}
|
|
25
|
+
function balance(ctx, key, token) {
|
|
26
|
+
if (key) {
|
|
27
|
+
const data = request(ctx, 'https://api.deepseek.com/user/balance', key, 15000);
|
|
28
|
+
if (!Array.isArray(data.balance_infos)) fail('failed', 'DeepSeek balance response changed.');
|
|
29
|
+
const values = data.balance_infos.map(value => ({currency:String(value.currency || '').toUpperCase(), total:amount(value.total_balance),
|
|
30
|
+
paid:amount(value.topped_up_balance), granted:amount(value.granted_balance)}));
|
|
31
|
+
if (values.some(v => !v.currency || v.total === null || v.paid === null || v.granted === null)) fail('failed', 'DeepSeek returned an invalid balance.');
|
|
32
|
+
return {value:choose(values), available:data.is_available !== false};
|
|
17
33
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
34
|
+
const data = request(ctx, PLATFORM+'users/get_user_summary', token, 15000).data?.biz_data;
|
|
35
|
+
if (!data || !Array.isArray(data.normal_wallets) || !Array.isArray(data.bonus_wallets)) fail('failed', 'DeepSeek wallet response changed.');
|
|
36
|
+
const values = new Map();
|
|
37
|
+
for (const [field, wallets] of [['paid',data.normal_wallets],['granted',data.bonus_wallets]]) {
|
|
38
|
+
for (const wallet of wallets) {
|
|
39
|
+
const currency = String(wallet.currency || '').toUpperCase(), value = amount(wallet.balance);
|
|
40
|
+
if (!currency || value === null) fail('failed', 'DeepSeek returned an invalid wallet.');
|
|
41
|
+
if (!values.has(currency)) values.set(currency,{currency,total:0,paid:0,granted:0});
|
|
42
|
+
values.get(currency)[field] += value;
|
|
43
|
+
values.get(currency).total += value;
|
|
44
|
+
}
|
|
28
45
|
}
|
|
29
|
-
|
|
30
|
-
|
|
46
|
+
return {value:choose([...values.values()]),available:true};
|
|
47
|
+
}
|
|
48
|
+
function details(ctx, token, lines) {
|
|
49
|
+
const now = new Date(ctx.nowIso), end = Date.parse(ctx.nowIso.slice(0,10)) + 86400000, start = end - 30*86400000;
|
|
50
|
+
const deadline = Date.now() + 5000;
|
|
51
|
+
const fetch = suffix => {
|
|
52
|
+
const left = deadline - Date.now();
|
|
53
|
+
if (left <= 0) fail('failed','DeepSeek detail deadline exceeded.');
|
|
54
|
+
return request(ctx, PLATFORM+'usage/'+suffix, token, Math.min(1500,left)).data?.biz_data;
|
|
55
|
+
};
|
|
56
|
+
let amounts, costs, monthly = false;
|
|
57
|
+
try {
|
|
58
|
+
const query = '?start='+Math.floor(start/1000)+'&end='+Math.floor(end/1000)+'&tz=0';
|
|
59
|
+
amounts = fetch('by_api_key/amount'+query);
|
|
60
|
+
costs = fetch('by_api_key/cost'+query);
|
|
61
|
+
if (!Array.isArray(amounts?.series) || !Array.isArray(costs?.data)) throw new Error('Unrecognized series');
|
|
62
|
+
} catch (error) {
|
|
63
|
+
if (error?.code === 'credential-rejected' || /rate limited/.test(error?.message || '')) throw error;
|
|
64
|
+
monthly = true;
|
|
65
|
+
const query = '?month='+(now.getUTCMonth()+1)+'&year='+now.getUTCFullYear();
|
|
66
|
+
amounts = fetch('amount'+query);
|
|
67
|
+
costs = fetch('cost'+query);
|
|
68
|
+
if (!Array.isArray(amounts?.days) || !Array.isArray(costs)) throw new Error('Unrecognized monthly usage');
|
|
31
69
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
70
|
+
const blocks = monthly ? costs : costs.data;
|
|
71
|
+
const block = blocks.find(b => b.currency === 'USD') || blocks[0];
|
|
72
|
+
if (!block || typeof block.currency !== 'string') throw new Error('Unknown currency');
|
|
73
|
+
const currency = block.currency.toUpperCase(), days = new Map(), models = new Map(), keys = new Set();
|
|
74
|
+
const lower = monthly ? ctx.nowIso.slice(0,7)+'-01' : new Date(start).toISOString().slice(0,10), upper = ctx.nowIso.slice(0,10);
|
|
75
|
+
function day(date) {
|
|
76
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(date) || date < lower || date > upper || new Date(date).toISOString().slice(0,10) !== date) return null;
|
|
77
|
+
if (!days.has(date)) days.set(date,{date,inputTokens:0,outputTokens:0,cacheReadTokens:0,totalTokens:0,costUsd:0,
|
|
78
|
+
requests:0,tokensKnown:false,costKnown:false,amountSeen:false,costSeen:false,badTokens:false,badCost:false});
|
|
79
|
+
return days.get(date);
|
|
38
80
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
81
|
+
function addAmount(date, usage) {
|
|
82
|
+
const row = day(date);
|
|
83
|
+
if (!row || !usage || typeof usage !== 'object') return;
|
|
84
|
+
for (const [type, field] of [['PROMPT_CACHE_MISS_TOKEN','inputTokens'],['PROMPT_CACHE_HIT_TOKEN','cacheReadTokens'],['RESPONSE_TOKEN','outputTokens'],['REQUEST','requests']]) {
|
|
85
|
+
if (!own(usage,type)) continue;
|
|
86
|
+
const value = amount(usage[type]);
|
|
87
|
+
if (value === null || !Number.isSafeInteger(value)) { row.badTokens=true; continue; }
|
|
88
|
+
row[field] += value;
|
|
89
|
+
if (field !== 'requests') { row.totalTokens += value; row.amountSeen=true; }
|
|
90
|
+
}
|
|
45
91
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
if (!
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
92
|
+
function addCost(date, model, raw) {
|
|
93
|
+
const row = day(date), value = amount(raw);
|
|
94
|
+
if (!row) return;
|
|
95
|
+
if (value === null) { row.badCost=true; if(model) models.set(model,null); return; }
|
|
96
|
+
row.costUsd += value; row.costSeen=true;
|
|
97
|
+
if (model && models.get(model) !== null) models.set(model,(models.get(model)||0)+value);
|
|
98
|
+
}
|
|
99
|
+
const dateFor = time => typeof time === 'number' && time*1000 >= start && time*1000 < end ? new Date(time*1000).toISOString().slice(0,10) : '';
|
|
100
|
+
if (!monthly) {
|
|
101
|
+
if (amounts.series.length > 10000 || !Array.isArray(block.series) || block.series.length > 10000) throw new Error('Too many series');
|
|
102
|
+
for (const series of amounts.series) {
|
|
103
|
+
if (series.api_key) keys.add(JSON.stringify(series.api_key));
|
|
104
|
+
if (!Array.isArray(series.buckets) || series.buckets.length > 32) throw new Error('Invalid buckets');
|
|
105
|
+
for (const bucket of series.buckets) addAmount(dateFor(bucket.time),bucket.usage);
|
|
106
|
+
}
|
|
107
|
+
for (const series of block.series) {
|
|
108
|
+
if (series.api_key) keys.add(JSON.stringify(series.api_key));
|
|
109
|
+
if (!Array.isArray(series.buckets) || series.buckets.length > 32) throw new Error('Invalid buckets');
|
|
110
|
+
for (const bucket of series.buckets) addCost(dateFor(bucket.time),series.model,bucket.cost);
|
|
111
|
+
}
|
|
58
112
|
} else {
|
|
59
|
-
|
|
113
|
+
for (const item of amounts.days.slice(0,32)) for (const model of (item.data || []).slice(0,1000))
|
|
114
|
+
addAmount(item.date, Object.fromEntries((model.usage || []).map(value => [value.type,value.amount])));
|
|
115
|
+
for (const item of (block.days || []).slice(0,32)) for (const model of (item.data || []).slice(0,1000))
|
|
116
|
+
for (const value of model.usage || []) addCost(item.date,model.model,value.amount);
|
|
117
|
+
}
|
|
118
|
+
const daily = [...days.values()].sort((a,b)=>a.date.localeCompare(b.date));
|
|
119
|
+
for (const row of daily) {
|
|
120
|
+
row.tokensKnown = row.amountSeen && !row.badTokens && Number.isSafeInteger(row.totalTokens);
|
|
121
|
+
row.costKnown = row.costSeen && !row.badCost && Number.isFinite(row.costUsd);
|
|
122
|
+
if (!Number.isFinite(row.costUsd)) throw new Error('Cost overflow');
|
|
123
|
+
delete row.amountSeen; delete row.costSeen; delete row.badTokens; delete row.badCost;
|
|
60
124
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
if
|
|
64
|
-
|
|
125
|
+
if (!daily.length) return;
|
|
126
|
+
const total = daily.reduce((sum,row)=>sum+row.costUsd,0), complete = daily.every(row=>row.costKnown);
|
|
127
|
+
if(!Number.isFinite(total)) throw new Error('Cost overflow');
|
|
128
|
+
const usageLines = [
|
|
129
|
+
ctx.line.text({label:monthly?'This month':'Last 30 days',value:currency+' '+total.toFixed(2)+(complete?'':'+'),subtitle:'Platform-account spend across API keys'}),
|
|
130
|
+
ctx.line.text({label:'Tokens',value:String(daily.reduce((sum,row)=>sum+row.totalTokens,0))+(daily.every(row=>row.tokensKnown)?'':'+')}),
|
|
131
|
+
ctx.line.text({label:'Requests',value:String(daily.reduce((sum,row)=>sum+row.requests,0))})
|
|
132
|
+
];
|
|
133
|
+
if(keys.size) usageLines.push(ctx.line.text({label:'API keys',value:String(keys.size)}));
|
|
134
|
+
for(const [model,cost] of [...models].filter(([,v])=>v!==null && Number.isFinite(v)).sort((a,b)=>b[1]-a[1]).slice(0,30))
|
|
135
|
+
usageLines.push(ctx.line.text({label:model,value:currency+' '+cost.toFixed(2)}));
|
|
136
|
+
usageLines.push(ctx.line.barChart({label:'Daily tokens',points:daily.map(row=>({label:row.date,value:row.totalTokens}))}));
|
|
137
|
+
usageLines.push(ctx.line.barChart({label:'Daily spend',points:daily.filter(row=>row.costKnown).map(row=>({label:row.date,value:row.costUsd,valueLabel:currency+' '+row.costUsd.toFixed(2)}))}));
|
|
138
|
+
// The shared ledger is USD-only; never relabel CNY spend as dollars.
|
|
139
|
+
const stored = daily.map(row=>currency==='USD'?row:{...row,costUsd:0,costKnown:false});
|
|
140
|
+
ctx.host.usageDaily.ingest({displayName:'DeepSeek',source:'deepseek_platform',daily:stored});
|
|
141
|
+
lines.push(...usageLines);
|
|
142
|
+
}
|
|
143
|
+
function probe(ctx) {
|
|
144
|
+
const provider = ctx.provider || {}, settings = provider.settings || {}, scoped = provider.instanceId && provider.instanceId !== 'deepseek';
|
|
145
|
+
const env = key => scoped ? null : clean(ctx.host.env.get(key));
|
|
146
|
+
const key = ctx.sourceMode === 'web' ? null : own(provider,'apiKey') ? clean(provider.apiKey) : env('DEEPSEEK_API_KEY') || env('DEEPSEEK_KEY');
|
|
147
|
+
const token = own(settings,'platformToken') ? clean(settings.platformToken) : own(provider,'cookieHeader') ? clean(provider.cookieHeader) : env('DEEPSEEK_PLATFORM_TOKEN') || env('DEEPSEEK_USER_TOKEN');
|
|
148
|
+
if (!key && !token || ctx.sourceMode === 'api' && !key) fail('missing-auth','Set a DeepSeek API key or a Platform token in web mode.');
|
|
149
|
+
const data = balance(ctx,key,token), lines = [], value = data.value;
|
|
150
|
+
if (value) lines.push(ctx.line.text({label:'Balance',value:value.currency+' '+value.total.toFixed(2),
|
|
151
|
+
subtitle:'Paid: '+value.paid.toFixed(2)+' / Granted: '+value.granted.toFixed(2)}));
|
|
152
|
+
else lines.push(ctx.line.badge({label:'Balance',text:'No balance data',color:'#a3a3a3'}));
|
|
153
|
+
if (!data.available) lines.push(ctx.line.badge({label:'Status',text:'Balance unavailable for API calls',color:'#ef4444'}));
|
|
154
|
+
// Pair website totals only with an explicitly bound API key, never ambient account state.
|
|
155
|
+
if (token && (!key || own(settings,'platformToken') && settings.platformApiKeyHash === ctx.host.crypto.sha256(key)) && settings.extraUsage !== false) {
|
|
156
|
+
try { details(ctx,token,lines); }
|
|
157
|
+
catch (_) { lines.push(ctx.line.text({label:'Details',value:'Detailed usage unavailable'})); }
|
|
65
158
|
}
|
|
66
|
-
|
|
67
|
-
return { lines: lines };
|
|
159
|
+
return {source:key?'api':'web',lines};
|
|
68
160
|
}
|
|
69
|
-
|
|
70
|
-
globalThis.__openusage_plugin = { id: "deepseek", probe: probe };
|
|
161
|
+
globalThis.__openusage_plugin = {id:'deepseek',probe};
|
|
71
162
|
})();
|
|
@@ -9,8 +9,10 @@
|
|
|
9
9
|
{ "label": "Platform", "url": "https://platform.deepseek.com/usage" }
|
|
10
10
|
],
|
|
11
11
|
"usageDashboardUrl": "https://platform.deepseek.com/usage",
|
|
12
|
-
"supportedModes": ["api"],
|
|
12
|
+
"supportedModes": ["api", "web"],
|
|
13
13
|
"autoMode": "api",
|
|
14
|
+
"webUrl": "https://platform.deepseek.com",
|
|
15
|
+
"envVars": ["DEEPSEEK_API_KEY", "DEEPSEEK_KEY", "DEEPSEEK_PLATFORM_TOKEN", "DEEPSEEK_USER_TOKEN"],
|
|
14
16
|
"lines": [
|
|
15
17
|
{ "type": "text", "label": "Balance", "scope": "overview" }
|
|
16
18
|
]
|
package/plugins/devin/icon.svg
CHANGED
|
File without changes
|
package/plugins/devin/plugin.js
CHANGED
|
@@ -273,8 +273,11 @@
|
|
|
273
273
|
var hideDailyQuota = planInfo.hideDailyQuota === true
|
|
274
274
|
var dailyRemaining = readFiniteNumber(planStatus.dailyQuotaRemainingPercent)
|
|
275
275
|
var weeklyRemaining = readFiniteNumber(planStatus.weeklyQuotaRemainingPercent)
|
|
276
|
+
if (Object.prototype.hasOwnProperty.call(planStatus, "weeklyQuotaRemainingPercent") && weeklyRemaining === null) throw QUOTA_HINT
|
|
276
277
|
var dailyReset = !hideDailyQuota ? unixSecondsToIso(ctx, planStatus.dailyQuotaResetAtUnix) : null
|
|
277
278
|
var weeklyReset = unixSecondsToIso(ctx, planStatus.weeklyQuotaResetAtUnix)
|
|
279
|
+
// Proto3 omits a zero remaining percentage; a reset identifies the exhausted window.
|
|
280
|
+
if (weeklyRemaining === null && weeklyReset) weeklyRemaining = 0
|
|
278
281
|
var extraUsageBalance = formatDollarsFromMicros(planStatus.overageBalanceMicros)
|
|
279
282
|
|
|
280
283
|
var dailyLine = !hideDailyQuota
|
|
@@ -305,8 +308,119 @@
|
|
|
305
308
|
return auth.apiKey + "\n" + effectiveApiServerUrl(auth)
|
|
306
309
|
}
|
|
307
310
|
|
|
311
|
+
function firstPresent(values) {
|
|
312
|
+
for (var i = 0; i < values.length; i++) if (values[i] !== null && values[i] !== undefined) return values[i]
|
|
313
|
+
return null
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function manualOrganization(raw) {
|
|
317
|
+
if (typeof raw !== "string") throw {code: "missing-auth", message: "Set Devin workspace_id or DEVIN_ORGANIZATION to the intended organization."}
|
|
318
|
+
var value = raw.trim().replace(/^\/+|\/+$/g, "")
|
|
319
|
+
if (/^https:\/\//i.test(value)) {
|
|
320
|
+
var url = /^https:\/\/(?:[a-z0-9-]+\.)*devin\.ai\/(org|organizations)\/([^/?#]+)(?:[/?#].*)?$/i.exec(value)
|
|
321
|
+
if (!url) throw {code: "failed", message: "Use an app.devin.ai organization URL, organization ID, or slug."}
|
|
322
|
+
value = url[1].toLowerCase() + "/" + url[2]
|
|
323
|
+
}
|
|
324
|
+
var parts = value.split("/")
|
|
325
|
+
var id = parts.length === 1 ? parts[0] : parts[1]
|
|
326
|
+
if (parts.length > 2 || (parts.length === 2 && !/^(org|organizations)$/.test(parts[0])) || !/^[a-z0-9][a-z0-9_.-]*$/i.test(id)) {
|
|
327
|
+
throw {code: "failed", message: "Invalid Devin organization; use an organization ID, slug, or app.devin.ai organization URL."}
|
|
328
|
+
}
|
|
329
|
+
var internal = parts.length === 2 ? parts[0] === "organizations" : /^org[-_]/.test(id)
|
|
330
|
+
return { id: id, internal: internal, path: (internal ? "organizations/" : "org/") + id }
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
function manualQuotaPercent(value) {
|
|
334
|
+
var number = readFiniteNumber(value)
|
|
335
|
+
if (number !== null) return number <= 1 ? number * 100 : number
|
|
336
|
+
if (!value || typeof value !== "object") return null
|
|
337
|
+
var usedPercent = firstPresent([value.used_percent, value.usedPercent, value.usage_percent, value.usagePercent, value.percent_used, value.percentUsed, value.percent])
|
|
338
|
+
if (usedPercent !== null) return manualQuotaPercent(usedPercent)
|
|
339
|
+
var remainingPercent = firstPresent([value.remaining_percent, value.remainingPercent, value.percent_remaining, value.percentRemaining])
|
|
340
|
+
if (remainingPercent !== null) {
|
|
341
|
+
var remaining = manualQuotaPercent(remainingPercent)
|
|
342
|
+
return remaining === null ? null : 100 - remaining
|
|
343
|
+
}
|
|
344
|
+
var limit = readFiniteNumber(firstPresent([value.limit, value.quota, value.total, value.max]))
|
|
345
|
+
var used = readFiniteNumber(firstPresent([value.used, value.usage, value.used_count, value.usedCount, value.consumed]))
|
|
346
|
+
if (limit !== null && limit > 0 && used !== null) return used / limit * 100
|
|
347
|
+
remaining = readFiniteNumber(firstPresent([value.remaining, value.left]))
|
|
348
|
+
return limit !== null && limit > 0 && remaining !== null ? (limit - remaining) / limit * 100 : null
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
function manualWindow(ctx, data, cadence, depth) {
|
|
352
|
+
if (!data || typeof data !== "object" || depth > 8) return null
|
|
353
|
+
var current = readFiniteNumber(data[cadence + "_percentage"])
|
|
354
|
+
if (current !== null) {
|
|
355
|
+
var currentPercent = current < 1 ? current * 100 : current
|
|
356
|
+
if (Number.isFinite(currentPercent)) return {used: currentPercent, reset: ctx.util.toIso(data[cadence + "_reset_at"])}
|
|
357
|
+
}
|
|
358
|
+
var singular = cadence === "daily" ? "day" : "week"
|
|
359
|
+
var window = firstPresent([data[cadence], data[singular], data[cadence + "_quota"], data[cadence + "Quota"], data[cadence + "_usage"], data[cadence + "Usage"]])
|
|
360
|
+
var percent = manualQuotaPercent(window)
|
|
361
|
+
if (percent !== null && Number.isFinite(percent)) {
|
|
362
|
+
return {used: percent, reset: ctx.util.toIso(window && typeof window === "object" ? firstPresent([window.resetsAt, window.reset_at, window.resetAt, window.reset_time]) : null)}
|
|
363
|
+
}
|
|
364
|
+
var keys = Object.keys(data)
|
|
365
|
+
for (var i = 0; i < keys.length; i++) {
|
|
366
|
+
var nested = manualWindow(ctx, data[keys[i]], cadence, depth + 1)
|
|
367
|
+
if (nested) return nested
|
|
368
|
+
}
|
|
369
|
+
return null
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
function manualOutput(ctx, data) {
|
|
373
|
+
var daily = manualWindow(ctx, data, "daily", 0)
|
|
374
|
+
var weekly = manualWindow(ctx, data, "weekly", 0)
|
|
375
|
+
var lines = []
|
|
376
|
+
if (daily) lines.push(buildUsedQuotaLine(ctx, "Daily quota", daily.used, daily.reset, DAY_MS))
|
|
377
|
+
if (weekly) lines.push(buildUsedQuotaLine(ctx, "Weekly quota", weekly.used, weekly.reset, WEEK_MS))
|
|
378
|
+
if (!lines.length) throw {code: "no-data", message: "Devin web response did not contain measurable daily or weekly quotas."}
|
|
379
|
+
var balance = readFiniteNumber(data.overage_balance)
|
|
380
|
+
if (balance === null) {
|
|
381
|
+
var cents = readFiniteNumber(data.overage_balance_cents)
|
|
382
|
+
if (cents !== null) balance = cents / 100
|
|
383
|
+
}
|
|
384
|
+
if (balance !== null && balance >= 0) lines.push(ctx.line.text({label: "Extra usage balance", value: "$" + balance.toFixed(2)}))
|
|
385
|
+
var plan = firstPresent([data.plan_name, data.planName, data.plan, data.tier, data.subscription_tier])
|
|
386
|
+
return {source: "web", plan: typeof plan === "string" && plan.trim() ? plan.trim() : null, lines: lines}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
function probeManual(ctx, opts) {
|
|
390
|
+
if (opts.cookieSource === "off") throw {code: "missing-auth", message: "Devin web authentication is disabled in settings.cookieSource."}
|
|
391
|
+
if (opts.credentialsPath || opts.ideVariant || opts.userDataDir || (opts.authSource && ["auto", "manual"].indexOf(opts.authSource) < 0)) {
|
|
392
|
+
throw {code: "failed", message: "Select either Devin manual web authentication or a CLI/IDE credential source."}
|
|
393
|
+
}
|
|
394
|
+
var raw = firstPresent([ctx.host.env.get("DEVIN_BEARER_TOKEN"), ctx.host.env.get("DEVIN_AUTHORIZATION"), ctx.provider.cookieHeader, opts.bearerToken])
|
|
395
|
+
var token = typeof raw === "string" ? raw.trim().replace(/^Authorization:\s*/i, "").replace(/^Bearer(?:\s+|$)/i, "").trim() : ""
|
|
396
|
+
if (!token || /[^\x21-\x7e]/.test(token)) throw {code: "missing-auth", message: "Set a valid Devin bearer token in cookie_header or DEVIN_BEARER_TOKEN."}
|
|
397
|
+
var org = manualOrganization(firstPresent([ctx.host.env.get("DEVIN_ORGANIZATION"), ctx.host.env.get("DEVIN_ORG"), ctx.provider.workspaceId, opts.organization]))
|
|
398
|
+
var paths = org.internal ? [org.id, org.path] : [org.path, org.id]
|
|
399
|
+
for (var i = 0; i < paths.length; i++) {
|
|
400
|
+
var headers = {Authorization: "Bearer " + token, Accept: "application/json", "Accept-Language": "en-US,en;q=0.9", "User-Agent": "usagestat/" + ctx.app.version}
|
|
401
|
+
if (org.internal) headers["x-cog-org-id"] = org.id
|
|
402
|
+
var response = ctx.util.request({method: "GET", url: "https://app.devin.ai/api/" + paths[i] + "/billing/quota/usage", headers: headers, timeoutMs: 10000})
|
|
403
|
+
if (response.status === 401 || response.status === 403) throw {code: "credential-denied", message: "Devin web token was rejected. Reauthenticate the selected organization."}
|
|
404
|
+
// Alternate routes refer to the same organization; only missing routes
|
|
405
|
+
// permit retry. A rejected token never selects a CLI or IDE account.
|
|
406
|
+
if (response.status === 404 || response.status === 405) continue
|
|
407
|
+
if (response.status !== 200) throw {code: "failed", message: "Devin quota request failed (HTTP " + response.status + ")."}
|
|
408
|
+
var data = ctx.util.tryParseJson(response.bodyText)
|
|
409
|
+
if (!data || typeof data !== "object") throw {code: "no-data", message: "Invalid Devin quota response."}
|
|
410
|
+
return manualOutput(ctx, data)
|
|
411
|
+
}
|
|
412
|
+
throw {code: "no-data", message: "Devin quota endpoint was not found for the selected organization."}
|
|
413
|
+
}
|
|
414
|
+
|
|
308
415
|
function probe(ctx) {
|
|
309
416
|
var opts = settings(ctx)
|
|
417
|
+
var mode = ctx.sourceMode || "auto"
|
|
418
|
+
var manual = mode === "web" || opts.authSource === "manual" || opts.cookieSource === "manual" ||
|
|
419
|
+
(mode === "auto" && !opts.authSource && opts.cookieSource == null && (ctx.provider.cookieHeader != null || opts.bearerToken != null))
|
|
420
|
+
if (manual) {
|
|
421
|
+
if (mode === "local") throw {code: "failed", message: "Select web or auto mode to use Devin manual web authentication."}
|
|
422
|
+
return probeManual(ctx, opts)
|
|
423
|
+
}
|
|
310
424
|
var source = opts.authSource || (opts.credentialsPath ? "cli" : opts.ideVariant || opts.userDataDir ? "ide" : "auto")
|
|
311
425
|
if (["auto", "cli", "ide"].indexOf(source) < 0) throw {code: "failed", message: "Set Devin settings.authSource to auto, cli or ide."}
|
|
312
426
|
if ((opts.credentialsPath && source !== "cli") || ((opts.ideVariant || opts.userDataDir) && source !== "ide")) {
|
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
"entry": "plugin.js",
|
|
7
7
|
"icon": "icon.svg",
|
|
8
8
|
"brandColor": "#000000",
|
|
9
|
-
"supportedModes": ["local"],
|
|
9
|
+
"supportedModes": ["local", "web"],
|
|
10
10
|
"autoMode": "local",
|
|
11
|
+
"envVars": ["DEVIN_BEARER_TOKEN", "DEVIN_AUTHORIZATION", "DEVIN_ORGANIZATION", "DEVIN_ORG"],
|
|
11
12
|
"lines": [
|
|
12
13
|
{ "type": "progress", "label": "Weekly quota", "scope": "overview", "primaryOrder": 1 },
|
|
13
14
|
{ "type": "progress", "label": "Daily quota", "scope": "overview" },
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Peter Steinberger
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|