@ouro.bot/cli 0.1.0-alpha.550 → 0.1.0-alpha.551
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/changelog.json +6 -0
- package/dist/heart/daemon/daemon.js +41 -3
- package/package.json +1 -1
package/changelog.json
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_note": "This changelog is maintained as part of the PR/version-bump workflow. Agent-curated, not auto-generated. Agents read this file directly via read_file to understand what changed between versions.",
|
|
3
3
|
"versions": [
|
|
4
|
+
{
|
|
5
|
+
"version": "0.1.0-alpha.551",
|
|
6
|
+
"changes": [
|
|
7
|
+
"`ouro up` now waits for SIGTERMed orphan daemon processes to settle before opening the replacement Unix socket, preventing the previous daemon from unlinking the new daemon's command socket during orphan cleanup."
|
|
8
|
+
]
|
|
9
|
+
},
|
|
4
10
|
{
|
|
5
11
|
"version": "0.1.0-alpha.550",
|
|
6
12
|
"changes": [
|
|
@@ -37,6 +37,7 @@ exports.OuroDaemon = void 0;
|
|
|
37
37
|
exports.parseOrphanPidsFromPs = parseOrphanPidsFromPs;
|
|
38
38
|
exports.filterPidfilePidsToActualOrphans = filterPidfilePidsToActualOrphans;
|
|
39
39
|
exports.mergeUniqueOrphanPids = mergeUniqueOrphanPids;
|
|
40
|
+
exports.waitForOrphanProcessesToSettle = waitForOrphanProcessesToSettle;
|
|
40
41
|
exports.killOrphanProcesses = killOrphanProcesses;
|
|
41
42
|
exports.writePidfile = writePidfile;
|
|
42
43
|
exports.handleAgentSenseTurn = handleAgentSenseTurn;
|
|
@@ -176,6 +177,40 @@ function mergeUniqueOrphanPids(...sources) {
|
|
|
176
177
|
}
|
|
177
178
|
return merged;
|
|
178
179
|
}
|
|
180
|
+
const ORPHAN_CLEANUP_SETTLE_TIMEOUT_MS = 5_000;
|
|
181
|
+
const ORPHAN_CLEANUP_SETTLE_POLL_INTERVAL_MS = 50;
|
|
182
|
+
/* v8 ignore start -- process liveness probe; pure wait behavior covered via injected deps @preserve */
|
|
183
|
+
function defaultIsPidAlive(pid) {
|
|
184
|
+
try {
|
|
185
|
+
process.kill(pid, 0);
|
|
186
|
+
return true;
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
return error.code === "EPERM";
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
/* v8 ignore stop */
|
|
193
|
+
/* v8 ignore start -- real timer wiring; wait behavior covered via injected sleep @preserve */
|
|
194
|
+
async function defaultSettleSleep(ms) {
|
|
195
|
+
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
196
|
+
}
|
|
197
|
+
/* v8 ignore stop */
|
|
198
|
+
async function waitForOrphanProcessesToSettle(pids, deps = {}) {
|
|
199
|
+
if (pids.length === 0)
|
|
200
|
+
return [];
|
|
201
|
+
const isPidAlive = deps.isPidAlive ?? defaultIsPidAlive;
|
|
202
|
+
const now = deps.now ?? Date.now;
|
|
203
|
+
const sleep = deps.sleep ?? defaultSettleSleep;
|
|
204
|
+
const timeoutMs = deps.timeoutMs ?? ORPHAN_CLEANUP_SETTLE_TIMEOUT_MS;
|
|
205
|
+
const pollIntervalMs = deps.pollIntervalMs ?? ORPHAN_CLEANUP_SETTLE_POLL_INTERVAL_MS;
|
|
206
|
+
const deadline = now() + timeoutMs;
|
|
207
|
+
let survivors = pids.filter(isPidAlive);
|
|
208
|
+
while (survivors.length > 0 && now() < deadline) {
|
|
209
|
+
await sleep(pollIntervalMs);
|
|
210
|
+
survivors = pids.filter(isPidAlive);
|
|
211
|
+
}
|
|
212
|
+
return survivors;
|
|
213
|
+
}
|
|
179
214
|
/* v8 ignore start -- shells out to ps; covered by filterPidfilePidsToActualOrphans unit tests via injected runner @preserve */
|
|
180
215
|
function runPsCheck(pids) {
|
|
181
216
|
try {
|
|
@@ -217,7 +252,7 @@ function killOrphanProcesses(socketPath = socket_client_1.DEFAULT_DAEMON_SOCKET_
|
|
|
217
252
|
message: "blocked orphan cleanup for non-production daemon socket",
|
|
218
253
|
meta: { socketPath, pidfilePath: PIDFILE_PATH },
|
|
219
254
|
});
|
|
220
|
-
return;
|
|
255
|
+
return [];
|
|
221
256
|
}
|
|
222
257
|
if (isVitestProcess()) {
|
|
223
258
|
(0, runtime_1.emitNervesEvent)({
|
|
@@ -227,7 +262,7 @@ function killOrphanProcesses(socketPath = socket_client_1.DEFAULT_DAEMON_SOCKET_
|
|
|
227
262
|
message: "blocked killOrphanProcesses from touching real pidfile under vitest",
|
|
228
263
|
meta: { pidfilePath: PIDFILE_PATH },
|
|
229
264
|
});
|
|
230
|
-
return;
|
|
265
|
+
return [];
|
|
231
266
|
}
|
|
232
267
|
try {
|
|
233
268
|
let pidfileOrphans = [];
|
|
@@ -269,6 +304,7 @@ function killOrphanProcesses(socketPath = socket_client_1.DEFAULT_DAEMON_SOCKET_
|
|
|
269
304
|
meta: { pids: pidsToKill },
|
|
270
305
|
});
|
|
271
306
|
}
|
|
307
|
+
return pidsToKill;
|
|
272
308
|
}
|
|
273
309
|
catch (error) {
|
|
274
310
|
(0, runtime_1.emitNervesEvent)({
|
|
@@ -278,6 +314,7 @@ function killOrphanProcesses(socketPath = socket_client_1.DEFAULT_DAEMON_SOCKET_
|
|
|
278
314
|
message: "failed to clean up orphaned ouro processes",
|
|
279
315
|
meta: { error: error instanceof Error ? error.message : String(error) },
|
|
280
316
|
});
|
|
317
|
+
return [];
|
|
281
318
|
}
|
|
282
319
|
}
|
|
283
320
|
/**
|
|
@@ -594,7 +631,8 @@ class OuroDaemon {
|
|
|
594
631
|
// MCP connections are lazily initialized per-agent during senseTurn
|
|
595
632
|
// (daemon manages multiple agents; agent identity must be set before loading MCP config)
|
|
596
633
|
/* v8 ignore start -- orphan cleanup + pidfile: calls process management functions @preserve */
|
|
597
|
-
killOrphanProcesses(this.socketPath);
|
|
634
|
+
const killedOrphanPids = killOrphanProcesses(this.socketPath);
|
|
635
|
+
await waitForOrphanProcessesToSettle(killedOrphanPids);
|
|
598
636
|
/* v8 ignore stop */
|
|
599
637
|
await this.openCommandSocket();
|
|
600
638
|
this.triggerAutoStartAgents();
|