@hashimkarim/usagestat-linux-x64-gnu 2.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +57744 -0
- package/native-manifest.json +1414 -0
- package/package.json +254 -0
- package/plugins/abacus-ai/icon.svg +18 -0
- package/plugins/abacus-ai/plugin.js +121 -0
- package/plugins/abacus-ai/plugin.json +17 -0
- package/plugins/alibaba/icon-color.svg +1 -0
- package/plugins/alibaba/icon.svg +1 -0
- package/plugins/alibaba/plugin.js +322 -0
- package/plugins/alibaba/plugin.json +20 -0
- package/plugins/alibaba-token-plan/icon-color.svg +1 -0
- package/plugins/alibaba-token-plan/icon.svg +1 -0
- package/plugins/alibaba-token-plan/plugin.js +544 -0
- package/plugins/alibaba-token-plan/plugin.json +19 -0
- package/plugins/amp/icon-color.svg +1 -0
- package/plugins/amp/icon-conflict.svg +6 -0
- package/plugins/amp/icon.svg +1 -0
- package/plugins/amp/plugin.js +175 -0
- package/plugins/amp/plugin.json +16 -0
- package/plugins/antigravity/icon-color.svg +1 -0
- package/plugins/antigravity/icon-conflict.svg +3 -0
- package/plugins/antigravity/icon.svg +1 -0
- package/plugins/antigravity/plugin.js +739 -0
- package/plugins/antigravity/plugin.json +31 -0
- package/plugins/antigravity-cli/icon.svg +3 -0
- package/plugins/antigravity-cli/plugin.js +570 -0
- package/plugins/antigravity-cli/plugin.json +16 -0
- package/plugins/antigravity-ide/icon.svg +3 -0
- package/plugins/antigravity-ide/plugin.js +257 -0
- package/plugins/antigravity-ide/plugin.json +29 -0
- package/plugins/augment/icon.svg +14 -0
- package/plugins/augment/plugin.js +59 -0
- package/plugins/augment/plugin.json +18 -0
- package/plugins/aws-bedrock/icon-color.svg +1 -0
- package/plugins/aws-bedrock/icon.svg +1 -0
- package/plugins/aws-bedrock/plugin.js +206 -0
- package/plugins/aws-bedrock/plugin.json +18 -0
- package/plugins/azure-openai/icon-color.svg +1 -0
- package/plugins/azure-openai/icon.svg +1 -0
- package/plugins/azure-openai/plugin.js +145 -0
- package/plugins/azure-openai/plugin.json +17 -0
- package/plugins/chutes/icon.svg +7 -0
- package/plugins/chutes/plugin.js +236 -0
- package/plugins/chutes/plugin.json +19 -0
- package/plugins/claude/icon-color.svg +1 -0
- package/plugins/claude/icon.svg +1 -0
- package/plugins/claude/plugin.js +1723 -0
- package/plugins/claude/plugin.json +30 -0
- package/plugins/codebuff/icon.svg +92 -0
- package/plugins/codebuff/plugin.js +113 -0
- package/plugins/codebuff/plugin.json +17 -0
- package/plugins/codex/icon-color.svg +5 -0
- package/plugins/codex/icon.svg +1 -0
- package/plugins/codex/plugin.js +1009 -0
- package/plugins/codex/plugin.json +82 -0
- package/plugins/command-code/icon.svg +3 -0
- package/plugins/command-code/plugin.js +184 -0
- package/plugins/command-code/plugin.json +20 -0
- package/plugins/copilot/icon-color.svg +1 -0
- package/plugins/copilot/icon.svg +1 -0
- package/plugins/copilot/plugin.js +684 -0
- package/plugins/copilot/plugin.json +21 -0
- package/plugins/crof/icon.svg +3 -0
- package/plugins/crof/plugin.js +53 -0
- package/plugins/crof/plugin.json +17 -0
- package/plugins/crofai/icon.svg +16 -0
- package/plugins/crofai/plugin.js +81 -0
- package/plugins/crofai/plugin.json +18 -0
- package/plugins/cursor/icon-conflict.svg +3 -0
- package/plugins/cursor/icon.svg +1 -0
- package/plugins/cursor/plugin.js +1379 -0
- package/plugins/cursor/plugin.json +23 -0
- package/plugins/cursor-nightly/icon.png +0 -0
- package/plugins/cursor-nightly/plugin.js +1379 -0
- package/plugins/cursor-nightly/plugin.json +23 -0
- package/plugins/deepgram/icon.svg +1 -0
- package/plugins/deepgram/plugin.js +20 -0
- package/plugins/deepgram/plugin.json +17 -0
- package/plugins/deepseek/icon-color.svg +1 -0
- package/plugins/deepseek/icon.svg +1 -0
- package/plugins/deepseek/plugin.js +71 -0
- package/plugins/deepseek/plugin.json +17 -0
- package/plugins/devin/icon.svg +5 -0
- package/plugins/devin/plugin.js +341 -0
- package/plugins/devin/plugin.json +16 -0
- package/plugins/doubao/icon-color.svg +1 -0
- package/plugins/doubao/icon.svg +1 -0
- package/plugins/doubao/plugin.js +92 -0
- package/plugins/doubao/plugin.json +17 -0
- package/plugins/droid/icon.svg +1 -0
- package/plugins/droid/plugin.json +20 -0
- package/plugins/elevenlabs/icon.svg +4 -0
- package/plugins/elevenlabs/plugin.js +48 -0
- package/plugins/elevenlabs/plugin.json +18 -0
- package/plugins/factory/icon-conflict.svg +1 -0
- package/plugins/factory/icon.svg +1 -0
- package/plugins/factory/plugin.js +487 -0
- package/plugins/factory/plugin.json +15 -0
- package/plugins/fireworks-ai/icon.svg +6 -0
- package/plugins/fireworks-ai/plugin.js +370 -0
- package/plugins/fireworks-ai/plugin.json +19 -0
- package/plugins/gemini/icon-color.svg +1 -0
- package/plugins/gemini/icon.svg +1 -0
- package/plugins/gemini/plugin.js +460 -0
- package/plugins/gemini/plugin.json +16 -0
- package/plugins/grok/icon.svg +1 -0
- package/plugins/grok/plugin.js +297 -0
- package/plugins/grok/plugin.json +19 -0
- package/plugins/groqcloud/icon.svg +1 -0
- package/plugins/groqcloud/plugin.js +117 -0
- package/plugins/groqcloud/plugin.json +19 -0
- package/plugins/jetbrains-ai-assistant/icon-color.svg +14 -0
- package/plugins/jetbrains-ai-assistant/icon-conflict.svg +3 -0
- package/plugins/jetbrains-ai-assistant/icon.svg +14 -0
- package/plugins/jetbrains-ai-assistant/plugin.js +313 -0
- package/plugins/jetbrains-ai-assistant/plugin.json +16 -0
- package/plugins/kilo/icon.svg +1 -0
- package/plugins/kilo/plugin.js +111 -0
- package/plugins/kilo/plugin.json +19 -0
- package/plugins/kimi/icon-color.svg +1 -0
- package/plugins/kimi/icon-conflict.svg +3 -0
- package/plugins/kimi/icon.svg +1 -0
- package/plugins/kimi/plugin.js +358 -0
- package/plugins/kimi/plugin.json +15 -0
- package/plugins/kimi-k2/icon-color.svg +1 -0
- package/plugins/kimi-k2/icon.svg +1 -0
- package/plugins/kimi-k2/plugin.js +58 -0
- package/plugins/kimi-k2/plugin.json +18 -0
- package/plugins/kiro/icon-color.svg +5 -0
- package/plugins/kiro/icon-conflict.svg +1 -0
- package/plugins/kiro/icon.svg +4 -0
- package/plugins/kiro/plugin.js +390 -0
- package/plugins/kiro/plugin.json +16 -0
- package/plugins/litellm/icon.svg +16 -0
- package/plugins/litellm/plugin.js +199 -0
- package/plugins/litellm/plugin.json +16 -0
- package/plugins/llm-proxy/icon.svg +1 -0
- package/plugins/llm-proxy/plugin.js +40 -0
- package/plugins/llm-proxy/plugin.json +17 -0
- package/plugins/manus/icon.svg +6 -0
- package/plugins/manus/plugin.js +50 -0
- package/plugins/manus/plugin.json +17 -0
- package/plugins/mimo/icon.svg +1 -0
- package/plugins/mimo/plugin.js +177 -0
- package/plugins/mimo/plugin.json +19 -0
- package/plugins/minimax/icon-color.svg +1 -0
- package/plugins/minimax/icon-conflict.svg +4 -0
- package/plugins/minimax/icon.svg +1 -0
- package/plugins/minimax/plugin.js +453 -0
- package/plugins/minimax/plugin.json +14 -0
- package/plugins/mistral/icon-color.svg +1 -0
- package/plugins/mistral/icon.svg +1 -0
- package/plugins/mistral/plugin.js +152 -0
- package/plugins/mistral/plugin.json +18 -0
- package/plugins/moonshot/icon.svg +1 -0
- package/plugins/moonshot/plugin.js +43 -0
- package/plugins/moonshot/plugin.json +16 -0
- package/plugins/nanogpt/icon-color.svg +17 -0
- package/plugins/nanogpt/icon.svg +10 -0
- package/plugins/nanogpt/plugin.js +80 -0
- package/plugins/nanogpt/plugin.json +17 -0
- package/plugins/neuralwatt/icon.svg +3 -0
- package/plugins/neuralwatt/plugin.js +152 -0
- package/plugins/neuralwatt/plugin.json +17 -0
- package/plugins/ollama/icon.svg +1 -0
- package/plugins/ollama/plugin.js +92 -0
- package/plugins/ollama/plugin.json +20 -0
- package/plugins/openai-api/icon.svg +1 -0
- package/plugins/openai-api/plugin.js +533 -0
- package/plugins/openai-api/plugin.json +26 -0
- package/plugins/opencode/icon.svg +1 -0
- package/plugins/opencode/plugin.js +342 -0
- package/plugins/opencode/plugin.json +19 -0
- package/plugins/opencode-go/icon-conflict.svg +1 -0
- package/plugins/opencode-go/icon.svg +1 -0
- package/plugins/opencode-go/plugin.js +617 -0
- package/plugins/opencode-go/plugin.json +50 -0
- package/plugins/openrouter/icon.svg +1 -0
- package/plugins/openrouter/plugin.js +156 -0
- package/plugins/openrouter/plugin.json +8 -0
- package/plugins/perplexity/icon-color.svg +1 -0
- package/plugins/perplexity/icon-conflict.svg +1 -0
- package/plugins/perplexity/icon.svg +1 -0
- package/plugins/perplexity/plugin.js +425 -0
- package/plugins/perplexity/plugin.json +19 -0
- package/plugins/poe/icon.svg +1 -0
- package/plugins/poe/plugin.js +190 -0
- package/plugins/poe/plugin.json +19 -0
- package/plugins/stepfun/icon-color.svg +1 -0
- package/plugins/stepfun/icon.svg +1 -0
- package/plugins/stepfun/plugin.js +155 -0
- package/plugins/stepfun/plugin.json +18 -0
- package/plugins/synthetic/icon-conflict.svg +12 -0
- package/plugins/synthetic/icon.svg +14 -0
- package/plugins/synthetic/plugin.js +331 -0
- package/plugins/synthetic/plugin.json +23 -0
- package/plugins/t3chat/icon-color.svg +28 -0
- package/plugins/t3chat/icon.svg +4 -0
- package/plugins/t3chat/plugin.js +243 -0
- package/plugins/t3chat/plugin.json +20 -0
- package/plugins/venice/icon-color.svg +1 -0
- package/plugins/venice/icon.svg +1 -0
- package/plugins/venice/plugin.js +69 -0
- package/plugins/venice/plugin.json +16 -0
- package/plugins/vertex-ai/icon-color.svg +1 -0
- package/plugins/vertex-ai/icon.svg +1 -0
- package/plugins/vertex-ai/plugin.js +172 -0
- package/plugins/vertex-ai/plugin.json +18 -0
- package/plugins/warp/icon-color.svg +10 -0
- package/plugins/warp/icon.svg +6 -0
- package/plugins/warp/plugin.js +108 -0
- package/plugins/warp/plugin.json +18 -0
- package/plugins/windsurf/icon-conflict.svg +3 -0
- package/plugins/windsurf/icon.svg +1 -0
- package/plugins/windsurf/plugin.js +208 -0
- package/plugins/windsurf/plugin.json +16 -0
- package/plugins/zai/icon-conflict.svg +5 -0
- package/plugins/zai/icon.svg +1 -0
- package/plugins/zai/plugin.js +188 -0
- package/plugins/zai/plugin.json +16 -0
- package/plugins/zed/icon.svg +4 -0
- package/plugins/zed/plugin.js +270 -0
- package/plugins/zed/plugin.json +19 -0
- package/usagestat +0 -0
- package/usagestatd +0 -0
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
(function () {
|
|
2
|
+
const CRED_PATH = "~/.kimi/credentials/kimi-code.json"
|
|
3
|
+
const USAGE_URL = "https://api.kimi.com/coding/v1/usages"
|
|
4
|
+
const REFRESH_URL = "https://auth.kimi.com/api/oauth/token"
|
|
5
|
+
const CLIENT_ID = "17e5f671-d194-4dfb-9706-5516cb48c098"
|
|
6
|
+
const REFRESH_BUFFER_SEC = 5 * 60
|
|
7
|
+
|
|
8
|
+
function readNumber(value) {
|
|
9
|
+
const n = Number(value)
|
|
10
|
+
return Number.isFinite(n) ? n : null
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function titleCaseWords(value) {
|
|
14
|
+
return String(value)
|
|
15
|
+
.trim()
|
|
16
|
+
.toLowerCase()
|
|
17
|
+
.replace(/\b[a-z]/g, function (c) {
|
|
18
|
+
return c.toUpperCase()
|
|
19
|
+
})
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function parsePlanLabel(data) {
|
|
23
|
+
const level =
|
|
24
|
+
data &&
|
|
25
|
+
data.user &&
|
|
26
|
+
data.user.membership &&
|
|
27
|
+
typeof data.user.membership.level === "string"
|
|
28
|
+
? data.user.membership.level
|
|
29
|
+
: null
|
|
30
|
+
if (!level) return null
|
|
31
|
+
|
|
32
|
+
const cleaned = level.replace(/^LEVEL_/, "").replace(/_/g, " ")
|
|
33
|
+
const label = titleCaseWords(cleaned)
|
|
34
|
+
return label || null
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function loadCredentials(ctx) {
|
|
38
|
+
if (!ctx.host.fs.exists(CRED_PATH)) {
|
|
39
|
+
ctx.host.log.warn("credentials file not found: " + CRED_PATH)
|
|
40
|
+
return null
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
const text = ctx.host.fs.readText(CRED_PATH)
|
|
45
|
+
const parsed = ctx.util.tryParseJson(text)
|
|
46
|
+
if (!parsed || typeof parsed !== "object") {
|
|
47
|
+
ctx.host.log.warn("credentials file is not valid json")
|
|
48
|
+
return null
|
|
49
|
+
}
|
|
50
|
+
if (!parsed.access_token && !parsed.refresh_token) {
|
|
51
|
+
ctx.host.log.warn("credentials missing access_token and refresh_token")
|
|
52
|
+
return null
|
|
53
|
+
}
|
|
54
|
+
return parsed
|
|
55
|
+
} catch (e) {
|
|
56
|
+
ctx.host.log.warn("credentials read failed: " + String(e))
|
|
57
|
+
return null
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function saveCredentials(ctx, creds) {
|
|
62
|
+
try {
|
|
63
|
+
ctx.host.fs.writeText(CRED_PATH, JSON.stringify(creds))
|
|
64
|
+
} catch (e) {
|
|
65
|
+
ctx.host.log.warn("failed to persist credentials: " + String(e))
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function needsRefresh(creds, nowSec) {
|
|
70
|
+
if (!creds.access_token) return true
|
|
71
|
+
const expiresAt = readNumber(creds.expires_at)
|
|
72
|
+
if (expiresAt === null) return true
|
|
73
|
+
return nowSec + REFRESH_BUFFER_SEC >= expiresAt
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function refreshToken(ctx, creds) {
|
|
77
|
+
if (!creds.refresh_token) {
|
|
78
|
+
ctx.host.log.warn("refresh skipped: no refresh token")
|
|
79
|
+
return null
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
ctx.host.log.info("attempting token refresh")
|
|
83
|
+
let resp
|
|
84
|
+
try {
|
|
85
|
+
resp = ctx.util.request({
|
|
86
|
+
method: "POST",
|
|
87
|
+
url: REFRESH_URL,
|
|
88
|
+
headers: {
|
|
89
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
90
|
+
Accept: "application/json",
|
|
91
|
+
},
|
|
92
|
+
bodyText:
|
|
93
|
+
"client_id=" +
|
|
94
|
+
encodeURIComponent(CLIENT_ID) +
|
|
95
|
+
"&grant_type=refresh_token" +
|
|
96
|
+
"&refresh_token=" +
|
|
97
|
+
encodeURIComponent(creds.refresh_token),
|
|
98
|
+
timeoutMs: 15000,
|
|
99
|
+
})
|
|
100
|
+
} catch (e) {
|
|
101
|
+
ctx.host.log.error("refresh exception: " + String(e))
|
|
102
|
+
return null
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (ctx.util.isAuthStatus(resp.status)) {
|
|
106
|
+
throw "Session expired. Run `kimi login` to authenticate."
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (resp.status < 200 || resp.status >= 300) {
|
|
110
|
+
ctx.host.log.warn("refresh returned unexpected status: " + resp.status)
|
|
111
|
+
return null
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const body = ctx.util.tryParseJson(resp.bodyText)
|
|
115
|
+
if (!body || !body.access_token) {
|
|
116
|
+
ctx.host.log.warn("refresh response missing access_token")
|
|
117
|
+
return null
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
creds.access_token = body.access_token
|
|
121
|
+
if (body.refresh_token) creds.refresh_token = body.refresh_token
|
|
122
|
+
if (typeof body.expires_in === "number") {
|
|
123
|
+
creds.expires_at = Date.now() / 1000 + body.expires_in
|
|
124
|
+
}
|
|
125
|
+
if (typeof body.scope === "string") creds.scope = body.scope
|
|
126
|
+
if (typeof body.token_type === "string") creds.token_type = body.token_type
|
|
127
|
+
|
|
128
|
+
saveCredentials(ctx, creds)
|
|
129
|
+
return creds.access_token
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function fetchUsage(ctx, accessToken) {
|
|
133
|
+
return ctx.util.request({
|
|
134
|
+
method: "GET",
|
|
135
|
+
url: USAGE_URL,
|
|
136
|
+
headers: {
|
|
137
|
+
Authorization: "Bearer " + accessToken,
|
|
138
|
+
Accept: "application/json",
|
|
139
|
+
"User-Agent": "OpenUsage",
|
|
140
|
+
},
|
|
141
|
+
timeoutMs: 10000,
|
|
142
|
+
})
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function parseWindowPeriodMs(window) {
|
|
146
|
+
if (!window || typeof window !== "object") return null
|
|
147
|
+
const duration = readNumber(window.duration)
|
|
148
|
+
if (duration === null || duration <= 0) return null
|
|
149
|
+
|
|
150
|
+
const unit = String(window.timeUnit || window.time_unit || "").toUpperCase()
|
|
151
|
+
if (unit.indexOf("MINUTE") !== -1) return duration * 60 * 1000
|
|
152
|
+
if (unit.indexOf("HOUR") !== -1) return duration * 60 * 60 * 1000
|
|
153
|
+
if (unit.indexOf("DAY") !== -1) return duration * 24 * 60 * 60 * 1000
|
|
154
|
+
if (unit.indexOf("SECOND") !== -1) return duration * 1000
|
|
155
|
+
return null
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function parseQuota(row, ctx) {
|
|
159
|
+
if (!row || typeof row !== "object") return null
|
|
160
|
+
|
|
161
|
+
const limit = readNumber(row.limit)
|
|
162
|
+
if (limit === null || limit <= 0) return null
|
|
163
|
+
|
|
164
|
+
let used = readNumber(row.used)
|
|
165
|
+
if (used === null) {
|
|
166
|
+
const remaining = readNumber(row.remaining)
|
|
167
|
+
if (remaining !== null) {
|
|
168
|
+
used = limit - remaining
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
if (used === null) return null
|
|
172
|
+
|
|
173
|
+
return {
|
|
174
|
+
used,
|
|
175
|
+
limit,
|
|
176
|
+
resetsAt: ctx.util.toIso(row.resetTime || row.reset_at || row.resetAt || row.reset_time),
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function toPercentUsage(quota) {
|
|
181
|
+
if (!quota || quota.limit <= 0) return null
|
|
182
|
+
const usedPercent = (quota.used / quota.limit) * 100
|
|
183
|
+
if (!Number.isFinite(usedPercent)) return null
|
|
184
|
+
return {
|
|
185
|
+
used: Math.round(Math.max(0, usedPercent) * 10) / 10,
|
|
186
|
+
limit: 100,
|
|
187
|
+
resetsAt: quota.resetsAt,
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function collectLimitCandidates(ctx, data) {
|
|
192
|
+
const limits = Array.isArray(data && data.limits) ? data.limits : []
|
|
193
|
+
const out = []
|
|
194
|
+
|
|
195
|
+
for (let i = 0; i < limits.length; i += 1) {
|
|
196
|
+
const item = limits[i]
|
|
197
|
+
const detail = item && typeof item.detail === "object" ? item.detail : item
|
|
198
|
+
const quota = parseQuota(detail, ctx)
|
|
199
|
+
if (!quota) continue
|
|
200
|
+
|
|
201
|
+
const periodMs = parseWindowPeriodMs(item && item.window)
|
|
202
|
+
out.push({ quota, periodMs })
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return out
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function pickSessionCandidate(candidates) {
|
|
209
|
+
if (!candidates.length) return null
|
|
210
|
+
const sorted = candidates.slice().sort(function (a, b) {
|
|
211
|
+
const aKnown = typeof a.periodMs === "number"
|
|
212
|
+
const bKnown = typeof b.periodMs === "number"
|
|
213
|
+
if (aKnown && bKnown) return a.periodMs - b.periodMs
|
|
214
|
+
if (aKnown) return -1
|
|
215
|
+
if (bKnown) return 1
|
|
216
|
+
return 0
|
|
217
|
+
})
|
|
218
|
+
return sorted[0]
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function pickLargestByPeriod(candidates) {
|
|
222
|
+
if (!candidates.length) return null
|
|
223
|
+
let best = candidates[0]
|
|
224
|
+
for (let i = 1; i < candidates.length; i += 1) {
|
|
225
|
+
const cur = candidates[i]
|
|
226
|
+
const curMs = typeof cur.periodMs === "number" ? cur.periodMs : -1
|
|
227
|
+
const bestMs = typeof best.periodMs === "number" ? best.periodMs : -1
|
|
228
|
+
if (curMs > bestMs) best = cur
|
|
229
|
+
}
|
|
230
|
+
return best
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function sameQuota(a, b) {
|
|
234
|
+
if (!a || !b) return false
|
|
235
|
+
return (
|
|
236
|
+
a.quota.used === b.quota.used &&
|
|
237
|
+
a.quota.limit === b.quota.limit &&
|
|
238
|
+
(a.quota.resetsAt || null) === (b.quota.resetsAt || null)
|
|
239
|
+
)
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function probe(ctx) {
|
|
243
|
+
const creds = loadCredentials(ctx)
|
|
244
|
+
if (!creds) {
|
|
245
|
+
throw "Not logged in. Run `kimi login` to authenticate."
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const nowSec = Date.now() / 1000
|
|
249
|
+
let accessToken = creds.access_token || ""
|
|
250
|
+
|
|
251
|
+
if (needsRefresh(creds, nowSec)) {
|
|
252
|
+
const refreshed = refreshToken(ctx, creds)
|
|
253
|
+
if (refreshed) {
|
|
254
|
+
accessToken = refreshed
|
|
255
|
+
} else if (!accessToken) {
|
|
256
|
+
throw "Not logged in. Run `kimi login` to authenticate."
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
let didRefresh = false
|
|
261
|
+
let resp
|
|
262
|
+
try {
|
|
263
|
+
resp = ctx.util.retryOnceOnAuth({
|
|
264
|
+
request: function (token) {
|
|
265
|
+
return fetchUsage(ctx, token || accessToken)
|
|
266
|
+
},
|
|
267
|
+
refresh: function () {
|
|
268
|
+
didRefresh = true
|
|
269
|
+
const refreshed = refreshToken(ctx, creds)
|
|
270
|
+
if (refreshed) accessToken = refreshed
|
|
271
|
+
return refreshed
|
|
272
|
+
},
|
|
273
|
+
})
|
|
274
|
+
} catch (e) {
|
|
275
|
+
if (typeof e === "string") throw e
|
|
276
|
+
if (didRefresh) {
|
|
277
|
+
throw "Usage request failed after refresh. Try again."
|
|
278
|
+
}
|
|
279
|
+
throw "Usage request failed. Check your connection."
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if (ctx.util.isAuthStatus(resp.status)) {
|
|
283
|
+
throw "Token expired. Run `kimi login` to authenticate."
|
|
284
|
+
}
|
|
285
|
+
if (resp.status < 200 || resp.status >= 300) {
|
|
286
|
+
throw "Usage request failed (HTTP " + String(resp.status) + "). Try again later."
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const data = ctx.util.tryParseJson(resp.bodyText)
|
|
290
|
+
if (!data || typeof data !== "object") {
|
|
291
|
+
throw "Usage response invalid. Try again later."
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const lines = []
|
|
295
|
+
const candidates = collectLimitCandidates(ctx, data)
|
|
296
|
+
const sessionCandidate = pickSessionCandidate(candidates)
|
|
297
|
+
|
|
298
|
+
let weeklyCandidate = null
|
|
299
|
+
const usageQuota = parseQuota(data.usage, ctx)
|
|
300
|
+
if (usageQuota) {
|
|
301
|
+
weeklyCandidate = { quota: usageQuota, periodMs: null }
|
|
302
|
+
} else {
|
|
303
|
+
const withoutSession = candidates.filter(function (candidate) {
|
|
304
|
+
return candidate !== sessionCandidate
|
|
305
|
+
})
|
|
306
|
+
weeklyCandidate = pickLargestByPeriod(withoutSession)
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
if (sessionCandidate) {
|
|
310
|
+
const sessionPercent = toPercentUsage(sessionCandidate.quota)
|
|
311
|
+
if (sessionPercent) {
|
|
312
|
+
lines.push(
|
|
313
|
+
ctx.line.progress({
|
|
314
|
+
label: "Session",
|
|
315
|
+
used: sessionPercent.used,
|
|
316
|
+
limit: sessionPercent.limit,
|
|
317
|
+
format: { kind: "percent" },
|
|
318
|
+
resetsAt: sessionPercent.resetsAt || undefined,
|
|
319
|
+
periodDurationMs:
|
|
320
|
+
typeof sessionCandidate.periodMs === "number"
|
|
321
|
+
? sessionCandidate.periodMs
|
|
322
|
+
: undefined,
|
|
323
|
+
})
|
|
324
|
+
)
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
if (weeklyCandidate && !sameQuota(weeklyCandidate, sessionCandidate)) {
|
|
329
|
+
const weeklyPercent = toPercentUsage(weeklyCandidate.quota)
|
|
330
|
+
if (weeklyPercent) {
|
|
331
|
+
lines.push(
|
|
332
|
+
ctx.line.progress({
|
|
333
|
+
label: "Weekly",
|
|
334
|
+
used: weeklyPercent.used,
|
|
335
|
+
limit: weeklyPercent.limit,
|
|
336
|
+
format: { kind: "percent" },
|
|
337
|
+
resetsAt: weeklyPercent.resetsAt || undefined,
|
|
338
|
+
periodDurationMs:
|
|
339
|
+
typeof weeklyCandidate.periodMs === "number"
|
|
340
|
+
? weeklyCandidate.periodMs
|
|
341
|
+
: undefined,
|
|
342
|
+
})
|
|
343
|
+
)
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
if (lines.length === 0) {
|
|
348
|
+
lines.push(ctx.line.badge({ label: "Status", text: "No usage data", color: "#a3a3a3" }))
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
return {
|
|
352
|
+
plan: parsePlanLabel(data),
|
|
353
|
+
lines,
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
globalThis.__openusage_plugin = { id: "kimi", probe }
|
|
358
|
+
})()
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"id": "kimi",
|
|
4
|
+
"name": "Kimi",
|
|
5
|
+
"version": "0.0.1",
|
|
6
|
+
"entry": "plugin.js",
|
|
7
|
+
"icon": "icon.svg",
|
|
8
|
+
"brandColor": "#000000",
|
|
9
|
+
"supportedModes": ["oauth", "local"],
|
|
10
|
+
"autoMode": "oauth",
|
|
11
|
+
"lines": [
|
|
12
|
+
{ "type": "progress", "label": "Session", "scope": "overview", "primaryOrder": 1 },
|
|
13
|
+
{ "type": "progress", "label": "Weekly", "scope": "overview", "primaryOrder": 2 }
|
|
14
|
+
]
|
|
15
|
+
}
|
|
@@ -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>Kimi</title><path d="M21.846 0a1.923 1.923 0 110 3.846H20.15a.226.226 0 01-.227-.226V1.923C19.923.861 20.784 0 21.846 0z" fill="#1783FF"></path><path d="M11.065 11.199l7.257-7.2c.137-.136.06-.41-.116-.41H14.3a.164.164 0 00-.117.051l-7.82 7.756c-.122.12-.302.013-.302-.179V3.82c0-.127-.083-.23-.185-.23H3.186c-.103 0-.186.103-.186.23V19.77c0 .128.083.23.186.23h2.69c.103 0 .186-.102.186-.23v-3.25c0-.069.025-.135.069-.178l2.424-2.406a.158.158 0 01.205-.023l6.484 4.772a7.677 7.677 0 003.453 1.283c.108.012.2-.095.2-.23v-3.06c0-.117-.07-.212-.164-.227a5.028 5.028 0 01-2.027-.807l-5.613-4.064c-.117-.078-.132-.279-.028-.381z" fill="#fff"></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>Kimi</title><path d="M21.846 0a1.923 1.923 0 110 3.846H20.15a.226.226 0 01-.227-.226V1.923C19.923.861 20.784 0 21.846 0z"></path><path d="M11.065 11.199l7.257-7.2c.137-.136.06-.41-.116-.41H14.3a.164.164 0 00-.117.051l-7.82 7.756c-.122.12-.302.013-.302-.179V3.82c0-.127-.083-.23-.185-.23H3.186c-.103 0-.186.103-.186.23V19.77c0 .128.083.23.186.23h2.69c.103 0 .186-.102.186-.23v-3.25c0-.069.025-.135.069-.178l2.424-2.406a.158.158 0 01.205-.023l6.484 4.772a7.677 7.677 0 003.453 1.283c.108.012.2-.095.2-.23v-3.06c0-.117-.07-.212-.164-.227a5.028 5.028 0 01-2.027-.807l-5.613-4.064c-.117-.078-.132-.279-.028-.381z"></path></svg>
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
(function () {
|
|
2
|
+
var API_URL = "https://api.moonshot.cn/v1/users/me/balance";
|
|
3
|
+
|
|
4
|
+
function loadApiKey(ctx) {
|
|
5
|
+
var names = ["MOONSHOT_API_KEY", "KIMI_API_KEY"];
|
|
6
|
+
for (var i = 0; i < names.length; i++) {
|
|
7
|
+
var v = ctx.host.env.get(names[i]);
|
|
8
|
+
if (typeof v === "string" && v.trim()) return v.trim();
|
|
9
|
+
}
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function probe(ctx) {
|
|
14
|
+
var apiKey = loadApiKey(ctx);
|
|
15
|
+
if (!apiKey) {
|
|
16
|
+
throw "Kimi K2 / Moonshot API key not found. Set MOONSHOT_API_KEY or KIMI_API_KEY.";
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
var result = ctx.util.requestJson({
|
|
20
|
+
method: "GET",
|
|
21
|
+
url: API_URL,
|
|
22
|
+
headers: { Authorization: "Bearer " + apiKey, Accept: "application/json" },
|
|
23
|
+
timeoutMs: 30000,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
if (ctx.util.isAuthStatus(result.resp.status)) {
|
|
27
|
+
throw "API key invalid or expired.";
|
|
28
|
+
}
|
|
29
|
+
if (result.resp.status < 200 || result.resp.status >= 300) {
|
|
30
|
+
throw "Kimi K2 API error (HTTP " + result.resp.status + ").";
|
|
31
|
+
}
|
|
32
|
+
if (!result.json) throw "Could not parse Kimi K2 balance response.";
|
|
33
|
+
|
|
34
|
+
var data = result.json.data || result.json;
|
|
35
|
+
var available = typeof data.available_balance === "number" ? data.available_balance
|
|
36
|
+
: typeof data.balance === "number" ? data.balance : 0;
|
|
37
|
+
var total = typeof data.total_balance === "number" ? data.total_balance
|
|
38
|
+
: typeof data.total === "number" ? data.total : 0;
|
|
39
|
+
var used = typeof data.used_balance === "number" ? data.used_balance
|
|
40
|
+
: typeof data.used === "number" ? data.used : Math.max(0, total - available);
|
|
41
|
+
|
|
42
|
+
var usedPct = total > 0 ? Math.min(100, (used / total) * 100) : 0;
|
|
43
|
+
|
|
44
|
+
var lines = [
|
|
45
|
+
ctx.line.progress({
|
|
46
|
+
label: "Credits",
|
|
47
|
+
used: usedPct,
|
|
48
|
+
limit: 100,
|
|
49
|
+
format: { kind: "percent" },
|
|
50
|
+
}),
|
|
51
|
+
ctx.line.text({ label: "Balance", value: available.toFixed(4) + " CNY remaining" }),
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
return { lines: lines };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
globalThis.__openusage_plugin = { id: "kimi-k2", probe: probe };
|
|
58
|
+
})();
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"id": "kimi-k2",
|
|
4
|
+
"name": "Kimi K2",
|
|
5
|
+
"version": "0.0.1",
|
|
6
|
+
"entry": "plugin.js",
|
|
7
|
+
"brandColor": "#1A6EFF",
|
|
8
|
+
"links": [
|
|
9
|
+
{ "label": "Platform", "url": "https://platform.moonshot.cn" }
|
|
10
|
+
],
|
|
11
|
+
"usageDashboardUrl": "https://platform.moonshot.cn",
|
|
12
|
+
"supportedModes": ["api"],
|
|
13
|
+
"autoMode": "api",
|
|
14
|
+
"lines": [
|
|
15
|
+
{ "type": "progress", "label": "Credits", "scope": "overview", "primaryOrder": 1 },
|
|
16
|
+
{ "type": "text", "label": "Balance", "scope": "detail" }
|
|
17
|
+
]
|
|
18
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500">
|
|
2
|
+
<rect x="151.97" y="69.168" width="280.728" height="310.743" fill="#fff"/>
|
|
3
|
+
<path fill="#8845f4" fill-rule="nonzero" d="M166.827 19.829C135.251 21.699 107.072 40.278 92.913 68.571c-5.469 10.989-8.602 23-9.17 35.277-.152 2.653-.202 41.202-.152 120.737.051 109.873.102 117.022.392 119.687 1.427 11.747 4.092 20.866 8.93 30.592 8.589 17.316 22.684 31.299 40.064 39.761 9.473 4.699 19.047 7.452 30.288 8.74 2.868.341 9.726.341 122.366.341 112.981 0 119.448 0 122.366-.341 11.582-1.338 20.966-4.041 30.78-8.929 17.317-8.589 31.312-22.685 39.762-40.065 4.698-9.473 7.452-19.047 8.74-30.288.341-2.867.341-9.726.341-122.075 0-126.003.051-120.37-.884-126.685-3.6-24.693-17.468-46.708-38.195-60.602a69.461 69.461 0 0 0-9.562-5.621c-10.925-5.456-22.848-8.614-35.037-9.271-4.143-.252-232.871-.252-237.115 0Zm136.272 68.282c31.728 2.362 60.185 20.385 75.885 48.059 1.869 3.246 5.128 10.054 6.568 13.704 4.976 12.631 7.982 27.245 9.713 47.365.442 4.8.631 24.819.29 30.402-1.578 27.383-7.894 52.834-19.135 76.769a128.67 128.67 0 0 1-10.117 18.15c-11.747 16.483-29.303 29.455-43.955 32.461-11.304 2.324-20.234-1.263-25.867-10.445a42.032 42.032 0 0 1-3.158-6.669c-.442-1.226-.783-1.63-1.086-1.137-.038.101-1.137.947-2.413 1.932-11.999 9.12-25.513 14.841-38.637 16.332-3.448.379-10.849.29-13.704-.202-9.031-1.529-16.243-5.57-20.828-11.747a34.411 34.411 0 0 1-4.143-7.982c-1.477-4.547-1.97-10.269-1.477-15.498.682-6.947 2.854-14.955 6.113-22.306.24-.467.429-.972.543-1.478a24.767 24.767 0 0 0-1.731.695c-4.584 2.021-11.342 3.852-16.52 4.433-10.661 1.238-18.012-1.768-21.662-8.828-1.339-2.564-1.882-4.926-2.021-8.539-.101-3.296.101-5.431.834-8.285.745-2.905 1.528-4.636 5.09-11.242 4.825-9.094 6.214-11.948 8.033-17.026 4.143-11.355 6.063-21.762 8.69-47.415 1.869-18.555 3.208-27.03 5.469-34.936.354-1.137.985-3.499 1.44-5.23 10.054-38.826 39.319-65.464 77.653-70.744 1.629-.202 3.903-.505 5.04-.593 3.006-.202 12.125-.253 15.093 0Z"/>
|
|
4
|
+
<path fill="#8845f4" fill-rule="nonzero" d="M295.155 162.808c-1.794.48-3.436 1.427-4.737 2.766-2.223 2.274-3.701 5.57-4.496 10.155-.493 2.969-.733 7.604-.493 10.964.354 5.128 1.036 8.083 2.577 11.292 1.616 3.309 3.839 5.38 6.896 6.264 1.339.392 4.837.392 6.315 0 5.33-1.427 8.88-6.707 10.117-15.043.341-4.004.291-8.02-.151-11.999-.783-4.774-2.312-8.526-4.535-10.9-2.008-2.438-5.027-3.802-8.184-3.701-1.099-.114-2.223-.05-3.309.202Zm45.735-.101c-1.667.467-3.233 1.276-4.585 2.375-2.071 1.819-3.701 5.077-4.597 9.069-.632 2.905-.885 5.38-.885 9.384 0 4.042.253 6.454.885 9.372 1.389 6.265 4.446 10.206 8.689 11.342 1.529.392 4.787.392 6.316 0 5.077-1.326 8.589-6.315 9.864-14.02.442-2.501.594-8.184.303-10.988-.795-7.958-3.7-13.376-8.197-15.536a17.769 17.769 0 0 0-2.766-.998c-1.667-.252-3.36-.252-5.027 0Z"/>
|
|
5
|
+
</svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg width="17" height="16" viewBox="0 0 17 16" xmlns="http://www.w3.org/2000/svg" fill="currentColor"><path d="M8.74842 1C10.9904 0.997658 13.2522 2.35131 14.0873 4.98145L14.1635 5.24024L14.2631 5.65918C14.5302 6.92198 14.9273 10.1 13.1898 13.249L13.1888 13.25C12.6834 14.1641 11.7454 15.0605 10.7611 15.459C10.2633 15.6604 9.62658 15.7841 8.99744 15.5586C8.737 15.4652 8.51267 15.3237 8.32166 15.1465C7.29212 15.6815 6.13882 15.8407 5.18983 15.4424C4.52211 15.1621 3.99817 14.61 3.80799 13.8301C3.7494 13.5896 3.72834 13.3402 3.73572 13.084C3.20222 13.0354 2.72563 12.8114 2.39197 12.3281C2.12296 11.9385 2.05135 11.4999 2.06385 11.1397C2.07645 10.7768 2.17568 10.4166 2.33729 10.1113L2.34022 10.1064L2.62537 9.56934C2.69173 9.43932 2.7378 9.34011 2.77772 9.23438C2.93103 8.8105 2.97379 8.57168 3.04041 8.11328L3.04139 8.11133L3.08631 7.77051C3.12624 7.43395 3.15342 7.10561 3.19569 6.72657C3.24643 6.27143 3.31804 5.77596 3.46424 5.28809C4.13106 2.4575 6.43044 1.00258 8.74842 1ZM13.1986 5.50391C11.9212 0.832507 5.53387 0.824247 4.43494 5.52735C4.17712 6.35134 4.1734 7.28628 4.03065 8.25684L3.97694 8.59864C3.92246 8.91789 3.85695 9.19102 3.71717 9.57715C3.6061 9.87417 3.45901 10.1355 3.22108 10.5791L3.15858 10.7148C2.88165 11.4262 3.12847 12.5525 4.89881 11.9063L5.06776 11.8311C3.75892 14.732 6.55455 15.4597 8.61658 13.7607C9.18562 15.5472 11.2185 14.4089 12.1439 13.042L12.3138 12.7666C13.8864 9.9168 13.5268 7.01816 13.2875 5.87891L13.1986 5.50391Z"/><path d="M8.86245 7.52841C8.33877 7.52841 8.25943 6.90239 8.25943 6.52994C8.25943 6.19316 8.31894 5.92769 8.43399 5.75732C8.53317 5.60676 8.67996 5.53148 8.86245 5.53148C9.04495 5.53148 9.20364 5.60676 9.31472 5.76128C9.44167 5.93562 9.50912 6.20108 9.50912 6.52994C9.50912 7.15597 9.26711 7.52841 8.86642 7.52841H8.86245Z"/><path d="M11.0166 7.52841C10.4929 7.52841 10.4136 6.90239 10.4136 6.52994C10.4136 6.19316 10.4731 5.92769 10.5881 5.75732C10.6873 5.60676 10.8341 5.53148 11.0166 5.53148C11.1991 5.53148 11.3578 5.60676 11.4689 5.76128C11.5958 5.93562 11.6633 6.20108 11.6633 6.52994C11.6633 7.15597 11.4213 7.52841 11.0206 7.52841H11.0166Z"/></svg>
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500">
|
|
2
|
+
<path fill="currentColor" fill-rule="nonzero" d="M166.827 19.829C135.251 21.699 107.072 40.278 92.913 68.571c-5.469 10.989-8.602 23-9.17 35.277-.152 2.653-.202 41.202-.152 120.737.051 109.873.102 117.022.392 119.687 1.427 11.747 4.092 20.866 8.93 30.592 8.589 17.316 22.684 31.299 40.064 39.761 9.473 4.699 19.047 7.452 30.288 8.74 2.868.341 9.726.341 122.366.341 112.981 0 119.448 0 122.366-.341 11.582-1.338 20.966-4.041 30.78-8.929 17.317-8.589 31.312-22.685 39.762-40.065 4.698-9.473 7.452-19.047 8.74-30.288.341-2.867.341-9.726.341-122.075 0-126.003.051-120.37-.884-126.685-3.6-24.693-17.468-46.708-38.195-60.602a69.461 69.461 0 0 0-9.562-5.621c-10.925-5.456-22.848-8.614-35.037-9.271-4.143-.252-232.871-.252-237.115 0Zm136.272 68.282c31.728 2.362 60.185 20.385 75.885 48.059 1.869 3.246 5.128 10.054 6.568 13.704 4.976 12.631 7.982 27.245 9.713 47.365.442 4.8.631 24.819.29 30.402-1.578 27.383-7.894 52.834-19.135 76.769a128.67 128.67 0 0 1-10.117 18.15c-11.747 16.483-29.303 29.455-43.955 32.461-11.304 2.324-20.234-1.263-25.867-10.445a42.032 42.032 0 0 1-3.158-6.669c-.442-1.226-.783-1.63-1.086-1.137-.038.101-1.137.947-2.413 1.932-11.999 9.12-25.513 14.841-38.637 16.332-3.448.379-10.849.29-13.704-.202-9.031-1.529-16.243-5.57-20.828-11.747a34.411 34.411 0 0 1-4.143-7.982c-1.477-4.547-1.97-10.269-1.477-15.498.682-6.947 2.854-14.955 6.113-22.306.24-.467.429-.972.543-1.478a24.767 24.767 0 0 0-1.731.695c-4.584 2.021-11.342 3.852-16.52 4.433-10.661 1.238-18.012-1.768-21.662-8.828-1.339-2.564-1.882-4.926-2.021-8.539-.101-3.296.101-5.431.834-8.285.745-2.905 1.528-4.636 5.09-11.242 4.825-9.094 6.214-11.948 8.033-17.026 4.143-11.355 6.063-21.762 8.69-47.415 1.869-18.555 3.208-27.03 5.469-34.936.354-1.137.985-3.499 1.44-5.23 10.054-38.826 39.319-65.464 77.653-70.744 1.629-.202 3.903-.505 5.04-.593 3.006-.202 12.125-.253 15.093 0Z"/>
|
|
3
|
+
<path fill="currentColor" fill-rule="nonzero" d="M295.155 162.808c-1.794.48-3.436 1.427-4.737 2.766-2.223 2.274-3.701 5.57-4.496 10.155-.493 2.969-.733 7.604-.493 10.964.354 5.128 1.036 8.083 2.577 11.292 1.616 3.309 3.839 5.38 6.896 6.264 1.339.392 4.837.392 6.315 0 5.33-1.427 8.88-6.707 10.117-15.043.341-4.004.291-8.02-.151-11.999-.783-4.774-2.312-8.526-4.535-10.9-2.008-2.438-5.027-3.802-8.184-3.701-1.099-.114-2.223-.05-3.309.202Zm45.735-.101c-1.667.467-3.233 1.276-4.585 2.375-2.071 1.819-3.701 5.077-4.597 9.069-.632 2.905-.885 5.38-.885 9.384 0 4.042.253 6.454.885 9.372 1.389 6.265 4.446 10.206 8.689 11.342 1.529.392 4.787.392 6.316 0 5.077-1.326 8.589-6.315 9.864-14.02.442-2.501.594-8.184.303-10.988-.795-7.958-3.7-13.376-8.197-15.536a17.769 17.769 0 0 0-2.766-.998c-1.667-.252-3.36-.252-5.027 0Z"/>
|
|
4
|
+
</svg>
|