@ouro.bot/cli 0.1.0-alpha.548 → 0.1.0-alpha.549

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,13 @@
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.549",
6
+ "changes": [
7
+ "`ouro up` now unloads any already-loaded daemon LaunchAgent before replacing a drifted daemon runtime, preventing launchd KeepAlive from racing the manual replacement and leaving two daemon processes split across the same socket.",
8
+ "`ouro up` now rewrites the daemon boot plist as soon as the daemon is answering, so a degraded sense no longer prevents restart auto-start metadata from being refreshed."
9
+ ]
10
+ },
4
11
  {
5
12
  "version": "0.1.0-alpha.548",
6
13
  "changes": [
@@ -251,6 +251,15 @@ function defaultEnsureDaemonBootPersistence(socketPath) {
251
251
  envPath: process.env.PATH,
252
252
  });
253
253
  }
254
+ function defaultPrepareDaemonRuntimeReplacement() {
255
+ if (process.platform !== "darwin") {
256
+ return;
257
+ }
258
+ (0, launchd_1.bootoutLaunchAgentByLabel)({
259
+ exec: (cmd) => { (0, child_process_1.execSync)(cmd, { stdio: "ignore" }); },
260
+ userUid: process.getuid?.() ?? 0,
261
+ });
262
+ }
254
263
  async function defaultPromptInput(question) {
255
264
  const readline = await Promise.resolve().then(() => __importStar(require("readline/promises")));
256
265
  const rl = readline.createInterface({
@@ -615,6 +624,7 @@ function createDefaultOuroCliDeps(socketPath = socket_client_1.DEFAULT_DAEMON_SO
615
624
  syncGlobalOuroBotWrapper: ouro_bot_global_installer_1.syncGlobalOuroBotWrapper,
616
625
  pruneDaemonLogs: logs_prune_1.pruneDaemonLogs,
617
626
  ensureSkillManagement: skill_management_installer_1.ensureSkillManagement,
627
+ prepareDaemonRuntimeReplacement: defaultPrepareDaemonRuntimeReplacement,
618
628
  ensureDaemonBootPersistence: defaultEnsureDaemonBootPersistence,
619
629
  /* v8 ignore start -- dev-mode defaults: tests inject mocks for mode detection and binary resolution @preserve */
620
630
  detectMode: () => (0, runtime_mode_1.detectRuntimeMode)((0, identity_1.getRepoRoot)()),
@@ -943,6 +943,7 @@ async function ensureDaemonRunning(deps, options = {}) {
943
943
  stopDaemon: async () => {
944
944
  await deps.sendCommand(deps.socketPath, { kind: "daemon.stop" });
945
945
  },
946
+ prepareDaemonRuntimeReplacement: deps.prepareDaemonRuntimeReplacement,
946
947
  cleanupStaleSocket: deps.cleanupStaleSocket,
947
948
  startDaemonProcess: deps.startDaemonProcess,
948
949
  checkSocketAlive: deps.checkSocketAlive,
@@ -5901,6 +5902,20 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
5901
5902
  return returnCliFailure(deps, daemonResult.message);
5902
5903
  }
5903
5904
  progress.completePhase("starting daemon", daemonProgressSummary(daemonResult));
5905
+ if (deps.ensureDaemonBootPersistence) {
5906
+ try {
5907
+ await Promise.resolve(deps.ensureDaemonBootPersistence(deps.socketPath));
5908
+ }
5909
+ catch (error) {
5910
+ (0, runtime_1.emitNervesEvent)({
5911
+ level: "warn",
5912
+ component: "daemon",
5913
+ event: "daemon.system_setup_launchd_error",
5914
+ message: "failed to persist daemon boot startup",
5915
+ meta: { error: error instanceof Error ? error.message : String(error), socketPath: deps.socketPath },
5916
+ });
5917
+ }
5918
+ }
5904
5919
  progress.startPhase("provider checks");
5905
5920
  const providerDegraded = await checkAlreadyRunningAgentProviders(deps, (msg) => progress.updateDetail(msg));
5906
5921
  daemonResult.stability = mergeStartupStability(daemonResult.stability, providerDegraded);
@@ -6069,23 +6084,6 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
6069
6084
  const driftAdvisories = await collectAgentDriftAdvisories(deps);
6070
6085
  writeDriftAdvisorySummary(deps, driftAdvisories);
6071
6086
  }
6072
- // Persist boot startup AFTER daemon is running — bootstrap is safe now
6073
- // because the daemon socket exists, so launchd's KeepAlive registers
6074
- // for crash recovery without starting a competing process.
6075
- if (deps.ensureDaemonBootPersistence) {
6076
- try {
6077
- await Promise.resolve(deps.ensureDaemonBootPersistence(deps.socketPath));
6078
- }
6079
- catch (error) {
6080
- (0, runtime_1.emitNervesEvent)({
6081
- level: "warn",
6082
- component: "daemon",
6083
- event: "daemon.system_setup_launchd_error",
6084
- message: "failed to persist daemon boot startup",
6085
- meta: { error: error instanceof Error ? error.message : String(error), socketPath: deps.socketPath },
6086
- });
6087
- }
6088
- }
6089
6087
  return daemonResult.message;
6090
6088
  }
6091
6089
  if (command.kind === "daemon.dev") {
@@ -107,6 +107,24 @@ async function ensureCurrentDaemonRuntime(deps) {
107
107
  try {
108
108
  deps.onProgress?.("stopping the older background service");
109
109
  await deps.stopDaemon();
110
+ if (deps.prepareDaemonRuntimeReplacement) {
111
+ deps.onProgress?.("disabling daemon auto-restart during replacement");
112
+ try {
113
+ await Promise.resolve(deps.prepareDaemonRuntimeReplacement());
114
+ }
115
+ catch (error) {
116
+ (0, runtime_1.emitNervesEvent)({
117
+ level: "warn",
118
+ component: "daemon",
119
+ event: "daemon.runtime_sync_replacement_prepare_error",
120
+ message: "daemon runtime replacement preparation failed",
121
+ meta: {
122
+ socketPath: deps.socketPath,
123
+ reason: formatErrorReason(error),
124
+ },
125
+ });
126
+ }
127
+ }
110
128
  }
111
129
  catch (error) {
112
130
  const reason = formatErrorReason(error);
@@ -34,6 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.DAEMON_PLIST_LABEL = void 0;
37
+ exports.bootoutLaunchAgentByLabel = bootoutLaunchAgentByLabel;
37
38
  exports.generateDaemonPlist = generateDaemonPlist;
38
39
  exports.writeLaunchAgentPlist = writeLaunchAgentPlist;
39
40
  exports.installLaunchAgent = installLaunchAgent;
@@ -48,6 +49,26 @@ function plistFilePath(homeDir) {
48
49
  function userLaunchDomain(userUid) {
49
50
  return `gui/${userUid}`;
50
51
  }
52
+ function bootoutLaunchAgentByLabel(deps) {
53
+ const domain = userLaunchDomain(deps.userUid);
54
+ try {
55
+ deps.exec(`launchctl bootout ${domain}/${exports.DAEMON_PLIST_LABEL}`);
56
+ (0, runtime_1.emitNervesEvent)({
57
+ component: "daemon",
58
+ event: "daemon.launchd_label_bootout",
59
+ message: "booted out daemon launch agent by label",
60
+ meta: { label: exports.DAEMON_PLIST_LABEL, domain },
61
+ });
62
+ }
63
+ catch (error) {
64
+ (0, runtime_1.emitNervesEvent)({
65
+ component: "daemon",
66
+ event: "daemon.launchd_label_bootout_skipped",
67
+ message: "daemon launch agent label bootout skipped",
68
+ meta: { label: exports.DAEMON_PLIST_LABEL, domain, reason: error instanceof Error ? error.message : String(error) },
69
+ });
70
+ }
71
+ }
51
72
  function generateDaemonPlist(options) {
52
73
  (0, runtime_1.emitNervesEvent)({
53
74
  component: "daemon",
@@ -145,12 +166,8 @@ function uninstallLaunchAgent(deps) {
145
166
  meta: {},
146
167
  });
147
168
  const fullPath = plistFilePath(deps.homeDir);
148
- const domain = userLaunchDomain(deps.userUid);
169
+ bootoutLaunchAgentByLabel(deps);
149
170
  if (deps.existsFile(fullPath)) {
150
- try {
151
- deps.exec(`launchctl bootout ${domain} "${fullPath}"`);
152
- }
153
- catch { /* best effort */ }
154
171
  deps.removeFile(fullPath);
155
172
  }
156
173
  (0, runtime_1.emitNervesEvent)({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ouro.bot/cli",
3
- "version": "0.1.0-alpha.548",
3
+ "version": "0.1.0-alpha.549",
4
4
  "main": "dist/heart/daemon/ouro-entry.js",
5
5
  "bin": {
6
6
  "cli": "dist/heart/daemon/ouro-bot-entry.js",