openfox 1.5.2 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-defaults/builder.agent.md +1 -0
- package/dist/agent-defaults/planner.agent.md +1 -0
- package/dist/{auto-compaction-MNK2FZ6E.js → auto-compaction-BRT6SDEP.js} +7 -5
- package/dist/{chat-handler-Y7KR2RLL.js → chat-handler-55LA4LI2.js} +11 -9
- package/dist/chunk-574HZVLE.js +149 -0
- package/dist/{chunk-NW7PIZH3.js → chunk-CIXMZ73F.js} +82 -3
- package/dist/{chunk-S4QKTRGJ.js → chunk-EBOKO2PW.js} +2 -2
- package/dist/{chunk-GXVA5W7Q.js → chunk-GBBTJ6ND.js} +183 -15
- package/dist/chunk-NBU6KIOD.js +184 -0
- package/dist/{chunk-F7PUG5WA.js → chunk-S73ATBSR.js} +4 -4
- package/dist/{chunk-6PV24MJB.js → chunk-TKWJ665A.js} +2 -2
- package/dist/{chunk-UBWZDTZ4.js → chunk-WZJLCOV3.js} +89 -48
- package/dist/{chunk-TPT6HP4H.js → chunk-XQQ2BRJA.js} +1 -1
- package/dist/cli/dev.js +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/{events-B7S4U4DB.js → events-OZKDX6XE.js} +2 -2
- package/dist/manager-HM2J5VMW.js +20 -0
- package/dist/{orchestrator-QGFC5QB6.js → orchestrator-IEYZSNVH.js} +8 -6
- package/dist/package.json +1 -1
- package/dist/{processor-BFTXIEDV.js → processor-I4BGYK3T.js} +5 -5
- package/dist/{protocol-WQENDK72.js → protocol-ODKD7QJO.js} +3 -3
- package/dist/{protocol-CLWtTnMd.d.ts → protocol-vX_YbJXE.d.ts} +40 -2
- package/dist/{serve-JJLKBQXS.js → serve-SDBFDRNJ.js} +10 -8
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +8 -6
- package/dist/shared/index.d.ts +2 -2
- package/dist/shared/index.js +1 -1
- package/dist/store-2IF3ZSLD.js +33 -0
- package/dist/{tools-MY4TPRP4.js → tools-GQ3PJL6N.js} +7 -5
- package/dist/web/assets/{index-BnJ4NNAw.css → index-Dc2TJUUt.css} +1 -1
- package/dist/web/assets/{index-xs6xUYKs.js → index-JG-uVLoP.js} +70 -62
- package/dist/web/index.html +2 -2
- package/dist/web/sw.js +1 -1
- package/package.json +1 -1
|
@@ -2,16 +2,18 @@ import {
|
|
|
2
2
|
maybeAutoCompactContext,
|
|
3
3
|
performManualContextCompaction,
|
|
4
4
|
resolveCompactionStatsIdentity
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-GBBTJ6ND.js";
|
|
6
|
+
import "./chunk-NBU6KIOD.js";
|
|
7
|
+
import "./chunk-574HZVLE.js";
|
|
6
8
|
import "./chunk-XFXOSPYH.js";
|
|
7
|
-
import "./chunk-
|
|
9
|
+
import "./chunk-CIXMZ73F.js";
|
|
8
10
|
import "./chunk-WQ4W5H6A.js";
|
|
9
|
-
import "./chunk-
|
|
11
|
+
import "./chunk-EBOKO2PW.js";
|
|
10
12
|
import "./chunk-22CTURMH.js";
|
|
11
13
|
import "./chunk-7IOZFJBW.js";
|
|
12
14
|
import "./chunk-XKFPU2FA.js";
|
|
13
15
|
import "./chunk-3EHGGBWE.js";
|
|
14
|
-
import "./chunk-
|
|
16
|
+
import "./chunk-XQQ2BRJA.js";
|
|
15
17
|
import "./chunk-R4HADRYO.js";
|
|
16
18
|
import "./chunk-TVQOONDR.js";
|
|
17
19
|
import "./chunk-PNBH3RAX.js";
|
|
@@ -20,4 +22,4 @@ export {
|
|
|
20
22
|
performManualContextCompaction,
|
|
21
23
|
resolveCompactionStatsIdentity
|
|
22
24
|
};
|
|
23
|
-
//# sourceMappingURL=auto-compaction-
|
|
25
|
+
//# sourceMappingURL=auto-compaction-BRT6SDEP.js.map
|
|
@@ -1,16 +1,18 @@
|
|
|
1
|
-
import {
|
|
2
|
-
runChatTurn
|
|
3
|
-
} from "./chunk-F7PUG5WA.js";
|
|
4
|
-
import "./chunk-GXVA5W7Q.js";
|
|
5
1
|
import {
|
|
6
2
|
generateSessionName,
|
|
7
3
|
needsNameGeneration
|
|
8
4
|
} from "./chunk-QDEKU5RL.js";
|
|
5
|
+
import {
|
|
6
|
+
runChatTurn
|
|
7
|
+
} from "./chunk-S73ATBSR.js";
|
|
8
|
+
import "./chunk-GBBTJ6ND.js";
|
|
9
|
+
import "./chunk-NBU6KIOD.js";
|
|
10
|
+
import "./chunk-574HZVLE.js";
|
|
9
11
|
import "./chunk-XFXOSPYH.js";
|
|
10
12
|
import {
|
|
11
13
|
getEventStore,
|
|
12
14
|
updateSessionMetadata
|
|
13
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-CIXMZ73F.js";
|
|
14
16
|
import {
|
|
15
17
|
buildMessagesFromStoredEvents,
|
|
16
18
|
foldPendingConfirmations
|
|
@@ -21,12 +23,12 @@ import {
|
|
|
21
23
|
createPhaseChangedMessage,
|
|
22
24
|
createSessionRunningMessage,
|
|
23
25
|
createSessionStateMessage
|
|
24
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-EBOKO2PW.js";
|
|
25
27
|
import "./chunk-22CTURMH.js";
|
|
26
28
|
import "./chunk-7IOZFJBW.js";
|
|
27
29
|
import "./chunk-XKFPU2FA.js";
|
|
28
30
|
import "./chunk-3EHGGBWE.js";
|
|
29
|
-
import "./chunk-
|
|
31
|
+
import "./chunk-XQQ2BRJA.js";
|
|
30
32
|
import "./chunk-R4HADRYO.js";
|
|
31
33
|
import "./chunk-TVQOONDR.js";
|
|
32
34
|
import {
|
|
@@ -59,7 +61,7 @@ async function startChatSession(sessionId, content, deps, options) {
|
|
|
59
61
|
sessionManager.setRunning(sessionId, true);
|
|
60
62
|
broadcastForSession(sessionId, createSessionRunningMessage(true));
|
|
61
63
|
try {
|
|
62
|
-
const { maybeAutoCompactContext } = await import("./auto-compaction-
|
|
64
|
+
const { maybeAutoCompactContext } = await import("./auto-compaction-BRT6SDEP.js");
|
|
63
65
|
await maybeAutoCompactContext({
|
|
64
66
|
sessionManager,
|
|
65
67
|
sessionId,
|
|
@@ -198,4 +200,4 @@ export {
|
|
|
198
200
|
startChatSession,
|
|
199
201
|
stopSessionExecution
|
|
200
202
|
};
|
|
201
|
-
//# sourceMappingURL=chat-handler-
|
|
203
|
+
//# sourceMappingURL=chat-handler-55LA4LI2.js.map
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
// src/server/tools/background-process/store.ts
|
|
2
|
+
var MAX_PER_SESSION = 5;
|
|
3
|
+
var processesBySession = /* @__PURE__ */ new Map();
|
|
4
|
+
var logsByProcess = /* @__PURE__ */ new Map();
|
|
5
|
+
function getMaxPerSession() {
|
|
6
|
+
return MAX_PER_SESSION;
|
|
7
|
+
}
|
|
8
|
+
function getProcess(processId, sessionId) {
|
|
9
|
+
return processesBySession.get(sessionId)?.get(processId);
|
|
10
|
+
}
|
|
11
|
+
function getSessionProcesses(sessionId) {
|
|
12
|
+
const sessionProcesses = processesBySession.get(sessionId);
|
|
13
|
+
if (!sessionProcesses) return [];
|
|
14
|
+
return Array.from(sessionProcesses.values());
|
|
15
|
+
}
|
|
16
|
+
function getSessionProcessCount(sessionId) {
|
|
17
|
+
return getSessionProcesses(sessionId).filter((p) => p.status !== "exited").length;
|
|
18
|
+
}
|
|
19
|
+
function createProcess(sessionId, name, command, cwd) {
|
|
20
|
+
const count = getSessionProcessCount(sessionId);
|
|
21
|
+
if (count >= MAX_PER_SESSION) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
const process2 = {
|
|
25
|
+
id: crypto.randomUUID(),
|
|
26
|
+
sessionId,
|
|
27
|
+
name,
|
|
28
|
+
command,
|
|
29
|
+
cwd,
|
|
30
|
+
pid: null,
|
|
31
|
+
status: "pending",
|
|
32
|
+
exitCode: null,
|
|
33
|
+
createdAt: Date.now(),
|
|
34
|
+
startedAt: null,
|
|
35
|
+
endedAt: null
|
|
36
|
+
};
|
|
37
|
+
if (!processesBySession.has(sessionId)) {
|
|
38
|
+
processesBySession.set(sessionId, /* @__PURE__ */ new Map());
|
|
39
|
+
}
|
|
40
|
+
processesBySession.get(sessionId).set(process2.id, process2);
|
|
41
|
+
logsByProcess.set(process2.id, []);
|
|
42
|
+
return process2;
|
|
43
|
+
}
|
|
44
|
+
function startProcess(processId, sessionId, pid) {
|
|
45
|
+
const process2 = getProcess(processId, sessionId);
|
|
46
|
+
if (!process2) return void 0;
|
|
47
|
+
process2.pid = pid;
|
|
48
|
+
process2.status = "running";
|
|
49
|
+
process2.startedAt = Date.now();
|
|
50
|
+
return process2;
|
|
51
|
+
}
|
|
52
|
+
function updateStatus(processId, sessionId, status, exitCode) {
|
|
53
|
+
const process2 = getProcess(processId, sessionId);
|
|
54
|
+
if (!process2) return void 0;
|
|
55
|
+
process2.status = status;
|
|
56
|
+
if (exitCode !== void 0) {
|
|
57
|
+
process2.exitCode = exitCode;
|
|
58
|
+
}
|
|
59
|
+
if (status === "exited" || status === "stopping") {
|
|
60
|
+
process2.endedAt = Date.now();
|
|
61
|
+
}
|
|
62
|
+
return process2;
|
|
63
|
+
}
|
|
64
|
+
function removeProcess(processId, sessionId) {
|
|
65
|
+
const sessionProcesses = processesBySession.get(sessionId);
|
|
66
|
+
if (!sessionProcesses) return false;
|
|
67
|
+
const deleted = sessionProcesses.delete(processId);
|
|
68
|
+
logsByProcess.delete(processId);
|
|
69
|
+
return deleted;
|
|
70
|
+
}
|
|
71
|
+
function appendLog(processId, content, stream = "stdout") {
|
|
72
|
+
const logs = logsByProcess.get(processId);
|
|
73
|
+
if (!logs) return;
|
|
74
|
+
const offset = logs.length;
|
|
75
|
+
logs.push({
|
|
76
|
+
offset,
|
|
77
|
+
content,
|
|
78
|
+
timestamp: Date.now(),
|
|
79
|
+
stream
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
function getLogs(processId, offset = 0, limit) {
|
|
83
|
+
const logs = logsByProcess.get(processId) ?? [];
|
|
84
|
+
const start = Math.min(offset, logs.length);
|
|
85
|
+
const end = limit !== void 0 ? Math.min(start + limit, logs.length) : logs.length;
|
|
86
|
+
return logs.slice(start, end);
|
|
87
|
+
}
|
|
88
|
+
function getLogsPaginated(processId, since = 0, maxLines = 500) {
|
|
89
|
+
const logs = logsByProcess.get(processId) ?? [];
|
|
90
|
+
const totalLines = logs.length;
|
|
91
|
+
const filteredLogs = logs.filter((_, index) => index >= since);
|
|
92
|
+
const slicedLogs = filteredLogs.slice(0, maxLines);
|
|
93
|
+
const lastLine = slicedLogs[slicedLogs.length - 1];
|
|
94
|
+
const nextOffset = lastLine ? lastLine.offset + 1 : totalLines;
|
|
95
|
+
const hasMore = slicedLogs.length < filteredLogs.length;
|
|
96
|
+
return {
|
|
97
|
+
lines: slicedLogs,
|
|
98
|
+
totalLines,
|
|
99
|
+
nextOffset,
|
|
100
|
+
hasMore
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
function clearLogs(processId) {
|
|
104
|
+
logsByProcess.delete(processId);
|
|
105
|
+
logsByProcess.set(processId, []);
|
|
106
|
+
}
|
|
107
|
+
function getProcessById(processId) {
|
|
108
|
+
for (const sessionProcesses of processesBySession.values()) {
|
|
109
|
+
const proc = sessionProcesses.get(processId);
|
|
110
|
+
if (proc) return proc;
|
|
111
|
+
}
|
|
112
|
+
return void 0;
|
|
113
|
+
}
|
|
114
|
+
function cleanupAllProcesses() {
|
|
115
|
+
for (const sessionProcesses of processesBySession.values()) {
|
|
116
|
+
for (const proc of sessionProcesses.values()) {
|
|
117
|
+
if (proc.status === "running" && proc.pid) {
|
|
118
|
+
try {
|
|
119
|
+
process.kill(-proc.pid, "SIGTERM");
|
|
120
|
+
} catch {
|
|
121
|
+
try {
|
|
122
|
+
process.kill(proc.pid, "SIGTERM");
|
|
123
|
+
} catch (_) {
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
processesBySession.clear();
|
|
130
|
+
logsByProcess.clear();
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export {
|
|
134
|
+
getMaxPerSession,
|
|
135
|
+
getProcess,
|
|
136
|
+
getSessionProcesses,
|
|
137
|
+
getSessionProcessCount,
|
|
138
|
+
createProcess,
|
|
139
|
+
startProcess,
|
|
140
|
+
updateStatus,
|
|
141
|
+
removeProcess,
|
|
142
|
+
appendLog,
|
|
143
|
+
getLogs,
|
|
144
|
+
getLogsPaginated,
|
|
145
|
+
clearLogs,
|
|
146
|
+
getProcessById,
|
|
147
|
+
cleanupAllProcesses
|
|
148
|
+
};
|
|
149
|
+
//# sourceMappingURL=chunk-574HZVLE.js.map
|
|
@@ -18,6 +18,8 @@ import {
|
|
|
18
18
|
var EventStore = class {
|
|
19
19
|
db;
|
|
20
20
|
subscribers = /* @__PURE__ */ new Map();
|
|
21
|
+
globalSubscribers = /* @__PURE__ */ new Map();
|
|
22
|
+
globalSubscriberIdCounter = 0;
|
|
21
23
|
constructor(db) {
|
|
22
24
|
this.db = db;
|
|
23
25
|
this.initSchema();
|
|
@@ -239,13 +241,82 @@ var EventStore = class {
|
|
|
239
241
|
}
|
|
240
242
|
notifySubscribers(sessionId, event) {
|
|
241
243
|
const sessionSubs = this.subscribers.get(sessionId);
|
|
242
|
-
if (
|
|
243
|
-
|
|
244
|
+
if (sessionSubs) {
|
|
245
|
+
for (const subscriber of sessionSubs) {
|
|
246
|
+
if (!subscriber.closed) {
|
|
247
|
+
subscriber.callback(event);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
for (const subscriber of this.globalSubscribers.values()) {
|
|
244
252
|
if (!subscriber.closed) {
|
|
245
253
|
subscriber.callback(event);
|
|
246
254
|
}
|
|
247
255
|
}
|
|
248
256
|
}
|
|
257
|
+
/**
|
|
258
|
+
* Subscribe to ALL events across ALL sessions.
|
|
259
|
+
* Unlike subscribe() which is session-specific, this receives every event.
|
|
260
|
+
* Used by WebSocket clients to receive real-time updates for all sessions.
|
|
261
|
+
*
|
|
262
|
+
* Returns an async iterator that yields events and an unsubscribe function
|
|
263
|
+
*/
|
|
264
|
+
subscribeAll() {
|
|
265
|
+
const queue = [];
|
|
266
|
+
let resolveNext = null;
|
|
267
|
+
let closed = false;
|
|
268
|
+
const closeIterator = () => {
|
|
269
|
+
closed = true;
|
|
270
|
+
if (resolveNext) {
|
|
271
|
+
resolveNext({ value: void 0, done: true });
|
|
272
|
+
resolveNext = null;
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
const wsId = ++this.globalSubscriberIdCounter;
|
|
276
|
+
const subscriber = {
|
|
277
|
+
wsId,
|
|
278
|
+
callback: (event) => {
|
|
279
|
+
if (closed) return;
|
|
280
|
+
if (resolveNext) {
|
|
281
|
+
resolveNext({ value: event, done: false });
|
|
282
|
+
resolveNext = null;
|
|
283
|
+
} else {
|
|
284
|
+
queue.push(event);
|
|
285
|
+
}
|
|
286
|
+
},
|
|
287
|
+
close: closeIterator,
|
|
288
|
+
closed: false
|
|
289
|
+
};
|
|
290
|
+
this.globalSubscribers.set(wsId, subscriber);
|
|
291
|
+
const iterator = {
|
|
292
|
+
[Symbol.asyncIterator]() {
|
|
293
|
+
return this;
|
|
294
|
+
},
|
|
295
|
+
async next() {
|
|
296
|
+
if (closed) {
|
|
297
|
+
return { value: void 0, done: true };
|
|
298
|
+
}
|
|
299
|
+
const queued = queue.shift();
|
|
300
|
+
if (queued) {
|
|
301
|
+
return { value: queued, done: false };
|
|
302
|
+
}
|
|
303
|
+
return new Promise((resolve) => {
|
|
304
|
+
resolveNext = resolve;
|
|
305
|
+
});
|
|
306
|
+
},
|
|
307
|
+
async return() {
|
|
308
|
+
closed = true;
|
|
309
|
+
subscriber.closed = true;
|
|
310
|
+
return { value: void 0, done: true };
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
const unsubscribe = () => {
|
|
314
|
+
subscriber.closed = true;
|
|
315
|
+
closeIterator();
|
|
316
|
+
this.globalSubscribers.delete(wsId);
|
|
317
|
+
};
|
|
318
|
+
return { iterator, unsubscribe };
|
|
319
|
+
}
|
|
249
320
|
// --------------------------------------------------------------------------
|
|
250
321
|
// Cleanup
|
|
251
322
|
// --------------------------------------------------------------------------
|
|
@@ -506,6 +577,13 @@ function updateSessionDangerLevel(id, dangerLevel) {
|
|
|
506
577
|
UPDATE sessions SET danger_level = ?, updated_at = ? WHERE id = ?
|
|
507
578
|
`).run(dangerLevel, now, id);
|
|
508
579
|
}
|
|
580
|
+
function updateSessionRunning(id, isRunning) {
|
|
581
|
+
const db = getDatabase();
|
|
582
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
583
|
+
db.prepare(`
|
|
584
|
+
UPDATE sessions SET is_running = ?, updated_at = ? WHERE id = ?
|
|
585
|
+
`).run(isRunning ? 1 : 0, now, id);
|
|
586
|
+
}
|
|
509
587
|
function updateSessionSummary(id, summary) {
|
|
510
588
|
const db = getDatabase();
|
|
511
589
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -1027,6 +1105,7 @@ export {
|
|
|
1027
1105
|
getSession,
|
|
1028
1106
|
updateSessionProvider,
|
|
1029
1107
|
updateSessionDangerLevel,
|
|
1108
|
+
updateSessionRunning,
|
|
1030
1109
|
updateSessionSummary,
|
|
1031
1110
|
updateSessionMetadata,
|
|
1032
1111
|
listSessions,
|
|
@@ -1064,4 +1143,4 @@ export {
|
|
|
1064
1143
|
compactContext,
|
|
1065
1144
|
getRecentUserPromptsForSession
|
|
1066
1145
|
};
|
|
1067
|
-
//# sourceMappingURL=chunk-
|
|
1146
|
+
//# sourceMappingURL=chunk-CIXMZ73F.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createServerMessage,
|
|
3
3
|
isClientMessage
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-XQQ2BRJA.js";
|
|
5
5
|
|
|
6
6
|
// src/server/ws/protocol.ts
|
|
7
7
|
function enrichMessagesWithToolResults(messages) {
|
|
@@ -340,4 +340,4 @@ export {
|
|
|
340
340
|
isQueueCancelPayload,
|
|
341
341
|
storedEventToServerMessage
|
|
342
342
|
};
|
|
343
|
-
//# sourceMappingURL=chunk-
|
|
343
|
+
//# sourceMappingURL=chunk-EBOKO2PW.js.map
|
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createProcess,
|
|
3
|
+
getPlatformShell,
|
|
4
|
+
getProcessLogs,
|
|
5
|
+
getProcessStatus,
|
|
6
|
+
getSessionProcesses,
|
|
7
|
+
startProcessCommand,
|
|
8
|
+
stopProcess
|
|
9
|
+
} from "./chunk-NBU6KIOD.js";
|
|
10
|
+
import {
|
|
11
|
+
getMaxPerSession,
|
|
12
|
+
getSessionProcessCount
|
|
13
|
+
} from "./chunk-574HZVLE.js";
|
|
1
14
|
import {
|
|
2
15
|
streamWithSegments
|
|
3
16
|
} from "./chunk-XFXOSPYH.js";
|
|
@@ -5,14 +18,14 @@ import {
|
|
|
5
18
|
getContextMessages,
|
|
6
19
|
getCurrentContextWindowId,
|
|
7
20
|
getEventStore
|
|
8
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-CIXMZ73F.js";
|
|
9
22
|
import {
|
|
10
23
|
createChatMessageMessage,
|
|
11
24
|
createChatPathConfirmationMessage,
|
|
12
25
|
createChatToolOutputMessage,
|
|
13
26
|
createChatVisionFallbackMessage,
|
|
14
27
|
createQueueStateMessage
|
|
15
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-EBOKO2PW.js";
|
|
16
29
|
import {
|
|
17
30
|
AskUserInterrupt,
|
|
18
31
|
askUserTool
|
|
@@ -1121,8 +1134,8 @@ import { resolve as resolve2, isAbsolute } from "path";
|
|
|
1121
1134
|
|
|
1122
1135
|
// src/server/tools/path-security.ts
|
|
1123
1136
|
import { realpath } from "fs/promises";
|
|
1124
|
-
import { resolve, normalize, join as join3 } from "path";
|
|
1125
|
-
import { homedir } from "os";
|
|
1137
|
+
import { resolve, normalize, join as join3, basename, sep } from "path";
|
|
1138
|
+
import { homedir, tmpdir } from "os";
|
|
1126
1139
|
var SAFE_PATHS = /* @__PURE__ */ new Set([
|
|
1127
1140
|
"/dev/null",
|
|
1128
1141
|
"/dev/zero",
|
|
@@ -1135,7 +1148,11 @@ var SAFE_PATHS = /* @__PURE__ */ new Set([
|
|
|
1135
1148
|
"/dev/fd/1",
|
|
1136
1149
|
"/dev/fd/2"
|
|
1137
1150
|
]);
|
|
1138
|
-
var ALLOWED_ROOTS = [
|
|
1151
|
+
var ALLOWED_ROOTS = [
|
|
1152
|
+
"/tmp",
|
|
1153
|
+
"/var/tmp",
|
|
1154
|
+
tmpdir()
|
|
1155
|
+
];
|
|
1139
1156
|
var SENSITIVE_FILE_PATTERNS = [
|
|
1140
1157
|
// Dotenv files (but not .envrc, .env-example, .env.example)
|
|
1141
1158
|
/^\.env$/,
|
|
@@ -1156,9 +1173,9 @@ var SENSITIVE_FILE_PATTERNS = [
|
|
|
1156
1173
|
/^\.netrc$/
|
|
1157
1174
|
];
|
|
1158
1175
|
function isSensitivePath(path) {
|
|
1159
|
-
const
|
|
1160
|
-
if (!
|
|
1161
|
-
return SENSITIVE_FILE_PATTERNS.some((pattern) => pattern.test(
|
|
1176
|
+
const fileName = basename(path);
|
|
1177
|
+
if (!fileName) return false;
|
|
1178
|
+
return SENSITIVE_FILE_PATTERNS.some((pattern) => pattern.test(fileName));
|
|
1162
1179
|
}
|
|
1163
1180
|
var sessionAllowedPaths = /* @__PURE__ */ new Map();
|
|
1164
1181
|
function addAllowedPath(sessionId, path) {
|
|
@@ -1200,12 +1217,12 @@ async function isPathWithinSandbox(path, workdir, sessionId) {
|
|
|
1200
1217
|
}
|
|
1201
1218
|
}
|
|
1202
1219
|
resolvedPath = resolvedPath.replace(/\/+$/, "");
|
|
1203
|
-
if (resolvedPath === normalizedWorkdir || resolvedPath.startsWith(normalizedWorkdir +
|
|
1220
|
+
if (resolvedPath === normalizedWorkdir || resolvedPath.startsWith(normalizedWorkdir + sep)) {
|
|
1204
1221
|
return { allowed: true, resolvedPath };
|
|
1205
1222
|
}
|
|
1206
1223
|
for (const root of ALLOWED_ROOTS) {
|
|
1207
1224
|
const normalizedRoot = normalize(root);
|
|
1208
|
-
if (resolvedPath === normalizedRoot || resolvedPath.startsWith(normalizedRoot +
|
|
1225
|
+
if (resolvedPath === normalizedRoot || resolvedPath.startsWith(normalizedRoot + sep)) {
|
|
1209
1226
|
return { allowed: true, resolvedPath };
|
|
1210
1227
|
}
|
|
1211
1228
|
}
|
|
@@ -2111,7 +2128,8 @@ function executeCommand(command, cwd, timeout, signal, onProgress) {
|
|
|
2111
2128
|
reject(new Error("Command aborted before execution"));
|
|
2112
2129
|
return;
|
|
2113
2130
|
}
|
|
2114
|
-
const
|
|
2131
|
+
const shell = getPlatformShell();
|
|
2132
|
+
const proc = spawn2(shell.command, [...shell.args, command], {
|
|
2115
2133
|
cwd,
|
|
2116
2134
|
env: { ...process.env, FORCE_COLOR: "0" },
|
|
2117
2135
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -3607,7 +3625,7 @@ var callSubAgentTool = {
|
|
|
3607
3625
|
};
|
|
3608
3626
|
}
|
|
3609
3627
|
try {
|
|
3610
|
-
const { getToolRegistryForAgent: getToolRegistryForAgent2 } = await import("./tools-
|
|
3628
|
+
const { getToolRegistryForAgent: getToolRegistryForAgent2 } = await import("./tools-GQ3PJL6N.js");
|
|
3611
3629
|
const toolRegistry = getToolRegistryForAgent2(agentDef);
|
|
3612
3630
|
const turnMetrics = new TurnMetrics();
|
|
3613
3631
|
const result = await executeSubAgent({
|
|
@@ -3954,7 +3972,8 @@ var DevServerManager = class {
|
|
|
3954
3972
|
instance.errorMessage = void 0;
|
|
3955
3973
|
instance.exited = false;
|
|
3956
3974
|
const resolved = this.resolveWorkdir(workdir);
|
|
3957
|
-
const
|
|
3975
|
+
const shell = getPlatformShell();
|
|
3976
|
+
const proc = spawn3(shell.command, [...shell.args, config.command], {
|
|
3958
3977
|
cwd: resolved,
|
|
3959
3978
|
env: { ...process.env, FORCE_COLOR: "1" },
|
|
3960
3979
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -4181,6 +4200,154 @@ var stepDoneTool = {
|
|
|
4181
4200
|
}
|
|
4182
4201
|
};
|
|
4183
4202
|
|
|
4203
|
+
// src/server/tools/background-process/index.ts
|
|
4204
|
+
var backgroundProcessTool = createTool(
|
|
4205
|
+
"background_process",
|
|
4206
|
+
{
|
|
4207
|
+
type: "function",
|
|
4208
|
+
function: {
|
|
4209
|
+
name: "background_process",
|
|
4210
|
+
description: `Start, stop, and monitor long-running background processes.
|
|
4211
|
+
|
|
4212
|
+
These processes run independently of agent turns and persist across session compaction. Processes are displayed in the right sidebar where you can view their logs and status.
|
|
4213
|
+
|
|
4214
|
+
**Actions:**
|
|
4215
|
+
- start: Launch a new background process (provide: name, command, cwd, timeout)
|
|
4216
|
+
- stop: Stop a running process and remove it from the sidebar
|
|
4217
|
+
- list: Show all processes for this session
|
|
4218
|
+
- status: Get detailed status of a specific process
|
|
4219
|
+
- logs: Retrieve process output with optional pagination`,
|
|
4220
|
+
parameters: {
|
|
4221
|
+
type: "object",
|
|
4222
|
+
properties: {
|
|
4223
|
+
action: {
|
|
4224
|
+
type: "string",
|
|
4225
|
+
enum: ["start", "stop", "list", "status", "logs"],
|
|
4226
|
+
description: "The action to perform on background processes"
|
|
4227
|
+
},
|
|
4228
|
+
name: {
|
|
4229
|
+
type: "string",
|
|
4230
|
+
description: "Display name for the process. Auto-generated from command if not provided."
|
|
4231
|
+
},
|
|
4232
|
+
command: {
|
|
4233
|
+
type: "string",
|
|
4234
|
+
description: 'Shell command to execute. Required for "start" action.'
|
|
4235
|
+
},
|
|
4236
|
+
cwd: {
|
|
4237
|
+
type: "string",
|
|
4238
|
+
description: "Working directory. Defaults to session workdir."
|
|
4239
|
+
},
|
|
4240
|
+
timeout: {
|
|
4241
|
+
type: "number",
|
|
4242
|
+
description: "Maximum runtime in milliseconds. Process will be terminated after this duration."
|
|
4243
|
+
},
|
|
4244
|
+
processId: {
|
|
4245
|
+
type: "string",
|
|
4246
|
+
description: "Process ID. Required for stop, status, and logs actions."
|
|
4247
|
+
},
|
|
4248
|
+
since: {
|
|
4249
|
+
type: "number",
|
|
4250
|
+
description: "Return logs after this offset. Default: 0"
|
|
4251
|
+
},
|
|
4252
|
+
maxLines: {
|
|
4253
|
+
type: "number",
|
|
4254
|
+
description: "Maximum lines to return. Default: 500, max: 2000"
|
|
4255
|
+
}
|
|
4256
|
+
},
|
|
4257
|
+
required: ["action"],
|
|
4258
|
+
dependentRequired: {
|
|
4259
|
+
start: ["command"],
|
|
4260
|
+
stop: ["processId"],
|
|
4261
|
+
status: ["processId"],
|
|
4262
|
+
logs: ["processId"]
|
|
4263
|
+
}
|
|
4264
|
+
}
|
|
4265
|
+
}
|
|
4266
|
+
},
|
|
4267
|
+
async (args, context, helpers) => {
|
|
4268
|
+
const sessionId = context.sessionId;
|
|
4269
|
+
const cwd = args.cwd ?? context.workdir;
|
|
4270
|
+
switch (args.action) {
|
|
4271
|
+
case "start": {
|
|
4272
|
+
const count = getSessionProcessCount(sessionId);
|
|
4273
|
+
const maxPerSession = getMaxPerSession();
|
|
4274
|
+
if (count >= maxPerSession) {
|
|
4275
|
+
return helpers.error(`Maximum number of background processes (${maxPerSession}) reached. Stop existing processes before starting new ones.`);
|
|
4276
|
+
}
|
|
4277
|
+
const name = args.name ?? args.command?.split(" ")[0] ?? "process";
|
|
4278
|
+
const process2 = createProcess(sessionId, name, args.command, cwd, args.timeout);
|
|
4279
|
+
if (!process2) {
|
|
4280
|
+
return helpers.error(`Failed to create process. Maximum limit may have been reached.`);
|
|
4281
|
+
}
|
|
4282
|
+
const pid = startProcessCommand(process2.id, sessionId, args.command, cwd);
|
|
4283
|
+
if (!pid) {
|
|
4284
|
+
return helpers.error(`Failed to start process.`);
|
|
4285
|
+
}
|
|
4286
|
+
return helpers.success(JSON.stringify({
|
|
4287
|
+
processId: process2.id,
|
|
4288
|
+
name: process2.name,
|
|
4289
|
+
pid,
|
|
4290
|
+
status: "running",
|
|
4291
|
+
maxReached: count + 1 >= maxPerSession
|
|
4292
|
+
}, null, 2));
|
|
4293
|
+
}
|
|
4294
|
+
case "stop": {
|
|
4295
|
+
const proc = getProcessStatus(args.processId, sessionId);
|
|
4296
|
+
if (!proc) {
|
|
4297
|
+
return helpers.error(`Process not found: ${args.processId}`);
|
|
4298
|
+
}
|
|
4299
|
+
if (proc.status !== "running") {
|
|
4300
|
+
return helpers.error(`Process is not running (status: ${proc.status}). Cannot stop.`);
|
|
4301
|
+
}
|
|
4302
|
+
await stopProcess(args.processId, sessionId);
|
|
4303
|
+
return helpers.success(JSON.stringify({
|
|
4304
|
+
processId: args.processId,
|
|
4305
|
+
status: "removed"
|
|
4306
|
+
}, null, 2));
|
|
4307
|
+
}
|
|
4308
|
+
case "list": {
|
|
4309
|
+
const processes = getSessionProcesses(sessionId);
|
|
4310
|
+
const maxPerSession = getMaxPerSession();
|
|
4311
|
+
return helpers.success(JSON.stringify({
|
|
4312
|
+
processes,
|
|
4313
|
+
maxPerSession,
|
|
4314
|
+
currentCount: processes.filter((p) => p.status !== "exited").length
|
|
4315
|
+
}, null, 2));
|
|
4316
|
+
}
|
|
4317
|
+
case "status": {
|
|
4318
|
+
const proc = getProcessStatus(args.processId, sessionId);
|
|
4319
|
+
if (!proc) {
|
|
4320
|
+
return helpers.error(`Process not found: ${args.processId}`);
|
|
4321
|
+
}
|
|
4322
|
+
const uptime = proc.startedAt ? Date.now() - proc.startedAt : null;
|
|
4323
|
+
return helpers.success(JSON.stringify({
|
|
4324
|
+
process: proc,
|
|
4325
|
+
uptime
|
|
4326
|
+
}, null, 2));
|
|
4327
|
+
}
|
|
4328
|
+
case "logs": {
|
|
4329
|
+
const proc = getProcessStatus(args.processId, sessionId);
|
|
4330
|
+
if (!proc) {
|
|
4331
|
+
return helpers.error(`Process not found: ${args.processId}`);
|
|
4332
|
+
}
|
|
4333
|
+
const since = args.since ?? 0;
|
|
4334
|
+
const maxLines = Math.min(args.maxLines ?? 500, 2e3);
|
|
4335
|
+
const { lines, totalLines, nextOffset, hasMore } = getProcessLogs(args.processId, since, maxLines);
|
|
4336
|
+
return helpers.success(JSON.stringify({
|
|
4337
|
+
processId: args.processId,
|
|
4338
|
+
lines,
|
|
4339
|
+
totalLines,
|
|
4340
|
+
nextOffset,
|
|
4341
|
+
hasMore,
|
|
4342
|
+
truncated: hasMore
|
|
4343
|
+
}, null, 2));
|
|
4344
|
+
}
|
|
4345
|
+
default:
|
|
4346
|
+
return helpers.error(`Unknown action: ${args.action}`);
|
|
4347
|
+
}
|
|
4348
|
+
}
|
|
4349
|
+
);
|
|
4350
|
+
|
|
4184
4351
|
// src/server/tools/index.ts
|
|
4185
4352
|
function parseToolPermissions(allowedTools) {
|
|
4186
4353
|
const result = {};
|
|
@@ -4315,7 +4482,8 @@ function getAllToolsMap() {
|
|
|
4315
4482
|
returnValueTool,
|
|
4316
4483
|
webFetchTool,
|
|
4317
4484
|
devServerTool,
|
|
4318
|
-
stepDoneTool
|
|
4485
|
+
stepDoneTool,
|
|
4486
|
+
backgroundProcessTool
|
|
4319
4487
|
].map((t) => [t.name, t])
|
|
4320
4488
|
]);
|
|
4321
4489
|
}
|
|
@@ -4590,4 +4758,4 @@ export {
|
|
|
4590
4758
|
getToolRegistryForAgent,
|
|
4591
4759
|
createToolRegistry
|
|
4592
4760
|
};
|
|
4593
|
-
//# sourceMappingURL=chunk-
|
|
4761
|
+
//# sourceMappingURL=chunk-GBBTJ6ND.js.map
|