@pixelbyte-software/pixcode 1.31.13 → 1.33.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.
Files changed (66) hide show
  1. package/dist/assets/index-Byb8Wnts.css +32 -0
  2. package/dist/assets/{index-oxZnRcf8.js → index-CZKV8Tbj.js} +163 -151
  3. package/dist/index.html +2 -2
  4. package/dist-server/server/database/db.js +542 -460
  5. package/dist-server/server/database/db.js.map +1 -1
  6. package/dist-server/server/database/json-store.js +184 -0
  7. package/dist-server/server/database/json-store.js.map +1 -0
  8. package/dist-server/server/index.js +16 -1
  9. package/dist-server/server/index.js.map +1 -1
  10. package/dist-server/server/modules/providers/list/opencode/opencode-auth.provider.js +113 -0
  11. package/dist-server/server/modules/providers/list/opencode/opencode-auth.provider.js.map +1 -0
  12. package/dist-server/server/modules/providers/list/opencode/opencode-mcp.provider.js +98 -0
  13. package/dist-server/server/modules/providers/list/opencode/opencode-mcp.provider.js.map +1 -0
  14. package/dist-server/server/modules/providers/list/opencode/opencode-sessions.provider.js +138 -0
  15. package/dist-server/server/modules/providers/list/opencode/opencode-sessions.provider.js.map +1 -0
  16. package/dist-server/server/modules/providers/list/opencode/opencode.provider.js +27 -0
  17. package/dist-server/server/modules/providers/list/opencode/opencode.provider.js.map +1 -0
  18. package/dist-server/server/modules/providers/provider.registry.js +2 -0
  19. package/dist-server/server/modules/providers/provider.registry.js.map +1 -1
  20. package/dist-server/server/modules/providers/provider.routes.js +4 -1
  21. package/dist-server/server/modules/providers/provider.routes.js.map +1 -1
  22. package/dist-server/server/modules/providers/shared/provider-configs.js +24 -0
  23. package/dist-server/server/modules/providers/shared/provider-configs.js.map +1 -1
  24. package/dist-server/server/routes/auth.js +5 -1
  25. package/dist-server/server/routes/auth.js.map +1 -1
  26. package/dist-server/server/routes/network.js +14 -21
  27. package/dist-server/server/routes/network.js.map +1 -1
  28. package/dist-server/server/services/external-access.js +18 -78
  29. package/dist-server/server/services/external-access.js.map +1 -1
  30. package/dist-server/server/services/install-jobs.js +2 -0
  31. package/dist-server/server/services/install-jobs.js.map +1 -1
  32. package/dist-server/server/services/provider-credentials.js +4 -0
  33. package/dist-server/server/services/provider-credentials.js.map +1 -1
  34. package/dist-server/server/services/telegram/bot.js +6 -6
  35. package/dist-server/server/services/telegram/bot.js.map +1 -1
  36. package/dist-server/server/services/telegram/telegram-http-client.js +130 -0
  37. package/dist-server/server/services/telegram/telegram-http-client.js.map +1 -0
  38. package/dist-server/server/services/vapid-keys.js +3 -3
  39. package/dist-server/server/services/vapid-keys.js.map +1 -1
  40. package/dist-server/shared/modelConstants.js +20 -0
  41. package/dist-server/shared/modelConstants.js.map +1 -1
  42. package/package.json +178 -178
  43. package/server/database/db.js +794 -696
  44. package/server/database/json-store.js +194 -0
  45. package/server/index.js +14 -1
  46. package/server/modules/providers/list/opencode/opencode-auth.provider.ts +130 -0
  47. package/server/modules/providers/list/opencode/opencode-mcp.provider.ts +126 -0
  48. package/server/modules/providers/list/opencode/opencode-sessions.provider.ts +155 -0
  49. package/server/modules/providers/list/opencode/opencode.provider.ts +29 -0
  50. package/server/modules/providers/provider.registry.ts +2 -0
  51. package/server/modules/providers/provider.routes.ts +4 -0
  52. package/server/modules/providers/shared/provider-configs.ts +24 -0
  53. package/server/routes/auth.js +5 -1
  54. package/server/routes/network.js +13 -21
  55. package/server/services/external-access.js +171 -240
  56. package/server/services/install-jobs.js +2 -0
  57. package/server/services/provider-credentials.js +8 -4
  58. package/server/services/telegram/bot.js +6 -7
  59. package/server/services/telegram/telegram-http-client.js +130 -0
  60. package/server/services/vapid-keys.js +36 -35
  61. package/server/shared/types.ts +1 -1
  62. package/shared/modelConstants.js +22 -0
  63. package/dist/assets/index-CLxSMbv1.css +0 -32
  64. package/dist-server/server/database/schema.js +0 -130
  65. package/dist-server/server/database/schema.js.map +0 -1
  66. package/server/database/schema.js +0 -138
@@ -0,0 +1,130 @@
1
+ import { EventEmitter } from 'node:events';
2
+
3
+ /**
4
+ * Minimal Telegram Bot API client.
5
+ *
6
+ * Replaces `node-telegram-bot-api` which pulled in the deprecated
7
+ * `request` / `har-validator` / `uuid@3` chain (~30 transitive packages,
8
+ * npm install warnings on every fresh box). The Bot API itself is just
9
+ * HTTP, and we only use two endpoints (getUpdates polling + sendMessage),
10
+ * so 100 lines of fetch is all that's needed. Exposes the same surface
11
+ * the bot.js consumer relied on: `getMe()`, `sendMessage()`, `on('message'|'polling_error')`,
12
+ * `stopPolling()`.
13
+ *
14
+ * No third-party deps — uses Node 22's built-in `fetch`.
15
+ */
16
+
17
+ const API_BASE = 'https://api.telegram.org/bot';
18
+
19
+ class TelegramApiError extends Error {
20
+ constructor(method, body, httpStatus) {
21
+ const description = body?.description || `HTTP ${httpStatus}`;
22
+ super(`Telegram ${method} failed: ${description}`);
23
+ this.name = 'TelegramApiError';
24
+ this.method = method;
25
+ this.httpStatus = httpStatus;
26
+ // Mirror the shape node-telegram-bot-api exposed so upstream error
27
+ // handling (401/409 checks in bot.js) keeps working unchanged.
28
+ this.response = { statusCode: httpStatus, body };
29
+ this.code = body?.error_code || httpStatus;
30
+ }
31
+ }
32
+
33
+ /**
34
+ * Call a Bot API method by name. Returns the `result` field on success,
35
+ * throws a TelegramApiError otherwise.
36
+ */
37
+ async function callApi(token, method, params, { signal } = {}) {
38
+ const url = `${API_BASE}${token}/${method}`;
39
+ const res = await fetch(url, {
40
+ method: 'POST',
41
+ headers: { 'Content-Type': 'application/json' },
42
+ body: JSON.stringify(params || {}),
43
+ signal,
44
+ });
45
+ let body;
46
+ try { body = await res.json(); } catch { body = null; }
47
+ if (!res.ok || !body?.ok) {
48
+ throw new TelegramApiError(method, body, res.status);
49
+ }
50
+ return body.result;
51
+ }
52
+
53
+ export class TelegramHttpBot extends EventEmitter {
54
+ constructor(token, { polling = true, pollTimeoutSec = 30 } = {}) {
55
+ super();
56
+ if (!token) throw new Error('TelegramHttpBot: token is required');
57
+ this._token = token;
58
+ this._pollTimeoutSec = pollTimeoutSec;
59
+ this._offset = 0;
60
+ this._polling = false;
61
+ this._abortController = null;
62
+ if (polling) this._startPolling();
63
+ }
64
+
65
+ // ---------- Public API (mirrors node-telegram-bot-api surface) ----------
66
+
67
+ async getMe() {
68
+ return callApi(this._token, 'getMe', {});
69
+ }
70
+
71
+ async sendMessage(chatId, text, extra = {}) {
72
+ return callApi(this._token, 'sendMessage', {
73
+ chat_id: chatId,
74
+ text,
75
+ ...extra,
76
+ });
77
+ }
78
+
79
+ async stopPolling(_opts = {}) {
80
+ this._polling = false;
81
+ try { this._abortController?.abort(); } catch { /* ignore */ }
82
+ this._abortController = null;
83
+ }
84
+
85
+ // ---------- Polling loop ----------
86
+
87
+ async _startPolling() {
88
+ this._polling = true;
89
+ // Kick off a non-awaited loop. Each iteration long-polls getUpdates for
90
+ // up to pollTimeoutSec, then loops immediately. We deliberately serialize
91
+ // (no concurrent long-polls) because Telegram rejects that with 409.
92
+ (async () => {
93
+ while (this._polling) {
94
+ this._abortController = new AbortController();
95
+ try {
96
+ const updates = await callApi(
97
+ this._token,
98
+ 'getUpdates',
99
+ {
100
+ offset: this._offset,
101
+ timeout: this._pollTimeoutSec,
102
+ allowed_updates: ['message'],
103
+ },
104
+ { signal: this._abortController.signal },
105
+ );
106
+ for (const update of updates) {
107
+ if (typeof update.update_id === 'number') {
108
+ this._offset = Math.max(this._offset, update.update_id + 1);
109
+ }
110
+ if (update.message) {
111
+ try { this.emit('message', update.message); } catch (err) {
112
+ // Don't let a listener exception break the poll loop.
113
+ this.emit('polling_error', err);
114
+ }
115
+ }
116
+ }
117
+ } catch (err) {
118
+ // AbortError is the expected path when stopPolling() is called.
119
+ if (err?.name === 'AbortError' || !this._polling) break;
120
+ this.emit('polling_error', err);
121
+ // Back off before retrying — rapid retries on 401/409 would
122
+ // otherwise spin at 100% CPU. Upstream consumer's polling_error
123
+ // handler may also call stopBot() on 401/409 which flips _polling
124
+ // off and breaks the loop on the next tick.
125
+ await new Promise((r) => setTimeout(r, 2000));
126
+ }
127
+ }
128
+ })();
129
+ }
130
+ }
@@ -1,35 +1,36 @@
1
- import webPush from 'web-push';
2
- import { db } from '../database/db.js';
3
-
4
- let cachedKeys = null;
5
-
6
- function ensureVapidKeys() {
7
- if (cachedKeys) return cachedKeys;
8
-
9
- const row = db.prepare('SELECT public_key, private_key FROM vapid_keys ORDER BY id DESC LIMIT 1').get();
10
- if (row) {
11
- cachedKeys = { publicKey: row.public_key, privateKey: row.private_key };
12
- return cachedKeys;
13
- }
14
-
15
- const keys = webPush.generateVAPIDKeys();
16
- db.prepare('INSERT INTO vapid_keys (public_key, private_key) VALUES (?, ?)').run(keys.publicKey, keys.privateKey);
17
- cachedKeys = keys;
18
- return cachedKeys;
19
- }
20
-
21
- function getPublicKey() {
22
- return ensureVapidKeys().publicKey;
23
- }
24
-
25
- function configureWebPush() {
26
- const keys = ensureVapidKeys();
27
- webPush.setVapidDetails(
28
- 'mailto:noreply@pixcode.local',
29
- keys.publicKey,
30
- keys.privateKey
31
- );
32
- console.log('Web Push notifications configured');
33
- }
34
-
35
- export { ensureVapidKeys, getPublicKey, configureWebPush };
1
+ import webPush from 'web-push';
2
+
3
+ import { vapidKeysDb } from '../database/db.js';
4
+
5
+ let cachedKeys = null;
6
+
7
+ function ensureVapidKeys() {
8
+ if (cachedKeys) return cachedKeys;
9
+
10
+ const row = vapidKeysDb.getLatest();
11
+ if (row) {
12
+ cachedKeys = { publicKey: row.public_key, privateKey: row.private_key };
13
+ return cachedKeys;
14
+ }
15
+
16
+ const keys = webPush.generateVAPIDKeys();
17
+ vapidKeysDb.insert(keys.publicKey, keys.privateKey);
18
+ cachedKeys = keys;
19
+ return cachedKeys;
20
+ }
21
+
22
+ function getPublicKey() {
23
+ return ensureVapidKeys().publicKey;
24
+ }
25
+
26
+ function configureWebPush() {
27
+ const keys = ensureVapidKeys();
28
+ webPush.setVapidDetails(
29
+ 'mailto:noreply@pixcode.local',
30
+ keys.publicKey,
31
+ keys.privateKey
32
+ );
33
+ console.log('Web Push notifications configured');
34
+ }
35
+
36
+ export { ensureVapidKeys, getPublicKey, configureWebPush };
@@ -9,7 +9,7 @@ export type AnyRecord = Record<string, any>;
9
9
 
10
10
  // ---------------------------------------------------------------------------------------------
11
11
 
12
- export type LLMProvider = 'claude' | 'codex' | 'gemini' | 'cursor' | 'qwen';
12
+ export type LLMProvider = 'claude' | 'codex' | 'gemini' | 'cursor' | 'qwen' | 'opencode';
13
13
 
14
14
  // ---------------------------------------------------------------------------------------------
15
15
 
@@ -94,6 +94,28 @@ export const QWEN_MODELS = {
94
94
  DEFAULT: "qwen3-coder-plus",
95
95
  };
96
96
 
97
+ /**
98
+ * OpenCode Models
99
+ *
100
+ * OpenCode is multi-provider, so the picker is really "which upstream
101
+ * model does opencode talk to?". The defaults here point at OpenCode Zen
102
+ * (their curated routing tier) plus a few direct picks the docs call
103
+ * out as well-supported. Advanced users override via opencode.json's
104
+ * `provider` / `model` block, which bypasses this list.
105
+ */
106
+ export const OPENCODE_MODELS = {
107
+ OPTIONS: [
108
+ { value: "opencode/zen-best", label: "OpenCode Zen (Best)" },
109
+ { value: "opencode/zen-fast", label: "OpenCode Zen (Fast)" },
110
+ { value: "anthropic/claude-sonnet-4-6", label: "Claude Sonnet 4.6 (Anthropic)" },
111
+ { value: "anthropic/claude-opus-4-6", label: "Claude Opus 4.6 (Anthropic)" },
112
+ { value: "openai/gpt-5.4", label: "GPT-5.4 (OpenAI)" },
113
+ { value: "google/gemini-3-pro-preview", label: "Gemini 3 Pro (Google)" },
114
+ ],
115
+
116
+ DEFAULT: "opencode/zen-best",
117
+ };
118
+
97
119
  /**
98
120
  * Gemini Models
99
121
  */