@bulletproof-sh/ctrl-daemon 0.0.13 → 0.0.15
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/index.js +104 -104
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -11,6 +11,7 @@ var __export = (target, all) => {
|
|
|
11
11
|
};
|
|
12
12
|
|
|
13
13
|
// src/index.ts
|
|
14
|
+
import * as fs3 from "fs";
|
|
14
15
|
import * as path3 from "path";
|
|
15
16
|
|
|
16
17
|
// src/analytics.ts
|
|
@@ -4315,7 +4316,7 @@ var PANEL_MARGIN_X = 5;
|
|
|
4315
4316
|
var PANEL_MARGIN_Y = 3;
|
|
4316
4317
|
var PANEL_MIN_WIDTH = 40;
|
|
4317
4318
|
var PANEL_MIN_HEIGHT = 12;
|
|
4318
|
-
var PANEL_HEADER_HEIGHT =
|
|
4319
|
+
var PANEL_HEADER_HEIGHT = 9;
|
|
4319
4320
|
var LOG_RING_SIZE = 200;
|
|
4320
4321
|
var BORDER_GLOW_SPEED = 0.05;
|
|
4321
4322
|
var BOX = {
|
|
@@ -4842,10 +4843,19 @@ function restoreConsole() {
|
|
|
4842
4843
|
}
|
|
4843
4844
|
|
|
4844
4845
|
// src/sessionWatcher.ts
|
|
4845
|
-
|
|
4846
|
+
var SHARED_BUF_SIZE = 64 * 1024;
|
|
4847
|
+
var sharedReadBuf = Buffer.allocUnsafe(SHARED_BUF_SIZE);
|
|
4848
|
+
function startSessionWatcher(agentId, filePath, agents, openFds, staleAgents, fileWatchers, pollingTimers, waitingTimers, permissionTimers, broadcast) {
|
|
4849
|
+
try {
|
|
4850
|
+
const fd = fs.openSync(filePath, "r");
|
|
4851
|
+
openFds.set(agentId, fd);
|
|
4852
|
+
} catch (e) {
|
|
4853
|
+
daemonLog(`Failed to open fd for agent ${agentId}: ${e}`);
|
|
4854
|
+
return;
|
|
4855
|
+
}
|
|
4846
4856
|
try {
|
|
4847
4857
|
const watcher = fs.watch(filePath, () => {
|
|
4848
|
-
readNewLines(agentId, agents, waitingTimers, permissionTimers, broadcast);
|
|
4858
|
+
readNewLines(agentId, agents, openFds, staleAgents, waitingTimers, permissionTimers, broadcast);
|
|
4849
4859
|
});
|
|
4850
4860
|
fileWatchers.set(agentId, watcher);
|
|
4851
4861
|
} catch (e) {
|
|
@@ -4856,47 +4866,58 @@ function startSessionWatcher(agentId, filePath, agents, fileWatchers, pollingTim
|
|
|
4856
4866
|
clearInterval(interval);
|
|
4857
4867
|
return;
|
|
4858
4868
|
}
|
|
4859
|
-
readNewLines(agentId, agents, waitingTimers, permissionTimers, broadcast);
|
|
4869
|
+
readNewLines(agentId, agents, openFds, staleAgents, waitingTimers, permissionTimers, broadcast);
|
|
4860
4870
|
}, FILE_WATCHER_POLL_INTERVAL_MS);
|
|
4861
4871
|
pollingTimers.set(agentId, interval);
|
|
4862
4872
|
}
|
|
4863
|
-
function readNewLines(agentId, agents, waitingTimers, permissionTimers, broadcast) {
|
|
4873
|
+
function readNewLines(agentId, agents, openFds, staleAgents, waitingTimers, permissionTimers, broadcast) {
|
|
4864
4874
|
const agent = agents.get(agentId);
|
|
4865
4875
|
if (!agent)
|
|
4866
4876
|
return;
|
|
4877
|
+
const fd = openFds.get(agentId);
|
|
4878
|
+
if (fd === undefined)
|
|
4879
|
+
return;
|
|
4867
4880
|
try {
|
|
4868
|
-
const stat = fs.
|
|
4881
|
+
const stat = fs.fstatSync(fd);
|
|
4869
4882
|
if (stat.size <= agent.fileOffset)
|
|
4870
4883
|
return;
|
|
4871
|
-
const
|
|
4872
|
-
const
|
|
4873
|
-
fs.readSync(fd, buf, 0,
|
|
4874
|
-
fs.closeSync(fd);
|
|
4884
|
+
const readSize = stat.size - agent.fileOffset;
|
|
4885
|
+
const buf = readSize <= sharedReadBuf.length ? sharedReadBuf : Buffer.allocUnsafe(readSize);
|
|
4886
|
+
const bytesRead = fs.readSync(fd, buf, 0, readSize, agent.fileOffset);
|
|
4875
4887
|
agent.fileOffset = stat.size;
|
|
4876
|
-
const text = agent.lineBuffer + buf.toString("utf-8");
|
|
4888
|
+
const text = agent.lineBuffer + buf.toString("utf-8", 0, bytesRead);
|
|
4877
4889
|
const lines = text.split(`
|
|
4878
4890
|
`);
|
|
4879
4891
|
agent.lineBuffer = lines.pop() || "";
|
|
4880
|
-
|
|
4881
|
-
if (hasLines) {
|
|
4882
|
-
agent.lastActivityAt = Date.now();
|
|
4883
|
-
cancelWaitingTimer(agentId, waitingTimers);
|
|
4884
|
-
cancelPermissionTimer(agentId, permissionTimers);
|
|
4885
|
-
if (agent.permissionSent) {
|
|
4886
|
-
agent.permissionSent = false;
|
|
4887
|
-
broadcast({ type: "agentToolPermissionClear", id: agentId });
|
|
4888
|
-
}
|
|
4889
|
-
}
|
|
4892
|
+
let activityUpdated = false;
|
|
4890
4893
|
for (const line of lines) {
|
|
4891
4894
|
if (!line.trim())
|
|
4892
4895
|
continue;
|
|
4896
|
+
if (!activityUpdated) {
|
|
4897
|
+
agent.lastActivityAt = Date.now();
|
|
4898
|
+
cancelWaitingTimer(agentId, waitingTimers);
|
|
4899
|
+
cancelPermissionTimer(agentId, permissionTimers);
|
|
4900
|
+
if (agent.permissionSent) {
|
|
4901
|
+
agent.permissionSent = false;
|
|
4902
|
+
broadcast({ type: "agentToolPermissionClear", id: agentId });
|
|
4903
|
+
}
|
|
4904
|
+
activityUpdated = true;
|
|
4905
|
+
}
|
|
4893
4906
|
processTranscriptLine(agentId, line, agents, waitingTimers, permissionTimers, broadcast);
|
|
4894
4907
|
}
|
|
4895
4908
|
} catch (e) {
|
|
4896
4909
|
daemonLog(`Read error for agent ${agentId}: ${e}`);
|
|
4910
|
+
staleAgents.add(agentId);
|
|
4897
4911
|
}
|
|
4898
4912
|
}
|
|
4899
|
-
function stopSessionWatcher(agentId, fileWatchers, pollingTimers, waitingTimers, permissionTimers) {
|
|
4913
|
+
function stopSessionWatcher(agentId, openFds, fileWatchers, pollingTimers, waitingTimers, permissionTimers) {
|
|
4914
|
+
const fd = openFds.get(agentId);
|
|
4915
|
+
if (fd !== undefined) {
|
|
4916
|
+
try {
|
|
4917
|
+
fs.closeSync(fd);
|
|
4918
|
+
} catch {}
|
|
4919
|
+
openFds.delete(agentId);
|
|
4920
|
+
}
|
|
4900
4921
|
fileWatchers.get(agentId)?.close();
|
|
4901
4922
|
fileWatchers.delete(agentId);
|
|
4902
4923
|
const pt = pollingTimers.get(agentId);
|
|
@@ -4960,7 +4981,7 @@ function collectAllJsonlFiles(projectsRoot) {
|
|
|
4960
4981
|
}
|
|
4961
4982
|
return files;
|
|
4962
4983
|
}
|
|
4963
|
-
function startProjectScanner(rootDir, scanAll, agents, fileWatchers, pollingTimers, waitingTimers, permissionTimers, broadcast, idleTimeoutMs) {
|
|
4984
|
+
function startProjectScanner(rootDir, scanAll, agents, openFds, staleAgents, fileWatchers, pollingTimers, waitingTimers, permissionTimers, broadcast, idleTimeoutMs) {
|
|
4964
4985
|
const knownJsonlFiles = new Set;
|
|
4965
4986
|
let nextAgentId = 1;
|
|
4966
4987
|
function scan() {
|
|
@@ -4993,17 +5014,18 @@ function startProjectScanner(rootDir, scanAll, agents, fileWatchers, pollingTime
|
|
|
4993
5014
|
agents.set(id, agent);
|
|
4994
5015
|
daemonLog(`Agent ${id}: watching ${path2.basename(filePath)}`);
|
|
4995
5016
|
broadcast({ type: "agentCreated", id });
|
|
4996
|
-
startSessionWatcher(id, filePath, agents, fileWatchers, pollingTimers, waitingTimers, permissionTimers, broadcast);
|
|
4997
|
-
readNewLines(id, agents, waitingTimers, permissionTimers, broadcast);
|
|
5017
|
+
startSessionWatcher(id, filePath, agents, openFds, staleAgents, fileWatchers, pollingTimers, waitingTimers, permissionTimers, broadcast);
|
|
5018
|
+
readNewLines(id, agents, openFds, staleAgents, waitingTimers, permissionTimers, broadcast);
|
|
4998
5019
|
}
|
|
4999
5020
|
for (const [agentId, agent] of agents) {
|
|
5000
5021
|
const lastActivity = agent.lastActivityAt || 0;
|
|
5001
5022
|
const idle = now - lastActivity > idleTimeoutMs;
|
|
5002
|
-
const removed =
|
|
5023
|
+
const removed = staleAgents.has(agentId);
|
|
5003
5024
|
if (removed || idle) {
|
|
5004
5025
|
const reason = removed ? "JSONL removed" : "idle timeout";
|
|
5005
5026
|
daemonLog(`Agent ${agentId}: ${reason}, closing`);
|
|
5006
|
-
|
|
5027
|
+
staleAgents.delete(agentId);
|
|
5028
|
+
stopSessionWatcher(agentId, openFds, fileWatchers, pollingTimers, waitingTimers, permissionTimers);
|
|
5007
5029
|
agents.delete(agentId);
|
|
5008
5030
|
knownJsonlFiles.delete(agent.jsonlFile);
|
|
5009
5031
|
broadcast({ type: "agentClosed", id: agentId });
|
|
@@ -5118,6 +5140,7 @@ var CURSOR_SHOW = "\x1B[?25h";
|
|
|
5118
5140
|
var CLEAR_SCREEN = "\x1B[2J";
|
|
5119
5141
|
var RESET_ATTRS = "\x1B[0m";
|
|
5120
5142
|
var resizeCallback = null;
|
|
5143
|
+
var moveToTable = [];
|
|
5121
5144
|
function onSigwinch() {
|
|
5122
5145
|
resizeCallback?.();
|
|
5123
5146
|
}
|
|
@@ -5144,8 +5167,19 @@ function offResize() {
|
|
|
5144
5167
|
resizeCallback = null;
|
|
5145
5168
|
process.removeListener("SIGWINCH", onSigwinch);
|
|
5146
5169
|
}
|
|
5170
|
+
function buildMoveToTable(rows, cols) {
|
|
5171
|
+
const table = [];
|
|
5172
|
+
for (let r = 0;r <= rows; r++) {
|
|
5173
|
+
const row = [];
|
|
5174
|
+
for (let c = 0;c <= cols; c++) {
|
|
5175
|
+
row.push(`\x1B[${r};${c}H`);
|
|
5176
|
+
}
|
|
5177
|
+
table.push(row);
|
|
5178
|
+
}
|
|
5179
|
+
moveToTable = table;
|
|
5180
|
+
}
|
|
5147
5181
|
function moveTo(row, col) {
|
|
5148
|
-
return `\x1B[${row};${col}H`;
|
|
5182
|
+
return moveToTable[row]?.[col] ?? `\x1B[${row};${col}H`;
|
|
5149
5183
|
}
|
|
5150
5184
|
|
|
5151
5185
|
// src/tui/renderer.ts
|
|
@@ -5182,7 +5216,7 @@ function setCell(buf, row, col, char, fg, bold, dim) {
|
|
|
5182
5216
|
}
|
|
5183
5217
|
}
|
|
5184
5218
|
function flushDiff(current, previous) {
|
|
5185
|
-
|
|
5219
|
+
const parts = [];
|
|
5186
5220
|
let lastFg = "\x00";
|
|
5187
5221
|
let lastBold = false;
|
|
5188
5222
|
let lastDim = false;
|
|
@@ -5198,7 +5232,7 @@ function flushDiff(current, previous) {
|
|
|
5198
5232
|
const prev = prevRow[c];
|
|
5199
5233
|
if (cur.char === " " && cur.fg === "" && prev.char === " " && prev.fg === "") {
|
|
5200
5234
|
if (runStart !== -1) {
|
|
5201
|
-
|
|
5235
|
+
parts.push(flushRun(curRow, r, runStart, c, lastFg, lastBold, lastDim));
|
|
5202
5236
|
const last = curRow[c - 1];
|
|
5203
5237
|
lastFg = last.fg;
|
|
5204
5238
|
lastBold = last.bold;
|
|
@@ -5216,7 +5250,7 @@ function flushDiff(current, previous) {
|
|
|
5216
5250
|
if (runStart === -1)
|
|
5217
5251
|
runStart = c;
|
|
5218
5252
|
} else if (runStart !== -1) {
|
|
5219
|
-
|
|
5253
|
+
parts.push(flushRun(curRow, r, runStart, c, lastFg, lastBold, lastDim));
|
|
5220
5254
|
const last = curRow[c - 1];
|
|
5221
5255
|
lastFg = last.fg;
|
|
5222
5256
|
lastBold = last.bold;
|
|
@@ -5225,9 +5259,9 @@ function flushDiff(current, previous) {
|
|
|
5225
5259
|
}
|
|
5226
5260
|
}
|
|
5227
5261
|
}
|
|
5228
|
-
if (
|
|
5229
|
-
|
|
5230
|
-
process.stdout.write(
|
|
5262
|
+
if (parts.length > 0) {
|
|
5263
|
+
parts.push(RESET);
|
|
5264
|
+
process.stdout.write(parts.join(""));
|
|
5231
5265
|
}
|
|
5232
5266
|
}
|
|
5233
5267
|
function flushRun(row, r, start, end, lastFg, lastBold, lastDim) {
|
|
@@ -5331,33 +5365,21 @@ function renderPanel(buf, panel, logs, agentCount, clientCount, version2, webUrl
|
|
|
5331
5365
|
}
|
|
5332
5366
|
}
|
|
5333
5367
|
if (version2 && LOGO_LINES.length >= 3) {
|
|
5334
|
-
const
|
|
5368
|
+
const infoStr = `v${version2} \xB7 ${agentCount} agent${agentCount !== 1 ? "s" : ""} \xB7 ${clientCount} client${clientCount !== 1 ? "s" : ""}`;
|
|
5335
5369
|
const maxLen = innerWidth - (LOGO_LINES[2]?.length || 0) - 3;
|
|
5336
|
-
if (maxLen > 4) {
|
|
5337
|
-
const trimmed = vStr.slice(0, maxLen);
|
|
5338
|
-
const col = x + width - 2 - trimmed.length;
|
|
5339
|
-
writeString(buf, logoStartRow + 2, col, trimmed, CYAN_FG, false, true);
|
|
5340
|
-
}
|
|
5341
|
-
}
|
|
5342
|
-
if (LOGO_LINES.length >= 4) {
|
|
5343
|
-
const maxLen = innerWidth - (LOGO_LINES[3]?.length || 0) - 3;
|
|
5344
5370
|
if (maxLen > 10) {
|
|
5345
|
-
const trimmed =
|
|
5371
|
+
const trimmed = infoStr.slice(0, maxLen);
|
|
5346
5372
|
const col = x + width - 2 - trimmed.length;
|
|
5347
|
-
writeString(buf, logoStartRow +
|
|
5373
|
+
writeString(buf, logoStartRow + 2, col, trimmed, CYAN_FG, false, true);
|
|
5348
5374
|
}
|
|
5349
5375
|
}
|
|
5350
|
-
|
|
5351
|
-
|
|
5352
|
-
const
|
|
5353
|
-
const
|
|
5354
|
-
|
|
5355
|
-
const trimmed = statusStr.slice(0, maxCountLen);
|
|
5356
|
-
const countCol = x + width - 2 - trimmed.length;
|
|
5357
|
-
writeString(buf, logoStartRow + 4, countCol, trimmed, BRIGHT_GREEN_FG, false, false);
|
|
5358
|
-
}
|
|
5376
|
+
const urlRow = logoStartRow + LOGO_LINES.length;
|
|
5377
|
+
if (urlRow < y + height - 2) {
|
|
5378
|
+
const trimmed = webUrl.slice(0, innerWidth - 2);
|
|
5379
|
+
const col = x + 1 + Math.floor((innerWidth - trimmed.length) / 2);
|
|
5380
|
+
writeString(buf, urlRow, col, trimmed, CYAN_FG, false, false);
|
|
5359
5381
|
}
|
|
5360
|
-
const sepRow =
|
|
5382
|
+
const sepRow = urlRow + 1;
|
|
5361
5383
|
if (sepRow < y + height - 1) {
|
|
5362
5384
|
const sepBorderIdx = Math.floor(glowPosition) % perimeter;
|
|
5363
5385
|
setCell(buf, sepRow, x, BOX.teeLeft, borderColor(sepBorderIdx, perimeter), false, false);
|
|
@@ -5478,9 +5500,7 @@ for (let offset = 0;offset <= 4; offset++) {
|
|
|
5478
5500
|
}
|
|
5479
5501
|
GRADIENT_STRINGS.push(arr);
|
|
5480
5502
|
}
|
|
5481
|
-
var
|
|
5482
|
-
var LIGHTNING_NEAR = fg256(159);
|
|
5483
|
-
var LIGHTNING_TAIL = fg256(49);
|
|
5503
|
+
var LIGHTNING_COLORS = [fg256(231), fg256(159), fg256(49)];
|
|
5484
5504
|
function renderRain(layers, buf, panel) {
|
|
5485
5505
|
const bufRows = buf.rows;
|
|
5486
5506
|
const bufCols = buf.cols;
|
|
@@ -5495,51 +5515,22 @@ function renderRain(layers, buf, panel) {
|
|
|
5495
5515
|
const gradStrs = GRADIENT_STRINGS[brightnessOffset];
|
|
5496
5516
|
const colCount = Math.min(layer.columns.length, bufCols);
|
|
5497
5517
|
for (let col = 0;col < colCount; col++) {
|
|
5498
|
-
|
|
5499
|
-
|
|
5500
|
-
|
|
5501
|
-
|
|
5502
|
-
|
|
5503
|
-
|
|
5504
|
-
|
|
5505
|
-
|
|
5506
|
-
|
|
5507
|
-
|
|
5508
|
-
|
|
5509
|
-
|
|
5510
|
-
|
|
5511
|
-
|
|
5512
|
-
|
|
5513
|
-
|
|
5514
|
-
const gradIdx = trailLen > 1 ? i * gradLen / (trailLen - 1) | 0 : 0;
|
|
5515
|
-
color = gradStrs[Math.min(gradIdx, gradLen)];
|
|
5516
|
-
}
|
|
5517
|
-
const bold = i === 0 || drop.isLightning;
|
|
5518
|
-
const dim = !drop.isLightning && i > trailLen * 0.7;
|
|
5519
|
-
setCell(buf, row, col, drop.chars[i], color, bold, dim);
|
|
5520
|
-
}
|
|
5521
|
-
}
|
|
5522
|
-
} else {
|
|
5523
|
-
const drops = layer.columns[col].drops;
|
|
5524
|
-
for (let d = 0;d < drops.length; d++) {
|
|
5525
|
-
const drop = drops[d];
|
|
5526
|
-
const headRow = drop.y | 0;
|
|
5527
|
-
const trailLen = drop.trailLen;
|
|
5528
|
-
for (let i = 0;i < trailLen; i++) {
|
|
5529
|
-
const row = headRow - i;
|
|
5530
|
-
if (row < 0 || row >= bufRows)
|
|
5531
|
-
continue;
|
|
5532
|
-
let color;
|
|
5533
|
-
if (drop.isLightning) {
|
|
5534
|
-
color = i === 0 ? LIGHTNING_HEAD : i === 1 ? LIGHTNING_NEAR : LIGHTNING_TAIL;
|
|
5535
|
-
} else {
|
|
5536
|
-
const gradIdx = trailLen > 1 ? i * gradLen / (trailLen - 1) | 0 : 0;
|
|
5537
|
-
color = gradStrs[Math.min(gradIdx, gradLen)];
|
|
5538
|
-
}
|
|
5539
|
-
const bold = i === 0 || drop.isLightning;
|
|
5540
|
-
const dim = !drop.isLightning && i > trailLen * 0.7;
|
|
5541
|
-
setCell(buf, row, col, drop.chars[i], color, bold, dim);
|
|
5542
|
-
}
|
|
5518
|
+
const checkPanel = panelVisible && col >= panelX && col < panelX2;
|
|
5519
|
+
const drops = layer.columns[col].drops;
|
|
5520
|
+
for (let d = 0;d < drops.length; d++) {
|
|
5521
|
+
const drop = drops[d];
|
|
5522
|
+
const headRow = drop.y | 0;
|
|
5523
|
+
const trailLen = drop.trailLen;
|
|
5524
|
+
for (let i = 0;i < trailLen; i++) {
|
|
5525
|
+
const row = headRow - i;
|
|
5526
|
+
if (row < 0 || row >= bufRows)
|
|
5527
|
+
continue;
|
|
5528
|
+
if (checkPanel && row >= panelY && row < panelY2)
|
|
5529
|
+
continue;
|
|
5530
|
+
const color = drop.isLightning ? LIGHTNING_COLORS[Math.min(i, 2)] : gradStrs[Math.min(trailLen > 1 ? i * gradLen / (trailLen - 1) | 0 : 0, gradLen)];
|
|
5531
|
+
const bold = i === 0 || drop.isLightning;
|
|
5532
|
+
const dim = !drop.isLightning && i > trailLen * 0.7;
|
|
5533
|
+
setCell(buf, row, col, drop.chars[i], color, bold, dim);
|
|
5543
5534
|
}
|
|
5544
5535
|
}
|
|
5545
5536
|
}
|
|
@@ -5566,6 +5557,7 @@ var tuiOptions = null;
|
|
|
5566
5557
|
function handleResize() {
|
|
5567
5558
|
const { rows, cols } = getTerminalSize();
|
|
5568
5559
|
clearScreen();
|
|
5560
|
+
buildMoveToTable(rows, cols);
|
|
5569
5561
|
bufA = createFrameBuffer(rows, cols);
|
|
5570
5562
|
bufB = createFrameBuffer(rows, cols);
|
|
5571
5563
|
currentIsA = true;
|
|
@@ -5599,6 +5591,7 @@ function startTui(options) {
|
|
|
5599
5591
|
tuiOptions = options;
|
|
5600
5592
|
enterAltScreen();
|
|
5601
5593
|
const { rows, cols } = getTerminalSize();
|
|
5594
|
+
buildMoveToTable(rows, cols);
|
|
5602
5595
|
bufA = createFrameBuffer(rows, cols);
|
|
5603
5596
|
bufB = createFrameBuffer(rows, cols);
|
|
5604
5597
|
currentIsA = true;
|
|
@@ -5766,6 +5759,8 @@ async function main() {
|
|
|
5766
5759
|
scanDirs = [projectsRoot];
|
|
5767
5760
|
}
|
|
5768
5761
|
const agents = new Map;
|
|
5762
|
+
const openFds = new Map;
|
|
5763
|
+
const staleAgents = new Set;
|
|
5769
5764
|
const fileWatchers = new Map;
|
|
5770
5765
|
const pollingTimers = new Map;
|
|
5771
5766
|
const waitingTimers = new Map;
|
|
@@ -5796,7 +5791,7 @@ async function main() {
|
|
|
5796
5791
|
...analyticsConfig
|
|
5797
5792
|
});
|
|
5798
5793
|
const scanAll = !projectDir;
|
|
5799
|
-
const scanner = startProjectScanner(scanDirs[0], scanAll, agents, fileWatchers, pollingTimers, waitingTimers, permissionTimers, broadcast, idleTimeoutMs);
|
|
5794
|
+
const scanner = startProjectScanner(scanDirs[0], scanAll, agents, openFds, staleAgents, fileWatchers, pollingTimers, waitingTimers, permissionTimers, broadcast, idleTimeoutMs);
|
|
5800
5795
|
const updateCheckTimer = setInterval(async () => {
|
|
5801
5796
|
const msg = await checkForUpdate();
|
|
5802
5797
|
if (msg) {
|
|
@@ -5810,6 +5805,11 @@ async function main() {
|
|
|
5810
5805
|
[ctrl-daemon] Shutting down...`);
|
|
5811
5806
|
scanner.stop();
|
|
5812
5807
|
server.stop();
|
|
5808
|
+
for (const fd of openFds.values()) {
|
|
5809
|
+
try {
|
|
5810
|
+
fs3.closeSync(fd);
|
|
5811
|
+
} catch {}
|
|
5812
|
+
}
|
|
5813
5813
|
for (const watcher of fileWatchers.values())
|
|
5814
5814
|
watcher.close();
|
|
5815
5815
|
for (const timer of pollingTimers.values())
|