openfox 2.0.76 → 2.0.78
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-3BZ4PDL2.js → chat-handler-5ZHPYU24.js} +21 -20
- package/dist/{chunk-MF3UW36X.js → chunk-37WF2Z3T.js} +84 -17
- package/dist/{chunk-OBQPXUXI.js → chunk-5CQRB7AD.js} +2 -2
- package/dist/chunk-64TKWWNF.js +7 -0
- package/dist/{chunk-LXFLRM7M.js → chunk-6AE3JPDJ.js} +2 -2
- package/dist/chunk-AANVMTYU.js +327 -0
- package/dist/{chunk-YMFCFMMB.js → chunk-AFJLY43Z.js} +8 -3
- package/dist/{chunk-OCVRIPQP.js → chunk-CJDYSUU5.js} +3 -3
- package/dist/{chunk-OMWVB2XC.js → chunk-DI4SIPFT.js} +46 -27
- package/dist/{chunk-7772ENZN.js → chunk-EHVDAVYG.js} +4 -3
- package/dist/{chunk-DH3SSBZN.js → chunk-EYIWUONA.js} +2 -2
- package/dist/{chunk-NGJ5XJ7D.js → chunk-M7EFXRDS.js} +57 -290
- package/dist/{chunk-4QHDQP2N.js → chunk-MTUYDBSL.js} +2 -2
- package/dist/{chunk-HHUIXHHX.js → chunk-NUR2B4RU.js} +7 -7
- package/dist/{chunk-46RORSKU.js → chunk-NZIYELSQ.js} +9 -7
- package/dist/{chunk-7QXRQ5ZL.js → chunk-RGUUZD5B.js} +5 -1
- package/dist/{chunk-EZK7CGJ7.js → chunk-RMXPVQP4.js} +315 -45
- package/dist/{chunk-D6CI2B7B.js → chunk-SGBXBP3S.js} +253 -110
- package/dist/{chunk-O3NUNU4H.js → chunk-SJTG56CH.js} +5 -4
- package/dist/{chunk-DJASQ2ZB.js → chunk-TSVFRWSG.js} +24 -5
- package/dist/{chunk-XTK6E2QR.js → chunk-UIU7OGHP.js} +26 -10
- package/dist/{chunk-J7VCI5EX.js → chunk-UMX7MMNW.js} +652 -248
- package/dist/{chunk-HLHGNHMV.js → chunk-VGWJFXPR.js} +23 -11
- package/dist/{chunk-KVRSAC4Z.js → chunk-VPFUXGMM.js} +6 -1
- package/dist/{chunk-W4ZEG3LX.js → chunk-WL2WEJAK.js} +2 -2
- package/dist/{chunk-HAQV6AJP.js → chunk-WUSWNLTV.js} +3 -3
- package/dist/{chunk-5GOOSZX7.js → chunk-X6BXZFO7.js} +1 -1
- package/dist/{chunk-WGAAQASA.js → chunk-YFVSSMA3.js} +3 -2
- package/dist/cli/dev.js +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/{client-TDPQVBQ7.js → client-V5DZRO2D.js} +3 -3
- package/dist/{client-pure-NMLDKRDN.js → client-pure-5YE5WFJP.js} +2 -2
- package/dist/compactor-G7B3V24F.js +24 -0
- package/dist/{config-EUMVEFHU.js → config-MD74ETY5.js} +2 -2
- package/dist/{events-FLWRLM6V.js → events-KNOZX7YG.js} +7 -4
- package/dist/{folding-ONH3D4OK.js → folding-OPP2BVUB.js} +2 -2
- package/dist/{inspect-proxy-JHZV34QR.js → inspect-proxy-DRYIIH4O.js} +4 -4
- package/dist/{manager-OPMCSYN2.js → manager-ATWZUL3O.js} +5 -5
- package/dist/{orchestrator-5IMCWX5P.js → orchestrator-L6LX5BV7.js} +20 -19
- package/dist/package.json +6 -1
- package/dist/{path-security-ZROWNL22.js → path-security-HUXQHEQ5.js} +10 -7
- package/dist/{platform-QGXO3CNR.js → platform-VBNNMTR5.js} +4 -4
- package/dist/{processor-3R4GS6VB.js → processor-UQX5KL56.js} +21 -20
- package/dist/{project-creator-C22J43BC.js → project-creator-NNUITNUI.js} +3 -3
- package/dist/{projects-WSVINK2C.js → projects-ZGJGICGT.js} +3 -3
- package/dist/{protocol-Sr6Jr4ZS.d.ts → protocol-BXxJmsOW.d.ts} +2 -1
- package/dist/{protocol-EWEVW65B.js → protocol-Q7X4NEME.js} +3 -3
- package/dist/provider/index.d.ts +4 -4
- package/dist/{provider-G2YC2IC4.js → provider-PI3RDDE4.js} +6 -6
- package/dist/{provider-manager-SQIELYLK.js → provider-manager-PD3BXUHY.js} +4 -4
- package/dist/{serve-MXKMKZYY.js → serve-QWC3U5MB.js} +26 -25
- package/dist/server/index.d.ts +27 -4
- package/dist/server/index.js +25 -24
- package/dist/server-3XUD2NB7.js +40 -0
- package/dist/sessions-SFG42M4W.js +42 -0
- package/dist/{settings-7XDMSPIC.js → settings-6M55N4Q2.js} +5 -3
- package/dist/shared/index.d.ts +3 -3
- package/dist/shared/index.js +1 -1
- package/dist/{tools-JRCUWPJO.js → tools-HGKUD327.js} +26 -23
- package/dist/{types-C4cG9CtC.d.ts → types-C308SU4B.d.ts} +3 -0
- package/dist/{types-DSZhFA8O.d.ts → types-o07LJcLI.d.ts} +1 -1
- package/dist/{update-OXDQ75M7.js → update-NWZALB5M.js} +2 -2
- package/dist/{update-server-4MTM7M5P.js → update-server-V6GJ43WH.js} +2 -2
- package/dist/web/assets/index-7_xKqeJc.js +305 -0
- package/dist/web/assets/index-DRkTjPo3.css +32 -0
- package/dist/web/index.html +4 -4
- package/dist/web/manifest.webmanifest +1 -1
- package/dist/web/registerSW.js +1 -1
- package/dist/web/sw.js +1 -1
- package/dist/{workspace-6QTTUMMW.js → workspace-J74ZMSOJ.js} +14 -2
- package/package.json +6 -1
- package/dist/chunk-KQEVAO2Q.js +0 -7
- package/dist/compactor-BB3YYVRP.js +0 -23
- package/dist/server-SPYFMFQE.js +0 -39
- package/dist/web/assets/index-BNVBxKnB.css +0 -32
- package/dist/web/assets/index-ghDkIdlf.js +0 -305
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
tokenFromPassword,
|
|
22
22
|
verifyPassword,
|
|
23
23
|
workflowExists
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-DI4SIPFT.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-SGBXBP3S.js";
|
|
70
70
|
import {
|
|
71
71
|
createMcpTools
|
|
72
72
|
} from "./chunk-NWO6GRYE.js";
|
|
@@ -74,14 +74,18 @@ import {
|
|
|
74
74
|
deleteWorkspace,
|
|
75
75
|
ensureWorkspace,
|
|
76
76
|
getCommitsBehind,
|
|
77
|
+
getDefaultBranch,
|
|
77
78
|
getGitBranch,
|
|
79
|
+
getGlobalDataDir,
|
|
78
80
|
getWorkspacesDir,
|
|
79
81
|
loadWorkspaceConfig,
|
|
82
|
+
resolveAndValidateSourceBranch,
|
|
80
83
|
runGit,
|
|
81
84
|
saveWorkspaceConfig,
|
|
85
|
+
validateRef,
|
|
82
86
|
validateWorkspaceName,
|
|
83
87
|
workspaceExists
|
|
84
|
-
} from "./chunk-
|
|
88
|
+
} from "./chunk-37WF2Z3T.js";
|
|
85
89
|
import {
|
|
86
90
|
EventEmitter
|
|
87
91
|
} from "./chunk-EU3WWTFH.js";
|
|
@@ -89,25 +93,23 @@ import {
|
|
|
89
93
|
ALWAYS_ALLOWED,
|
|
90
94
|
ALWAYS_ALLOWED_FOR_SUBAGENTS,
|
|
91
95
|
TOP_LEVEL_ONLY_TOOLS
|
|
92
|
-
} from "./chunk-
|
|
93
|
-
import {
|
|
94
|
-
getProject
|
|
95
|
-
} from "./chunk-LXFLRM7M.js";
|
|
96
|
+
} from "./chunk-EHVDAVYG.js";
|
|
96
97
|
import {
|
|
97
98
|
getPathSeparator,
|
|
98
99
|
isAbsolutePath
|
|
99
|
-
} from "./chunk-
|
|
100
|
+
} from "./chunk-MTUYDBSL.js";
|
|
100
101
|
import {
|
|
101
102
|
deleteSetting,
|
|
102
103
|
getSetting,
|
|
103
104
|
setSetting
|
|
104
|
-
} from "./chunk-
|
|
105
|
+
} from "./chunk-AFJLY43Z.js";
|
|
106
|
+
import {
|
|
107
|
+
getProject
|
|
108
|
+
} from "./chunk-6AE3JPDJ.js";
|
|
105
109
|
import {
|
|
106
110
|
VERSION
|
|
107
|
-
} from "./chunk-
|
|
111
|
+
} from "./chunk-64TKWWNF.js";
|
|
108
112
|
import {
|
|
109
|
-
createSession,
|
|
110
|
-
deleteSession,
|
|
111
113
|
emitAssistantMessageStart,
|
|
112
114
|
emitContextState,
|
|
113
115
|
emitCriteriaSet,
|
|
@@ -119,32 +121,37 @@ import {
|
|
|
119
121
|
emitSessionInitialized,
|
|
120
122
|
emitUserMessage,
|
|
121
123
|
getEventStore,
|
|
122
|
-
getSession,
|
|
123
|
-
getSessionCachedPrompt,
|
|
124
124
|
getSessionState,
|
|
125
125
|
initEventStore,
|
|
126
|
+
setRuntimeConfig
|
|
127
|
+
} from "./chunk-M7EFXRDS.js";
|
|
128
|
+
import {
|
|
129
|
+
createSession,
|
|
130
|
+
deleteSession,
|
|
131
|
+
getSession,
|
|
132
|
+
getSessionCachedPrompt,
|
|
126
133
|
listSessions,
|
|
127
134
|
listSessionsByProject,
|
|
128
|
-
|
|
135
|
+
updateSessionBranch,
|
|
129
136
|
updateSessionCachedPrompt,
|
|
130
137
|
updateSessionDangerLevel,
|
|
131
138
|
updateSessionMetadata,
|
|
132
139
|
updateSessionProvider,
|
|
133
140
|
updateSessionRunning,
|
|
134
141
|
updateSessionWorkdir
|
|
135
|
-
} from "./chunk-
|
|
142
|
+
} from "./chunk-AANVMTYU.js";
|
|
136
143
|
import {
|
|
137
144
|
initDatabase
|
|
138
|
-
} from "./chunk-
|
|
145
|
+
} from "./chunk-RGUUZD5B.js";
|
|
139
146
|
import {
|
|
140
147
|
createContextStateMessage
|
|
141
|
-
} from "./chunk-
|
|
148
|
+
} from "./chunk-SJTG56CH.js";
|
|
142
149
|
import {
|
|
143
150
|
createProviderManager,
|
|
144
151
|
detectModel,
|
|
145
152
|
getLlmStatus,
|
|
146
153
|
parseDefaultModelSelection
|
|
147
|
-
} from "./chunk-
|
|
154
|
+
} from "./chunk-CJDYSUU5.js";
|
|
148
155
|
import {
|
|
149
156
|
getModelProfile
|
|
150
157
|
} from "./chunk-V4IE7HJY.js";
|
|
@@ -163,7 +170,7 @@ import {
|
|
|
163
170
|
} from "./chunk-K44MW7JJ.js";
|
|
164
171
|
import {
|
|
165
172
|
createServerMessage
|
|
166
|
-
} from "./chunk-
|
|
173
|
+
} from "./chunk-X6BXZFO7.js";
|
|
167
174
|
import {
|
|
168
175
|
getGlobalConfigDir
|
|
169
176
|
} from "./chunk-CQGTEGKL.js";
|
|
@@ -173,7 +180,7 @@ import express from "express";
|
|
|
173
180
|
import cors from "cors";
|
|
174
181
|
import { createServer as createHttpServer } from "http";
|
|
175
182
|
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
176
|
-
import { dirname as dirname8, resolve as
|
|
183
|
+
import { dirname as dirname8, resolve as resolve8, join as join10 } from "path";
|
|
177
184
|
import { readFile as readFile4 } from "fs/promises";
|
|
178
185
|
import { createServer as createViteServer } from "vite";
|
|
179
186
|
|
|
@@ -1490,6 +1497,26 @@ var McpManager = class {
|
|
|
1490
1497
|
throw new Error(`Unsupported transport: ${entry.config.transport}`);
|
|
1491
1498
|
}
|
|
1492
1499
|
if (!transport) throw new Error("Failed to create transport");
|
|
1500
|
+
let sdkOnMessage = void 0;
|
|
1501
|
+
Object.defineProperty(transport, "onmessage", {
|
|
1502
|
+
get() {
|
|
1503
|
+
return sdkOnMessage;
|
|
1504
|
+
},
|
|
1505
|
+
set(fn) {
|
|
1506
|
+
sdkOnMessage = (message) => {
|
|
1507
|
+
const msg = message;
|
|
1508
|
+
if (msg && msg.result && Array.isArray(msg.result.tools)) {
|
|
1509
|
+
for (const tool of msg.result.tools) {
|
|
1510
|
+
if (tool && tool.outputSchema) {
|
|
1511
|
+
delete tool.outputSchema;
|
|
1512
|
+
}
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1515
|
+
fn?.(message);
|
|
1516
|
+
};
|
|
1517
|
+
},
|
|
1518
|
+
configurable: true
|
|
1519
|
+
});
|
|
1493
1520
|
await client.connect(transport);
|
|
1494
1521
|
const { tools: mcpTools } = await client.listTools();
|
|
1495
1522
|
const disabledSet = new Set(entry.config.disabledTools ?? []);
|
|
@@ -1585,7 +1612,27 @@ var McpManager = class {
|
|
|
1585
1612
|
if (!entry) return { success: false, error: `MCP server '${serverName}' not found` };
|
|
1586
1613
|
if (!entry.client) return { success: false, error: `MCP server '${serverName}' is not connected` };
|
|
1587
1614
|
try {
|
|
1588
|
-
const
|
|
1615
|
+
const timeout = entry.config.timeout;
|
|
1616
|
+
const requestOptions = timeout !== void 0 && timeout > 0 ? { timeout: timeout * 1e3 } : void 0;
|
|
1617
|
+
let result;
|
|
1618
|
+
if (timeout !== void 0 && timeout > 0) {
|
|
1619
|
+
let timer;
|
|
1620
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
1621
|
+
timer = setTimeout(() => {
|
|
1622
|
+
reject(new Error(`MCP tool call timed out after ${timeout} seconds`));
|
|
1623
|
+
}, timeout * 1e3);
|
|
1624
|
+
});
|
|
1625
|
+
try {
|
|
1626
|
+
result = await Promise.race([
|
|
1627
|
+
entry.client.callTool({ name: toolName, arguments: args }, void 0, requestOptions),
|
|
1628
|
+
timeoutPromise
|
|
1629
|
+
]);
|
|
1630
|
+
} finally {
|
|
1631
|
+
if (timer) clearTimeout(timer);
|
|
1632
|
+
}
|
|
1633
|
+
} else {
|
|
1634
|
+
result = await entry.client.callTool({ name: toolName, arguments: args });
|
|
1635
|
+
}
|
|
1589
1636
|
const content = result.content;
|
|
1590
1637
|
const textParts = content.filter((c) => c.type === "text").map((c) => c.text);
|
|
1591
1638
|
return { success: !result.isError, output: textParts.join("\n") };
|
|
@@ -1731,8 +1778,8 @@ var LspServer = class {
|
|
|
1731
1778
|
windowsHide: true,
|
|
1732
1779
|
shell: needsShell
|
|
1733
1780
|
});
|
|
1734
|
-
await new Promise((
|
|
1735
|
-
this.process.once("spawn",
|
|
1781
|
+
await new Promise((resolve9, reject) => {
|
|
1782
|
+
this.process.once("spawn", resolve9);
|
|
1736
1783
|
this.process.once("error", reject);
|
|
1737
1784
|
});
|
|
1738
1785
|
if (!this.process.stdin || !this.process.stdout) {
|
|
@@ -1952,19 +1999,19 @@ var LspServer = class {
|
|
|
1952
1999
|
*/
|
|
1953
2000
|
async getDiagnosticsWithWait(path, timeoutMs = DIAGNOSTIC_WAIT_MS) {
|
|
1954
2001
|
if (this.openDocuments.has(path)) {
|
|
1955
|
-
return new Promise((
|
|
2002
|
+
return new Promise((resolve9) => {
|
|
1956
2003
|
const existing = this.diagnostics.get(path);
|
|
1957
2004
|
if (existing !== void 0) {
|
|
1958
2005
|
setTimeout(() => {
|
|
1959
|
-
|
|
2006
|
+
resolve9(this.diagnostics.get(path) ?? []);
|
|
1960
2007
|
}, 100);
|
|
1961
2008
|
return;
|
|
1962
2009
|
}
|
|
1963
2010
|
const timeout = setTimeout(() => {
|
|
1964
2011
|
this.pendingDiagnostics.delete(path);
|
|
1965
|
-
|
|
2012
|
+
resolve9(this.diagnostics.get(path) ?? []);
|
|
1966
2013
|
}, timeoutMs);
|
|
1967
|
-
this.pendingDiagnostics.set(path, { resolve:
|
|
2014
|
+
this.pendingDiagnostics.set(path, { resolve: resolve9, timeout });
|
|
1968
2015
|
});
|
|
1969
2016
|
}
|
|
1970
2017
|
return this.diagnostics.get(path) ?? [];
|
|
@@ -2583,6 +2630,35 @@ var SessionManager = class {
|
|
|
2583
2630
|
getCurrentModelContext() {
|
|
2584
2631
|
return this.providerManager.getCurrentModelContext();
|
|
2585
2632
|
}
|
|
2633
|
+
/**
|
|
2634
|
+
* Get the effective working directory for a session.
|
|
2635
|
+
* Uses workspace path when active, otherwise the project workdir.
|
|
2636
|
+
*/
|
|
2637
|
+
getEffectiveWorkdir(sessionId) {
|
|
2638
|
+
const session = this.requireSession(sessionId);
|
|
2639
|
+
return session.workspace ?? session.workdir;
|
|
2640
|
+
}
|
|
2641
|
+
/**
|
|
2642
|
+
* Return (effectiveWorkdir, actualBranch) for a session.
|
|
2643
|
+
*/
|
|
2644
|
+
async getActualBranchPair(sessionId) {
|
|
2645
|
+
const effectiveWorkdir = this.getEffectiveWorkdir(sessionId);
|
|
2646
|
+
const branch = await getGitBranch(effectiveWorkdir);
|
|
2647
|
+
return { workdir: effectiveWorkdir, branch };
|
|
2648
|
+
}
|
|
2649
|
+
/**
|
|
2650
|
+
* Check that the session's persisted branch matches the actual branch on disk.
|
|
2651
|
+
* If they differ (and persisted branch exists), returns a warning message.
|
|
2652
|
+
*/
|
|
2653
|
+
async checkBranchConsistency(sessionId) {
|
|
2654
|
+
const session = this.getSession(sessionId);
|
|
2655
|
+
if (!session?.branch) return null;
|
|
2656
|
+
const actualBranch = await getGitBranch(session.workspace ?? session.workdir);
|
|
2657
|
+
if (actualBranch && actualBranch !== session.branch) {
|
|
2658
|
+
return `Branch mismatch: session expects "${session.branch}" but workspace is on "${actualBranch}". The workspace branch was changed externally.`;
|
|
2659
|
+
}
|
|
2660
|
+
return null;
|
|
2661
|
+
}
|
|
2586
2662
|
// ============================================================================
|
|
2587
2663
|
// Session Lifecycle
|
|
2588
2664
|
// ============================================================================
|
|
@@ -2606,6 +2682,20 @@ var SessionManager = class {
|
|
|
2606
2682
|
const contextWindowId = crypto.randomUUID();
|
|
2607
2683
|
emitSessionInitialized(dbSession.id, projectId, effectiveWorkdir, contextWindowId, sessionTitle);
|
|
2608
2684
|
const session = this.buildSessionFromDb(dbSession);
|
|
2685
|
+
getGitBranch(effectiveWorkdir).then((branch) => {
|
|
2686
|
+
if (branch) {
|
|
2687
|
+
updateSessionBranch(session.id, branch);
|
|
2688
|
+
const updatedDb = getSession(session.id);
|
|
2689
|
+
if (updatedDb) {
|
|
2690
|
+
this.emit({ type: "session_updated", session: this.buildSessionFromDb(updatedDb) });
|
|
2691
|
+
}
|
|
2692
|
+
}
|
|
2693
|
+
}).catch((err) => {
|
|
2694
|
+
logger.error("Failed to persist initial branch for session", {
|
|
2695
|
+
sessionId: session.id,
|
|
2696
|
+
error: err instanceof Error ? err.message : String(err)
|
|
2697
|
+
});
|
|
2698
|
+
});
|
|
2609
2699
|
this.emit({ type: "session_created", session });
|
|
2610
2700
|
return session;
|
|
2611
2701
|
}
|
|
@@ -2699,6 +2789,16 @@ var SessionManager = class {
|
|
|
2699
2789
|
this.emit({ type: "session_updated", session: updatedSession });
|
|
2700
2790
|
return updatedSession;
|
|
2701
2791
|
}
|
|
2792
|
+
/**
|
|
2793
|
+
* Emit session_updated for the given session.
|
|
2794
|
+
* Used by REST handlers after updating sibling session branches.
|
|
2795
|
+
*/
|
|
2796
|
+
emitBranchChange(sessionId) {
|
|
2797
|
+
const session = this.getSession(sessionId);
|
|
2798
|
+
if (session) {
|
|
2799
|
+
this.emit({ type: "session_updated", session });
|
|
2800
|
+
}
|
|
2801
|
+
}
|
|
2702
2802
|
/**
|
|
2703
2803
|
* Change session phase. Emits phase.changed event.
|
|
2704
2804
|
*/
|
|
@@ -3209,6 +3309,24 @@ var SessionManager = class {
|
|
|
3209
3309
|
const effectiveWorkdir = session.workspace ?? session.workdir;
|
|
3210
3310
|
return getLspManager(sessionId, effectiveWorkdir);
|
|
3211
3311
|
}
|
|
3312
|
+
async applyBranchIfNeeded(projectDir, projectName, workspaceName, branch, sourceBranch) {
|
|
3313
|
+
const wsPath = resolve2(await getWorkspacesDir(projectName, projectDir), workspaceName);
|
|
3314
|
+
const currentBranch = await getGitBranch(wsPath);
|
|
3315
|
+
if (currentBranch !== branch) {
|
|
3316
|
+
try {
|
|
3317
|
+
await validateRef(wsPath, branch);
|
|
3318
|
+
await runGit(wsPath, ["checkout", branch]).catch(async () => {
|
|
3319
|
+
const sb = sourceBranch ?? await getDefaultBranch(projectDir);
|
|
3320
|
+
const validated = sourceBranch ? await resolveAndValidateSourceBranch(wsPath, sourceBranch, projectDir) : sb;
|
|
3321
|
+
await runGit(wsPath, ["checkout", "-b", branch, validated]);
|
|
3322
|
+
});
|
|
3323
|
+
} catch (err) {
|
|
3324
|
+
throw new Error(
|
|
3325
|
+
`Failed to apply branch "${branch}" to workspace "${workspaceName}": ${err instanceof Error ? err.message : String(err)}`
|
|
3326
|
+
);
|
|
3327
|
+
}
|
|
3328
|
+
}
|
|
3329
|
+
}
|
|
3212
3330
|
// ============================================================================
|
|
3213
3331
|
// Workspace Lifecycle
|
|
3214
3332
|
// ============================================================================
|
|
@@ -3218,44 +3336,55 @@ var SessionManager = class {
|
|
|
3218
3336
|
* Emits a single type of event — switching is always "opening" a workspace.
|
|
3219
3337
|
* Switches are serialized per-session to prevent race conditions.
|
|
3220
3338
|
*/
|
|
3221
|
-
async switchWorkspace(sessionId, target, branch) {
|
|
3222
|
-
if (target !== "original")
|
|
3223
|
-
validateWorkspaceName(target);
|
|
3224
|
-
}
|
|
3339
|
+
async switchWorkspace(sessionId, target, branch, sourceBranch) {
|
|
3340
|
+
if (target !== "original") validateWorkspaceName(target);
|
|
3225
3341
|
const existingLock = this.switchLocks.get(sessionId);
|
|
3226
|
-
if (existingLock)
|
|
3227
|
-
await existingLock;
|
|
3228
|
-
}
|
|
3342
|
+
if (existingLock) await existingLock;
|
|
3229
3343
|
const lockPromise = (async () => {
|
|
3230
3344
|
const session = this.requireSession(sessionId);
|
|
3231
3345
|
const project = getProject(session.projectId);
|
|
3232
3346
|
if (!project) throw new Error(`Project not found: ${session.projectId}`);
|
|
3233
|
-
|
|
3234
|
-
if (target
|
|
3347
|
+
const isBranchChangeOnly = target !== "original" && session.workspace?.split("/").pop() === target && branch !== void 0;
|
|
3348
|
+
if (target === "original" && !session.workspace && !branch) return session;
|
|
3349
|
+
if (target !== "original" && session.workspace?.split("/").pop() === target && !branch) return session;
|
|
3350
|
+
if (isBranchChangeOnly) {
|
|
3351
|
+
const currentBranch = await getGitBranch(session.workspace ?? session.workdir);
|
|
3352
|
+
if (currentBranch === branch) return session;
|
|
3353
|
+
}
|
|
3235
3354
|
const previousPath = session.workspace;
|
|
3236
|
-
if (previousPath) {
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3355
|
+
if (previousPath && !isBranchChangeOnly) {
|
|
3356
|
+
const otherSessionsUsingPath = this.listSessions().filter(
|
|
3357
|
+
(s) => s.id !== sessionId && s.workspace === previousPath
|
|
3358
|
+
);
|
|
3359
|
+
if (otherSessionsUsingPath.length === 0) {
|
|
3360
|
+
try {
|
|
3361
|
+
await devServerManager.stop(previousPath);
|
|
3362
|
+
} catch (err) {
|
|
3363
|
+
logger.error("Error stopping dev server for workspace switch", {
|
|
3364
|
+
sessionId,
|
|
3365
|
+
workspace: previousPath,
|
|
3366
|
+
error: err
|
|
3367
|
+
});
|
|
3368
|
+
}
|
|
3369
|
+
} else {
|
|
3370
|
+
logger.info("Skipping dev server stop \u2014 other sessions still use path", {
|
|
3371
|
+
path: previousPath,
|
|
3372
|
+
otherSessions: otherSessionsUsingPath.map((s) => s.id)
|
|
3244
3373
|
});
|
|
3245
3374
|
}
|
|
3246
3375
|
}
|
|
3247
3376
|
if (target === "original") {
|
|
3248
3377
|
updateSessionWorkdir(sessionId, project.workdir, null);
|
|
3249
|
-
} else {
|
|
3378
|
+
} else if (!isBranchChangeOnly) {
|
|
3250
3379
|
const createLockKey = `${project.name}:${target}`;
|
|
3251
3380
|
const existingCreateLock = this.workspaceCreationLocks.get(createLockKey);
|
|
3252
|
-
if (existingCreateLock)
|
|
3253
|
-
await existingCreateLock;
|
|
3254
|
-
}
|
|
3381
|
+
if (existingCreateLock) await existingCreateLock;
|
|
3255
3382
|
const createLockPromise = (async () => {
|
|
3256
|
-
const exists = await workspaceExists(project.name, target);
|
|
3383
|
+
const exists = await workspaceExists(project.name, target, project.workdir);
|
|
3257
3384
|
if (!exists) {
|
|
3258
|
-
await ensureWorkspace(project.workdir, target, project.name, branch);
|
|
3385
|
+
await ensureWorkspace(project.workdir, target, project.name, branch, sourceBranch);
|
|
3386
|
+
} else if (branch) {
|
|
3387
|
+
await this.applyBranchIfNeeded(project.workdir, project.name, target, branch, sourceBranch);
|
|
3259
3388
|
}
|
|
3260
3389
|
})();
|
|
3261
3390
|
this.workspaceCreationLocks.set(createLockKey, createLockPromise);
|
|
@@ -3264,16 +3393,31 @@ var SessionManager = class {
|
|
|
3264
3393
|
} finally {
|
|
3265
3394
|
this.workspaceCreationLocks.delete(createLockKey);
|
|
3266
3395
|
}
|
|
3267
|
-
const
|
|
3396
|
+
const wsDir = await getWorkspacesDir(project.name, project.workdir);
|
|
3397
|
+
const wsPath = resolve2(wsDir, target);
|
|
3268
3398
|
updateSessionWorkdir(sessionId, project.workdir, wsPath);
|
|
3399
|
+
} else {
|
|
3400
|
+
await this.applyBranchIfNeeded(project.workdir, project.name, target, branch, sourceBranch);
|
|
3269
3401
|
}
|
|
3270
3402
|
try {
|
|
3271
3403
|
await shutdownLspManager(sessionId);
|
|
3272
3404
|
} catch (err) {
|
|
3273
3405
|
logger.error("Error shutting down LSP for workspace switch", { sessionId, error: err });
|
|
3274
3406
|
}
|
|
3275
|
-
const
|
|
3407
|
+
const wsDirForBranch = await getWorkspacesDir(project.name, project.workdir);
|
|
3408
|
+
const effectiveWorkdir = target === "original" ? project.workdir : resolve2(wsDirForBranch, target);
|
|
3276
3409
|
const actualBranch = await getGitBranch(effectiveWorkdir);
|
|
3410
|
+
if (actualBranch) {
|
|
3411
|
+
updateSessionBranch(sessionId, actualBranch);
|
|
3412
|
+
const otherSessionsOnWorkspace = this.listSessions().filter(
|
|
3413
|
+
(s) => s.id !== sessionId && s.workspace === effectiveWorkdir
|
|
3414
|
+
);
|
|
3415
|
+
for (const other of otherSessionsOnWorkspace) {
|
|
3416
|
+
updateSessionBranch(other.id, actualBranch);
|
|
3417
|
+
const updated2 = this.getSession(other.id);
|
|
3418
|
+
if (updated2) this.emit({ type: "session_updated", session: updated2 });
|
|
3419
|
+
}
|
|
3420
|
+
}
|
|
3277
3421
|
let stalenessHint = "";
|
|
3278
3422
|
if (target !== "original" && actualBranch) {
|
|
3279
3423
|
await runGit(effectiveWorkdir, ["fetch", "origin", "--no-tags", "--quiet"]).catch(() => {
|
|
@@ -3310,9 +3454,7 @@ All file and git operations should use this directory.
|
|
|
3310
3454
|
})();
|
|
3311
3455
|
this.switchLocks.set(sessionId, lockPromise);
|
|
3312
3456
|
lockPromise.finally(() => {
|
|
3313
|
-
if (this.switchLocks.get(sessionId) === lockPromise)
|
|
3314
|
-
this.switchLocks.delete(sessionId);
|
|
3315
|
-
}
|
|
3457
|
+
if (this.switchLocks.get(sessionId) === lockPromise) this.switchLocks.delete(sessionId);
|
|
3316
3458
|
});
|
|
3317
3459
|
return lockPromise;
|
|
3318
3460
|
}
|
|
@@ -3340,12 +3482,13 @@ All file and git operations should use this directory.
|
|
|
3340
3482
|
if (currentWsName === target) {
|
|
3341
3483
|
await this.switchWorkspace(sessionId, "original");
|
|
3342
3484
|
}
|
|
3343
|
-
const
|
|
3485
|
+
const wsDir = await getWorkspacesDir(project.name, project.workdir);
|
|
3486
|
+
const effectivePath = resolve2(wsDir, target);
|
|
3344
3487
|
try {
|
|
3345
3488
|
await devServerManager.stop(effectivePath);
|
|
3346
3489
|
} catch {
|
|
3347
3490
|
}
|
|
3348
|
-
await deleteWorkspace(project.name, target);
|
|
3491
|
+
await deleteWorkspace(project.name, target, project.workdir);
|
|
3349
3492
|
const updated = this.requireSession(sessionId);
|
|
3350
3493
|
this.emit({ type: "session_updated", session: updated });
|
|
3351
3494
|
return updated;
|
|
@@ -4114,6 +4257,85 @@ function createDevServerRoutes() {
|
|
|
4114
4257
|
|
|
4115
4258
|
// src/server/routes/workspace-config.ts
|
|
4116
4259
|
import { Router as Router5 } from "express";
|
|
4260
|
+
import { stat as stat2, mkdir as mkdir4, readdir, access as access3 } from "fs/promises";
|
|
4261
|
+
import { constants as constants3 } from "fs";
|
|
4262
|
+
import { resolve as resolve4, isAbsolute as isAbsolute3, join as join6 } from "path";
|
|
4263
|
+
|
|
4264
|
+
// src/shared/workspace.ts
|
|
4265
|
+
var BLOCKED_EXACT_PATHS = [
|
|
4266
|
+
"/",
|
|
4267
|
+
"/etc",
|
|
4268
|
+
"/bin",
|
|
4269
|
+
"/sbin",
|
|
4270
|
+
"/lib",
|
|
4271
|
+
"/lib64",
|
|
4272
|
+
"/usr",
|
|
4273
|
+
"/var",
|
|
4274
|
+
"/opt",
|
|
4275
|
+
"/root",
|
|
4276
|
+
"/run",
|
|
4277
|
+
"/tmp",
|
|
4278
|
+
"/home",
|
|
4279
|
+
"/mnt",
|
|
4280
|
+
"/media"
|
|
4281
|
+
];
|
|
4282
|
+
var BLOCKED_VIRTUAL_FS_PREFIXES = ["/proc/", "/sys/", "/dev/", "/boot/", "/etc/", "/lost+found/"];
|
|
4283
|
+
function getRootDirBlockReason(path, exactPaths = BLOCKED_EXACT_PATHS, virtualFsPrefixes = BLOCKED_VIRTUAL_FS_PREFIXES) {
|
|
4284
|
+
if (!path) return null;
|
|
4285
|
+
const normalized = path.replace(/\/+$/, "") || "/";
|
|
4286
|
+
if (exactPaths.includes(normalized)) return "exact";
|
|
4287
|
+
for (const prefix of virtualFsPrefixes) {
|
|
4288
|
+
if (normalized.startsWith(prefix)) return "virtual_fs";
|
|
4289
|
+
}
|
|
4290
|
+
return null;
|
|
4291
|
+
}
|
|
4292
|
+
|
|
4293
|
+
// src/server/routes/workspace-config.ts
|
|
4294
|
+
async function isWritable(path) {
|
|
4295
|
+
try {
|
|
4296
|
+
await access3(path, constants3.W_OK);
|
|
4297
|
+
return true;
|
|
4298
|
+
} catch {
|
|
4299
|
+
return false;
|
|
4300
|
+
}
|
|
4301
|
+
}
|
|
4302
|
+
function resolveRootDir(rootDir, workdir) {
|
|
4303
|
+
return isAbsolute3(rootDir) ? rootDir : resolve4(workdir, rootDir);
|
|
4304
|
+
}
|
|
4305
|
+
async function checkDirExists(path) {
|
|
4306
|
+
try {
|
|
4307
|
+
const st = await stat2(path);
|
|
4308
|
+
return st.isDirectory();
|
|
4309
|
+
} catch {
|
|
4310
|
+
return false;
|
|
4311
|
+
}
|
|
4312
|
+
}
|
|
4313
|
+
async function validatePathWritable(path) {
|
|
4314
|
+
if (await isWritable(path)) return null;
|
|
4315
|
+
return "Workspace root directory exists but is not writable";
|
|
4316
|
+
}
|
|
4317
|
+
async function findOrphanedWorkspaces(dir) {
|
|
4318
|
+
const results = [];
|
|
4319
|
+
try {
|
|
4320
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
4321
|
+
for (const entry of entries) {
|
|
4322
|
+
if (entry.isDirectory()) {
|
|
4323
|
+
try {
|
|
4324
|
+
const gitStat = await stat2(join6(dir, entry.name, ".git"));
|
|
4325
|
+
if (gitStat.isDirectory()) {
|
|
4326
|
+
results.push({ name: entry.name });
|
|
4327
|
+
}
|
|
4328
|
+
} catch {
|
|
4329
|
+
}
|
|
4330
|
+
}
|
|
4331
|
+
}
|
|
4332
|
+
} catch (err) {
|
|
4333
|
+
if (err?.code !== "ENOENT") {
|
|
4334
|
+
logger.error("Error scanning for orphaned workspaces", { dir, error: String(err) });
|
|
4335
|
+
}
|
|
4336
|
+
}
|
|
4337
|
+
return results;
|
|
4338
|
+
}
|
|
4117
4339
|
function createWorkspaceConfigRoutes() {
|
|
4118
4340
|
const router = Router5();
|
|
4119
4341
|
router.get("/config", async (req, res) => {
|
|
@@ -4125,18 +4347,93 @@ function createWorkspaceConfigRoutes() {
|
|
|
4125
4347
|
router.post("/config", async (req, res) => {
|
|
4126
4348
|
const workdir = req.query["workdir"];
|
|
4127
4349
|
if (!workdir) return res.status(400).json({ error: "workdir required" });
|
|
4128
|
-
const { setup } = req.body;
|
|
4129
|
-
if (!Array.isArray(setup)) {
|
|
4350
|
+
const { setup, rootDir } = req.body;
|
|
4351
|
+
if (!Array.isArray(setup) && typeof rootDir !== "string") {
|
|
4352
|
+
return res.status(400).json({ error: "At least one of setup or rootDir must be provided" });
|
|
4353
|
+
}
|
|
4354
|
+
if (setup !== void 0 && !Array.isArray(setup)) {
|
|
4130
4355
|
return res.status(400).json({ error: "setup must be an array of strings" });
|
|
4131
4356
|
}
|
|
4357
|
+
const config3 = {};
|
|
4358
|
+
if (Array.isArray(setup)) {
|
|
4359
|
+
config3.setup = setup;
|
|
4360
|
+
}
|
|
4361
|
+
if (typeof rootDir === "string") {
|
|
4362
|
+
const trimmed = rootDir.trim();
|
|
4363
|
+
if (trimmed) {
|
|
4364
|
+
const resolvedPath = resolveRootDir(trimmed, workdir);
|
|
4365
|
+
const displayPath = resolvedPath.replace(/\/+$/, "") || "/";
|
|
4366
|
+
const blockReason = getRootDirBlockReason(resolvedPath);
|
|
4367
|
+
if (blockReason === "exact") {
|
|
4368
|
+
return res.status(400).json({ error: `Cannot use "${displayPath}" directly as workspace root. Use a subdirectory instead.` });
|
|
4369
|
+
}
|
|
4370
|
+
if (blockReason === "virtual_fs") {
|
|
4371
|
+
return res.status(400).json({ error: `Cannot use paths under "${displayPath}" for workspaces.` });
|
|
4372
|
+
}
|
|
4373
|
+
const dirExists = await checkDirExists(resolvedPath);
|
|
4374
|
+
if (dirExists) {
|
|
4375
|
+
const writableErr = await validatePathWritable(resolvedPath);
|
|
4376
|
+
if (writableErr) return res.status(400).json({ error: writableErr });
|
|
4377
|
+
}
|
|
4378
|
+
config3.rootDir = trimmed;
|
|
4379
|
+
}
|
|
4380
|
+
}
|
|
4132
4381
|
try {
|
|
4133
|
-
const config3 = { setup };
|
|
4134
4382
|
await saveWorkspaceConfig(workdir, config3);
|
|
4135
4383
|
res.json({ config: config3 });
|
|
4136
4384
|
} catch (err) {
|
|
4137
4385
|
res.status(500).json({ error: err instanceof Error ? err.message : "Failed to save config" });
|
|
4138
4386
|
}
|
|
4139
4387
|
});
|
|
4388
|
+
router.post("/config/validate", async (req, res) => {
|
|
4389
|
+
const { rootDir, workdir, projectName, createIfMissing } = req.body;
|
|
4390
|
+
if (!rootDir || typeof rootDir !== "string") {
|
|
4391
|
+
return res.status(400).json({ error: "rootDir is required" });
|
|
4392
|
+
}
|
|
4393
|
+
if (!workdir || typeof workdir !== "string") {
|
|
4394
|
+
return res.status(400).json({ error: "workdir is required" });
|
|
4395
|
+
}
|
|
4396
|
+
const resolvedPath = resolveRootDir(rootDir, workdir);
|
|
4397
|
+
const displayPath = resolvedPath.replace(/\/+$/, "") || "/";
|
|
4398
|
+
const blockReason = getRootDirBlockReason(resolvedPath);
|
|
4399
|
+
if (blockReason === "exact") {
|
|
4400
|
+
const suggestion = typeof projectName === "string" ? `${displayPath}/${projectName}` : void 0;
|
|
4401
|
+
return res.status(400).json({
|
|
4402
|
+
error: suggestion ? `Cannot use "${displayPath}" directly as workspace root. Use a subdirectory like "${suggestion}" instead.` : `Cannot use "${displayPath}" directly as workspace root. Use a subdirectory instead.`
|
|
4403
|
+
});
|
|
4404
|
+
}
|
|
4405
|
+
if (blockReason === "virtual_fs") {
|
|
4406
|
+
return res.status(400).json({ error: `Cannot use paths under "${displayPath}" for workspaces.` });
|
|
4407
|
+
}
|
|
4408
|
+
let dirExists = await checkDirExists(resolvedPath);
|
|
4409
|
+
if (dirExists) {
|
|
4410
|
+
const writableErr = await validatePathWritable(resolvedPath);
|
|
4411
|
+
if (writableErr) return res.status(400).json({ error: writableErr });
|
|
4412
|
+
}
|
|
4413
|
+
let created = false;
|
|
4414
|
+
if (!dirExists && createIfMissing) {
|
|
4415
|
+
await mkdir4(resolvedPath, { recursive: true });
|
|
4416
|
+
dirExists = true;
|
|
4417
|
+
created = true;
|
|
4418
|
+
}
|
|
4419
|
+
const workspaces = [];
|
|
4420
|
+
try {
|
|
4421
|
+
const currentConfig = await loadWorkspaceConfig(workdir);
|
|
4422
|
+
const previousRootDir = currentConfig?.rootDir ? resolveRootDir(currentConfig.rootDir, workdir) : null;
|
|
4423
|
+
if (previousRootDir && previousRootDir !== resolvedPath) {
|
|
4424
|
+
const orphans = await findOrphanedWorkspaces(previousRootDir);
|
|
4425
|
+
workspaces.push(...orphans);
|
|
4426
|
+
} else if (!previousRootDir && projectName && typeof projectName === "string") {
|
|
4427
|
+
const defaultDir = join6(getGlobalDataDir(), "workspaces", projectName);
|
|
4428
|
+
if (defaultDir !== resolvedPath) {
|
|
4429
|
+
const orphans = await findOrphanedWorkspaces(defaultDir);
|
|
4430
|
+
workspaces.push(...orphans);
|
|
4431
|
+
}
|
|
4432
|
+
}
|
|
4433
|
+
} catch {
|
|
4434
|
+
}
|
|
4435
|
+
res.json({ exists: dirExists, resolvedPath, created, workspaces });
|
|
4436
|
+
});
|
|
4140
4437
|
return router;
|
|
4141
4438
|
}
|
|
4142
4439
|
|
|
@@ -4183,19 +4480,19 @@ function createTerminalRoutes() {
|
|
|
4183
4480
|
|
|
4184
4481
|
// src/server/routes/directories.ts
|
|
4185
4482
|
import { Router as Router7 } from "express";
|
|
4186
|
-
import { readdir } from "fs/promises";
|
|
4187
|
-
import { resolve as
|
|
4483
|
+
import { readdir as readdir2 } from "fs/promises";
|
|
4484
|
+
import { resolve as resolve5, join as join7, dirname as dirname5, basename as basename2 } from "path";
|
|
4188
4485
|
function createDirectoryRoutes() {
|
|
4189
4486
|
const router = Router7();
|
|
4190
4487
|
const DEFAULT_BASE_PATH = process.cwd();
|
|
4191
4488
|
router.get("/", async (req, res) => {
|
|
4192
4489
|
const path = req.query["path"] || DEFAULT_BASE_PATH;
|
|
4193
4490
|
try {
|
|
4194
|
-
const resolvedPath =
|
|
4195
|
-
const entries = await
|
|
4491
|
+
const resolvedPath = resolve5(path);
|
|
4492
|
+
const entries = await readdir2(resolvedPath, { withFileTypes: true });
|
|
4196
4493
|
const directories = entries.filter((entry) => entry.isDirectory()).map((entry) => ({
|
|
4197
4494
|
name: entry.name,
|
|
4198
|
-
path:
|
|
4495
|
+
path: join7(resolvedPath, entry.name)
|
|
4199
4496
|
})).sort((a, b) => a.name.localeCompare(b.name));
|
|
4200
4497
|
const parent = dirname5(resolvedPath);
|
|
4201
4498
|
const hasParent = parent !== resolvedPath;
|
|
@@ -4349,7 +4646,7 @@ function isDevMode() {
|
|
|
4349
4646
|
return process.env["NODE_ENV"] === "development";
|
|
4350
4647
|
}
|
|
4351
4648
|
async function getRemote() {
|
|
4352
|
-
return new Promise((
|
|
4649
|
+
return new Promise((resolve9) => {
|
|
4353
4650
|
const child = spawn2("git", ["remote"], {
|
|
4354
4651
|
stdio: ["ignore", "pipe", "pipe"],
|
|
4355
4652
|
windowsHide: true
|
|
@@ -4360,23 +4657,23 @@ async function getRemote() {
|
|
|
4360
4657
|
});
|
|
4361
4658
|
child.on("close", () => {
|
|
4362
4659
|
const remotes = output.trim().split("\n").map((r) => r.trim()).filter(Boolean);
|
|
4363
|
-
if (remotes.includes("upstream"))
|
|
4364
|
-
else if (remotes.includes("origin"))
|
|
4365
|
-
else
|
|
4660
|
+
if (remotes.includes("upstream")) resolve9("upstream");
|
|
4661
|
+
else if (remotes.includes("origin")) resolve9("origin");
|
|
4662
|
+
else resolve9("origin");
|
|
4366
4663
|
});
|
|
4367
|
-
child.on("error", () =>
|
|
4664
|
+
child.on("error", () => resolve9("origin"));
|
|
4368
4665
|
});
|
|
4369
4666
|
}
|
|
4370
4667
|
async function getLatestDevelopVersion() {
|
|
4371
4668
|
const remote = await getRemote();
|
|
4372
|
-
return new Promise((
|
|
4669
|
+
return new Promise((resolve9) => {
|
|
4373
4670
|
const fetchChild = spawn2("git", ["fetch", remote, "develop", "--no-tags"], {
|
|
4374
4671
|
stdio: ["ignore", "pipe", "pipe"],
|
|
4375
4672
|
windowsHide: true
|
|
4376
4673
|
});
|
|
4377
4674
|
fetchChild.on("error", (err) => {
|
|
4378
4675
|
logger.error("[auto-update] Git fetch error", { error: err.message });
|
|
4379
|
-
|
|
4676
|
+
resolve9("unknown");
|
|
4380
4677
|
});
|
|
4381
4678
|
fetchChild.on("close", (code) => {
|
|
4382
4679
|
if (code !== 0) {
|
|
@@ -4392,7 +4689,7 @@ async function getLatestDevelopVersion() {
|
|
|
4392
4689
|
});
|
|
4393
4690
|
tagChild.on("close", (tagCode) => {
|
|
4394
4691
|
if (tagCode === 0 && tagOutput.trim()) {
|
|
4395
|
-
|
|
4692
|
+
resolve9(tagOutput.trim());
|
|
4396
4693
|
} else {
|
|
4397
4694
|
const fallbackChild = spawn2("git", ["describe", "--tags", "--abbrev=0", "develop"], {
|
|
4398
4695
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -4404,18 +4701,18 @@ async function getLatestDevelopVersion() {
|
|
|
4404
4701
|
});
|
|
4405
4702
|
fallbackChild.on("close", (fallbackCode) => {
|
|
4406
4703
|
if (fallbackCode === 0 && fallbackOutput.trim()) {
|
|
4407
|
-
|
|
4704
|
+
resolve9(fallbackOutput.trim());
|
|
4408
4705
|
} else {
|
|
4409
4706
|
logger.warn("[auto-update] No tags found on develop branch");
|
|
4410
|
-
|
|
4707
|
+
resolve9("unknown");
|
|
4411
4708
|
}
|
|
4412
4709
|
});
|
|
4413
|
-
fallbackChild.on("error", () =>
|
|
4710
|
+
fallbackChild.on("error", () => resolve9("unknown"));
|
|
4414
4711
|
}
|
|
4415
4712
|
});
|
|
4416
4713
|
tagChild.on("error", (err) => {
|
|
4417
4714
|
logger.error("[auto-update] Git tag error", { error: err.message });
|
|
4418
|
-
|
|
4715
|
+
resolve9("unknown");
|
|
4419
4716
|
});
|
|
4420
4717
|
});
|
|
4421
4718
|
});
|
|
@@ -4432,7 +4729,7 @@ function createAutoUpdateRoutes(options = {}) {
|
|
|
4432
4729
|
return;
|
|
4433
4730
|
}
|
|
4434
4731
|
try {
|
|
4435
|
-
const latest = isDev ? await getLatestDevelopVersion() : await new Promise((
|
|
4732
|
+
const latest = isDev ? await getLatestDevelopVersion() : await new Promise((resolve9, reject) => {
|
|
4436
4733
|
const win = process.platform === "win32";
|
|
4437
4734
|
const child = spawn2(win ? "npm view openfox version" : "npm", win ? [] : ["view", "openfox", "version"], {
|
|
4438
4735
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -4445,7 +4742,7 @@ function createAutoUpdateRoutes(options = {}) {
|
|
|
4445
4742
|
});
|
|
4446
4743
|
child.on("close", (code) => {
|
|
4447
4744
|
if (code === 0) {
|
|
4448
|
-
|
|
4745
|
+
resolve9(stdout.trim());
|
|
4449
4746
|
} else {
|
|
4450
4747
|
reject(new Error(`npm view exited with code ${code}`));
|
|
4451
4748
|
}
|
|
@@ -4460,12 +4757,13 @@ function createAutoUpdateRoutes(options = {}) {
|
|
|
4460
4757
|
const latestVersion = latest.replace(/^v/, "");
|
|
4461
4758
|
const isUpdateAvailable = currentVersion !== latestVersion;
|
|
4462
4759
|
const now = Date.now();
|
|
4463
|
-
versionCache.data = { current, latest, isUpdateAvailable, isService };
|
|
4760
|
+
versionCache.data = { current, latest: latestVersion, isUpdateAvailable, isService };
|
|
4464
4761
|
versionCache.timestamp = now;
|
|
4465
|
-
res.json({ current, latest, isUpdateAvailable, isService });
|
|
4762
|
+
res.json({ current, latest: latestVersion, isUpdateAvailable, isService });
|
|
4466
4763
|
} catch (err) {
|
|
4467
4764
|
logger.error("[auto-update] Error in version check", { error: err instanceof Error ? err.message : String(err) });
|
|
4468
|
-
|
|
4765
|
+
const currentVersion = isDev ? current.replace(/-dev$/, "") : current;
|
|
4766
|
+
res.json({ current, latest: currentVersion, isUpdateAvailable: false, isService });
|
|
4469
4767
|
}
|
|
4470
4768
|
});
|
|
4471
4769
|
router.post("/", async (req, res) => {
|
|
@@ -4496,9 +4794,9 @@ function createAutoUpdateRoutes(options = {}) {
|
|
|
4496
4794
|
const timeout = setTimeout(() => {
|
|
4497
4795
|
child.kill();
|
|
4498
4796
|
}, UPDATE_TIMEOUT);
|
|
4499
|
-
const exitCode = await new Promise((
|
|
4500
|
-
child.on("close",
|
|
4501
|
-
child.on("error", () =>
|
|
4797
|
+
const exitCode = await new Promise((resolve9) => {
|
|
4798
|
+
child.on("close", resolve9);
|
|
4799
|
+
child.on("error", () => resolve9(1));
|
|
4502
4800
|
});
|
|
4503
4801
|
clearTimeout(timeout);
|
|
4504
4802
|
if (exitCode === 0) {
|
|
@@ -4559,7 +4857,7 @@ function createProviderAuthRoutes(config3, providerManager, registry) {
|
|
|
4559
4857
|
try {
|
|
4560
4858
|
const { challenge, completion } = await adapter.beginLogin({ providerId: provider.id });
|
|
4561
4859
|
void completion.then(async ({ credentialRef }) => {
|
|
4562
|
-
const { loadGlobalConfig, saveGlobalConfig, updateProvider } = await import("./config-
|
|
4860
|
+
const { loadGlobalConfig, saveGlobalConfig, updateProvider } = await import("./config-MD74ETY5.js");
|
|
4563
4861
|
const globalConfig = await loadGlobalConfig(config3.mode ?? "production", config3.globalConfigPath);
|
|
4564
4862
|
const updatedConfig = updateProvider(globalConfig, provider.id, { credentialRef, authAdapter: adapter.id });
|
|
4565
4863
|
await saveGlobalConfig(config3.mode ?? "production", updatedConfig, config3.globalConfigPath);
|
|
@@ -4593,7 +4891,7 @@ function createProviderAuthRoutes(config3, providerManager, registry) {
|
|
|
4593
4891
|
if (!context) return;
|
|
4594
4892
|
const { provider, adapter } = context;
|
|
4595
4893
|
if (provider.credentialRef && adapter) await adapter.logout(provider.credentialRef);
|
|
4596
|
-
const { loadGlobalConfig, saveGlobalConfig } = await import("./config-
|
|
4894
|
+
const { loadGlobalConfig, saveGlobalConfig } = await import("./config-MD74ETY5.js");
|
|
4597
4895
|
const globalConfig = await loadGlobalConfig(config3.mode ?? "production", config3.globalConfigPath);
|
|
4598
4896
|
const updatedConfig = {
|
|
4599
4897
|
...globalConfig,
|
|
@@ -4670,26 +4968,26 @@ var ProviderRegistry = class {
|
|
|
4670
4968
|
};
|
|
4671
4969
|
|
|
4672
4970
|
// src/server/providers/plugins/loader.ts
|
|
4673
|
-
import { readdir as
|
|
4674
|
-
import { dirname as dirname6, join as
|
|
4971
|
+
import { readdir as readdir3, readFile as readFile2, stat as stat3 } from "fs/promises";
|
|
4972
|
+
import { dirname as dirname6, join as join8, resolve as resolve6 } from "path";
|
|
4675
4973
|
import { fileURLToPath as fileURLToPath5, pathToFileURL } from "url";
|
|
4676
4974
|
async function packageDirectories(root) {
|
|
4677
4975
|
let entries;
|
|
4678
4976
|
try {
|
|
4679
|
-
entries = await
|
|
4977
|
+
entries = await readdir3(root, { withFileTypes: true });
|
|
4680
4978
|
} catch {
|
|
4681
4979
|
return [];
|
|
4682
4980
|
}
|
|
4683
4981
|
const directories = [];
|
|
4684
4982
|
for (const entry of entries) {
|
|
4685
|
-
const entryPath =
|
|
4686
|
-
const isDirectory = entry.isDirectory() || entry.isSymbolicLink() && (await
|
|
4983
|
+
const entryPath = join8(root, entry.name);
|
|
4984
|
+
const isDirectory = entry.isDirectory() || entry.isSymbolicLink() && (await stat3(entryPath).catch(() => void 0))?.isDirectory();
|
|
4687
4985
|
if (!isDirectory) continue;
|
|
4688
4986
|
if (entry.name.startsWith("@")) {
|
|
4689
|
-
const scoped = await
|
|
4987
|
+
const scoped = await readdir3(entryPath, { withFileTypes: true }).catch(() => []);
|
|
4690
4988
|
for (const child of scoped) {
|
|
4691
|
-
const childPath =
|
|
4692
|
-
const childIsDirectory = child.isDirectory() || child.isSymbolicLink() && (await
|
|
4989
|
+
const childPath = join8(entryPath, child.name);
|
|
4990
|
+
const childIsDirectory = child.isDirectory() || child.isSymbolicLink() && (await stat3(childPath).catch(() => void 0))?.isDirectory();
|
|
4693
4991
|
if (childIsDirectory) directories.push(childPath);
|
|
4694
4992
|
}
|
|
4695
4993
|
} else {
|
|
@@ -4701,16 +4999,16 @@ async function packageDirectories(root) {
|
|
|
4701
4999
|
async function loadProviderPlugins(options) {
|
|
4702
5000
|
const moduleDirectory = dirname6(fileURLToPath5(import.meta.url));
|
|
4703
5001
|
const roots = [
|
|
4704
|
-
|
|
4705
|
-
|
|
4706
|
-
|
|
4707
|
-
|
|
5002
|
+
join8(options.configDirectory, "plugins"),
|
|
5003
|
+
join8(options.cwd ?? process.cwd(), "node_modules"),
|
|
5004
|
+
resolve6(moduleDirectory, "node_modules"),
|
|
5005
|
+
resolve6(moduleDirectory, "../../../../node_modules")
|
|
4708
5006
|
];
|
|
4709
5007
|
const seen = /* @__PURE__ */ new Set();
|
|
4710
5008
|
const diagnostics = [];
|
|
4711
5009
|
for (const root of roots) {
|
|
4712
5010
|
for (const packageDir of await packageDirectories(root)) {
|
|
4713
|
-
const manifestPath =
|
|
5011
|
+
const manifestPath = join8(packageDir, "package.json");
|
|
4714
5012
|
let manifest;
|
|
4715
5013
|
try {
|
|
4716
5014
|
manifest = JSON.parse(await readFile2(manifestPath, "utf8"));
|
|
@@ -4751,7 +5049,7 @@ async function loadProviderPlugins(options) {
|
|
|
4751
5049
|
}
|
|
4752
5050
|
};
|
|
4753
5051
|
try {
|
|
4754
|
-
const module = await import(pathToFileURL(
|
|
5052
|
+
const module = await import(pathToFileURL(join8(packageDir, plugin)).href);
|
|
4755
5053
|
if (typeof module.register !== "function") throw new Error("Plugin does not export register(registry)");
|
|
4756
5054
|
await module.register(trackingRegistry);
|
|
4757
5055
|
diagnostic.loaded = true;
|
|
@@ -4766,9 +5064,9 @@ async function loadProviderPlugins(options) {
|
|
|
4766
5064
|
// src/server/routes/plugins.ts
|
|
4767
5065
|
import { Router as Router11 } from "express";
|
|
4768
5066
|
import { fileURLToPath as fileURLToPath6, pathToFileURL as pathToFileURL2 } from "url";
|
|
4769
|
-
import { dirname as dirname7, resolve as
|
|
5067
|
+
import { dirname as dirname7, resolve as resolve7, join as join9 } from "path";
|
|
4770
5068
|
import { existsSync } from "fs";
|
|
4771
|
-
import { readFile as readFile3, readdir as
|
|
5069
|
+
import { readFile as readFile3, readdir as readdir4, rm as rm2, rename as rename2 } from "fs/promises";
|
|
4772
5070
|
import { platform } from "os";
|
|
4773
5071
|
import { execFile } from "child_process";
|
|
4774
5072
|
import { promisify } from "util";
|
|
@@ -4794,9 +5092,9 @@ function createPluginRoutes(options) {
|
|
|
4794
5092
|
return res.json({ plugins: registryCache.data });
|
|
4795
5093
|
}
|
|
4796
5094
|
const moduleDir = dirname7(fileURLToPath6(import.meta.url));
|
|
4797
|
-
let registryPath =
|
|
5095
|
+
let registryPath = resolve7(moduleDir, "../plugins-registry.json");
|
|
4798
5096
|
if (!existsSync(registryPath)) {
|
|
4799
|
-
registryPath =
|
|
5097
|
+
registryPath = resolve7(moduleDir, "../../../plugins-registry.json");
|
|
4800
5098
|
}
|
|
4801
5099
|
const data = JSON.parse(await readFile3(registryPath, "utf8"));
|
|
4802
5100
|
registryCache = { data, ts: now };
|
|
@@ -4819,9 +5117,9 @@ function createPluginRoutes(options) {
|
|
|
4819
5117
|
if (!/^[a-zA-Z0-9_-]+$/.test(repoName)) {
|
|
4820
5118
|
return res.status(400).json({ error: "Invalid repository name" });
|
|
4821
5119
|
}
|
|
4822
|
-
const pluginsDir =
|
|
4823
|
-
const targetDir =
|
|
4824
|
-
const tmpDir =
|
|
5120
|
+
const pluginsDir = join9(getGlobalConfigDir(config3.mode ?? "production"), "plugins");
|
|
5121
|
+
const targetDir = join9(pluginsDir, repoName);
|
|
5122
|
+
const tmpDir = join9(pluginsDir, `.${repoName}-tmp-${Date.now()}`);
|
|
4825
5123
|
try {
|
|
4826
5124
|
await execFileP("mkdir", ["-p", pluginsDir], { timeout: 5e3 });
|
|
4827
5125
|
} catch {
|
|
@@ -4852,7 +5150,7 @@ function createPluginRoutes(options) {
|
|
|
4852
5150
|
}
|
|
4853
5151
|
if (!loadError) {
|
|
4854
5152
|
try {
|
|
4855
|
-
const manifest = JSON.parse(await readFile3(
|
|
5153
|
+
const manifest = JSON.parse(await readFile3(join9(targetDir, "package.json"), "utf8"));
|
|
4856
5154
|
const pluginEntry = manifest.openfox?.plugin;
|
|
4857
5155
|
const apiVersion = manifest.openfox?.apiVersion;
|
|
4858
5156
|
if (!pluginEntry || !manifest.name) {
|
|
@@ -4860,7 +5158,7 @@ function createPluginRoutes(options) {
|
|
|
4860
5158
|
} else if (apiVersion !== 1) {
|
|
4861
5159
|
loadError = `Unsupported plugin API version: ${String(apiVersion)}`;
|
|
4862
5160
|
} else {
|
|
4863
|
-
const mod = await import(pathToFileURL2(
|
|
5161
|
+
const mod = await import(pathToFileURL2(join9(targetDir, pluginEntry)).href);
|
|
4864
5162
|
if (typeof mod.register !== "function") {
|
|
4865
5163
|
loadError = "Plugin does not export register(registry)";
|
|
4866
5164
|
} else {
|
|
@@ -4909,13 +5207,13 @@ function createPluginRoutes(options) {
|
|
|
4909
5207
|
}
|
|
4910
5208
|
});
|
|
4911
5209
|
router.get("/installed", async (_req, res) => {
|
|
4912
|
-
const pluginsDir =
|
|
5210
|
+
const pluginsDir = join9(getGlobalConfigDir(config3.mode ?? "production"), "plugins");
|
|
4913
5211
|
try {
|
|
4914
|
-
const entries = await
|
|
5212
|
+
const entries = await readdir4(pluginsDir, { withFileTypes: true });
|
|
4915
5213
|
const installed = [];
|
|
4916
5214
|
for (const entry of entries) {
|
|
4917
5215
|
if (!entry.isDirectory()) continue;
|
|
4918
|
-
const pkgPath =
|
|
5216
|
+
const pkgPath = join9(pluginsDir, entry.name, "package.json");
|
|
4919
5217
|
let version = null;
|
|
4920
5218
|
try {
|
|
4921
5219
|
const pkg = JSON.parse(await readFile3(pkgPath, "utf8"));
|
|
@@ -4930,13 +5228,13 @@ function createPluginRoutes(options) {
|
|
|
4930
5228
|
}
|
|
4931
5229
|
});
|
|
4932
5230
|
router.get("/open-folder", async (_req, res) => {
|
|
4933
|
-
const pluginsDir =
|
|
5231
|
+
const pluginsDir = join9(getGlobalConfigDir(config3.mode ?? "production"), "plugins");
|
|
4934
5232
|
await openFolder(pluginsDir, res);
|
|
4935
5233
|
});
|
|
4936
5234
|
router.get("/:name/open-folder", async (req, res) => {
|
|
4937
5235
|
const name = req.params.name;
|
|
4938
5236
|
if (!/^[a-zA-Z0-9_-]+$/.test(name)) return res.status(400).json({ error: "Invalid plugin name" });
|
|
4939
|
-
const targetDir =
|
|
5237
|
+
const targetDir = join9(getGlobalConfigDir(config3.mode ?? "production"), "plugins", name);
|
|
4940
5238
|
await openFolder(targetDir, res);
|
|
4941
5239
|
});
|
|
4942
5240
|
router.delete("/:name", async (req, res) => {
|
|
@@ -4944,7 +5242,7 @@ function createPluginRoutes(options) {
|
|
|
4944
5242
|
if (!/^[a-zA-Z0-9_-]+$/.test(name)) {
|
|
4945
5243
|
return res.status(400).json({ error: "Invalid plugin name" });
|
|
4946
5244
|
}
|
|
4947
|
-
const targetDir =
|
|
5245
|
+
const targetDir = join9(getGlobalConfigDir(config3.mode ?? "production"), "plugins", name);
|
|
4948
5246
|
try {
|
|
4949
5247
|
await rm2(targetDir, { recursive: true, force: true });
|
|
4950
5248
|
for (let i = pluginDiagnostics.length - 1; i >= 0; i--) {
|
|
@@ -5073,7 +5371,7 @@ async function createServerHandle(config3) {
|
|
|
5073
5371
|
const mcpManager = new McpManager({
|
|
5074
5372
|
onToolsDiscovered: async (name, tools) => {
|
|
5075
5373
|
try {
|
|
5076
|
-
const { loadGlobalConfig, saveGlobalConfig } = await import("./config-
|
|
5374
|
+
const { loadGlobalConfig, saveGlobalConfig } = await import("./config-MD74ETY5.js");
|
|
5077
5375
|
const mode = config3.mode ?? "production";
|
|
5078
5376
|
const globalConfig = await loadGlobalConfig(mode, config3.globalConfigPath);
|
|
5079
5377
|
const mcpServers2 = {
|
|
@@ -5104,12 +5402,11 @@ async function createServerHandle(config3) {
|
|
|
5104
5402
|
setMcpTools(mcpTools);
|
|
5105
5403
|
logger.info("MCP tools registered", { count: mcpTools.length });
|
|
5106
5404
|
}
|
|
5107
|
-
const { signalMcpReady } = await import("./server-
|
|
5405
|
+
const { signalMcpReady } = await import("./server-3XUD2NB7.js");
|
|
5108
5406
|
signalMcpReady();
|
|
5109
5407
|
});
|
|
5110
5408
|
const app = express();
|
|
5111
5409
|
app.use(cors());
|
|
5112
|
-
app.use(express.json({ limit: "10mb" }));
|
|
5113
5410
|
const authMiddleware = async (req, res, next) => {
|
|
5114
5411
|
const path = req.path;
|
|
5115
5412
|
const publicPaths = ["/health", "/auth", "/auth/login", "/auto-update/check"];
|
|
@@ -5127,6 +5424,7 @@ async function createServerHandle(config3) {
|
|
|
5127
5424
|
next();
|
|
5128
5425
|
};
|
|
5129
5426
|
app.use("/api", authMiddleware);
|
|
5427
|
+
app.use(express.json({ limit: "75mb" }));
|
|
5130
5428
|
app.get("/api/health", (_req, res) => {
|
|
5131
5429
|
res.json({ status: "ok", timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
5132
5430
|
});
|
|
@@ -5166,7 +5464,7 @@ async function createServerHandle(config3) {
|
|
|
5166
5464
|
res.json({ tools });
|
|
5167
5465
|
});
|
|
5168
5466
|
app.get("/api/projects", async (_req, res) => {
|
|
5169
|
-
const { listProjects } = await import("./projects-
|
|
5467
|
+
const { listProjects } = await import("./projects-ZGJGICGT.js");
|
|
5170
5468
|
const projects = listProjects();
|
|
5171
5469
|
res.json({ projects });
|
|
5172
5470
|
});
|
|
@@ -5175,7 +5473,7 @@ async function createServerHandle(config3) {
|
|
|
5175
5473
|
if (!name || !workdir) {
|
|
5176
5474
|
return res.status(400).json({ error: "name and workdir are required" });
|
|
5177
5475
|
}
|
|
5178
|
-
const { createDirectoryWithGit } = await import("./project-creator-
|
|
5476
|
+
const { createDirectoryWithGit } = await import("./project-creator-NNUITNUI.js");
|
|
5179
5477
|
try {
|
|
5180
5478
|
const project = await createDirectoryWithGit(name, workdir);
|
|
5181
5479
|
res.status(201).json({ project });
|
|
@@ -5220,7 +5518,7 @@ async function createServerHandle(config3) {
|
|
|
5220
5518
|
}
|
|
5221
5519
|
});
|
|
5222
5520
|
app.get("/api/projects/:id", async (req, res) => {
|
|
5223
|
-
const { getProject: getProject2 } = await import("./projects-
|
|
5521
|
+
const { getProject: getProject2 } = await import("./projects-ZGJGICGT.js");
|
|
5224
5522
|
const project = getProject2(req.params.id);
|
|
5225
5523
|
if (!project) {
|
|
5226
5524
|
return res.status(404).json({ error: "Project not found" });
|
|
@@ -5228,7 +5526,7 @@ async function createServerHandle(config3) {
|
|
|
5228
5526
|
res.json({ project });
|
|
5229
5527
|
});
|
|
5230
5528
|
app.put("/api/projects/:id", async (req, res) => {
|
|
5231
|
-
const { updateProject } = await import("./projects-
|
|
5529
|
+
const { updateProject } = await import("./projects-ZGJGICGT.js");
|
|
5232
5530
|
const { name, customInstructions, dangerLevel } = req.body;
|
|
5233
5531
|
const updates = {};
|
|
5234
5532
|
if (name !== void 0) updates.name = name;
|
|
@@ -5241,7 +5539,7 @@ async function createServerHandle(config3) {
|
|
|
5241
5539
|
res.json({ project: updated });
|
|
5242
5540
|
});
|
|
5243
5541
|
app.delete("/api/projects/:id", async (req, res) => {
|
|
5244
|
-
const { getProject: getProject2, deleteProject } = await import("./projects-
|
|
5542
|
+
const { getProject: getProject2, deleteProject } = await import("./projects-ZGJGICGT.js");
|
|
5245
5543
|
const project = getProject2(req.params.id);
|
|
5246
5544
|
if (!project) {
|
|
5247
5545
|
return res.status(404).json({ error: "Project not found" });
|
|
@@ -5250,7 +5548,7 @@ async function createServerHandle(config3) {
|
|
|
5250
5548
|
res.json({ success: true });
|
|
5251
5549
|
});
|
|
5252
5550
|
app.put("/api/projects/:id/star", async (req, res) => {
|
|
5253
|
-
const { toggleStar } = await import("./projects-
|
|
5551
|
+
const { toggleStar } = await import("./projects-ZGJGICGT.js");
|
|
5254
5552
|
const { isStarred } = req.body;
|
|
5255
5553
|
if (typeof isStarred !== "boolean") {
|
|
5256
5554
|
return res.status(400).json({ error: "isStarred is required and must be a boolean" });
|
|
@@ -5262,37 +5560,60 @@ async function createServerHandle(config3) {
|
|
|
5262
5560
|
res.json({ project });
|
|
5263
5561
|
});
|
|
5264
5562
|
app.get("/api/projects/:id/branches", async (req, res) => {
|
|
5265
|
-
const { getProject: getProject2 } = await import("./projects-
|
|
5563
|
+
const { getProject: getProject2 } = await import("./projects-ZGJGICGT.js");
|
|
5266
5564
|
const project = getProject2(req.params.id);
|
|
5267
5565
|
if (!project) return res.status(404).json({ error: "Project not found" });
|
|
5268
|
-
const { listBranches } = await import("./workspace-
|
|
5566
|
+
const { listBranches } = await import("./workspace-J74ZMSOJ.js");
|
|
5269
5567
|
const branches = await listBranches(project.workdir);
|
|
5270
5568
|
res.json({ branches });
|
|
5271
5569
|
});
|
|
5272
5570
|
app.post("/api/projects/:id/checkout", async (req, res) => {
|
|
5273
|
-
const { getProject: getProject2 } = await import("./projects-
|
|
5571
|
+
const { getProject: getProject2 } = await import("./projects-ZGJGICGT.js");
|
|
5274
5572
|
const project = getProject2(req.params.id);
|
|
5275
5573
|
if (!project) return res.status(404).json({ error: "Project not found" });
|
|
5276
5574
|
const { branch } = req.body;
|
|
5277
5575
|
if (!branch || typeof branch !== "string") return res.status(400).json({ error: "branch is required" });
|
|
5278
|
-
const { checkoutBranch } = await import("./workspace-
|
|
5576
|
+
const { checkoutBranch } = await import("./workspace-J74ZMSOJ.js");
|
|
5279
5577
|
try {
|
|
5280
5578
|
await checkoutBranch(project.workdir, branch);
|
|
5579
|
+
const { updateSessionBranch: updateSessionBranch2 } = await import("./sessions-SFG42M4W.js");
|
|
5580
|
+
const allSessions = sessionManager.listSessions();
|
|
5581
|
+
for (const s of allSessions) {
|
|
5582
|
+
const effectiveWorkdir = s.workspace ?? s.workdir;
|
|
5583
|
+
if (effectiveWorkdir === project.workdir) {
|
|
5584
|
+
updateSessionBranch2(s.id, branch);
|
|
5585
|
+
sessionManager.emitBranchChange(s.id);
|
|
5586
|
+
}
|
|
5587
|
+
}
|
|
5281
5588
|
res.json({ branch });
|
|
5282
5589
|
} catch (err) {
|
|
5283
5590
|
res.status(400).json({ error: err instanceof Error ? err.message : "Failed to checkout branch" });
|
|
5284
5591
|
}
|
|
5285
5592
|
});
|
|
5286
5593
|
app.post("/api/projects/:id/checkout-new", async (req, res) => {
|
|
5287
|
-
const { getProject: getProject2 } = await import("./projects-
|
|
5594
|
+
const { getProject: getProject2 } = await import("./projects-ZGJGICGT.js");
|
|
5288
5595
|
const project = getProject2(req.params.id);
|
|
5289
5596
|
if (!project) return res.status(404).json({ error: "Project not found" });
|
|
5290
|
-
const { name } = req.body;
|
|
5597
|
+
const { name, sourceBranch } = req.body;
|
|
5291
5598
|
if (!name || typeof name !== "string") return res.status(400).json({ error: "name is required" });
|
|
5292
|
-
const { createBranch } = await import("./workspace-
|
|
5599
|
+
const { createBranch, resolveAndValidateSourceBranch: resolveAndValidateSourceBranch2, validateRef: validateRef2 } = await import("./workspace-J74ZMSOJ.js");
|
|
5293
5600
|
try {
|
|
5294
|
-
await
|
|
5295
|
-
|
|
5601
|
+
await validateRef2(project.workdir, name);
|
|
5602
|
+
let sb;
|
|
5603
|
+
if (sourceBranch) {
|
|
5604
|
+
sb = await resolveAndValidateSourceBranch2(project.workdir, sourceBranch, project.workdir);
|
|
5605
|
+
}
|
|
5606
|
+
await createBranch(project.workdir, name, sb);
|
|
5607
|
+
const { updateSessionBranch: updateSessionBranch2 } = await import("./sessions-SFG42M4W.js");
|
|
5608
|
+
const allSessions = sessionManager.listSessions();
|
|
5609
|
+
for (const s of allSessions) {
|
|
5610
|
+
const effectiveWorkdir = s.workspace ?? s.workdir;
|
|
5611
|
+
if (effectiveWorkdir === project.workdir) {
|
|
5612
|
+
updateSessionBranch2(s.id, name);
|
|
5613
|
+
sessionManager.emitBranchChange(s.id);
|
|
5614
|
+
}
|
|
5615
|
+
}
|
|
5616
|
+
res.json({ branch: name, sourceBranch: sourceBranch ?? null });
|
|
5296
5617
|
} catch (err) {
|
|
5297
5618
|
res.status(400).json({ error: err instanceof Error ? err.message : "Failed to create branch" });
|
|
5298
5619
|
}
|
|
@@ -5301,9 +5622,13 @@ async function createServerHandle(config3) {
|
|
|
5301
5622
|
const session = sessionManager.getSession(req.params.id);
|
|
5302
5623
|
if (!session) return res.status(404).json({ error: "Session not found" });
|
|
5303
5624
|
const effectiveWorkdir = session.workspace ?? session.workdir;
|
|
5304
|
-
const { listBranches } = await import("./workspace-
|
|
5305
|
-
const branches = await
|
|
5306
|
-
|
|
5625
|
+
const { listBranches, getDefaultBranch: getDefaultBranch2 } = await import("./workspace-J74ZMSOJ.js");
|
|
5626
|
+
const [branches, defaultBranch] = await Promise.all([
|
|
5627
|
+
listBranches(effectiveWorkdir),
|
|
5628
|
+
getDefaultBranch2(session.workdir)
|
|
5629
|
+
// project root, not workspace, for real upstream origin/HEAD
|
|
5630
|
+
]);
|
|
5631
|
+
res.json({ branches, defaultBranch });
|
|
5307
5632
|
});
|
|
5308
5633
|
app.post("/api/sessions/:id/checkout", async (req, res) => {
|
|
5309
5634
|
const session = sessionManager.getSession(req.params.id);
|
|
@@ -5311,10 +5636,21 @@ async function createServerHandle(config3) {
|
|
|
5311
5636
|
const { branch } = req.body;
|
|
5312
5637
|
if (!branch || typeof branch !== "string") return res.status(400).json({ error: "branch is required" });
|
|
5313
5638
|
const effectiveWorkdir = session.workspace ?? session.workdir;
|
|
5314
|
-
const { checkoutBranch, validateRef } = await import("./workspace-
|
|
5639
|
+
const { checkoutBranch, validateRef: validateRef2 } = await import("./workspace-J74ZMSOJ.js");
|
|
5640
|
+
const { updateSessionBranch: updateSessionBranch2 } = await import("./sessions-SFG42M4W.js");
|
|
5315
5641
|
try {
|
|
5316
|
-
await
|
|
5642
|
+
await validateRef2(effectiveWorkdir, branch);
|
|
5317
5643
|
await checkoutBranch(effectiveWorkdir, branch);
|
|
5644
|
+
updateSessionBranch2(req.params.id, branch);
|
|
5645
|
+
if (session.workspace) {
|
|
5646
|
+
const all = sessionManager.listSessions();
|
|
5647
|
+
for (const s of all) {
|
|
5648
|
+
if (s.id !== req.params.id && s.workspace === session.workspace) {
|
|
5649
|
+
updateSessionBranch2(s.id, branch);
|
|
5650
|
+
sessionManager.emitBranchChange(s.id);
|
|
5651
|
+
}
|
|
5652
|
+
}
|
|
5653
|
+
}
|
|
5318
5654
|
res.json({ branch });
|
|
5319
5655
|
} catch (err) {
|
|
5320
5656
|
res.status(400).json({ error: err instanceof Error ? err.message : "Failed to checkout branch" });
|
|
@@ -5323,30 +5659,48 @@ async function createServerHandle(config3) {
|
|
|
5323
5659
|
app.post("/api/sessions/:id/checkout-new", async (req, res) => {
|
|
5324
5660
|
const session = sessionManager.getSession(req.params.id);
|
|
5325
5661
|
if (!session) return res.status(404).json({ error: "Session not found" });
|
|
5326
|
-
const { name } = req.body;
|
|
5662
|
+
const { name, sourceBranch } = req.body;
|
|
5327
5663
|
if (!name || typeof name !== "string") return res.status(400).json({ error: "name is required" });
|
|
5328
5664
|
const effectiveWorkdir = session.workspace ?? session.workdir;
|
|
5329
|
-
const {
|
|
5665
|
+
const { validateRef: validateRef2 } = await import("./workspace-J74ZMSOJ.js");
|
|
5666
|
+
const { updateSessionBranch: updateSessionBranch2 } = await import("./sessions-SFG42M4W.js");
|
|
5330
5667
|
try {
|
|
5331
|
-
await
|
|
5332
|
-
|
|
5333
|
-
|
|
5668
|
+
await validateRef2(effectiveWorkdir, name);
|
|
5669
|
+
if (sourceBranch) {
|
|
5670
|
+
const { resolveAndValidateSourceBranch: resolveAndValidateSourceBranch2, createBranch } = await import("./workspace-J74ZMSOJ.js");
|
|
5671
|
+
const sb = await resolveAndValidateSourceBranch2(effectiveWorkdir, sourceBranch, session.workdir);
|
|
5672
|
+
await createBranch(effectiveWorkdir, name, sb);
|
|
5673
|
+
} else {
|
|
5674
|
+
const { createBranch } = await import("./workspace-J74ZMSOJ.js");
|
|
5675
|
+
await createBranch(effectiveWorkdir, name);
|
|
5676
|
+
}
|
|
5677
|
+
updateSessionBranch2(req.params.id, name);
|
|
5678
|
+
if (session.workspace) {
|
|
5679
|
+
const all = sessionManager.listSessions();
|
|
5680
|
+
for (const s of all) {
|
|
5681
|
+
if (s.id !== req.params.id && s.workspace === session.workspace) {
|
|
5682
|
+
updateSessionBranch2(s.id, name);
|
|
5683
|
+
sessionManager.emitBranchChange(s.id);
|
|
5684
|
+
}
|
|
5685
|
+
}
|
|
5686
|
+
}
|
|
5687
|
+
res.json({ branch: name, sourceBranch: sourceBranch ?? null });
|
|
5334
5688
|
} catch (err) {
|
|
5335
5689
|
res.status(400).json({ error: err instanceof Error ? err.message : "Failed to create branch" });
|
|
5336
5690
|
}
|
|
5337
5691
|
});
|
|
5338
5692
|
app.get("/api/projects/:id/workspaces", async (req, res) => {
|
|
5339
|
-
const { getProject: getProject2 } = await import("./projects-
|
|
5693
|
+
const { getProject: getProject2 } = await import("./projects-ZGJGICGT.js");
|
|
5340
5694
|
const project = getProject2(req.params.id);
|
|
5341
5695
|
if (!project) return res.status(404).json({ error: "Project not found" });
|
|
5342
|
-
const { listWorkspaces } = await import("./workspace-
|
|
5343
|
-
const all = await listWorkspaces(project.name);
|
|
5696
|
+
const { listWorkspaces } = await import("./workspace-J74ZMSOJ.js");
|
|
5697
|
+
const all = await listWorkspaces(project.name, project.workdir);
|
|
5344
5698
|
const workspacesList = all.filter((ws) => ws.path !== project.workdir);
|
|
5345
5699
|
res.json({ workspaces: workspacesList });
|
|
5346
5700
|
});
|
|
5347
5701
|
app.get("/api/sessions", async (req, res) => {
|
|
5348
|
-
const { getRecentUserPromptsForSession } = await import("./events-
|
|
5349
|
-
const { getPendingConfirmationsBySession } = await import("./path-security-
|
|
5702
|
+
const { getRecentUserPromptsForSession } = await import("./events-KNOZX7YG.js");
|
|
5703
|
+
const { getPendingConfirmationsBySession } = await import("./path-security-HUXQHEQ5.js");
|
|
5350
5704
|
const projectId = req.query["projectId"];
|
|
5351
5705
|
const limit = Math.min(parseInt(req.query["limit"]) || 20, 100);
|
|
5352
5706
|
const offset = parseInt(req.query["offset"]) || 0;
|
|
@@ -5384,7 +5738,7 @@ async function createServerHandle(config3) {
|
|
|
5384
5738
|
}
|
|
5385
5739
|
const { providerId, model } = parseDefaultModelSelection(config3.defaultModelSelection);
|
|
5386
5740
|
const session = sessionManager.createSession(projectId, title, providerId ?? null, model ?? null);
|
|
5387
|
-
wssExports.
|
|
5741
|
+
wssExports.broadcastForProject(projectId, session.id, {
|
|
5388
5742
|
type: "session.created",
|
|
5389
5743
|
sessionId: session.id,
|
|
5390
5744
|
payload: {
|
|
@@ -5412,10 +5766,10 @@ async function createServerHandle(config3) {
|
|
|
5412
5766
|
app.post("/api/sessions/:id/switch-workspace", async (req, res) => {
|
|
5413
5767
|
const session = sessionManager.getSession(req.params.id);
|
|
5414
5768
|
if (!session) return res.status(404).json({ error: "Session not found" });
|
|
5415
|
-
const { target, branch } = req.body;
|
|
5769
|
+
const { target, branch, sourceBranch } = req.body;
|
|
5416
5770
|
if (!target || typeof target !== "string") return res.status(400).json({ error: "target is required" });
|
|
5417
5771
|
try {
|
|
5418
|
-
const updated = await sessionManager.switchWorkspace(req.params.id, target, branch);
|
|
5772
|
+
const updated = await sessionManager.switchWorkspace(req.params.id, target, branch, sourceBranch);
|
|
5419
5773
|
res.json({ session: updated });
|
|
5420
5774
|
} catch (err) {
|
|
5421
5775
|
res.status(400).json({ error: err instanceof Error ? err.message : "Failed to switch workspace" });
|
|
@@ -5434,21 +5788,32 @@ async function createServerHandle(config3) {
|
|
|
5434
5788
|
}
|
|
5435
5789
|
});
|
|
5436
5790
|
app.get("/api/sessions/:id", async (req, res) => {
|
|
5437
|
-
const { getEventStore: getEventStore2 } = await import("./events-
|
|
5438
|
-
const { buildMessagesFromStoredEvents, foldPendingConfirmations } = await import("./folding-
|
|
5439
|
-
const { getPendingQuestionsForSession } = await import("./tools-
|
|
5791
|
+
const { getEventStore: getEventStore2, combineEventsWithSnapshot } = await import("./events-KNOZX7YG.js");
|
|
5792
|
+
const { buildMessagesFromStoredEvents, foldPendingConfirmations } = await import("./folding-OPP2BVUB.js");
|
|
5793
|
+
const { getPendingQuestionsForSession } = await import("./tools-HGKUD327.js");
|
|
5794
|
+
const { getMaxVisibleItems } = await import("./settings-6M55N4Q2.js");
|
|
5440
5795
|
const session = sessionManager.getSession(req.params.id);
|
|
5441
5796
|
if (!session) {
|
|
5442
5797
|
return res.status(404).json({ error: "Session not found" });
|
|
5443
5798
|
}
|
|
5444
5799
|
const eventStore = getEventStore2();
|
|
5445
|
-
const events = eventStore.
|
|
5446
|
-
const
|
|
5800
|
+
const { snapshot, events: eventsSinceSnapshot } = eventStore.getEventsSinceSnapshot(req.params.id);
|
|
5801
|
+
const events = combineEventsWithSnapshot(req.params.id, snapshot, eventsSinceSnapshot);
|
|
5802
|
+
const maxVisibleItems = req.query["full"] === "true" ? void 0 : getMaxVisibleItems() || void 0;
|
|
5803
|
+
const { messages, hiddenCount } = buildMessagesFromStoredEvents(events, maxVisibleItems);
|
|
5447
5804
|
const contextState = sessionManager.getContextState(req.params.id);
|
|
5448
5805
|
const queueState = sessionManager.getQueueState(req.params.id);
|
|
5449
5806
|
const pendingQuestions = getPendingQuestionsForSession(req.params.id);
|
|
5450
5807
|
const pendingConfirmations = foldPendingConfirmations(events);
|
|
5451
|
-
res.json({
|
|
5808
|
+
res.json({
|
|
5809
|
+
session,
|
|
5810
|
+
messages,
|
|
5811
|
+
hiddenCount,
|
|
5812
|
+
contextState,
|
|
5813
|
+
queueState,
|
|
5814
|
+
pendingQuestions,
|
|
5815
|
+
pendingConfirmations
|
|
5816
|
+
});
|
|
5452
5817
|
});
|
|
5453
5818
|
app.delete("/api/sessions/:id", async (req, res) => {
|
|
5454
5819
|
const sessionId = req.params["id"];
|
|
@@ -5456,8 +5821,8 @@ async function createServerHandle(config3) {
|
|
|
5456
5821
|
if (!session) {
|
|
5457
5822
|
return res.status(404).json({ error: "Session not found" });
|
|
5458
5823
|
}
|
|
5459
|
-
const { stopSessionExecution } = await import("./chat-handler-
|
|
5460
|
-
const { cancelQuestionsForSession, cancelPathConfirmationsForSession } = await import("./tools-
|
|
5824
|
+
const { stopSessionExecution } = await import("./chat-handler-5ZHPYU24.js");
|
|
5825
|
+
const { cancelQuestionsForSession, cancelPathConfirmationsForSession } = await import("./tools-HGKUD327.js");
|
|
5461
5826
|
sessionManager.clearMessageQueue(sessionId);
|
|
5462
5827
|
stopSessionExecution(sessionId, sessionManager);
|
|
5463
5828
|
abortSession(sessionId);
|
|
@@ -5486,8 +5851,9 @@ async function createServerHandle(config3) {
|
|
|
5486
5851
|
res.json({ success: true });
|
|
5487
5852
|
});
|
|
5488
5853
|
app.post("/api/sessions/:id/provider", async (req, res) => {
|
|
5489
|
-
const { getEventStore: getEventStore2 } = await import("./events-
|
|
5490
|
-
const { buildMessagesFromStoredEvents } = await import("./folding-
|
|
5854
|
+
const { getEventStore: getEventStore2, combineEventsWithSnapshot: combineEv } = await import("./events-KNOZX7YG.js");
|
|
5855
|
+
const { buildMessagesFromStoredEvents } = await import("./folding-OPP2BVUB.js");
|
|
5856
|
+
const { getMaxVisibleItems } = await import("./settings-6M55N4Q2.js");
|
|
5491
5857
|
const sessionId = req.params.id;
|
|
5492
5858
|
const session = sessionManager.getSession(sessionId);
|
|
5493
5859
|
if (!session) {
|
|
@@ -5502,10 +5868,12 @@ async function createServerHandle(config3) {
|
|
|
5502
5868
|
sessionManager.setSessionProvider(sessionId, providerId, resolvedModel);
|
|
5503
5869
|
const contextState = sessionManager.getContextState(sessionId);
|
|
5504
5870
|
const eventStore = getEventStore2();
|
|
5505
|
-
const events = eventStore.
|
|
5506
|
-
const
|
|
5871
|
+
const { snapshot, events: eventsSinceSnapshot } = eventStore.getEventsSinceSnapshot(sessionId);
|
|
5872
|
+
const events = combineEv(sessionId, snapshot, eventsSinceSnapshot);
|
|
5873
|
+
const maxVisibleItems = getMaxVisibleItems();
|
|
5874
|
+
const { messages, hiddenCount } = buildMessagesFromStoredEvents(events, maxVisibleItems || void 0);
|
|
5507
5875
|
const updatedSession = sessionManager.getSession(sessionId);
|
|
5508
|
-
res.json({ session: updatedSession, messages, contextState });
|
|
5876
|
+
res.json({ session: updatedSession, messages, hiddenCount, contextState });
|
|
5509
5877
|
});
|
|
5510
5878
|
app.post("/api/default-model", async (req, res) => {
|
|
5511
5879
|
const { providerId, model } = req.body;
|
|
@@ -5520,7 +5888,7 @@ async function createServerHandle(config3) {
|
|
|
5520
5888
|
if (!result.success) {
|
|
5521
5889
|
return res.status(500).json({ error: result.error ?? "Failed to set default model" });
|
|
5522
5890
|
}
|
|
5523
|
-
const { loadGlobalConfig, saveGlobalConfig, setDefaultModelSelection } = await import("./config-
|
|
5891
|
+
const { loadGlobalConfig, saveGlobalConfig, setDefaultModelSelection } = await import("./config-MD74ETY5.js");
|
|
5524
5892
|
const globalConfig = await loadGlobalConfig(config3.mode ?? "production", config3.globalConfigPath);
|
|
5525
5893
|
const updatedConfig = setDefaultModelSelection(globalConfig, providerId, model);
|
|
5526
5894
|
await saveGlobalConfig(config3.mode ?? "production", updatedConfig, config3.globalConfigPath);
|
|
@@ -5598,8 +5966,9 @@ async function createServerHandle(config3) {
|
|
|
5598
5966
|
res.json({ success: true });
|
|
5599
5967
|
});
|
|
5600
5968
|
app.put("/api/sessions/:id/mode", async (req, res) => {
|
|
5601
|
-
const { getEventStore: getEventStore2 } = await import("./events-
|
|
5602
|
-
const { buildMessagesFromStoredEvents } = await import("./folding-
|
|
5969
|
+
const { getEventStore: getEventStore2, combineEventsWithSnapshot: combineEv } = await import("./events-KNOZX7YG.js");
|
|
5970
|
+
const { buildMessagesFromStoredEvents } = await import("./folding-OPP2BVUB.js");
|
|
5971
|
+
const { getMaxVisibleItems } = await import("./settings-6M55N4Q2.js");
|
|
5603
5972
|
const sessionId = req.params.id;
|
|
5604
5973
|
const session = sessionManager.getSession(sessionId);
|
|
5605
5974
|
if (!session) {
|
|
@@ -5616,10 +5985,12 @@ async function createServerHandle(config3) {
|
|
|
5616
5985
|
}
|
|
5617
5986
|
sessionManager.setMode(sessionId, mode);
|
|
5618
5987
|
const eventStore = getEventStore2();
|
|
5619
|
-
const events = eventStore.
|
|
5620
|
-
const
|
|
5988
|
+
const { snapshot, events: eventsSinceSnapshot } = eventStore.getEventsSinceSnapshot(sessionId);
|
|
5989
|
+
const events = combineEv(sessionId, snapshot, eventsSinceSnapshot);
|
|
5990
|
+
const maxVisibleItems = getMaxVisibleItems();
|
|
5991
|
+
const { messages, hiddenCount } = buildMessagesFromStoredEvents(events, maxVisibleItems || void 0);
|
|
5621
5992
|
const updatedSession = sessionManager.getSession(sessionId);
|
|
5622
|
-
res.json({ session: updatedSession, messages });
|
|
5993
|
+
res.json({ session: updatedSession, messages, hiddenCount });
|
|
5623
5994
|
});
|
|
5624
5995
|
app.put("/api/sessions/:id/danger-level", async (req, res) => {
|
|
5625
5996
|
const sessionId = req.params.id;
|
|
@@ -5652,29 +6023,50 @@ async function createServerHandle(config3) {
|
|
|
5652
6023
|
app.post("/api/sessions/:id/confirm-path", async (req, res) => {
|
|
5653
6024
|
const sessionId = req.params.id;
|
|
5654
6025
|
const { callId, approved, alwaysAllow } = req.body;
|
|
5655
|
-
if (!callId || approved
|
|
5656
|
-
return res.status(400).json({ error: "callId and approved are required" });
|
|
6026
|
+
if (!callId || typeof approved !== "boolean") {
|
|
6027
|
+
return res.status(400).json({ error: "callId and approved (boolean) are required" });
|
|
6028
|
+
}
|
|
6029
|
+
if (alwaysAllow !== void 0 && typeof alwaysAllow !== "boolean") {
|
|
6030
|
+
return res.status(400).json({ error: "alwaysAllow must be a boolean if provided" });
|
|
6031
|
+
}
|
|
6032
|
+
const { providePathConfirmation, getConfirmationSessionId } = await import("./tools-HGKUD327.js");
|
|
6033
|
+
const pendingSessionId = getConfirmationSessionId(callId);
|
|
6034
|
+
if (!pendingSessionId) {
|
|
6035
|
+
return res.status(404).json({ error: "No pending path confirmation with that ID" });
|
|
6036
|
+
}
|
|
6037
|
+
if (pendingSessionId !== sessionId) {
|
|
6038
|
+
return res.status(403).json({ error: "Confirmation does not belong to this session" });
|
|
5657
6039
|
}
|
|
5658
|
-
const { providePathConfirmation } = await import("./tools-JRCUWPJO.js");
|
|
5659
6040
|
const result = providePathConfirmation(callId, approved, alwaysAllow);
|
|
5660
6041
|
if (!result.found) {
|
|
5661
6042
|
return res.status(404).json({ error: "No pending path confirmation with that ID" });
|
|
5662
6043
|
}
|
|
5663
|
-
const { getEventStore: getEventStore2 } = await import("./events-
|
|
5664
|
-
const { buildMessagesFromStoredEvents, foldPendingConfirmations } = await import("./folding-
|
|
5665
|
-
const { createSessionStateMessage } = await import("./protocol-
|
|
5666
|
-
const { getPendingQuestionsForSession } = await import("./tools-
|
|
6044
|
+
const { getEventStore: getEventStore2, combineEventsWithSnapshot: combineEvents } = await import("./events-KNOZX7YG.js");
|
|
6045
|
+
const { buildMessagesFromStoredEvents, foldPendingConfirmations } = await import("./folding-OPP2BVUB.js");
|
|
6046
|
+
const { createSessionStateMessage } = await import("./protocol-Q7X4NEME.js");
|
|
6047
|
+
const { getPendingQuestionsForSession } = await import("./tools-HGKUD327.js");
|
|
6048
|
+
const { getMaxVisibleItems } = await import("./settings-6M55N4Q2.js");
|
|
5667
6049
|
const eventStore = getEventStore2();
|
|
5668
|
-
const events = eventStore.
|
|
5669
|
-
const
|
|
6050
|
+
const { snapshot, events: eventsSinceSnapshot } = eventStore.getEventsSinceSnapshot(sessionId);
|
|
6051
|
+
const events = combineEvents(sessionId, snapshot, eventsSinceSnapshot);
|
|
6052
|
+
const maxVisibleItems = getMaxVisibleItems();
|
|
6053
|
+
const { messages, hiddenCount } = buildMessagesFromStoredEvents(events, maxVisibleItems || void 0);
|
|
5670
6054
|
const pendingConfirmations = foldPendingConfirmations(events);
|
|
5671
6055
|
const pendingQuestions = getPendingQuestionsForSession(sessionId);
|
|
5672
6056
|
const session = sessionManager.getSession(sessionId);
|
|
5673
6057
|
if (session) {
|
|
5674
|
-
const stateMsg = createSessionStateMessage(
|
|
6058
|
+
const stateMsg = createSessionStateMessage(
|
|
6059
|
+
session,
|
|
6060
|
+
messages,
|
|
6061
|
+
pendingConfirmations,
|
|
6062
|
+
pendingQuestions,
|
|
6063
|
+
void 0,
|
|
6064
|
+
void 0,
|
|
6065
|
+
hiddenCount
|
|
6066
|
+
);
|
|
5675
6067
|
wssExports.broadcastForSession(sessionId, { ...stateMsg, sessionId });
|
|
5676
6068
|
}
|
|
5677
|
-
wssExports.
|
|
6069
|
+
wssExports.broadcastForSession(sessionId, {
|
|
5678
6070
|
type: "session.confirmation_resolved",
|
|
5679
6071
|
sessionId,
|
|
5680
6072
|
payload: { sessionId, callId }
|
|
@@ -5689,7 +6081,7 @@ async function createServerHandle(config3) {
|
|
|
5689
6081
|
if (!skip && typeof answer !== "string") {
|
|
5690
6082
|
return res.status(400).json({ error: "answer is required when not skipping" });
|
|
5691
6083
|
}
|
|
5692
|
-
const { provideAnswer } = await import("./tools-
|
|
6084
|
+
const { provideAnswer } = await import("./tools-HGKUD327.js");
|
|
5693
6085
|
const found = provideAnswer(callId, answer ?? "", skip ?? false);
|
|
5694
6086
|
if (!found) {
|
|
5695
6087
|
return res.status(404).json({ error: "No pending question with that ID" });
|
|
@@ -5717,7 +6109,7 @@ async function createServerHandle(config3) {
|
|
|
5717
6109
|
if (!session) {
|
|
5718
6110
|
return res.status(404).json({ error: "Session not found" });
|
|
5719
6111
|
}
|
|
5720
|
-
const { getSetting: getSetting2, SETTINGS_KEYS } = await import("./settings-
|
|
6112
|
+
const { getSetting: getSetting2, SETTINGS_KEYS } = await import("./settings-6M55N4Q2.js");
|
|
5721
6113
|
if (getSetting2(SETTINGS_KEYS.CACHE_WARMING) !== "true") {
|
|
5722
6114
|
return res.json({ success: false, reason: "disabled" });
|
|
5723
6115
|
}
|
|
@@ -5749,7 +6141,7 @@ async function createServerHandle(config3) {
|
|
|
5749
6141
|
backend: activeProvider?.backend ?? llmClient.getBackend(),
|
|
5750
6142
|
model: llmClient.getModel()
|
|
5751
6143
|
};
|
|
5752
|
-
const { runAgentTurn, TurnMetrics } = await import("./orchestrator-
|
|
6144
|
+
const { runAgentTurn, TurnMetrics } = await import("./orchestrator-L6LX5BV7.js");
|
|
5753
6145
|
runAgentTurn(
|
|
5754
6146
|
{
|
|
5755
6147
|
sessionManager,
|
|
@@ -5787,15 +6179,15 @@ async function createServerHandle(config3) {
|
|
|
5787
6179
|
if (!session) {
|
|
5788
6180
|
return res.status(404).json({ error: "Session not found" });
|
|
5789
6181
|
}
|
|
5790
|
-
const { stopSessionExecution } = await import("./chat-handler-
|
|
5791
|
-
const { cancelQuestionsForSession, cancelPathConfirmationsForSession } = await import("./tools-
|
|
6182
|
+
const { stopSessionExecution } = await import("./chat-handler-5ZHPYU24.js");
|
|
6183
|
+
const { cancelQuestionsForSession, cancelPathConfirmationsForSession } = await import("./tools-HGKUD327.js");
|
|
5792
6184
|
const queuedMessages = sessionManager.getQueueState(sessionId);
|
|
5793
6185
|
sessionManager.clearMessageQueue(sessionId);
|
|
5794
6186
|
stopSessionExecution(sessionId, sessionManager);
|
|
5795
6187
|
abortSession(sessionId);
|
|
5796
6188
|
cancelQuestionsForSession(sessionId, "Session stopped by user");
|
|
5797
6189
|
cancelPathConfirmationsForSession(sessionId, "Session stopped by user");
|
|
5798
|
-
const eventStore = (await import("./events-
|
|
6190
|
+
const eventStore = (await import("./events-KNOZX7YG.js")).getEventStore();
|
|
5799
6191
|
eventStore.append(sessionId, { type: "running.changed", data: { isRunning: false } });
|
|
5800
6192
|
res.json({ success: true, queuedMessages });
|
|
5801
6193
|
});
|
|
@@ -5809,7 +6201,7 @@ async function createServerHandle(config3) {
|
|
|
5809
6201
|
if (typeof messageIndex !== "number" || messageIndex < 0) {
|
|
5810
6202
|
return res.status(400).json({ error: "messageIndex must be a non-negative number" });
|
|
5811
6203
|
}
|
|
5812
|
-
const { truncateSessionMessages } = await import("./events-
|
|
6204
|
+
const { truncateSessionMessages } = await import("./events-KNOZX7YG.js");
|
|
5813
6205
|
truncateSessionMessages(sessionId, messageIndex);
|
|
5814
6206
|
res.json({ success: true });
|
|
5815
6207
|
});
|
|
@@ -5826,11 +6218,11 @@ async function createServerHandle(config3) {
|
|
|
5826
6218
|
if (content !== void 0 && (typeof content !== "string" || !content.trim())) {
|
|
5827
6219
|
return res.status(400).json({ error: "content must be a non-empty string if provided" });
|
|
5828
6220
|
}
|
|
5829
|
-
const { getEventStore: getEventStore2 } = await import("./events-
|
|
5830
|
-
const { buildMessagesFromStoredEvents } = await import("./folding-
|
|
6221
|
+
const { getEventStore: getEventStore2 } = await import("./events-KNOZX7YG.js");
|
|
6222
|
+
const { buildMessagesFromStoredEvents } = await import("./folding-OPP2BVUB.js");
|
|
5831
6223
|
const eventStore = getEventStore2();
|
|
5832
6224
|
const events = eventStore.getEvents(sessionId);
|
|
5833
|
-
const messages = buildMessagesFromStoredEvents(events);
|
|
6225
|
+
const { messages } = buildMessagesFromStoredEvents(events);
|
|
5834
6226
|
const msgIndex = messages.findIndex((m) => m.id === messageId);
|
|
5835
6227
|
if (msgIndex === -1) {
|
|
5836
6228
|
return res.status(400).json({ error: "Message not found" });
|
|
@@ -5839,7 +6231,7 @@ async function createServerHandle(config3) {
|
|
|
5839
6231
|
if (msg.role !== "user" || msg.isSystemGenerated) {
|
|
5840
6232
|
return res.status(400).json({ error: "Can only replay user messages" });
|
|
5841
6233
|
}
|
|
5842
|
-
const { truncateSessionMessages } = await import("./events-
|
|
6234
|
+
const { truncateSessionMessages } = await import("./events-KNOZX7YG.js");
|
|
5843
6235
|
truncateSessionMessages(sessionId, msgIndex - 1);
|
|
5844
6236
|
sessionManager.queueMessage(sessionId, "asap", content ?? msg.content, msg.attachments, msg.messageKind);
|
|
5845
6237
|
res.json({ success: true });
|
|
@@ -5871,7 +6263,7 @@ async function createServerHandle(config3) {
|
|
|
5871
6263
|
res.json({ accepted: true });
|
|
5872
6264
|
});
|
|
5873
6265
|
app.get("/api/settings", async (req, res) => {
|
|
5874
|
-
const { getSetting: getSetting2, SETTINGS_DEFAULTS } = await import("./settings-
|
|
6266
|
+
const { getSetting: getSetting2, SETTINGS_DEFAULTS } = await import("./settings-6M55N4Q2.js");
|
|
5875
6267
|
const keysParam = req.query["keys"];
|
|
5876
6268
|
if (!keysParam) {
|
|
5877
6269
|
return res.status(400).json({ error: "keys query parameter is required" });
|
|
@@ -5884,19 +6276,19 @@ async function createServerHandle(config3) {
|
|
|
5884
6276
|
res.json(result);
|
|
5885
6277
|
});
|
|
5886
6278
|
app.get("/api/settings/:key", async (req, res) => {
|
|
5887
|
-
const { getSetting: getSetting2, SETTINGS_DEFAULTS } = await import("./settings-
|
|
6279
|
+
const { getSetting: getSetting2, SETTINGS_DEFAULTS } = await import("./settings-6M55N4Q2.js");
|
|
5888
6280
|
const key = req.params.key;
|
|
5889
6281
|
const value = getSetting2(key) ?? SETTINGS_DEFAULTS[key] ?? null;
|
|
5890
6282
|
res.json({ key, value });
|
|
5891
6283
|
});
|
|
5892
6284
|
app.get("/api/settings/:key", async (req, res) => {
|
|
5893
|
-
const { getSetting: getSetting2, SETTINGS_DEFAULTS } = await import("./settings-
|
|
6285
|
+
const { getSetting: getSetting2, SETTINGS_DEFAULTS } = await import("./settings-6M55N4Q2.js");
|
|
5894
6286
|
const key = req.params.key;
|
|
5895
6287
|
const value = getSetting2(key) ?? SETTINGS_DEFAULTS[key] ?? null;
|
|
5896
6288
|
res.json({ key, value });
|
|
5897
6289
|
});
|
|
5898
6290
|
app.put("/api/settings/:key", async (req, res) => {
|
|
5899
|
-
const { setSetting: setSetting2 } = await import("./settings-
|
|
6291
|
+
const { setSetting: setSetting2 } = await import("./settings-6M55N4Q2.js");
|
|
5900
6292
|
const key = req.params.key;
|
|
5901
6293
|
const { value } = req.body;
|
|
5902
6294
|
if (value === void 0) {
|
|
@@ -5908,14 +6300,14 @@ async function createServerHandle(config3) {
|
|
|
5908
6300
|
app.get("/api/tools/rtk-check", async (_req, res) => {
|
|
5909
6301
|
const { spawn: spawn3 } = await import("child_process");
|
|
5910
6302
|
try {
|
|
5911
|
-
const available = await new Promise((
|
|
6303
|
+
const available = await new Promise((resolve9) => {
|
|
5912
6304
|
const proc = spawn3("rtk", ["--version"], { stdio: ["ignore", "pipe", "pipe"] });
|
|
5913
6305
|
let out = "";
|
|
5914
6306
|
proc.stdout?.on("data", (d) => {
|
|
5915
6307
|
out += d.toString();
|
|
5916
6308
|
});
|
|
5917
|
-
proc.on("error", () =>
|
|
5918
|
-
proc.on("close", (code) =>
|
|
6309
|
+
proc.on("error", () => resolve9(false));
|
|
6310
|
+
proc.on("close", (code) => resolve9(code === 0 && out.startsWith("rtk ")));
|
|
5919
6311
|
});
|
|
5920
6312
|
res.json({ available });
|
|
5921
6313
|
} catch {
|
|
@@ -5923,7 +6315,7 @@ async function createServerHandle(config3) {
|
|
|
5923
6315
|
}
|
|
5924
6316
|
});
|
|
5925
6317
|
app.get("/api/tools/shells", async (_req, res) => {
|
|
5926
|
-
const { listAvailableShells } = await import("./platform-
|
|
6318
|
+
const { listAvailableShells } = await import("./platform-VBNNMTR5.js");
|
|
5927
6319
|
res.json({ shells: listAvailableShells() });
|
|
5928
6320
|
});
|
|
5929
6321
|
app.get("/api/config", async (_req, res) => {
|
|
@@ -5932,7 +6324,7 @@ async function createServerHandle(config3) {
|
|
|
5932
6324
|
let visionFallback;
|
|
5933
6325
|
let globalWorkdir;
|
|
5934
6326
|
try {
|
|
5935
|
-
const { loadGlobalConfig, getVisionFallback } = await import("./config-
|
|
6327
|
+
const { loadGlobalConfig, getVisionFallback } = await import("./config-MD74ETY5.js");
|
|
5936
6328
|
const globalConfig = await loadGlobalConfig(config3.mode ?? "production", config3.globalConfigPath);
|
|
5937
6329
|
const fallback = getVisionFallback(globalConfig);
|
|
5938
6330
|
if (fallback) {
|
|
@@ -6086,7 +6478,7 @@ async function createServerHandle(config3) {
|
|
|
6086
6478
|
const backend = req.query["backend"];
|
|
6087
6479
|
if (!url) return res.status(400).json({ error: "url is required" });
|
|
6088
6480
|
try {
|
|
6089
|
-
const { fetchModelsWithContext } = await import("./provider-manager-
|
|
6481
|
+
const { fetchModelsWithContext } = await import("./provider-manager-PD3BXUHY.js");
|
|
6090
6482
|
const { getModelProfile: getModelProfile2 } = await import("./profiles-5J7F4BML.js");
|
|
6091
6483
|
const models = await fetchModelsWithContext(
|
|
6092
6484
|
url,
|
|
@@ -6156,7 +6548,7 @@ async function createServerHandle(config3) {
|
|
|
6156
6548
|
}
|
|
6157
6549
|
const { getModelProfile: getModelProfile2 } = await import("./profiles-5J7F4BML.js");
|
|
6158
6550
|
const { getBackendCapabilities } = await import("./backend-P3GHHLHJ.js");
|
|
6159
|
-
const { buildNonStreamingCreateParams } = await import("./client-pure-
|
|
6551
|
+
const { buildNonStreamingCreateParams } = await import("./client-pure-5YE5WFJP.js");
|
|
6160
6552
|
const { OpenAIHttpClient } = await import("./http-client-PIWB7BXK.js");
|
|
6161
6553
|
const { ensureVersionPrefix } = await import("./url-utils-SAJP7AEX.js");
|
|
6162
6554
|
const profile = getModelProfile2(model);
|
|
@@ -6226,7 +6618,7 @@ async function createServerHandle(config3) {
|
|
|
6226
6618
|
return res.status(400).json({ error: "name, url, and backend are required" });
|
|
6227
6619
|
}
|
|
6228
6620
|
try {
|
|
6229
|
-
const { loadGlobalConfig, saveGlobalConfig, addProvider, setDefaultModelSelection } = await import("./config-
|
|
6621
|
+
const { loadGlobalConfig, saveGlobalConfig, addProvider, setDefaultModelSelection } = await import("./config-MD74ETY5.js");
|
|
6230
6622
|
const globalConfig = await loadGlobalConfig(config3.mode ?? "production", config3.globalConfigPath);
|
|
6231
6623
|
const providerBackend = backend;
|
|
6232
6624
|
const providerModels = modelConfigs?.length ? buildModelConfigs(modelConfigs) : model ? [{ id: model, contextWindow: 2e5, source: "user" }] : [];
|
|
@@ -6266,7 +6658,7 @@ async function createServerHandle(config3) {
|
|
|
6266
6658
|
app.post("/api/init/config", async (req, res) => {
|
|
6267
6659
|
const { workdir, visionFallback } = req.body;
|
|
6268
6660
|
try {
|
|
6269
|
-
const { loadGlobalConfig, saveGlobalConfig } = await import("./config-
|
|
6661
|
+
const { loadGlobalConfig, saveGlobalConfig } = await import("./config-MD74ETY5.js");
|
|
6270
6662
|
const globalConfig = await loadGlobalConfig(config3.mode ?? "production", config3.globalConfigPath);
|
|
6271
6663
|
const updatedConfig = {
|
|
6272
6664
|
...globalConfig,
|
|
@@ -6305,7 +6697,7 @@ async function createServerHandle(config3) {
|
|
|
6305
6697
|
});
|
|
6306
6698
|
app.delete("/api/providers/:id", async (req, res) => {
|
|
6307
6699
|
const { id } = req.params;
|
|
6308
|
-
const { loadGlobalConfig, saveGlobalConfig, removeProvider } = await import("./config-
|
|
6700
|
+
const { loadGlobalConfig, saveGlobalConfig, removeProvider } = await import("./config-MD74ETY5.js");
|
|
6309
6701
|
const globalConfig = await loadGlobalConfig(config3.mode ?? "production", config3.globalConfigPath);
|
|
6310
6702
|
const updatedConfig = removeProvider(globalConfig, id);
|
|
6311
6703
|
await saveGlobalConfig(config3.mode ?? "production", updatedConfig, config3.globalConfigPath);
|
|
@@ -6317,7 +6709,7 @@ async function createServerHandle(config3) {
|
|
|
6317
6709
|
const { id } = req.params;
|
|
6318
6710
|
const { isLocal } = req.body;
|
|
6319
6711
|
try {
|
|
6320
|
-
const { loadGlobalConfig, saveGlobalConfig, updateProvider } = await import("./config-
|
|
6712
|
+
const { loadGlobalConfig, saveGlobalConfig, updateProvider } = await import("./config-MD74ETY5.js");
|
|
6321
6713
|
const globalConfig = await loadGlobalConfig(config3.mode ?? "production", config3.globalConfigPath);
|
|
6322
6714
|
const provider = globalConfig.providers.find((p) => p.id === id);
|
|
6323
6715
|
if (!provider) {
|
|
@@ -6348,7 +6740,7 @@ async function createServerHandle(config3) {
|
|
|
6348
6740
|
transportAdapter
|
|
6349
6741
|
} = req.body;
|
|
6350
6742
|
try {
|
|
6351
|
-
const { loadGlobalConfig, saveGlobalConfig, updateProvider } = await import("./config-
|
|
6743
|
+
const { loadGlobalConfig, saveGlobalConfig, updateProvider } = await import("./config-MD74ETY5.js");
|
|
6352
6744
|
const globalConfig = await loadGlobalConfig(config3.mode ?? "production", config3.globalConfigPath);
|
|
6353
6745
|
const provider = globalConfig.providers.find((p) => p.id === id);
|
|
6354
6746
|
if (!provider) {
|
|
@@ -6388,7 +6780,7 @@ async function createServerHandle(config3) {
|
|
|
6388
6780
|
return res.status(400).json({ error: result.error });
|
|
6389
6781
|
}
|
|
6390
6782
|
const llmClient = getLLMClient();
|
|
6391
|
-
const { loadGlobalConfig, saveGlobalConfig, setDefaultModelSelection } = await import("./config-
|
|
6783
|
+
const { loadGlobalConfig, saveGlobalConfig, setDefaultModelSelection } = await import("./config-MD74ETY5.js");
|
|
6392
6784
|
const globalConfig = await loadGlobalConfig(config3.mode ?? "production", config3.globalConfigPath);
|
|
6393
6785
|
const updatedConfig = setDefaultModelSelection(globalConfig, id, llmClient.getModel());
|
|
6394
6786
|
await saveGlobalConfig(config3.mode ?? "production", updatedConfig, config3.globalConfigPath);
|
|
@@ -6415,7 +6807,7 @@ async function createServerHandle(config3) {
|
|
|
6415
6807
|
});
|
|
6416
6808
|
async function rebuildMcpTools() {
|
|
6417
6809
|
const { createMcpTools: createMcpTools2 } = await import("./tool-adapter-MOGEI6TP.js");
|
|
6418
|
-
const { setMcpTools: setMcpTools2 } = await import("./tools-
|
|
6810
|
+
const { setMcpTools: setMcpTools2 } = await import("./tools-HGKUD327.js");
|
|
6419
6811
|
const mcpTools = createMcpTools2(mcpManager);
|
|
6420
6812
|
setMcpTools2(mcpTools);
|
|
6421
6813
|
}
|
|
@@ -6424,7 +6816,7 @@ async function createServerHandle(config3) {
|
|
|
6424
6816
|
res.json({ servers });
|
|
6425
6817
|
});
|
|
6426
6818
|
app.post("/api/mcp/servers/test", async (req, res) => {
|
|
6427
|
-
const { name, transport, command, args, env, url, headers } = req.body;
|
|
6819
|
+
const { name, transport, command, args, env, url, headers, timeout } = req.body;
|
|
6428
6820
|
if (transport !== void 0 && transport !== "stdio" && transport !== "http") {
|
|
6429
6821
|
return res.status(400).json({ error: `Invalid transport '${transport}'. Must be 'stdio' or 'http'.` });
|
|
6430
6822
|
}
|
|
@@ -6434,6 +6826,9 @@ async function createServerHandle(config3) {
|
|
|
6434
6826
|
if (transport === "http" && !url) {
|
|
6435
6827
|
return res.status(400).json({ error: "url is required for http transport" });
|
|
6436
6828
|
}
|
|
6829
|
+
if (timeout !== void 0 && (typeof timeout !== "number" || timeout <= 0)) {
|
|
6830
|
+
return res.status(400).json({ error: "timeout must be a positive number" });
|
|
6831
|
+
}
|
|
6437
6832
|
try {
|
|
6438
6833
|
const testManager = new McpManager();
|
|
6439
6834
|
const resolvedTransport = transport === "http" ? "http" : "stdio";
|
|
@@ -6443,7 +6838,8 @@ async function createServerHandle(config3) {
|
|
|
6443
6838
|
...args && args.length > 0 ? { args } : {},
|
|
6444
6839
|
...env && Object.keys(env).length > 0 ? { env } : {},
|
|
6445
6840
|
...url ? { url } : {},
|
|
6446
|
-
...headers && Object.keys(headers).length > 0 ? { headers } : {}
|
|
6841
|
+
...headers && Object.keys(headers).length > 0 ? { headers } : {},
|
|
6842
|
+
...timeout !== void 0 ? { timeout } : {}
|
|
6447
6843
|
};
|
|
6448
6844
|
await testManager.addServer(name ?? "test", testConfig);
|
|
6449
6845
|
const server = testManager.getServer(name ?? "test");
|
|
@@ -6458,13 +6854,16 @@ async function createServerHandle(config3) {
|
|
|
6458
6854
|
}
|
|
6459
6855
|
});
|
|
6460
6856
|
app.post("/api/mcp/servers", async (req, res) => {
|
|
6461
|
-
const { name, transport, command, args, env, url, headers } = req.body;
|
|
6857
|
+
const { name, transport, command, args, env, url, headers, timeout } = req.body;
|
|
6462
6858
|
if (!name) {
|
|
6463
6859
|
return res.status(400).json({ error: "name is required" });
|
|
6464
6860
|
}
|
|
6465
6861
|
if (transport !== void 0 && transport !== "stdio" && transport !== "http") {
|
|
6466
6862
|
return res.status(400).json({ error: `Invalid transport '${transport}'. Must be 'stdio' or 'http'.` });
|
|
6467
6863
|
}
|
|
6864
|
+
if (timeout !== void 0 && (typeof timeout !== "number" || timeout <= 0)) {
|
|
6865
|
+
return res.status(400).json({ error: "timeout must be a positive number" });
|
|
6866
|
+
}
|
|
6468
6867
|
try {
|
|
6469
6868
|
const resolvedTransport = transport === "http" ? "http" : "stdio";
|
|
6470
6869
|
const serverCfg = {
|
|
@@ -6473,11 +6872,12 @@ async function createServerHandle(config3) {
|
|
|
6473
6872
|
...args && args.length > 0 ? { args } : {},
|
|
6474
6873
|
...env && Object.keys(env).length > 0 ? { env } : {},
|
|
6475
6874
|
...url ? { url } : {},
|
|
6476
|
-
...headers && Object.keys(headers).length > 0 ? { headers } : {}
|
|
6875
|
+
...headers && Object.keys(headers).length > 0 ? { headers } : {},
|
|
6876
|
+
...timeout !== void 0 ? { timeout } : {}
|
|
6477
6877
|
};
|
|
6478
6878
|
await mcpManager.addServer(name, serverCfg);
|
|
6479
6879
|
const server = mcpManager.getServer(name);
|
|
6480
|
-
const { loadGlobalConfig, saveGlobalConfig } = await import("./config-
|
|
6880
|
+
const { loadGlobalConfig, saveGlobalConfig } = await import("./config-MD74ETY5.js");
|
|
6481
6881
|
const globalConfig = await loadGlobalConfig(config3.mode ?? "production", config3.globalConfigPath);
|
|
6482
6882
|
const updatedMcpServers = { ...globalConfig.mcpServers ?? {}, [name]: serverCfg };
|
|
6483
6883
|
await saveGlobalConfig(
|
|
@@ -6507,7 +6907,7 @@ async function createServerHandle(config3) {
|
|
|
6507
6907
|
return res.status(404).json({ error: `MCP server '${name}' not found` });
|
|
6508
6908
|
}
|
|
6509
6909
|
const body = req.body;
|
|
6510
|
-
const { transport: rawTransport, command, args, env, url, headers } = body;
|
|
6910
|
+
const { transport: rawTransport, command, args, env, url, headers, timeout } = body;
|
|
6511
6911
|
if (rawTransport !== void 0 && rawTransport !== "stdio" && rawTransport !== "http") {
|
|
6512
6912
|
return res.status(400).json({ error: `Invalid transport '${String(rawTransport)}'. Must be 'stdio' or 'http'.` });
|
|
6513
6913
|
}
|
|
@@ -6526,9 +6926,12 @@ async function createServerHandle(config3) {
|
|
|
6526
6926
|
if (headers !== void 0 && (typeof headers !== "object" || headers === null || Array.isArray(headers) || Object.values(headers).some((v) => typeof v !== "string"))) {
|
|
6527
6927
|
return res.status(400).json({ error: "headers must be a string/string object" });
|
|
6528
6928
|
}
|
|
6929
|
+
if (timeout !== void 0 && (typeof timeout !== "number" || timeout <= 0)) {
|
|
6930
|
+
return res.status(400).json({ error: "timeout must be a positive number" });
|
|
6931
|
+
}
|
|
6529
6932
|
try {
|
|
6530
|
-
const { loadGlobalConfig, saveGlobalConfig } = await import("./config-
|
|
6531
|
-
const { applyMcpServerUpdate } = await import("./update-server-
|
|
6933
|
+
const { loadGlobalConfig, saveGlobalConfig } = await import("./config-MD74ETY5.js");
|
|
6934
|
+
const { applyMcpServerUpdate } = await import("./update-server-V6GJ43WH.js");
|
|
6532
6935
|
const globalConfig = await loadGlobalConfig(config3.mode ?? "production", config3.globalConfigPath);
|
|
6533
6936
|
const mcpServers2 = { ...globalConfig.mcpServers ?? {} };
|
|
6534
6937
|
const patch = {
|
|
@@ -6537,7 +6940,8 @@ async function createServerHandle(config3) {
|
|
|
6537
6940
|
...args !== void 0 ? { args } : {},
|
|
6538
6941
|
...env !== void 0 ? { env } : {},
|
|
6539
6942
|
...url !== void 0 ? { url } : {},
|
|
6540
|
-
...headers !== void 0 ? { headers } : {}
|
|
6943
|
+
...headers !== void 0 ? { headers } : {},
|
|
6944
|
+
...timeout !== void 0 ? { timeout } : {}
|
|
6541
6945
|
};
|
|
6542
6946
|
const { error: updateError } = await applyMcpServerUpdate({
|
|
6543
6947
|
name,
|
|
@@ -6570,7 +6974,7 @@ async function createServerHandle(config3) {
|
|
|
6570
6974
|
return res.status(404).json({ error: `MCP server '${name}' not found` });
|
|
6571
6975
|
}
|
|
6572
6976
|
mcpManager.removeServer(name);
|
|
6573
|
-
const { loadGlobalConfig, saveGlobalConfig } = await import("./config-
|
|
6977
|
+
const { loadGlobalConfig, saveGlobalConfig } = await import("./config-MD74ETY5.js");
|
|
6574
6978
|
const globalConfig = await loadGlobalConfig(config3.mode ?? "production", config3.globalConfigPath);
|
|
6575
6979
|
const updatedMcpServers = { ...globalConfig.mcpServers ?? {} };
|
|
6576
6980
|
delete updatedMcpServers[name];
|
|
@@ -6599,7 +7003,7 @@ async function createServerHandle(config3) {
|
|
|
6599
7003
|
await mcpManager.setToolEnabled(name, toolName, enabled);
|
|
6600
7004
|
const server = mcpManager.getServer(name);
|
|
6601
7005
|
if (server) {
|
|
6602
|
-
const { loadGlobalConfig, saveGlobalConfig } = await import("./config-
|
|
7006
|
+
const { loadGlobalConfig, saveGlobalConfig } = await import("./config-MD74ETY5.js");
|
|
6603
7007
|
const globalConfig = await loadGlobalConfig(config3.mode ?? "production", config3.globalConfigPath);
|
|
6604
7008
|
const mcpServers2 = { ...globalConfig.mcpServers ?? {} };
|
|
6605
7009
|
const serverCfg = mcpServers2[name];
|
|
@@ -6650,13 +7054,13 @@ async function createServerHandle(config3) {
|
|
|
6650
7054
|
})
|
|
6651
7055
|
);
|
|
6652
7056
|
app.get("/api/sessions/:id/background-processes", async (req, res) => {
|
|
6653
|
-
const { getSessionProcesses } = await import("./manager-
|
|
7057
|
+
const { getSessionProcesses } = await import("./manager-ATWZUL3O.js");
|
|
6654
7058
|
const sessionId = req.params.id;
|
|
6655
7059
|
const processes = getSessionProcesses(sessionId);
|
|
6656
7060
|
res.json({ processes });
|
|
6657
7061
|
});
|
|
6658
7062
|
app.post("/api/sessions/:id/background-process/:processId/stop", async (req, res) => {
|
|
6659
|
-
const { stopProcess } = await import("./manager-
|
|
7063
|
+
const { stopProcess } = await import("./manager-ATWZUL3O.js");
|
|
6660
7064
|
const sessionId = req.params.id;
|
|
6661
7065
|
const processId = req.params.processId;
|
|
6662
7066
|
const session = sessionManager.getSession(sessionId);
|
|
@@ -6676,14 +7080,14 @@ async function createServerHandle(config3) {
|
|
|
6676
7080
|
});
|
|
6677
7081
|
app.use("/api/directories", createDirectoryRoutes());
|
|
6678
7082
|
app.use("/api/files", createFileSearchRoutes());
|
|
6679
|
-
const webDir =
|
|
7083
|
+
const webDir = resolve8(__dirname3, "../../web");
|
|
6680
7084
|
const isDev = config3.mode === "development";
|
|
6681
7085
|
let viteServer;
|
|
6682
7086
|
if (isDev) {
|
|
6683
7087
|
logger.info("Dev mode: using Vite middleware");
|
|
6684
7088
|
viteServer = await createViteServer({
|
|
6685
7089
|
root: webDir,
|
|
6686
|
-
configFile:
|
|
7090
|
+
configFile: resolve8(__dirname3, "../../web/vite.config.ts"),
|
|
6687
7091
|
server: { middlewareMode: true },
|
|
6688
7092
|
appType: "spa",
|
|
6689
7093
|
logLevel: "warn"
|
|
@@ -6703,7 +7107,7 @@ async function createServerHandle(config3) {
|
|
|
6703
7107
|
}
|
|
6704
7108
|
});
|
|
6705
7109
|
app.get("/fox.svg", (_req, res) => {
|
|
6706
|
-
readFile4(
|
|
7110
|
+
readFile4(join10(webDir, "fox.svg")).then((content) => {
|
|
6707
7111
|
res.set("Content-Type", "image/svg+xml");
|
|
6708
7112
|
res.send(content);
|
|
6709
7113
|
}).catch(() => {
|
|
@@ -6712,7 +7116,7 @@ async function createServerHandle(config3) {
|
|
|
6712
7116
|
});
|
|
6713
7117
|
app.use(
|
|
6714
7118
|
"/sounds",
|
|
6715
|
-
express.static(
|
|
7119
|
+
express.static(join10(webDir, "public", "sounds"), {
|
|
6716
7120
|
setHeaders: (res) => {
|
|
6717
7121
|
res.set("Content-Type", "audio/mpeg");
|
|
6718
7122
|
}
|
|
@@ -6721,13 +7125,13 @@ async function createServerHandle(config3) {
|
|
|
6721
7125
|
app.use("/__inspect__.js", (_req, res) => {
|
|
6722
7126
|
res.set("Access-Control-Allow-Origin", "*");
|
|
6723
7127
|
res.set("Content-Type", "application/javascript");
|
|
6724
|
-
readFile4(
|
|
7128
|
+
readFile4(join10(webDir, "public", "__inspect__.js")).then((content) => res.send(content)).catch(() => res.status(404).send("Not found"));
|
|
6725
7129
|
});
|
|
6726
7130
|
app.get("/*path", (req, res) => {
|
|
6727
7131
|
if (req.path.startsWith("/api/")) {
|
|
6728
7132
|
return;
|
|
6729
7133
|
}
|
|
6730
|
-
readFile4(
|
|
7134
|
+
readFile4(join10(webDir, "index.html"), "utf-8").then((indexHtml) => viteServer.transformIndexHtml(req.originalUrl, indexHtml)).then((transformed) => res.send(transformed)).catch((err) => {
|
|
6731
7135
|
logger.error("Error serving index.html", { error: err });
|
|
6732
7136
|
res.status(500).send("Server error");
|
|
6733
7137
|
});
|
|
@@ -6735,10 +7139,10 @@ async function createServerHandle(config3) {
|
|
|
6735
7139
|
logger.info("Vite middleware ready", { port: config3.server.port });
|
|
6736
7140
|
}
|
|
6737
7141
|
if (!isDev) {
|
|
6738
|
-
const distWebDir =
|
|
7142
|
+
const distWebDir = resolve8(__dirname3, "web");
|
|
6739
7143
|
app.use(
|
|
6740
7144
|
"/assets",
|
|
6741
|
-
express.static(
|
|
7145
|
+
express.static(join10(distWebDir, "assets"), {
|
|
6742
7146
|
setHeaders: (res, filepath) => {
|
|
6743
7147
|
if (filepath.endsWith(".css")) {
|
|
6744
7148
|
res.set("Content-Type", "text/css");
|
|
@@ -6746,11 +7150,11 @@ async function createServerHandle(config3) {
|
|
|
6746
7150
|
}
|
|
6747
7151
|
})
|
|
6748
7152
|
);
|
|
6749
|
-
app.use("/manifest.webmanifest", express.static(
|
|
6750
|
-
app.use("/registerSW.js", express.static(
|
|
6751
|
-
app.use("/sw.js", express.static(
|
|
7153
|
+
app.use("/manifest.webmanifest", express.static(join10(distWebDir, "manifest.webmanifest")));
|
|
7154
|
+
app.use("/registerSW.js", express.static(join10(distWebDir, "registerSW.js")));
|
|
7155
|
+
app.use("/sw.js", express.static(join10(distWebDir, "sw.js")));
|
|
6752
7156
|
app.get("/fox.svg", (_req, res) => {
|
|
6753
|
-
readFile4(
|
|
7157
|
+
readFile4(join10(distWebDir, "fox.svg")).then((content) => {
|
|
6754
7158
|
res.set("Content-Type", "image/svg+xml");
|
|
6755
7159
|
res.send(content);
|
|
6756
7160
|
}).catch(() => {
|
|
@@ -6759,7 +7163,7 @@ async function createServerHandle(config3) {
|
|
|
6759
7163
|
});
|
|
6760
7164
|
app.use(
|
|
6761
7165
|
"/sounds",
|
|
6762
|
-
express.static(
|
|
7166
|
+
express.static(join10(distWebDir, "sounds"), {
|
|
6763
7167
|
setHeaders: (res) => {
|
|
6764
7168
|
res.set("Content-Type", "audio/mpeg");
|
|
6765
7169
|
}
|
|
@@ -6768,10 +7172,10 @@ async function createServerHandle(config3) {
|
|
|
6768
7172
|
app.use("/__inspect__.js", (_req, res) => {
|
|
6769
7173
|
res.set("Access-Control-Allow-Origin", "*");
|
|
6770
7174
|
res.set("Content-Type", "application/javascript");
|
|
6771
|
-
readFile4(
|
|
7175
|
+
readFile4(join10(distWebDir, "__inspect__.js")).then((content) => res.send(content)).catch(() => res.status(404).send("Not found"));
|
|
6772
7176
|
});
|
|
6773
7177
|
app.get("/", (_req, res) => {
|
|
6774
|
-
readFile4(
|
|
7178
|
+
readFile4(join10(distWebDir, "index.html"), "utf-8").then((content) => res.send(content)).catch(() => {
|
|
6775
7179
|
res.status(404).send("Web UI not built. Run `npm run build:web`");
|
|
6776
7180
|
});
|
|
6777
7181
|
});
|
|
@@ -6779,7 +7183,7 @@ async function createServerHandle(config3) {
|
|
|
6779
7183
|
if (req.path.startsWith("/api/") || req.path.startsWith("/assets/") || req.path.startsWith("/sounds/") || req.path.startsWith("/manifest.webmanifest") || req.path.startsWith("/registerSW.js") || req.path.startsWith("/sw.js") || req.path === "/fox.svg") {
|
|
6780
7184
|
return;
|
|
6781
7185
|
}
|
|
6782
|
-
readFile4(
|
|
7186
|
+
readFile4(join10(distWebDir, "index.html"), "utf-8").then((content) => res.send(content)).catch(() => {
|
|
6783
7187
|
res.status(404).send("Web UI not built");
|
|
6784
7188
|
});
|
|
6785
7189
|
});
|
|
@@ -6799,7 +7203,7 @@ async function createServerHandle(config3) {
|
|
|
6799
7203
|
const state = sessionManager.getContextState(sessionId);
|
|
6800
7204
|
wssExports.broadcastForSession(sessionId, createContextStateMessage(state));
|
|
6801
7205
|
});
|
|
6802
|
-
const { QueueProcessor } = await import("./processor-
|
|
7206
|
+
const { QueueProcessor } = await import("./processor-UQX5KL56.js");
|
|
6803
7207
|
const queueProcessor = new QueueProcessor({
|
|
6804
7208
|
sessionManager,
|
|
6805
7209
|
providerManager,
|
|
@@ -6822,7 +7226,7 @@ async function createServerHandle(config3) {
|
|
|
6822
7226
|
return {
|
|
6823
7227
|
httpServer,
|
|
6824
7228
|
ctx: { config: config3, sessionManager, llmClient: getLLMClient(), toolRegistry, providerManager },
|
|
6825
|
-
start: (port) => new Promise((
|
|
7229
|
+
start: (port) => new Promise((resolve9, reject) => {
|
|
6826
7230
|
const listenPort = port ?? config3.server.port;
|
|
6827
7231
|
const host = config3.server.host;
|
|
6828
7232
|
httpServer.listen(listenPort, host, () => {
|
|
@@ -6832,16 +7236,16 @@ async function createServerHandle(config3) {
|
|
|
6832
7236
|
logger.info(`OpenFox server running at http://${host}:${actualPort}`);
|
|
6833
7237
|
logger.info(`WebSocket available at ws://${host}:${actualPort}/ws`);
|
|
6834
7238
|
logger.info(`LLM backend: ${client.getBackend()}, model: ${client.getModel()}, url: ${config3.llm.baseUrl}`);
|
|
6835
|
-
|
|
7239
|
+
resolve9({ port: actualPort });
|
|
6836
7240
|
});
|
|
6837
7241
|
httpServer.on("error", reject);
|
|
6838
7242
|
}),
|
|
6839
|
-
close: () => new Promise((
|
|
7243
|
+
close: () => new Promise((resolve9) => {
|
|
6840
7244
|
logger.info("Shutting down...");
|
|
6841
7245
|
void (async () => {
|
|
6842
7246
|
await devServerManager.stopAll();
|
|
6843
7247
|
await mcpManager.disconnectAll();
|
|
6844
|
-
const { stopAllInspectProxies } = await import("./inspect-proxy-
|
|
7248
|
+
const { stopAllInspectProxies } = await import("./inspect-proxy-DRYIIH4O.js");
|
|
6845
7249
|
stopAllInspectProxies();
|
|
6846
7250
|
const { cleanupAllProcesses } = await import("./store-SARB6V2N.js");
|
|
6847
7251
|
cleanupAllProcesses();
|
|
@@ -6855,7 +7259,7 @@ async function createServerHandle(config3) {
|
|
|
6855
7259
|
client.terminate();
|
|
6856
7260
|
}
|
|
6857
7261
|
wss.close();
|
|
6858
|
-
httpServer.close(() =>
|
|
7262
|
+
httpServer.close(() => resolve9());
|
|
6859
7263
|
})();
|
|
6860
7264
|
})
|
|
6861
7265
|
};
|
|
@@ -6879,4 +7283,4 @@ export {
|
|
|
6879
7283
|
createServerHandle,
|
|
6880
7284
|
createServer
|
|
6881
7285
|
};
|
|
6882
|
-
//# sourceMappingURL=chunk-
|
|
7286
|
+
//# sourceMappingURL=chunk-UMX7MMNW.js.map
|