specrails-desktop 2.27.0 → 2.28.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/client/dist/assets/{ActivityFeedPage-BlkNVXCv.js → ActivityFeedPage-DcMmDAP3.js} +1 -1
- package/client/dist/assets/AgentBrowserCapture-CZ3oc1UL.js +1 -0
- package/client/dist/assets/AgentIntegrationsModal-DkqooCFn.js +1 -0
- package/client/dist/assets/{AgentModeCodePane-BUR_QxqR.js → AgentModeCodePane-CM77ljte.js} +2 -2
- package/client/dist/assets/{AgentModeJobsPane-CnRXelns.js → AgentModeJobsPane-DbZzogbi.js} +1 -1
- package/client/dist/assets/AgentsPage-BZIml7eL.js +86 -0
- package/client/dist/assets/{AnalyticsPage-C_eT3I3i.js → AnalyticsPage-B4qflNxi.js} +1 -1
- package/client/dist/assets/{BarChart-DuzYxiJ6.js → BarChart-Ckstq9fl.js} +1 -1
- package/client/dist/assets/CodePage-DFZXLbI1.js +2 -0
- package/client/dist/assets/{DesktopAnalyticsPage-BSeBkF2n.js → DesktopAnalyticsPage-DbgMa8OO.js} +1 -1
- package/client/dist/assets/{DocsDialog-CGzqDyN3.js → DocsDialog-BQc9Kwev.js} +2 -2
- package/client/dist/assets/DocsPage-OsV44ECy.js +11 -0
- package/client/dist/assets/{ExportDropdown-IehskH-7.js → ExportDropdown-a43XHO3Y.js} +1 -1
- package/client/dist/assets/IntegrationsPage-C3E8hZhB.js +1 -0
- package/client/dist/assets/InteractiveJobComposer-zj8SrOAl.js +19 -0
- package/client/dist/assets/JobDetailModal-Cm6ZeVoh.js +1 -0
- package/client/dist/assets/JobDetailPage-DN67LsdX.js +1 -0
- package/client/dist/assets/JobsPage-DF9wKGbw.js +1 -0
- package/client/dist/assets/LoopBuilderPage-RJ6GGjli.js +7 -0
- package/client/dist/assets/{LoopPreviewModal-BNUQ9iL8.js → LoopPreviewModal-B2wmifF6.js} +1 -1
- package/client/dist/assets/LoopsPage-DdlvH-dJ.js +1 -0
- package/client/dist/assets/PluginsPage-9DI0a6jI.js +2 -0
- package/client/dist/assets/ProjectSettingsDialog-dgy5hqPd.js +1 -0
- package/client/dist/assets/{TemplatePreviewModal-C6mndL8D.js → TemplatePreviewModal-CERf1IYB.js} +1 -1
- package/client/dist/assets/agent-BRJCESkc2.js +1 -0
- package/client/dist/assets/agent-BuYz6fJd.js +1 -0
- package/client/dist/assets/agent-CxnRzL6Z.js +1 -0
- package/client/dist/assets/agent-D4JAuEGN2.js +1 -0
- package/client/dist/assets/agent-DNQlI8EN.js +1 -0
- package/client/dist/assets/agent-DyzUH89R.js +1 -0
- package/client/dist/assets/agent-MaTxBlg5.js +1 -0
- package/client/dist/assets/agent-ostmMYNz2.js +1 -0
- package/client/dist/assets/{brain-Dia32foa.js → brain-BPbhM1Jx.js} +1 -1
- package/client/dist/assets/{dist-js-D_4k5prK.js → dist-js-Byjcju1W.js} +1 -1
- package/client/dist/assets/{dist-js-DN7Pxudf.js → dist-js-Dh-9lbLD.js} +1 -1
- package/client/dist/assets/index-89SuhD4Y.js +158 -0
- package/client/dist/assets/index-DOGzWJhO.css +2 -0
- package/client/dist/assets/integrations-By80EBkf.js +1 -0
- package/client/dist/assets/integrations-CAjq5tdW2.js +1 -0
- package/client/dist/assets/integrations-CG2dp3Kd.js +1 -0
- package/client/dist/assets/integrations-CP_aiV_8.js +1 -0
- package/client/dist/assets/integrations-CUNe3t9l2.js +1 -0
- package/client/dist/assets/integrations-CWjh5VRk.js +1 -0
- package/client/dist/assets/integrations-JOHSCvB3.js +1 -0
- package/client/dist/assets/integrations-RJfzXkPx2.js +1 -0
- package/client/dist/assets/{lib-BxSZPd0W.js → lib-yKyTNJ1c.js} +1 -1
- package/client/dist/assets/nav-B2_ToNqS.js +1 -0
- package/client/dist/assets/nav-BAMkVEId.js +1 -0
- package/client/dist/assets/nav-BTg8s-cD.js +1 -0
- package/client/dist/assets/nav-BY_4EWRv.js +1 -0
- package/client/dist/assets/nav-CVXtv0wX2.js +1 -0
- package/client/dist/assets/nav-D0Erv9ZJ2.js +1 -0
- package/client/dist/assets/nav-DUuw9VIU2.js +1 -0
- package/client/dist/assets/nav-S4HM94vW.js +1 -0
- package/client/dist/assets/{upload-4u055Eea.js → upload-Qh1NE3xi.js} +1 -1
- package/client/dist/assets/{value-C3Qe3VXm.js → value-BMPeyInx.js} +1 -1
- package/client/dist/index.html +29 -29
- package/package.json +1 -1
- package/server/dist/agent-chat-router.js +2 -0
- package/server/dist/agent-operator-prompt.js +10 -3
- package/server/dist/global-plugins-router.js +62 -0
- package/server/dist/headroom-manager.js +971 -0
- package/server/dist/headroom-routing.js +53 -0
- package/server/dist/index.js +7 -0
- package/server/dist/mcp/guide.js +3 -0
- package/server/dist/mcp/tools/jobs.js +52 -9
- package/server/dist/path-resolver.js +10 -3
- package/server/dist/project-router-jobs.js +56 -6
- package/server/dist/setup-manager.js +32 -29
- package/server/dist/setup-prerequisites.js +3 -1
- package/server/dist/transient-children.js +152 -13
- package/server/dist/util/cli-prompt.js +3 -0
- package/client/dist/assets/AgentBrowserCapture-76Ri2QR1.js +0 -1
- package/client/dist/assets/AgentIntegrationsModal-D9hVgaBR.js +0 -1
- package/client/dist/assets/AgentsPage-DEt9vpzh.js +0 -86
- package/client/dist/assets/CodePage-72-FLBNw.js +0 -2
- package/client/dist/assets/DocsPage-BB3VGFM9.js +0 -11
- package/client/dist/assets/IntegrationsPage-X8bLyuDk.js +0 -3
- package/client/dist/assets/InteractiveJobComposer-D1HUALME.js +0 -19
- package/client/dist/assets/JobDetailModal-CMg6aKSO.js +0 -1
- package/client/dist/assets/JobDetailPage-Bg01rzeu.js +0 -1
- package/client/dist/assets/JobsPage-Cwkm9yYc.js +0 -1
- package/client/dist/assets/LoopBuilderPage-4uPNN8Xn.js +0 -7
- package/client/dist/assets/LoopsPage-DLXESZxq.js +0 -1
- package/client/dist/assets/ProjectSettingsDialog-DP6hAug-.js +0 -1
- package/client/dist/assets/agent-B0Rg_eLw2.js +0 -1
- package/client/dist/assets/agent-B8f79myL.js +0 -1
- package/client/dist/assets/agent-BCH7a3z-.js +0 -1
- package/client/dist/assets/agent-BELAd4RF.js +0 -1
- package/client/dist/assets/agent-BrCnHlvX2.js +0 -1
- package/client/dist/assets/agent-CrcIj6WE2.js +0 -1
- package/client/dist/assets/agent-CtwLUmjl.js +0 -1
- package/client/dist/assets/agent-xG4qLg4R.js +0 -1
- package/client/dist/assets/index-BbVOi-dY.js +0 -158
- package/client/dist/assets/index-o3Q2Lii5.css +0 -2
- package/client/dist/assets/integrations-BQNkrfr7.js +0 -1
- package/client/dist/assets/integrations-BdN2f6bP.js +0 -1
- package/client/dist/assets/integrations-BrIUJmVf.js +0 -1
- package/client/dist/assets/integrations-CuWnMR5L.js +0 -1
- package/client/dist/assets/integrations-Cyp7cSYv2.js +0 -1
- package/client/dist/assets/integrations-DDR3OHdq.js +0 -1
- package/client/dist/assets/integrations-DVxi8b0j2.js +0 -1
- package/client/dist/assets/integrations-RuNEX3La2.js +0 -1
- package/client/dist/assets/nav-BFCUtHUQ2.js +0 -1
- package/client/dist/assets/nav-BouzorQ5.js +0 -1
- package/client/dist/assets/nav-Bpr-K0tD.js +0 -1
- package/client/dist/assets/nav-CpFrRDXd2.js +0 -1
- package/client/dist/assets/nav-CzKzuwH8.js +0 -1
- package/client/dist/assets/nav-Dkv4Vlr_2.js +0 -1
- package/client/dist/assets/nav-GG6azCbh.js +0 -1
- package/client/dist/assets/nav-prHkMqcr.js +0 -1
- /package/client/dist/assets/{activity-D8vQJrpW.js → activity-Dbl71S-E.js} +0 -0
- /package/client/dist/assets/{addspec-DxW6oPsk.js → addspec-DrXqP8ip.js} +0 -0
- /package/client/dist/assets/{agents-Cev2oFfX.js → agents-CGDn_3kB.js} +0 -0
- /package/client/dist/assets/{agentstudio-CZm2rOzt.js → agentstudio-Dxe_94PK.js} +0 -0
- /package/client/dist/assets/{aiedit-DYtnZU9H.js → aiedit-DrfHQnlz.js} +0 -0
- /package/client/dist/assets/{analytics-Ce-sPORu.js → analytics-CxDYcBl9.js} +0 -0
- /package/client/dist/assets/{attachments-Ci6_42Kh.js → attachments-DvxQbBTC.js} +0 -0
- /package/client/dist/assets/{auth-Cvsb7-Ek.js → auth-DpZq5p1e.js} +0 -0
- /package/client/dist/assets/{browser-CdS6O1Qb.js → browser-DM8G151q.js} +0 -0
- /package/client/dist/assets/{chat-VMflhzxn.js → chat-0dg5hOo_.js} +0 -0
- /package/client/dist/assets/{code-thSEptMx.js → code-B62fClk-.js} +0 -0
- /package/client/dist/assets/{commands-CckaBWdV.js → commands-DCJ-R9E4.js} +0 -0
- /package/client/dist/assets/{common-CYaT2yHp.js → common-DXrmj6WD.js} +0 -0
- /package/client/dist/assets/{dashboard-BawQCyrV.js → dashboard-DBuLfWo9.js} +0 -0
- /package/client/dist/assets/{explore-BKVV5JSu.js → explore-_XyU5e7R.js} +0 -0
- /package/client/dist/assets/{jira-B3613-gj.js → jira-DeIjwCK3.js} +0 -0
- /package/client/dist/assets/{jobs-D5sZzgLs.js → jobs-DrYmsKy5.js} +0 -0
- /package/client/dist/assets/{loops-Brnx4Fji.js → loops-CO6q75W8.js} +0 -0
- /package/client/dist/assets/{mcp-CIH0pH1K.js → mcp-HwBbQDk0.js} +0 -0
- /package/client/dist/assets/{settings-BFv6UbKV.js → settings-BYCMtxOz.js} +0 -0
- /package/client/dist/assets/{setup-RiUHzq7E.js → setup-D2CmgAro.js} +0 -0
- /package/client/dist/assets/{specs-CmEZY57v.js → specs-PGIOzMtc.js} +0 -0
- /package/client/dist/assets/{terminal-DFPNRLKp.js → terminal-CFt56A5f.js} +0 -0
- /package/client/dist/assets/{tickets-CkfbISuK.js → tickets-BHv3ewvq.js} +0 -0
|
@@ -3,13 +3,16 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.BACKGROUND_LOG_RETENTION_MS = void 0;
|
|
6
7
|
exports.trackTransientChild = trackTransientChild;
|
|
7
8
|
exports.killTransientChildren = killTransientChildren;
|
|
8
9
|
exports.startBackgroundProcess = startBackgroundProcess;
|
|
9
10
|
exports.getBackgroundProcess = getBackgroundProcess;
|
|
11
|
+
exports.getBackgroundProcessLogs = getBackgroundProcessLogs;
|
|
10
12
|
exports.listBackgroundProcesses = listBackgroundProcesses;
|
|
11
13
|
exports.killBackgroundProcess = killBackgroundProcess;
|
|
12
14
|
exports.killOwnedBackgroundProcess = killOwnedBackgroundProcess;
|
|
15
|
+
exports.killBackgroundProcessesForChat = killBackgroundProcessesForChat;
|
|
13
16
|
const tree_kill_1 = __importDefault(require("tree-kill"));
|
|
14
17
|
const child_process_1 = require("child_process");
|
|
15
18
|
const readline_1 = __importDefault(require("readline"));
|
|
@@ -25,16 +28,34 @@ const readline_1 = __importDefault(require("readline"));
|
|
|
25
28
|
*/
|
|
26
29
|
const byProject = new Map();
|
|
27
30
|
const backgroundByPid = new Map();
|
|
31
|
+
const finishedBackgroundByPid = new Map();
|
|
28
32
|
const backgroundTerminal = new Set(['exited', 'killed', 'failed']);
|
|
33
|
+
const BACKGROUND_KILL_GRACE_MS = 2500;
|
|
34
|
+
const BACKGROUND_OUTPUT_MAX_LINE_CHARS = 1000;
|
|
35
|
+
const BACKGROUND_OUTPUT_MAX_LINES_PER_SECOND = 20;
|
|
36
|
+
const BACKGROUND_LOG_MAX_LINES = 500;
|
|
37
|
+
exports.BACKGROUND_LOG_RETENTION_MS = 10 * 60 * 1000;
|
|
29
38
|
function treeKillSafe(pid, signal) {
|
|
30
39
|
try {
|
|
31
40
|
(0, tree_kill_1.default)(pid, signal, () => undefined);
|
|
32
41
|
}
|
|
33
42
|
catch { /* best-effort */ }
|
|
34
43
|
}
|
|
44
|
+
function treeKillWithEscalation(pid, isStillAlive = () => backgroundByPid.has(pid)) {
|
|
45
|
+
treeKillSafe(pid, 'SIGTERM');
|
|
46
|
+
const timer = setTimeout(() => {
|
|
47
|
+
if (isStillAlive())
|
|
48
|
+
treeKillSafe(pid, 'SIGKILL');
|
|
49
|
+
}, BACKGROUND_KILL_GRACE_MS);
|
|
50
|
+
timer.unref?.();
|
|
51
|
+
return timer;
|
|
52
|
+
}
|
|
35
53
|
function cloneProcess(process) {
|
|
36
54
|
return { ...process };
|
|
37
55
|
}
|
|
56
|
+
function cloneLogLine(line) {
|
|
57
|
+
return { ...line };
|
|
58
|
+
}
|
|
38
59
|
/** Track a child under a projectId; auto-removes itself on close. */
|
|
39
60
|
function trackTransientChild(projectId, child) {
|
|
40
61
|
let set = byProject.get(projectId);
|
|
@@ -54,13 +75,19 @@ function trackTransientChild(projectId, child) {
|
|
|
54
75
|
child.once('close', drop);
|
|
55
76
|
child.once('error', drop);
|
|
56
77
|
}
|
|
57
|
-
/** SIGTERM the whole subtree of every tracked child for a project, then
|
|
78
|
+
/** SIGTERM the whole subtree of every tracked child for a project, then escalate. */
|
|
58
79
|
function killTransientChildren(projectId) {
|
|
59
80
|
const set = byProject.get(projectId);
|
|
60
81
|
if (set)
|
|
61
82
|
for (const child of set) {
|
|
62
83
|
if (child.pid) {
|
|
63
|
-
|
|
84
|
+
if (backgroundByPid.has(child.pid))
|
|
85
|
+
continue;
|
|
86
|
+
let alive = true;
|
|
87
|
+
const timer = treeKillWithEscalation(child.pid, () => alive);
|
|
88
|
+
const clear = () => { alive = false; clearTimeout(timer); };
|
|
89
|
+
child.once('close', clear);
|
|
90
|
+
child.once('error', clear);
|
|
64
91
|
}
|
|
65
92
|
}
|
|
66
93
|
byProject.delete(projectId);
|
|
@@ -68,8 +95,7 @@ function killTransientChildren(projectId) {
|
|
|
68
95
|
if (record.process.projectId !== projectId)
|
|
69
96
|
continue;
|
|
70
97
|
markTerminal(record, 'killed', null, 'SIGTERM');
|
|
71
|
-
|
|
72
|
-
backgroundByPid.delete(pid);
|
|
98
|
+
terminateBackgroundRecord(record);
|
|
73
99
|
}
|
|
74
100
|
}
|
|
75
101
|
function startBackgroundProcess(command, cwd, chatId, projectId, hooks) {
|
|
@@ -91,19 +117,32 @@ function startBackgroundProcess(command, cwd, chatId, projectId, hooks) {
|
|
|
91
117
|
chatId,
|
|
92
118
|
projectId,
|
|
93
119
|
};
|
|
94
|
-
const
|
|
120
|
+
const staleFinished = finishedBackgroundByPid.get(child.pid);
|
|
121
|
+
if (staleFinished) {
|
|
122
|
+
clearTimeout(staleFinished.cleanupTimer);
|
|
123
|
+
finishedBackgroundByPid.delete(child.pid);
|
|
124
|
+
}
|
|
125
|
+
const record = {
|
|
126
|
+
child,
|
|
127
|
+
process,
|
|
128
|
+
hooks: hooks ?? {},
|
|
129
|
+
outputLines: [],
|
|
130
|
+
droppedOutputLines: 0,
|
|
131
|
+
};
|
|
95
132
|
backgroundByPid.set(child.pid, record);
|
|
96
133
|
trackTransientChild(projectId, child);
|
|
97
134
|
attachOutput(child, 'stdout', record);
|
|
98
135
|
attachOutput(child, 'stderr', record);
|
|
99
136
|
child.once('error', () => {
|
|
100
|
-
markTerminal(record, 'failed', null, null);
|
|
137
|
+
markTerminal(record, process.status === 'killed' ? 'killed' : 'failed', null, null);
|
|
101
138
|
backgroundByPid.delete(process.pid);
|
|
139
|
+
retainFinishedRecord(record);
|
|
102
140
|
});
|
|
103
141
|
child.once('close', (code, signal) => {
|
|
104
142
|
const status = process.status === 'killed' ? 'killed' : code === 0 ? 'exited' : 'failed';
|
|
105
143
|
markTerminal(record, status, code, signal);
|
|
106
144
|
backgroundByPid.delete(process.pid);
|
|
145
|
+
retainFinishedRecord(record);
|
|
107
146
|
});
|
|
108
147
|
record.hooks.onStarted?.(cloneProcess(process));
|
|
109
148
|
return cloneProcess(process);
|
|
@@ -111,27 +150,112 @@ function startBackgroundProcess(command, cwd, chatId, projectId, hooks) {
|
|
|
111
150
|
function attachOutput(child, source, record) {
|
|
112
151
|
const stream = source === 'stdout' ? child.stdout : child.stderr;
|
|
113
152
|
const rl = readline_1.default.createInterface({ input: stream });
|
|
153
|
+
let windowStart = Date.now();
|
|
154
|
+
let emittedInWindow = 0;
|
|
114
155
|
rl.on('line', (line) => {
|
|
156
|
+
const clipped = line.length > BACKGROUND_OUTPUT_MAX_LINE_CHARS ? `${line.slice(0, BACKGROUND_OUTPUT_MAX_LINE_CHARS)}...` : line;
|
|
157
|
+
appendOutputLine(record, source, clipped);
|
|
158
|
+
if (!record.hooks.onOutput)
|
|
159
|
+
return;
|
|
160
|
+
const now = Date.now();
|
|
161
|
+
if (now - windowStart >= 1000) {
|
|
162
|
+
windowStart = now;
|
|
163
|
+
emittedInWindow = 0;
|
|
164
|
+
}
|
|
165
|
+
if (emittedInWindow >= BACKGROUND_OUTPUT_MAX_LINES_PER_SECOND)
|
|
166
|
+
return;
|
|
167
|
+
emittedInWindow += 1;
|
|
115
168
|
record.hooks.onOutput?.({
|
|
116
169
|
pid: record.process.pid,
|
|
117
170
|
chatId: record.process.chatId,
|
|
118
171
|
projectId: record.process.projectId,
|
|
119
172
|
source,
|
|
120
|
-
line,
|
|
173
|
+
line: clipped,
|
|
121
174
|
});
|
|
122
175
|
});
|
|
123
176
|
}
|
|
177
|
+
function appendOutputLine(record, source, line) {
|
|
178
|
+
record.outputLines.push({ at: Date.now(), source, line });
|
|
179
|
+
if (record.outputLines.length > BACKGROUND_LOG_MAX_LINES) {
|
|
180
|
+
const overflow = record.outputLines.length - BACKGROUND_LOG_MAX_LINES;
|
|
181
|
+
record.outputLines.splice(0, overflow);
|
|
182
|
+
record.droppedOutputLines += overflow;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
function retainFinishedRecord(record) {
|
|
186
|
+
if (record.retained) {
|
|
187
|
+
const existing = finishedBackgroundByPid.get(record.process.pid);
|
|
188
|
+
if (existing) {
|
|
189
|
+
existing.process = cloneProcess(record.process);
|
|
190
|
+
existing.outputLines = record.outputLines.map(cloneLogLine);
|
|
191
|
+
existing.droppedOutputLines = record.droppedOutputLines;
|
|
192
|
+
}
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
record.retained = true;
|
|
196
|
+
const previous = finishedBackgroundByPid.get(record.process.pid);
|
|
197
|
+
if (previous)
|
|
198
|
+
clearTimeout(previous.cleanupTimer);
|
|
199
|
+
const cleanupTimer = setTimeout(() => {
|
|
200
|
+
finishedBackgroundByPid.delete(record.process.pid);
|
|
201
|
+
}, exports.BACKGROUND_LOG_RETENTION_MS);
|
|
202
|
+
cleanupTimer.unref?.();
|
|
203
|
+
finishedBackgroundByPid.set(record.process.pid, {
|
|
204
|
+
process: cloneProcess(record.process),
|
|
205
|
+
outputLines: record.outputLines.map(cloneLogLine),
|
|
206
|
+
droppedOutputLines: record.droppedOutputLines,
|
|
207
|
+
cleanupTimer,
|
|
208
|
+
});
|
|
209
|
+
}
|
|
124
210
|
function markTerminal(record, status, exitCode, signal) {
|
|
125
211
|
if (record.killTimer)
|
|
126
212
|
clearTimeout(record.killTimer);
|
|
127
213
|
record.process.status = status;
|
|
128
214
|
record.process.exitCode = exitCode;
|
|
129
215
|
record.process.signal = signal;
|
|
216
|
+
if (record.terminalNotified)
|
|
217
|
+
return;
|
|
218
|
+
record.terminalNotified = true;
|
|
130
219
|
record.hooks.onExited?.(cloneProcess(record.process));
|
|
131
220
|
}
|
|
132
221
|
function getBackgroundProcess(pid) {
|
|
133
222
|
const record = backgroundByPid.get(pid);
|
|
134
|
-
|
|
223
|
+
if (record)
|
|
224
|
+
return cloneProcess(record.process);
|
|
225
|
+
const finished = finishedBackgroundByPid.get(pid);
|
|
226
|
+
return finished ? cloneProcess(finished.process) : null;
|
|
227
|
+
}
|
|
228
|
+
function getBackgroundProcessLogs(pid, filter = {}) {
|
|
229
|
+
const live = backgroundByPid.get(pid);
|
|
230
|
+
const record = live
|
|
231
|
+
? {
|
|
232
|
+
process: live.process,
|
|
233
|
+
outputLines: live.outputLines,
|
|
234
|
+
droppedOutputLines: live.droppedOutputLines,
|
|
235
|
+
}
|
|
236
|
+
: finishedBackgroundByPid.get(pid);
|
|
237
|
+
if (!record)
|
|
238
|
+
return null;
|
|
239
|
+
if (filter.projectId && record.process.projectId !== filter.projectId)
|
|
240
|
+
return null;
|
|
241
|
+
if (filter.chatId && record.process.chatId !== filter.chatId)
|
|
242
|
+
return null;
|
|
243
|
+
const limit = typeof filter.limit === 'number' && Number.isFinite(filter.limit)
|
|
244
|
+
? Math.max(1, Math.min(BACKGROUND_LOG_MAX_LINES, Math.floor(filter.limit)))
|
|
245
|
+
: BACKGROUND_LOG_MAX_LINES;
|
|
246
|
+
const start = Math.max(0, record.outputLines.length - limit);
|
|
247
|
+
const lines = record.outputLines.slice(start).map(cloneLogLine);
|
|
248
|
+
const droppedByLimit = record.outputLines.length - lines.length;
|
|
249
|
+
const droppedLines = record.droppedOutputLines + droppedByLimit;
|
|
250
|
+
return {
|
|
251
|
+
process: cloneProcess(record.process),
|
|
252
|
+
lines,
|
|
253
|
+
truncated: droppedLines > 0,
|
|
254
|
+
droppedLines,
|
|
255
|
+
maxLines: BACKGROUND_LOG_MAX_LINES,
|
|
256
|
+
maxLineChars: BACKGROUND_OUTPUT_MAX_LINE_CHARS,
|
|
257
|
+
retentionMs: exports.BACKGROUND_LOG_RETENTION_MS,
|
|
258
|
+
};
|
|
135
259
|
}
|
|
136
260
|
function listBackgroundProcesses(filter = {}) {
|
|
137
261
|
const processes = [];
|
|
@@ -152,11 +276,7 @@ function killBackgroundProcess(pid) {
|
|
|
152
276
|
if (!record)
|
|
153
277
|
return;
|
|
154
278
|
record.process.status = 'killed';
|
|
155
|
-
|
|
156
|
-
record.killTimer = setTimeout(() => {
|
|
157
|
-
if (backgroundByPid.has(pid))
|
|
158
|
-
treeKillSafe(pid, 'SIGKILL');
|
|
159
|
-
}, 2500);
|
|
279
|
+
terminateBackgroundRecord(record);
|
|
160
280
|
}
|
|
161
281
|
function killOwnedBackgroundProcess(pid, owner) {
|
|
162
282
|
const record = backgroundByPid.get(pid);
|
|
@@ -169,3 +289,22 @@ function killOwnedBackgroundProcess(pid, owner) {
|
|
|
169
289
|
killBackgroundProcess(pid);
|
|
170
290
|
return true;
|
|
171
291
|
}
|
|
292
|
+
function terminateBackgroundRecord(record) {
|
|
293
|
+
if (record.killTimer)
|
|
294
|
+
clearTimeout(record.killTimer);
|
|
295
|
+
record.killTimer = treeKillWithEscalation(record.process.pid);
|
|
296
|
+
}
|
|
297
|
+
function killBackgroundProcessesForChat(chatId, projectId) {
|
|
298
|
+
let killed = 0;
|
|
299
|
+
for (const record of backgroundByPid.values()) {
|
|
300
|
+
if (record.process.chatId !== chatId)
|
|
301
|
+
continue;
|
|
302
|
+
if (projectId && record.process.projectId !== projectId)
|
|
303
|
+
continue;
|
|
304
|
+
record.process.status = 'killed';
|
|
305
|
+
markTerminal(record, 'killed', null, 'SIGTERM');
|
|
306
|
+
terminateBackgroundRecord(record);
|
|
307
|
+
killed += 1;
|
|
308
|
+
}
|
|
309
|
+
return killed;
|
|
310
|
+
}
|
|
@@ -29,6 +29,7 @@ exports.spawnCodex = spawnCodex;
|
|
|
29
29
|
exports.spawnGemini = spawnGemini;
|
|
30
30
|
exports.spawnAiCli = spawnAiCli;
|
|
31
31
|
const win_spawn_1 = require("./win-spawn");
|
|
32
|
+
const headroom_routing_1 = require("../headroom-routing");
|
|
32
33
|
// Per-call (not a frozen module const) so a test can flip the platform with a
|
|
33
34
|
// `process.platform` spy without re-importing this module — which removes a
|
|
34
35
|
// flaky vi.doMock + resetModules + dynamic-import dance in the spawn tests.
|
|
@@ -147,6 +148,7 @@ function ensureStdinPipe(stdio) {
|
|
|
147
148
|
* survive. POSIX call is identical to `spawnCli('claude', args, options)`.
|
|
148
149
|
*/
|
|
149
150
|
function spawnClaude(args, options = {}) {
|
|
151
|
+
options = (0, headroom_routing_1.withHeadroomSpawnEnv)('claude', options);
|
|
150
152
|
if (!isWin()) {
|
|
151
153
|
return (0, win_spawn_1.spawnCli)('claude', args, options);
|
|
152
154
|
}
|
|
@@ -169,6 +171,7 @@ function spawnClaude(args, options = {}) {
|
|
|
169
171
|
* survive. POSIX call is identical to `spawnCli('codex', args, options)`.
|
|
170
172
|
*/
|
|
171
173
|
function spawnCodex(args, options = {}) {
|
|
174
|
+
options = (0, headroom_routing_1.withHeadroomSpawnEnv)('codex', options);
|
|
172
175
|
if (!isWin()) {
|
|
173
176
|
return (0, win_spawn_1.spawnCli)('codex', args, options);
|
|
174
177
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{a as e}from"./chunk-BNv3lrIs.js";import{I as t,Rn as n,n as r,qn as i,s as a,wn as o,zn as s}from"./index-BbVOi-dY.js";var c=e(i(),1);function l(e,t){let n=e.indexOf(`,`);if(!e.startsWith(`data:`)||n===-1)throw Error(`dataUrlToFile: not a data URL`);let r=e.slice(0,n),i=/^data:([^;,]+)/.exec(r)?.[1]||`application/octet-stream`,a=e.slice(n+1);if(/;base64$/i.test(r)){let e=atob(a),n=new Uint8Array(e.length);for(let t=0;t<e.length;t++)n[t]=e.charCodeAt(t);return new File([n],t,{type:i})}return new File([decodeURIComponent(a)],t,{type:i})}var u=o();function d({projectId:e,conversationId:i}){let{t:o}=s(`agent`),{closeBrowser:d,queueCapture:f}=r(),p=(0,c.useMemo)(()=>`agent-${i??`home`}-${Math.round(performance.now())}`,[i]),m=async e=>{if(!i){n.error(o(`workspace.requiresConversation`));return}try{f(await a(i,l(e.screenshotDataUrl,`capture-${Date.now()}.png`))),n.success(o(`workspace.browserCaptured`)),d()}catch(e){n.error(o(`workspace.uploadFailed`),{description:e instanceof Error?e.message:void 0})}};return(0,u.jsx)(t,{open:!0,onClose:d,projectId:e,pendingSpecId:p,confirmLabel:o(`workspace.browserConfirm`),onCaptured:e=>{m(e)}})}export{d as AgentBrowserCapture};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{a as e}from"./chunk-BNv3lrIs.js";import{$ as t,H as n,Kn as r,Q as i,Tt as a,ot as o,qn as s,wn as c,zn as l}from"./index-BbVOi-dY.js";import u from"./IntegrationsPage-X8bLyuDk.js";var d=e(s(),1),f=e(r(),1),p=c();function m({onClose:e}){let{t:r}=l(`nav`),{t:s}=l(`common`),{panelRef:c,panelStyle:m,headerHandleProps:h,resizeHandles:g,isFloating:_,guardBackdrop:v}=t({minWidth:320,minHeight:200,persistKey:`specrails-desktop:agent-integrations-modal`});return(0,d.useEffect)(()=>{function t(t){t.key===`Escape`&&e()}return window.addEventListener(`keydown`,t),()=>window.removeEventListener(`keydown`,t)},[e]),(0,f.createPortal)((0,p.jsx)(n,{delayDuration:400,children:(0,p.jsxs)(`div`,{className:`fixed inset-0 z-[65] flex items-stretch justify-center`,children:[(0,p.jsx)(`div`,{className:`absolute inset-0 bg-black/50 backdrop-blur-sm`,onClick:v(e)}),(0,p.jsxs)(`div`,{ref:c,className:`relative m-3 flex w-full flex-col overflow-hidden rounded-xl border border-border/30 glass-card animate-in fade-in zoom-in-95 duration-200`,style:m,children:[(0,p.jsxs)(`div`,{...h,className:`flex items-center justify-between border-b border-border/30 px-4 py-3${_?` cursor-grab active:cursor-grabbing`:``}`,children:[(0,p.jsxs)(`div`,{className:`flex min-w-0 items-center gap-2`,children:[(0,p.jsx)(a,{className:`h-4 w-4 flex-shrink-0 text-accent-primary`}),(0,p.jsx)(`h2`,{className:`truncate text-sm font-semibold text-foreground`,children:r(`rightSidebar.integrations`)})]}),(0,p.jsx)(`button`,{type:`button`,onClick:e,"aria-label":s(`actions.close`),className:`flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-surface/50 hover:text-foreground`,children:(0,p.jsx)(o,{className:`h-4 w-4`})})]}),(0,p.jsx)(`div`,{className:`min-h-0 flex-1 overflow-auto`,children:(0,p.jsx)(u,{})})]}),(0,p.jsx)(i,{handles:g})]})}),document.body)}export{m as AgentIntegrationsModal};
|