@hydra-acp/cli 0.1.2 → 0.1.3
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/README.md +4 -2
- package/dist/cli.js +1195 -374
- package/dist/index.d.ts +12 -1
- package/dist/index.js +125 -21
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -92,10 +92,13 @@ declare const HydraConfig: z.ZodObject<{
|
|
|
92
92
|
}>>>;
|
|
93
93
|
tui: z.ZodDefault<z.ZodObject<{
|
|
94
94
|
repaintThrottleMs: z.ZodDefault<z.ZodNumber>;
|
|
95
|
+
maxScrollbackLines: z.ZodDefault<z.ZodNumber>;
|
|
95
96
|
}, "strip", z.ZodTypeAny, {
|
|
96
97
|
repaintThrottleMs: number;
|
|
98
|
+
maxScrollbackLines: number;
|
|
97
99
|
}, {
|
|
98
100
|
repaintThrottleMs?: number | undefined;
|
|
101
|
+
maxScrollbackLines?: number | undefined;
|
|
99
102
|
}>>;
|
|
100
103
|
}, "strip", z.ZodTypeAny, {
|
|
101
104
|
daemon: {
|
|
@@ -117,6 +120,7 @@ declare const HydraConfig: z.ZodObject<{
|
|
|
117
120
|
}>;
|
|
118
121
|
tui: {
|
|
119
122
|
repaintThrottleMs: number;
|
|
123
|
+
maxScrollbackLines: number;
|
|
120
124
|
};
|
|
121
125
|
registry: {
|
|
122
126
|
url: string;
|
|
@@ -145,6 +149,7 @@ declare const HydraConfig: z.ZodObject<{
|
|
|
145
149
|
}> | undefined;
|
|
146
150
|
tui?: {
|
|
147
151
|
repaintThrottleMs?: number | undefined;
|
|
152
|
+
maxScrollbackLines?: number | undefined;
|
|
148
153
|
} | undefined;
|
|
149
154
|
registry?: {
|
|
150
155
|
url?: string | undefined;
|
|
@@ -1250,9 +1255,12 @@ interface SessionInit {
|
|
|
1250
1255
|
currentModel?: string;
|
|
1251
1256
|
currentMode?: string;
|
|
1252
1257
|
agentCommands?: AdvertisedCommand[];
|
|
1258
|
+
firstPromptSeeded?: boolean;
|
|
1253
1259
|
}
|
|
1254
1260
|
interface CloseOptions {
|
|
1255
1261
|
deleteRecord?: boolean;
|
|
1262
|
+
regenTitle?: boolean;
|
|
1263
|
+
regenTitleTimeoutMs?: number;
|
|
1256
1264
|
}
|
|
1257
1265
|
declare class Session {
|
|
1258
1266
|
readonly sessionId: string;
|
|
@@ -1294,6 +1302,7 @@ declare class Session {
|
|
|
1294
1302
|
upstreamSessionId: string;
|
|
1295
1303
|
}) => void): void;
|
|
1296
1304
|
get attachedCount(): number;
|
|
1305
|
+
get turnStartedAt(): number | undefined;
|
|
1297
1306
|
getHistorySnapshot(): CachedNotification[];
|
|
1298
1307
|
onBroadcast(handler: (entry: CachedNotification) => void): () => void;
|
|
1299
1308
|
attach(client: AttachedClient, historyPolicy: HistoryPolicy): CachedNotification[];
|
|
@@ -1447,6 +1456,7 @@ declare class SessionManager {
|
|
|
1447
1456
|
cwd?: string;
|
|
1448
1457
|
}): Promise<SessionListEntry[]>;
|
|
1449
1458
|
deleteRecord(sessionId: string): Promise<boolean>;
|
|
1459
|
+
hasRecord(sessionId: string): Promise<boolean>;
|
|
1450
1460
|
private persistTitle;
|
|
1451
1461
|
private persistAgentChange;
|
|
1452
1462
|
private persistSnapshot;
|
|
@@ -1530,7 +1540,8 @@ declare const paths: {
|
|
|
1530
1540
|
extensionsDir: () => string;
|
|
1531
1541
|
extensionLogFile: (name: string) => string;
|
|
1532
1542
|
extensionPidFile: (name: string) => string;
|
|
1533
|
-
tuiHistoryFile: () => string;
|
|
1543
|
+
tuiHistoryFile: (id: string) => string;
|
|
1544
|
+
tuiLogFile: () => string;
|
|
1534
1545
|
};
|
|
1535
1546
|
|
|
1536
1547
|
export { type AgentCapabilities, AgentInstance, HistoryPolicy, HydraConfig, type InitializeResult, JsonRpcConnection, type MessageStream, Registry, Session, SessionAttachParams, type SessionCapabilities, SessionDetachParams, SessionListEntry, SessionListParams, SessionListResult, SessionManager, defaultConfig, ensureConfig, generateAuthToken, loadConfig, ndjsonStreamFromStdio, paths, planSpawn, startDaemon, writeConfig, wsToMessageStream };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/daemon/server.ts
|
|
2
|
-
import * as
|
|
2
|
+
import * as fs7 from "fs";
|
|
3
3
|
import * as fsp2 from "fs/promises";
|
|
4
4
|
import Fastify from "fastify";
|
|
5
5
|
import websocketPlugin from "@fastify/websocket";
|
|
@@ -20,6 +20,11 @@ function hydraHome() {
|
|
|
20
20
|
if (override && override.length > 0) {
|
|
21
21
|
return path.resolve(override);
|
|
22
22
|
}
|
|
23
|
+
if (process.env.VITEST) {
|
|
24
|
+
throw new Error(
|
|
25
|
+
"HYDRA_ACP_HOME is unset under VITEST; vitest.setup.ts must run first"
|
|
26
|
+
);
|
|
27
|
+
}
|
|
23
28
|
return path.join(os.homedir(), ".hydra-acp");
|
|
24
29
|
}
|
|
25
30
|
var paths = {
|
|
@@ -41,7 +46,8 @@ var paths = {
|
|
|
41
46
|
extensionsDir: () => path.join(hydraHome(), "extensions"),
|
|
42
47
|
extensionLogFile: (name) => path.join(hydraHome(), "extensions", `${name}.log`),
|
|
43
48
|
extensionPidFile: (name) => path.join(hydraHome(), "extensions", `${name}.pid`),
|
|
44
|
-
tuiHistoryFile: () => path.join(hydraHome(), "
|
|
49
|
+
tuiHistoryFile: (id) => path.join(hydraHome(), "sessions", id, "prompt-history"),
|
|
50
|
+
tuiLogFile: () => path.join(hydraHome(), "tui.log")
|
|
45
51
|
};
|
|
46
52
|
|
|
47
53
|
// src/core/config.ts
|
|
@@ -69,7 +75,11 @@ var TuiConfig = z.object({
|
|
|
69
75
|
// /clear, ^L, resize — bypass this throttle. Default 1000 (1 Hz) keeps
|
|
70
76
|
// CPU low during heavy streaming; bump to 250 for 4 Hz, 100 for ~10 Hz,
|
|
71
77
|
// or 0 to disable throttling entirely.
|
|
72
|
-
repaintThrottleMs: z.number().int().nonnegative().default(1e3)
|
|
78
|
+
repaintThrottleMs: z.number().int().nonnegative().default(1e3),
|
|
79
|
+
// Cap on logical lines retained in the in-memory scrollback render
|
|
80
|
+
// buffer. Oldest lines are dropped on overflow. The on-disk session
|
|
81
|
+
// history is unaffected; this only bounds the TUI's local view buffer.
|
|
82
|
+
maxScrollbackLines: z.number().int().positive().default(1e4)
|
|
73
83
|
});
|
|
74
84
|
var ExtensionName = z.string().min(1).regex(/^[A-Za-z0-9._-]+$/, "extension name must be filename-safe");
|
|
75
85
|
var ExtensionBody = z.object({
|
|
@@ -94,7 +104,7 @@ var HydraConfig = z.object({
|
|
|
94
104
|
// recency and truncated to this count. `--all` overrides in the CLI.
|
|
95
105
|
sessionListColdLimit: z.number().int().nonnegative().default(20),
|
|
96
106
|
extensions: z.record(ExtensionName, ExtensionBody).default({}),
|
|
97
|
-
tui: TuiConfig.default({ repaintThrottleMs: 1e3 })
|
|
107
|
+
tui: TuiConfig.default({ repaintThrottleMs: 1e3, maxScrollbackLines: 1e4 })
|
|
98
108
|
});
|
|
99
109
|
function extensionList(config) {
|
|
100
110
|
return Object.entries(config.extensions).map(([name, body]) => ({
|
|
@@ -337,6 +347,9 @@ function planSpawn(agent, extraArgs = []) {
|
|
|
337
347
|
throw new Error(`Agent ${agent.id} has no usable distribution method.`);
|
|
338
348
|
}
|
|
339
349
|
|
|
350
|
+
// src/core/session-manager.ts
|
|
351
|
+
import * as fs5 from "fs/promises";
|
|
352
|
+
|
|
340
353
|
// src/core/agent-instance.ts
|
|
341
354
|
import { spawn } from "child_process";
|
|
342
355
|
|
|
@@ -421,6 +434,9 @@ function extractHydraMeta(meta) {
|
|
|
421
434
|
if (typeof obj.currentMode === "string") {
|
|
422
435
|
out.currentMode = obj.currentMode;
|
|
423
436
|
}
|
|
437
|
+
if (typeof obj.turnStartedAt === "number" && obj.turnStartedAt > 0) {
|
|
438
|
+
out.turnStartedAt = obj.turnStartedAt;
|
|
439
|
+
}
|
|
424
440
|
if (Array.isArray(obj.availableCommands)) {
|
|
425
441
|
const cmds = [];
|
|
426
442
|
for (const raw of obj.availableCommands) {
|
|
@@ -877,6 +893,9 @@ var Session = class {
|
|
|
877
893
|
}
|
|
878
894
|
this.idleTimeoutMs = init.idleTimeoutMs ?? 0;
|
|
879
895
|
this.spawnReplacementAgent = init.spawnReplacementAgent;
|
|
896
|
+
if (init.firstPromptSeeded) {
|
|
897
|
+
this.firstPromptSeeded = true;
|
|
898
|
+
}
|
|
880
899
|
this.historyStore = init.historyStore;
|
|
881
900
|
if (init.seedHistory && init.seedHistory.length > 0) {
|
|
882
901
|
this.history = [...init.seedHistory];
|
|
@@ -941,6 +960,29 @@ var Session = class {
|
|
|
941
960
|
get attachedCount() {
|
|
942
961
|
return this.clients.size;
|
|
943
962
|
}
|
|
963
|
+
// Wall-clock when the in-flight agent turn began, or undefined when
|
|
964
|
+
// idle. Derived from history: the most recent prompt_received without
|
|
965
|
+
// a later turn_complete is the outstanding turn, and its recordedAt
|
|
966
|
+
// is when the prompt was first broadcast. Used by buildResponseMeta
|
|
967
|
+
// so a fresh client reattaching mid-turn boots up with the busy
|
|
968
|
+
// banner showing real elapsed time.
|
|
969
|
+
get turnStartedAt() {
|
|
970
|
+
for (let i = this.history.length - 1; i >= 0; i--) {
|
|
971
|
+
const entry = this.history[i];
|
|
972
|
+
if (!entry) {
|
|
973
|
+
continue;
|
|
974
|
+
}
|
|
975
|
+
const params = entry.params;
|
|
976
|
+
const kind = params?.update?.sessionUpdate;
|
|
977
|
+
if (kind === "turn_complete") {
|
|
978
|
+
return void 0;
|
|
979
|
+
}
|
|
980
|
+
if (kind === "prompt_received") {
|
|
981
|
+
return entry.recordedAt;
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
return void 0;
|
|
985
|
+
}
|
|
944
986
|
// Snapshot of the current in-memory replay history. Used by the
|
|
945
987
|
// HTTP history endpoint to deliver the "what's accumulated so far"
|
|
946
988
|
// prefix before optionally tailing with onBroadcast. Returns a copy
|
|
@@ -1018,13 +1060,19 @@ var Session = class {
|
|
|
1018
1060
|
this.broadcastPromptReceived(client, params);
|
|
1019
1061
|
this.maybeSeedTitleFromPrompt(params);
|
|
1020
1062
|
return this.enqueuePrompt(async () => {
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1063
|
+
let response;
|
|
1064
|
+
try {
|
|
1065
|
+
response = await this.agent.connection.request(
|
|
1066
|
+
"session/prompt",
|
|
1067
|
+
{
|
|
1068
|
+
...params,
|
|
1069
|
+
sessionId: this.upstreamSessionId
|
|
1070
|
+
}
|
|
1071
|
+
);
|
|
1072
|
+
} catch (err) {
|
|
1073
|
+
this.broadcastTurnComplete(client.clientId, { stopReason: "error" });
|
|
1074
|
+
throw err;
|
|
1075
|
+
}
|
|
1028
1076
|
this.broadcastTurnComplete(client.clientId, response);
|
|
1029
1077
|
return response;
|
|
1030
1078
|
});
|
|
@@ -1112,6 +1160,13 @@ var Session = class {
|
|
|
1112
1160
|
return;
|
|
1113
1161
|
}
|
|
1114
1162
|
this.cancelIdleTimer();
|
|
1163
|
+
if (opts.regenTitle && this.firstPromptSeeded) {
|
|
1164
|
+
const timeoutMs = opts.regenTitleTimeoutMs ?? 5e3;
|
|
1165
|
+
await Promise.race([
|
|
1166
|
+
this.runTitleRegen().catch(() => void 0),
|
|
1167
|
+
new Promise((r) => setTimeout(r, timeoutMs).unref?.())
|
|
1168
|
+
]);
|
|
1169
|
+
}
|
|
1115
1170
|
await this.agent.kill().catch(() => void 0);
|
|
1116
1171
|
this.markClosed({ deleteRecord: opts.deleteRecord ?? false });
|
|
1117
1172
|
}
|
|
@@ -1160,7 +1215,7 @@ var Session = class {
|
|
|
1160
1215
|
}
|
|
1161
1216
|
const promptParams = params ?? {};
|
|
1162
1217
|
const text = extractPromptText(promptParams.prompt);
|
|
1163
|
-
const seed = firstLine(text,
|
|
1218
|
+
const seed = firstLine(text, 200);
|
|
1164
1219
|
if (!seed) {
|
|
1165
1220
|
return;
|
|
1166
1221
|
}
|
|
@@ -1539,7 +1594,8 @@ _(switched from \`${oldAgentId}\` to \`${newAgentId}\`)_
|
|
|
1539
1594
|
}
|
|
1540
1595
|
this.idleTimer = setTimeout(() => {
|
|
1541
1596
|
this.idleTimer = void 0;
|
|
1542
|
-
|
|
1597
|
+
const opts = this.firstPromptSeeded ? { deleteRecord: false, regenTitle: true } : { deleteRecord: true };
|
|
1598
|
+
void this.close(opts).catch(() => void 0);
|
|
1543
1599
|
}, this.idleTimeoutMs);
|
|
1544
1600
|
if (typeof this.idleTimer.unref === "function") {
|
|
1545
1601
|
this.idleTimer.unref();
|
|
@@ -2139,7 +2195,8 @@ var SessionManager = class {
|
|
|
2139
2195
|
seedHistory: params.seedHistory,
|
|
2140
2196
|
currentModel: params.currentModel,
|
|
2141
2197
|
currentMode: params.currentMode,
|
|
2142
|
-
agentCommands: params.agentCommands
|
|
2198
|
+
agentCommands: params.agentCommands,
|
|
2199
|
+
firstPromptSeeded: true
|
|
2143
2200
|
});
|
|
2144
2201
|
await this.attachManagerHooks(session);
|
|
2145
2202
|
return session;
|
|
@@ -2310,13 +2367,14 @@ var SessionManager = class {
|
|
|
2310
2367
|
continue;
|
|
2311
2368
|
}
|
|
2312
2369
|
liveIds.add(session.sessionId);
|
|
2370
|
+
const used = await historyMtimeIso(session.sessionId) ?? new Date(session.updatedAt).toISOString();
|
|
2313
2371
|
entries.push({
|
|
2314
2372
|
sessionId: session.sessionId,
|
|
2315
2373
|
upstreamSessionId: session.upstreamSessionId,
|
|
2316
2374
|
cwd: session.cwd,
|
|
2317
2375
|
title: session.title,
|
|
2318
2376
|
agentId: session.agentId,
|
|
2319
|
-
updatedAt:
|
|
2377
|
+
updatedAt: used,
|
|
2320
2378
|
attachedClients: session.attachedCount,
|
|
2321
2379
|
status: "live"
|
|
2322
2380
|
});
|
|
@@ -2329,13 +2387,14 @@ var SessionManager = class {
|
|
|
2329
2387
|
if (filter.cwd && r.cwd !== filter.cwd) {
|
|
2330
2388
|
continue;
|
|
2331
2389
|
}
|
|
2390
|
+
const used = await historyMtimeIso(r.sessionId) ?? r.updatedAt;
|
|
2332
2391
|
entries.push({
|
|
2333
2392
|
sessionId: r.sessionId,
|
|
2334
2393
|
upstreamSessionId: r.upstreamSessionId,
|
|
2335
2394
|
cwd: r.cwd,
|
|
2336
2395
|
title: r.title,
|
|
2337
2396
|
agentId: r.agentId,
|
|
2338
|
-
updatedAt:
|
|
2397
|
+
updatedAt: used,
|
|
2339
2398
|
attachedClients: 0,
|
|
2340
2399
|
status: "cold"
|
|
2341
2400
|
});
|
|
@@ -2351,6 +2410,10 @@ var SessionManager = class {
|
|
|
2351
2410
|
await this.store.delete(sessionId).catch(() => void 0);
|
|
2352
2411
|
return true;
|
|
2353
2412
|
}
|
|
2413
|
+
async hasRecord(sessionId) {
|
|
2414
|
+
const record = await this.store.read(sessionId).catch(() => void 0);
|
|
2415
|
+
return record !== void 0;
|
|
2416
|
+
}
|
|
2354
2417
|
// Persist a title update from Session.setTitle. The on-disk record
|
|
2355
2418
|
// was written at create time; updating it here keeps the session
|
|
2356
2419
|
// record's title in sync with what was broadcast to clients so a
|
|
@@ -2425,10 +2488,18 @@ var SessionManager = class {
|
|
|
2425
2488
|
this.sessions.clear();
|
|
2426
2489
|
}
|
|
2427
2490
|
};
|
|
2491
|
+
async function historyMtimeIso(sessionId) {
|
|
2492
|
+
try {
|
|
2493
|
+
const st = await fs5.stat(paths.historyFile(sessionId));
|
|
2494
|
+
return new Date(st.mtimeMs).toISOString();
|
|
2495
|
+
} catch {
|
|
2496
|
+
return void 0;
|
|
2497
|
+
}
|
|
2498
|
+
}
|
|
2428
2499
|
|
|
2429
2500
|
// src/core/extensions.ts
|
|
2430
2501
|
import { spawn as spawn2 } from "child_process";
|
|
2431
|
-
import * as
|
|
2502
|
+
import * as fs6 from "fs";
|
|
2432
2503
|
import * as fsp from "fs/promises";
|
|
2433
2504
|
import * as path3 from "path";
|
|
2434
2505
|
var RESTART_BASE_MS = 1e3;
|
|
@@ -2711,7 +2782,7 @@ var ExtensionManager = class {
|
|
|
2711
2782
|
}
|
|
2712
2783
|
const ext = entry.config;
|
|
2713
2784
|
const command = ext.command.length > 0 ? ext.command : [ext.name];
|
|
2714
|
-
const logStream =
|
|
2785
|
+
const logStream = fs6.createWriteStream(paths.extensionLogFile(ext.name), {
|
|
2715
2786
|
flags: "a"
|
|
2716
2787
|
});
|
|
2717
2788
|
logStream.write(
|
|
@@ -2761,7 +2832,7 @@ var ExtensionManager = class {
|
|
|
2761
2832
|
}
|
|
2762
2833
|
if (typeof child.pid === "number") {
|
|
2763
2834
|
try {
|
|
2764
|
-
|
|
2835
|
+
fs6.writeFileSync(paths.extensionPidFile(ext.name), `${child.pid}
|
|
2765
2836
|
`, {
|
|
2766
2837
|
encoding: "utf8",
|
|
2767
2838
|
mode: 384
|
|
@@ -2786,7 +2857,7 @@ var ExtensionManager = class {
|
|
|
2786
2857
|
});
|
|
2787
2858
|
child.on("exit", (code, signal) => {
|
|
2788
2859
|
try {
|
|
2789
|
-
|
|
2860
|
+
fs6.unlinkSync(paths.extensionPidFile(ext.name));
|
|
2790
2861
|
} catch {
|
|
2791
2862
|
}
|
|
2792
2863
|
logStream.write(
|
|
@@ -2920,6 +2991,22 @@ function registerSessionRoutes(app, manager, defaults) {
|
|
|
2920
2991
|
reply.code(500).send({ error: err.message });
|
|
2921
2992
|
}
|
|
2922
2993
|
});
|
|
2994
|
+
app.post("/v1/sessions/:id/kill", async (request, reply) => {
|
|
2995
|
+
const raw = request.params.id;
|
|
2996
|
+
const id = await manager.resolveCanonicalId(raw) ?? raw;
|
|
2997
|
+
const session = manager.get(id);
|
|
2998
|
+
if (session) {
|
|
2999
|
+
await session.close({ deleteRecord: false });
|
|
3000
|
+
reply.code(204).send();
|
|
3001
|
+
return;
|
|
3002
|
+
}
|
|
3003
|
+
const exists = await manager.hasRecord(id);
|
|
3004
|
+
if (!exists) {
|
|
3005
|
+
reply.code(404).send({ error: "session not found" });
|
|
3006
|
+
return;
|
|
3007
|
+
}
|
|
3008
|
+
reply.code(204).send();
|
|
3009
|
+
});
|
|
2923
3010
|
app.delete("/v1/sessions/:id", async (request, reply) => {
|
|
2924
3011
|
const raw = request.params.id;
|
|
2925
3012
|
const id = await manager.resolveCanonicalId(raw) ?? raw;
|
|
@@ -3127,6 +3214,16 @@ function parseRegisterBody(body) {
|
|
|
3127
3214
|
};
|
|
3128
3215
|
}
|
|
3129
3216
|
|
|
3217
|
+
// src/daemon/routes/config.ts
|
|
3218
|
+
function registerConfigRoutes(app, defaults) {
|
|
3219
|
+
app.get("/v1/config", async () => {
|
|
3220
|
+
return {
|
|
3221
|
+
defaultAgent: defaults.defaultAgent,
|
|
3222
|
+
defaultCwd: defaults.defaultCwd
|
|
3223
|
+
};
|
|
3224
|
+
});
|
|
3225
|
+
}
|
|
3226
|
+
|
|
3130
3227
|
// src/daemon/acp-ws.ts
|
|
3131
3228
|
import { nanoid as nanoid2 } from "nanoid";
|
|
3132
3229
|
|
|
@@ -3450,6 +3547,9 @@ function buildResponseMeta(session) {
|
|
|
3450
3547
|
if (commands.length > 0) {
|
|
3451
3548
|
ours.availableCommands = commands;
|
|
3452
3549
|
}
|
|
3550
|
+
if (session.turnStartedAt !== void 0) {
|
|
3551
|
+
ours.turnStartedAt = session.turnStartedAt;
|
|
3552
|
+
}
|
|
3453
3553
|
return mergeMeta(session.agentMeta, ours);
|
|
3454
3554
|
}
|
|
3455
3555
|
function buildInitializeResult() {
|
|
@@ -3535,6 +3635,10 @@ async function startDaemon(config) {
|
|
|
3535
3635
|
});
|
|
3536
3636
|
registerAgentRoutes(app, registry);
|
|
3537
3637
|
registerExtensionRoutes(app, extensions);
|
|
3638
|
+
registerConfigRoutes(app, {
|
|
3639
|
+
defaultAgent: config.defaultAgent,
|
|
3640
|
+
defaultCwd: config.defaultCwd
|
|
3641
|
+
});
|
|
3538
3642
|
registerAcpWsEndpoint(app, {
|
|
3539
3643
|
config,
|
|
3540
3644
|
manager,
|
|
@@ -3570,7 +3674,7 @@ async function startDaemon(config) {
|
|
|
3570
3674
|
await manager.closeAll();
|
|
3571
3675
|
await app.close();
|
|
3572
3676
|
try {
|
|
3573
|
-
|
|
3677
|
+
fs7.unlinkSync(paths.pidFile());
|
|
3574
3678
|
} catch {
|
|
3575
3679
|
}
|
|
3576
3680
|
try {
|