@ouro.bot/cli 0.1.0-alpha.551 → 0.1.0-alpha.552

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 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.552",
6
+ "changes": [
7
+ "`ouro up` now bootstraps the daemon LaunchAgent into the current login session when it is not already loaded, waits for the launchd-owned daemon socket to settle, and keeps the launchd adoption non-fatal if macOS refuses the bootstrap."
8
+ ]
9
+ },
4
10
  {
5
11
  "version": "0.1.0-alpha.551",
6
12
  "changes": [
@@ -41,6 +41,8 @@ var __importStar = (this && this.__importStar) || (function () {
41
41
  Object.defineProperty(exports, "__esModule", { value: true });
42
42
  exports.defaultStartDaemonProcess = defaultStartDaemonProcess;
43
43
  exports.readFirstBundleMetaVersion = readFirstBundleMetaVersion;
44
+ exports.isDaemonLaunchAgentLoaded = isDaemonLaunchAgentLoaded;
45
+ exports.waitForBootstrappedDaemonSocket = waitForBootstrappedDaemonSocket;
44
46
  exports.defaultListDiscoveredAgents = defaultListDiscoveredAgents;
45
47
  exports.defaultRunSerpentGuide = defaultRunSerpentGuide;
46
48
  exports.createDefaultOuroCliDeps = createDefaultOuroCliDeps;
@@ -216,7 +218,56 @@ function defaultFallbackPendingMessage(command) {
216
218
  });
217
219
  return pendingPath;
218
220
  }
219
- function defaultEnsureDaemonBootPersistence(socketPath) {
221
+ function currentUserUid() {
222
+ return process.getuid?.() ?? 0;
223
+ }
224
+ function launchAgentDomain(userUid = currentUserUid()) {
225
+ return `gui/${userUid}`;
226
+ }
227
+ function isDaemonLaunchAgentLoaded(deps) {
228
+ const userUid = deps?.userUid ?? currentUserUid();
229
+ const exec = deps?.exec ?? ((cmd) => { (0, child_process_1.execSync)(cmd, { stdio: "ignore" }); });
230
+ try {
231
+ exec(`launchctl print ${launchAgentDomain(userUid)}/${launchd_1.DAEMON_PLIST_LABEL}`);
232
+ return true;
233
+ }
234
+ catch {
235
+ return false;
236
+ }
237
+ }
238
+ async function waitForBootstrappedDaemonSocket(socketPath, deps = {}) {
239
+ const checkSocketAlive = deps.checkSocketAlive ?? socket_client_1.checkDaemonSocketAlive;
240
+ const now = deps.now ?? Date.now;
241
+ const sleep = deps.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
242
+ const timeoutMs = deps.timeoutMs ?? 30_000;
243
+ const initialSettleMs = deps.initialSettleMs ?? 1_000;
244
+ const pollIntervalMs = deps.pollIntervalMs ?? 250;
245
+ const requiredConsecutiveAliveChecks = deps.requiredConsecutiveAliveChecks ?? 2;
246
+ const deadline = now() + timeoutMs;
247
+ const firstTrustworthyCheckAt = now() + initialSettleMs;
248
+ let consecutiveAliveChecks = 0;
249
+ while (now() < deadline) {
250
+ await sleep(pollIntervalMs);
251
+ if (now() < firstTrustworthyCheckAt)
252
+ continue;
253
+ if (await checkSocketAlive(socketPath)) {
254
+ consecutiveAliveChecks += 1;
255
+ if (consecutiveAliveChecks >= requiredConsecutiveAliveChecks)
256
+ return;
257
+ }
258
+ else {
259
+ consecutiveAliveChecks = 0;
260
+ }
261
+ }
262
+ (0, runtime_1.emitNervesEvent)({
263
+ level: "warn",
264
+ component: "daemon",
265
+ event: "daemon.launchd_bootstrap_socket_wait_timeout",
266
+ message: "launchd bootstrap finished but daemon socket did not settle before timeout",
267
+ meta: { socketPath },
268
+ });
269
+ }
270
+ async function defaultEnsureDaemonBootPersistence(socketPath) {
220
271
  if (process.platform !== "darwin") {
221
272
  return;
222
273
  }
@@ -238,18 +289,48 @@ function defaultEnsureDaemonBootPersistence(socketPath) {
238
289
  });
239
290
  }
240
291
  const logDir = (0, identity_1.getAgentDaemonLogsDir)();
241
- // Write plist only do NOT launchctl bootstrap.
242
- // The daemon is already running (started by ouro up). Bootstrapping would
243
- // start a SECOND daemon via launchd's RunAtLoad, causing a race where
244
- // killOrphanProcesses kills the first daemon and both end up dead.
245
- // The plist on disk is sufficient: launchd picks it up on login.
246
- (0, launchd_1.writeLaunchAgentPlist)(writeDeps, {
292
+ const plistPath = (0, launchd_1.writeLaunchAgentPlist)(writeDeps, {
247
293
  nodePath: process.execPath,
248
294
  entryPath,
249
295
  socketPath,
250
296
  logDir,
251
297
  envPath: process.env.PATH,
252
298
  });
299
+ const userUid = currentUserUid();
300
+ if (isDaemonLaunchAgentLoaded({ exec: (cmd) => { (0, child_process_1.execSync)(cmd, { stdio: "ignore" }); }, userUid })) {
301
+ (0, runtime_1.emitNervesEvent)({
302
+ component: "daemon",
303
+ event: "daemon.launchd_bootstrap_skipped_loaded",
304
+ message: "daemon launch agent already loaded",
305
+ meta: { plistPath, label: launchd_1.DAEMON_PLIST_LABEL },
306
+ });
307
+ return;
308
+ }
309
+ try {
310
+ (0, runtime_1.emitNervesEvent)({
311
+ component: "daemon",
312
+ event: "daemon.launchd_bootstrap_start",
313
+ message: "bootstrapping daemon launch agent for current login session",
314
+ meta: { plistPath, label: launchd_1.DAEMON_PLIST_LABEL },
315
+ });
316
+ (0, child_process_1.execSync)(`launchctl bootstrap ${launchAgentDomain(userUid)} "${plistPath}"`, { stdio: "ignore" });
317
+ (0, runtime_1.emitNervesEvent)({
318
+ component: "daemon",
319
+ event: "daemon.launchd_bootstrap_end",
320
+ message: "daemon launch agent bootstrapped for current login session",
321
+ meta: { plistPath, label: launchd_1.DAEMON_PLIST_LABEL },
322
+ });
323
+ await waitForBootstrappedDaemonSocket(socketPath);
324
+ }
325
+ catch (error) {
326
+ (0, runtime_1.emitNervesEvent)({
327
+ level: "warn",
328
+ component: "daemon",
329
+ event: "daemon.launchd_bootstrap_error",
330
+ message: "failed to bootstrap daemon launch agent for current login session",
331
+ meta: { plistPath, label: launchd_1.DAEMON_PLIST_LABEL, error: error instanceof Error ? error.message : String(error) },
332
+ });
333
+ }
253
334
  }
254
335
  function defaultPrepareDaemonRuntimeReplacement() {
255
336
  if (process.platform !== "darwin") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ouro.bot/cli",
3
- "version": "0.1.0-alpha.551",
3
+ "version": "0.1.0-alpha.552",
4
4
  "main": "dist/heart/daemon/ouro-entry.js",
5
5
  "bin": {
6
6
  "cli": "dist/heart/daemon/ouro-bot-entry.js",