@ouro.bot/cli 0.1.0-alpha.458 → 0.1.0-alpha.459

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,14 @@
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.459",
6
+ "changes": [
7
+ "`ouro connect bluebubbles` now applies a machine-local attachment to a running daemon by recycling Ouro once after the vault and bundle update, so the webhook listener starts immediately instead of requiring a manual `ouro down && ouro up` discovery step.",
8
+ "`ouro status` and daemon health now probe the BlueBubbles listener declared in the agent's machine-local vault config, including non-default webhook ports, instead of reporting stale health against the default port.",
9
+ "BlueBubbles setup docs now state the live-apply behavior directly, and daemon coverage locks the dynamic sense-health probe plus running-daemon connect path."
10
+ ]
11
+ },
4
12
  {
5
13
  "version": "0.1.0-alpha.458",
6
14
  "changes": [
@@ -1911,6 +1911,29 @@ async function applyRuntimeChangeToRunningAgent(agent, deps, onProgress) {
1911
1911
  return `daemon restart skipped: ${error instanceof Error ? error.message : String(error)}`;
1912
1912
  }
1913
1913
  }
1914
+ async function applyLocalSenseChangeToRunningDaemon(agent, senseLabel, deps, onProgress) {
1915
+ try {
1916
+ onProgress?.("checking whether Ouro is already running");
1917
+ const alive = await deps.checkSocketAlive(deps.socketPath);
1918
+ if (!alive)
1919
+ return "daemon is not running; next `ouro up` will load the change";
1920
+ onProgress?.(`restarting Ouro so ${senseLabel} is attached in the live sense manager`);
1921
+ const stopped = await withCliTimeout(DEFAULT_AGENT_RESTART_TIMEOUT_MS, "daemon stop request timed out", () => deps.sendCommand(deps.socketPath, { kind: "daemon.stop" }));
1922
+ if (!stopped.ok)
1923
+ return `daemon restart skipped: ${stopped.error ?? stopped.message ?? "unknown daemon error"}`;
1924
+ deps.cleanupStaleSocket(deps.socketPath);
1925
+ const started = await ensureDaemonRunning({
1926
+ ...deps,
1927
+ reportDaemonStartupPhase: (message) => onProgress?.(message),
1928
+ }, { initialAlive: false });
1929
+ if (!started.ok)
1930
+ return `daemon restart requested, but startup failed: ${started.message}`;
1931
+ return `restarted Ouro; ${senseLabel} is loaded for ${agent}`;
1932
+ }
1933
+ catch (error) {
1934
+ return `daemon restart skipped: ${error instanceof Error ? error.message : String(error)}`;
1935
+ }
1936
+ }
1914
1937
  async function executeVaultConfigSet(command, deps) {
1915
1938
  if (command.agent === "SerpentGuide") {
1916
1939
  throw new Error("SerpentGuide does not have persistent runtime credentials. Store credentials in the hatchling agent vault.");
@@ -2623,6 +2646,7 @@ async function executeConnectBlueBubbles(agent, deps) {
2623
2646
  const machineId = currentMachineId(deps);
2624
2647
  const progress = createHumanCommandProgress(deps, "connect bluebubbles");
2625
2648
  let stored;
2649
+ let daemonApply = "not applied";
2626
2650
  try {
2627
2651
  progress.startPhase("saving BlueBubbles attachment");
2628
2652
  progress.updateDetail("checking existing machine runtime config");
@@ -2649,6 +2673,7 @@ async function executeConnectBlueBubbles(agent, deps) {
2649
2673
  progress.updateDetail("enabling BlueBubbles in agent.json");
2650
2674
  enableAgentSense(agent, "bluebubbles", deps);
2651
2675
  progress.completePhase("saving BlueBubbles attachment", "secret stored");
2676
+ daemonApply = await runCommandProgressPhase(progress, "applying BlueBubbles to running Ouro", () => applyLocalSenseChangeToRunningDaemon(agent, "BlueBubbles", deps, (message) => progress.updateDetail(message)), (result) => result);
2652
2677
  progress.end();
2653
2678
  }
2654
2679
  catch (error) {
@@ -2663,11 +2688,13 @@ async function executeConnectBlueBubbles(agent, deps) {
2663
2688
  `Machine: ${machineId}`,
2664
2689
  `Stored: ${stored.itemPath}`,
2665
2690
  "agent.json: senses.bluebubbles.enabled = true",
2691
+ `Runtime: ${daemonApply}`,
2666
2692
  "secret was not printed",
2667
2693
  ...(syncSummary ? [syncSummary] : []),
2668
2694
  ],
2669
2695
  nextMoves: [
2670
- "Point BlueBubbles at this machine's webhook, then run ouro up.",
2696
+ `Point BlueBubbles at this machine's webhook listener on port ${port}${webhookPath}.`,
2697
+ "If BlueBubbles was already pointed there, messages can now reach the agent.",
2671
2698
  `Attach other machines separately if ${agent} should use BlueBubbles there too.`,
2672
2699
  ],
2673
2700
  fallbackLines: [
@@ -2675,9 +2702,10 @@ async function executeConnectBlueBubbles(agent, deps) {
2675
2702
  `machine: ${machineId}`,
2676
2703
  `stored: ${stored.itemPath}`,
2677
2704
  "agent.json: senses.bluebubbles.enabled = true",
2705
+ `runtime: ${daemonApply}`,
2678
2706
  "secret was not printed",
2679
2707
  "",
2680
- "Next: point BlueBubbles at this machine's webhook, then run `ouro up`.",
2708
+ `Next: point BlueBubbles at this machine's webhook listener on port ${port}${webhookPath}.`,
2681
2709
  ...(syncSummary ? [syncSummary] : []),
2682
2710
  ],
2683
2711
  });
@@ -58,8 +58,6 @@ const agent_config_check_1 = require("./agent-config-check");
58
58
  const pulse_1 = require("./pulse");
59
59
  const socket_client_1 = require("./socket-client");
60
60
  const bundle_manifest_1 = require("../../mind/bundle-manifest");
61
- const http_health_probe_1 = require("./http-health-probe");
62
- const config_1 = require("../config");
63
61
  function parseSocketPath(argv) {
64
62
  const socketIndex = argv.indexOf("--socket");
65
63
  if (socketIndex >= 0) {
@@ -128,19 +126,10 @@ const router = new message_router_1.FileMessageRouter();
128
126
  const senseManager = new sense_manager_1.DaemonSenseManager({
129
127
  agents: [...managedAgents],
130
128
  });
131
- /* v8 ignore next 5 -- entry-point wiring: probe factory and HealthMonitor both have full unit tests @preserve */
132
- let bbPort = 18790;
133
- try {
134
- bbPort = (0, config_1.getBlueBubblesChannelConfig)().port;
135
- }
136
- catch {
137
- // Daemon runs without --agent; agent-scoped config may not be available.
138
- }
139
- const bbProbe = (0, http_health_probe_1.createHttpHealthProbe)("bluebubbles", bbPort);
140
129
  const healthMonitor = new health_monitor_1.HealthMonitor({
141
130
  processManager,
142
131
  scheduler,
143
- senseProbes: [bbProbe],
132
+ senseProbeProvider: () => senseManager.listHealthProbes(),
144
133
  alertSink: (message) => {
145
134
  (0, runtime_1.emitNervesEvent)({
146
135
  level: "error",
@@ -9,6 +9,7 @@ class HealthMonitor {
9
9
  diskUsagePercent;
10
10
  onCriticalAgent;
11
11
  senseProbes;
12
+ senseProbeProvider;
12
13
  intervalHandle = null;
13
14
  constructor(options) {
14
15
  this.processManager = options.processManager;
@@ -17,6 +18,7 @@ class HealthMonitor {
17
18
  this.diskUsagePercent = options.diskUsagePercent ?? (() => 0);
18
19
  this.onCriticalAgent = options.onCriticalAgent ?? (() => undefined);
19
20
  this.senseProbes = options.senseProbes ?? [];
21
+ this.senseProbeProvider = options.senseProbeProvider ?? (() => []);
20
22
  }
21
23
  startPeriodicChecks(intervalMs) {
22
24
  if (this.intervalHandle !== null)
@@ -113,7 +115,18 @@ class HealthMonitor {
113
115
  message: `disk usage healthy (${diskPercent}%)`,
114
116
  });
115
117
  }
116
- for (const probe of this.senseProbes) {
118
+ const senseProbes = [...this.senseProbes];
119
+ try {
120
+ senseProbes.push(...this.senseProbeProvider());
121
+ }
122
+ catch (error) {
123
+ results.push({
124
+ name: "sense-probes",
125
+ status: "warn",
126
+ message: `sense probe discovery failed: ${error instanceof Error ? error.message : String(error)}`,
127
+ });
128
+ }
129
+ for (const probe of senseProbes) {
117
130
  try {
118
131
  const outcome = await probe.check();
119
132
  if (outcome.ok) {
@@ -43,6 +43,7 @@ const runtime_credentials_1 = require("../runtime-credentials");
43
43
  const sense_truth_1 = require("../sense-truth");
44
44
  const machine_identity_1 = require("../machine-identity");
45
45
  const process_manager_1 = require("./process-manager");
46
+ const http_health_probe_1 = require("./http-health-probe");
46
47
  const DEFAULT_TEAMS_PORT = 3978;
47
48
  const DEFAULT_BLUEBUBBLES_PORT = 18790;
48
49
  const DEFAULT_BLUEBUBBLES_WEBHOOK_PATH = "/bluebubbles-webhook";
@@ -352,6 +353,22 @@ class DaemonSenseManager {
352
353
  .filter((pid) => pid !== null && pid !== undefined);
353
354
  }
354
355
  /* v8 ignore stop */
356
+ listHealthProbes() {
357
+ const probes = [];
358
+ for (const [agent, context] of this.contexts.entries()) {
359
+ const runtimeConfig = (0, runtime_credentials_1.readRuntimeCredentialConfig)(agent);
360
+ const machineRuntimeConfig = (0, runtime_credentials_1.readMachineRuntimeCredentialConfig)(agent);
361
+ context.facts = senseFactsFromRuntimeConfig(agent, context.senses, runtimeConfig, machineRuntimeConfig);
362
+ if (!context.senses.bluebubbles.enabled || !context.facts.bluebubbles.configured || !machineRuntimeConfig.ok) {
363
+ continue;
364
+ }
365
+ const machinePayload = machineRuntimeConfig.config;
366
+ const bluebubblesChannel = machinePayload.bluebubblesChannel;
367
+ const port = numberField(bluebubblesChannel, "port", DEFAULT_BLUEBUBBLES_PORT);
368
+ probes.push((0, http_health_probe_1.createHttpHealthProbe)(`bluebubbles:${agent}`, port));
369
+ }
370
+ return probes;
371
+ }
355
372
  listSenseRows() {
356
373
  const runtime = new Map();
357
374
  for (const snapshot of this.processManager.listAgentSnapshots()) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ouro.bot/cli",
3
- "version": "0.1.0-alpha.458",
3
+ "version": "0.1.0-alpha.459",
4
4
  "main": "dist/heart/daemon/ouro-entry.js",
5
5
  "bin": {
6
6
  "cli": "dist/heart/daemon/ouro-bot-entry.js",