openfox 2.0.73 → 2.0.74
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/dist/{chat-handler-LK5RUAGO.js → chat-handler-ETKFIHUO.js} +4 -4
- package/dist/{chunk-GMF36EZ3.js → chunk-2VBETAU2.js} +4 -4
- package/dist/chunk-3OZBPWHP.js +7 -0
- package/dist/{chunk-X2Y3AJPP.js → chunk-MF3UW36X.js} +10 -2
- package/dist/{chunk-EYXDM2FY.js → chunk-QFR6JF32.js} +266 -84
- package/dist/{chunk-KKRLQH6F.js → chunk-R6L2QXQ5.js} +5 -5
- package/dist/{chunk-TK4BZIXA.js → chunk-TMRFTWXP.js} +11 -4
- package/dist/{chunk-O2BE7KVQ.js → chunk-ZRQDCQ7R.js} +4 -4
- package/dist/cli/dev.js +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/{orchestrator-RTZVMWQV.js → orchestrator-O2YAAZ3U.js} +4 -4
- package/dist/package.json +1 -1
- package/dist/{processor-3O26I7DO.js → processor-FKAS3K4L.js} +4 -4
- package/dist/{serve-I6K7A7RL.js → serve-T5U6SLB7.js} +7 -7
- package/dist/server/index.d.ts +4 -0
- package/dist/server/index.js +6 -6
- package/dist/{server-G2J4RAXL.js → server-T2YP3VT2.js} +5 -5
- package/dist/{tools-X52DFUS6.js → tools-APW7MY4E.js} +3 -3
- package/dist/{update-RJB4GPHE.js → update-FWO365SV.js} +2 -2
- package/dist/web/assets/{index-CmechlaK.css → index-DZRcUhoE.css} +1 -1
- package/dist/web/assets/{index-C7SW16F7.js → index-Xh2VHbZe.js} +69 -69
- package/dist/web/index.html +2 -2
- package/dist/web/sw.js +1 -1
- package/dist/{workspace-ET3FHZYN.js → workspace-6QTTUMMW.js} +4 -2
- package/package.json +1 -1
- package/dist/chunk-NE7OWIIO.js +0 -7
|
@@ -5,9 +5,9 @@ import {
|
|
|
5
5
|
} from "./chunk-2DCJERYX.js";
|
|
6
6
|
import {
|
|
7
7
|
runChatTurn
|
|
8
|
-
} from "./chunk-
|
|
9
|
-
import "./chunk-
|
|
10
|
-
import "./chunk-
|
|
8
|
+
} from "./chunk-ZRQDCQ7R.js";
|
|
9
|
+
import "./chunk-2VBETAU2.js";
|
|
10
|
+
import "./chunk-MF3UW36X.js";
|
|
11
11
|
import "./chunk-WGMJCFCE.js";
|
|
12
12
|
import "./chunk-EU3WWTFH.js";
|
|
13
13
|
import "./chunk-XWBNYU2L.js";
|
|
@@ -158,4 +158,4 @@ export {
|
|
|
158
158
|
startChatSession,
|
|
159
159
|
stopSessionExecution
|
|
160
160
|
};
|
|
161
|
-
//# sourceMappingURL=chat-handler-
|
|
161
|
+
//# sourceMappingURL=chat-handler-ETKFIHUO.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getGitBranch,
|
|
3
3
|
listWorkspaces
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-MF3UW36X.js";
|
|
5
5
|
import {
|
|
6
6
|
AskUserInterrupt,
|
|
7
7
|
askUserTool
|
|
@@ -3814,7 +3814,7 @@ var callSubAgentTool = {
|
|
|
3814
3814
|
};
|
|
3815
3815
|
}
|
|
3816
3816
|
try {
|
|
3817
|
-
const { getToolRegistryForAgent: getToolRegistryForAgent2 } = await import("./tools-
|
|
3817
|
+
const { getToolRegistryForAgent: getToolRegistryForAgent2 } = await import("./tools-APW7MY4E.js");
|
|
3818
3818
|
const toolRegistry = getToolRegistryForAgent2(agentDef);
|
|
3819
3819
|
const turnMetrics = new TurnMetrics();
|
|
3820
3820
|
const result = await executeSubAgent({
|
|
@@ -4813,7 +4813,7 @@ var mcpConfigTool = createTool(
|
|
|
4813
4813
|
mcpNotifyChanged?.(sessionId);
|
|
4814
4814
|
}
|
|
4815
4815
|
async function rebuildTools() {
|
|
4816
|
-
const { setMcpTools: setMcpTools2 } = await import("./tools-
|
|
4816
|
+
const { setMcpTools: setMcpTools2 } = await import("./tools-APW7MY4E.js");
|
|
4817
4817
|
const mcpTools = createMcpTools(mcpManagerForTools);
|
|
4818
4818
|
setMcpTools2(mcpTools);
|
|
4819
4819
|
}
|
|
@@ -5493,4 +5493,4 @@ export {
|
|
|
5493
5493
|
getToolRegistryForAgent,
|
|
5494
5494
|
createToolRegistry
|
|
5495
5495
|
};
|
|
5496
|
-
//# sourceMappingURL=chunk-
|
|
5496
|
+
//# sourceMappingURL=chunk-2VBETAU2.js.map
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
// src/server/git/workspace.ts
|
|
9
9
|
import { spawn, execSync } from "child_process";
|
|
10
10
|
import { mkdir as mkdir2 } from "fs/promises";
|
|
11
|
-
import { resolve as resolve2, join as join2 } from "path";
|
|
11
|
+
import { resolve as resolve2, join as join2, isAbsolute } from "path";
|
|
12
12
|
import { homedir, platform } from "os";
|
|
13
13
|
|
|
14
14
|
// src/server/git/workspace-config.ts
|
|
@@ -106,6 +106,13 @@ async function getCommitsBehind(cwd, branch) {
|
|
|
106
106
|
function validateRef(cwd, name) {
|
|
107
107
|
return runGit(cwd, ["check-ref-format", `refs/heads/${name}`]);
|
|
108
108
|
}
|
|
109
|
+
function validateWorkspaceName(name) {
|
|
110
|
+
if (!name || typeof name !== "string") throw new Error("Workspace name is required");
|
|
111
|
+
if (name.includes("/") || name.includes("\\")) throw new Error("Workspace name cannot contain path separators");
|
|
112
|
+
if (name === "." || name === "..") throw new Error('Workspace name cannot be "." or ".."');
|
|
113
|
+
if (isAbsolute(name)) throw new Error("Workspace name cannot be an absolute path");
|
|
114
|
+
if (name.length > 255) throw new Error("Workspace name is too long");
|
|
115
|
+
}
|
|
109
116
|
function checkoutBranch(cwd, name) {
|
|
110
117
|
return runGit(cwd, ["checkout", name]);
|
|
111
118
|
}
|
|
@@ -206,6 +213,7 @@ export {
|
|
|
206
213
|
listBranches,
|
|
207
214
|
getCommitsBehind,
|
|
208
215
|
validateRef,
|
|
216
|
+
validateWorkspaceName,
|
|
209
217
|
checkoutBranch,
|
|
210
218
|
createBranch,
|
|
211
219
|
workspaceExists,
|
|
@@ -213,4 +221,4 @@ export {
|
|
|
213
221
|
ensureWorkspace,
|
|
214
222
|
deleteWorkspace
|
|
215
223
|
};
|
|
216
|
-
//# sourceMappingURL=chunk-
|
|
224
|
+
//# sourceMappingURL=chunk-MF3UW36X.js.map
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
tokenFromPassword,
|
|
22
22
|
verifyPassword,
|
|
23
23
|
workflowExists
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-TMRFTWXP.js";
|
|
25
25
|
import {
|
|
26
26
|
agentExists,
|
|
27
27
|
createToolRegistry,
|
|
@@ -66,7 +66,7 @@ import {
|
|
|
66
66
|
setSkillEnabled,
|
|
67
67
|
skillExists,
|
|
68
68
|
updateOwnedSkill
|
|
69
|
-
} from "./chunk-
|
|
69
|
+
} from "./chunk-2VBETAU2.js";
|
|
70
70
|
import {
|
|
71
71
|
deleteWorkspace,
|
|
72
72
|
ensureWorkspace,
|
|
@@ -76,8 +76,9 @@ import {
|
|
|
76
76
|
loadWorkspaceConfig,
|
|
77
77
|
runGit,
|
|
78
78
|
saveWorkspaceConfig,
|
|
79
|
+
validateWorkspaceName,
|
|
79
80
|
workspaceExists
|
|
80
|
-
} from "./chunk-
|
|
81
|
+
} from "./chunk-MF3UW36X.js";
|
|
81
82
|
import {
|
|
82
83
|
EventEmitter
|
|
83
84
|
} from "./chunk-EU3WWTFH.js";
|
|
@@ -94,7 +95,7 @@ import {
|
|
|
94
95
|
} from "./chunk-NWO6GRYE.js";
|
|
95
96
|
import {
|
|
96
97
|
VERSION
|
|
97
|
-
} from "./chunk-
|
|
98
|
+
} from "./chunk-3OZBPWHP.js";
|
|
98
99
|
import {
|
|
99
100
|
createSession,
|
|
100
101
|
deleteSession,
|
|
@@ -2557,6 +2558,8 @@ var SessionManager = class {
|
|
|
2557
2558
|
dynamicContextChangedStore = /* @__PURE__ */ new Map();
|
|
2558
2559
|
debugDumpStore = /* @__PURE__ */ new Map();
|
|
2559
2560
|
warmedUpSessions = /* @__PURE__ */ new Set();
|
|
2561
|
+
switchLocks = /* @__PURE__ */ new Map();
|
|
2562
|
+
workspaceCreationLocks = /* @__PURE__ */ new Map();
|
|
2560
2563
|
constructor(providerManager) {
|
|
2561
2564
|
this.providerManager = providerManager;
|
|
2562
2565
|
}
|
|
@@ -3213,89 +3216,135 @@ var SessionManager = class {
|
|
|
3213
3216
|
* Switch to a workspace. Target can be "original" (project root) or a workspace name.
|
|
3214
3217
|
* If the workspace doesn't exist yet, it's created first.
|
|
3215
3218
|
* Emits a single type of event — switching is always "opening" a workspace.
|
|
3219
|
+
* Switches are serialized per-session to prevent race conditions.
|
|
3216
3220
|
*/
|
|
3217
3221
|
async switchWorkspace(sessionId, target, branch) {
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
if (
|
|
3223
|
-
|
|
3224
|
-
|
|
3222
|
+
if (target !== "original") {
|
|
3223
|
+
validateWorkspaceName(target);
|
|
3224
|
+
}
|
|
3225
|
+
const existingLock = this.switchLocks.get(sessionId);
|
|
3226
|
+
if (existingLock) {
|
|
3227
|
+
await existingLock;
|
|
3228
|
+
}
|
|
3229
|
+
const lockPromise = (async () => {
|
|
3230
|
+
const session = this.requireSession(sessionId);
|
|
3231
|
+
const project = getProject(session.projectId);
|
|
3232
|
+
if (!project) throw new Error(`Project not found: ${session.projectId}`);
|
|
3233
|
+
if (target === "original" && !session.workspace) return session;
|
|
3234
|
+
if (target !== "original" && session.workspace?.split("/").pop() === target) return session;
|
|
3235
|
+
const previousPath = session.workspace;
|
|
3236
|
+
if (previousPath) {
|
|
3237
|
+
try {
|
|
3238
|
+
await devServerManager.stop(previousPath);
|
|
3239
|
+
} catch (err) {
|
|
3240
|
+
logger.error("Error stopping dev server for workspace switch", {
|
|
3241
|
+
sessionId,
|
|
3242
|
+
workspace: previousPath,
|
|
3243
|
+
error: err
|
|
3244
|
+
});
|
|
3245
|
+
}
|
|
3246
|
+
}
|
|
3247
|
+
if (target === "original") {
|
|
3248
|
+
updateSessionWorkdir(sessionId, project.workdir, null);
|
|
3249
|
+
} else {
|
|
3250
|
+
const createLockKey = `${project.name}:${target}`;
|
|
3251
|
+
const existingCreateLock = this.workspaceCreationLocks.get(createLockKey);
|
|
3252
|
+
if (existingCreateLock) {
|
|
3253
|
+
await existingCreateLock;
|
|
3254
|
+
}
|
|
3255
|
+
const createLockPromise = (async () => {
|
|
3256
|
+
const exists = await workspaceExists(project.name, target);
|
|
3257
|
+
if (!exists) {
|
|
3258
|
+
await ensureWorkspace(project.workdir, target, project.name, branch);
|
|
3259
|
+
}
|
|
3260
|
+
})();
|
|
3261
|
+
this.workspaceCreationLocks.set(createLockKey, createLockPromise);
|
|
3262
|
+
try {
|
|
3263
|
+
await createLockPromise;
|
|
3264
|
+
} finally {
|
|
3265
|
+
this.workspaceCreationLocks.delete(createLockKey);
|
|
3266
|
+
}
|
|
3267
|
+
const wsPath = resolve2(getWorkspacesDir(project.name), target);
|
|
3268
|
+
updateSessionWorkdir(sessionId, project.workdir, wsPath);
|
|
3269
|
+
}
|
|
3225
3270
|
try {
|
|
3226
|
-
await
|
|
3271
|
+
await shutdownLspManager(sessionId);
|
|
3227
3272
|
} catch (err) {
|
|
3228
|
-
logger.error("Error
|
|
3229
|
-
sessionId,
|
|
3230
|
-
workspace: previousPath,
|
|
3231
|
-
error: err
|
|
3232
|
-
});
|
|
3233
|
-
}
|
|
3234
|
-
}
|
|
3235
|
-
if (target === "original") {
|
|
3236
|
-
updateSessionWorkdir(sessionId, project.workdir, null);
|
|
3237
|
-
} else {
|
|
3238
|
-
const exists = await workspaceExists(project.name, target);
|
|
3239
|
-
if (!exists) {
|
|
3240
|
-
await ensureWorkspace(project.workdir, target, project.name, branch);
|
|
3273
|
+
logger.error("Error shutting down LSP for workspace switch", { sessionId, error: err });
|
|
3241
3274
|
}
|
|
3242
|
-
const
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
let stalenessHint = "";
|
|
3253
|
-
if (target !== "original" && actualBranch) {
|
|
3254
|
-
await runGit(effectiveWorkdir, ["fetch", "origin", "--no-tags", "--quiet"]).catch(() => {
|
|
3255
|
-
});
|
|
3256
|
-
const behind = await getCommitsBehind(effectiveWorkdir, actualBranch);
|
|
3257
|
-
if (behind !== null && behind > 0) {
|
|
3258
|
-
const plural = behind === 1 ? "" : "s";
|
|
3259
|
-
stalenessHint = `
|
|
3275
|
+
const effectiveWorkdir = target === "original" ? project.workdir : resolve2(getWorkspacesDir(project.name), target);
|
|
3276
|
+
const actualBranch = await getGitBranch(effectiveWorkdir);
|
|
3277
|
+
let stalenessHint = "";
|
|
3278
|
+
if (target !== "original" && actualBranch) {
|
|
3279
|
+
await runGit(effectiveWorkdir, ["fetch", "origin", "--no-tags", "--quiet"]).catch(() => {
|
|
3280
|
+
});
|
|
3281
|
+
const behind = await getCommitsBehind(effectiveWorkdir, actualBranch);
|
|
3282
|
+
if (behind !== null && behind > 0) {
|
|
3283
|
+
const plural = behind === 1 ? "" : "s";
|
|
3284
|
+
stalenessHint = `
|
|
3260
3285
|
(${behind} commit${plural} behind ${actualBranch} on main workspace \u2014 run \`git pull\` to sync)`;
|
|
3286
|
+
}
|
|
3261
3287
|
}
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
const reminderContent = `<system-reminder>
|
|
3288
|
+
const wsLabel = target === "original" ? "original" : target;
|
|
3289
|
+
const reminderContent = `<system-reminder>
|
|
3265
3290
|
This session is now operating in workspace "${wsLabel}" on branch "${actualBranch ?? "unknown"}" at ${effectiveWorkdir}.${stalenessHint}
|
|
3266
3291
|
All file and git operations should use this directory.
|
|
3267
3292
|
</system-reminder>`;
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3293
|
+
this.addMessage(sessionId, {
|
|
3294
|
+
role: "user",
|
|
3295
|
+
content: reminderContent,
|
|
3296
|
+
isSystemGenerated: true,
|
|
3297
|
+
messageKind: "auto-prompt",
|
|
3298
|
+
metadata: {
|
|
3299
|
+
type: "workspace",
|
|
3300
|
+
name: "Workspace",
|
|
3301
|
+
color: "#22c55e",
|
|
3302
|
+
kind: "definition",
|
|
3303
|
+
workspaceName: wsLabel,
|
|
3304
|
+
...actualBranch ? { branchName: actualBranch } : {}
|
|
3305
|
+
}
|
|
3306
|
+
});
|
|
3307
|
+
const updated = this.requireSession(sessionId);
|
|
3308
|
+
this.emit({ type: "session_updated", session: updated });
|
|
3309
|
+
return updated;
|
|
3310
|
+
})();
|
|
3311
|
+
this.switchLocks.set(sessionId, lockPromise);
|
|
3312
|
+
lockPromise.finally(() => {
|
|
3313
|
+
if (this.switchLocks.get(sessionId) === lockPromise) {
|
|
3314
|
+
this.switchLocks.delete(sessionId);
|
|
3280
3315
|
}
|
|
3281
3316
|
});
|
|
3282
|
-
|
|
3283
|
-
this.emit({ type: "session_updated", session: updated });
|
|
3284
|
-
return updated;
|
|
3317
|
+
return lockPromise;
|
|
3285
3318
|
}
|
|
3286
3319
|
/**
|
|
3287
3320
|
* Delete a workspace by name. If the session is currently in that workspace,
|
|
3288
3321
|
* switches to original first. Throws if target is "original".
|
|
3322
|
+
* Refuses deletion if other sessions reference this workspace.
|
|
3289
3323
|
*/
|
|
3290
3324
|
async deleteWorkspace(sessionId, target) {
|
|
3291
3325
|
if (target === "original") throw new Error("Cannot delete the original workspace");
|
|
3326
|
+
validateWorkspaceName(target);
|
|
3292
3327
|
const session = this.requireSession(sessionId);
|
|
3293
3328
|
const project = getProject(session.projectId);
|
|
3294
3329
|
if (!project) throw new Error(`Project not found: ${session.projectId}`);
|
|
3330
|
+
const otherSessionsUsingIt = this.listSessions().filter(
|
|
3331
|
+
(s) => s.id !== sessionId && s.workspace?.split("/").pop() === target
|
|
3332
|
+
);
|
|
3333
|
+
if (otherSessionsUsingIt.length > 0) {
|
|
3334
|
+
const otherIds = otherSessionsUsingIt.map((s) => s.id).join(", ");
|
|
3335
|
+
throw new Error(
|
|
3336
|
+
`Workspace "${target}" is in use by other session(s): ${otherIds}. Switch them to original first.`
|
|
3337
|
+
);
|
|
3338
|
+
}
|
|
3295
3339
|
const currentWsName = session.workspace?.split("/").pop();
|
|
3296
3340
|
if (currentWsName === target) {
|
|
3297
3341
|
await this.switchWorkspace(sessionId, "original");
|
|
3298
3342
|
}
|
|
3343
|
+
const effectivePath = resolve2(getWorkspacesDir(project.name), target);
|
|
3344
|
+
try {
|
|
3345
|
+
await devServerManager.stop(effectivePath);
|
|
3346
|
+
} catch {
|
|
3347
|
+
}
|
|
3299
3348
|
await deleteWorkspace(project.name, target);
|
|
3300
3349
|
const updated = this.requireSession(sessionId);
|
|
3301
3350
|
this.emit({ type: "session_updated", session: updated });
|
|
@@ -4252,6 +4301,11 @@ function fuzzyScore(filePath, query) {
|
|
|
4252
4301
|
import { Router as Router9 } from "express";
|
|
4253
4302
|
import { spawn as spawn2 } from "child_process";
|
|
4254
4303
|
var updateInProgress = false;
|
|
4304
|
+
var CACHE_TTL_MS = 60 * 60 * 1e3;
|
|
4305
|
+
var versionCache = {
|
|
4306
|
+
data: null,
|
|
4307
|
+
timestamp: 0
|
|
4308
|
+
};
|
|
4255
4309
|
function isRunningAsService() {
|
|
4256
4310
|
return process.env["OPENFOX_SERVICE"] === "true";
|
|
4257
4311
|
}
|
|
@@ -4265,13 +4319,94 @@ async function checkAuth(req, opts) {
|
|
|
4265
4319
|
}
|
|
4266
4320
|
return true;
|
|
4267
4321
|
}
|
|
4322
|
+
function isDevMode() {
|
|
4323
|
+
return process.env["NODE_ENV"] === "development";
|
|
4324
|
+
}
|
|
4325
|
+
async function getRemote() {
|
|
4326
|
+
return new Promise((resolve8) => {
|
|
4327
|
+
const child = spawn2("git", ["remote"], {
|
|
4328
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
4329
|
+
windowsHide: true
|
|
4330
|
+
});
|
|
4331
|
+
let output = "";
|
|
4332
|
+
child.stdout?.on("data", (data) => {
|
|
4333
|
+
output += data.toString();
|
|
4334
|
+
});
|
|
4335
|
+
child.on("close", () => {
|
|
4336
|
+
const remotes = output.trim().split("\n").map((r) => r.trim()).filter(Boolean);
|
|
4337
|
+
if (remotes.includes("upstream")) resolve8("upstream");
|
|
4338
|
+
else if (remotes.includes("origin")) resolve8("origin");
|
|
4339
|
+
else resolve8("origin");
|
|
4340
|
+
});
|
|
4341
|
+
child.on("error", () => resolve8("origin"));
|
|
4342
|
+
});
|
|
4343
|
+
}
|
|
4344
|
+
async function getLatestDevelopVersion() {
|
|
4345
|
+
const remote = await getRemote();
|
|
4346
|
+
return new Promise((resolve8) => {
|
|
4347
|
+
const fetchChild = spawn2("git", ["fetch", remote, "develop", "--no-tags"], {
|
|
4348
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
4349
|
+
windowsHide: true
|
|
4350
|
+
});
|
|
4351
|
+
fetchChild.on("error", (err) => {
|
|
4352
|
+
logger.error("[auto-update] Git fetch error", { error: err.message });
|
|
4353
|
+
resolve8("unknown");
|
|
4354
|
+
});
|
|
4355
|
+
fetchChild.on("close", (code) => {
|
|
4356
|
+
if (code !== 0) {
|
|
4357
|
+
logger.warn("[auto-update] Git fetch failed, trying local tags...");
|
|
4358
|
+
}
|
|
4359
|
+
const tagChild = spawn2("git", ["describe", "--tags", "--abbrev=0", `${remote}/develop`], {
|
|
4360
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
4361
|
+
windowsHide: true
|
|
4362
|
+
});
|
|
4363
|
+
let tagOutput = "";
|
|
4364
|
+
tagChild.stdout?.on("data", (data) => {
|
|
4365
|
+
tagOutput += data.toString();
|
|
4366
|
+
});
|
|
4367
|
+
tagChild.on("close", (tagCode) => {
|
|
4368
|
+
if (tagCode === 0 && tagOutput.trim()) {
|
|
4369
|
+
resolve8(tagOutput.trim());
|
|
4370
|
+
} else {
|
|
4371
|
+
const fallbackChild = spawn2("git", ["describe", "--tags", "--abbrev=0", "develop"], {
|
|
4372
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
4373
|
+
windowsHide: true
|
|
4374
|
+
});
|
|
4375
|
+
let fallbackOutput = "";
|
|
4376
|
+
fallbackChild.stdout?.on("data", (data) => {
|
|
4377
|
+
fallbackOutput += data.toString();
|
|
4378
|
+
});
|
|
4379
|
+
fallbackChild.on("close", (fallbackCode) => {
|
|
4380
|
+
if (fallbackCode === 0 && fallbackOutput.trim()) {
|
|
4381
|
+
resolve8(fallbackOutput.trim());
|
|
4382
|
+
} else {
|
|
4383
|
+
logger.warn("[auto-update] No tags found on develop branch");
|
|
4384
|
+
resolve8("unknown");
|
|
4385
|
+
}
|
|
4386
|
+
});
|
|
4387
|
+
fallbackChild.on("error", () => resolve8("unknown"));
|
|
4388
|
+
}
|
|
4389
|
+
});
|
|
4390
|
+
tagChild.on("error", (err) => {
|
|
4391
|
+
logger.error("[auto-update] Git tag error", { error: err.message });
|
|
4392
|
+
resolve8("unknown");
|
|
4393
|
+
});
|
|
4394
|
+
});
|
|
4395
|
+
});
|
|
4396
|
+
}
|
|
4268
4397
|
function createAutoUpdateRoutes(options = {}) {
|
|
4269
4398
|
const router = Router9();
|
|
4270
|
-
router.get("/check", async (
|
|
4399
|
+
router.get("/check", async (req, res) => {
|
|
4271
4400
|
const isService = isRunningAsService();
|
|
4401
|
+
const isDev = isDevMode();
|
|
4272
4402
|
const current = VERSION;
|
|
4403
|
+
const forceRefresh = req.query["force"] === "true";
|
|
4404
|
+
if (!forceRefresh && versionCache.data && Date.now() - versionCache.timestamp < CACHE_TTL_MS) {
|
|
4405
|
+
res.json({ ...versionCache.data, isService });
|
|
4406
|
+
return;
|
|
4407
|
+
}
|
|
4273
4408
|
try {
|
|
4274
|
-
const latest = await new Promise((resolve8, reject) => {
|
|
4409
|
+
const latest = isDev ? await getLatestDevelopVersion() : await new Promise((resolve8, reject) => {
|
|
4275
4410
|
const win = process.platform === "win32";
|
|
4276
4411
|
const child = spawn2(win ? "npm view openfox version" : "npm", win ? [] : ["view", "openfox", "version"], {
|
|
4277
4412
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -4295,9 +4430,15 @@ function createAutoUpdateRoutes(options = {}) {
|
|
|
4295
4430
|
reject(new Error("npm view timed out"));
|
|
4296
4431
|
}, 1e4);
|
|
4297
4432
|
});
|
|
4298
|
-
const
|
|
4433
|
+
const currentVersion = isDev ? current.replace(/-dev$/, "") : current;
|
|
4434
|
+
const latestVersion = latest.replace(/^v/, "");
|
|
4435
|
+
const isUpdateAvailable = currentVersion !== latestVersion;
|
|
4436
|
+
const now = Date.now();
|
|
4437
|
+
versionCache.data = { current, latest, isUpdateAvailable, isService };
|
|
4438
|
+
versionCache.timestamp = now;
|
|
4299
4439
|
res.json({ current, latest, isUpdateAvailable, isService });
|
|
4300
|
-
} catch {
|
|
4440
|
+
} catch (err) {
|
|
4441
|
+
logger.error("[auto-update] Error in version check", { error: err instanceof Error ? err.message : String(err) });
|
|
4301
4442
|
res.json({ current, latest: current, isUpdateAvailable: false, isService });
|
|
4302
4443
|
}
|
|
4303
4444
|
});
|
|
@@ -4889,7 +5030,7 @@ async function createServerHandle(config3) {
|
|
|
4889
5030
|
setMcpTools(mcpTools);
|
|
4890
5031
|
logger.info("MCP tools registered", { count: mcpTools.length });
|
|
4891
5032
|
}
|
|
4892
|
-
const { signalMcpReady } = await import("./server-
|
|
5033
|
+
const { signalMcpReady } = await import("./server-T2YP3VT2.js");
|
|
4893
5034
|
signalMcpReady();
|
|
4894
5035
|
});
|
|
4895
5036
|
const app = express();
|
|
@@ -5050,7 +5191,7 @@ async function createServerHandle(config3) {
|
|
|
5050
5191
|
const { getProject: getProject2 } = await import("./projects-LHRNCUGW.js");
|
|
5051
5192
|
const project = getProject2(req.params.id);
|
|
5052
5193
|
if (!project) return res.status(404).json({ error: "Project not found" });
|
|
5053
|
-
const { listBranches } = await import("./workspace-
|
|
5194
|
+
const { listBranches } = await import("./workspace-6QTTUMMW.js");
|
|
5054
5195
|
const branches = await listBranches(project.workdir);
|
|
5055
5196
|
res.json({ branches });
|
|
5056
5197
|
});
|
|
@@ -5060,7 +5201,7 @@ async function createServerHandle(config3) {
|
|
|
5060
5201
|
if (!project) return res.status(404).json({ error: "Project not found" });
|
|
5061
5202
|
const { branch } = req.body;
|
|
5062
5203
|
if (!branch || typeof branch !== "string") return res.status(400).json({ error: "branch is required" });
|
|
5063
|
-
const { checkoutBranch } = await import("./workspace-
|
|
5204
|
+
const { checkoutBranch } = await import("./workspace-6QTTUMMW.js");
|
|
5064
5205
|
try {
|
|
5065
5206
|
await checkoutBranch(project.workdir, branch);
|
|
5066
5207
|
res.json({ branch });
|
|
@@ -5074,7 +5215,7 @@ async function createServerHandle(config3) {
|
|
|
5074
5215
|
if (!project) return res.status(404).json({ error: "Project not found" });
|
|
5075
5216
|
const { name } = req.body;
|
|
5076
5217
|
if (!name || typeof name !== "string") return res.status(400).json({ error: "name is required" });
|
|
5077
|
-
const { createBranch } = await import("./workspace-
|
|
5218
|
+
const { createBranch } = await import("./workspace-6QTTUMMW.js");
|
|
5078
5219
|
try {
|
|
5079
5220
|
await createBranch(project.workdir, name);
|
|
5080
5221
|
res.json({ branch: name });
|
|
@@ -5082,11 +5223,49 @@ async function createServerHandle(config3) {
|
|
|
5082
5223
|
res.status(400).json({ error: err instanceof Error ? err.message : "Failed to create branch" });
|
|
5083
5224
|
}
|
|
5084
5225
|
});
|
|
5226
|
+
app.get("/api/sessions/:id/branches", async (req, res) => {
|
|
5227
|
+
const session = sessionManager.getSession(req.params.id);
|
|
5228
|
+
if (!session) return res.status(404).json({ error: "Session not found" });
|
|
5229
|
+
const effectiveWorkdir = session.workspace ?? session.workdir;
|
|
5230
|
+
const { listBranches } = await import("./workspace-6QTTUMMW.js");
|
|
5231
|
+
const branches = await listBranches(effectiveWorkdir);
|
|
5232
|
+
res.json({ branches });
|
|
5233
|
+
});
|
|
5234
|
+
app.post("/api/sessions/:id/checkout", async (req, res) => {
|
|
5235
|
+
const session = sessionManager.getSession(req.params.id);
|
|
5236
|
+
if (!session) return res.status(404).json({ error: "Session not found" });
|
|
5237
|
+
const { branch } = req.body;
|
|
5238
|
+
if (!branch || typeof branch !== "string") return res.status(400).json({ error: "branch is required" });
|
|
5239
|
+
const effectiveWorkdir = session.workspace ?? session.workdir;
|
|
5240
|
+
const { checkoutBranch, validateRef } = await import("./workspace-6QTTUMMW.js");
|
|
5241
|
+
try {
|
|
5242
|
+
await validateRef(effectiveWorkdir, branch);
|
|
5243
|
+
await checkoutBranch(effectiveWorkdir, branch);
|
|
5244
|
+
res.json({ branch });
|
|
5245
|
+
} catch (err) {
|
|
5246
|
+
res.status(400).json({ error: err instanceof Error ? err.message : "Failed to checkout branch" });
|
|
5247
|
+
}
|
|
5248
|
+
});
|
|
5249
|
+
app.post("/api/sessions/:id/checkout-new", async (req, res) => {
|
|
5250
|
+
const session = sessionManager.getSession(req.params.id);
|
|
5251
|
+
if (!session) return res.status(404).json({ error: "Session not found" });
|
|
5252
|
+
const { name } = req.body;
|
|
5253
|
+
if (!name || typeof name !== "string") return res.status(400).json({ error: "name is required" });
|
|
5254
|
+
const effectiveWorkdir = session.workspace ?? session.workdir;
|
|
5255
|
+
const { createBranch, validateRef } = await import("./workspace-6QTTUMMW.js");
|
|
5256
|
+
try {
|
|
5257
|
+
await validateRef(effectiveWorkdir, name);
|
|
5258
|
+
await createBranch(effectiveWorkdir, name);
|
|
5259
|
+
res.json({ branch: name });
|
|
5260
|
+
} catch (err) {
|
|
5261
|
+
res.status(400).json({ error: err instanceof Error ? err.message : "Failed to create branch" });
|
|
5262
|
+
}
|
|
5263
|
+
});
|
|
5085
5264
|
app.get("/api/projects/:id/workspaces", async (req, res) => {
|
|
5086
5265
|
const { getProject: getProject2 } = await import("./projects-LHRNCUGW.js");
|
|
5087
5266
|
const project = getProject2(req.params.id);
|
|
5088
5267
|
if (!project) return res.status(404).json({ error: "Project not found" });
|
|
5089
|
-
const { listWorkspaces } = await import("./workspace-
|
|
5268
|
+
const { listWorkspaces } = await import("./workspace-6QTTUMMW.js");
|
|
5090
5269
|
const all = await listWorkspaces(project.name);
|
|
5091
5270
|
const workspacesList = all.filter((ws) => ws.path !== project.workdir);
|
|
5092
5271
|
res.json({ workspaces: workspacesList });
|
|
@@ -5151,7 +5330,7 @@ async function createServerHandle(config3) {
|
|
|
5151
5330
|
app.get("/api/sessions/:id", async (req, res) => {
|
|
5152
5331
|
const { getEventStore: getEventStore2 } = await import("./events-AEQ6GQXI.js");
|
|
5153
5332
|
const { buildMessagesFromStoredEvents } = await import("./folding-ONH3D4OK.js");
|
|
5154
|
-
const { getPendingQuestionsForSession } = await import("./tools-
|
|
5333
|
+
const { getPendingQuestionsForSession } = await import("./tools-APW7MY4E.js");
|
|
5155
5334
|
const session = sessionManager.getSession(req.params.id);
|
|
5156
5335
|
if (!session) {
|
|
5157
5336
|
return res.status(404).json({ error: "Session not found" });
|
|
@@ -5170,8 +5349,8 @@ async function createServerHandle(config3) {
|
|
|
5170
5349
|
if (!session) {
|
|
5171
5350
|
return res.status(404).json({ error: "Session not found" });
|
|
5172
5351
|
}
|
|
5173
|
-
const { stopSessionExecution } = await import("./chat-handler-
|
|
5174
|
-
const { cancelQuestionsForSession, cancelPathConfirmationsForSession } = await import("./tools-
|
|
5352
|
+
const { stopSessionExecution } = await import("./chat-handler-ETKFIHUO.js");
|
|
5353
|
+
const { cancelQuestionsForSession, cancelPathConfirmationsForSession } = await import("./tools-APW7MY4E.js");
|
|
5175
5354
|
sessionManager.clearMessageQueue(sessionId);
|
|
5176
5355
|
stopSessionExecution(sessionId, sessionManager);
|
|
5177
5356
|
abortSession(sessionId);
|
|
@@ -5359,7 +5538,7 @@ async function createServerHandle(config3) {
|
|
|
5359
5538
|
if (!callId || approved === void 0) {
|
|
5360
5539
|
return res.status(400).json({ error: "callId and approved are required" });
|
|
5361
5540
|
}
|
|
5362
|
-
const { providePathConfirmation } = await import("./tools-
|
|
5541
|
+
const { providePathConfirmation } = await import("./tools-APW7MY4E.js");
|
|
5363
5542
|
const result = providePathConfirmation(callId, approved, alwaysAllow);
|
|
5364
5543
|
if (!result.found) {
|
|
5365
5544
|
return res.status(404).json({ error: "No pending path confirmation with that ID" });
|
|
@@ -5367,7 +5546,7 @@ async function createServerHandle(config3) {
|
|
|
5367
5546
|
const { getEventStore: getEventStore2 } = await import("./events-AEQ6GQXI.js");
|
|
5368
5547
|
const { buildMessagesFromStoredEvents, foldPendingConfirmations } = await import("./folding-ONH3D4OK.js");
|
|
5369
5548
|
const { createSessionStateMessage } = await import("./protocol-4QFU7WAI.js");
|
|
5370
|
-
const { getPendingQuestionsForSession } = await import("./tools-
|
|
5549
|
+
const { getPendingQuestionsForSession } = await import("./tools-APW7MY4E.js");
|
|
5371
5550
|
const eventStore = getEventStore2();
|
|
5372
5551
|
const events = eventStore.getEvents(sessionId);
|
|
5373
5552
|
const messages = buildMessagesFromStoredEvents(events);
|
|
@@ -5388,7 +5567,7 @@ async function createServerHandle(config3) {
|
|
|
5388
5567
|
if (!skip && typeof answer !== "string") {
|
|
5389
5568
|
return res.status(400).json({ error: "answer is required when not skipping" });
|
|
5390
5569
|
}
|
|
5391
|
-
const { provideAnswer } = await import("./tools-
|
|
5570
|
+
const { provideAnswer } = await import("./tools-APW7MY4E.js");
|
|
5392
5571
|
const found = provideAnswer(callId, answer ?? "", skip ?? false);
|
|
5393
5572
|
if (!found) {
|
|
5394
5573
|
return res.status(404).json({ error: "No pending question with that ID" });
|
|
@@ -5448,7 +5627,7 @@ async function createServerHandle(config3) {
|
|
|
5448
5627
|
backend: activeProvider?.backend ?? llmClient.getBackend(),
|
|
5449
5628
|
model: llmClient.getModel()
|
|
5450
5629
|
};
|
|
5451
|
-
const { runAgentTurn, TurnMetrics } = await import("./orchestrator-
|
|
5630
|
+
const { runAgentTurn, TurnMetrics } = await import("./orchestrator-O2YAAZ3U.js");
|
|
5452
5631
|
runAgentTurn(
|
|
5453
5632
|
{
|
|
5454
5633
|
sessionManager,
|
|
@@ -5486,8 +5665,8 @@ async function createServerHandle(config3) {
|
|
|
5486
5665
|
if (!session) {
|
|
5487
5666
|
return res.status(404).json({ error: "Session not found" });
|
|
5488
5667
|
}
|
|
5489
|
-
const { stopSessionExecution } = await import("./chat-handler-
|
|
5490
|
-
const { cancelQuestionsForSession, cancelPathConfirmationsForSession } = await import("./tools-
|
|
5668
|
+
const { stopSessionExecution } = await import("./chat-handler-ETKFIHUO.js");
|
|
5669
|
+
const { cancelQuestionsForSession, cancelPathConfirmationsForSession } = await import("./tools-APW7MY4E.js");
|
|
5491
5670
|
const queuedMessages = sessionManager.getQueueState(sessionId);
|
|
5492
5671
|
sessionManager.clearMessageQueue(sessionId);
|
|
5493
5672
|
stopSessionExecution(sessionId, sessionManager);
|
|
@@ -5518,10 +5697,13 @@ async function createServerHandle(config3) {
|
|
|
5518
5697
|
if (!session) {
|
|
5519
5698
|
return res.status(404).json({ error: "Session not found" });
|
|
5520
5699
|
}
|
|
5521
|
-
const { messageId } = req.body;
|
|
5700
|
+
const { messageId, content } = req.body;
|
|
5522
5701
|
if (typeof messageId !== "string" || !messageId) {
|
|
5523
5702
|
return res.status(400).json({ error: "messageId is required" });
|
|
5524
5703
|
}
|
|
5704
|
+
if (content !== void 0 && (typeof content !== "string" || !content.trim())) {
|
|
5705
|
+
return res.status(400).json({ error: "content must be a non-empty string if provided" });
|
|
5706
|
+
}
|
|
5525
5707
|
const { getEventStore: getEventStore2 } = await import("./events-AEQ6GQXI.js");
|
|
5526
5708
|
const { buildMessagesFromStoredEvents } = await import("./folding-ONH3D4OK.js");
|
|
5527
5709
|
const eventStore = getEventStore2();
|
|
@@ -5537,7 +5719,7 @@ async function createServerHandle(config3) {
|
|
|
5537
5719
|
}
|
|
5538
5720
|
const { truncateSessionMessages } = await import("./events-AEQ6GQXI.js");
|
|
5539
5721
|
truncateSessionMessages(sessionId, msgIndex - 1);
|
|
5540
|
-
sessionManager.queueMessage(sessionId, "asap", msg.content, msg.attachments, msg.messageKind);
|
|
5722
|
+
sessionManager.queueMessage(sessionId, "asap", content ?? msg.content, msg.attachments, msg.messageKind);
|
|
5541
5723
|
res.json({ success: true });
|
|
5542
5724
|
});
|
|
5543
5725
|
app.post("/api/sessions/:id/chat", async (req, res) => {
|
|
@@ -6110,7 +6292,7 @@ async function createServerHandle(config3) {
|
|
|
6110
6292
|
});
|
|
6111
6293
|
async function rebuildMcpTools() {
|
|
6112
6294
|
const { createMcpTools: createMcpTools2 } = await import("./tool-adapter-MOGEI6TP.js");
|
|
6113
|
-
const { setMcpTools: setMcpTools2 } = await import("./tools-
|
|
6295
|
+
const { setMcpTools: setMcpTools2 } = await import("./tools-APW7MY4E.js");
|
|
6114
6296
|
const mcpTools = createMcpTools2(mcpManager);
|
|
6115
6297
|
setMcpTools2(mcpTools);
|
|
6116
6298
|
}
|
|
@@ -6494,7 +6676,7 @@ async function createServerHandle(config3) {
|
|
|
6494
6676
|
const state = sessionManager.getContextState(sessionId);
|
|
6495
6677
|
wssExports.broadcastForSession(sessionId, createContextStateMessage(state));
|
|
6496
6678
|
});
|
|
6497
|
-
const { QueueProcessor } = await import("./processor-
|
|
6679
|
+
const { QueueProcessor } = await import("./processor-FKAS3K4L.js");
|
|
6498
6680
|
const queueProcessor = new QueueProcessor({
|
|
6499
6681
|
sessionManager,
|
|
6500
6682
|
providerManager,
|
|
@@ -6574,4 +6756,4 @@ export {
|
|
|
6574
6756
|
createServerHandle,
|
|
6575
6757
|
createServer
|
|
6576
6758
|
};
|
|
6577
|
-
//# sourceMappingURL=chunk-
|
|
6759
|
+
//# sourceMappingURL=chunk-QFR6JF32.js.map
|