@ouro.bot/cli 0.1.0-alpha.38 → 0.1.0-alpha.381

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.
Files changed (331) hide show
  1. package/README.md +109 -14
  2. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/agent.json +3 -2
  3. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/SOUL.md +2 -2
  4. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +1 -1
  5. package/changelog.json +2303 -2
  6. package/dist/arc/attention-types.js +8 -0
  7. package/dist/arc/cares.js +140 -0
  8. package/dist/arc/episodes.js +117 -0
  9. package/dist/arc/intentions.js +133 -0
  10. package/dist/arc/json-store.js +117 -0
  11. package/dist/arc/obligations.js +237 -0
  12. package/dist/arc/packets.js +193 -0
  13. package/dist/arc/presence.js +185 -0
  14. package/dist/arc/task-lifecycle.js +65 -0
  15. package/dist/heart/active-work.js +832 -0
  16. package/dist/heart/agent-entry.js +58 -3
  17. package/dist/heart/attachments/image-normalize.js +194 -0
  18. package/dist/heart/attachments/materialize.js +97 -0
  19. package/dist/heart/attachments/originals.js +88 -0
  20. package/dist/heart/attachments/render.js +29 -0
  21. package/dist/heart/attachments/sources/adapter.js +2 -0
  22. package/dist/heart/attachments/sources/bluebubbles.js +156 -0
  23. package/dist/heart/attachments/sources/cli-local-file.js +78 -0
  24. package/dist/heart/attachments/sources/index.js +16 -0
  25. package/dist/heart/attachments/store.js +103 -0
  26. package/dist/heart/attachments/types.js +93 -0
  27. package/dist/heart/auth/auth-flow.js +378 -0
  28. package/dist/heart/bridges/manager.js +358 -0
  29. package/dist/heart/bridges/state-machine.js +135 -0
  30. package/dist/heart/bridges/store.js +123 -0
  31. package/dist/heart/bundle-state.js +168 -0
  32. package/dist/heart/commitments.js +111 -0
  33. package/dist/heart/config-registry.js +304 -0
  34. package/dist/heart/config.js +111 -128
  35. package/dist/heart/core.js +803 -259
  36. package/dist/heart/cross-chat-delivery.js +131 -0
  37. package/dist/heart/daemon/agent-config-check.js +376 -0
  38. package/dist/heart/daemon/agent-discovery.js +79 -3
  39. package/dist/heart/daemon/agent-service.js +360 -0
  40. package/dist/heart/daemon/agentic-repair.js +205 -0
  41. package/dist/heart/daemon/bluebubbles-health-diagnostics.js +122 -0
  42. package/dist/heart/daemon/cadence.js +70 -0
  43. package/dist/heart/daemon/cli-defaults.js +560 -0
  44. package/dist/heart/daemon/cli-exec.js +3220 -0
  45. package/dist/heart/daemon/cli-help.js +319 -0
  46. package/dist/heart/daemon/cli-parse.js +1060 -0
  47. package/dist/heart/daemon/cli-render-doctor.js +57 -0
  48. package/dist/heart/daemon/cli-render.js +560 -0
  49. package/dist/heart/daemon/cli-types.js +8 -0
  50. package/dist/heart/daemon/daemon-cli.js +29 -1498
  51. package/dist/heart/daemon/daemon-entry.js +356 -3
  52. package/dist/heart/daemon/daemon-health.js +141 -0
  53. package/dist/heart/daemon/daemon-runtime-sync.js +157 -12
  54. package/dist/heart/daemon/daemon-tombstone.js +236 -0
  55. package/dist/heart/daemon/daemon.js +774 -58
  56. package/dist/heart/daemon/doctor-types.js +8 -0
  57. package/dist/heart/daemon/doctor.js +419 -0
  58. package/dist/heart/daemon/health-monitor.js +79 -1
  59. package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
  60. package/dist/heart/daemon/hooks/bundle-meta.js +115 -1
  61. package/dist/heart/daemon/http-health-probe.js +80 -0
  62. package/dist/heart/daemon/inner-status.js +89 -0
  63. package/dist/heart/daemon/interactive-repair.js +182 -0
  64. package/dist/heart/daemon/launchd.js +46 -9
  65. package/dist/heart/daemon/log-tailer.js +82 -12
  66. package/dist/heart/daemon/logs-prune.js +105 -0
  67. package/dist/heart/daemon/message-router.js +17 -8
  68. package/dist/heart/daemon/os-cron-deps.js +134 -0
  69. package/dist/heart/daemon/ouro-bot-entry.js +1 -1
  70. package/dist/heart/daemon/process-manager.js +201 -0
  71. package/dist/heart/daemon/provider-discovery.js +137 -0
  72. package/dist/heart/daemon/pulse.js +475 -0
  73. package/dist/heart/daemon/run-hooks.js +2 -0
  74. package/dist/heart/daemon/runtime-logging.js +67 -16
  75. package/dist/heart/daemon/runtime-metadata.js +73 -0
  76. package/dist/heart/daemon/runtime-mode.js +67 -0
  77. package/dist/heart/daemon/safe-mode.js +161 -0
  78. package/dist/heart/daemon/sense-manager.js +119 -30
  79. package/dist/heart/daemon/session-id-resolver.js +131 -0
  80. package/dist/heart/daemon/skill-management-installer.js +94 -0
  81. package/dist/heart/daemon/socket-client.js +307 -0
  82. package/dist/heart/daemon/stale-bundle-prune.js +96 -0
  83. package/dist/heart/daemon/startup-tui.js +237 -0
  84. package/dist/heart/daemon/task-scheduler.js +3 -25
  85. package/dist/heart/daemon/thoughts.js +510 -0
  86. package/dist/heart/daemon/up-progress.js +135 -0
  87. package/dist/heart/delegation.js +62 -0
  88. package/dist/heart/habits/habit-migration.js +181 -0
  89. package/dist/heart/habits/habit-parser.js +140 -0
  90. package/dist/heart/habits/habit-scheduler.js +371 -0
  91. package/dist/heart/{daemon → hatch}/hatch-flow.js +55 -126
  92. package/dist/heart/{daemon → hatch}/hatch-specialist.js +3 -3
  93. package/dist/heart/{daemon → hatch}/specialist-prompt.js +10 -8
  94. package/dist/heart/{daemon → hatch}/specialist-tools.js +30 -10
  95. package/dist/heart/identity.js +153 -65
  96. package/dist/heart/kept-notes.js +357 -0
  97. package/dist/heart/kicks.js +2 -20
  98. package/dist/heart/machine-identity.js +161 -0
  99. package/dist/heart/mcp/mcp-server.js +653 -0
  100. package/dist/heart/migrate-config.js +100 -0
  101. package/dist/heart/model-capabilities.js +59 -0
  102. package/dist/heart/outlook/outlook-http-hooks.js +64 -0
  103. package/dist/heart/outlook/outlook-http-response.js +7 -0
  104. package/dist/heart/outlook/outlook-http-routes.js +232 -0
  105. package/dist/heart/outlook/outlook-http-static.js +99 -0
  106. package/dist/heart/outlook/outlook-http-transport.js +116 -0
  107. package/dist/heart/outlook/outlook-http.js +99 -0
  108. package/dist/heart/outlook/outlook-read.js +28 -0
  109. package/dist/heart/outlook/outlook-types.js +27 -0
  110. package/dist/heart/outlook/outlook-view.js +195 -0
  111. package/dist/heart/outlook/readers/agent-machine.js +359 -0
  112. package/dist/heart/outlook/readers/continuity-readers.js +332 -0
  113. package/dist/heart/outlook/readers/runtime-readers.js +660 -0
  114. package/dist/heart/outlook/readers/sessions.js +232 -0
  115. package/dist/heart/outlook/readers/shared.js +111 -0
  116. package/dist/heart/platform.js +81 -0
  117. package/dist/heart/progress-story.js +42 -0
  118. package/dist/heart/provider-attempt.js +133 -0
  119. package/dist/heart/provider-binding-resolver.js +239 -0
  120. package/dist/heart/provider-credentials.js +379 -0
  121. package/dist/heart/provider-failover.js +266 -0
  122. package/dist/heart/provider-models.js +81 -0
  123. package/dist/heart/provider-ping.js +237 -0
  124. package/dist/heart/provider-state.js +216 -0
  125. package/dist/heart/provider-visibility.js +186 -0
  126. package/dist/heart/providers/anthropic-token.js +131 -0
  127. package/dist/heart/providers/anthropic.js +193 -55
  128. package/dist/heart/providers/azure.js +103 -12
  129. package/dist/heart/providers/error-classification.js +63 -0
  130. package/dist/heart/providers/github-copilot.js +145 -0
  131. package/dist/heart/providers/minimax-vlm.js +189 -0
  132. package/dist/heart/providers/minimax.js +29 -7
  133. package/dist/heart/providers/openai-codex.js +39 -29
  134. package/dist/heart/runtime-credentials.js +181 -0
  135. package/dist/heart/session-activity.js +190 -0
  136. package/dist/heart/session-events.js +855 -0
  137. package/dist/heart/session-transcript.js +167 -0
  138. package/dist/heart/start-of-turn-packet.js +345 -0
  139. package/dist/heart/streaming.js +36 -27
  140. package/dist/heart/sync.js +332 -0
  141. package/dist/heart/target-resolution.js +127 -0
  142. package/dist/heart/tempo.js +93 -0
  143. package/dist/heart/temporal-view.js +41 -0
  144. package/dist/heart/tool-activity-callbacks.js +36 -0
  145. package/dist/heart/tool-description.js +135 -0
  146. package/dist/heart/tool-friction.js +55 -0
  147. package/dist/heart/tool-loop.js +200 -0
  148. package/dist/heart/turn-context.js +351 -0
  149. package/dist/heart/turn-coordinator.js +28 -0
  150. package/dist/heart/{daemon → versioning}/ouro-bot-global-installer.js +1 -1
  151. package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
  152. package/dist/heart/versioning/ouro-path-installer.js +301 -0
  153. package/dist/heart/versioning/ouro-version-manager.js +295 -0
  154. package/dist/heart/{daemon → versioning}/staged-restart.js +40 -8
  155. package/dist/heart/{daemon → versioning}/update-checker.js +12 -2
  156. package/dist/heart/{daemon → versioning}/update-hooks.js +63 -59
  157. package/dist/mind/bundle-manifest.js +7 -1
  158. package/dist/mind/context.js +141 -94
  159. package/dist/mind/diary-integrity.js +60 -0
  160. package/dist/mind/{memory.js → diary.js} +84 -96
  161. package/dist/mind/embedding-provider.js +60 -0
  162. package/dist/mind/file-state.js +179 -0
  163. package/dist/mind/first-impressions.js +14 -1
  164. package/dist/mind/friends/channel.js +48 -0
  165. package/dist/mind/friends/group-context.js +144 -0
  166. package/dist/mind/friends/resolver.js +38 -1
  167. package/dist/mind/friends/store-file.js +39 -3
  168. package/dist/mind/friends/trust-explanation.js +74 -0
  169. package/dist/mind/friends/types.js +9 -1
  170. package/dist/mind/journal-index.js +161 -0
  171. package/dist/mind/note-search.js +268 -0
  172. package/dist/mind/obligation-steering.js +221 -0
  173. package/dist/mind/pending.js +74 -7
  174. package/dist/mind/prompt-refresh.js +3 -2
  175. package/dist/mind/prompt.js +966 -183
  176. package/dist/mind/provenance-trust.js +26 -0
  177. package/dist/mind/scrutiny.js +173 -0
  178. package/dist/mind/token-estimate.js +8 -12
  179. package/dist/nerves/cli-logging.js +7 -1
  180. package/dist/nerves/coverage/audit-rules.js +15 -6
  181. package/dist/nerves/coverage/audit.js +28 -2
  182. package/dist/nerves/coverage/cli.js +1 -1
  183. package/dist/nerves/coverage/file-completeness.js +83 -5
  184. package/dist/nerves/coverage/run-artifacts.js +1 -1
  185. package/dist/nerves/event-buffer.js +111 -0
  186. package/dist/nerves/index.js +224 -4
  187. package/dist/nerves/observation.js +20 -0
  188. package/dist/nerves/redact.js +79 -0
  189. package/dist/nerves/runtime.js +5 -1
  190. package/dist/outlook-ui/assets/index-BAcU08c-.css +1 -0
  191. package/dist/outlook-ui/assets/index-D7l3l4vY.js +61 -0
  192. package/dist/outlook-ui/index.html +15 -0
  193. package/dist/repertoire/ado-client.js +15 -56
  194. package/dist/repertoire/ado-semantic.js +11 -10
  195. package/dist/repertoire/api-client.js +97 -0
  196. package/dist/repertoire/bitwarden-store.js +365 -0
  197. package/dist/repertoire/bundle-templates.js +72 -0
  198. package/dist/repertoire/bw-installer.js +79 -0
  199. package/dist/repertoire/coding/codex-jsonl.js +64 -0
  200. package/dist/repertoire/coding/context-pack.js +330 -0
  201. package/dist/repertoire/coding/feedback.js +197 -30
  202. package/dist/repertoire/coding/manager.js +158 -9
  203. package/dist/repertoire/coding/spawner.js +55 -9
  204. package/dist/repertoire/coding/tools.js +170 -7
  205. package/dist/repertoire/commerce-errors.js +109 -0
  206. package/dist/repertoire/commerce-self-test.js +156 -0
  207. package/dist/repertoire/credential-access.js +107 -0
  208. package/dist/repertoire/duffel-client.js +185 -0
  209. package/dist/repertoire/github-client.js +14 -55
  210. package/dist/repertoire/graph-client.js +11 -52
  211. package/dist/repertoire/guardrails.js +371 -0
  212. package/dist/repertoire/mcp-client.js +255 -0
  213. package/dist/repertoire/mcp-manager.js +305 -0
  214. package/dist/repertoire/mcp-tools.js +63 -0
  215. package/dist/repertoire/shell-sessions.js +133 -0
  216. package/dist/repertoire/skills.js +15 -24
  217. package/dist/repertoire/stripe-client.js +131 -0
  218. package/dist/repertoire/tasks/board.js +43 -5
  219. package/dist/repertoire/tasks/fix.js +182 -0
  220. package/dist/repertoire/tasks/index.js +28 -10
  221. package/dist/repertoire/tasks/lifecycle.js +2 -2
  222. package/dist/repertoire/tasks/parser.js +3 -2
  223. package/dist/repertoire/tasks/scanner.js +194 -37
  224. package/dist/repertoire/tasks/transitions.js +16 -79
  225. package/dist/repertoire/tool-results.js +29 -0
  226. package/dist/repertoire/tools-attachments.js +317 -0
  227. package/dist/repertoire/tools-base.js +42 -690
  228. package/dist/repertoire/tools-bluebubbles.js +1 -0
  229. package/dist/repertoire/tools-bridge.js +141 -0
  230. package/dist/repertoire/tools-bundle.js +984 -0
  231. package/dist/repertoire/tools-config.js +185 -0
  232. package/dist/repertoire/tools-continuity.js +248 -0
  233. package/dist/repertoire/tools-credential.js +182 -0
  234. package/dist/repertoire/tools-files.js +342 -0
  235. package/dist/repertoire/tools-flight.js +224 -0
  236. package/dist/repertoire/tools-flow.js +105 -0
  237. package/dist/repertoire/tools-github.js +1 -7
  238. package/dist/repertoire/tools-notes.js +376 -0
  239. package/dist/repertoire/tools-session.js +739 -0
  240. package/dist/repertoire/tools-shell.js +120 -0
  241. package/dist/repertoire/tools-stripe.js +180 -0
  242. package/dist/repertoire/tools-surface.js +243 -0
  243. package/dist/repertoire/tools-teams.js +12 -62
  244. package/dist/repertoire/tools-travel.js +125 -0
  245. package/dist/repertoire/tools-user-profile.js +144 -0
  246. package/dist/repertoire/tools-vault.js +40 -0
  247. package/dist/repertoire/tools.js +144 -120
  248. package/dist/repertoire/travel-api-client.js +360 -0
  249. package/dist/repertoire/user-profile.js +118 -0
  250. package/dist/repertoire/vault-setup.js +241 -0
  251. package/dist/repertoire/vault-unlock.js +364 -0
  252. package/dist/scripts/claude-code-hook.js +41 -0
  253. package/dist/scripts/claude-code-stop-hook.js +47 -0
  254. package/dist/senses/attention-queue.js +116 -0
  255. package/dist/senses/bluebubbles/attachment-cache.js +53 -0
  256. package/dist/senses/bluebubbles/attachment-download.js +137 -0
  257. package/dist/senses/{bluebubbles-client.js → bluebubbles/client.js} +260 -9
  258. package/dist/senses/bluebubbles/entry.js +70 -0
  259. package/dist/senses/bluebubbles/inbound-log.js +113 -0
  260. package/dist/senses/bluebubbles/index.js +1620 -0
  261. package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +121 -70
  262. package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +43 -12
  263. package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +46 -6
  264. package/dist/senses/bluebubbles/replay.js +129 -0
  265. package/dist/senses/bluebubbles/runtime-state.js +109 -0
  266. package/dist/senses/{bluebubbles-session-cleanup.js → bluebubbles/session-cleanup.js} +1 -1
  267. package/dist/senses/cli/bracketed-paste.js +82 -0
  268. package/dist/senses/cli/image-paste.js +287 -0
  269. package/dist/senses/cli/image-ref-navigation.js +75 -0
  270. package/dist/senses/cli/ink-app.js +156 -0
  271. package/dist/senses/cli/inline-diff.js +64 -0
  272. package/dist/senses/cli/input-keys.js +174 -0
  273. package/dist/senses/cli/kill-ring.js +86 -0
  274. package/dist/senses/cli/message-list.js +51 -0
  275. package/dist/senses/cli/ouro-tui.js +605 -0
  276. package/dist/senses/cli/spinner-imperative.js +135 -0
  277. package/dist/senses/cli/spinner.js +101 -0
  278. package/dist/senses/cli/status-line.js +60 -0
  279. package/dist/senses/cli/streaming-markdown.js +526 -0
  280. package/dist/senses/cli/tool-display.js +83 -0
  281. package/dist/senses/cli/tool-render.js +85 -0
  282. package/dist/senses/cli/tui-store.js +240 -0
  283. package/dist/senses/cli/virtual-list.js +35 -0
  284. package/dist/senses/cli-entry.js +60 -8
  285. package/dist/senses/cli-layout.js +187 -0
  286. package/dist/senses/cli.js +574 -254
  287. package/dist/senses/commands.js +66 -3
  288. package/dist/senses/continuity.js +94 -0
  289. package/dist/senses/habit-turn-message.js +108 -0
  290. package/dist/senses/inner-dialog-worker.js +112 -19
  291. package/dist/senses/inner-dialog.js +630 -82
  292. package/dist/senses/pipeline.js +602 -0
  293. package/dist/senses/proactive-content-guard.js +51 -0
  294. package/dist/senses/shared-turn.js +205 -0
  295. package/dist/senses/surface-tool.js +68 -0
  296. package/dist/senses/teams-entry.js +60 -8
  297. package/dist/senses/teams.js +585 -231
  298. package/dist/senses/trust-gate.js +112 -2
  299. package/package.json +28 -7
  300. package/skills/agent-commerce.md +106 -0
  301. package/skills/browser-navigation.md +110 -0
  302. package/skills/commerce-setup-guide.md +116 -0
  303. package/skills/commerce-setup.md +84 -0
  304. package/skills/configure-dev-tools.md +101 -0
  305. package/skills/travel-planning.md +134 -0
  306. package/dist/heart/daemon/ouro-path-installer.js +0 -178
  307. package/dist/heart/daemon/subagent-installer.js +0 -134
  308. package/dist/mind/associative-recall.js +0 -197
  309. package/dist/senses/bluebubbles-entry.js +0 -11
  310. package/dist/senses/bluebubbles.js +0 -736
  311. package/dist/senses/debug-activity.js +0 -127
  312. package/subagents/README.md +0 -60
  313. package/subagents/work-doer.md +0 -235
  314. package/subagents/work-merger.md +0 -618
  315. package/subagents/work-planner.md +0 -382
  316. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
  317. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
  318. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
  319. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
  320. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
  321. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +0 -0
  322. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
  323. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
  324. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
  325. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
  326. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
  327. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
  328. /package/dist/heart/{daemon → hatch}/hatch-animation.js +0 -0
  329. /package/dist/heart/{daemon → hatch}/specialist-orchestrator.js +0 -0
  330. /package/dist/heart/{daemon → versioning}/ouro-uti.js +0 -0
  331. /package/dist/heart/{daemon → versioning}/wrapper-publish-guard.js +0 -0
@@ -34,6 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.getRuntimeMetadata = getRuntimeMetadata;
37
+ const crypto_1 = require("crypto");
37
38
  const fs = __importStar(require("fs"));
38
39
  const path = __importStar(require("path"));
39
40
  const childProcess = __importStar(require("child_process"));
@@ -85,10 +86,71 @@ function readLastUpdated(repoRoot, packageJsonPath, statSyncImpl, execFileSyncIm
85
86
  return { value: UNKNOWN_METADATA, source: "unknown" };
86
87
  }
87
88
  }
89
+ function listConfigTargets(bundlesRoot, daemonLoggingPath, readdirSyncImpl) {
90
+ if (!readdirSyncImpl)
91
+ return [];
92
+ const targets = new Set();
93
+ if (daemonLoggingPath) {
94
+ targets.add(daemonLoggingPath);
95
+ }
96
+ try {
97
+ const bundleEntries = readdirSyncImpl(bundlesRoot, { withFileTypes: true });
98
+ for (const entry of bundleEntries) {
99
+ if (!entry.isDirectory() || !entry.name.endsWith(".ouro"))
100
+ continue;
101
+ targets.add(path.join(bundlesRoot, entry.name, "agent.json"));
102
+ }
103
+ }
104
+ catch {
105
+ // ignore unreadable bundle roots
106
+ }
107
+ return [...targets].sort();
108
+ }
109
+ function readConfigFingerprint(targets, readFileSyncImpl, existsSyncImpl) {
110
+ if (!readFileSyncImpl || !existsSyncImpl) {
111
+ return {
112
+ value: UNKNOWN_METADATA,
113
+ source: "unknown",
114
+ trackedFiles: targets.length,
115
+ presentFiles: 0,
116
+ };
117
+ }
118
+ const hash = (0, crypto_1.createHash)("sha256");
119
+ let presentFiles = 0;
120
+ for (const target of targets) {
121
+ hash.update(target);
122
+ hash.update("\0");
123
+ if (!existsSyncImpl(target)) {
124
+ hash.update("missing");
125
+ hash.update("\0");
126
+ continue;
127
+ }
128
+ presentFiles += 1;
129
+ hash.update("present");
130
+ hash.update("\0");
131
+ try {
132
+ hash.update(readFileSyncImpl(target, "utf-8"));
133
+ }
134
+ catch {
135
+ hash.update("unreadable");
136
+ }
137
+ hash.update("\0");
138
+ }
139
+ return {
140
+ value: hash.digest("hex"),
141
+ source: "content-hash",
142
+ trackedFiles: targets.length,
143
+ presentFiles,
144
+ };
145
+ }
88
146
  function getRuntimeMetadata(deps = {}) {
89
147
  const repoRoot = deps.repoRoot ?? (0, identity_1.getRepoRoot)();
148
+ const bundlesRoot = deps.bundlesRoot ?? (0, identity_1.getAgentBundlesRoot)();
149
+ const daemonLoggingPath = deps.daemonLoggingPath ?? (0, identity_1.getAgentDaemonLoggingConfigPath)();
90
150
  const readFileSyncImpl = deps.readFileSync ?? optionalFunction(fs, "readFileSync")?.bind(fs) ?? null;
91
151
  const statSyncImpl = deps.statSync ?? optionalFunction(fs, "statSync")?.bind(fs) ?? null;
152
+ const readdirSyncImpl = deps.readdirSync ?? optionalFunction(fs, "readdirSync")?.bind(fs) ?? null;
153
+ const existsSyncImpl = deps.existsSync ?? optionalFunction(fs, "existsSync")?.bind(fs) ?? null;
92
154
  const execFileSyncImpl = deps.execFileSync
93
155
  ?? optionalFunction(childProcess, "execFileSync")?.bind(childProcess)
94
156
  ?? null;
@@ -101,6 +163,8 @@ function getRuntimeMetadata(deps = {}) {
101
163
  throw new Error("git unavailable");
102
164
  }))
103
165
  : { value: UNKNOWN_METADATA, source: "unknown" };
166
+ const configTargets = listConfigTargets(bundlesRoot, daemonLoggingPath, readdirSyncImpl);
167
+ const configFingerprint = readConfigFingerprint(configTargets, readFileSyncImpl, existsSyncImpl);
104
168
  (0, runtime_1.emitNervesEvent)({
105
169
  component: "daemon",
106
170
  event: "daemon.runtime_metadata_read",
@@ -109,10 +173,19 @@ function getRuntimeMetadata(deps = {}) {
109
173
  version,
110
174
  lastUpdated: lastUpdated.value,
111
175
  lastUpdatedSource: lastUpdated.source,
176
+ repoRoot,
177
+ configFingerprint: configFingerprint.value === UNKNOWN_METADATA
178
+ ? UNKNOWN_METADATA
179
+ : configFingerprint.value.slice(0, 12),
180
+ configFingerprintSource: configFingerprint.source,
181
+ configTrackedFiles: configFingerprint.trackedFiles,
182
+ configPresentFiles: configFingerprint.presentFiles,
112
183
  },
113
184
  });
114
185
  return {
115
186
  version,
116
187
  lastUpdated: lastUpdated.value,
188
+ repoRoot,
189
+ configFingerprint: configFingerprint.value,
117
190
  };
118
191
  }
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.detectRuntimeMode = detectRuntimeMode;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const runtime_1 = require("../../nerves/runtime");
40
+ function detectRuntimeMode(rootPath, deps = {}) {
41
+ const checkExists = deps.existsSync ?? fs.existsSync;
42
+ // 1. Production: installed via npm
43
+ if (rootPath.includes("node_modules/@ouro.bot/cli") ||
44
+ rootPath.includes("node_modules/ouro.bot")) {
45
+ (0, runtime_1.emitNervesEvent)({
46
+ component: "daemon",
47
+ event: "daemon.runtime_mode_detected",
48
+ message: "detected runtime mode",
49
+ meta: { rootPath, mode: "production" },
50
+ });
51
+ return "production";
52
+ }
53
+ // 2-4. Everything else is dev: worktrees, git repos, unknown paths
54
+ // (conservative default: assume dev unless proven production)
55
+ const reason = rootPath.includes(".claude/worktrees/")
56
+ ? "worktree"
57
+ : checkExists(path.join(rootPath, ".git"))
58
+ ? "git-repo"
59
+ : "unknown";
60
+ (0, runtime_1.emitNervesEvent)({
61
+ component: "daemon",
62
+ event: "daemon.runtime_mode_detected",
63
+ message: "detected runtime mode",
64
+ meta: { rootPath, mode: "dev", reason },
65
+ });
66
+ return "dev";
67
+ }
@@ -0,0 +1,161 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.SAFE_MODE_OVERRIDE_FILENAME = void 0;
37
+ exports.detectSafeMode = detectSafeMode;
38
+ exports.pruneOldCrashes = pruneOldCrashes;
39
+ const fs = __importStar(require("fs"));
40
+ const path = __importStar(require("path"));
41
+ const runtime_1 = require("../../nerves/runtime");
42
+ exports.SAFE_MODE_OVERRIDE_FILENAME = "safe-mode-override.json";
43
+ /** 3+ crashes within this window triggers safe mode */
44
+ const CRASH_WINDOW_MS = 5 * 60 * 1000; // 5 minutes
45
+ const CRASH_THRESHOLD = 3;
46
+ /**
47
+ * Reads crash history from the tombstone file and determines if safe mode should be active.
48
+ * Returns active if 3+ crashes occurred within 5 minutes.
49
+ *
50
+ * Safe mode is bypassed when:
51
+ * - devMode is true
52
+ * - A safe-mode override file exists (written by `ouro up --force`)
53
+ */
54
+ function detectSafeMode(tombstonePath, options) {
55
+ const inactive = { active: false, reason: "", enteredAt: "" };
56
+ // Dev mode: never enter safe mode
57
+ if (options?.devMode) {
58
+ return inactive;
59
+ }
60
+ // Check for override file (--force)
61
+ const overridePath = path.join(path.dirname(tombstonePath), exports.SAFE_MODE_OVERRIDE_FILENAME);
62
+ try {
63
+ if (fs.existsSync(overridePath)) {
64
+ return inactive;
65
+ }
66
+ }
67
+ catch {
68
+ // Best-effort check
69
+ }
70
+ // Read tombstone
71
+ let parsed;
72
+ try {
73
+ const raw = fs.readFileSync(tombstonePath, "utf-8");
74
+ parsed = JSON.parse(raw);
75
+ }
76
+ catch {
77
+ return inactive;
78
+ }
79
+ // Extract recentCrashes
80
+ if (!Array.isArray(parsed.recentCrashes)) {
81
+ return inactive;
82
+ }
83
+ const nowMs = options?.now ? options.now() : Date.now();
84
+ const windowStart = nowMs - CRASH_WINDOW_MS;
85
+ // Filter to valid string timestamps within the crash window
86
+ const recentInWindow = parsed.recentCrashes.filter((entry) => {
87
+ if (typeof entry !== "string")
88
+ return false;
89
+ const ts = new Date(entry).getTime();
90
+ if (isNaN(ts))
91
+ return false;
92
+ return ts >= windowStart;
93
+ });
94
+ if (recentInWindow.length < CRASH_THRESHOLD) {
95
+ return inactive;
96
+ }
97
+ const result = {
98
+ active: true,
99
+ reason: `crash loop detected: ${recentInWindow.length} crashes in last 5 minutes`,
100
+ enteredAt: new Date(nowMs).toISOString(),
101
+ };
102
+ (0, runtime_1.emitNervesEvent)({
103
+ level: "error",
104
+ component: "daemon",
105
+ event: "daemon.safe_mode_entered",
106
+ message: result.reason,
107
+ meta: {
108
+ crashCount: recentInWindow.length,
109
+ windowMs: CRASH_WINDOW_MS,
110
+ tombstonePath,
111
+ },
112
+ });
113
+ return result;
114
+ }
115
+ /**
116
+ * Prunes crash entries older than 5 minutes from the tombstone's recentCrashes.
117
+ * Also removes the safe-mode override file if present.
118
+ * Called after successful startup (uptime > stability threshold).
119
+ */
120
+ function pruneOldCrashes(tombstonePath, options) {
121
+ // Remove override file
122
+ const overridePath = path.join(path.dirname(tombstonePath), exports.SAFE_MODE_OVERRIDE_FILENAME);
123
+ try {
124
+ if (fs.existsSync(overridePath)) {
125
+ fs.unlinkSync(overridePath);
126
+ }
127
+ }
128
+ catch {
129
+ // Best-effort
130
+ }
131
+ // Read existing tombstone
132
+ let parsed;
133
+ try {
134
+ const raw = fs.readFileSync(tombstonePath, "utf-8");
135
+ parsed = JSON.parse(raw);
136
+ }
137
+ catch {
138
+ return;
139
+ }
140
+ if (!Array.isArray(parsed.recentCrashes)) {
141
+ return;
142
+ }
143
+ const nowMs = options?.now ? options.now() : Date.now();
144
+ const windowStart = nowMs - CRASH_WINDOW_MS;
145
+ // Keep only entries within the window
146
+ const pruned = parsed.recentCrashes.filter((entry) => {
147
+ if (typeof entry !== "string")
148
+ return false;
149
+ const ts = new Date(entry).getTime();
150
+ if (isNaN(ts))
151
+ return false;
152
+ return ts >= windowStart;
153
+ });
154
+ parsed.recentCrashes = pruned;
155
+ try {
156
+ fs.writeFileSync(tombstonePath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
157
+ }
158
+ catch {
159
+ // Best-effort
160
+ }
161
+ }
@@ -39,11 +39,13 @@ const os = __importStar(require("os"));
39
39
  const path = __importStar(require("path"));
40
40
  const runtime_1 = require("../../nerves/runtime");
41
41
  const identity_1 = require("../identity");
42
+ const runtime_credentials_1 = require("../runtime-credentials");
42
43
  const sense_truth_1 = require("../sense-truth");
43
44
  const process_manager_1 = require("./process-manager");
44
45
  const DEFAULT_TEAMS_PORT = 3978;
45
46
  const DEFAULT_BLUEBUBBLES_PORT = 18790;
46
47
  const DEFAULT_BLUEBUBBLES_WEBHOOK_PATH = "/bluebubbles-webhook";
48
+ const BLUEBUBBLES_RUNTIME_FRESHNESS_WINDOW_MS = 90_000;
47
49
  function defaultSenses() {
48
50
  return {
49
51
  cli: { ...identity_1.DEFAULT_AGENT_SENSES.cli },
@@ -86,22 +88,6 @@ function readAgentSenses(agentJsonPath) {
86
88
  }
87
89
  return defaults;
88
90
  }
89
- function readSecretsPayload(secretsPath) {
90
- try {
91
- const raw = fs.readFileSync(secretsPath, "utf-8");
92
- const parsed = JSON.parse(raw);
93
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
94
- return { payload: {}, error: "invalid secrets.json object" };
95
- }
96
- return { payload: parsed, error: null };
97
- }
98
- catch (error) {
99
- return {
100
- payload: {},
101
- error: error instanceof Error ? error.message : String(error),
102
- };
103
- }
104
- }
105
91
  function textField(record, key) {
106
92
  const value = record?.[key];
107
93
  return typeof value === "string" ? value.trim() : "";
@@ -110,13 +96,28 @@ function numberField(record, key, fallback) {
110
96
  const value = record?.[key];
111
97
  return typeof value === "number" && Number.isFinite(value) ? value : fallback;
112
98
  }
113
- function senseFactsFromSecrets(agent, senses, secretsPath) {
99
+ function compactRuntimeConfigError(agent, error) {
100
+ const compact = error.replace(/\s+/g, " ").trim();
101
+ if (/credential vault is locked|vault locked|vault is locked/i.test(compact)) {
102
+ return `vault locked; run 'ouro vault unlock --agent ${agent}'`;
103
+ }
104
+ return compact || "unavailable";
105
+ }
106
+ function runtimeConfigUnavailableDetail(agent, runtimeConfig) {
107
+ if (runtimeConfig.ok)
108
+ return "";
109
+ if (runtimeConfig.reason === "missing")
110
+ return `missing vault runtime/config (${agent})`;
111
+ return `vault runtime/config unavailable (${compactRuntimeConfigError(agent, runtimeConfig.error)})`;
112
+ }
113
+ function senseFactsFromRuntimeConfig(agent, senses, runtimeConfig) {
114
114
  const base = {
115
115
  cli: { configured: true, detail: "local interactive terminal" },
116
116
  teams: { configured: false, detail: "not enabled in agent.json" },
117
117
  bluebubbles: { configured: false, detail: "not enabled in agent.json" },
118
118
  };
119
- const { payload, error } = readSecretsPayload(secretsPath);
119
+ const payload = runtimeConfig.ok ? runtimeConfig.config : {};
120
+ const unavailableDetail = runtimeConfigUnavailableDetail(agent, runtimeConfig);
120
121
  const teams = payload.teams;
121
122
  const teamsChannel = payload.teamsChannel;
122
123
  const bluebubbles = payload.bluebubbles;
@@ -136,9 +137,7 @@ function senseFactsFromSecrets(agent, senses, secretsPath) {
136
137
  }
137
138
  : {
138
139
  configured: false,
139
- detail: error && !fs.existsSync(secretsPath)
140
- ? `missing secrets.json (${agent})`
141
- : `missing ${missing.join("/")}`,
140
+ detail: runtimeConfig.ok ? `missing ${missing.join("/")}` : unavailableDetail,
142
141
  };
143
142
  }
144
143
  if (senses.bluebubbles.enabled) {
@@ -154,13 +153,17 @@ function senseFactsFromSecrets(agent, senses, secretsPath) {
154
153
  }
155
154
  : {
156
155
  configured: false,
157
- detail: error && !fs.existsSync(secretsPath)
158
- ? `missing secrets.json (${agent})`
159
- : `missing ${missing.join("/")}`,
156
+ detail: runtimeConfig.ok ? `missing ${missing.join("/")}` : unavailableDetail,
160
157
  };
161
158
  }
162
159
  return base;
163
160
  }
161
+ function senseRepairHint(agent, sense) {
162
+ if (sense === "teams") {
163
+ return `Run 'ouro vault config set --agent ${agent} --key teams.clientId', teams.clientSecret, and teams.tenantId; then run 'ouro up' again.`;
164
+ }
165
+ return `Run 'ouro vault config set --agent ${agent} --key bluebubbles.serverUrl' and bluebubbles.password; then run 'ouro up' again.`;
166
+ }
164
167
  function parseSenseSnapshotName(name) {
165
168
  const parts = name.split(":");
166
169
  if (parts.length !== 2)
@@ -175,30 +178,102 @@ function runtimeInfoFor(status) {
175
178
  return { runtime: "running" };
176
179
  return { runtime: "error" };
177
180
  }
181
+ function blueBubblesRuntimeStateIsFresh(lastCheckedAt, now = Date.now()) {
182
+ if (!lastCheckedAt) {
183
+ return false;
184
+ }
185
+ const checkedAt = Date.parse(lastCheckedAt);
186
+ if (!Number.isFinite(checkedAt)) {
187
+ return false;
188
+ }
189
+ return checkedAt >= now - BLUEBUBBLES_RUNTIME_FRESHNESS_WINDOW_MS;
190
+ }
191
+ function readBlueBubblesRuntimeJson(runtimePath) {
192
+ try {
193
+ const raw = fs.readFileSync(runtimePath, "utf-8");
194
+ const parsed = JSON.parse(raw);
195
+ /* v8 ignore start -- branches: ternary fallbacks for missing/malformed BB runtime fields @preserve */
196
+ return {
197
+ upstreamStatus: parsed.upstreamStatus === "ok" || parsed.upstreamStatus === "error"
198
+ ? parsed.upstreamStatus
199
+ : "unknown",
200
+ detail: typeof parsed.detail === "string" && parsed.detail.trim()
201
+ ? parsed.detail
202
+ : "startup health probe pending",
203
+ lastCheckedAt: typeof parsed.lastCheckedAt === "string" ? parsed.lastCheckedAt : undefined,
204
+ };
205
+ /* v8 ignore stop */
206
+ /* v8 ignore start -- defensive: catch for missing/corrupt BB runtime state file @preserve */
207
+ }
208
+ catch {
209
+ return { upstreamStatus: "unknown", detail: "startup health probe pending" };
210
+ }
211
+ /* v8 ignore stop */
212
+ }
213
+ function readBlueBubblesRuntimeFacts(agent, bundlesRoot, snapshot) {
214
+ const agentRoot = path.join(bundlesRoot, `${agent}.ouro`);
215
+ const runtimePath = path.join(agentRoot, "state", "senses", "bluebubbles", "runtime.json");
216
+ if (!fs.existsSync(runtimePath)) {
217
+ return { runtime: snapshot?.runtime };
218
+ }
219
+ const state = readBlueBubblesRuntimeJson(runtimePath);
220
+ if (!blueBubblesRuntimeStateIsFresh(state.lastCheckedAt)) {
221
+ return { runtime: snapshot?.runtime };
222
+ }
223
+ if (state.upstreamStatus === "error") {
224
+ return {
225
+ runtime: "error",
226
+ detail: state.detail,
227
+ };
228
+ }
229
+ if (state.upstreamStatus === "ok") {
230
+ return { runtime: "running" };
231
+ }
232
+ return { runtime: snapshot?.runtime };
233
+ }
178
234
  class DaemonSenseManager {
179
235
  processManager;
180
236
  contexts;
237
+ bundlesRoot;
181
238
  constructor(options) {
182
239
  const bundlesRoot = options.bundlesRoot ?? path.join(os.homedir(), "AgentBundles");
183
- const secretsRoot = options.secretsRoot ?? path.join(os.homedir(), ".agentsecrets");
240
+ this.bundlesRoot = bundlesRoot;
184
241
  this.contexts = new Map(options.agents.map((agent) => {
185
242
  const senses = readAgentSenses(path.join(bundlesRoot, `${agent}.ouro`, "agent.json"));
186
- const facts = senseFactsFromSecrets(agent, senses, path.join(secretsRoot, agent, "secrets.json"));
243
+ const facts = senseFactsFromRuntimeConfig(agent, senses, (0, runtime_credentials_1.readRuntimeCredentialConfig)(agent));
187
244
  return [agent, { senses, facts }];
188
245
  }));
189
246
  const managedSenseAgents = [...this.contexts.entries()].flatMap(([agent, context]) => {
190
247
  return ["teams", "bluebubbles"]
191
- .filter((sense) => context.senses[sense].enabled && context.facts[sense].configured)
248
+ .filter((sense) => context.senses[sense].enabled)
192
249
  .map((sense) => ({
193
250
  name: `${agent}:${sense}`,
194
251
  agentArg: agent,
195
- entry: sense === "teams" ? "senses/teams-entry.js" : "senses/bluebubbles-entry.js",
252
+ entry: sense === "teams" ? "senses/teams-entry.js" : "senses/bluebubbles/entry.js",
196
253
  channel: sense,
197
254
  autoStart: true,
198
255
  }));
199
256
  });
200
257
  this.processManager = options.processManager ?? new process_manager_1.DaemonProcessManager({
201
258
  agents: managedSenseAgents,
259
+ configCheck: async (name) => {
260
+ const parsed = parseSenseSnapshotName(name);
261
+ if (!parsed)
262
+ return { ok: true };
263
+ const context = this.contexts.get(parsed.agent);
264
+ if (!context)
265
+ return { ok: true };
266
+ const refreshed = await (0, runtime_credentials_1.refreshRuntimeCredentialConfig)(parsed.agent, { preserveCachedOnFailure: true });
267
+ context.facts = senseFactsFromRuntimeConfig(parsed.agent, context.senses, refreshed);
268
+ const fact = context.facts[parsed.sense];
269
+ if (fact.configured)
270
+ return { ok: true };
271
+ return {
272
+ ok: false,
273
+ error: `${parsed.sense} is enabled for ${parsed.agent} but runtime credentials are not ready: ${fact.detail}`,
274
+ fix: senseRepairHint(parsed.agent, parsed.sense),
275
+ };
276
+ },
202
277
  });
203
278
  (0, runtime_1.emitNervesEvent)({
204
279
  component: "channels",
@@ -216,6 +291,13 @@ class DaemonSenseManager {
216
291
  async stopAll() {
217
292
  await this.processManager.stopAll();
218
293
  }
294
+ /* v8 ignore start -- pid collection for orphan cleanup pidfile @preserve */
295
+ listManagedPids() {
296
+ return this.processManager.listAgentSnapshots()
297
+ .map((s) => s.pid)
298
+ .filter((pid) => pid !== null && pid !== undefined);
299
+ }
300
+ /* v8 ignore stop */
219
301
  listSenseRows() {
220
302
  const runtime = new Map();
221
303
  for (const snapshot of this.processManager.listAgentSnapshots()) {
@@ -227,6 +309,8 @@ class DaemonSenseManager {
227
309
  runtime.set(parsed.agent, current);
228
310
  }
229
311
  const rows = [...this.contexts.entries()].flatMap(([agent, context]) => {
312
+ context.facts = senseFactsFromRuntimeConfig(agent, context.senses, (0, runtime_credentials_1.readRuntimeCredentialConfig)(agent));
313
+ const blueBubblesRuntimeFacts = readBlueBubblesRuntimeFacts(agent, this.bundlesRoot, runtime.get(agent)?.bluebubbles);
230
314
  const runtimeInfo = {
231
315
  cli: { configured: true },
232
316
  teams: {
@@ -235,7 +319,7 @@ class DaemonSenseManager {
235
319
  },
236
320
  bluebubbles: {
237
321
  configured: context.facts.bluebubbles.configured,
238
- ...(runtime.get(agent)?.bluebubbles ?? {}),
322
+ ...blueBubblesRuntimeFacts,
239
323
  },
240
324
  };
241
325
  const inventory = (0, sense_truth_1.getSenseInventory)({ senses: context.senses }, runtimeInfo);
@@ -245,7 +329,12 @@ class DaemonSenseManager {
245
329
  label: entry.label,
246
330
  enabled: entry.enabled,
247
331
  status: entry.status,
248
- detail: entry.enabled ? context.facts[entry.sense].detail : "not enabled in agent.json",
332
+ detail: entry.enabled
333
+ ? entry.sense === "bluebubbles"
334
+ ? blueBubblesRuntimeFacts.detail
335
+ ?? context.facts[entry.sense].detail
336
+ : context.facts[entry.sense].detail
337
+ : "not enabled in agent.json",
249
338
  }));
250
339
  });
251
340
  (0, runtime_1.emitNervesEvent)({