opencode-pollinations-plugin 6.4.9 → 6.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.de.md +67 -54
- package/README.es.md +79 -66
- package/README.fr.md +70 -57
- package/README.it.md +78 -65
- package/README.md +33 -29
- package/README.zh.md +77 -64
- package/dist/locales/de.json +82 -47
- package/dist/locales/en.json +84 -49
- package/dist/locales/es.json +82 -47
- package/dist/locales/fr.json +81 -46
- package/dist/locales/it.json +82 -47
- package/dist/locales/zh.json +82 -47
- package/dist/server/commands.js +118 -178
- package/dist/server/config.d.ts +22 -6
- package/dist/server/config.js +45 -5
- package/dist/server/connect-response.js +7 -7
- package/dist/server/generate-config.js +2 -2
- package/dist/server/models/cache.d.ts +23 -10
- package/dist/server/models/cache.js +46 -24
- package/dist/server/models/fetcher.js +2 -0
- package/dist/server/models/types.d.ts +2 -0
- package/dist/server/models/worker.js +4 -4
- package/dist/server/proxy.d.ts +6 -0
- package/dist/server/proxy.js +318 -218
- package/dist/server/quota.d.ts +23 -32
- package/dist/server/quota.js +44 -184
- package/dist/server/scripts/pollinations_pricing.js +6 -3
- package/dist/server/status.js +1 -2
- package/dist/server/toast.js +1 -1
- package/dist/tools/index.d.ts +2 -1
- package/dist/tools/index.js +3 -1
- package/dist/tools/pollinations/artifact-core.d.ts +53 -0
- package/dist/tools/pollinations/artifact-core.js +159 -0
- package/dist/tools/pollinations/beta_discovery.js +2 -1
- package/dist/tools/pollinations/cost-guard.d.ts +2 -2
- package/dist/tools/pollinations/error-parser.d.ts +38 -0
- package/dist/tools/pollinations/error-parser.js +112 -0
- package/dist/tools/pollinations/gen_3d.d.ts +17 -0
- package/dist/tools/pollinations/gen_3d.js +207 -0
- package/dist/tools/pollinations/gen_image.js +29 -10
- package/dist/tools/pollinations/gen_music.js +3 -2
- package/dist/tools/pollinations/gen_video.js +13 -2
- package/dist/tools/pollinations/polli_config.js +15 -21
- package/dist/tools/pollinations/polli_gen_confirm.js +2 -0
- package/dist/tools/pollinations/shared.d.ts +1 -1
- package/dist/tools/pollinations/shared.js +53 -142
- package/dist/tools/pollinations/timeout-policy.d.ts +80 -0
- package/dist/tools/pollinations/timeout-policy.js +124 -0
- package/dist/tools/pollinations/tool-capability-registry.d.ts +51 -0
- package/dist/tools/pollinations/tool-capability-registry.js +215 -0
- package/dist/tools/pollinations/transcribe_audio.js +5 -24
- package/package.json +64 -62
- package/dist/server/tier-info.d.ts +0 -36
- package/dist/server/tier-info.js +0 -107
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool Capability Registry (v6.5) — capability-centric, declarative.
|
|
3
|
+
*
|
|
4
|
+
* Answers "HOW to execute this capability" — endpoint, transport, execution
|
|
5
|
+
* mode, timeouts, retry/recovery policy, artifact format, backend overrides.
|
|
6
|
+
*
|
|
7
|
+
* The Model Registry remains model-centric ("WHAT exists"). The TCR
|
|
8
|
+
* references/enriches it and does NOT duplicate model fields (pricing,
|
|
9
|
+
* paid_only, modalities stay in the Model Registry).
|
|
10
|
+
*
|
|
11
|
+
* Overrides that the live catalog does NOT expose (special headers, endpoint
|
|
12
|
+
* quirks, token formats) live here — never as `if (model === ...)` scattered
|
|
13
|
+
* across tools.
|
|
14
|
+
*/
|
|
15
|
+
import { resolveEffectiveTimeout } from './timeout-policy.js';
|
|
16
|
+
export const TOOL_CAPABILITIES = [
|
|
17
|
+
// ── Pollinations generation (cache-backed, LONG_BLOCKING, SERVER_DEDUP) ──
|
|
18
|
+
{
|
|
19
|
+
capability: 'gen_image',
|
|
20
|
+
backend: 'pollinations',
|
|
21
|
+
transport: { endpoint: 'https://gen.pollinations.ai/image/{prompt}', method: 'GET', mode: 'LONG_BLOCKING' },
|
|
22
|
+
execution: {
|
|
23
|
+
defaultTimeoutSeconds: 600,
|
|
24
|
+
retryPolicy: 'RECOVER_SAME_REQUEST',
|
|
25
|
+
idempotency: 'SERVER_DEDUP',
|
|
26
|
+
supportsCancel: false,
|
|
27
|
+
recovery: 'same request (same model/params/seed) → cache hit, not rebilled',
|
|
28
|
+
},
|
|
29
|
+
backendOverrides: {
|
|
30
|
+
'gpt-image-2': { quality: ['low', 'med', 'high'], transparent: true },
|
|
31
|
+
kontext: { header: 'x-usage-completion-image-tokens' },
|
|
32
|
+
klein: { header: 'x-usage-completion-image-tokens' },
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
capability: 'gen_video',
|
|
37
|
+
backend: 'pollinations',
|
|
38
|
+
// v6.5: /video/{prompt} is the canonical route (SDK/CLI).
|
|
39
|
+
transport: { endpoint: 'https://gen.pollinations.ai/video/{prompt}', method: 'GET', mode: 'LONG_BLOCKING' },
|
|
40
|
+
execution: {
|
|
41
|
+
defaultTimeoutSeconds: 1800,
|
|
42
|
+
retryPolicy: 'RECOVER_SAME_REQUEST',
|
|
43
|
+
idempotency: 'SERVER_DEDUP',
|
|
44
|
+
supportsCancel: false,
|
|
45
|
+
recovery: 'same request (same model/params/seed) → cache hit, not rebilled',
|
|
46
|
+
},
|
|
47
|
+
backendOverrides: {
|
|
48
|
+
wan: { requiresReferenceImage: true, t2vDummyImage: true },
|
|
49
|
+
veo: { interpolationRefs: 2 },
|
|
50
|
+
'seedance-*': { headerVideoTokens: true, fixedDuration4s: true },
|
|
51
|
+
'ltx-2': { error520Known: true },
|
|
52
|
+
'grok-video-pro': { forceAudio: true },
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
capability: 'gen_3d',
|
|
57
|
+
backend: 'pollinations',
|
|
58
|
+
transport: { endpoint: 'https://gen.pollinations.ai/3d/{prompt}', method: 'GET', mode: 'LONG_BLOCKING' },
|
|
59
|
+
outputs: { artifactFormat: 'glb', mime: 'model/gltf-binary' },
|
|
60
|
+
execution: {
|
|
61
|
+
defaultTimeoutSeconds: 1800,
|
|
62
|
+
retryPolicy: 'RECOVER_SAME_REQUEST',
|
|
63
|
+
idempotency: 'SERVER_DEDUP',
|
|
64
|
+
supportsCancel: false,
|
|
65
|
+
recovery: 'same request (same model/params/seed) → model3dCache hit, not rebilled',
|
|
66
|
+
},
|
|
67
|
+
backendOverrides: {
|
|
68
|
+
'trellis-2': { resolutions: ['low', 'medium', 'high'], timeoutSeconds: 1200, maxRefImages: 1 },
|
|
69
|
+
'hyper3d-rodin': { timeoutSeconds: 1800 },
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
capability: 'tts',
|
|
74
|
+
backend: 'pollinations',
|
|
75
|
+
transport: { endpoint: 'https://gen.pollinations.ai/v1/audio/speech', method: 'POST', mode: 'SHORT_REQUEST' },
|
|
76
|
+
execution: { defaultTimeoutSeconds: 600, retryPolicy: 'NO_AUTOMATIC_RETRY', idempotency: 'SERVER_DEDUP' },
|
|
77
|
+
backendOverrides: {
|
|
78
|
+
elevenlabs: { voices: 'registry' },
|
|
79
|
+
'openai-audio': { voices: ['alloy', 'echo', 'fable', 'onyx', 'nova', 'shimmer'], formats: ['mp3', 'wav', 'pcm16'] },
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
capability: 'music',
|
|
84
|
+
backend: 'pollinations',
|
|
85
|
+
transport: { endpoint: 'https://gen.pollinations.ai/audio/{prompt}', method: 'GET', mode: 'LONG_BLOCKING' },
|
|
86
|
+
execution: { defaultTimeoutSeconds: 600, retryPolicy: 'NO_AUTOMATIC_RETRY', idempotency: 'SERVER_DEDUP' },
|
|
87
|
+
constraints: { maxDurationSeconds: 300 },
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
capability: 'stt',
|
|
91
|
+
backend: 'pollinations',
|
|
92
|
+
transport: { endpoint: 'https://gen.pollinations.ai/v1/audio/transcriptions', method: 'POST', mode: 'SHORT_REQUEST' },
|
|
93
|
+
execution: { defaultTimeoutSeconds: 600, retryPolicy: 'NO_AUTOMATIC_RETRY' },
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
capability: 'web_search',
|
|
97
|
+
backend: 'pollinations',
|
|
98
|
+
transport: { endpoint: 'https://gen.pollinations.ai/v1/chat/completions', method: 'POST', mode: 'SHORT_REQUEST' },
|
|
99
|
+
execution: { defaultTimeoutSeconds: 300, retryPolicy: 'NO_AUTOMATIC_RETRY' },
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
capability: 'embed',
|
|
103
|
+
backend: 'pollinations',
|
|
104
|
+
transport: { endpoint: 'https://gen.pollinations.ai/v1/embeddings', method: 'POST', mode: 'SHORT_REQUEST' },
|
|
105
|
+
// Billable POST → never auto-replay (NOT a read-only operation).
|
|
106
|
+
execution: { defaultTimeoutSeconds: 60, retryPolicy: 'NO_AUTOMATIC_RETRY', idempotency: 'NONE' },
|
|
107
|
+
},
|
|
108
|
+
// ── Tier services (true ASYNC_JOB with job.id, re-poll safe) ──
|
|
109
|
+
{
|
|
110
|
+
capability: 'video_free',
|
|
111
|
+
backend: 'playground',
|
|
112
|
+
transport: { endpoint: 'https://pruna-playground-production-861e.up.railway.app/api/p-video/generate', method: 'POST', mode: 'ASYNC_JOB' },
|
|
113
|
+
execution: {
|
|
114
|
+
defaultTimeoutSeconds: 900,
|
|
115
|
+
retryPolicy: 'REPOLL_JOB',
|
|
116
|
+
idempotency: 'NONE',
|
|
117
|
+
pollIntervalSeconds: 4,
|
|
118
|
+
supportsCancel: false,
|
|
119
|
+
recovery: 're-poll job.id (never resubmit)',
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
capability: 'remove_background',
|
|
124
|
+
backend: 'imgtools',
|
|
125
|
+
// No modelId — the TCR is capability-centric, not model-centric.
|
|
126
|
+
transport: { endpoint: 'https://rmbg.bgeraser.com/api/rmbg', method: 'POST', mode: 'ASYNC_JOB' },
|
|
127
|
+
execution: {
|
|
128
|
+
defaultTimeoutSeconds: 300,
|
|
129
|
+
retryPolicy: 'REPOLL_JOB',
|
|
130
|
+
pollIntervalSeconds: 5,
|
|
131
|
+
supportsCancel: false,
|
|
132
|
+
recovery: 're-poll job.id / key rotation + provider fallback',
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
capability: 'object_remove',
|
|
137
|
+
backend: 'imgtools',
|
|
138
|
+
transport: { endpoint: 'https://objectremover.com/api/remove', method: 'POST', mode: 'ASYNC_JOB' },
|
|
139
|
+
execution: { defaultTimeoutSeconds: 300, retryPolicy: 'REPOLL_JOB', pollIntervalSeconds: 3 },
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
capability: 'image_upscale',
|
|
143
|
+
backend: 'imgtools',
|
|
144
|
+
transport: { endpoint: 'https://imgupscaler.com/api/upscale', method: 'POST', mode: 'ASYNC_JOB' },
|
|
145
|
+
execution: { defaultTimeoutSeconds: 300, retryPolicy: 'REPOLL_JOB', pollIntervalSeconds: 5 },
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
capability: 'image_enhance',
|
|
149
|
+
backend: 'imgtools',
|
|
150
|
+
transport: { endpoint: 'https://imgupscaler.com/api/enhance', method: 'POST', mode: 'ASYNC_JOB' },
|
|
151
|
+
execution: { defaultTimeoutSeconds: 300, retryPolicy: 'REPOLL_JOB', pollIntervalSeconds: 3 },
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
capability: 'upload',
|
|
155
|
+
backend: 'filehost',
|
|
156
|
+
transport: { endpoint: 'multi-provider cascade', method: 'POST', mode: 'SHORT_REQUEST' },
|
|
157
|
+
// POST upload → NOT a read-only op. The provider cascade is explicit,
|
|
158
|
+
// not an automatic same-request replay.
|
|
159
|
+
execution: { defaultTimeoutSeconds: 45, retryPolicy: 'NO_AUTOMATIC_RETRY', idempotency: 'NONE' },
|
|
160
|
+
},
|
|
161
|
+
// ── Local (offline) ──
|
|
162
|
+
{
|
|
163
|
+
capability: 'qrcode',
|
|
164
|
+
backend: 'local',
|
|
165
|
+
transport: { endpoint: 'local', method: 'GET', mode: 'LOCAL' },
|
|
166
|
+
execution: { retryPolicy: 'SAFE_READ_ONLY' },
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
capability: 'palette',
|
|
170
|
+
backend: 'local',
|
|
171
|
+
transport: { endpoint: 'local', method: 'GET', mode: 'LOCAL' },
|
|
172
|
+
execution: { retryPolicy: 'SAFE_READ_ONLY' },
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
capability: 'diagram',
|
|
176
|
+
backend: 'mermaid-ink',
|
|
177
|
+
transport: { endpoint: 'https://mermaid.ink', method: 'GET', mode: 'SHORT_REQUEST' },
|
|
178
|
+
execution: { defaultTimeoutSeconds: 15, retryPolicy: 'NO_AUTOMATIC_RETRY' },
|
|
179
|
+
},
|
|
180
|
+
];
|
|
181
|
+
/** Resolve a capability declaration by name (optionally filtered by backend). */
|
|
182
|
+
export function resolveCapability(capability, backend) {
|
|
183
|
+
return TOOL_CAPABILITIES.find(c => c.capability === capability && (backend === undefined || c.backend === backend));
|
|
184
|
+
}
|
|
185
|
+
export function listCapabilities() {
|
|
186
|
+
return TOOL_CAPABILITIES.map(c => c.capability);
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Effective timeout for a capability+model with full v6.5 precedence:
|
|
190
|
+
* per-call > USER model override > USER capability override
|
|
191
|
+
* > built-in model default > built-in capability > global.
|
|
192
|
+
*/
|
|
193
|
+
export function resolveCapabilityTimeout(capability, model, perCall, userConfig) {
|
|
194
|
+
const cap = resolveCapability(capability);
|
|
195
|
+
return resolveEffectiveTimeout({
|
|
196
|
+
perCall,
|
|
197
|
+
model,
|
|
198
|
+
capabilityKey: mapCapabilityToTimeoutKey(capability),
|
|
199
|
+
longRunning: cap?.transport.mode === 'LONG_BLOCKING',
|
|
200
|
+
user: userConfig ?? null,
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
function mapCapabilityToTimeoutKey(capability) {
|
|
204
|
+
if (capability === 'gen_image')
|
|
205
|
+
return 'image';
|
|
206
|
+
if (capability === 'gen_video')
|
|
207
|
+
return 'video';
|
|
208
|
+
if (capability === 'gen_3d')
|
|
209
|
+
return 'threeD';
|
|
210
|
+
if (capability === 'tts' || capability === 'music' || capability === 'stt')
|
|
211
|
+
return 'audio';
|
|
212
|
+
if (capability === 'embed')
|
|
213
|
+
return 'embed';
|
|
214
|
+
return undefined;
|
|
215
|
+
}
|
|
@@ -50,30 +50,11 @@ export const polliSttTool = tool({
|
|
|
50
50
|
// Download from URL
|
|
51
51
|
context.metadata({ title: t('tools.polli_transcribe_audio.toast_dl') });
|
|
52
52
|
try {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
protocol.get(audioPath, (res) => {
|
|
59
|
-
if (res.statusCode === 301 || res.statusCode === 302) {
|
|
60
|
-
// Follow redirect
|
|
61
|
-
const redirectUrl = res.headers.location;
|
|
62
|
-
if (redirectUrl) {
|
|
63
|
-
const redirectProtocol = redirectUrl.startsWith('https') ? https : http;
|
|
64
|
-
redirectProtocol.get(redirectUrl, (res2) => {
|
|
65
|
-
res2.on('data', chunk => chunks.push(chunk));
|
|
66
|
-
res2.on('end', () => resolve(Buffer.concat(chunks)));
|
|
67
|
-
res2.on('error', reject);
|
|
68
|
-
}).on('error', reject);
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
res.on('data', chunk => chunks.push(chunk));
|
|
73
|
-
res.on('end', () => resolve(Buffer.concat(chunks)));
|
|
74
|
-
res.on('error', reject);
|
|
75
|
-
}).on('error', reject);
|
|
76
|
-
});
|
|
53
|
+
// v6.5: use a single bounded fetch (timeout) instead of unbounded http(s).get.
|
|
54
|
+
audioBuffer = Buffer.from(await (await fetch(audioPath, {
|
|
55
|
+
signal: AbortSignal.timeout(60000),
|
|
56
|
+
redirect: 'follow',
|
|
57
|
+
})).arrayBuffer());
|
|
77
58
|
// Extract filename from URL
|
|
78
59
|
try {
|
|
79
60
|
const urlPath = new URL(audioPath).pathname;
|
package/package.json
CHANGED
|
@@ -1,65 +1,67 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
},
|
|
33
|
-
"bin": {
|
|
34
|
-
"opencode-pollinations-plugin": "./bin/setup.js"
|
|
35
|
-
},
|
|
36
|
-
"main": "./dist/index.js",
|
|
37
|
-
"types": "./dist/index.d.ts",
|
|
38
|
-
"engines": {
|
|
39
|
-
"node": ">=18"
|
|
40
|
-
},
|
|
41
|
-
"scripts": {
|
|
42
|
-
"build": "tsc",
|
|
43
|
-
"test": "npm run build && node scripts/tests/test-suite.cjs",
|
|
44
|
-
"test:unit": "node scripts/tests/test-suite.cjs",
|
|
45
|
-
"test:i18n": "node scripts/tests/test-i18n.cjs",
|
|
46
|
-
"prepare": "npm run build",
|
|
47
|
-
"prepublishOnly": "npm run build && npm run test:unit && npm run test:i18n"
|
|
48
|
-
},
|
|
49
|
-
"files": [
|
|
50
|
-
"dist",
|
|
51
|
-
"bin",
|
|
52
|
-
"README.md",
|
|
53
|
-
"LICENSE.md"
|
|
54
|
-
],
|
|
55
|
-
"dependencies": {
|
|
56
|
-
"@opencode-ai/plugin": "^1.0.85",
|
|
57
|
-
"qrcode": "^1.5.4",
|
|
58
|
-
"zod": "^3.25.76"
|
|
59
|
-
},
|
|
60
|
-
"devDependencies": {
|
|
61
|
-
"@types/node": "^20.0.0",
|
|
62
|
-
"@types/qrcode": "^1.5.6",
|
|
63
|
-
"typescript": "^5.0.0"
|
|
2
|
+
"name": "opencode-pollinations-plugin",
|
|
3
|
+
"displayName": "Pollinations",
|
|
4
|
+
"version": "6.5.0",
|
|
5
|
+
"description": "Native Pollinations.ai Provider Plugin for OpenCode — free & premium AI models, media tools, quests, cost guards",
|
|
6
|
+
"author": "fkom13",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"keywords": [
|
|
9
|
+
"opencode",
|
|
10
|
+
"pollinations",
|
|
11
|
+
"ai",
|
|
12
|
+
"plugin",
|
|
13
|
+
"image-generation",
|
|
14
|
+
"video-generation",
|
|
15
|
+
"llm",
|
|
16
|
+
"pollen"
|
|
17
|
+
],
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/fkom13/opencode-pollinations-plugin.git"
|
|
21
|
+
},
|
|
22
|
+
"bugs": {
|
|
23
|
+
"url": "https://github.com/fkom13/opencode-pollinations-plugin/issues"
|
|
24
|
+
},
|
|
25
|
+
"homepage": "https://github.com/fkom13/opencode-pollinations-plugin#readme",
|
|
26
|
+
"type": "module",
|
|
27
|
+
"exports": {
|
|
28
|
+
".": {
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"default": "./dist/index.js"
|
|
64
31
|
}
|
|
32
|
+
},
|
|
33
|
+
"bin": {
|
|
34
|
+
"opencode-pollinations-plugin": "bin/setup.js"
|
|
35
|
+
},
|
|
36
|
+
"main": "./dist/index.js",
|
|
37
|
+
"types": "./dist/index.d.ts",
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=18"
|
|
40
|
+
},
|
|
41
|
+
"scripts": {
|
|
42
|
+
"build": "tsc",
|
|
43
|
+
"test": "npm run build && node scripts/tests/test-suite.cjs && node scripts/tests/test-v65.cjs && node scripts/tests/test-i18n.cjs && node scripts/tests/test-ux-vocab.cjs",
|
|
44
|
+
"test:unit": "node scripts/tests/test-suite.cjs",
|
|
45
|
+
"test:v65": "node scripts/tests/test-v65.cjs",
|
|
46
|
+
"test:i18n": "node scripts/tests/test-i18n.cjs",
|
|
47
|
+
"prepare": "npm run build",
|
|
48
|
+
"prepublishOnly": "npm run build && npm run test:unit && npm run test:v65 && npm run test:i18n && npm run test:vocab",
|
|
49
|
+
"test:vocab": "node scripts/tests/test-ux-vocab.cjs"
|
|
50
|
+
},
|
|
51
|
+
"files": [
|
|
52
|
+
"dist",
|
|
53
|
+
"bin",
|
|
54
|
+
"README.md",
|
|
55
|
+
"LICENSE.md"
|
|
56
|
+
],
|
|
57
|
+
"dependencies": {
|
|
58
|
+
"@opencode-ai/plugin": "^1.0.85",
|
|
59
|
+
"qrcode": "^1.5.4",
|
|
60
|
+
"zod": "^3.25.76"
|
|
61
|
+
},
|
|
62
|
+
"devDependencies": {
|
|
63
|
+
"@types/node": "^20.0.0",
|
|
64
|
+
"@types/qrcode": "^1.5.6",
|
|
65
|
+
"typescript": "^5.0.0"
|
|
66
|
+
}
|
|
65
67
|
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tier Information - Central Configuration
|
|
3
|
-
*
|
|
4
|
-
* Hourly quota system (Pollinations API). Quotas refill every hour at :00.
|
|
5
|
-
* Tiers mirror the official pollinations/shared/tier-config.ts.
|
|
6
|
-
*
|
|
7
|
-
* NOTE (2026-06): The legacy account-level upgrade paths (dev-points → Seed,
|
|
8
|
-
* publish-app → Flower, admin tier-update) were removed upstream. Pollen is now
|
|
9
|
-
* primarily earned by completing Quests. The `condition` fields below describe
|
|
10
|
-
* the broad tier profile, not an automated upgrade trigger.
|
|
11
|
-
*/
|
|
12
|
-
export interface TierInfo {
|
|
13
|
-
name: string;
|
|
14
|
-
emoji: string;
|
|
15
|
-
hourlyPollen: number;
|
|
16
|
-
dailyEstimate: number;
|
|
17
|
-
condition: string;
|
|
18
|
-
conditionKey: string;
|
|
19
|
-
}
|
|
20
|
-
export declare const TIER_INFO: Record<string, TierInfo>;
|
|
21
|
-
/**
|
|
22
|
-
* Get tier info by name
|
|
23
|
-
*/
|
|
24
|
-
export declare function getTierInfo(tierName: string): TierInfo | undefined;
|
|
25
|
-
/**
|
|
26
|
-
* Get all tiers as array (sorted by hourlyPollen)
|
|
27
|
-
*/
|
|
28
|
-
export declare function getAllTiers(): TierInfo[];
|
|
29
|
-
/**
|
|
30
|
-
* Format tier list for display (markdown table)
|
|
31
|
-
*/
|
|
32
|
-
export declare function formatTierTable(lang?: 'en' | 'fr' | 'es' | 'de' | 'it' | 'zh'): string;
|
|
33
|
-
/**
|
|
34
|
-
* Get dynamic tier description with hourly rates
|
|
35
|
-
*/
|
|
36
|
-
export declare function getTierDescription(lang?: 'en' | 'fr' | 'es' | 'de' | 'it' | 'zh'): string;
|
package/dist/server/tier-info.js
DELETED
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tier Information - Central Configuration
|
|
3
|
-
*
|
|
4
|
-
* Hourly quota system (Pollinations API). Quotas refill every hour at :00.
|
|
5
|
-
* Tiers mirror the official pollinations/shared/tier-config.ts.
|
|
6
|
-
*
|
|
7
|
-
* NOTE (2026-06): The legacy account-level upgrade paths (dev-points → Seed,
|
|
8
|
-
* publish-app → Flower, admin tier-update) were removed upstream. Pollen is now
|
|
9
|
-
* primarily earned by completing Quests. The `condition` fields below describe
|
|
10
|
-
* the broad tier profile, not an automated upgrade trigger.
|
|
11
|
-
*/
|
|
12
|
-
import { t } from '../locales/index.js';
|
|
13
|
-
export const TIER_INFO = {
|
|
14
|
-
microbe: {
|
|
15
|
-
name: 'Microbe',
|
|
16
|
-
emoji: '🦠',
|
|
17
|
-
hourlyPollen: 0,
|
|
18
|
-
dailyEstimate: 0,
|
|
19
|
-
condition: 'Account under review',
|
|
20
|
-
conditionKey: 'tier.condition.under_review',
|
|
21
|
-
},
|
|
22
|
-
spore: {
|
|
23
|
-
name: 'Spore',
|
|
24
|
-
emoji: '🍄',
|
|
25
|
-
hourlyPollen: 0.01,
|
|
26
|
-
dailyEstimate: 0.24,
|
|
27
|
-
condition: 'New account (default)',
|
|
28
|
-
conditionKey: 'tier.condition.default',
|
|
29
|
-
},
|
|
30
|
-
seed: {
|
|
31
|
-
name: 'Seed',
|
|
32
|
-
emoji: '🌱',
|
|
33
|
-
hourlyPollen: 0.15,
|
|
34
|
-
dailyEstimate: 3.6,
|
|
35
|
-
condition: 'Active community member',
|
|
36
|
-
conditionKey: 'tier.condition.community',
|
|
37
|
-
},
|
|
38
|
-
flower: {
|
|
39
|
-
name: 'Flower',
|
|
40
|
-
emoji: '🌸',
|
|
41
|
-
hourlyPollen: 0.4,
|
|
42
|
-
dailyEstimate: 9.6,
|
|
43
|
-
condition: 'Complete Quests & contribute',
|
|
44
|
-
conditionKey: 'tier.condition.quests',
|
|
45
|
-
},
|
|
46
|
-
nectar: {
|
|
47
|
-
name: 'Nectar',
|
|
48
|
-
emoji: '🍯',
|
|
49
|
-
hourlyPollen: 0.8,
|
|
50
|
-
dailyEstimate: 19.2,
|
|
51
|
-
condition: 'Top contributor',
|
|
52
|
-
conditionKey: 'tier.condition.top_contributor',
|
|
53
|
-
},
|
|
54
|
-
router: {
|
|
55
|
-
name: 'Router',
|
|
56
|
-
emoji: '🐝',
|
|
57
|
-
hourlyPollen: 10,
|
|
58
|
-
dailyEstimate: 240,
|
|
59
|
-
condition: 'Special / invite-only',
|
|
60
|
-
conditionKey: 'tier.condition.special',
|
|
61
|
-
},
|
|
62
|
-
};
|
|
63
|
-
/**
|
|
64
|
-
* Get tier info by name
|
|
65
|
-
*/
|
|
66
|
-
export function getTierInfo(tierName) {
|
|
67
|
-
return TIER_INFO[tierName.toLowerCase()];
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* Get all tiers as array (sorted by hourlyPollen)
|
|
71
|
-
*/
|
|
72
|
-
export function getAllTiers() {
|
|
73
|
-
return Object.values(TIER_INFO).sort((a, b) => a.hourlyPollen - b.hourlyPollen);
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* Format tier list for display (markdown table)
|
|
77
|
-
*/
|
|
78
|
-
export function formatTierTable(lang = 'en') {
|
|
79
|
-
const tiers = getAllTiers();
|
|
80
|
-
const headers = {
|
|
81
|
-
en: '| Tier | Hourly | Daily (est.) | Condition |',
|
|
82
|
-
fr: '| Palier | Horaire | Journalier (est.) | Condition |',
|
|
83
|
-
es: '| Nivel | Por hora | Diario (est.) | Condición |',
|
|
84
|
-
de: '| Stufe | Pro Stunde | Täglich (ca.) | Bedingung |',
|
|
85
|
-
it: '| Livello | Orario | Giornaliero (stima) | Condizione |',
|
|
86
|
-
zh: '| 等级 | 每小时 | 每日 (估算) | 条件 |',
|
|
87
|
-
};
|
|
88
|
-
const separator = '|------|---------|----------------|-----------|';
|
|
89
|
-
const rows = tiers.map(tier => {
|
|
90
|
-
const conditionText = t(tier.conditionKey);
|
|
91
|
-
return `| ${tier.emoji} **${tier.name}** | **${tier.hourlyPollen} pollen/h** | ~${tier.dailyEstimate}/day | ${conditionText} |`;
|
|
92
|
-
});
|
|
93
|
-
return [headers[lang] || headers.en, separator, ...rows].join('\n');
|
|
94
|
-
}
|
|
95
|
-
/**
|
|
96
|
-
* Get dynamic tier description with hourly rates
|
|
97
|
-
*/
|
|
98
|
-
export function getTierDescription(lang = 'en') {
|
|
99
|
-
const perHour = lang === 'fr' ? '/heure' : '/hour';
|
|
100
|
-
const perDay = lang === 'fr' ? '/jour (est.)' : '/day (est.)';
|
|
101
|
-
const tiers = getAllTiers();
|
|
102
|
-
const lines = tiers.map(tier => {
|
|
103
|
-
const conditionText = t(tier.conditionKey);
|
|
104
|
-
return `- ${tier.emoji} **${tier.name}** (**${tier.hourlyPollen} Pollen${perHour}** ≈ ~${tier.dailyEstimate}${perDay}) : ${conditionText}`;
|
|
105
|
-
});
|
|
106
|
-
return lines.join('\n');
|
|
107
|
-
}
|