@love-moon/conductor-cli 0.2.8 → 0.2.10
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/package.json +3 -3
- package/src/daemon.js +70 -12
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@love-moon/conductor-cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.10",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"conductor": "bin/conductor.js"
|
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
"test": "node --test"
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@love-moon/tui-driver": "0.2.
|
|
20
|
-
"@love-moon/conductor-sdk": "0.2.
|
|
19
|
+
"@love-moon/tui-driver": "0.2.10",
|
|
20
|
+
"@love-moon/conductor-sdk": "0.2.10",
|
|
21
21
|
"dotenv": "^16.4.5",
|
|
22
22
|
"enquirer": "^2.4.1",
|
|
23
23
|
"js-yaml": "^4.1.1",
|
package/src/daemon.js
CHANGED
|
@@ -61,6 +61,7 @@ export function startDaemon(config = {}, deps = {}) {
|
|
|
61
61
|
const killFn = deps.kill || process.kill;
|
|
62
62
|
let requestShutdown = async () => {};
|
|
63
63
|
let shutdownSignalHandled = false;
|
|
64
|
+
let forcedSignalExitHandled = false;
|
|
64
65
|
|
|
65
66
|
const exitAndReturn = (code) => {
|
|
66
67
|
exitFn(code);
|
|
@@ -145,6 +146,14 @@ export function startDaemon(config = {}, deps = {}) {
|
|
|
145
146
|
process.env.CONDUCTOR_STOP_FORCE_KILL_TIMEOUT_MS,
|
|
146
147
|
5000,
|
|
147
148
|
);
|
|
149
|
+
const SHUTDOWN_STATUS_REPORT_TIMEOUT_MS = parsePositiveInt(
|
|
150
|
+
process.env.CONDUCTOR_SHUTDOWN_STATUS_REPORT_TIMEOUT_MS,
|
|
151
|
+
1000,
|
|
152
|
+
);
|
|
153
|
+
const SHUTDOWN_DISCONNECT_TIMEOUT_MS = parsePositiveInt(
|
|
154
|
+
process.env.CONDUCTOR_SHUTDOWN_DISCONNECT_TIMEOUT_MS,
|
|
155
|
+
1000,
|
|
156
|
+
);
|
|
148
157
|
|
|
149
158
|
try {
|
|
150
159
|
mkdirSyncFn(WORKSPACE_ROOT, { recursive: true });
|
|
@@ -216,8 +225,16 @@ export function startDaemon(config = {}, deps = {}) {
|
|
|
216
225
|
};
|
|
217
226
|
|
|
218
227
|
process.on("exit", cleanupLock);
|
|
228
|
+
const signalExitCode = (signal) => (signal === "SIGINT" ? 130 : 143);
|
|
219
229
|
const handleSignal = (signal) => {
|
|
220
|
-
if (shutdownSignalHandled)
|
|
230
|
+
if (shutdownSignalHandled) {
|
|
231
|
+
if (forcedSignalExitHandled) return;
|
|
232
|
+
forcedSignalExitHandled = true;
|
|
233
|
+
log(`Received ${signal} again, forcing exit now`);
|
|
234
|
+
cleanupLock();
|
|
235
|
+
exitFn(signalExitCode(signal));
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
221
238
|
shutdownSignalHandled = true;
|
|
222
239
|
void (async () => {
|
|
223
240
|
try {
|
|
@@ -227,7 +244,7 @@ export function startDaemon(config = {}, deps = {}) {
|
|
|
227
244
|
logError(`Graceful shutdown failed on ${signal}: ${err?.message || err}`);
|
|
228
245
|
} finally {
|
|
229
246
|
cleanupLock();
|
|
230
|
-
exitFn(
|
|
247
|
+
exitFn(signalExitCode(signal));
|
|
231
248
|
}
|
|
232
249
|
})();
|
|
233
250
|
};
|
|
@@ -639,6 +656,20 @@ export function startDaemon(config = {}, deps = {}) {
|
|
|
639
656
|
return;
|
|
640
657
|
}
|
|
641
658
|
|
|
659
|
+
const existingTaskRecord = activeTaskProcesses.get(taskId);
|
|
660
|
+
if (existingTaskRecord?.child) {
|
|
661
|
+
log(
|
|
662
|
+
`Duplicate create_task ignored for ${taskId}: task already active (pid=${existingTaskRecord.child.pid ?? "unknown"})`,
|
|
663
|
+
);
|
|
664
|
+
sendAgentCommandAck({
|
|
665
|
+
requestId,
|
|
666
|
+
taskId,
|
|
667
|
+
eventType: "create_task",
|
|
668
|
+
accepted: true,
|
|
669
|
+
}).catch(() => {});
|
|
670
|
+
return;
|
|
671
|
+
}
|
|
672
|
+
|
|
642
673
|
// Validate and get CLI command for the backend
|
|
643
674
|
const effectiveBackend = backendType || SUPPORTED_BACKENDS[0];
|
|
644
675
|
if (!SUPPORTED_BACKENDS.includes(effectiveBackend)) {
|
|
@@ -892,15 +923,19 @@ export function startDaemon(config = {}, deps = {}) {
|
|
|
892
923
|
activeEntries.map(async ([taskId, record]) => {
|
|
893
924
|
suppressedExitStatusReports.add(taskId);
|
|
894
925
|
try {
|
|
895
|
-
await
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
926
|
+
await withTimeout(
|
|
927
|
+
client.sendJson({
|
|
928
|
+
type: "task_status_update",
|
|
929
|
+
payload: {
|
|
930
|
+
task_id: taskId,
|
|
931
|
+
project_id: record.projectId,
|
|
932
|
+
status: "KILLED",
|
|
933
|
+
summary: `daemon shutdown (${reason})`,
|
|
934
|
+
},
|
|
935
|
+
}),
|
|
936
|
+
SHUTDOWN_STATUS_REPORT_TIMEOUT_MS,
|
|
937
|
+
`report shutdown status for ${taskId}`,
|
|
938
|
+
);
|
|
904
939
|
} catch (err) {
|
|
905
940
|
logError(`Failed to report shutdown status (KILLED) for ${taskId}: ${err?.message || err}`);
|
|
906
941
|
}
|
|
@@ -923,7 +958,11 @@ export function startDaemon(config = {}, deps = {}) {
|
|
|
923
958
|
activeTaskProcesses.clear();
|
|
924
959
|
|
|
925
960
|
try {
|
|
926
|
-
await
|
|
961
|
+
await withTimeout(
|
|
962
|
+
Promise.resolve(client.disconnect()),
|
|
963
|
+
SHUTDOWN_DISCONNECT_TIMEOUT_MS,
|
|
964
|
+
"disconnect daemon websocket",
|
|
965
|
+
);
|
|
927
966
|
} catch (error) {
|
|
928
967
|
logError(`Failed to disconnect client on daemon close: ${error?.message || error}`);
|
|
929
968
|
}
|
|
@@ -989,6 +1028,25 @@ function parsePositiveInt(value, fallback) {
|
|
|
989
1028
|
return fallback;
|
|
990
1029
|
}
|
|
991
1030
|
|
|
1031
|
+
async function withTimeout(promise, timeoutMs, label) {
|
|
1032
|
+
let timer = null;
|
|
1033
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
1034
|
+
timer = setTimeout(() => {
|
|
1035
|
+
reject(new Error(`${label} timed out after ${timeoutMs}ms`));
|
|
1036
|
+
}, timeoutMs);
|
|
1037
|
+
if (typeof timer?.unref === "function") {
|
|
1038
|
+
timer.unref();
|
|
1039
|
+
}
|
|
1040
|
+
});
|
|
1041
|
+
try {
|
|
1042
|
+
return await Promise.race([promise, timeoutPromise]);
|
|
1043
|
+
} finally {
|
|
1044
|
+
if (timer) {
|
|
1045
|
+
clearTimeout(timer);
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
|
|
992
1050
|
function expandHomePath(inputPath, homeDir) {
|
|
993
1051
|
if (typeof inputPath !== "string" || !inputPath) {
|
|
994
1052
|
return inputPath;
|