@hashimkarim/usagestat-linux-x64-gnu 2.0.0-alpha.1 → 2.0.0-alpha.3
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 +365 -77
- package/package.json +49 -1
- package/plugins/UPSTREAM-LICENSES.md +109 -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/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 +0 -0
- package/plugins/antigravity/plugin.json +0 -0
- package/plugins/antigravity-cli/icon.svg +0 -0
- package/plugins/antigravity-cli/plugin.js +0 -0
- package/plugins/antigravity-cli/plugin.json +0 -0
- package/plugins/antigravity-ide/icon.svg +0 -0
- package/plugins/antigravity-ide/plugin.js +0 -0
- package/plugins/antigravity-ide/plugin.json +0 -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/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 +70 -23
- package/plugins/claude/plugin.json +0 -0
- 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 +71 -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.svg +0 -0
- package/plugins/codebuff/plugin.js +0 -0
- package/plugins/codebuff/plugin.json +0 -0
- package/plugins/codex/icon-color.svg +0 -0
- package/plugins/codex/icon.svg +0 -0
- package/plugins/codex/plugin.js +7 -2
- package/plugins/codex/plugin.json +0 -0
- package/plugins/command-code/icon.svg +0 -0
- package/plugins/command-code/plugin.js +7 -0
- package/plugins/command-code/plugin.json +0 -0
- package/plugins/copilot/icon-color.svg +0 -0
- package/plugins/copilot/icon.svg +0 -0
- package/plugins/copilot/plugin.js +61 -9
- package/plugins/copilot/plugin.json +4 -1
- 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.svg +0 -0
- package/plugins/crofai/plugin.js +0 -0
- package/plugins/crofai/plugin.json +0 -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.svg +4 -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 +0 -0
- package/plugins/deepseek/plugin.json +0 -0
- package/plugins/devin/icon.svg +0 -0
- package/plugins/devin/plugin.js +111 -0
- package/plugins/devin/plugin.json +2 -1
- 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.svg +0 -0
- package/plugins/elevenlabs/plugin.js +17 -2
- package/plugins/elevenlabs/plugin.json +0 -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.svg +0 -0
- 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/grok/icon.svg +0 -0
- package/plugins/grok/plugin.js +30 -5
- package/plugins/grok/plugin.json +3 -1
- package/plugins/groqcloud/icon.svg +0 -0
- package/plugins/groqcloud/plugin.js +0 -0
- package/plugins/groqcloud/plugin.json +0 -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.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 +0 -0
- 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/longcat/icon.svg +4 -0
- package/plugins/longcat/plugin.js +182 -0
- package/plugins/longcat/plugin.json +23 -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.svg +0 -0
- 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 +0 -0
- package/plugins/mistral/plugin.json +0 -0
- package/plugins/moonshot/icon.svg +0 -0
- package/plugins/moonshot/plugin.js +8 -6
- package/plugins/moonshot/plugin.json +0 -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/ollama/icon.svg +0 -0
- package/plugins/ollama/plugin.js +257 -56
- package/plugins/ollama/plugin.json +6 -3
- 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.svg +0 -0
- package/plugins/opencode/plugin.js +0 -0
- package/plugins/opencode/plugin.json +0 -0
- package/plugins/opencode-go/icon-conflict.svg +0 -0
- package/plugins/opencode-go/icon.svg +0 -0
- package/plugins/opencode-go/plugin.js +78 -10
- package/plugins/opencode-go/plugin.json +5 -2
- 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/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.svg +4 -0
- package/plugins/qwencloud/plugin.js +677 -0
- package/plugins/qwencloud/plugin.json +29 -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-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/venice/icon-color.svg +0 -0
- package/plugins/venice/icon.svg +0 -0
- package/plugins/venice/plugin.js +0 -0
- package/plugins/venice/plugin.json +0 -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-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.svg +7 -0
- package/plugins/xai/plugin.js +162 -0
- package/plugins/xai/plugin.json +28 -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.svg +3 -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,282 @@
|
|
|
1
|
+
(function () {
|
|
2
|
+
var BASE_URL = "https://app.notion.com";
|
|
3
|
+
var GET_SPACES_URL = "https://app.notion.com/api/v3/getSpaces";
|
|
4
|
+
var RATE_LIMIT_URL = "https://app.notion.com/api/v3/getCreditRateLimitStatus";
|
|
5
|
+
var SESSION_COOKIE_NAME = "token_v2";
|
|
6
|
+
var USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36";
|
|
7
|
+
|
|
8
|
+
function trim(value) {
|
|
9
|
+
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function env(ctx, name) {
|
|
13
|
+
try {
|
|
14
|
+
return trim(ctx.host.env.get(name));
|
|
15
|
+
} catch (_) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function setting(ctx, names) {
|
|
21
|
+
var settings = ctx.provider && ctx.provider.settings ? ctx.provider.settings : {};
|
|
22
|
+
for (var i = 0; i < names.length; i++) {
|
|
23
|
+
var value = trim(settings[names[i]]);
|
|
24
|
+
if (value) return value;
|
|
25
|
+
}
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function normalizeCookie(raw) {
|
|
30
|
+
var value = trim(raw);
|
|
31
|
+
if (!value) return null;
|
|
32
|
+
if (value.slice(0, 7).toLowerCase() === "cookie:") value = value.slice(7).trim();
|
|
33
|
+
if (!value) return null;
|
|
34
|
+
if (value.indexOf("=") < 0) return SESSION_COOKIE_NAME + "=" + value;
|
|
35
|
+
var pairs = [];
|
|
36
|
+
var chunks = value.split(";");
|
|
37
|
+
for (var i = 0; i < chunks.length; i++) {
|
|
38
|
+
var idx = chunks[i].indexOf("=");
|
|
39
|
+
if (idx < 0) continue;
|
|
40
|
+
var name = chunks[i].slice(0, idx).trim();
|
|
41
|
+
var val = chunks[i].slice(idx + 1).trim();
|
|
42
|
+
if (name && val) pairs.push(name + "=" + val);
|
|
43
|
+
}
|
|
44
|
+
return pairs.length ? pairs.join("; ") : null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function cookieHeader(ctx) {
|
|
48
|
+
return normalizeCookie(ctx.provider && ctx.provider.cookieHeader) ||
|
|
49
|
+
normalizeCookie(setting(ctx, ["cookieHeader", "cookie", "token"])) ||
|
|
50
|
+
normalizeCookie(env(ctx, "NOTION_COOKIE"));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function spaceOverride(ctx) {
|
|
54
|
+
return setting(ctx, ["spaceId", "workspaceId", "workspace"]) ||
|
|
55
|
+
trim(ctx.provider && ctx.provider.workspaceId) ||
|
|
56
|
+
env(ctx, "NOTION_SPACE_ID");
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function requestJson(ctx, url, cookie, body) {
|
|
60
|
+
var result = ctx.util.requestJson({
|
|
61
|
+
method: "POST",
|
|
62
|
+
url: url,
|
|
63
|
+
headers: {
|
|
64
|
+
Cookie: cookie,
|
|
65
|
+
"Content-Type": "application/json",
|
|
66
|
+
Accept: "*/*",
|
|
67
|
+
"Accept-Language": "en-US,en;q=0.9",
|
|
68
|
+
"User-Agent": USER_AGENT,
|
|
69
|
+
Referer: BASE_URL + "/",
|
|
70
|
+
Origin: BASE_URL,
|
|
71
|
+
"Sec-Fetch-Dest": "empty",
|
|
72
|
+
"Sec-Fetch-Mode": "cors",
|
|
73
|
+
"Sec-Fetch-Site": "same-origin",
|
|
74
|
+
},
|
|
75
|
+
bodyText: JSON.stringify(body || {}),
|
|
76
|
+
timeoutMs: 15000,
|
|
77
|
+
});
|
|
78
|
+
if (result.resp.status === 401) throw "Notion login required.";
|
|
79
|
+
if (result.resp.status < 200 || result.resp.status >= 300) throw "Notion API error: HTTP " + result.resp.status + ".";
|
|
80
|
+
if (!result.json || typeof result.json !== "object") throw "Could not parse Notion usage.";
|
|
81
|
+
return result.json;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function unwrapRecord(raw) {
|
|
85
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
|
|
86
|
+
var value = raw.value && typeof raw.value === "object" ? raw.value : raw;
|
|
87
|
+
if (value.value && typeof value.value === "object" && !Array.isArray(value.value)) return value.value;
|
|
88
|
+
return value;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function resolveUserId(root) {
|
|
92
|
+
var ids = [];
|
|
93
|
+
var keys = Object.keys(root || {});
|
|
94
|
+
for (var i = 0; i < keys.length; i++) {
|
|
95
|
+
var key = keys[i];
|
|
96
|
+
var container = root[key];
|
|
97
|
+
var users = container && container.notion_user;
|
|
98
|
+
var record = users && unwrapRecord(users[key]);
|
|
99
|
+
if (record && record.id === key) ids.push(key);
|
|
100
|
+
}
|
|
101
|
+
if (ids.length === 1) return ids[0];
|
|
102
|
+
return keys.length === 1 ? keys[0] : null;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function normalizeSpaceId(raw) {
|
|
106
|
+
var text = trim(raw);
|
|
107
|
+
if (!text) return null;
|
|
108
|
+
var compact = text.replace(/-/g, "").toLowerCase();
|
|
109
|
+
if (/^[0-9a-f]{32}$/.test(compact)) {
|
|
110
|
+
return compact.slice(0, 8) + "-" + compact.slice(8, 12) + "-" + compact.slice(12, 16) + "-" +
|
|
111
|
+
compact.slice(16, 20) + "-" + compact.slice(20);
|
|
112
|
+
}
|
|
113
|
+
return text.toLowerCase();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function parseSpaces(json) {
|
|
117
|
+
var root = json && typeof json === "object" && !Array.isArray(json) ? json : null;
|
|
118
|
+
if (!root) throw "getSpaces response is not a JSON object.";
|
|
119
|
+
var userId = resolveUserId(root);
|
|
120
|
+
if (!userId || !root[userId]) throw "getSpaces response did not identify a single user.";
|
|
121
|
+
var container = root[userId];
|
|
122
|
+
var email = null;
|
|
123
|
+
var users = container.notion_user || {};
|
|
124
|
+
var record = unwrapRecord(users[userId]);
|
|
125
|
+
if (!record) {
|
|
126
|
+
var userKeys = Object.keys(users);
|
|
127
|
+
for (var i = 0; i < userKeys.length && !record; i++) record = unwrapRecord(users[userKeys[i]]);
|
|
128
|
+
}
|
|
129
|
+
if (record && typeof record.email === "string") email = record.email;
|
|
130
|
+
|
|
131
|
+
var spaces = [];
|
|
132
|
+
var spaceObj = container.space || {};
|
|
133
|
+
var spaceKeys = Object.keys(spaceObj).sort();
|
|
134
|
+
for (var j = 0; j < spaceKeys.length; j++) {
|
|
135
|
+
var key = spaceKeys[j];
|
|
136
|
+
var ws = unwrapRecord(spaceObj[key]);
|
|
137
|
+
if (!ws) continue;
|
|
138
|
+
spaces.push({
|
|
139
|
+
id: String(ws.id || key),
|
|
140
|
+
name: trim(ws.name),
|
|
141
|
+
tier: trim(ws.subscription_tier),
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
return { email: email, workspaces: spaces };
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function mayHaveAllowance(workspace) {
|
|
148
|
+
var tier = String(workspace && workspace.tier || "").toLowerCase();
|
|
149
|
+
return tier === "business" || tier === "enterprise";
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function pickWorkspace(account, preferredId) {
|
|
153
|
+
var preferred = normalizeSpaceId(preferredId);
|
|
154
|
+
if (preferred) {
|
|
155
|
+
for (var i = 0; i < account.workspaces.length; i++) {
|
|
156
|
+
if (normalizeSpaceId(account.workspaces[i].id) === preferred) return account.workspaces[i];
|
|
157
|
+
}
|
|
158
|
+
throw "Selected Notion workspace was not found in this account.";
|
|
159
|
+
}
|
|
160
|
+
for (var j = 0; j < account.workspaces.length; j++) {
|
|
161
|
+
if (mayHaveAllowance(account.workspaces[j])) return account.workspaces[j];
|
|
162
|
+
}
|
|
163
|
+
return account.workspaces[0] || null;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function title(value) {
|
|
167
|
+
var text = trim(value);
|
|
168
|
+
return text ? text.charAt(0).toUpperCase() + text.slice(1) : null;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function number(value) {
|
|
172
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
173
|
+
if (typeof value === "string" && value.trim()) {
|
|
174
|
+
var parsed = Number(value.replace(/,/g, ""));
|
|
175
|
+
if (Number.isFinite(parsed)) return parsed;
|
|
176
|
+
}
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function percent(used, limit) {
|
|
181
|
+
used = number(used);
|
|
182
|
+
limit = number(limit);
|
|
183
|
+
if (used === null || limit === null || limit <= 0) return null;
|
|
184
|
+
return Math.max(0, used / limit * 100);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function minutesFromWindow(raw) {
|
|
188
|
+
var text = String(raw || "").trim().toLowerCase();
|
|
189
|
+
var match = /^(\d+)([mhdw])$/.exec(text);
|
|
190
|
+
if (!match) return null;
|
|
191
|
+
var n = Number(match[1]);
|
|
192
|
+
if (!n) return null;
|
|
193
|
+
if (match[2] === "m") return n;
|
|
194
|
+
if (match[2] === "h") return n * 60;
|
|
195
|
+
if (match[2] === "d") return n * 24 * 60;
|
|
196
|
+
return n * 7 * 24 * 60;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function rollingReset(ctx, seconds) {
|
|
200
|
+
var n = number(seconds);
|
|
201
|
+
if (n === null || n < 0) return null;
|
|
202
|
+
return ctx.util.toIso(Date.parse(ctx.nowIso) + n * 1000);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function dateFromMs(value) {
|
|
206
|
+
var n = number(value);
|
|
207
|
+
if (n === null || n <= 0) return null;
|
|
208
|
+
var date = new Date(n);
|
|
209
|
+
return Number.isFinite(date.getTime()) ? date.toISOString() : null;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function parseRateLimit(json) {
|
|
213
|
+
return {
|
|
214
|
+
status: trim(json && json.status),
|
|
215
|
+
window: json && json.window && typeof json.window === "object" ? json.window : null,
|
|
216
|
+
billing: json && json.billingPeriodWindow && typeof json.billingPeriodWindow === "object" ? json.billingPeriodWindow : null,
|
|
217
|
+
resetsInSeconds: number(json && json.resetsInSeconds),
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function buildSnapshot(ctx, rateLimit, workspace, account) {
|
|
222
|
+
if (rateLimit.status && rateLimit.status.toLowerCase() === "not_applicable") {
|
|
223
|
+
throw "Notion AI usage allowance is not tracked for " + (workspace.name || "this workspace") + ".";
|
|
224
|
+
}
|
|
225
|
+
var lines = [];
|
|
226
|
+
if (rateLimit.window) {
|
|
227
|
+
var pct = percent(rateLimit.window.used, rateLimit.window.limit);
|
|
228
|
+
if (pct !== null) {
|
|
229
|
+
var minutes = minutesFromWindow(rateLimit.window.window);
|
|
230
|
+
var opts = {
|
|
231
|
+
label: "Rolling",
|
|
232
|
+
used: Math.max(0, Math.min(100, pct)),
|
|
233
|
+
limit: 100,
|
|
234
|
+
format: { kind: "percent" },
|
|
235
|
+
};
|
|
236
|
+
if (minutes && minutes !== 30 * 24 * 60) opts.periodDurationMs = minutes * 60 * 1000;
|
|
237
|
+
var rolling = rollingReset(ctx, rateLimit.resetsInSeconds);
|
|
238
|
+
if (rolling) opts.resetsAt = rolling;
|
|
239
|
+
lines.push(ctx.line.progress(opts));
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
if (rateLimit.billing) {
|
|
243
|
+
var bpct = percent(rateLimit.billing.used, rateLimit.billing.limit);
|
|
244
|
+
if (bpct !== null) {
|
|
245
|
+
var bopts = {
|
|
246
|
+
label: "Monthly",
|
|
247
|
+
used: Math.max(0, Math.min(100, bpct)),
|
|
248
|
+
limit: 100,
|
|
249
|
+
format: { kind: "percent" },
|
|
250
|
+
};
|
|
251
|
+
var reset = dateFromMs(rateLimit.billing.periodEndMs);
|
|
252
|
+
if (reset) {
|
|
253
|
+
bopts.resetsAt = reset;
|
|
254
|
+
bopts.periodDurationMs = ctx.util.calendarMonthDuration(reset);
|
|
255
|
+
}
|
|
256
|
+
var start = dateFromMs(rateLimit.billing.periodStartMs);
|
|
257
|
+
if (reset && start && Date.parse(reset) > Date.parse(start)) bopts.periodDurationMs = Date.parse(reset) - Date.parse(start);
|
|
258
|
+
lines.push(ctx.line.progress(bopts));
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
if (!lines.length) throw "getCreditRateLimitStatus returned no measurable usage windows.";
|
|
262
|
+
if (account.email) lines.push(ctx.line.text({ label: "Account", value: account.email }));
|
|
263
|
+
return {
|
|
264
|
+
displayName: "Notion AI",
|
|
265
|
+
source: "web",
|
|
266
|
+
plan: title(workspace.tier),
|
|
267
|
+
lines: lines,
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function probe(ctx) {
|
|
272
|
+
var cookie = cookieHeader(ctx);
|
|
273
|
+
if (!cookie) throw "Notion session not configured. Set NOTION_COOKIE or provider cookieHeader.";
|
|
274
|
+
var account = parseSpaces(requestJson(ctx, GET_SPACES_URL, cookie, {}));
|
|
275
|
+
var workspace = pickWorkspace(account, spaceOverride(ctx));
|
|
276
|
+
if (!workspace) throw "No Notion workspace found for this account.";
|
|
277
|
+
var rateLimit = parseRateLimit(requestJson(ctx, RATE_LIMIT_URL, cookie, { spaceId: workspace.id }));
|
|
278
|
+
return buildSnapshot(ctx, rateLimit, workspace, account);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
globalThis.__openusage_plugin = { id: "notion", probe: probe };
|
|
282
|
+
})();
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"id": "notion",
|
|
4
|
+
"name": "Notion AI",
|
|
5
|
+
"version": "0.1.0",
|
|
6
|
+
"entry": "plugin.js",
|
|
7
|
+
"enabledByDefault": false,
|
|
8
|
+
"supportedModes": [
|
|
9
|
+
"web"
|
|
10
|
+
],
|
|
11
|
+
"autoMode": "web",
|
|
12
|
+
"webUrl": "https://app.notion.com",
|
|
13
|
+
"usageDashboardUrl": "https://app.notion.com/",
|
|
14
|
+
"statusPageUrl": "https://status.notion.so",
|
|
15
|
+
"links": [
|
|
16
|
+
{
|
|
17
|
+
"label": "Dashboard",
|
|
18
|
+
"url": "https://app.notion.com/"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"label": "Status",
|
|
22
|
+
"url": "https://status.notion.so"
|
|
23
|
+
}
|
|
24
|
+
],
|
|
25
|
+
"envVars": [
|
|
26
|
+
"NOTION_COOKIE",
|
|
27
|
+
"NOTION_SPACE_ID"
|
|
28
|
+
]
|
|
29
|
+
}
|
package/plugins/ollama/icon.svg
CHANGED
|
File without changes
|
package/plugins/ollama/plugin.js
CHANGED
|
@@ -1,92 +1,293 @@
|
|
|
1
1
|
(function () {
|
|
2
|
-
var SETTINGS_URL = "https://ollama.com/settings"
|
|
3
|
-
var
|
|
2
|
+
var SETTINGS_URL = "https://ollama.com/settings";
|
|
3
|
+
var TAGS_URL = "https://ollama.com/api/tags";
|
|
4
|
+
var VALIDATION_URL = "https://ollama.com/api/web_search";
|
|
5
|
+
var SESSION_COOKIE = "__Secure-session";
|
|
6
|
+
var SESSION_MS = 5 * 60 * 60 * 1000;
|
|
7
|
+
var WEEK_MS = 7 * 24 * 60 * 60 * 1000;
|
|
4
8
|
|
|
5
|
-
function
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
+
function clean(value) {
|
|
10
|
+
if (typeof value !== "string") return null;
|
|
11
|
+
var v = value.trim();
|
|
12
|
+
if (!v) return null;
|
|
13
|
+
if (
|
|
14
|
+
v.length >= 2 &&
|
|
15
|
+
((v.charAt(0) === '"' && v.charAt(v.length - 1) === '"') ||
|
|
16
|
+
(v.charAt(0) === "'" && v.charAt(v.length - 1) === "'"))
|
|
17
|
+
) {
|
|
18
|
+
v = v.slice(1, -1).trim();
|
|
19
|
+
}
|
|
20
|
+
return v || null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function env(ctx, name) {
|
|
24
|
+
try {
|
|
25
|
+
return clean(ctx.host.env.get(name));
|
|
26
|
+
} catch (_) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function setting(ctx, names) {
|
|
32
|
+
var settings = ctx.provider && ctx.provider.settings ? ctx.provider.settings : {};
|
|
33
|
+
for (var i = 0; i < names.length; i++) {
|
|
34
|
+
var value = clean(settings[names[i]]);
|
|
35
|
+
if (value) return value;
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function getApiKey(ctx) {
|
|
41
|
+
return clean(ctx.provider && ctx.provider.apiKey) ||
|
|
42
|
+
setting(ctx, ["apiKey", "ollamaApiKey"]) ||
|
|
43
|
+
env(ctx, "OLLAMA_API_KEY") ||
|
|
44
|
+
env(ctx, "OLLAMA_KEY");
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function getCookieHeader(ctx, optional) {
|
|
48
|
+
var raw = clean(ctx.provider && ctx.provider.cookieHeader) ||
|
|
49
|
+
setting(ctx, ["cookieHeader", "cookie"]) ||
|
|
50
|
+
env(ctx, "OLLAMA_COOKIE");
|
|
51
|
+
if (!raw) {
|
|
52
|
+
if (optional) return null;
|
|
53
|
+
throw "Set OLLAMA_COOKIE to your " + SESSION_COOKIE + " cookie value from ollama.com/settings.";
|
|
54
|
+
}
|
|
55
|
+
var val = raw;
|
|
56
|
+
if (val.toLowerCase().slice(0, 5) === "curl ") {
|
|
57
|
+
var cookieMatch = val.match(/(?:^|\s)-H\s+['"]Cookie:\s*([^'"]+)['"]/i) ||
|
|
58
|
+
val.match(/(?:^|\s)--header\s+['"]Cookie:\s*([^'"]+)['"]/i);
|
|
59
|
+
if (cookieMatch) val = cookieMatch[1].trim();
|
|
9
60
|
}
|
|
10
|
-
var val = raw.trim()
|
|
11
|
-
// Strip optional "cookie:" prefix
|
|
12
61
|
if (val.toLowerCase().slice(0, 7) === "cookie:") {
|
|
13
|
-
val = val.slice(7).trim()
|
|
62
|
+
val = val.slice(7).trim();
|
|
14
63
|
}
|
|
15
|
-
// If just a bare token value with no key=value format, wrap it
|
|
16
64
|
if (val.indexOf("=") < 0) {
|
|
17
|
-
return SESSION_COOKIE + "=" + val
|
|
65
|
+
return SESSION_COOKIE + "=" + val;
|
|
66
|
+
}
|
|
67
|
+
return val;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function request(ctx, req) {
|
|
71
|
+
try {
|
|
72
|
+
return ctx.host.http.request(req);
|
|
73
|
+
} catch (e) {
|
|
74
|
+
ctx.host.log.warn("Ollama request failed: " + String(e));
|
|
75
|
+
throw "Ollama request failed. Check your connection.";
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function parseJson(ctx, text) {
|
|
80
|
+
var parsed = ctx.util && typeof ctx.util.tryParseJson === "function"
|
|
81
|
+
? ctx.util.tryParseJson(text)
|
|
82
|
+
: null;
|
|
83
|
+
if (!parsed && text) {
|
|
84
|
+
try {
|
|
85
|
+
parsed = JSON.parse(text);
|
|
86
|
+
} catch (_) {}
|
|
87
|
+
}
|
|
88
|
+
return parsed;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function probeApi(ctx, apiKey) {
|
|
92
|
+
var validation = request(ctx, {
|
|
93
|
+
method: "POST",
|
|
94
|
+
url: VALIDATION_URL,
|
|
95
|
+
headers: {
|
|
96
|
+
Authorization: "Bearer " + apiKey,
|
|
97
|
+
Accept: "application/json",
|
|
98
|
+
"Content-Type": "application/json",
|
|
99
|
+
"User-Agent": "usagestat/" + String(ctx.app && ctx.app.version ? ctx.app.version : "0.0.0"),
|
|
100
|
+
},
|
|
101
|
+
bodyText: '{"query":""}',
|
|
102
|
+
timeoutMs: 15000,
|
|
103
|
+
});
|
|
104
|
+
if (validation.status === 401 || validation.status === 403) {
|
|
105
|
+
throw "Ollama API key is invalid or revoked.";
|
|
106
|
+
}
|
|
107
|
+
if (validation.status !== 200 && validation.status !== 400) {
|
|
108
|
+
throw "Ollama API validation returned HTTP " + validation.status + ".";
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
var tags = request(ctx, {
|
|
112
|
+
method: "GET",
|
|
113
|
+
url: TAGS_URL,
|
|
114
|
+
headers: {
|
|
115
|
+
Authorization: "Bearer " + apiKey,
|
|
116
|
+
Accept: "application/json",
|
|
117
|
+
"User-Agent": "usagestat/" + String(ctx.app && ctx.app.version ? ctx.app.version : "0.0.0"),
|
|
118
|
+
},
|
|
119
|
+
timeoutMs: 15000,
|
|
120
|
+
});
|
|
121
|
+
if (tags.status === 401 || tags.status === 403) {
|
|
122
|
+
throw "Ollama API key is invalid or revoked.";
|
|
123
|
+
}
|
|
124
|
+
if (tags.status < 200 || tags.status >= 300) {
|
|
125
|
+
throw "Ollama API returned HTTP " + tags.status + ".";
|
|
18
126
|
}
|
|
19
|
-
|
|
127
|
+
var parsed = parseJson(ctx, tags.bodyText);
|
|
128
|
+
if (!parsed || !Array.isArray(parsed.models)) {
|
|
129
|
+
throw "Ollama API tags response was not valid JSON.";
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return {
|
|
133
|
+
displayName: "Ollama",
|
|
134
|
+
source: "api",
|
|
135
|
+
plan: "API key",
|
|
136
|
+
lines: [
|
|
137
|
+
ctx.line.text({
|
|
138
|
+
label: "Cloud Models",
|
|
139
|
+
value: String(parsed.models.length) + " available",
|
|
140
|
+
}),
|
|
141
|
+
ctx.line.badge({
|
|
142
|
+
label: "Status",
|
|
143
|
+
text: "API key valid; quota unavailable",
|
|
144
|
+
color: "#22c55e",
|
|
145
|
+
}),
|
|
146
|
+
],
|
|
147
|
+
};
|
|
20
148
|
}
|
|
21
149
|
|
|
22
|
-
function
|
|
150
|
+
function blockEnd(html, start, currentLabel) {
|
|
151
|
+
var labels = ["Monthly usage", "Session usage", "Hourly usage", "Weekly usage"];
|
|
152
|
+
var end = html.length;
|
|
23
153
|
for (var i = 0; i < labels.length; i++) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
154
|
+
if (labels[i] === currentLabel) continue;
|
|
155
|
+
var idx = html.indexOf(labels[i], start + currentLabel.length);
|
|
156
|
+
if (idx >= 0 && idx < end) end = idx;
|
|
157
|
+
}
|
|
158
|
+
return Math.min(end, start + 4000);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function stripHtmlEntities(value) {
|
|
162
|
+
return String(value || "")
|
|
163
|
+
.replace(/ /g, " ")
|
|
164
|
+
.replace(/&/g, "&")
|
|
165
|
+
.replace(///g, "/")
|
|
166
|
+
.replace(/\s+/g, " ")
|
|
167
|
+
.trim();
|
|
168
|
+
}
|
|
27
169
|
|
|
28
|
-
|
|
29
|
-
|
|
170
|
+
function parseIso(segment) {
|
|
171
|
+
var match = String(segment || "").match(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})/);
|
|
172
|
+
if (!match) return null;
|
|
173
|
+
var ms = Date.parse(match[0]);
|
|
174
|
+
return Number.isFinite(ms) ? new Date(ms).toISOString() : null;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function parseResetDescription(segment) {
|
|
178
|
+
var match = String(segment || "").match(/(resets?\s+in\s+[^<\n\r]+|reset\s+[^<\n\r]+)/i);
|
|
179
|
+
return match ? stripHtmlEntities(match[1]) : null;
|
|
180
|
+
}
|
|
30
181
|
|
|
31
|
-
|
|
32
|
-
|
|
182
|
+
function parseUsageBlock(html, labels, periodMs) {
|
|
183
|
+
for (var i = 0; i < labels.length; i++) {
|
|
184
|
+
var label = labels[i];
|
|
185
|
+
var idx = html.indexOf(label);
|
|
186
|
+
if (idx < 0) continue;
|
|
187
|
+
var segment = html.slice(idx, blockEnd(html, idx, label));
|
|
188
|
+
var usedMatch = segment.match(/(\d+(?:\.\d+)?)\s*%\s*used/i);
|
|
189
|
+
var dollars = segment.match(/\$((?:\d{1,3}(?:,\d{3})+|\d+)(?:\.\d+)?)\s+of\s+\$((?:\d{1,3}(?:,\d{3})+|\d+)(?:\.\d+)?)\s+used/i);
|
|
190
|
+
var widthMatch = segment.match(/width:\s*(\d+(?:\.\d+)?)%/i);
|
|
191
|
+
var value = usedMatch ? parseFloat(usedMatch[1]) : null;
|
|
192
|
+
if (value === null && dollars) {
|
|
193
|
+
var spent = Number(dollars[1].replace(/,/g, ""));
|
|
194
|
+
var cap = Number(dollars[2].replace(/,/g, ""));
|
|
195
|
+
if (Number.isFinite(spent) && Number.isFinite(cap) && cap > 0) value = spent / cap * 100;
|
|
196
|
+
}
|
|
197
|
+
if (!Number.isFinite(value) && widthMatch) value = parseFloat(widthMatch[1]);
|
|
198
|
+
if (Number.isFinite(value)) {
|
|
199
|
+
return {
|
|
200
|
+
used: Math.max(0, Math.min(100, value)),
|
|
201
|
+
resetsAt: parseIso(segment),
|
|
202
|
+
detail: parseResetDescription(segment),
|
|
203
|
+
periodMs: label === "Hourly usage" ? null : periodMs,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
33
206
|
}
|
|
34
|
-
return null
|
|
207
|
+
return null;
|
|
35
208
|
}
|
|
36
209
|
|
|
37
|
-
function
|
|
38
|
-
var
|
|
210
|
+
function progress(ctx, label, block) {
|
|
211
|
+
var line = {
|
|
212
|
+
label: label,
|
|
213
|
+
used: block.used,
|
|
214
|
+
limit: 100,
|
|
215
|
+
format: { kind: "percent" },
|
|
216
|
+
};
|
|
217
|
+
if (block.periodMs) line.periodDurationMs = block.periodMs;
|
|
218
|
+
if (block.resetsAt) line.resetsAt = block.resetsAt;
|
|
219
|
+
if (block.detail) line.detail = block.detail;
|
|
220
|
+
return ctx.line.progress(line);
|
|
221
|
+
}
|
|
39
222
|
|
|
40
|
-
|
|
223
|
+
function probeWeb(ctx) {
|
|
224
|
+
var cookieHeader = getCookieHeader(ctx);
|
|
225
|
+
var resp = request(ctx, {
|
|
41
226
|
method: "GET",
|
|
42
227
|
url: SETTINGS_URL,
|
|
43
228
|
headers: {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
"User-Agent": "Mozilla/5.0 (
|
|
229
|
+
Cookie: cookieHeader,
|
|
230
|
+
Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
231
|
+
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/143.0.0.0 Safari/537.36",
|
|
47
232
|
},
|
|
48
233
|
timeoutMs: 20000,
|
|
49
|
-
})
|
|
234
|
+
});
|
|
50
235
|
|
|
51
236
|
if (resp.status === 401 || resp.status === 403) {
|
|
52
|
-
throw "Session expired. Update OLLAMA_COOKIE with a fresh session token."
|
|
237
|
+
throw "Session expired. Update OLLAMA_COOKIE with a fresh session token.";
|
|
53
238
|
}
|
|
54
239
|
|
|
55
|
-
var html = resp.bodyText || ""
|
|
56
|
-
|
|
57
|
-
if (!html.includes("Session usage") && !html.includes("Weekly usage") && !html.includes("Cloud Usage")) {
|
|
240
|
+
var html = resp.bodyText || "";
|
|
241
|
+
if (!html.includes("Monthly usage") && !html.includes("Session usage") && !html.includes("Weekly usage") && !html.includes("Cloud Usage")) {
|
|
58
242
|
if (html.includes("Sign in") || resp.status !== 200) {
|
|
59
|
-
throw "Session expired. Update OLLAMA_COOKIE with a fresh session token."
|
|
243
|
+
throw "Session expired. Update OLLAMA_COOKIE with a fresh session token.";
|
|
60
244
|
}
|
|
61
245
|
}
|
|
62
246
|
|
|
63
|
-
var
|
|
64
|
-
|
|
247
|
+
var monthly = parseUsageBlock(html, ["Monthly usage"], null);
|
|
248
|
+
if (monthly && monthly.resetsAt) monthly.periodMs = ctx.util.calendarMonthDuration(monthly.resetsAt);
|
|
249
|
+
var session = parseUsageBlock(html, ["Session usage", "Hourly usage"], SESSION_MS);
|
|
250
|
+
var weekly = parseUsageBlock(html, ["Weekly usage"], WEEK_MS);
|
|
65
251
|
|
|
66
|
-
if (
|
|
67
|
-
throw "Could not find usage data on Ollama settings page."
|
|
252
|
+
if (!monthly && !session && !weekly) {
|
|
253
|
+
throw "Could not find usage data on Ollama settings page.";
|
|
68
254
|
}
|
|
69
255
|
|
|
70
|
-
var lines = []
|
|
71
|
-
if (
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
256
|
+
var lines = [];
|
|
257
|
+
if (monthly) lines.push(progress(ctx, "Monthly credits", monthly));
|
|
258
|
+
if (session) lines.push(progress(ctx, "Session", session));
|
|
259
|
+
if (weekly) lines.push(progress(ctx, "Weekly", weekly));
|
|
260
|
+
|
|
261
|
+
var planMatch = html.match(/(?:Included usage|Cloud Usage)\s*<\/span>\s*<span[^>]*>([^<]+)<\/span/i);
|
|
262
|
+
return {
|
|
263
|
+
displayName: "Ollama",
|
|
264
|
+
source: "web",
|
|
265
|
+
plan: planMatch ? stripHtmlEntities(planMatch[1]) : undefined,
|
|
266
|
+
lines: lines,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function probe(ctx) {
|
|
271
|
+
var source = String(ctx.sourceMode || "auto").toLowerCase();
|
|
272
|
+
var apiKey = getApiKey(ctx);
|
|
273
|
+
if (source === "api") {
|
|
274
|
+
if (!apiKey) throw "Missing Ollama API key. Set OLLAMA_API_KEY.";
|
|
275
|
+
return probeApi(ctx, apiKey);
|
|
78
276
|
}
|
|
79
|
-
if (
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
277
|
+
if (source === "web") return probeWeb(ctx);
|
|
278
|
+
if (getCookieHeader(ctx, true)) {
|
|
279
|
+
try {
|
|
280
|
+
return probeWeb(ctx);
|
|
281
|
+
} catch (e) {
|
|
282
|
+
if (!apiKey) throw e;
|
|
283
|
+
ctx.host.log.warn("Ollama settings unavailable; checking API access.");
|
|
284
|
+
}
|
|
86
285
|
}
|
|
87
|
-
|
|
88
|
-
|
|
286
|
+
if (apiKey) {
|
|
287
|
+
return probeApi(ctx, apiKey);
|
|
288
|
+
}
|
|
289
|
+
return probeWeb(ctx);
|
|
89
290
|
}
|
|
90
291
|
|
|
91
|
-
globalThis.__openusage_plugin = { id: "ollama", probe: probe }
|
|
92
|
-
})()
|
|
292
|
+
globalThis.__openusage_plugin = { id: "ollama", probe: probe };
|
|
293
|
+
})();
|
|
@@ -8,13 +8,16 @@
|
|
|
8
8
|
"links": [
|
|
9
9
|
{ "label": "Settings", "url": "https://ollama.com/settings" }
|
|
10
10
|
],
|
|
11
|
-
"envVars": ["OLLAMA_COOKIE"],
|
|
12
|
-
"supportedModes": ["web"],
|
|
11
|
+
"envVars": ["OLLAMA_COOKIE", "OLLAMA_API_KEY", "OLLAMA_KEY"],
|
|
12
|
+
"supportedModes": ["api", "web"],
|
|
13
13
|
"autoMode": "web",
|
|
14
14
|
"webUrl": "https://ollama.com",
|
|
15
15
|
"usageDashboardUrl": "https://ollama.com/settings",
|
|
16
16
|
"lines": [
|
|
17
17
|
{ "type": "progress", "label": "Session", "scope": "overview" },
|
|
18
|
-
{ "type": "progress", "label": "Weekly", "scope": "detail" }
|
|
18
|
+
{ "type": "progress", "label": "Weekly", "scope": "detail" },
|
|
19
|
+
{ "type": "progress", "label": "Monthly credits", "scope": "overview" },
|
|
20
|
+
{ "type": "text", "label": "Cloud Models", "scope": "detail" },
|
|
21
|
+
{ "type": "badge", "label": "Status", "scope": "detail" }
|
|
19
22
|
]
|
|
20
23
|
}
|