opencode-pollinations-plugin 6.0.0 → 6.1.0-beta.10
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.md +140 -87
- package/dist/index.js +33 -154
- package/dist/server/commands.d.ts +2 -0
- package/dist/server/commands.js +84 -25
- package/dist/server/config.d.ts +6 -0
- package/dist/server/config.js +4 -1
- package/dist/server/generate-config.d.ts +3 -30
- package/dist/server/generate-config.js +172 -100
- package/dist/server/index.d.ts +2 -1
- package/dist/server/index.js +124 -149
- package/dist/server/pollinations-api.d.ts +11 -0
- package/dist/server/pollinations-api.js +20 -0
- package/dist/server/proxy.js +158 -72
- package/dist/server/quota.d.ts +8 -0
- package/dist/server/quota.js +106 -61
- package/dist/server/toast.d.ts +3 -0
- package/dist/server/toast.js +16 -0
- package/dist/tools/design/gen_diagram.d.ts +2 -0
- package/dist/tools/design/gen_diagram.js +94 -0
- package/dist/tools/design/gen_palette.d.ts +2 -0
- package/dist/tools/design/gen_palette.js +182 -0
- package/dist/tools/design/gen_qrcode.d.ts +2 -0
- package/dist/tools/design/gen_qrcode.js +50 -0
- package/dist/tools/index.d.ts +22 -0
- package/dist/tools/index.js +81 -0
- package/dist/tools/pollinations/deepsearch.d.ts +7 -0
- package/dist/tools/pollinations/deepsearch.js +80 -0
- package/dist/tools/pollinations/gen_audio.d.ts +18 -0
- package/dist/tools/pollinations/gen_audio.js +204 -0
- package/dist/tools/pollinations/gen_image.d.ts +13 -0
- package/dist/tools/pollinations/gen_image.js +239 -0
- package/dist/tools/pollinations/gen_music.d.ts +14 -0
- package/dist/tools/pollinations/gen_music.js +139 -0
- package/dist/tools/pollinations/gen_video.d.ts +16 -0
- package/dist/tools/pollinations/gen_video.js +222 -0
- package/dist/tools/pollinations/search_crawl_scrape.d.ts +7 -0
- package/dist/tools/pollinations/search_crawl_scrape.js +85 -0
- package/dist/tools/pollinations/shared.d.ts +170 -0
- package/dist/tools/pollinations/shared.js +454 -0
- package/dist/tools/pollinations/transcribe_audio.d.ts +17 -0
- package/dist/tools/pollinations/transcribe_audio.js +235 -0
- package/dist/tools/power/extract_audio.d.ts +2 -0
- package/dist/tools/power/extract_audio.js +180 -0
- package/dist/tools/power/extract_frames.d.ts +2 -0
- package/dist/tools/power/extract_frames.js +240 -0
- package/dist/tools/power/file_to_url.d.ts +2 -0
- package/dist/tools/power/file_to_url.js +217 -0
- package/dist/tools/power/remove_background.d.ts +2 -0
- package/dist/tools/power/remove_background.js +365 -0
- package/dist/tools/power/rmbg_keys.d.ts +2 -0
- package/dist/tools/power/rmbg_keys.js +78 -0
- package/dist/tools/shared.d.ts +30 -0
- package/dist/tools/shared.js +74 -0
- package/package.json +9 -3
- package/dist/server/models-seed.d.ts +0 -18
- package/dist/server/models-seed.js +0 -55
package/README.md
CHANGED
|
@@ -1,119 +1,172 @@
|
|
|
1
|
-
# 🌸 Pollinations AI Plugin for OpenCode
|
|
1
|
+
# 🌸 Pollinations AI Plugin for OpenCode (v6.1-beta)
|
|
2
2
|
|
|
3
3
|
<div align="center">
|
|
4
|
-
<img src="https://avatars.githubusercontent.com/u/88394740?s=400&v=4" alt="Pollinations.ai Logo" width="
|
|
4
|
+
<img src="https://avatars.githubusercontent.com/u/88394740?s=400&v=4" alt="Pollinations.ai Logo" width="200">
|
|
5
5
|
<br>
|
|
6
|
-
<b>The Bridge between OpenCode and the Pollinations.ai Ecosystem
|
|
6
|
+
<b>The Bridge between OpenCode and the Pollinations.ai Ecosystem.</b>
|
|
7
7
|
<br>
|
|
8
|
-
Access
|
|
8
|
+
Access unlimited free AI models or premium enterprise models directly within your editor.
|
|
9
9
|
</div>
|
|
10
10
|
|
|
11
11
|
<div align="center">
|
|
12
12
|
|
|
13
|
-

|
|
14
14
|

|
|
15
|
-
 | [🛣️ Roadmap](./ROADMAP.md)
|
|
15
|
+

|
|
18
16
|
|
|
19
17
|
</div>
|
|
20
18
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
## ✨ Features
|
|
24
|
-
|
|
25
|
-
- **👁️ Vision Support**: Send images to AI models (OpenAI, Claude, Gemini, Kimi)
|
|
26
|
-
- **🧠 Reasoning Models**: Access advanced thinking models (DeepSeek, Kimi, Perplexity)
|
|
27
|
-
- **🛠️ Native Tools**: Full function calling support for compatible models
|
|
28
|
-
- **🔐 Secure Auth**: Native OpenCode `/connect` integration
|
|
29
|
-
- **🔄 Hot-Reload**: Change API keys without restarting OpenCode
|
|
30
|
-
|
|
31
|
-
---
|
|
32
|
-
|
|
33
|
-
## 🐝 Understanding Pollen & Tiers
|
|
34
|
-
|
|
35
|
-
**Pollen** is Pollinations' unified credit system. $1 ≈ 1 Pollen.
|
|
36
|
-
|
|
37
|
-
| Tier | Daily Grant | Requirement |
|
|
38
|
-
|:-----|:------------|:------------|
|
|
39
|
-
| 🦠 **Microbe** | 0.1 Pollen | Flagged accounts |
|
|
40
|
-
| 🌱 **Spore** | 1 Pollen | Sign up |
|
|
41
|
-
| 🌿 **Seed** | 3 Pollen | Active GitHub dev (8+ points) |
|
|
42
|
-
| 🌸 **Flower** | 10 Pollen | Published app |
|
|
43
|
-
| 🍯 **Nectar** | 20 Pollen | Major contributor |
|
|
44
|
-
|
|
45
|
-
> 💡 This plugin was published to the OpenCode ecosystem, granting its author **Flower** tier (10 Pollen/day).
|
|
46
|
-
|
|
47
|
-
---
|
|
19
|
+
## 📖 Philosophy: Open AI for Creators
|
|
48
20
|
|
|
49
|
-
|
|
21
|
+
> **"No closed doors, no corporate hoops — just good tools and good people."**
|
|
50
22
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
```
|
|
23
|
+
Pollinations.ai is an open-source platform built by and for the community. We provide a unified API for image, text, audio, and video generation.
|
|
24
|
+
- **Transparent**: Our code, roadmap, and discussions are open.
|
|
25
|
+
- **Community Driven**: Features are prioritized based on what *you* need.
|
|
26
|
+
- **Fair**: One single currency (**Pollen**) for all models. No complex subscriptions.
|
|
56
27
|
|
|
57
|
-
|
|
58
|
-
```
|
|
59
|
-
/connect
|
|
60
|
-
```
|
|
61
|
-
Select **pollinations** → Enter your API key from [enter.pollinations.ai](https://enter.pollinations.ai)
|
|
28
|
+
## 📸 Gallery
|
|
62
29
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
## 👁️ Vision Support
|
|
69
|
-
|
|
70
|
-
The following models support image input:
|
|
30
|
+
<p align="center">
|
|
31
|
+
<img src="https://github.com/fkom13/opencode-pollinations-plugin/raw/main/docs/images/connect.png" alt="Connect Command" width="800">
|
|
32
|
+
<br>
|
|
33
|
+
<em>Easy Connection with /connect or /pollinations config apiKey</em>
|
|
34
|
+
</p>
|
|
71
35
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
| `kimi` | ✅ | ✅ | - |
|
|
78
|
-
| `openai-audio` | ✅ | - | ✅ |
|
|
36
|
+
<p align="center">
|
|
37
|
+
<img src="https://github.com/fkom13/opencode-pollinations-plugin/raw/main/docs/images/usage_dashboard.png" alt="Usage Dashboard" width="800">
|
|
38
|
+
<br>
|
|
39
|
+
<em>Integrated Usage Dashboard (/pollinations usage)</em>
|
|
40
|
+
</p>
|
|
79
41
|
|
|
80
|
-
|
|
42
|
+
<p align="center">
|
|
43
|
+
<img src="https://github.com/fkom13/opencode-pollinations-plugin/raw/main/docs/images/models.png" alt="Models" width="800">
|
|
44
|
+
<br>
|
|
45
|
+
<em>Wide Range of Models (Mistral, OpenAI, Gemini, Claude)</em>
|
|
46
|
+
</p>
|
|
81
47
|
|
|
82
|
-
|
|
48
|
+
<p align="center">
|
|
49
|
+
<img src="https://github.com/fkom13/opencode-pollinations-plugin/raw/main/docs/images/free_add.png" alt="Free Chat Example" width="800">
|
|
50
|
+
<br>
|
|
51
|
+
<em>Free Universe Chat (Supported by Pollinations Ads)</em>
|
|
52
|
+
</p>
|
|
83
53
|
|
|
84
|
-
|
|
54
|
+
<p align="center">
|
|
55
|
+
<img src="https://github.com/fkom13/opencode-pollinations-plugin/raw/main/docs/images/plan_1.png" alt="Plan Build Step 1" width="400">
|
|
56
|
+
<img src="https://github.com/fkom13/opencode-pollinations-plugin/raw/main/docs/images/plan_2.png" alt="Plan Build Step 2" width="400">
|
|
57
|
+
<br>
|
|
58
|
+
<em>Integrated Plan Building Workflow</em>
|
|
59
|
+
</p>
|
|
85
60
|
|
|
86
|
-
|
|
87
|
-
- **OpenAI**: `openai`, `openai-fast`, `openai-large`
|
|
88
|
-
- **Gemini**: `gemini`, `gemini-fast`, `gemini-search`, `gemini-large` 💎
|
|
89
|
-
- **Claude**: `claude-fast`, `claude`, `claude-large` 💎
|
|
90
|
-
- **Reasoning**: `deepseek`, `kimi`, `perplexity-reasoning`
|
|
91
|
-
- **Code**: `qwen-coder`, `mistral`
|
|
92
|
-
- **Fast**: `nova-fast`, `grok`
|
|
61
|
+
## ✨ Features
|
|
93
62
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
- `claude-
|
|
63
|
+
- **🌍 Free Universe**: Access generic models (`openai`, `mistral`, `gemini`) for **FREE**, unlimited time, no API key required.
|
|
64
|
+
- **🛡️ Robust Quota System (New v6.1)**: Local "Ledger" technology (`~/.pollinations/usage_history.json`) ensures 100% accurate usage tracking, zero lag, and no wallet drain.
|
|
65
|
+
- **🚀 Pro Mode**: Connect your Pollinations API Key to access Premium Models (`claude-3-opus`, `gpt-4o`, `deepseek-coder`).
|
|
66
|
+
- **🔐 Limited Key Support**: Use keys restricted to "Generation Only". The plugin automatically disables Advanced Features (Dashboard/Quota) but allows full generation in Manual Mode.
|
|
67
|
+
- **🛡️ Safety Net V5**: never get blocked.
|
|
68
|
+
- **Transparent Fallback**: If your Pro quota runs out mid-chat, the plugin automatically switches to a free model instantly. No errors, just a seamless experience.
|
|
69
|
+
- **Smart Mode Switching**: Prevents Limited Keys from entering "Pro" mode to avoid confusing errors.
|
|
70
|
+
- **📊 Real-time Dashboard**: Track your **Pollen** usage, Tier Status, and Wallet Balance inside OpenCode.
|
|
71
|
+
- **🔇 Stealth Mode**: Status notifications are now strictly limited to Pollinations Enter (Paid) sessions. No more cluttered notifications when using other providers like Nvidia or Google AI.
|
|
97
72
|
|
|
98
|
-
|
|
73
|
+
### 📚 Documentation
|
|
99
74
|
|
|
100
|
-
|
|
75
|
+
- **[User Manual](docs/technical/manual.md)**
|
|
76
|
+
- **[API Reference](docs/technical/api_reference.md)**
|
|
77
|
+
- **[Architecture](docs/technical/architecture.md)**
|
|
101
78
|
|
|
102
|
-
|
|
103
|
-
/pollinations usage # View Pollen balance
|
|
104
|
-
/pollinations usage full # Detailed model breakdown
|
|
105
|
-
/pollinations status # Plugin health check
|
|
106
|
-
```
|
|
79
|
+
## 🐝 Understanding Pollen & Tiers
|
|
107
80
|
|
|
108
|
-
|
|
81
|
+
**Pollen** is our unified credit system. $1 ≈ 1 Pollen.
|
|
82
|
+
You spend it to verify API calls on premium models.
|
|
83
|
+
|
|
84
|
+
### Tiers (Free Daily Grants during Beta)
|
|
85
|
+
|
|
86
|
+
| Tier | Grant | Requirement |
|
|
87
|
+
| :--- | :--- | :--- |
|
|
88
|
+
| **🦠 Spore** | **1 Pollen/day** | Just Sign Up! |
|
|
89
|
+
| **🌱 Seed** | **3 Pollen/day** | Active GitHub Developer (8+ points) |
|
|
90
|
+
| **🌸 Flower** | **10 Pollen/day** | **Publish an App** (Like this Plugin!) |
|
|
91
|
+
| **🍯 Nectar** | **20 Pollen/day** | Major Contributors (Coming Soon) |
|
|
92
|
+
|
|
93
|
+
> 🎁 **Beta Bonus**: Buy one Pollen pack, get one free!
|
|
94
|
+
|
|
95
|
+
### 🐧 Platform Support & Dynamic Ports (v5.4.6+)
|
|
96
|
+
This plugin is **true Cross-Platform** (Windows, macOS, Linux).
|
|
97
|
+
- **Dynamic Port Allocation**: No more port conflicts! The plugin automatically finds an available port on startup.
|
|
98
|
+
- **Tools Support**: Using tools with Gemini (Free) triggers an **Automatic Intelligent Fallback** to OpenAI to ensure your workflow never breaks.
|
|
99
|
+
|
|
100
|
+
> **Note**: Legacy static port (10001) logic has been replaced with system-assigned ports (0). This eliminates "Address in use" errors and effectively removes the need for Linux-specific `fuser` commands, making the plugin fully **Cross-Platform**.
|
|
101
|
+
|
|
102
|
+
This plugin is part of the **OpenCode Ecosystem**.
|
|
103
|
+
|
|
104
|
+
### Option 1: NPM (Instant Setup) (Recommended)
|
|
105
|
+
This method automatically configures OpenCode to load the plugin.
|
|
106
|
+
|
|
107
|
+
1. Install global:
|
|
108
|
+
```bash
|
|
109
|
+
npm install -g opencode-pollinations-plugin
|
|
110
|
+
```
|
|
111
|
+
2. Run the Auto-Setup (Magic):
|
|
112
|
+
```bash
|
|
113
|
+
npx opencode-pollinations-plugin
|
|
114
|
+
```
|
|
115
|
+
*This detects your OpenCode config and injects the plugin path automatically.*
|
|
116
|
+
|
|
117
|
+
### Option 2: Manual Configuration
|
|
118
|
+
1. Install globally as above.
|
|
119
|
+
2. Edit `~/.config/opencode/opencode.json`:
|
|
120
|
+
```json
|
|
121
|
+
{
|
|
122
|
+
"plugin": [
|
|
123
|
+
"opencode-pollinations-plugin"
|
|
124
|
+
]
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
*Note: If OpenCode fails to find it, use the absolute path to the global install.*
|
|
128
|
+
|
|
129
|
+
## 🚀 Publication (The "Registry")
|
|
130
|
+
OpenCode uses NPM as its registry. To publish:
|
|
131
|
+
|
|
132
|
+
1. **Publish to NPM**:
|
|
133
|
+
```bash
|
|
134
|
+
npm login
|
|
135
|
+
npm publish
|
|
136
|
+
```
|
|
137
|
+
2. **Join Ecosystem**: Submit a Pull Request to [OpenCode Ecosystem](https://github.com/opencode-ai/ecosystem) to list your plugin officially.
|
|
138
|
+
*Once accepted, users can find it via documentation or future registry commands.*
|
|
139
|
+
|
|
140
|
+
## 🚀 Getting Started
|
|
141
|
+
|
|
142
|
+
### 1. The Basics (Free Mode)
|
|
143
|
+
Just type in the chat. You are in **Manual Mode** by default.
|
|
144
|
+
- Model: `openai-fast` (GPT-OSS 20b)
|
|
145
|
+
- Model: `mistral` (Mistral Small 3.1)
|
|
146
|
+
- ...
|
|
147
|
+
|
|
148
|
+
### 🔑 Configuration (API Key)
|
|
149
|
+
|
|
150
|
+
1. Run the setup command:
|
|
151
|
+
```bash
|
|
152
|
+
/connect
|
|
153
|
+
```
|
|
154
|
+
2. Choose "pollinations" and enter your key if you have one (or leave blank for free tier).
|
|
155
|
+
3. **IMPORTANT**: You must **restart OpenCode** for the model list to update with your new tier (e.g. to see Paid models).
|
|
156
|
+
|
|
157
|
+
### 🤖 Models
|
|
158
|
+
|
|
159
|
+
### 🔑 Types de Clés Supportés
|
|
160
|
+
- **Clés Standard (`sk-...`)**: Accès complet (Modèles + Dashboard Usage + Quota).
|
|
161
|
+
- **Clés Limitées**: Accès Génération uniquement. Le dashboard affichera une alerte de restriction.
|
|
162
|
+
- **Support Legacy**: Les anciennes clés (`sk_...`) sont aussi acceptées.
|
|
109
163
|
|
|
110
164
|
## 🔗 Links
|
|
111
165
|
|
|
112
|
-
- **
|
|
113
|
-
- **
|
|
114
|
-
- **
|
|
115
|
-
|
|
116
|
-
---
|
|
166
|
+
- **Sign up Pollinations Beta (more and best free tiers access and paids models)**: [pollinations.ai](https://enter.pollinations.ai)
|
|
167
|
+
- **Pollinations Website**: [pollinations.ai](https://pollinations.ai)
|
|
168
|
+
- **Discord Community**: [Join us!](https://discord.gg/pollinations-ai-885844321461485618)
|
|
169
|
+
- **OpenCode Ecosystem**: [opencode.ai](https://opencode.ai/docs/ecosystem#plugins)
|
|
117
170
|
|
|
118
171
|
## 📜 License
|
|
119
172
|
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import * as http from 'http';
|
|
2
2
|
import * as fs from 'fs';
|
|
3
3
|
import { generatePollinationsConfig } from './server/generate-config.js';
|
|
4
|
-
import { loadConfig
|
|
4
|
+
import { loadConfig } from './server/config.js';
|
|
5
5
|
import { handleChatCompletion } from './server/proxy.js';
|
|
6
|
-
import { createToastHooks, setGlobalClient } from './server/toast.js';
|
|
6
|
+
import { createToastHooks, createToolHooks, setGlobalClient } from './server/toast.js';
|
|
7
7
|
import { createStatusHooks } from './server/status.js';
|
|
8
|
-
import { createCommandHooks } from './server/commands.js';
|
|
8
|
+
import { createCommandHooks, setClientForCommands } from './server/commands.js';
|
|
9
|
+
import { createToolRegistry } from './tools/index.js';
|
|
9
10
|
import { createRequire } from 'module';
|
|
10
11
|
const require = createRequire(import.meta.url);
|
|
11
12
|
const LOG_FILE = '/tmp/opencode_pollinations_v4.log';
|
|
@@ -15,17 +16,12 @@ function log(msg) {
|
|
|
15
16
|
}
|
|
16
17
|
catch (e) { }
|
|
17
18
|
}
|
|
18
|
-
//
|
|
19
|
-
const DEFAULT_PORT = 18888;
|
|
20
|
-
const GLOBAL_SERVER_KEY = '__POLLINATIONS_PROXY_SERVER__';
|
|
19
|
+
// Port killing removed: Using dynamic ports.
|
|
21
20
|
const startProxy = () => {
|
|
22
|
-
// Check if server exists in global scope (survives module reloads)
|
|
23
|
-
if (global[GLOBAL_SERVER_KEY]) {
|
|
24
|
-
log(`[Proxy] Reusing existing global server on port ${DEFAULT_PORT}`);
|
|
25
|
-
return Promise.resolve(DEFAULT_PORT);
|
|
26
|
-
}
|
|
27
21
|
return new Promise((resolve) => {
|
|
28
22
|
const server = http.createServer(async (req, res) => {
|
|
23
|
+
// ... (Request Handling) ...
|
|
24
|
+
// We reuse the existing logic structure but simplified startup
|
|
29
25
|
log(`[Proxy] Request: ${req.method} ${req.url}`);
|
|
30
26
|
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
31
27
|
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
|
@@ -67,156 +63,40 @@ const startProxy = () => {
|
|
|
67
63
|
res.writeHead(404);
|
|
68
64
|
res.end("Not Found");
|
|
69
65
|
});
|
|
70
|
-
//
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
log(`[Proxy] Port ${port} in use, falling back to dynamic port`);
|
|
82
|
-
server.removeAllListeners('error');
|
|
83
|
-
tryListen(0, false); // Try dynamic port
|
|
84
|
-
}
|
|
85
|
-
else {
|
|
86
|
-
log(`[Proxy] Fatal Error: ${e}`);
|
|
87
|
-
resolve(0);
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
};
|
|
91
|
-
tryListen(DEFAULT_PORT, true);
|
|
66
|
+
// Listen on random port (0) to avoid conflicts (CLI/IDE)
|
|
67
|
+
server.listen(0, '127.0.0.1', () => {
|
|
68
|
+
// @ts-ignore
|
|
69
|
+
const assignedPort = server.address().port;
|
|
70
|
+
log(`[Proxy] Started v${require('../package.json').version} (Dynamic Port) on port ${assignedPort}`);
|
|
71
|
+
resolve(assignedPort);
|
|
72
|
+
});
|
|
73
|
+
server.on('error', (e) => {
|
|
74
|
+
log(`[Proxy] Fatal Error: ${e}`);
|
|
75
|
+
resolve(0);
|
|
76
|
+
});
|
|
92
77
|
});
|
|
93
78
|
};
|
|
94
|
-
// === AUTH HOOK: Native /connect Integration ===
|
|
95
|
-
// Auth Hook moved inside plugin to access context
|
|
96
79
|
// === PLUGIN EXPORT ===
|
|
97
80
|
export const PollinationsPlugin = async (ctx) => {
|
|
98
|
-
|
|
99
|
-
|
|
81
|
+
const v = require('../package.json').version;
|
|
82
|
+
log(`Plugin Initializing v${v}...`);
|
|
83
|
+
console.log(`🚀 POLLINATIONS PLUGIN v${v} LOADED 🚀`);
|
|
84
|
+
// START PROXY
|
|
100
85
|
const port = await startProxy();
|
|
101
86
|
const localBaseUrl = `http://127.0.0.1:${port}/v1`;
|
|
102
87
|
setGlobalClient(ctx.client);
|
|
88
|
+
setClientForCommands(ctx.client);
|
|
103
89
|
const toastHooks = createToastHooks(ctx.client);
|
|
104
90
|
const commandHooks = createCommandHooks();
|
|
105
|
-
//
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
if (isRefreshing)
|
|
109
|
-
return;
|
|
110
|
-
isRefreshing = true;
|
|
111
|
-
try {
|
|
112
|
-
log('[Event] Refreshing provider config after auth update...');
|
|
113
|
-
const modelsArray = await generatePollinationsConfig();
|
|
114
|
-
const modelsObj = {};
|
|
115
|
-
for (const m of modelsArray) {
|
|
116
|
-
modelsObj[m.id] = m;
|
|
117
|
-
}
|
|
118
|
-
const version = require('../package.json').version;
|
|
119
|
-
// CRITICAL: Fetch current config first to avoid overwriting other providers
|
|
120
|
-
let currentConfig = {};
|
|
121
|
-
try {
|
|
122
|
-
// Try to fetch existing config to preserve other providers
|
|
123
|
-
const response = await ctx.client.fetch('/config');
|
|
124
|
-
if (response.ok) {
|
|
125
|
-
currentConfig = await response.json();
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
catch (err) {
|
|
129
|
-
log(`[Event] Warning: Could not fetch current config: ${err}`);
|
|
130
|
-
}
|
|
131
|
-
// Safe Merge
|
|
132
|
-
if (!currentConfig.provider)
|
|
133
|
-
currentConfig.provider = {};
|
|
134
|
-
currentConfig.provider.pollinations = {
|
|
135
|
-
id: 'openai',
|
|
136
|
-
name: `Pollinations AI (v${version})`,
|
|
137
|
-
options: {
|
|
138
|
-
baseURL: localBaseUrl,
|
|
139
|
-
apiKey: 'plugin-managed',
|
|
140
|
-
},
|
|
141
|
-
models: modelsObj
|
|
142
|
-
};
|
|
143
|
-
// Use Server API to update config with the MERGED object
|
|
144
|
-
await ctx.client.fetch('/config', {
|
|
145
|
-
method: 'PATCH',
|
|
146
|
-
headers: { 'Content-Type': 'application/json' },
|
|
147
|
-
body: JSON.stringify({
|
|
148
|
-
provider: currentConfig.provider
|
|
149
|
-
})
|
|
150
|
-
});
|
|
151
|
-
log(`[Event] Provider config refreshed with ${Object.keys(modelsObj).length} models.`);
|
|
152
|
-
}
|
|
153
|
-
catch (e) {
|
|
154
|
-
log(`[Event] Failed to refresh provider config: ${e}`);
|
|
155
|
-
}
|
|
156
|
-
finally {
|
|
157
|
-
// Debounce: prevent another refresh for 5 seconds
|
|
158
|
-
setTimeout(() => { isRefreshing = false; }, 5000);
|
|
159
|
-
}
|
|
160
|
-
};
|
|
91
|
+
// Build tool registry (conditional on API key presence)
|
|
92
|
+
const toolRegistry = createToolRegistry();
|
|
93
|
+
log(`[Tools] ${Object.keys(toolRegistry).length} tools registered`);
|
|
161
94
|
return {
|
|
162
|
-
|
|
163
|
-
auth: {
|
|
164
|
-
provider: 'pollinations',
|
|
165
|
-
loader: async (auth, provider) => {
|
|
166
|
-
log('[AuthHook] loader() called');
|
|
167
|
-
try {
|
|
168
|
-
const authData = await auth();
|
|
169
|
-
if (authData && 'key' in authData) {
|
|
170
|
-
const k = authData.key;
|
|
171
|
-
saveConfig({ apiKey: k });
|
|
172
|
-
return { apiKey: k };
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
catch (e) {
|
|
176
|
-
log(`[AuthHook] loader error: ${e}`);
|
|
177
|
-
}
|
|
178
|
-
const config = loadConfig();
|
|
179
|
-
if (config.apiKey)
|
|
180
|
-
return { apiKey: config.apiKey };
|
|
181
|
-
return {};
|
|
182
|
-
},
|
|
183
|
-
methods: [{
|
|
184
|
-
type: 'api',
|
|
185
|
-
label: 'Pollinations API Key',
|
|
186
|
-
prompts: [{
|
|
187
|
-
type: 'text',
|
|
188
|
-
key: 'apiKey',
|
|
189
|
-
message: 'Enter Pollinations API Key (starts with sk_)',
|
|
190
|
-
validate: (v) => (!v || v.length < 10) ? 'Invalid key' : undefined
|
|
191
|
-
}],
|
|
192
|
-
authorize: async (inputs) => {
|
|
193
|
-
log(`[AuthHook] authorize() called`);
|
|
194
|
-
if (!inputs?.apiKey)
|
|
195
|
-
return { type: 'failed' };
|
|
196
|
-
try {
|
|
197
|
-
const r = await fetch('https://gen.pollinations.ai/text/models', {
|
|
198
|
-
headers: { 'Authorization': `Bearer ${inputs.apiKey}` }
|
|
199
|
-
});
|
|
200
|
-
if (r.ok) {
|
|
201
|
-
log('[AuthHook] Success. Saving & Refreshing Config...');
|
|
202
|
-
saveConfig({ apiKey: inputs.apiKey });
|
|
203
|
-
// CRITICAL: Refresh config IMMEDIATELY after successful auth
|
|
204
|
-
await refreshProviderConfig();
|
|
205
|
-
return { type: 'success', key: inputs.apiKey };
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
catch (e) {
|
|
209
|
-
log(`[AuthHook] Auth error: ${e}`);
|
|
210
|
-
}
|
|
211
|
-
return { type: 'failed' };
|
|
212
|
-
}
|
|
213
|
-
}]
|
|
214
|
-
},
|
|
215
|
-
// Event hook removed (logic moved to authorize)
|
|
216
|
-
event: async ({ event }) => { },
|
|
95
|
+
tool: toolRegistry,
|
|
217
96
|
async config(config) {
|
|
218
97
|
log("[Hook] config() called");
|
|
219
|
-
//
|
|
98
|
+
// STARTUP only - No complex hot reload logic
|
|
99
|
+
// The user must restart OpenCode to refresh this list if they change keys.
|
|
220
100
|
const modelsArray = await generatePollinationsConfig();
|
|
221
101
|
const modelsObj = {};
|
|
222
102
|
for (const m of modelsArray) {
|
|
@@ -224,19 +104,18 @@ export const PollinationsPlugin = async (ctx) => {
|
|
|
224
104
|
}
|
|
225
105
|
if (!config.provider)
|
|
226
106
|
config.provider = {};
|
|
107
|
+
// Dynamic Provider Name
|
|
227
108
|
const version = require('../package.json').version;
|
|
228
109
|
config.provider['pollinations'] = {
|
|
229
|
-
id: '
|
|
110
|
+
id: 'pollinations',
|
|
230
111
|
name: `Pollinations AI (v${version})`,
|
|
231
|
-
options: {
|
|
232
|
-
baseURL: localBaseUrl,
|
|
233
|
-
apiKey: 'plugin-managed', // Key is managed by auth hook
|
|
234
|
-
},
|
|
112
|
+
options: { baseURL: localBaseUrl },
|
|
235
113
|
models: modelsObj
|
|
236
114
|
};
|
|
237
115
|
log(`[Hook] Registered ${Object.keys(modelsObj).length} models.`);
|
|
238
116
|
},
|
|
239
117
|
...toastHooks,
|
|
118
|
+
...createToolHooks(ctx.client),
|
|
240
119
|
...createStatusHooks(ctx.client),
|
|
241
120
|
...commandHooks
|
|
242
121
|
};
|
|
@@ -9,8 +9,10 @@ interface CommandResult {
|
|
|
9
9
|
response?: string;
|
|
10
10
|
error?: string;
|
|
11
11
|
}
|
|
12
|
+
export declare function setClientForCommands(client: any): void;
|
|
12
13
|
export declare function handleCommand(command: string): Promise<CommandResult>;
|
|
13
14
|
export declare function createCommandHooks(): {
|
|
14
15
|
'tui.command.execute': (input: any, output: any) => Promise<void>;
|
|
16
|
+
'command.execute.before': (input: any, output: any) => Promise<void>;
|
|
15
17
|
};
|
|
16
18
|
export {};
|