openfox 1.3.3 → 1.4.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 (29) hide show
  1. package/dist/auth-JF2HDJ6P.js +53 -0
  2. package/dist/{auto-compaction-RRFGQDQN.js → auto-compaction-C7URGBG3.js} +4 -4
  3. package/dist/{chat-handler-34PPF43W.js → chat-handler-BUCN7QJG.js} +6 -6
  4. package/dist/{chunk-O7O3XMWO.js → chunk-7POE2HLF.js} +2 -2
  5. package/dist/{chunk-4JBBQQOD.js → chunk-G5U2OBHQ.js} +8 -8
  6. package/dist/{chunk-IBA3NQAD.js → chunk-JVAYCY76.js} +1 -1
  7. package/dist/{chunk-NGSSEMII.js → chunk-L46YMTF2.js} +4 -4
  8. package/dist/{chunk-ON2IR3E4.js → chunk-M6HB2O3B.js} +127 -25
  9. package/dist/{chunk-D3C4Z53N.js → chunk-NJ24TM3O.js} +69 -44
  10. package/dist/{chunk-YSPC6TQJ.js → chunk-TXTPA76S.js} +2 -2
  11. package/dist/{chunk-BNK5N227.js → chunk-UZ6LHPX7.js} +2 -2
  12. package/dist/cli/dev.js +1 -1
  13. package/dist/cli/index.js +1 -1
  14. package/dist/config-ONC2MTDE.js +3 -3
  15. package/dist/{orchestrator-K6PLFOVY.js → orchestrator-L3MBTPG2.js} +5 -5
  16. package/dist/package.json +1 -1
  17. package/dist/{processor-V57VGPXZ.js → processor-77Z5BZPK.js} +2 -2
  18. package/dist/{provider-FAO4R2GH.js → provider-K4HAXILY.js} +7 -7
  19. package/dist/{serve-SK5FZJXJ.js → serve-6QG3HSOL.js} +17 -17
  20. package/dist/server/index.js +8 -8
  21. package/dist/{tools-KTY6SVMF.js → tools-G6PT5NJO.js} +4 -4
  22. package/dist/{vision-fallback-MGSC5SWE.js → vision-fallback-P7WM3UGQ.js} +2 -2
  23. package/dist/web/assets/{index-BW3T98H-.css → index-BBtTirUQ.css} +1 -1
  24. package/dist/web/assets/index-D8PVAl5p.js +142 -0
  25. package/dist/web/index.html +2 -2
  26. package/dist/web/sw.js +1 -1
  27. package/package.json +1 -1
  28. package/dist/init-TLQQLRGQ.js +0 -294
  29. package/dist/web/assets/index-MxvFVrSK.js +0 -142
@@ -5,8 +5,8 @@
5
5
  <link rel="icon" type="image/png" href="/assets/openfox.png" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <title>OpenFox</title>
8
- <script type="module" crossorigin src="/assets/index-MxvFVrSK.js"></script>
9
- <link rel="stylesheet" crossorigin href="/assets/index-BW3T98H-.css">
8
+ <script type="module" crossorigin src="/assets/index-D8PVAl5p.js"></script>
9
+ <link rel="stylesheet" crossorigin href="/assets/index-BBtTirUQ.css">
10
10
  <link rel="manifest" href="/manifest.webmanifest"><script id="vite-plugin-pwa:register-sw" src="/registerSW.js"></script></head>
11
11
  <body class="bg-bg-primary text-text-primary font-mono">
12
12
  <div id="root"></div>
package/dist/web/sw.js CHANGED
@@ -1 +1 @@
1
- if(!self.define){let e,s={};const i=(i,n)=>(i=new URL(i+".js",n).href,s[i]||new Promise(s=>{if("document"in self){const e=document.createElement("script");e.src=i,e.onload=s,document.head.appendChild(e)}else e=i,importScripts(i),s()}).then(()=>{let e=s[i];if(!e)throw new Error(`Module ${i} didn’t register its module`);return e}));self.define=(n,r)=>{const t=e||("document"in self?document.currentScript.src:"")||location.href;if(s[t])return;let o={};const l=e=>i(e,t),d={module:{uri:t},exports:o,require:l};s[t]=Promise.all(n.map(e=>d[e]||l(e))).then(e=>(r(...e),o))}}define(["./workbox-8c29f6e4"],function(e){"use strict";self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"registerSW.js",revision:"1872c500de691dce40960bb85481de07"},{url:"index.html",revision:"ca27daddf5a31060ab522683fd17455b"},{url:"assets/index-MxvFVrSK.js",revision:null},{url:"assets/index-BW3T98H-.css",revision:null},{url:"assets/html2canvas.esm-QH1iLAAe.js",revision:null},{url:"assets/openfox-192.png",revision:"79feeb86d692c274854e37959a7dae67"},{url:"assets/openfox-512.png",revision:"fee24b214220594b4f595a467e73036e"},{url:"manifest.webmanifest",revision:"c25f372c782e623ab1e768a8dfe350ca"}],{}),e.cleanupOutdatedCaches(),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("index.html")))});
1
+ if(!self.define){let e,s={};const i=(i,n)=>(i=new URL(i+".js",n).href,s[i]||new Promise(s=>{if("document"in self){const e=document.createElement("script");e.src=i,e.onload=s,document.head.appendChild(e)}else e=i,importScripts(i),s()}).then(()=>{let e=s[i];if(!e)throw new Error(`Module ${i} didn’t register its module`);return e}));self.define=(n,r)=>{const t=e||("document"in self?document.currentScript.src:"")||location.href;if(s[t])return;let o={};const l=e=>i(e,t),u={module:{uri:t},exports:o,require:l};s[t]=Promise.all(n.map(e=>u[e]||l(e))).then(e=>(r(...e),o))}}define(["./workbox-8c29f6e4"],function(e){"use strict";self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"registerSW.js",revision:"1872c500de691dce40960bb85481de07"},{url:"index.html",revision:"bf5942a1748f55c55fa40b48741093e3"},{url:"assets/index-D8PVAl5p.js",revision:null},{url:"assets/index-BBtTirUQ.css",revision:null},{url:"assets/html2canvas.esm-QH1iLAAe.js",revision:null},{url:"assets/openfox-192.png",revision:"79feeb86d692c274854e37959a7dae67"},{url:"assets/openfox-512.png",revision:"fee24b214220594b4f595a467e73036e"},{url:"manifest.webmanifest",revision:"c25f372c782e623ab1e768a8dfe350ca"}],{}),e.cleanupOutdatedCaches(),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("index.html")))});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openfox",
3
- "version": "1.3.3",
3
+ "version": "1.4.0",
4
4
  "description": "Local-LLM-first agentic coding assistant",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,294 +0,0 @@
1
- import {
2
- addProvider,
3
- saveGlobalConfig
4
- } from "./chunk-BNK5N227.js";
5
- import {
6
- detectBackend,
7
- detectModel
8
- } from "./chunk-NGSSEMII.js";
9
- import "./chunk-XFXOSPYH.js";
10
- import {
11
- getAuthConfigPath,
12
- getAuthKeyPath
13
- } from "./chunk-R4HADRYO.js";
14
- import "./chunk-IBA3NQAD.js";
15
- import "./chunk-PNBH3RAX.js";
16
-
17
- // src/cli/init.ts
18
- import { select, text, password, spinner, outro, confirm } from "@clack/prompts";
19
- import { writeFile as writeFile2 } from "fs/promises";
20
-
21
- // src/cli/auth.ts
22
- import { readFile, writeFile, mkdir, access } from "fs/promises";
23
- import { dirname } from "path";
24
- import { createHash, publicEncrypt } from "crypto";
25
- async function saveAuthConfig(mode, auth) {
26
- const authPath = getAuthConfigPath(mode);
27
- await mkdir(dirname(authPath), { recursive: true });
28
- await writeFile(authPath, JSON.stringify(auth, null, 2));
29
- }
30
- async function loadAuthConfig(mode) {
31
- const authPath = getAuthConfigPath(mode);
32
- try {
33
- const data = await readFile(authPath, "utf-8");
34
- return JSON.parse(data);
35
- } catch {
36
- return null;
37
- }
38
- }
39
- function encryptPassword(password2, publicKey) {
40
- const encrypted = publicEncrypt(
41
- { key: publicKey, padding: 1 },
42
- Buffer.from(password2)
43
- );
44
- return encrypted.toString("base64");
45
- }
46
-
47
- // src/cli/init.ts
48
- import { generateKeyPairSync } from "crypto";
49
- var LLM_OPTIONS = [
50
- { value: "http://localhost:8000", label: "http://localhost:8000" },
51
- { value: "http://localhost:11434", label: "http://localhost:11434" },
52
- { value: "http://localhost:8080", label: "http://localhost:8080" },
53
- { value: "other", label: "Other..." }
54
- ];
55
- function createBaseConfig() {
56
- return {
57
- providers: [],
58
- defaultModelSelection: void 0,
59
- activeProviderId: void 0,
60
- activeWorkflowId: void 0,
61
- server: { port: 10369, host: "127.0.0.1", openBrowser: true },
62
- logging: { level: "error" },
63
- database: { path: "" },
64
- workspace: { workdir: process.cwd() },
65
- visionFallback: { enabled: false, url: "http://localhost:11434", model: "qwen3-vl:2b", timeout: 120 }
66
- };
67
- }
68
- async function promptNetworkAccessibility(mode) {
69
- const networkChoice = await select({
70
- message: "How should OpenFox be accessible?",
71
- options: [
72
- { value: "localhost", label: "Secure (localhost only)" },
73
- { value: "network", label: "Accessible from local network (phone, tablet, etc.)" }
74
- ]
75
- });
76
- if (networkChoice === /* @__PURE__ */ Symbol.for("clack:cancel")) {
77
- return { host: "127.0.0.1", strategy: "local" };
78
- }
79
- const isNetwork = networkChoice === "network";
80
- const host = isNetwork ? "0.0.0.0" : "127.0.0.1";
81
- if (isNetwork) {
82
- const existingAuth = await loadAuthConfig(mode);
83
- const existingPassword = !!existingAuth?.encryptedPassword;
84
- if (existingPassword) {
85
- const keepChoice = await confirm({
86
- message: "Keep existing password?",
87
- initialValue: true
88
- });
89
- if (keepChoice === true) {
90
- return { host, strategy: "network" };
91
- }
92
- }
93
- const passwordResult = await password({
94
- message: "Set a password (optional, press Enter to skip)"
95
- });
96
- const pwd = typeof passwordResult === "string" ? passwordResult : "";
97
- if (pwd.length > 0) {
98
- const { publicKey, privateKey } = generateKeyPairSync("rsa", {
99
- modulusLength: 2048,
100
- privateKeyEncoding: { type: "pkcs8", format: "pem" },
101
- publicKeyEncoding: { type: "spki", format: "pem" }
102
- });
103
- const keyPath = getAuthKeyPath(mode);
104
- await writeFile2(keyPath, privateKey, { mode: 384 });
105
- const encryptedPassword = encryptPassword(pwd, publicKey);
106
- await saveAuthConfig(mode, {
107
- strategy: "network",
108
- encryptedPassword
109
- });
110
- } else {
111
- await saveAuthConfig(mode, {
112
- strategy: "network",
113
- encryptedPassword: null
114
- });
115
- }
116
- } else {
117
- await saveAuthConfig(mode, {
118
- strategy: "local",
119
- encryptedPassword: null
120
- });
121
- }
122
- return { host, strategy: isNetwork ? "network" : "local" };
123
- }
124
- async function runInitWithSelect(mode, existingConfig) {
125
- let preserveProviders = false;
126
- let config;
127
- if (existingConfig && existingConfig.providers.length > 0) {
128
- console.log("\nCurrent configuration detected:");
129
- console.log(` Providers: ${existingConfig.providers.length}`);
130
- existingConfig.providers.forEach((p, i) => {
131
- console.log(` ${i + 1}. ${p.name} (${p.url}) - ${p.model}`);
132
- });
133
- console.log(` Server: ${existingConfig.server.host}`);
134
- const keepChoice = await confirm({
135
- message: "Keep existing providers?",
136
- initialValue: true
137
- });
138
- if (keepChoice === true) {
139
- preserveProviders = true;
140
- config = {
141
- ...existingConfig,
142
- server: { ...existingConfig.server }
143
- // Copy server settings
144
- };
145
- console.log("\nPreserving existing providers...\n");
146
- } else {
147
- console.log("\nStarting fresh configuration...\n");
148
- config = createBaseConfig();
149
- }
150
- } else {
151
- config = createBaseConfig();
152
- }
153
- if (!preserveProviders) {
154
- const s = spinner();
155
- s.start("Searching for local LLM...");
156
- const detected = await Promise.all(
157
- LLM_OPTIONS.filter((o) => o.value !== "other").map(async ({ value: url }) => {
158
- try {
159
- const [backend, model] = await Promise.all([
160
- detectBackend(url, void 0, true),
161
- detectModel(url, 1, true)
162
- ]);
163
- if (backend !== "unknown" && model) {
164
- return { url, backend, model };
165
- }
166
- } catch {
167
- }
168
- return null;
169
- })
170
- );
171
- const found = detected.find((r) => r !== null);
172
- if (found) {
173
- s.stop(`\u2713 Found ${found.backend} (${found.model})`);
174
- config = addProvider(config, {
175
- name: "Default",
176
- url: found.url,
177
- backend: found.backend,
178
- models: [],
179
- isActive: true
180
- });
181
- } else {
182
- s.stop("\u2717 No LLM server detected");
183
- const selection = await select({
184
- message: "Select your LLM server:",
185
- options: LLM_OPTIONS
186
- });
187
- let url;
188
- if (String(selection) === "other") {
189
- const textValue = await text({
190
- message: "LLM Server URL (don't include /v1)",
191
- placeholder: "http://localhost:8000",
192
- initialValue: "http://localhost:8000",
193
- validate: (value) => {
194
- if (!value || value.length === 0) return "URL is required";
195
- if (!value.startsWith("http")) return "Must start with http://";
196
- }
197
- });
198
- url = String(textValue);
199
- } else {
200
- url = String(selection);
201
- }
202
- const s2 = spinner();
203
- s2.start(`Testing connection to ${url}...`);
204
- try {
205
- const backend = await detectBackend(url);
206
- const model = await detectModel(url);
207
- s2.stop(`Connected to ${backend}${model ? " (" + model + ")" : ""}`);
208
- config = addProvider(config, {
209
- name: "Default",
210
- url,
211
- backend,
212
- models: [],
213
- isActive: true
214
- });
215
- const { setDefaultModelSelection } = await import("./config-ONC2MTDE.js");
216
- config = setDefaultModelSelection(config, config.providers[config.providers.length - 1].id, model ?? "auto");
217
- } catch {
218
- s2.stop("Server isn't available");
219
- const choice = await select({
220
- message: "Continue with this URL or retry?",
221
- options: [
222
- { value: "continue", label: "Continue" },
223
- { value: "retry", label: "Retry" },
224
- { value: "change", label: "Select different server" }
225
- ]
226
- });
227
- if (choice === "retry") {
228
- return runInitWithSelect(mode, existingConfig);
229
- } else if (choice === "change") {
230
- return runInitWithSelect(mode, existingConfig);
231
- }
232
- config = addProvider(config, {
233
- name: "Default",
234
- url,
235
- backend: "auto",
236
- models: [],
237
- isActive: true
238
- });
239
- const { setDefaultModelSelection } = await import("./config-ONC2MTDE.js");
240
- config = setDefaultModelSelection(config, config.providers[config.providers.length - 1].id, "auto");
241
- }
242
- }
243
- }
244
- const { host } = await promptNetworkAccessibility(mode);
245
- config.server.host = host;
246
- const workdirChoice = await text({
247
- message: "Workspace directory for new projects",
248
- placeholder: "Directory where new projects will be created",
249
- initialValue: config.workspace?.workdir || process.cwd(),
250
- validate: (value) => {
251
- if (!value || value.length === 0) return "Workspace directory is required";
252
- }
253
- });
254
- config.workspace = { workdir: String(workdirChoice).replace(/\/$/, "") };
255
- const visionChoice = await confirm({
256
- message: "Configure vision fallback for non-vision models?",
257
- initialValue: false
258
- });
259
- if (visionChoice === true) {
260
- const visionUrl = await text({
261
- message: "Vision fallback server URL",
262
- placeholder: "http://localhost:11434",
263
- initialValue: config.visionFallback?.url || "http://localhost:11434",
264
- validate: (value) => {
265
- if (!value || value.length === 0) return "URL is required";
266
- if (!value.startsWith("http")) return "Must start with http://";
267
- }
268
- });
269
- const visionModel = await text({
270
- message: "Vision fallback model name",
271
- placeholder: "qwen3-vl:2b",
272
- initialValue: config.visionFallback?.model || "qwen3-vl:2b",
273
- validate: (value) => {
274
- if (!value || value.length === 0) return "Model name is required";
275
- }
276
- });
277
- config.visionFallback = {
278
- enabled: true,
279
- url: String(visionUrl),
280
- model: String(visionModel),
281
- timeout: 120
282
- };
283
- }
284
- if (config.providers.length > 0 && !config.defaultModelSelection) {
285
- const { setDefaultModelSelection } = await import("./config-ONC2MTDE.js");
286
- config = setDefaultModelSelection(config, config.providers[0].id, "auto");
287
- }
288
- await saveGlobalConfig(mode, config);
289
- outro("Configuration saved!");
290
- }
291
- export {
292
- runInitWithSelect
293
- };
294
- //# sourceMappingURL=init-TLQQLRGQ.js.map