openzoo 0.18.4 → 0.18.5
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/lib/cursorcfg.js +48 -0
- package/lib/setup.js +10 -16
- package/package.json +1 -1
package/lib/cursorcfg.js
CHANGED
|
@@ -149,3 +149,51 @@ export function writeEditorProviderConfig(which, { baseUrl, models }) {
|
|
|
149
149
|
const modelsStick = models.every((m) => verified.models.includes(m));
|
|
150
150
|
return { db, before, baseUrl, added, verified, modelsStick };
|
|
151
151
|
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* PIN the settings with a SQLite trigger so the editor cannot revert them.
|
|
155
|
+
*
|
|
156
|
+
* Cursor treats the model list and selection as SERVER-authoritative: it syncs
|
|
157
|
+
* them from the account on every launch and overwrites local state. Measured
|
|
158
|
+
* three times — written and verified while closed, then availableAPIKeyModels
|
|
159
|
+
* [] and composer.defaultModel "default" again after relaunch.
|
|
160
|
+
*
|
|
161
|
+
* Making the whole state.vscdb read-only would break the editor (it stores
|
|
162
|
+
* window layout, history, everything there). A trigger is surgical: Cursor
|
|
163
|
+
* keeps full write access, and only OUR fields are re-applied, on any write
|
|
164
|
+
* that clobbers them. Removable with unpinEditorProviderConfig.
|
|
165
|
+
*/
|
|
166
|
+
export function pinEditorProviderConfig(which, { baseUrl, models }) {
|
|
167
|
+
const db = storagePath(which);
|
|
168
|
+
if (!fs.existsSync(db)) return null;
|
|
169
|
+
const esc = (v) => String(v).replace(/'/g, "''");
|
|
170
|
+
const modelJson = esc(JSON.stringify(models.map((m) => ({ name: m, defaultOn: true, supportsAgent: true }))));
|
|
171
|
+
const primary = esc(models[0]);
|
|
172
|
+
const base = esc(baseUrl);
|
|
173
|
+
const sql = `
|
|
174
|
+
DROP TRIGGER IF EXISTS openzoo_pin;
|
|
175
|
+
CREATE TRIGGER openzoo_pin AFTER UPDATE ON ItemTable
|
|
176
|
+
WHEN NEW.key = '${KEY}'
|
|
177
|
+
AND (json_extract(NEW.value,'$.openAIBaseUrl') IS NOT '${base}'
|
|
178
|
+
OR json_extract(NEW.value,'$.featureModelConfigs.composer.defaultModel') IS NOT '${primary}')
|
|
179
|
+
BEGIN
|
|
180
|
+
UPDATE ItemTable SET value = json_set(
|
|
181
|
+
NEW.value,
|
|
182
|
+
'$.openAIBaseUrl', '${base}',
|
|
183
|
+
'$.useOpenAIKey', json('true'),
|
|
184
|
+
'$.availableAPIKeyModels', json('${modelJson}'),
|
|
185
|
+
'$.featureModelConfigs.composer.defaultModel', '${primary}',
|
|
186
|
+
'$.featureModelConfigs.cmdK.defaultModel', '${primary}'
|
|
187
|
+
) WHERE key = NEW.key;
|
|
188
|
+
END;`;
|
|
189
|
+
try { sqlite(db, sql); } catch (e) { return { error: e.message }; }
|
|
190
|
+
return { pinned: true, db };
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/** Remove the pin — the editor goes back to managing its own settings. */
|
|
194
|
+
export function unpinEditorProviderConfig(which) {
|
|
195
|
+
const db = storagePath(which);
|
|
196
|
+
if (!fs.existsSync(db)) return null;
|
|
197
|
+
try { sqlite(db, 'DROP TRIGGER IF EXISTS openzoo_pin;'); return { unpinned: true }; }
|
|
198
|
+
catch (e) { return { error: e.message }; }
|
|
199
|
+
}
|
package/lib/setup.js
CHANGED
|
@@ -20,7 +20,7 @@ import os from 'node:os';
|
|
|
20
20
|
import path from 'node:path';
|
|
21
21
|
import { spawn } from 'node:child_process';
|
|
22
22
|
import { config } from './config.js';
|
|
23
|
-
import { writeEditorProviderConfig, editorRunning, quitEditor } from './cursorcfg.js';
|
|
23
|
+
import { writeEditorProviderConfig, editorRunning, quitEditor, pinEditorProviderConfig } from './cursorcfg.js';
|
|
24
24
|
|
|
25
25
|
const DEFAULT_MODELS = ['anthropic/claude-opus-5', 'deepseek/deepseek-v4-pro-0813'];
|
|
26
26
|
|
|
@@ -183,21 +183,15 @@ export async function setupEditor(which, target) {
|
|
|
183
183
|
} else if (wrote) {
|
|
184
184
|
console.log(`settings: openAIBaseUrl -> ${wrote.verified?.openAIBaseUrl || base}`);
|
|
185
185
|
console.log(' useOpenAIKey -> true');
|
|
186
|
-
//
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
console.log(
|
|
194
|
-
|
|
195
|
-
console.log(' Settings -> Models -> + Add model');
|
|
196
|
-
console.log(` ${models[0]}`);
|
|
197
|
-
console.log(' then select it in the chat model dropdown.');
|
|
198
|
-
console.log(' Built-in models and "Auto" route to Cursor\'s backend, never here.');
|
|
199
|
-
console.log(' Verify it worked: send one message and watch this terminal for a');
|
|
200
|
-
console.log(' "paid $0.0… · rail solana · tx …" line. No line = it did not route.');
|
|
186
|
+
// PIN so the editor's account-sync cannot revert it on launch.
|
|
187
|
+
const pin = pinEditorProviderConfig(target0, { baseUrl: base, models });
|
|
188
|
+
console.log(` models -> ${models.join(', ')}`);
|
|
189
|
+
console.log(` selected -> ${models[0]}`);
|
|
190
|
+
console.log(pin?.pinned
|
|
191
|
+
? ' pinned -> yes (the editor re-syncs these from its account; a DB trigger re-applies them)'
|
|
192
|
+
: ` pinned -> NO (${pin?.error || 'unavailable'}) — the editor may revert these on launch`);
|
|
193
|
+
console.log(' verify: send one message, watch for "paid $0.0… · rail solana · tx …" here.');
|
|
194
|
+
}
|
|
201
195
|
|
|
202
196
|
// 3. LAUNCH with that env. Editor resolved platform-agnostically; Cursor
|
|
203
197
|
// wins when both are installed.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openzoo",
|
|
3
|
-
"version": "0.18.
|
|
3
|
+
"version": "0.18.5",
|
|
4
4
|
"description": "Local x402-paying proxy + MCP server for openzoo.fun — point any OpenAI-compatible harness (Cursor, Claude Code, aider, SDKs) at localhost and it pays per call from a local burner wallet. Solana and Base rails live; Robinhood experimental.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|