opencode-pollinations-plugin 6.1.0-beta.9 → 6.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.de.md +130 -0
- package/README.es.md +130 -0
- package/README.fr.md +130 -0
- package/README.it.md +130 -0
- package/README.md +87 -73
- package/dist/index.js +52 -161
- package/dist/locales/de.json +374 -0
- package/dist/locales/en.json +373 -0
- package/dist/locales/es.json +374 -0
- package/dist/locales/fr.json +373 -0
- package/dist/locales/index.d.ts +1 -0
- package/dist/locales/index.js +37 -0
- package/dist/locales/it.json +374 -0
- package/dist/server/commands.d.ts +6 -0
- package/dist/server/commands.js +394 -125
- package/dist/server/config.d.ts +34 -23
- package/dist/server/config.js +200 -108
- package/dist/server/connect-response.d.ts +2 -0
- package/dist/server/connect-response.js +59 -0
- package/dist/server/generate-config.d.ts +3 -30
- package/dist/server/generate-config.js +164 -106
- package/dist/server/index.d.ts +2 -1
- package/dist/server/index.js +124 -149
- package/dist/server/logger.d.ts +8 -0
- package/dist/server/logger.js +38 -0
- package/dist/server/models/cache.d.ts +35 -0
- package/dist/server/models/cache.js +160 -0
- package/dist/server/models/fetcher.d.ts +18 -0
- package/dist/server/models/fetcher.js +194 -0
- package/dist/server/models/index.d.ts +6 -0
- package/dist/server/models/index.js +5 -0
- package/dist/server/models/manual.d.ts +15 -0
- package/dist/server/models/manual.js +92 -0
- package/dist/server/models/types.d.ts +55 -0
- package/dist/server/models/types.js +7 -0
- package/dist/server/models/worker.d.ts +22 -0
- package/dist/server/models/worker.js +174 -0
- package/dist/server/pollinations-api.d.ts +11 -0
- package/dist/server/pollinations-api.js +21 -8
- package/dist/server/proxy.js +222 -307
- package/dist/server/quota.d.ts +2 -0
- package/dist/server/quota.js +89 -86
- package/dist/server/scripts/pollinations_pricing.d.ts +8 -0
- package/dist/server/scripts/pollinations_pricing.js +246 -0
- package/dist/server/scripts/test_cost_endpoints.d.ts +1 -0
- package/dist/server/scripts/test_cost_endpoints.js +61 -0
- package/dist/server/scripts/test_dynamic_pricing.d.ts +1 -0
- package/dist/server/scripts/test_dynamic_pricing.js +39 -0
- package/dist/server/scripts/test_freetier_audit.d.ts +11 -0
- package/dist/server/scripts/test_freetier_audit.js +215 -0
- package/dist/server/scripts/test_parallel_cost.d.ts +1 -0
- package/dist/server/scripts/test_parallel_cost.js +104 -0
- package/dist/server/toast.d.ts +7 -1
- package/dist/server/toast.js +43 -10
- 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/ffmpeg.d.ts +24 -0
- package/dist/tools/ffmpeg.js +54 -0
- package/dist/tools/index.d.ts +25 -0
- package/dist/tools/index.js +86 -0
- package/dist/tools/pollinations/beta_discovery.d.ts +9 -0
- package/dist/tools/pollinations/beta_discovery.js +201 -0
- package/dist/tools/pollinations/cost-guard.d.ts +38 -0
- package/dist/tools/pollinations/cost-guard.js +136 -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 +220 -0
- package/dist/tools/pollinations/gen_image.d.ts +11 -0
- package/dist/tools/pollinations/gen_image.js +211 -0
- package/dist/tools/pollinations/gen_music.d.ts +14 -0
- package/dist/tools/pollinations/gen_music.js +157 -0
- package/dist/tools/pollinations/gen_video.d.ts +16 -0
- package/dist/tools/pollinations/gen_video.js +249 -0
- package/dist/tools/pollinations/polli_config.d.ts +2 -0
- package/dist/tools/pollinations/polli_config.js +95 -0
- package/dist/tools/pollinations/polli_gen_confirm.d.ts +2 -0
- package/dist/tools/pollinations/polli_gen_confirm.js +48 -0
- package/dist/tools/pollinations/polli_status.d.ts +2 -0
- package/dist/tools/pollinations/polli_status.js +31 -0
- package/dist/tools/pollinations/polli_web_search.d.ts +15 -0
- package/dist/tools/pollinations/polli_web_search.js +126 -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 +181 -0
- package/dist/tools/pollinations/shared.js +758 -0
- package/dist/tools/pollinations/test_estimators.d.ts +1 -0
- package/dist/tools/pollinations/test_estimators.js +22 -0
- package/dist/tools/pollinations/transcribe_audio.d.ts +13 -0
- package/dist/tools/pollinations/transcribe_audio.js +171 -0
- package/dist/tools/power/extract_audio.d.ts +2 -0
- package/dist/tools/power/extract_audio.js +179 -0
- package/dist/tools/power/extract_frames.d.ts +2 -0
- package/dist/tools/power/extract_frames.js +237 -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 +404 -0
- package/dist/tools/power/rmbg_keys.d.ts +2 -0
- package/dist/tools/power/rmbg_keys.js +79 -0
- package/dist/tools/shared.d.ts +30 -0
- package/dist/tools/shared.js +80 -0
- package/package.json +9 -3
- package/dist/server/models-seed.d.ts +0 -18
- package/dist/server/models-seed.js +0 -55
package/dist/server/config.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
export
|
|
1
|
+
export declare function getConfigDir(): string;
|
|
2
|
+
export declare const CONFIG_DIR: string;
|
|
3
|
+
export declare const CONFIG_FILE: string;
|
|
4
|
+
export interface PollinationsConfigV5 {
|
|
2
5
|
version: string | number;
|
|
3
|
-
mode: 'manual' | '
|
|
6
|
+
mode: 'manual' | 'alwaysfree' | 'pro';
|
|
4
7
|
apiKey?: string;
|
|
5
8
|
keyHasAccessToProfile?: boolean;
|
|
6
9
|
gui: {
|
|
@@ -9,24 +12,28 @@ export interface PollinationsConfigV6 {
|
|
|
9
12
|
};
|
|
10
13
|
thresholds: {
|
|
11
14
|
tier: number;
|
|
12
|
-
|
|
13
|
-
wallet_stop: number;
|
|
15
|
+
wallet: number;
|
|
14
16
|
};
|
|
15
17
|
fallbacks: {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
free: {
|
|
19
|
+
main: string;
|
|
20
|
+
agent: string;
|
|
21
|
+
};
|
|
22
|
+
enter: {
|
|
23
|
+
agent: string;
|
|
24
|
+
};
|
|
22
25
|
};
|
|
23
26
|
enablePaidTools: boolean;
|
|
27
|
+
costThreshold: number;
|
|
28
|
+
costConfirmationRequired: boolean;
|
|
24
29
|
statusBar: boolean;
|
|
30
|
+
costEstimator: boolean;
|
|
31
|
+
lang?: string;
|
|
25
32
|
}
|
|
26
|
-
export declare function loadConfig():
|
|
27
|
-
export declare function saveConfig(updates: Partial<
|
|
33
|
+
export declare function loadConfig(): PollinationsConfigV5;
|
|
34
|
+
export declare function saveConfig(updates: Partial<PollinationsConfigV5>): {
|
|
28
35
|
version: string;
|
|
29
|
-
mode: "manual" | "
|
|
36
|
+
mode: "manual" | "alwaysfree" | "pro";
|
|
30
37
|
apiKey?: string;
|
|
31
38
|
keyHasAccessToProfile?: boolean;
|
|
32
39
|
gui: {
|
|
@@ -35,19 +42,23 @@ export declare function saveConfig(updates: Partial<PollinationsConfigV6>): {
|
|
|
35
42
|
};
|
|
36
43
|
thresholds: {
|
|
37
44
|
tier: number;
|
|
38
|
-
|
|
39
|
-
wallet_stop: number;
|
|
45
|
+
wallet: number;
|
|
40
46
|
};
|
|
41
47
|
fallbacks: {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
+
free: {
|
|
49
|
+
main: string;
|
|
50
|
+
agent: string;
|
|
51
|
+
};
|
|
52
|
+
enter: {
|
|
53
|
+
agent: string;
|
|
54
|
+
};
|
|
48
55
|
};
|
|
49
56
|
enablePaidTools: boolean;
|
|
57
|
+
costThreshold: number;
|
|
58
|
+
costConfirmationRequired: boolean;
|
|
50
59
|
statusBar: boolean;
|
|
60
|
+
costEstimator: boolean;
|
|
61
|
+
lang?: string;
|
|
51
62
|
};
|
|
52
|
-
export declare function
|
|
53
|
-
export declare function
|
|
63
|
+
export declare function saveKeyToAuthJson(key: string): boolean;
|
|
64
|
+
export declare function migrateLegacyConfig(): void;
|
package/dist/server/config.js
CHANGED
|
@@ -2,14 +2,61 @@ import * as fs from 'fs';
|
|
|
2
2
|
import * as path from 'path';
|
|
3
3
|
import * as os from 'os';
|
|
4
4
|
// PATHS
|
|
5
|
+
// PATHS & CROSS-PLATFORM LOGIC
|
|
6
|
+
export function getConfigDir() {
|
|
7
|
+
switch (process.platform) {
|
|
8
|
+
case 'win32':
|
|
9
|
+
return path.join(process.env.APPDATA || os.homedir(), 'pollinations');
|
|
10
|
+
case 'darwin':
|
|
11
|
+
return path.join(os.homedir(), 'Library', 'Application Support', 'pollinations');
|
|
12
|
+
default:
|
|
13
|
+
return path.join(process.env.XDG_CONFIG_HOME || path.join(os.homedir(), '.config'), 'pollinations');
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export const CONFIG_DIR = getConfigDir();
|
|
17
|
+
export const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
|
|
18
|
+
// Legacy/External Paths (OpenCode specific)
|
|
5
19
|
const HOMEDIR = os.homedir();
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
|
|
20
|
+
// Multi-OS Candidate Paths for Auth & Global Config
|
|
21
|
+
function getExternalConfigPaths() {
|
|
22
|
+
const candidatesAuth = [];
|
|
23
|
+
const candidatesConfig = [];
|
|
24
|
+
// 0. OpenCode Environment Variables (Highest Priority)
|
|
25
|
+
if (process.env.OPENCODE_CONFIG) {
|
|
26
|
+
// Direct config file path
|
|
27
|
+
candidatesConfig.push(process.env.OPENCODE_CONFIG);
|
|
28
|
+
}
|
|
29
|
+
if (process.env.OPENCODE_CONFIG_DIR) {
|
|
30
|
+
// Config directory override
|
|
31
|
+
candidatesConfig.push(path.join(process.env.OPENCODE_CONFIG_DIR, 'opencode.json'));
|
|
32
|
+
candidatesConfig.push(path.join(process.env.OPENCODE_CONFIG_DIR, 'config.json'));
|
|
33
|
+
candidatesAuth.push(path.join(process.env.OPENCODE_CONFIG_DIR, 'auth.json'));
|
|
34
|
+
}
|
|
35
|
+
// Also check standard env vars often used in overrides
|
|
36
|
+
if (process.env.OPENCODE_AUTH)
|
|
37
|
+
candidatesAuth.push(process.env.OPENCODE_AUTH);
|
|
38
|
+
// 1. Linux Standard (Current)
|
|
39
|
+
// ... rest of function ...
|
|
40
|
+
candidatesAuth.push(path.join(HOMEDIR, '.local', 'share', 'opencode', 'auth.json'));
|
|
41
|
+
candidatesConfig.push(path.join(HOMEDIR, '.config', 'opencode', 'opencode.json'));
|
|
42
|
+
// 2. Windows Standard (%APPDATA%)
|
|
43
|
+
if (process.platform === 'win32') {
|
|
44
|
+
const appData = process.env.APPDATA || path.join(HOMEDIR, 'AppData', 'Roaming');
|
|
45
|
+
candidatesAuth.push(path.join(appData, 'opencode', 'auth.json'));
|
|
46
|
+
candidatesAuth.push(path.join(appData, 'OpenCode', 'auth.json'));
|
|
47
|
+
candidatesConfig.push(path.join(appData, 'opencode', 'config.json'));
|
|
48
|
+
}
|
|
49
|
+
// 3. Mac Standard
|
|
50
|
+
if (process.platform === 'darwin') {
|
|
51
|
+
const support = path.join(HOMEDIR, 'Library', 'Application Support', 'OpenCode');
|
|
52
|
+
candidatesAuth.push(path.join(support, 'auth.json'));
|
|
53
|
+
candidatesConfig.push(path.join(support, 'config.json'));
|
|
54
|
+
}
|
|
55
|
+
return { auth: candidatesAuth, config: candidatesConfig };
|
|
56
|
+
}
|
|
57
|
+
const EXTERNAL_PATHS = getExternalConfigPaths();
|
|
11
58
|
// LOAD PACKAGE VERSION
|
|
12
|
-
let PKG_VERSION = '
|
|
59
|
+
let PKG_VERSION = '5.2.0';
|
|
13
60
|
try {
|
|
14
61
|
const pkgPath = path.join(__dirname, '../../package.json');
|
|
15
62
|
if (fs.existsSync(pkgPath)) {
|
|
@@ -17,118 +64,113 @@ try {
|
|
|
17
64
|
PKG_VERSION = pkg.version;
|
|
18
65
|
}
|
|
19
66
|
}
|
|
20
|
-
catch (e) {
|
|
21
|
-
|
|
67
|
+
catch (e) {
|
|
68
|
+
logSystem(`[Config] Error loading package version: ${e}`);
|
|
69
|
+
}
|
|
70
|
+
const DEFAULT_CONFIG_V5 = {
|
|
22
71
|
version: PKG_VERSION,
|
|
23
|
-
mode: '
|
|
72
|
+
mode: 'manual',
|
|
24
73
|
gui: { status: 'alert', logs: 'none' },
|
|
25
|
-
thresholds: {
|
|
26
|
-
tier: 20, // 20% tier restant → alerte/fallback
|
|
27
|
-
wallet_warn: 20, // 20% wallet restant → alerte (pro)
|
|
28
|
-
wallet_stop: 0.50 // $0.50 → stop absolu (pro)
|
|
29
|
-
},
|
|
74
|
+
thresholds: { tier: 10, wallet: 5 },
|
|
30
75
|
fallbacks: {
|
|
31
|
-
|
|
32
|
-
|
|
76
|
+
free: { main: 'free/mistral', agent: 'free/openai-fast' },
|
|
77
|
+
enter: { agent: 'free/openai-fast' }
|
|
33
78
|
},
|
|
34
|
-
session: {},
|
|
35
79
|
enablePaidTools: false,
|
|
36
|
-
|
|
37
|
-
|
|
80
|
+
costThreshold: 0.15, // Default 0.15 🌻
|
|
81
|
+
costConfirmationRequired: true, // Ask confirmation when cost exceeds threshold
|
|
82
|
+
keyHasAccessToProfile: true, // Default true for legacy keys
|
|
83
|
+
statusBar: true,
|
|
84
|
+
costEstimator: true, // Show cost estimates by default
|
|
85
|
+
lang: 'en', // Default language is English
|
|
38
86
|
};
|
|
87
|
+
import { log as logSystem } from './logger.js';
|
|
39
88
|
function logConfig(msg) {
|
|
40
|
-
|
|
41
|
-
if (!fs.existsSync('/tmp/opencode_pollinations_config_debug.log')) {
|
|
42
|
-
fs.writeFileSync('/tmp/opencode_pollinations_config_debug.log', '');
|
|
43
|
-
}
|
|
44
|
-
fs.appendFileSync('/tmp/opencode_pollinations_config_debug.log', `[${new Date().toISOString()}] ${msg}\n`);
|
|
45
|
-
}
|
|
46
|
-
catch (e) { }
|
|
47
|
-
}
|
|
48
|
-
// MIGRATION: alwaysfree → economy
|
|
49
|
-
function migrateConfig(config) {
|
|
50
|
-
if (config.mode === 'alwaysfree') {
|
|
51
|
-
config.mode = 'economy';
|
|
52
|
-
logConfig('[Migration] alwaysfree → economy');
|
|
53
|
-
}
|
|
54
|
-
// Migrate old fallbacks structure
|
|
55
|
-
if (config.fallbacks?.free?.main) {
|
|
56
|
-
if (!config.fallbacks)
|
|
57
|
-
config.fallbacks = {};
|
|
58
|
-
config.fallbacks.economy = config.fallbacks.free.main.replace('free/', '');
|
|
59
|
-
delete config.fallbacks.free;
|
|
60
|
-
logConfig('[Migration] fallbacks.free → fallbacks.economy');
|
|
61
|
-
}
|
|
62
|
-
// Remove obsolete 'enter' fallback
|
|
63
|
-
if (config.fallbacks?.enter) {
|
|
64
|
-
delete config.fallbacks.enter;
|
|
65
|
-
logConfig('[Migration] Removed obsolete fallbacks.enter');
|
|
66
|
-
}
|
|
67
|
-
// Migrate old wallet threshold
|
|
68
|
-
if (config.thresholds?.wallet) {
|
|
69
|
-
if (!config.thresholds.wallet_warn) {
|
|
70
|
-
config.thresholds.wallet_warn = config.thresholds.wallet;
|
|
71
|
-
}
|
|
72
|
-
delete config.thresholds.wallet;
|
|
73
|
-
logConfig('[Migration] thresholds.wallet → thresholds.wallet_warn');
|
|
74
|
-
}
|
|
75
|
-
return config;
|
|
89
|
+
logSystem(`[Config] ${msg}`);
|
|
76
90
|
}
|
|
77
91
|
// SIMPLE LOAD (Direct Disk Read - No Caching, No Watchers)
|
|
92
|
+
// This ensures the Proxy ALWAYS sees the latest state from auth.json
|
|
78
93
|
export function loadConfig() {
|
|
79
94
|
return readConfigFromDisk();
|
|
80
95
|
}
|
|
81
96
|
function readConfigFromDisk() {
|
|
82
|
-
let config = { ...
|
|
97
|
+
let config = { ...DEFAULT_CONFIG_V5 };
|
|
83
98
|
let finalKey = undefined;
|
|
84
99
|
let source = 'none';
|
|
100
|
+
// TIMESTAMP BASED PRIORITY LOGIC
|
|
101
|
+
// We want the most recently updated Valid Key to win.
|
|
85
102
|
let configTime = 0;
|
|
86
103
|
let authTime = 0;
|
|
87
104
|
try {
|
|
88
105
|
if (fs.existsSync(CONFIG_FILE))
|
|
89
106
|
configTime = fs.statSync(CONFIG_FILE).mtime.getTime();
|
|
90
107
|
}
|
|
91
|
-
catch (e) {
|
|
108
|
+
catch (e) {
|
|
109
|
+
logSystem(`[Config] Error stat config: ${e}`);
|
|
110
|
+
}
|
|
111
|
+
try {
|
|
112
|
+
if (fs.existsSync(CONFIG_FILE))
|
|
113
|
+
configTime = fs.statSync(CONFIG_FILE).mtime.getTime();
|
|
114
|
+
}
|
|
115
|
+
catch (e) {
|
|
116
|
+
logSystem(`[Config] Error stat config: ${e}`);
|
|
117
|
+
}
|
|
92
118
|
try {
|
|
93
|
-
|
|
94
|
-
|
|
119
|
+
for (const f of EXTERNAL_PATHS.auth) {
|
|
120
|
+
if (fs.existsSync(f)) {
|
|
121
|
+
authTime = Math.max(authTime, fs.statSync(f).mtime.getTime());
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
catch (e) {
|
|
126
|
+
logSystem(`[Config] Error stat auth candidates: ${e}`);
|
|
95
127
|
}
|
|
96
|
-
|
|
128
|
+
// 1. EXTRACT KEYS
|
|
97
129
|
// 1. EXTRACT KEYS
|
|
98
130
|
let configKey = undefined;
|
|
99
131
|
if (fs.existsSync(CONFIG_FILE)) {
|
|
100
132
|
try {
|
|
101
133
|
const raw = fs.readFileSync(CONFIG_FILE, 'utf-8');
|
|
102
134
|
const custom = JSON.parse(raw);
|
|
103
|
-
|
|
104
|
-
// DEEP MERGE for nested objects to preserve defaults vs overrides
|
|
105
|
-
config = {
|
|
106
|
-
...config,
|
|
107
|
-
...migrated,
|
|
108
|
-
thresholds: { ...config.thresholds, ...(migrated.thresholds || {}) },
|
|
109
|
-
fallbacks: { ...config.fallbacks, ...(migrated.fallbacks || {}) },
|
|
110
|
-
gui: { ...config.gui, ...(migrated.gui || {}) }
|
|
111
|
-
};
|
|
135
|
+
config = { ...config, ...custom }; // Helper: We load the rest of config anyway
|
|
112
136
|
if (custom.apiKey && custom.apiKey.length > 5)
|
|
113
137
|
configKey = custom.apiKey;
|
|
114
138
|
}
|
|
115
|
-
catch (e) {
|
|
139
|
+
catch (e) {
|
|
140
|
+
logConfig(`ERROR reading config.json: ${e}`);
|
|
141
|
+
// Backup corrupt file to avoid overwrite loop
|
|
142
|
+
try {
|
|
143
|
+
fs.copyFileSync(CONFIG_FILE, CONFIG_FILE + '.corrupt');
|
|
144
|
+
}
|
|
145
|
+
catch (e) {
|
|
146
|
+
logSystem(`[Config] Error copying corrupt config: ${e}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
116
149
|
}
|
|
117
150
|
let authKey = undefined;
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
151
|
+
// Check all auth candidates
|
|
152
|
+
for (const authFile of EXTERNAL_PATHS.auth) {
|
|
153
|
+
if (fs.existsSync(authFile)) {
|
|
154
|
+
try {
|
|
155
|
+
authTime = Math.max(authTime, fs.statSync(authFile).mtime.getTime()); // Track newest
|
|
156
|
+
const raw = fs.readFileSync(authFile, 'utf-8');
|
|
157
|
+
const authData = JSON.parse(raw);
|
|
158
|
+
const entry = authData['pollinations'] || authData['pollinations_enter'] || authData['pollinations_api_key'];
|
|
159
|
+
if (entry) {
|
|
160
|
+
const k = (typeof entry === 'object' && entry.key) ? entry.key : entry;
|
|
161
|
+
if (k && typeof k === 'string' && k.length > 10) {
|
|
162
|
+
authKey = k;
|
|
163
|
+
break; // Found a key, stop looking (priority to first found? or newest? First in list is Linux default so ok)
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
catch (e) {
|
|
168
|
+
logConfig(`ERROR reading auth candidate ${authFile}: ${e}`);
|
|
127
169
|
}
|
|
128
170
|
}
|
|
129
|
-
catch (e) { }
|
|
130
171
|
}
|
|
131
172
|
// 2. DETERMINE WINNER
|
|
173
|
+
// If both exist, newest wins. If one exists, it wins.
|
|
132
174
|
if (configKey && authKey) {
|
|
133
175
|
if (configTime >= authTime) {
|
|
134
176
|
finalKey = configKey;
|
|
@@ -150,25 +192,37 @@ function readConfigFromDisk() {
|
|
|
150
192
|
// 3. Fallback to OpenCode Global Config (Lowest Priority)
|
|
151
193
|
if (!finalKey) {
|
|
152
194
|
try {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
data?.provider?.
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
195
|
+
for (const configFile of EXTERNAL_PATHS.config) {
|
|
196
|
+
if (fs.existsSync(configFile)) {
|
|
197
|
+
const raw = fs.readFileSync(configFile, 'utf-8');
|
|
198
|
+
const data = JSON.parse(raw);
|
|
199
|
+
const nativeKey = data?.provider?.pollinations?.options?.apiKey ||
|
|
200
|
+
data?.provider?.pollinations_enter?.options?.apiKey;
|
|
201
|
+
if (nativeKey && nativeKey.length > 5 && nativeKey !== 'dummy') {
|
|
202
|
+
finalKey = nativeKey;
|
|
203
|
+
source = 'opencode_global';
|
|
204
|
+
break;
|
|
205
|
+
}
|
|
161
206
|
}
|
|
162
207
|
}
|
|
163
208
|
}
|
|
164
|
-
catch (e) {
|
|
209
|
+
catch (e) {
|
|
210
|
+
logSystem(`[Config] Error reading global override config: ${e}`);
|
|
211
|
+
}
|
|
165
212
|
}
|
|
166
213
|
// 4. APPLY
|
|
167
214
|
if (finalKey) {
|
|
168
215
|
config.apiKey = finalKey;
|
|
216
|
+
// config.mode = 'pro'; // REMOVED: Mode is decoupled from Key presence.
|
|
169
217
|
}
|
|
170
218
|
else {
|
|
219
|
+
// Ensure no phantom key remains
|
|
171
220
|
delete config.apiKey;
|
|
221
|
+
// if (config.mode === 'pro') config.mode = 'manual'; // OPTIONAL: Downgrade if no key? User says "No link".
|
|
222
|
+
// Actually, if I am in PRO mode and lose my key, I am broken. Falling back to manual is safer?
|
|
223
|
+
// User said "Manual mode is like standard API".
|
|
224
|
+
// Let's REMOVE this auto-downgrade too to be strictly "Decoupled".
|
|
225
|
+
// If user is in PRO without key, they get "Missing Key" error, which is correct.
|
|
172
226
|
}
|
|
173
227
|
return { ...config, version: PKG_VERSION };
|
|
174
228
|
}
|
|
@@ -176,11 +230,10 @@ export function saveConfig(updates) {
|
|
|
176
230
|
try {
|
|
177
231
|
const current = readConfigFromDisk();
|
|
178
232
|
const updated = { ...current, ...updates, version: PKG_VERSION };
|
|
179
|
-
if (!fs.existsSync(
|
|
180
|
-
fs.mkdirSync(
|
|
233
|
+
if (!fs.existsSync(CONFIG_DIR)) {
|
|
234
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
181
235
|
}
|
|
182
236
|
fs.writeFileSync(CONFIG_FILE, JSON.stringify(updated, null, 2));
|
|
183
|
-
logConfig(`[SaveConfig] Updated: ${Object.keys(updates).join(', ')}`);
|
|
184
237
|
return updated;
|
|
185
238
|
}
|
|
186
239
|
catch (e) {
|
|
@@ -188,23 +241,62 @@ export function saveConfig(updates) {
|
|
|
188
241
|
throw e;
|
|
189
242
|
}
|
|
190
243
|
}
|
|
191
|
-
//
|
|
192
|
-
export function
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
244
|
+
// === NATIVE AUTH SYNC ===
|
|
245
|
+
export function saveKeyToAuthJson(key) {
|
|
246
|
+
let success = false;
|
|
247
|
+
for (const authFile of EXTERNAL_PATHS.auth) {
|
|
248
|
+
try {
|
|
249
|
+
let authData = {};
|
|
250
|
+
if (fs.existsSync(authFile)) {
|
|
251
|
+
authData = JSON.parse(fs.readFileSync(authFile, 'utf-8'));
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
// Ensure directory exists if we create a new auth.json
|
|
255
|
+
fs.mkdirSync(path.dirname(authFile), { recursive: true });
|
|
199
256
|
}
|
|
200
|
-
|
|
201
|
-
|
|
257
|
+
// Set the key (OpenCode standard struct)
|
|
258
|
+
authData['pollinations'] = {
|
|
259
|
+
type: "api",
|
|
260
|
+
key: key
|
|
261
|
+
};
|
|
262
|
+
fs.writeFileSync(authFile, JSON.stringify(authData, null, 2), 'utf-8');
|
|
263
|
+
logConfig(`Synchronized API key to native auth file: ${authFile}`);
|
|
264
|
+
success = true;
|
|
265
|
+
// Only write to the first valid one we find/create, or write to all existing?
|
|
266
|
+
// Usually writing to all existing ones is safest to avoid desync
|
|
267
|
+
}
|
|
268
|
+
catch (e) {
|
|
269
|
+
logConfig(`Failed to sync to auth file ${authFile}: ${e}`);
|
|
270
|
+
}
|
|
202
271
|
}
|
|
272
|
+
return success;
|
|
203
273
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
274
|
+
// === MIGRATION UTIL ===
|
|
275
|
+
export function migrateLegacyConfig() {
|
|
276
|
+
try {
|
|
277
|
+
const legacyDir = path.join(os.homedir(), '.pollinations');
|
|
278
|
+
const newDir = getConfigDir();
|
|
279
|
+
if (fs.existsSync(legacyDir) && legacyDir !== newDir) {
|
|
280
|
+
logConfig(`Migrating legacy config from ${legacyDir} to ${newDir}`);
|
|
281
|
+
if (!fs.existsSync(newDir))
|
|
282
|
+
fs.mkdirSync(newDir, { recursive: true });
|
|
283
|
+
const files = fs.readdirSync(legacyDir);
|
|
284
|
+
for (const file of files) {
|
|
285
|
+
const srcPath = path.join(legacyDir, file);
|
|
286
|
+
const destPath = path.join(newDir, file);
|
|
287
|
+
// Don't overwrite existing new files (priority to new system)
|
|
288
|
+
if (!fs.existsSync(destPath)) {
|
|
289
|
+
// Check if it's a file
|
|
290
|
+
if (fs.statSync(srcPath).isFile()) {
|
|
291
|
+
fs.copyFileSync(srcPath, destPath); // Copy first
|
|
292
|
+
// fs.unlinkSync(srcPath); // Optional: Delete old? Let's keep for safety for now.
|
|
293
|
+
logConfig(`Migrated: ${file}`);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
catch (e) {
|
|
300
|
+
logConfig(`Migration Error: ${e}`);
|
|
301
|
+
}
|
|
210
302
|
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { t } from '../locales/index.js';
|
|
2
|
+
export async function buildConnectResponse(config) {
|
|
3
|
+
const hasKey = !!config.apiKey;
|
|
4
|
+
const mode = config.mode;
|
|
5
|
+
let name = "Developer";
|
|
6
|
+
let tier = "anonymous";
|
|
7
|
+
if (hasKey) {
|
|
8
|
+
try {
|
|
9
|
+
const res = await fetch('https://gen.pollinations.ai/account/profile', {
|
|
10
|
+
headers: { 'Authorization': `Bearer ${config.apiKey}` }
|
|
11
|
+
});
|
|
12
|
+
if (res.ok) {
|
|
13
|
+
const data = await res.json();
|
|
14
|
+
if (data.name)
|
|
15
|
+
name = data.name;
|
|
16
|
+
tier = data.tier || "anonymous";
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
catch (e) {
|
|
20
|
+
// Ignorer l'erreur réseau et garder les valeurs par défaut
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
const emojis = {
|
|
24
|
+
microbe: '🦠', spore: '🍄', seed: '🌱', flower: '🌸', nectar: '🍯', anonymous: '👤'
|
|
25
|
+
};
|
|
26
|
+
const tierEmoji = emojis[tier] || '❓';
|
|
27
|
+
if (hasKey) {
|
|
28
|
+
return `${t('connect_response.title_key', { name, mode })}
|
|
29
|
+
|
|
30
|
+
> **Your Tiers:** ${tierEmoji} ${tier.toUpperCase()}
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
${t('connect_response.tools_intro')}
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
${t('connect_response.terminal_cmds')}
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
${t('connect_response.resources')}`;
|
|
42
|
+
}
|
|
43
|
+
let freeModelsText = `Modèles gratuits disponibles : \`openai-fast\`, \`gemini-fast\`, \`mistral\`, \`qwen-coder\`, \`nova-fast\``;
|
|
44
|
+
try {
|
|
45
|
+
const freeRes = await fetch('https://text.pollinations.ai/models', { signal: AbortSignal.timeout(4000) });
|
|
46
|
+
if (freeRes.ok) {
|
|
47
|
+
const freeData = await freeRes.json();
|
|
48
|
+
const modelsList = freeData.slice(0, 15).map((m) => `\`${m.name}\``).join(', ');
|
|
49
|
+
freeModelsText = t('connect_response.free_models_success', { models: modelsList });
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
freeModelsText = t('connect_response.free_models_error');
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
catch (e) {
|
|
56
|
+
freeModelsText = t('connect_response.free_models_error');
|
|
57
|
+
}
|
|
58
|
+
return t('connect_response.onboarding', { freeText: freeModelsText });
|
|
59
|
+
}
|
|
@@ -1,34 +1,8 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* generate-config.ts - v6.0 Simplified
|
|
3
|
-
*
|
|
4
|
-
* Single endpoint: gen.pollinations.ai/text/models
|
|
5
|
-
* No more Free tier, no cache ETag, no prefixes
|
|
6
|
-
*/
|
|
7
|
-
export interface PollinationsModel {
|
|
8
|
-
name: string;
|
|
9
|
-
description?: string;
|
|
10
|
-
type?: string;
|
|
11
|
-
tools?: boolean;
|
|
12
|
-
reasoning?: boolean;
|
|
13
|
-
context?: number;
|
|
14
|
-
context_window?: number;
|
|
15
|
-
input_modalities?: string[];
|
|
16
|
-
output_modalities?: string[];
|
|
17
|
-
paid_only?: boolean;
|
|
18
|
-
vision?: boolean;
|
|
19
|
-
audio?: boolean;
|
|
20
|
-
pricing?: {
|
|
21
|
-
promptTextTokens?: number;
|
|
22
|
-
completionTextTokens?: number;
|
|
23
|
-
promptImageTokens?: number;
|
|
24
|
-
promptAudioTokens?: number;
|
|
25
|
-
completionAudioTokens?: number;
|
|
26
|
-
};
|
|
27
|
-
[key: string]: any;
|
|
28
|
-
}
|
|
29
1
|
interface OpenCodeModel {
|
|
30
2
|
id: string;
|
|
31
3
|
name: string;
|
|
4
|
+
object: string;
|
|
5
|
+
variants?: any;
|
|
32
6
|
options?: any;
|
|
33
7
|
limit?: {
|
|
34
8
|
context?: number;
|
|
@@ -38,7 +12,6 @@ interface OpenCodeModel {
|
|
|
38
12
|
input?: string[];
|
|
39
13
|
output?: string[];
|
|
40
14
|
};
|
|
41
|
-
tool_call?: boolean;
|
|
42
15
|
}
|
|
43
|
-
export declare function generatePollinationsConfig(forceApiKey?: string): Promise<OpenCodeModel[]>;
|
|
16
|
+
export declare function generatePollinationsConfig(forceApiKey?: string, forceStrict?: boolean): Promise<OpenCodeModel[]>;
|
|
44
17
|
export {};
|