openfox 2.0.124 → 2.0.126
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/CHANGELOG.md +24 -0
- package/README.md +1 -0
- package/dist/CHANGELOG.md +24 -0
- package/dist/{backend-67OLCS5O.js → backend-4YPEC3J2.js} +2 -2
- package/dist/{chat-handler-N43TBYLV.js → chat-handler-OJ4XBQY4.js} +13 -13
- package/dist/{chunk-QJNBQCAF.js → chunk-2UPFWNC4.js} +4 -4
- package/dist/{chunk-57UCBFBD.js → chunk-6VW4BQMP.js} +9 -9
- package/dist/{chunk-5CCM655F.js → chunk-76A3E4LK.js} +35 -19
- package/dist/{chunk-KGFERMCV.js → chunk-77PJWQR7.js} +6 -6
- package/dist/chunk-ABCCTPBC.js +7 -0
- package/dist/{chunk-UGEFD67O.js → chunk-CTHRGR4O.js} +2 -2
- package/dist/{chunk-SYTEO5LA.js → chunk-FNXTJLCZ.js} +197 -8
- package/dist/{chunk-RXLAFEZB.js → chunk-H2RZDEVL.js} +4 -4
- package/dist/{chunk-W4SM4FFZ.js → chunk-HOSFRPPI.js} +14 -10
- package/dist/{chunk-MIPQOHWS.js → chunk-KAZWU73N.js} +26 -2
- package/dist/{chunk-62GUO2EG.js → chunk-LJX7KXRU.js} +3 -3
- package/dist/{chunk-AZHWLLPP.js → chunk-PBFGJFGC.js} +28 -10
- package/dist/{chunk-A6EZBX62.js → chunk-T3JVYO3Z.js} +16 -6
- package/dist/{chunk-FAL4WO4V.js → chunk-TP2PGZSE.js} +3 -3
- package/dist/{chunk-JEZN37KV.js → chunk-UAAFZEIS.js} +2 -2
- package/dist/{chunk-3NMLSANH.js → chunk-Y3BSBKHY.js} +31 -17
- package/dist/chunk-ZFNBATE3.js +196 -0
- package/dist/{chunk-VUBFPRKT.js → chunk-ZS55MMG6.js} +58 -51
- package/dist/cli/dev.js +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/{client-XHJHOFMU.js → client-YHYIWZY7.js} +5 -5
- package/dist/{client-pure-QSY7TJGK.js → client-pure-CJKM3ACP.js} +2 -2
- package/dist/{compactor-VTATJTPN.js → compactor-7KPBTFZF.js} +5 -5
- package/dist/{dynamic-context-KTQCAPTK.js → dynamic-context-PYAUG2LP.js} +2 -2
- package/dist/{http-client-N4ASJEKJ.js → http-client-ROVNSHF6.js} +2 -2
- package/dist/{launch-Z5D5YFRJ.js → launch-3F2GCRRF.js} +13 -13
- package/dist/{orchestrator-BQBBO4US.js → orchestrator-BRHIA2KE.js} +12 -12
- package/dist/package.json +1 -1
- package/dist/plugins-registry.json +6 -0
- package/dist/{processor-WTRVYXAO.js → processor-2IFXIJXG.js} +12 -12
- package/dist/provider/index.d.ts +2 -2
- package/dist/{provider-LICG53GG.js → provider-6LUA73HF.js} +6 -6
- package/dist/{provider-manager-3QC2MSSR.js → provider-manager-OQTEXZ7X.js} +6 -6
- package/dist/{serve-75G5Z7UQ.js → serve-WJKFUMLI.js} +18 -18
- package/dist/server/index.d.ts +6 -1
- package/dist/server/index.js +17 -17
- package/dist/{server-N3VATHIA.js → server-6LDC4HU6.js} +16 -16
- package/dist/{service-OURGS2SI.js → service-BRKMLM4C.js} +7 -7
- package/dist/{tasks-4SOLTX6A.js → tasks-DEUZ6BNS.js} +7 -7
- package/dist/{tools-G44LBKD4.js → tools-AOLICK5U.js} +10 -10
- package/dist/{types-Cr4EgGwK.d.ts → types-BWuVnaBw.d.ts} +3 -1
- package/dist/{update-R2TEHD7V.js → update-VH75MTCP.js} +2 -2
- package/dist/web/assets/index-DQ3Wg2OF.js +324 -0
- package/dist/web/index.html +1 -1
- package/dist/web/sw.js +1 -1
- package/dist/{workspace-J3JEGF6U.js → workspace-6CUE26YA.js} +2 -2
- package/package.json +1 -1
- package/plugins-registry.json +6 -0
- package/dist/chunk-SBADOWVC.js +0 -7
- package/dist/chunk-VPRB5FNR.js +0 -167
- package/dist/web/assets/index-GZTGHRRr.js +0 -324
|
@@ -12,15 +12,28 @@ import {
|
|
|
12
12
|
// src/server/git/workspace.ts
|
|
13
13
|
import { spawn, execSync } from "child_process";
|
|
14
14
|
import { mkdir as mkdir2, rm as rm2 } from "fs/promises";
|
|
15
|
-
import { resolve as resolve2, join as
|
|
15
|
+
import { resolve as resolve2, join as join3, isAbsolute } from "path";
|
|
16
16
|
import { homedir, platform } from "os";
|
|
17
17
|
|
|
18
|
+
// src/server/utils/fs.ts
|
|
19
|
+
import { stat } from "fs/promises";
|
|
20
|
+
import { join } from "path";
|
|
21
|
+
async function isDirectoryEntry(parent, entry) {
|
|
22
|
+
if (entry.isDirectory()) return true;
|
|
23
|
+
if (!entry.isSymbolicLink()) return false;
|
|
24
|
+
try {
|
|
25
|
+
return (await stat(join(parent, entry.name))).isDirectory();
|
|
26
|
+
} catch {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
18
31
|
// src/server/git/workspace-config.ts
|
|
19
32
|
import { readFile, writeFile, mkdir, rm } from "fs/promises";
|
|
20
|
-
import { resolve, join } from "path";
|
|
33
|
+
import { resolve, join as join2 } from "path";
|
|
21
34
|
var CONFIG_FILENAME = ".openfox/workspace.json";
|
|
22
35
|
function getConfigPath(workdir) {
|
|
23
|
-
return
|
|
36
|
+
return join2(resolve(workdir), CONFIG_FILENAME);
|
|
24
37
|
}
|
|
25
38
|
async function loadWorkspaceConfig(workdir) {
|
|
26
39
|
try {
|
|
@@ -50,7 +63,7 @@ async function saveWorkspaceConfig(workdir, config) {
|
|
|
50
63
|
return;
|
|
51
64
|
}
|
|
52
65
|
const resolved = resolve(workdir);
|
|
53
|
-
const dirPath =
|
|
66
|
+
const dirPath = join2(resolved, ".openfox");
|
|
54
67
|
await mkdir(dirPath, { recursive: true });
|
|
55
68
|
await writeFile(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
56
69
|
}
|
|
@@ -90,11 +103,11 @@ function getGlobalDataDir() {
|
|
|
90
103
|
const home = homedir();
|
|
91
104
|
switch (platform()) {
|
|
92
105
|
case "darwin":
|
|
93
|
-
return
|
|
106
|
+
return join3(home, "Library", "Application Support", `openfox${suffix}`);
|
|
94
107
|
case "win32":
|
|
95
|
-
return
|
|
108
|
+
return join3(process.env["LOCALAPPDATA"] ?? join3(home, "AppData", "Local"), `openfox${suffix}`);
|
|
96
109
|
default:
|
|
97
|
-
return
|
|
110
|
+
return join3(process.env["XDG_DATA_HOME"] ?? join3(home, ".local", "share"), `openfox${suffix}`);
|
|
98
111
|
}
|
|
99
112
|
}
|
|
100
113
|
async function getWorkspacesDir(projectName, projectDir) {
|
|
@@ -102,10 +115,10 @@ async function getWorkspacesDir(projectName, projectDir) {
|
|
|
102
115
|
if (project?.workspaceRootDir) {
|
|
103
116
|
return isAbsolute(project.workspaceRootDir) ? project.workspaceRootDir : resolve2(projectDir, project.workspaceRootDir);
|
|
104
117
|
}
|
|
105
|
-
return
|
|
118
|
+
return join3(getGlobalDataDir(), "workspaces", projectName);
|
|
106
119
|
}
|
|
107
120
|
function getDefaultGlobalWorkspacesDir(projectName) {
|
|
108
|
-
return
|
|
121
|
+
return join3(getGlobalDataDir(), "workspaces", projectName);
|
|
109
122
|
}
|
|
110
123
|
function getGitBranch(cwd) {
|
|
111
124
|
return captureStdout(cwd, ["rev-parse", "--abbrev-ref", "HEAD"]).then((r) => r?.trim() ?? null);
|
|
@@ -208,7 +221,7 @@ async function workspaceExists(projectName, name, projectDir) {
|
|
|
208
221
|
const wsPath = resolve2(dir, name);
|
|
209
222
|
const st = await statSafe(wsPath);
|
|
210
223
|
if (!st?.isDirectory()) return false;
|
|
211
|
-
const gitDir =
|
|
224
|
+
const gitDir = join3(wsPath, ".git");
|
|
212
225
|
const gitSt = await statSafe(gitDir);
|
|
213
226
|
return gitSt?.isDirectory() ?? false;
|
|
214
227
|
}
|
|
@@ -219,7 +232,7 @@ async function listWorkspaces(projectName, projectDir) {
|
|
|
219
232
|
const entries = await readdir(dir, { withFileTypes: true });
|
|
220
233
|
const workspaces = [];
|
|
221
234
|
for (const entry of entries) {
|
|
222
|
-
if (entry
|
|
235
|
+
if (await isDirectoryEntry(dir, entry)) {
|
|
223
236
|
const wsPath = resolve2(dir, entry.name);
|
|
224
237
|
const branch = await getGitBranch(wsPath);
|
|
225
238
|
workspaces.push({ path: wsPath, name: entry.name, branch });
|
|
@@ -236,7 +249,7 @@ async function ensureWorkspace(projectDir, name, projectName, branch, sourceBran
|
|
|
236
249
|
await mkdir2(workspacesDir, { recursive: true });
|
|
237
250
|
const existing = await statSafe(wsPath);
|
|
238
251
|
if (existing?.isDirectory()) {
|
|
239
|
-
const gitDir =
|
|
252
|
+
const gitDir = join3(wsPath, ".git");
|
|
240
253
|
const gitStat = await statSafe(gitDir);
|
|
241
254
|
if (!gitStat?.isDirectory()) {
|
|
242
255
|
throw new Error("Existing path is not a valid workspace: " + wsPath);
|
|
@@ -290,9 +303,9 @@ async function deleteWorkspace(projectName, name, projectDir) {
|
|
|
290
303
|
logger.info("Deleted workspace", { projectName, name, path: wsPath });
|
|
291
304
|
}
|
|
292
305
|
async function isGitRepository(cwd) {
|
|
293
|
-
const { stat } = await import("fs/promises");
|
|
306
|
+
const { stat: stat2 } = await import("fs/promises");
|
|
294
307
|
try {
|
|
295
|
-
const st = await
|
|
308
|
+
const st = await stat2(join3(cwd, ".git"));
|
|
296
309
|
if (st.isDirectory()) return true;
|
|
297
310
|
} catch {
|
|
298
311
|
}
|
|
@@ -301,14 +314,15 @@ async function isGitRepository(cwd) {
|
|
|
301
314
|
}
|
|
302
315
|
async function statSafe(p) {
|
|
303
316
|
try {
|
|
304
|
-
const { stat } = await import("fs/promises");
|
|
305
|
-
return await
|
|
317
|
+
const { stat: stat2 } = await import("fs/promises");
|
|
318
|
+
return await stat2(p);
|
|
306
319
|
} catch {
|
|
307
320
|
return null;
|
|
308
321
|
}
|
|
309
322
|
}
|
|
310
323
|
|
|
311
324
|
export {
|
|
325
|
+
isDirectoryEntry,
|
|
312
326
|
loadWorkspaceConfig,
|
|
313
327
|
saveWorkspaceConfig,
|
|
314
328
|
runGit,
|
|
@@ -333,4 +347,4 @@ export {
|
|
|
333
347
|
deleteWorkspace,
|
|
334
348
|
isGitRepository
|
|
335
349
|
};
|
|
336
|
-
//# sourceMappingURL=chunk-
|
|
350
|
+
//# sourceMappingURL=chunk-Y3BSBKHY.js.map
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import {
|
|
2
|
+
SETTINGS_KEYS,
|
|
3
|
+
getSetting
|
|
4
|
+
} from "./chunk-N2Q3KYWM.js";
|
|
5
|
+
import {
|
|
6
|
+
logger
|
|
7
|
+
} from "./chunk-K44MW7JJ.js";
|
|
8
|
+
|
|
9
|
+
// src/server/utils/errors.ts
|
|
10
|
+
var OpenFoxError = class extends Error {
|
|
11
|
+
constructor(message, code, details) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.code = code;
|
|
14
|
+
this.details = details;
|
|
15
|
+
this.name = "OpenFoxError";
|
|
16
|
+
}
|
|
17
|
+
code;
|
|
18
|
+
details;
|
|
19
|
+
};
|
|
20
|
+
var SessionNotFoundError = class extends OpenFoxError {
|
|
21
|
+
constructor(sessionId) {
|
|
22
|
+
super(`Session not found: ${sessionId}`, "SESSION_NOT_FOUND", { sessionId });
|
|
23
|
+
this.name = "SessionNotFoundError";
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
var LLMError = class extends OpenFoxError {
|
|
27
|
+
constructor(message, details) {
|
|
28
|
+
super(message, "LLM_ERROR", details);
|
|
29
|
+
this.name = "LLMError";
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
var WorkspaceInUseError = class extends OpenFoxError {
|
|
33
|
+
constructor(message, conflictingSessionIds) {
|
|
34
|
+
super(message, "WORKSPACE_IN_USE");
|
|
35
|
+
this.conflictingSessionIds = conflictingSessionIds;
|
|
36
|
+
this.name = "WorkspaceInUseError";
|
|
37
|
+
}
|
|
38
|
+
conflictingSessionIds;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// src/server/llm/http-shared.ts
|
|
42
|
+
var DONE = /* @__PURE__ */ Symbol("done");
|
|
43
|
+
var ChatHttpClient = class {
|
|
44
|
+
async post(params, options) {
|
|
45
|
+
const { url, headers, body } = this.buildRequest(params);
|
|
46
|
+
logger.debug("HTTP request to LLM", { url, bodyKeys: Object.keys(params) });
|
|
47
|
+
return postJson(url, headers, body, options);
|
|
48
|
+
}
|
|
49
|
+
async createChatCompletion(params, options, returnRaw) {
|
|
50
|
+
const response = await this.post(params, options);
|
|
51
|
+
return parseCompletionResponse(response, (data) => this.parseNonStreaming(data), returnRaw);
|
|
52
|
+
}
|
|
53
|
+
createChatCompletionStream(params, options) {
|
|
54
|
+
const parseStreamLine = this.parseStreamLine.bind(this);
|
|
55
|
+
const responsePromise = this.post(params, options);
|
|
56
|
+
async function* generate() {
|
|
57
|
+
const response = await responsePromise;
|
|
58
|
+
for await (const trimmed of readResponseLines(response)) {
|
|
59
|
+
const chunk = parseStreamLine(trimmed);
|
|
60
|
+
if (chunk === null) continue;
|
|
61
|
+
if (chunk === DONE) return;
|
|
62
|
+
yield chunk;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return generate();
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
async function postJson(url, headers, body, options) {
|
|
69
|
+
const response = await fetch(url, {
|
|
70
|
+
method: "POST",
|
|
71
|
+
headers,
|
|
72
|
+
body,
|
|
73
|
+
signal: options?.signal ?? null
|
|
74
|
+
});
|
|
75
|
+
if (!response.ok) {
|
|
76
|
+
const errorText = await response.text();
|
|
77
|
+
throw new LLMError(`HTTP ${response.status}: ${errorText}`);
|
|
78
|
+
}
|
|
79
|
+
return response;
|
|
80
|
+
}
|
|
81
|
+
async function parseCompletionResponse(response, parse, returnRaw) {
|
|
82
|
+
const rawText = await response.text();
|
|
83
|
+
try {
|
|
84
|
+
const mapped = parse(JSON.parse(rawText));
|
|
85
|
+
if (returnRaw) {
|
|
86
|
+
return { ...mapped, raw: rawText };
|
|
87
|
+
}
|
|
88
|
+
return mapped;
|
|
89
|
+
} catch (error) {
|
|
90
|
+
throw new LLMError(`Failed to parse response: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
async function* readResponseLines(response) {
|
|
94
|
+
if (!response.body) {
|
|
95
|
+
throw new LLMError("No response body for streaming");
|
|
96
|
+
}
|
|
97
|
+
const reader = response.body.getReader();
|
|
98
|
+
const decoder = new TextDecoder();
|
|
99
|
+
let buffer = "";
|
|
100
|
+
try {
|
|
101
|
+
while (true) {
|
|
102
|
+
const { done, value } = await reader.read();
|
|
103
|
+
if (done) break;
|
|
104
|
+
buffer += decoder.decode(value, { stream: true });
|
|
105
|
+
const lines = buffer.split("\n");
|
|
106
|
+
buffer = lines.pop() || "";
|
|
107
|
+
for (const line of lines) {
|
|
108
|
+
const trimmed = line.trim();
|
|
109
|
+
if (trimmed) yield trimmed;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
} finally {
|
|
113
|
+
reader.releaseLock();
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// src/server/llm/proxy.ts
|
|
118
|
+
import { fetch as undiciFetch, ProxyAgent } from "undici";
|
|
119
|
+
var _cachedProxyUrl;
|
|
120
|
+
var _cachedAgent;
|
|
121
|
+
function getProxyAgent() {
|
|
122
|
+
const proxyUrl = getSetting(SETTINGS_KEYS.PROXY_URL) ?? void 0;
|
|
123
|
+
if (!proxyUrl) {
|
|
124
|
+
if (_cachedAgent) {
|
|
125
|
+
_cachedAgent.destroy().catch((err) => {
|
|
126
|
+
logger.warn("[proxy] Failed to destroy old proxy agent", { error: err });
|
|
127
|
+
});
|
|
128
|
+
_cachedAgent = void 0;
|
|
129
|
+
_cachedProxyUrl = void 0;
|
|
130
|
+
}
|
|
131
|
+
return void 0;
|
|
132
|
+
}
|
|
133
|
+
if (proxyUrl !== _cachedProxyUrl) {
|
|
134
|
+
if (_cachedAgent) {
|
|
135
|
+
_cachedAgent.destroy().catch((err) => {
|
|
136
|
+
logger.warn("[proxy] Failed to destroy old proxy agent", { error: err });
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
_cachedProxyUrl = proxyUrl;
|
|
140
|
+
_cachedAgent = new ProxyAgent({ uri: proxyUrl, requestTls: { rejectUnauthorized: false } });
|
|
141
|
+
logger.info("[proxy] Proxy agent created");
|
|
142
|
+
}
|
|
143
|
+
return _cachedAgent;
|
|
144
|
+
}
|
|
145
|
+
var _originalFetch = globalThis.fetch;
|
|
146
|
+
globalThis.fetch = function(input, init) {
|
|
147
|
+
const agent = getProxyAgent();
|
|
148
|
+
if (agent) {
|
|
149
|
+
return undiciFetch(input, { ...init, dispatcher: agent });
|
|
150
|
+
}
|
|
151
|
+
return _originalFetch(input, init);
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
// src/server/llm/http-client.ts
|
|
155
|
+
var OpenAIHttpClient = class extends ChatHttpClient {
|
|
156
|
+
baseURL;
|
|
157
|
+
apiKey;
|
|
158
|
+
constructor(options) {
|
|
159
|
+
super();
|
|
160
|
+
this.baseURL = options.baseURL;
|
|
161
|
+
this.apiKey = options.apiKey;
|
|
162
|
+
}
|
|
163
|
+
buildRequest(params) {
|
|
164
|
+
return {
|
|
165
|
+
url: `${this.baseURL}/chat/completions`,
|
|
166
|
+
headers: {
|
|
167
|
+
"Content-Type": "application/json",
|
|
168
|
+
Authorization: `Bearer ${this.apiKey}`
|
|
169
|
+
},
|
|
170
|
+
body: JSON.stringify(params)
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
parseNonStreaming(data) {
|
|
174
|
+
return data;
|
|
175
|
+
}
|
|
176
|
+
parseStreamLine(trimmed) {
|
|
177
|
+
if (!trimmed.startsWith("data: ")) return null;
|
|
178
|
+
const data = trimmed.slice(6);
|
|
179
|
+
if (data === "[DONE]") return DONE;
|
|
180
|
+
try {
|
|
181
|
+
return JSON.parse(data);
|
|
182
|
+
} catch (error) {
|
|
183
|
+
logger.warn("Failed to parse SSE chunk", { data, error });
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
export {
|
|
190
|
+
SessionNotFoundError,
|
|
191
|
+
LLMError,
|
|
192
|
+
WorkspaceInUseError,
|
|
193
|
+
ChatHttpClient,
|
|
194
|
+
OpenAIHttpClient
|
|
195
|
+
};
|
|
196
|
+
//# sourceMappingURL=chunk-ZFNBATE3.js.map
|