opencode-pollinations-plugin 5.1.11 → 5.1.12
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/dist/server/config.d.ts +1 -0
- package/dist/server/config.js +61 -37
- package/dist/server/index.js +44 -1
- package/dist/server/proxy.js +2 -0
- package/package.json +1 -1
package/dist/server/config.d.ts
CHANGED
|
@@ -22,6 +22,7 @@ export interface PollinationsConfigV5 {
|
|
|
22
22
|
enablePaidTools: boolean;
|
|
23
23
|
statusBar: boolean;
|
|
24
24
|
}
|
|
25
|
+
export declare function subscribeToConfigChange(callback: () => void): void;
|
|
25
26
|
export declare function loadConfig(): PollinationsConfigV5;
|
|
26
27
|
export declare function saveConfig(updates: Partial<PollinationsConfigV5>): {
|
|
27
28
|
version: number;
|
package/dist/server/config.js
CHANGED
|
@@ -41,7 +41,57 @@ function logConfig(msg) {
|
|
|
41
41
|
}
|
|
42
42
|
catch (e) { }
|
|
43
43
|
}
|
|
44
|
+
// CACHE & WATCHER
|
|
45
|
+
let cachedConfig = null;
|
|
46
|
+
const listeners = [];
|
|
47
|
+
export function subscribeToConfigChange(callback) {
|
|
48
|
+
listeners.push(callback);
|
|
49
|
+
}
|
|
50
|
+
function notifyListeners() {
|
|
51
|
+
listeners.forEach(cb => {
|
|
52
|
+
try {
|
|
53
|
+
cb();
|
|
54
|
+
}
|
|
55
|
+
catch (e) {
|
|
56
|
+
logConfig(`Listener Error: ${e}`);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
// Watchers (Debounced)
|
|
61
|
+
const watchedFiles = new Set();
|
|
62
|
+
function watchFileSafe(filePath) {
|
|
63
|
+
if (watchedFiles.has(filePath))
|
|
64
|
+
return;
|
|
65
|
+
try {
|
|
66
|
+
if (!fs.existsSync(filePath))
|
|
67
|
+
return;
|
|
68
|
+
fs.watchFile(filePath, { interval: 2000 }, (curr, prev) => {
|
|
69
|
+
if (curr.mtime !== prev.mtime) {
|
|
70
|
+
logConfig(`File Changed: ${path.basename(filePath)}. Reloading Config...`);
|
|
71
|
+
cachedConfig = readConfigFromDisk();
|
|
72
|
+
notifyListeners();
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
watchedFiles.add(filePath);
|
|
76
|
+
}
|
|
77
|
+
catch (e) {
|
|
78
|
+
logConfig(`Watch Error for ${filePath}: ${e}`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
44
81
|
export function loadConfig() {
|
|
82
|
+
// 1. Return Cache if available
|
|
83
|
+
if (cachedConfig)
|
|
84
|
+
return cachedConfig;
|
|
85
|
+
// 2. Or Read Fresh
|
|
86
|
+
cachedConfig = readConfigFromDisk();
|
|
87
|
+
// 3. Initiate Watchers (Lazy)
|
|
88
|
+
watchFileSafe(CONFIG_FILE);
|
|
89
|
+
watchFileSafe(AUTH_FILE);
|
|
90
|
+
watchFileSafe(OPENCODE_CONFIG_FILE);
|
|
91
|
+
return cachedConfig;
|
|
92
|
+
}
|
|
93
|
+
// INTERNAL READER (The old loadConfig logic)
|
|
94
|
+
function readConfigFromDisk() {
|
|
45
95
|
let config = { ...DEFAULT_CONFIG_V5 };
|
|
46
96
|
let keyFound = false;
|
|
47
97
|
// 1. Try Custom Config
|
|
@@ -49,45 +99,16 @@ export function loadConfig() {
|
|
|
49
99
|
if (fs.existsSync(CONFIG_FILE)) {
|
|
50
100
|
const raw = fs.readFileSync(CONFIG_FILE, 'utf-8');
|
|
51
101
|
const custom = JSON.parse(raw);
|
|
52
|
-
//
|
|
102
|
+
// ... (Migration Logic is handled on Save, we trust Disk content here mostly)
|
|
53
103
|
if (!custom.version || custom.version < 5) {
|
|
54
|
-
|
|
55
|
-
//
|
|
56
|
-
if (custom.toastVerbosity) {
|
|
57
|
-
if (custom.toastVerbosity === 'none') {
|
|
58
|
-
config.gui.status = 'none';
|
|
59
|
-
config.gui.logs = 'none';
|
|
60
|
-
}
|
|
61
|
-
if (custom.toastVerbosity === 'alert') {
|
|
62
|
-
config.gui.status = 'alert';
|
|
63
|
-
config.gui.logs = 'error';
|
|
64
|
-
}
|
|
65
|
-
if (custom.toastVerbosity === 'all') {
|
|
66
|
-
config.gui.status = 'all';
|
|
67
|
-
config.gui.logs = 'verbose';
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
// Migrate Fallbacks
|
|
71
|
-
if (custom.fallbackModels) {
|
|
72
|
-
if (custom.fallbackModels.main)
|
|
73
|
-
config.fallbacks.free.main = custom.fallbackModels.main;
|
|
74
|
-
if (custom.fallbackModels.agent) {
|
|
75
|
-
config.fallbacks.free.agent = custom.fallbackModels.agent;
|
|
76
|
-
config.fallbacks.enter.agent = custom.fallbackModels.agent;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
// Preserve others
|
|
104
|
+
// If old, we don't migrate inside read to avoid write-loops.
|
|
105
|
+
// We just read what we can.
|
|
80
106
|
if (custom.apiKey)
|
|
81
107
|
config.apiKey = custom.apiKey;
|
|
82
108
|
if (custom.mode)
|
|
83
109
|
config.mode = custom.mode;
|
|
84
|
-
if (custom.statusBar !== undefined)
|
|
85
|
-
config.statusBar = custom.statusBar;
|
|
86
|
-
// Save Migrated
|
|
87
|
-
saveConfig(config);
|
|
88
110
|
}
|
|
89
111
|
else {
|
|
90
|
-
// Already V5
|
|
91
112
|
config = { ...config, ...custom };
|
|
92
113
|
}
|
|
93
114
|
if (config.apiKey)
|
|
@@ -103,14 +124,15 @@ export function loadConfig() {
|
|
|
103
124
|
if (fs.existsSync(AUTH_FILE)) {
|
|
104
125
|
const raw = fs.readFileSync(AUTH_FILE, 'utf-8');
|
|
105
126
|
const authData = JSON.parse(raw);
|
|
106
|
-
|
|
127
|
+
// Supports flat key or nested object
|
|
128
|
+
const entry = authData['pollinations'] || authData['pollinations_enter'] || authData['pollinations_api_key'];
|
|
107
129
|
if (entry) {
|
|
108
130
|
const key = (typeof entry === 'object' && entry.key) ? entry.key : entry;
|
|
109
131
|
if (key && typeof key === 'string' && key.length > 10) {
|
|
110
132
|
config.apiKey = key;
|
|
111
133
|
config.mode = 'pro';
|
|
112
134
|
keyFound = true;
|
|
113
|
-
logConfig(`
|
|
135
|
+
logConfig(`Hot-Loaded API Key from Auth Store`);
|
|
114
136
|
}
|
|
115
137
|
}
|
|
116
138
|
}
|
|
@@ -119,7 +141,7 @@ export function loadConfig() {
|
|
|
119
141
|
logConfig(`Error reading auth.json: ${e}`);
|
|
120
142
|
}
|
|
121
143
|
}
|
|
122
|
-
// 3. Try OpenCode Config
|
|
144
|
+
// 3. Try OpenCode Config (Fallback)
|
|
123
145
|
if (!keyFound) {
|
|
124
146
|
try {
|
|
125
147
|
if (fs.existsSync(OPENCODE_CONFIG_FILE)) {
|
|
@@ -136,7 +158,7 @@ export function loadConfig() {
|
|
|
136
158
|
}
|
|
137
159
|
catch (e) { }
|
|
138
160
|
}
|
|
139
|
-
// Default mode
|
|
161
|
+
// Default mode correction
|
|
140
162
|
if (!keyFound && config.mode === 'pro') {
|
|
141
163
|
config.mode = 'manual';
|
|
142
164
|
}
|
|
@@ -144,12 +166,14 @@ export function loadConfig() {
|
|
|
144
166
|
}
|
|
145
167
|
export function saveConfig(updates) {
|
|
146
168
|
try {
|
|
147
|
-
|
|
169
|
+
// We must base updates on current state (even if cached is slightly old, we refresh first?)
|
|
170
|
+
const current = readConfigFromDisk(); // Read disk for safety before write
|
|
148
171
|
const updated = { ...current, ...updates, version: 5 };
|
|
149
172
|
if (!fs.existsSync(CONFIG_DIR_POLLI)) {
|
|
150
173
|
fs.mkdirSync(CONFIG_DIR_POLLI, { recursive: true });
|
|
151
174
|
}
|
|
152
175
|
fs.writeFileSync(CONFIG_FILE, JSON.stringify(updated, null, 2));
|
|
176
|
+
cachedConfig = updated; // Update Cache immediately
|
|
153
177
|
return updated;
|
|
154
178
|
}
|
|
155
179
|
catch (e) {
|
package/dist/server/index.js
CHANGED
|
@@ -2,9 +2,18 @@ import * as http from 'http';
|
|
|
2
2
|
import * as fs from 'fs';
|
|
3
3
|
import * as path from 'path';
|
|
4
4
|
import { getAggregatedModels } from './pollinations-api.js';
|
|
5
|
-
import { loadConfig, saveConfig } from './config.js';
|
|
5
|
+
import { loadConfig, saveConfig, subscribeToConfigChange } from './config.js';
|
|
6
6
|
import { handleChatCompletion } from './proxy.js';
|
|
7
|
+
import { emitStatusToast } from './toast.js';
|
|
7
8
|
const LOG_FILE = path.join(process.env.HOME || '/tmp', '.config/opencode/plugins/pollinations-v3.log');
|
|
9
|
+
// Hot Reload Listener
|
|
10
|
+
subscribeToConfigChange(() => {
|
|
11
|
+
const config = loadConfig();
|
|
12
|
+
const mode = config.mode.toUpperCase();
|
|
13
|
+
const hasKey = !!config.apiKey;
|
|
14
|
+
log(`[HOT RELOAD] Config Updated. Mode: ${mode}, HasKey: ${hasKey}`);
|
|
15
|
+
emitStatusToast('info', `Configuration Updated (Hot Reload) | Mode: ${mode}`, 'Pollinations System');
|
|
16
|
+
});
|
|
8
17
|
// Simple file logger
|
|
9
18
|
function log(msg) {
|
|
10
19
|
const ts = new Date().toISOString();
|
|
@@ -18,6 +27,24 @@ function log(msg) {
|
|
|
18
27
|
// silent fail
|
|
19
28
|
}
|
|
20
29
|
}
|
|
30
|
+
// CRASH GUARD
|
|
31
|
+
const CRASH_LOG = '/tmp/opencode_pollinations_crash.log';
|
|
32
|
+
process.on('uncaughtException', (err) => {
|
|
33
|
+
try {
|
|
34
|
+
const msg = `[CRASH] Uncaught Exception: ${err.message}\n${err.stack}\n`;
|
|
35
|
+
fs.appendFileSync(CRASH_LOG, msg);
|
|
36
|
+
console.error(msg);
|
|
37
|
+
}
|
|
38
|
+
catch (e) { }
|
|
39
|
+
process.exit(1);
|
|
40
|
+
});
|
|
41
|
+
process.on('unhandledRejection', (reason, promise) => {
|
|
42
|
+
try {
|
|
43
|
+
const msg = `[CRASH] Unhandled Rejection: ${reason}\n`;
|
|
44
|
+
fs.appendFileSync(CRASH_LOG, msg);
|
|
45
|
+
}
|
|
46
|
+
catch (e) { }
|
|
47
|
+
});
|
|
21
48
|
const server = http.createServer(async (req, res) => {
|
|
22
49
|
log(`${req.method} ${req.url}`);
|
|
23
50
|
// CORS Headers
|
|
@@ -113,8 +140,24 @@ try {
|
|
|
113
140
|
}
|
|
114
141
|
}
|
|
115
142
|
catch (e) { }
|
|
143
|
+
// LIFECYCLE DEBUG (Sync Write)
|
|
144
|
+
const LIFE_LOG = '/tmp/POLLI_LIFECYCLE.log';
|
|
145
|
+
try {
|
|
146
|
+
fs.appendFileSync(LIFE_LOG, `[${new Date().toISOString()}] [STARTUP] PID:${process.pid} Initializing...\n`);
|
|
147
|
+
}
|
|
148
|
+
catch (e) { }
|
|
149
|
+
process.on('exit', (code) => {
|
|
150
|
+
try {
|
|
151
|
+
fs.appendFileSync(LIFE_LOG, `[${new Date().toISOString()}] [EXIT] PID:${process.pid} Exiting with code ${code}\n`);
|
|
152
|
+
}
|
|
153
|
+
catch (e) { }
|
|
154
|
+
});
|
|
116
155
|
server.listen(PORT, '127.0.0.1', () => {
|
|
117
156
|
const url = `http://127.0.0.1:${PORT}`;
|
|
118
157
|
log(`[SERVER] Started V3 Phase 3 (Auth Enabled) on port ${PORT}`);
|
|
158
|
+
try {
|
|
159
|
+
fs.appendFileSync(LIFE_LOG, `[${new Date().toISOString()}] [LISTEN] PID:${process.pid} Listening on ${PORT}\n`);
|
|
160
|
+
}
|
|
161
|
+
catch (e) { }
|
|
119
162
|
console.log(`POLLINATIONS_V3_URL=${url}`);
|
|
120
163
|
});
|
package/dist/server/proxy.js
CHANGED
|
@@ -149,6 +149,8 @@ export async function handleChatCompletion(req, res, bodyRaw) {
|
|
|
149
149
|
try {
|
|
150
150
|
const body = JSON.parse(bodyRaw);
|
|
151
151
|
const config = loadConfig();
|
|
152
|
+
// DEBUG: Trace Config State for Hot Reload verification
|
|
153
|
+
log(`[Proxy Request] Config Loaded. Mode: ${config.mode}, HasKey: ${!!config.apiKey}, KeyLength: ${config.apiKey ? config.apiKey.length : 0}`);
|
|
152
154
|
// 0. COMMAND HANDLING
|
|
153
155
|
if (body.messages && body.messages.length > 0) {
|
|
154
156
|
const lastMsg = body.messages[body.messages.length - 1];
|
package/package.json
CHANGED