@ouro.bot/cli 0.1.0-alpha.67 → 0.1.0-alpha.670

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 (457) hide show
  1. package/README.md +127 -23
  2. package/RepairGuide.ouro/agent.json +5 -0
  3. package/RepairGuide.ouro/psyche/IDENTITY.md +19 -0
  4. package/RepairGuide.ouro/psyche/SOUL.md +55 -0
  5. package/RepairGuide.ouro/skills/diagnose-broken-remote.md +63 -0
  6. package/RepairGuide.ouro/skills/diagnose-stacked-typed-issues.md +35 -0
  7. package/RepairGuide.ouro/skills/diagnose-sync-blocked.md +54 -0
  8. package/RepairGuide.ouro/skills/diagnose-vault-expired.md +60 -0
  9. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/agent.json +4 -2
  10. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/SOUL.md +2 -2
  11. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +1 -1
  12. package/changelog.json +4271 -16
  13. package/dist/a2a/card.js +56 -0
  14. package/dist/a2a/client.js +143 -0
  15. package/dist/a2a/config.js +50 -0
  16. package/dist/a2a/onboarding.js +111 -0
  17. package/dist/a2a/server.js +498 -0
  18. package/dist/a2a/task-store.js +69 -0
  19. package/dist/a2a/types.js +3 -0
  20. package/dist/arc/attention-types.js +8 -0
  21. package/dist/arc/cares.js +144 -0
  22. package/dist/arc/episodes.js +118 -0
  23. package/dist/arc/evolution.js +487 -0
  24. package/dist/arc/flight-recorder.js +810 -0
  25. package/dist/arc/intentions.js +134 -0
  26. package/dist/arc/json-store.js +117 -0
  27. package/dist/arc/obligations.js +326 -0
  28. package/dist/arc/packets.js +288 -0
  29. package/dist/arc/presence.js +185 -0
  30. package/dist/arc/task-lifecycle.js +57 -0
  31. package/dist/commerce/store.js +755 -0
  32. package/dist/commerce/types.js +3 -0
  33. package/dist/heart/active-work.js +860 -43
  34. package/dist/heart/agent-entry.js +69 -3
  35. package/dist/heart/attachments/image-normalize.js +194 -0
  36. package/dist/heart/attachments/materialize.js +97 -0
  37. package/dist/heart/attachments/originals.js +88 -0
  38. package/dist/heart/attachments/render.js +29 -0
  39. package/dist/heart/attachments/sources/bluebubbles.js +156 -0
  40. package/dist/heart/attachments/sources/cli-local-file.js +78 -0
  41. package/dist/heart/attachments/sources/index.js +16 -0
  42. package/dist/heart/attachments/store.js +103 -0
  43. package/dist/heart/attachments/types.js +93 -0
  44. package/dist/heart/auth/auth-flow.js +479 -0
  45. package/dist/heart/awaiting/await-alert.js +146 -0
  46. package/dist/heart/awaiting/await-expiry.js +108 -0
  47. package/dist/heart/awaiting/await-loader.js +91 -0
  48. package/dist/heart/awaiting/await-parser.js +141 -0
  49. package/dist/heart/awaiting/await-runtime-state.js +100 -0
  50. package/dist/heart/awaiting/await-scheduler.js +378 -0
  51. package/dist/heart/background-operations.js +281 -0
  52. package/dist/heart/bridges/manager.js +137 -17
  53. package/dist/heart/bridges/store.js +14 -2
  54. package/dist/heart/bundle-state.js +168 -0
  55. package/dist/heart/commitments.js +135 -0
  56. package/dist/heart/config-registry.js +331 -0
  57. package/dist/heart/config.js +118 -119
  58. package/dist/heart/context-loss-gauntlet.js +354 -0
  59. package/dist/heart/context-loss-sentinel.js +907 -0
  60. package/dist/heart/core.js +1288 -249
  61. package/dist/heart/cross-chat-delivery.js +8 -22
  62. package/dist/heart/daemon/agent-config-check.js +427 -0
  63. package/dist/heart/daemon/agent-discovery.js +102 -3
  64. package/dist/heart/daemon/agent-service.js +523 -0
  65. package/dist/heart/daemon/agentic-repair.js +547 -0
  66. package/dist/heart/daemon/bluebubbles-health-diagnostics.js +122 -0
  67. package/dist/heart/daemon/boot-sync-probe.js +197 -0
  68. package/dist/heart/daemon/cadence.js +70 -0
  69. package/dist/heart/daemon/cli-defaults.js +780 -0
  70. package/dist/heart/daemon/cli-desk.js +322 -0
  71. package/dist/heart/daemon/cli-exec.js +7981 -0
  72. package/dist/heart/daemon/cli-help.js +576 -0
  73. package/dist/heart/daemon/cli-parse.js +1850 -0
  74. package/dist/heart/daemon/cli-render-doctor.js +57 -0
  75. package/dist/heart/daemon/cli-render.js +763 -0
  76. package/dist/heart/daemon/cli-types.js +8 -0
  77. package/dist/heart/daemon/connect-bay.js +323 -0
  78. package/dist/heart/daemon/daemon-cli.js +29 -1750
  79. package/dist/heart/daemon/daemon-entry.js +533 -3
  80. package/dist/heart/daemon/daemon-health.js +176 -0
  81. package/dist/heart/daemon/daemon-rollup.js +57 -0
  82. package/dist/heart/daemon/daemon-runtime-sync.js +88 -13
  83. package/dist/heart/daemon/daemon-tombstone.js +236 -0
  84. package/dist/heart/daemon/daemon.js +950 -76
  85. package/dist/heart/daemon/dns-workflow.js +394 -0
  86. package/dist/heart/daemon/doctor-types.js +8 -0
  87. package/dist/heart/daemon/doctor.js +873 -0
  88. package/dist/heart/daemon/health-monitor.js +125 -1
  89. package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
  90. package/dist/heart/daemon/hooks/bundle-meta.js +135 -1
  91. package/dist/heart/daemon/http-health-probe.js +80 -0
  92. package/dist/heart/daemon/human-command-screens.js +234 -0
  93. package/dist/heart/daemon/human-readiness.js +114 -0
  94. package/dist/heart/daemon/inner-status.js +78 -0
  95. package/dist/heart/daemon/interactive-repair.js +394 -0
  96. package/dist/heart/daemon/launchd.js +37 -8
  97. package/dist/heart/daemon/log-tailer.js +79 -10
  98. package/dist/heart/daemon/logs-prune.js +110 -0
  99. package/dist/heart/daemon/mcp-canary.js +297 -0
  100. package/dist/heart/daemon/message-router.js +6 -2
  101. package/dist/heart/daemon/migrate-to-desk.js +848 -0
  102. package/dist/heart/daemon/os-cron-deps.js +135 -0
  103. package/dist/heart/daemon/os-cron.js +14 -12
  104. package/dist/heart/daemon/ouro-bot-entry.js +4 -2
  105. package/dist/heart/daemon/ouro-entry.js +3 -1
  106. package/dist/heart/daemon/plugin-cli.js +432 -0
  107. package/dist/heart/daemon/process-manager.js +511 -40
  108. package/dist/heart/daemon/provider-discovery.js +137 -0
  109. package/dist/heart/daemon/provider-ping-progress.js +83 -0
  110. package/dist/heart/daemon/pulse.js +475 -0
  111. package/dist/heart/daemon/readiness-repair.js +365 -0
  112. package/dist/heart/daemon/run-hooks.js +2 -0
  113. package/dist/heart/daemon/runtime-logging.js +41 -14
  114. package/dist/heart/daemon/runtime-metadata.js +2 -30
  115. package/dist/heart/daemon/safe-mode.js +161 -0
  116. package/dist/heart/daemon/sense-manager.js +564 -38
  117. package/dist/heart/daemon/session-id-resolver.js +131 -0
  118. package/dist/heart/daemon/skill-management-installer.js +1 -1
  119. package/dist/heart/daemon/socket-client.js +158 -11
  120. package/dist/heart/daemon/stale-bundle-prune.js +96 -0
  121. package/dist/heart/daemon/startup-tui.js +330 -0
  122. package/dist/heart/daemon/task-scheduler.js +117 -39
  123. package/dist/heart/daemon/terminal-ui.js +499 -0
  124. package/dist/heart/daemon/thoughts.js +229 -17
  125. package/dist/heart/daemon/up-progress.js +366 -0
  126. package/dist/heart/daemon/vault-items.js +56 -0
  127. package/dist/heart/delegation.js +1 -4
  128. package/dist/heart/habits/habit-migration.js +189 -0
  129. package/dist/heart/habits/habit-parser.js +211 -0
  130. package/dist/heart/habits/habit-runtime-state.js +114 -0
  131. package/dist/heart/habits/habit-scheduler.js +391 -0
  132. package/dist/heart/habits/habit-session-summary.js +318 -0
  133. package/dist/heart/habits/habit-session.js +618 -0
  134. package/dist/heart/{daemon → hatch}/hatch-flow.js +42 -56
  135. package/dist/heart/{daemon → hatch}/hatch-specialist.js +6 -8
  136. package/dist/heart/{daemon → hatch}/specialist-prompt.js +12 -9
  137. package/dist/heart/{daemon → hatch}/specialist-tools.js +45 -18
  138. package/dist/heart/identity.js +174 -57
  139. package/dist/heart/kept-notes.js +289 -0
  140. package/dist/heart/kicks.js +1 -1
  141. package/dist/heart/machine-identity.js +161 -0
  142. package/dist/heart/mail-import-discovery.js +353 -0
  143. package/dist/heart/mailbox/mailbox-http-hooks.js +96 -0
  144. package/dist/heart/mailbox/mailbox-http-response.js +7 -0
  145. package/dist/heart/mailbox/mailbox-http-routes.js +375 -0
  146. package/dist/heart/mailbox/mailbox-http-static.js +103 -0
  147. package/dist/heart/mailbox/mailbox-http-transport.js +116 -0
  148. package/dist/heart/mailbox/mailbox-http.js +99 -0
  149. package/dist/heart/mailbox/mailbox-read.js +37 -0
  150. package/dist/heart/mailbox/mailbox-types.js +27 -0
  151. package/dist/heart/mailbox/mailbox-view.js +197 -0
  152. package/dist/heart/mailbox/readers/agent-machine.js +428 -0
  153. package/dist/heart/mailbox/readers/continuity-readers.js +329 -0
  154. package/dist/heart/mailbox/readers/mail.js +375 -0
  155. package/dist/heart/mailbox/readers/runtime-readers.js +815 -0
  156. package/dist/heart/mailbox/readers/sessions.js +232 -0
  157. package/dist/heart/mailbox/readers/shared.js +111 -0
  158. package/dist/heart/mcp/mcp-server.js +696 -0
  159. package/dist/heart/migrate-config.js +100 -0
  160. package/dist/heart/model-capabilities.js +19 -0
  161. package/dist/heart/orientation-frame.js +217 -0
  162. package/dist/heart/platform.js +81 -0
  163. package/dist/heart/provider-attempt.js +134 -0
  164. package/dist/heart/provider-binding-resolver.js +273 -0
  165. package/dist/heart/provider-credentials.js +425 -0
  166. package/dist/heart/provider-failover.js +311 -0
  167. package/dist/heart/provider-models.js +81 -0
  168. package/dist/heart/provider-ping.js +262 -0
  169. package/dist/heart/provider-readiness-cache.js +119 -0
  170. package/dist/heart/provider-visibility.js +188 -0
  171. package/dist/heart/providers/anthropic-token.js +131 -0
  172. package/dist/heart/providers/anthropic.js +139 -52
  173. package/dist/heart/providers/azure.js +23 -11
  174. package/dist/heart/providers/error-classification.js +127 -0
  175. package/dist/heart/providers/github-copilot.js +145 -0
  176. package/dist/heart/providers/minimax-vlm.js +189 -0
  177. package/dist/heart/providers/minimax.js +26 -8
  178. package/dist/heart/providers/openai-codex-token.js +349 -0
  179. package/dist/heart/providers/openai-codex.js +55 -40
  180. package/dist/heart/runtime-capability-check.js +170 -0
  181. package/dist/heart/runtime-credentials.js +367 -0
  182. package/dist/heart/runtime-cwd.js +87 -0
  183. package/dist/heart/sense-truth.js +17 -4
  184. package/dist/heart/session-activity.js +48 -24
  185. package/dist/heart/session-events.js +1133 -0
  186. package/dist/heart/session-playback-cli-main.js +5 -0
  187. package/dist/heart/session-playback-cli.js +36 -0
  188. package/dist/heart/session-playback.js +231 -0
  189. package/dist/heart/session-stats-cli-main.js +5 -0
  190. package/dist/heart/session-stats.js +182 -0
  191. package/dist/heart/session-transcript.js +133 -0
  192. package/dist/heart/start-of-turn-packet.js +357 -0
  193. package/dist/heart/streaming.js +44 -27
  194. package/dist/heart/structured-output.js +196 -0
  195. package/dist/heart/sync-classification.js +176 -0
  196. package/dist/heart/sync.js +449 -0
  197. package/dist/heart/target-resolution.js +11 -7
  198. package/dist/heart/tempo.js +93 -0
  199. package/dist/heart/temporal-view.js +41 -0
  200. package/dist/heart/timeouts.js +101 -0
  201. package/dist/heart/tool-activity-callbacks.js +59 -0
  202. package/dist/heart/tool-description.js +155 -0
  203. package/dist/heart/tool-friction.js +55 -0
  204. package/dist/heart/tool-loop.js +200 -0
  205. package/dist/heart/turn-context.js +450 -0
  206. package/dist/heart/{daemon → versioning}/ouro-bot-global-installer.js +6 -5
  207. package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
  208. package/dist/heart/versioning/ouro-path-installer.js +426 -0
  209. package/dist/heart/versioning/ouro-version-manager.js +409 -0
  210. package/dist/heart/{daemon → versioning}/staged-restart.js +40 -8
  211. package/dist/heart/{daemon → versioning}/update-checker.js +6 -1
  212. package/dist/heart/versioning/update-hooks.js +154 -0
  213. package/dist/heart/work-card.js +390 -0
  214. package/dist/mailbox-ui/assets/index-CaTIFDmv.js +1 -0
  215. package/dist/mailbox-ui/assets/index-Du_9G9WO.css +1 -0
  216. package/dist/mailbox-ui/assets/vendor-CcN1XpQ9.js +61 -0
  217. package/dist/mailbox-ui/index.html +16 -0
  218. package/dist/mailroom/attention.js +167 -0
  219. package/dist/mailroom/autonomy.js +209 -0
  220. package/dist/mailroom/blob-store.js +715 -0
  221. package/dist/mailroom/body-cache.js +61 -0
  222. package/dist/mailroom/core.js +788 -0
  223. package/dist/mailroom/entry.js +160 -0
  224. package/dist/mailroom/file-store.js +568 -0
  225. package/dist/mailroom/mbox-import.js +393 -0
  226. package/dist/mailroom/migration.js +164 -0
  227. package/dist/mailroom/outbound.js +380 -0
  228. package/dist/mailroom/policy.js +263 -0
  229. package/dist/mailroom/reader.js +233 -0
  230. package/dist/mailroom/search-cache.js +334 -0
  231. package/dist/mailroom/search-relevance.js +319 -0
  232. package/dist/mailroom/smtp-ingress.js +176 -0
  233. package/dist/mailroom/source-state.js +176 -0
  234. package/dist/mailroom/thread.js +109 -0
  235. package/dist/mailroom/travel-extract.js +89 -0
  236. package/dist/mind/bundle-manifest.js +24 -2
  237. package/dist/mind/context.js +250 -101
  238. package/dist/mind/desk-section.js +362 -0
  239. package/dist/mind/diary-integrity.js +60 -0
  240. package/dist/mind/{memory.js → diary.js} +68 -77
  241. package/dist/mind/embedding-provider.js +60 -0
  242. package/dist/mind/file-state.js +179 -0
  243. package/dist/mind/{associative-recall.js → note-search.js} +47 -58
  244. package/dist/mind/obligation-steering.js +221 -0
  245. package/dist/mind/pending.js +6 -1
  246. package/dist/mind/prompt-refresh.js +3 -2
  247. package/dist/mind/prompt.js +1020 -148
  248. package/dist/mind/provenance-trust.js +26 -0
  249. package/dist/mind/record-paths.js +312 -0
  250. package/dist/mind/scrutiny.js +173 -0
  251. package/dist/nerves/cli-logging.js +7 -1
  252. package/dist/nerves/coverage/audit-rules.js +15 -6
  253. package/dist/nerves/coverage/audit.js +28 -2
  254. package/dist/nerves/coverage/cli.js +1 -1
  255. package/dist/nerves/coverage/contract.js +5 -5
  256. package/dist/nerves/coverage/file-completeness.js +139 -5
  257. package/dist/nerves/event-buffer.js +111 -0
  258. package/dist/nerves/index.js +224 -4
  259. package/dist/nerves/observation.js +20 -0
  260. package/dist/nerves/redact.js +79 -0
  261. package/dist/nerves/review/cli-main.js +5 -0
  262. package/dist/nerves/review/cli.js +156 -0
  263. package/dist/nerves/review/core.js +152 -0
  264. package/dist/nerves/runtime.js +5 -1
  265. package/dist/repertoire/ado-client.js +15 -56
  266. package/dist/repertoire/ado-semantic.js +16 -10
  267. package/dist/repertoire/api-client.js +97 -0
  268. package/dist/repertoire/bitwarden-store.js +1042 -0
  269. package/dist/repertoire/bundle-templates.js +71 -0
  270. package/dist/repertoire/bw-installer.js +180 -0
  271. package/dist/repertoire/coding/codex-jsonl.js +64 -0
  272. package/dist/repertoire/coding/context-pack.js +331 -0
  273. package/dist/repertoire/coding/feedback.js +197 -30
  274. package/dist/repertoire/coding/manager.js +166 -10
  275. package/dist/repertoire/coding/spawner.js +55 -9
  276. package/dist/repertoire/coding/tools.js +219 -7
  277. package/dist/repertoire/commerce-errors.js +109 -0
  278. package/dist/repertoire/commerce-self-test.js +156 -0
  279. package/dist/repertoire/credential-access.js +178 -0
  280. package/dist/repertoire/desk/classifier.js +362 -0
  281. package/dist/repertoire/duffel-client.js +185 -0
  282. package/dist/repertoire/github-client.js +14 -55
  283. package/dist/repertoire/graph-client.js +11 -52
  284. package/dist/repertoire/guardrails.js +161 -27
  285. package/dist/repertoire/mcp-client.js +295 -0
  286. package/dist/repertoire/mcp-manager.js +434 -0
  287. package/dist/repertoire/mcp-tools.js +83 -0
  288. package/dist/repertoire/plugin-mcp.js +175 -0
  289. package/dist/repertoire/plugins.js +253 -0
  290. package/dist/repertoire/shell-sessions.js +133 -0
  291. package/dist/repertoire/skills.js +48 -4
  292. package/dist/repertoire/stripe-client.js +131 -0
  293. package/dist/repertoire/tool-results.js +29 -0
  294. package/dist/repertoire/tools-a2a.js +282 -0
  295. package/dist/repertoire/tools-attachments.js +317 -0
  296. package/dist/repertoire/tools-awaiting.js +372 -0
  297. package/dist/repertoire/tools-base.js +63 -1082
  298. package/dist/repertoire/tools-bluebubbles.js +2 -0
  299. package/dist/repertoire/tools-bridge.js +144 -0
  300. package/dist/repertoire/tools-bundle.js +993 -0
  301. package/dist/repertoire/tools-commerce.js +253 -0
  302. package/dist/repertoire/tools-config.js +186 -0
  303. package/dist/repertoire/tools-continuity.js +252 -0
  304. package/dist/repertoire/tools-credential.js +383 -0
  305. package/dist/repertoire/tools-evolution.js +527 -0
  306. package/dist/repertoire/tools-files.js +344 -0
  307. package/dist/repertoire/tools-flight.js +290 -0
  308. package/dist/repertoire/tools-flow.js +119 -0
  309. package/dist/repertoire/tools-github.js +3 -8
  310. package/dist/repertoire/tools-mail.js +1975 -0
  311. package/dist/repertoire/tools-notes.js +468 -0
  312. package/dist/repertoire/tools-obligations.js +143 -0
  313. package/dist/repertoire/tools-orientation.js +31 -0
  314. package/dist/repertoire/tools-record.js +482 -0
  315. package/dist/repertoire/tools-runtime.js +150 -0
  316. package/dist/repertoire/tools-session.js +906 -0
  317. package/dist/repertoire/tools-shell.js +120 -0
  318. package/dist/repertoire/tools-stripe.js +224 -0
  319. package/dist/repertoire/tools-surface.js +355 -0
  320. package/dist/repertoire/tools-teams.js +12 -39
  321. package/dist/repertoire/tools-travel.js +125 -0
  322. package/dist/repertoire/tools-trip.js +982 -0
  323. package/dist/repertoire/tools-user-profile.js +146 -0
  324. package/dist/repertoire/tools-vault.js +40 -0
  325. package/dist/repertoire/tools-voice.js +145 -0
  326. package/dist/repertoire/tools.js +250 -79
  327. package/dist/repertoire/travel-api-client.js +360 -0
  328. package/dist/repertoire/user-profile.js +131 -0
  329. package/dist/repertoire/vault-setup.js +246 -0
  330. package/dist/repertoire/vault-unlock.js +594 -0
  331. package/dist/scripts/claude-code-hook.js +41 -0
  332. package/dist/scripts/claude-code-stop-hook.js +47 -0
  333. package/dist/senses/a2a-entry.js +78 -0
  334. package/dist/senses/attention-queue.js +186 -0
  335. package/dist/senses/await-turn-message.js +58 -0
  336. package/dist/senses/bluebubbles/active-turns.js +216 -0
  337. package/dist/senses/bluebubbles/attachment-cache.js +53 -0
  338. package/dist/senses/bluebubbles/attachment-download.js +137 -0
  339. package/dist/senses/{bluebubbles-client.js → bluebubbles/client.js} +219 -18
  340. package/dist/senses/bluebubbles/entry.js +77 -0
  341. package/dist/senses/{bluebubbles-inbound-log.js → bluebubbles/inbound-log.js} +20 -3
  342. package/dist/senses/bluebubbles/index.js +2732 -0
  343. package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +121 -71
  344. package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +33 -12
  345. package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +3 -3
  346. package/dist/senses/bluebubbles/processed-log.js +133 -0
  347. package/dist/senses/bluebubbles/replay.js +137 -0
  348. package/dist/senses/{bluebubbles-runtime-state.js → bluebubbles/runtime-state.js} +30 -2
  349. package/dist/senses/{bluebubbles-session-cleanup.js → bluebubbles/session-cleanup.js} +1 -1
  350. package/dist/senses/bluebubbles-meta-guard.js +40 -0
  351. package/dist/senses/cli/bracketed-paste.js +82 -0
  352. package/dist/senses/cli/image-paste.js +287 -0
  353. package/dist/senses/cli/image-ref-navigation.js +75 -0
  354. package/dist/senses/cli/ink-app.js +156 -0
  355. package/dist/senses/cli/inline-diff.js +64 -0
  356. package/dist/senses/cli/input-keys.js +174 -0
  357. package/dist/senses/cli/kill-ring.js +86 -0
  358. package/dist/senses/cli/message-list.js +51 -0
  359. package/dist/senses/cli/ouro-tui.js +607 -0
  360. package/dist/senses/cli/spinner-imperative.js +135 -0
  361. package/dist/senses/cli/spinner.js +101 -0
  362. package/dist/senses/cli/status-line.js +60 -0
  363. package/dist/senses/cli/streaming-markdown.js +526 -0
  364. package/dist/senses/cli/tool-display.js +85 -0
  365. package/dist/senses/cli/tool-render.js +85 -0
  366. package/dist/senses/cli/tui-store.js +240 -0
  367. package/dist/senses/cli/virtual-list.js +35 -0
  368. package/dist/senses/cli-entry.js +60 -8
  369. package/dist/senses/cli-layout.js +100 -0
  370. package/dist/senses/cli.js +522 -212
  371. package/dist/senses/commands.js +66 -3
  372. package/dist/senses/habit-turn-message.js +160 -0
  373. package/dist/senses/inner-dialog-worker.js +499 -22
  374. package/dist/senses/inner-dialog.js +544 -47
  375. package/dist/senses/mail-entry.js +66 -0
  376. package/dist/senses/mail.js +379 -0
  377. package/dist/senses/pipeline.js +870 -179
  378. package/dist/senses/proactive-content-guard.js +51 -0
  379. package/dist/senses/shared-turn.js +416 -0
  380. package/dist/senses/surface-tool.js +109 -0
  381. package/dist/senses/teams-entry.js +60 -8
  382. package/dist/senses/teams.js +400 -112
  383. package/dist/senses/trust-gate.js +102 -7
  384. package/dist/senses/voice/audio-playback.js +237 -0
  385. package/dist/senses/voice/audio-routing.js +119 -0
  386. package/dist/senses/voice/elevenlabs.js +202 -0
  387. package/dist/senses/voice/floor-control.js +431 -0
  388. package/dist/senses/voice/floor-controller.js +115 -0
  389. package/dist/senses/voice/golden-path.js +116 -0
  390. package/dist/senses/voice/index.js +29 -0
  391. package/dist/senses/voice/meeting.js +113 -0
  392. package/dist/senses/voice/outbound.js +190 -0
  393. package/dist/senses/voice/phone.js +33 -0
  394. package/dist/senses/voice/playback.js +139 -0
  395. package/dist/senses/voice/realtime-eval.js +496 -0
  396. package/dist/senses/voice/realtime-trace.js +531 -0
  397. package/dist/senses/voice/transcript.js +70 -0
  398. package/dist/senses/voice/turn.js +191 -0
  399. package/dist/senses/voice/twilio-phone-runtime.js +807 -0
  400. package/dist/senses/voice/twilio-phone.js +5077 -0
  401. package/dist/senses/voice/types.js +2 -0
  402. package/dist/senses/voice/whisper.js +161 -0
  403. package/dist/senses/voice-entry.js +81 -0
  404. package/dist/senses/voice-realtime-eval-command.js +99 -0
  405. package/dist/senses/voice-realtime-eval-entry.js +21 -0
  406. package/dist/senses/voice-twilio-entry.js +87 -0
  407. package/dist/trips/core.js +138 -0
  408. package/dist/trips/store.js +265 -0
  409. package/dist/util/frontmatter.js +69 -0
  410. package/package.json +57 -12
  411. package/skills/agent-commerce.md +113 -0
  412. package/skills/browser-navigation.md +117 -0
  413. package/skills/commerce-setup-guide.md +116 -0
  414. package/skills/commerce-setup.md +84 -0
  415. package/skills/configure-dev-tools.md +99 -0
  416. package/skills/travel-planning.md +138 -0
  417. package/dist/heart/daemon/auth-flow.js +0 -351
  418. package/dist/heart/daemon/ouro-path-installer.js +0 -178
  419. package/dist/heart/daemon/update-hooks.js +0 -138
  420. package/dist/heart/safe-workspace.js +0 -228
  421. package/dist/heart/session-recall.js +0 -116
  422. package/dist/mind/friends/channel.js +0 -84
  423. package/dist/mind/friends/group-context.js +0 -144
  424. package/dist/mind/friends/resolver.js +0 -84
  425. package/dist/mind/friends/store-file.js +0 -190
  426. package/dist/mind/friends/store.js +0 -4
  427. package/dist/mind/friends/tokens.js +0 -26
  428. package/dist/mind/friends/trust-explanation.js +0 -74
  429. package/dist/mind/friends/types.js +0 -29
  430. package/dist/repertoire/tasks/board.js +0 -134
  431. package/dist/repertoire/tasks/index.js +0 -224
  432. package/dist/repertoire/tasks/lifecycle.js +0 -80
  433. package/dist/repertoire/tasks/middleware.js +0 -65
  434. package/dist/repertoire/tasks/parser.js +0 -173
  435. package/dist/repertoire/tasks/scanner.js +0 -132
  436. package/dist/repertoire/tasks/transitions.js +0 -144
  437. package/dist/senses/bluebubbles-entry.js +0 -13
  438. package/dist/senses/bluebubbles.js +0 -1177
  439. package/dist/senses/debug-activity.js +0 -148
  440. package/subagents/README.md +0 -7
  441. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
  442. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
  443. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
  444. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
  445. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
  446. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +0 -0
  447. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
  448. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
  449. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
  450. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
  451. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
  452. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
  453. /package/dist/{repertoire/tasks/types.js → heart/attachments/sources/adapter.js} +0 -0
  454. /package/dist/heart/{daemon → hatch}/hatch-animation.js +0 -0
  455. /package/dist/heart/{daemon → hatch}/specialist-orchestrator.js +0 -0
  456. /package/dist/heart/{daemon → versioning}/ouro-uti.js +0 -0
  457. /package/dist/heart/{daemon → versioning}/wrapper-publish-guard.js +0 -0
@@ -1,35 +1,422 @@
1
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
+ })();
2
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.HEARTBEAT_OK_REST_SUPPRESSION_MS = exports.HABIT_RECURSION_BURST_THRESHOLD = exports.HABIT_RECURSION_BURST_WINDOW_MS = exports.HABIT_RECURSION_MIN_INTERVAL_MS = exports.MAX_CONSECUTIVE_INSTINCT_TURNS = void 0;
3
37
  exports.createInnerDialogWorker = createInnerDialogWorker;
4
38
  exports.startInnerDialogWorker = startInnerDialogWorker;
39
+ const fs = __importStar(require("fs"));
40
+ const path = __importStar(require("path"));
5
41
  const inner_dialog_1 = require("./inner-dialog");
6
42
  const runtime_1 = require("../nerves/runtime");
7
43
  const identity_1 = require("../heart/identity");
8
44
  const pending_1 = require("../mind/pending");
9
- function createInnerDialogWorker(runTurn = (options) => (0, inner_dialog_1.runInnerDialogTurn)(options), hasPendingWork = () => (0, pending_1.hasPendingMessages)((0, pending_1.getInnerDialogPendingDir)((0, identity_1.getAgentName)()))) {
45
+ const habit_parser_1 = require("../heart/habits/habit-parser");
46
+ const habit_runtime_state_1 = require("../heart/habits/habit-runtime-state");
47
+ const habit_session_1 = require("../heart/habits/habit-session");
48
+ const flight_recorder_1 = require("../arc/flight-recorder");
49
+ const habit_session_summary_1 = require("../heart/habits/habit-session-summary");
50
+ const friends_1 = require("@ouro.bot/friends");
51
+ const tools_base_1 = require("../repertoire/tools-base");
52
+ const tools_surface_1 = require("../repertoire/tools-surface");
53
+ const tools_1 = require("../repertoire/tools");
54
+ /**
55
+ * Cap on consecutive `instinct` follow-on turns triggered by `hasPendingWork()`
56
+ * with no externally-queued work in between. Without this cap, a turn that
57
+ * writes anything back into the inner-dialog pending dir as a side effect of
58
+ * processing (e.g. a surface tool routing a response) puts the worker into
59
+ * a self-sustaining loop where the next turn's drain produces another write,
60
+ * and so on. Real workflows rarely chain more than 2–3 instinct turns; an
61
+ * external trigger (habit, poke, chat) resets the counter so legitimate
62
+ * follow-on work is unaffected.
63
+ *
64
+ * Three feels right: legitimate cascading follow-ups (e.g. processing a
65
+ * batch of delegated returns) get through; a true self-loop caps fast.
66
+ */
67
+ exports.MAX_CONSECUTIVE_INSTINCT_TURNS = 3;
68
+ /**
69
+ * Habit recursion detector thresholds. The instinct cap above protects
70
+ * against pending-dir self-loops; this protects against the *external*
71
+ * IPC self-loop where heartbeat-shaped messages get re-issued faster
72
+ * than their cadence — e.g. a hook misconfigured to repost on every
73
+ * heartbeat, a daemon retry storm, or a stuck timer firing back-to-back.
74
+ *
75
+ * MIN_INTERVAL_MS — two of the same habit within this window is suspect
76
+ * regardless of cadence (no realistic habit fires every few seconds).
77
+ * BURST_THRESHOLD over BURST_WINDOW_MS catches slower runaways that stay
78
+ * just under MIN_INTERVAL_MS.
79
+ *
80
+ * Detection is observation-only: it emits warn-level nerves events, it
81
+ * does not drop the message. An operator (or follow-up auto-recovery)
82
+ * decides what to do with the signal.
83
+ */
84
+ exports.HABIT_RECURSION_MIN_INTERVAL_MS = 5_000;
85
+ exports.HABIT_RECURSION_BURST_WINDOW_MS = 60_000;
86
+ exports.HABIT_RECURSION_BURST_THRESHOLD = 5;
87
+ exports.HEARTBEAT_OK_REST_SUPPRESSION_MS = 20 * 60_000;
88
+ function isHeartbeatOkRestResult(result) {
89
+ if (!result || typeof result !== "object")
90
+ return false;
91
+ const maybeResult = result;
92
+ return maybeResult.turnOutcome === "rested" && maybeResult.restStatus === "HEARTBEAT_OK";
93
+ }
94
+ function isRecord(value) {
95
+ return !!value && typeof value === "object" && !Array.isArray(value);
96
+ }
97
+ function contentToText(content) {
98
+ if (typeof content === "string")
99
+ return content.trim();
100
+ if (!Array.isArray(content))
101
+ return "";
102
+ return content
103
+ .map((part) => isRecord(part) && typeof part.text === "string" ? part.text : "")
104
+ .filter((text) => text.trim().length > 0)
105
+ .join("\n")
106
+ .trim();
107
+ }
108
+ function resultMessages(result) {
109
+ if (Array.isArray(result))
110
+ return result.flatMap((entry) => resultMessages(entry));
111
+ return isRecord(result) && Array.isArray(result.messages) ? result.messages : [];
112
+ }
113
+ function latestAssistantText(results) {
114
+ for (let resultIndex = results.length - 1; resultIndex >= 0; resultIndex--) {
115
+ const messages = resultMessages(results[resultIndex]);
116
+ for (let messageIndex = messages.length - 1; messageIndex >= 0; messageIndex--) {
117
+ const message = messages[messageIndex];
118
+ if (!isRecord(message) || message.role !== "assistant")
119
+ continue;
120
+ const text = contentToText(message.content);
121
+ if (text.length > 0)
122
+ return text.replace(/^checkpoint\s*:\s*/i, "").trim() || text;
123
+ }
124
+ }
125
+ return null;
126
+ }
127
+ function deriveHabitSummarySnapshot(habitRun) {
128
+ const assistant = latestAssistantText(habitRun.results);
129
+ if (assistant)
130
+ return { summary: assistant, decisions: [], nextLikelyStep: null };
131
+ if (habitRun.errors.length > 0) {
132
+ return {
133
+ summary: `Habit ${habitRun.habit.name} finished with errors: ${habitRun.errors.join("; ")}`,
134
+ decisions: [],
135
+ nextLikelyStep: null,
136
+ };
137
+ }
138
+ const surfaced = habitRun.surfaceAttempts.find((attempt) => attempt.result !== "blocked" && attempt.result !== "failed" && attempt.result !== "unavailable");
139
+ if (surfaced) {
140
+ return {
141
+ summary: `Habit ${habitRun.habit.name} surfaced via ${surfaced.recipient}/${surfaced.channel}.`,
142
+ decisions: [],
143
+ nextLikelyStep: null,
144
+ };
145
+ }
146
+ const produced = habitRun.producedRefs.find((ref) => ref.kind !== "none");
147
+ if (produced) {
148
+ return {
149
+ summary: `Habit ${habitRun.habit.name} produced ${produced.kind}: ${produced.locator}.`,
150
+ decisions: [],
151
+ nextLikelyStep: null,
152
+ };
153
+ }
154
+ if (habitRun.results.some(isHeartbeatOkRestResult)) {
155
+ return {
156
+ summary: `Habit ${habitRun.habit.name} rested with HEARTBEAT_OK.`,
157
+ decisions: [],
158
+ nextLikelyStep: null,
159
+ };
160
+ }
161
+ return {
162
+ summary: `Habit ${habitRun.habit.name} completed without additional surfaced output.`,
163
+ decisions: [],
164
+ nextLikelyStep: null,
165
+ };
166
+ }
167
+ function fallbackHabitFile(habitName) {
168
+ return {
169
+ name: habitName,
170
+ title: habitName,
171
+ cadence: null,
172
+ status: "active",
173
+ lastRun: null,
174
+ created: null,
175
+ tools: [],
176
+ origin: null,
177
+ surface: { family: false, originator: false, extra: [] },
178
+ continuity: { mode: "fresh" },
179
+ body: "",
180
+ };
181
+ }
182
+ function readHabitForRun(agentRoot, habitName, errors) {
183
+ const habitPath = path.join(agentRoot, "habits", `${habitName}.md`);
184
+ try {
185
+ return (0, habit_parser_1.parseHabitFile)(fs.readFileSync(habitPath, "utf-8"), habitPath);
186
+ }
187
+ catch (error) {
188
+ const reason = error instanceof Error ? error.message : String(error);
189
+ errors.push(`habit file could not be read: ${reason}`);
190
+ (0, runtime_1.emitNervesEvent)({
191
+ level: "warn",
192
+ component: "senses",
193
+ event: "senses.habit_file_read_error",
194
+ message: "habit file could not be read for habit session",
195
+ meta: { habitName, habitPath, reason },
196
+ });
197
+ return fallbackHabitFile(habitName);
198
+ }
199
+ }
200
+ async function prepareHabitRun(habitName, trigger, startedAt) {
201
+ const agentRoot = (0, identity_1.getAgentRoot)();
202
+ const errors = [];
203
+ const habit = (0, habit_runtime_state_1.applyHabitRuntimeState)(agentRoot, readHabitForRun(agentRoot, habitName, errors));
204
+ const runId = (0, flight_recorder_1.createHabitRunId)(habitName, new Date(startedAt));
205
+ const operationId = habit.continuity.mode === "stateful" ? `habit:${habit.name}` : null;
206
+ const priorSessionSummary = readPriorSessionSummary(agentRoot, operationId);
207
+ const paths = (0, habit_session_1.createHabitSessionPaths)(agentRoot, runId, habit.name);
208
+ const friendStore = new friends_1.FileFriendStore(path.join(agentRoot, "friends"));
209
+ const permissionEnvelope = await (0, habit_session_1.normalizeHabitPermissionEnvelope)(habit, { agentRoot, friendStore });
210
+ const toolPolicy = (0, habit_session_1.filterHabitToolsForEnvelope)([...tools_base_1.baseToolDefinitions, tools_surface_1.surfaceToolDefinition], habit.tools ?? null, permissionEnvelope, riskProfileForHabitPolicy);
211
+ return {
212
+ agentRoot,
213
+ habit,
214
+ runId,
215
+ operationId,
216
+ trigger,
217
+ startedAt,
218
+ priorSessionSummary,
219
+ paths,
220
+ permissionEnvelope,
221
+ toolPolicy,
222
+ friendStore,
223
+ results: [],
224
+ errors,
225
+ producedRefs: [],
226
+ surfaceAttempts: [],
227
+ };
228
+ }
229
+ function riskProfileForHabitPolicy(definition, name) {
230
+ const probeArgs = name === "shell" ? { command: "touch /tmp/habit-policy-probe" } : {};
231
+ return (0, tools_1.riskProfileForTool)(definition, name, probeArgs);
232
+ }
233
+ function readPriorSessionSummary(agentRoot, operationId) {
234
+ if (operationId === null)
235
+ return undefined;
236
+ try {
237
+ const summary = (0, habit_session_summary_1.readHabitSessionSummary)(agentRoot, { operationId, which: "latest" });
238
+ if (!summary)
239
+ return { mode: "stateful", summary: null, sources: {}, warnings: [] };
240
+ return {
241
+ mode: "stateful",
242
+ summary: summary.summary,
243
+ sources: summary.sources,
244
+ warnings: summary.warnings,
245
+ };
246
+ }
247
+ catch (error) {
248
+ return {
249
+ mode: "stateful",
250
+ summary: null,
251
+ sources: {},
252
+ warnings: [`prior summary read failed: ${String(error)}`],
253
+ };
254
+ }
255
+ }
256
+ function createInnerDialogWorker(runTurn = (options) => (0, inner_dialog_1.runInnerDialogTurn)(options), hasPendingWork = (pendingDir) => (0, pending_1.hasPendingMessages)(pendingDir ?? (0, pending_1.getInnerDialogPendingDir)((0, identity_1.getAgentName)())), nowSource = () => Date.now()) {
10
257
  let running = false;
11
- let rerunRequested = false;
12
- let rerunReason = "instinct";
13
- let rerunTaskId;
14
- async function run(reason, taskId) {
15
- if (running) {
16
- rerunRequested = true;
17
- rerunReason = reason;
18
- if (taskId !== undefined) {
19
- rerunTaskId = taskId;
258
+ const queue = [];
259
+ const lastFireByHabit = new Map();
260
+ const recentHabitFires = [];
261
+ let heartbeatOkRestedAt = null;
262
+ function recordHabitCompletion(habitRun, endedAt = habitRun.startedAt) {
263
+ (0, habit_session_1.completeHabitRun)({
264
+ agentRoot: habitRun.agentRoot,
265
+ habit: habitRun.habit,
266
+ runId: habitRun.runId,
267
+ trigger: habitRun.trigger,
268
+ startedAt: habitRun.startedAt,
269
+ endedAt,
270
+ operationId: habitRun.operationId,
271
+ permissionEnvelope: habitRun.permissionEnvelope,
272
+ toolPolicy: habitRun.toolPolicy,
273
+ producedRefs: habitRun.producedRefs,
274
+ surfaceAttempts: habitRun.surfaceAttempts,
275
+ errors: habitRun.errors,
276
+ summarySnapshot: deriveHabitSummarySnapshot(habitRun),
277
+ });
278
+ }
279
+ function clearHeartbeatRestShield() {
280
+ heartbeatOkRestedAt = null;
281
+ }
282
+ function shouldReuseHeartbeatOkRest(habitName) {
283
+ if (habitName !== "heartbeat" || heartbeatOkRestedAt === null)
284
+ return false;
285
+ if (nowSource() - heartbeatOkRestedAt > exports.HEARTBEAT_OK_REST_SUPPRESSION_MS)
286
+ return false;
287
+ if (hasPendingWork()) {
288
+ clearHeartbeatRestShield();
289
+ return false;
290
+ }
291
+ return true;
292
+ }
293
+ async function reuseHeartbeatOkRest(habitName) {
294
+ const nowIso = new Date(nowSource()).toISOString();
295
+ const habitRun = await prepareHabitRun(habitName, "overdue", nowIso);
296
+ habitRun.results.push({ turnOutcome: "rested", restStatus: "HEARTBEAT_OK" });
297
+ recordHabitCompletion(habitRun, nowIso);
298
+ (0, runtime_1.emitNervesEvent)({
299
+ level: "info",
300
+ component: "senses",
301
+ event: "senses.heartbeat_ok_rest_reused",
302
+ message: "heartbeat skipped because previous HEARTBEAT_OK rest is still valid and no pending work exists",
303
+ meta: {
304
+ habitName,
305
+ quietWindowMs: exports.HEARTBEAT_OK_REST_SUPPRESSION_MS,
306
+ restedAgoMs: nowSource() - heartbeatOkRestedAt,
307
+ },
308
+ });
309
+ }
310
+ function recordHabitFireForRecursion(habitName) {
311
+ const now = nowSource();
312
+ const previous = lastFireByHabit.get(habitName);
313
+ if (previous !== undefined) {
314
+ const intervalMs = now - previous;
315
+ if (intervalMs < exports.HABIT_RECURSION_MIN_INTERVAL_MS) {
316
+ (0, runtime_1.emitNervesEvent)({
317
+ level: "warn",
318
+ component: "senses",
319
+ event: "senses.habit_recursion_suspected",
320
+ message: "habit fired suspiciously fast after the previous fire — possible self-recursion or duplicate dispatch",
321
+ meta: {
322
+ habitName,
323
+ intervalMs,
324
+ thresholdMs: exports.HABIT_RECURSION_MIN_INTERVAL_MS,
325
+ },
326
+ });
20
327
  }
328
+ }
329
+ lastFireByHabit.set(habitName, now);
330
+ recentHabitFires.push(now);
331
+ while (recentHabitFires.length > 0 && now - recentHabitFires[0] > exports.HABIT_RECURSION_BURST_WINDOW_MS) {
332
+ recentHabitFires.shift();
333
+ }
334
+ if (recentHabitFires.length >= exports.HABIT_RECURSION_BURST_THRESHOLD) {
335
+ (0, runtime_1.emitNervesEvent)({
336
+ level: "warn",
337
+ component: "senses",
338
+ event: "senses.habit_recursion_burst",
339
+ message: "habit messages arriving in a burst — possible runaway loop",
340
+ meta: {
341
+ count: recentHabitFires.length,
342
+ windowMs: exports.HABIT_RECURSION_BURST_WINDOW_MS,
343
+ thresholdCount: exports.HABIT_RECURSION_BURST_THRESHOLD,
344
+ lastHabitName: habitName,
345
+ },
346
+ });
347
+ }
348
+ }
349
+ async function run(reason, taskId, habitName, awaitName, trigger) {
350
+ if (running) {
351
+ queue.push({ reason, taskId, habitName, awaitName, trigger });
21
352
  return;
22
353
  }
23
354
  running = true;
24
355
  try {
25
356
  let nextReason = reason;
26
357
  let nextTaskId = taskId;
27
- do {
28
- rerunRequested = false;
358
+ let nextHabitName = habitName;
359
+ let nextAwaitName = awaitName;
360
+ let nextTrigger = trigger;
361
+ let nextHabitRun = null;
362
+ let consecutiveInstinctTurns = reason === "instinct" ? 1 : 0;
363
+ runLoop: do {
364
+ const currentReason = nextReason;
365
+ const currentHabitName = nextHabitName;
366
+ const currentTrigger = nextTrigger ?? "overdue";
367
+ const currentHabitRun = currentReason === "habit" && currentHabitName
368
+ ? nextHabitRun && nextHabitRun.habit.name === currentHabitName
369
+ ? nextHabitRun
370
+ : await prepareHabitRun(currentHabitName, currentTrigger, new Date(nowSource()).toISOString())
371
+ : null;
372
+ nextHabitRun = null;
373
+ let currentHabitRunFinalized = false;
374
+ const finalizeCurrentHabitRun = () => {
375
+ if (!currentHabitRun || currentHabitRunFinalized)
376
+ return;
377
+ recordHabitCompletion(currentHabitRun, new Date(nowSource()).toISOString());
378
+ currentHabitRunFinalized = true;
379
+ };
380
+ const turnErrors = [];
381
+ if (!(currentReason === "habit" && currentHabitName === "heartbeat")) {
382
+ clearHeartbeatRestShield();
383
+ }
384
+ let turnResult;
29
385
  try {
30
- await runTurn({ reason: nextReason, taskId: nextTaskId });
386
+ const turnOptions = {
387
+ reason: nextReason,
388
+ taskId: nextTaskId,
389
+ habitName: nextHabitName,
390
+ awaitName: nextAwaitName,
391
+ ...(currentHabitRun
392
+ ? {
393
+ trigger: currentHabitRun.trigger,
394
+ preparedHabit: {
395
+ runId: currentHabitRun.runId,
396
+ trigger: currentHabitRun.trigger,
397
+ operationId: currentHabitRun.operationId,
398
+ habit: currentHabitRun.habit,
399
+ priorSessionSummary: currentHabitRun.priorSessionSummary,
400
+ },
401
+ habitSession: {
402
+ runId: currentHabitRun.runId,
403
+ sessionPath: currentHabitRun.paths.sessionPath,
404
+ pendingDir: currentHabitRun.paths.pendingDir,
405
+ permissionEnvelope: currentHabitRun.permissionEnvelope,
406
+ toolPolicy: currentHabitRun.toolPolicy,
407
+ friendStore: currentHabitRun.friendStore,
408
+ recordProducedRef: (ref) => { currentHabitRun.producedRefs.push(ref); },
409
+ recordSurfaceAttempt: (attempt) => { currentHabitRun.surfaceAttempts.push(attempt); },
410
+ recordError: (error) => { currentHabitRun.errors.push(error); },
411
+ },
412
+ }
413
+ : {}),
414
+ };
415
+ turnResult = await runTurn(turnOptions);
31
416
  }
32
417
  catch (error) {
418
+ clearHeartbeatRestShield();
419
+ turnErrors.push(error instanceof Error ? error.message : String(error));
33
420
  (0, runtime_1.emitNervesEvent)({
34
421
  level: "error",
35
422
  component: "senses",
@@ -41,15 +428,78 @@ function createInnerDialogWorker(runTurn = (options) => (0, inner_dialog_1.runIn
41
428
  },
42
429
  });
43
430
  }
44
- if (!rerunRequested && hasPendingWork()) {
45
- rerunRequested = true;
46
- rerunReason = "instinct";
431
+ if (currentReason === "habit" && currentHabitName === "heartbeat") {
432
+ heartbeatOkRestedAt = isHeartbeatOkRestResult(turnResult) ? nowSource() : null;
433
+ }
434
+ if (currentHabitRun) {
435
+ currentHabitRun.results.push(turnResult);
436
+ currentHabitRun.errors.push(...turnErrors);
437
+ }
438
+ // Drain queue first. Externally-queued work resets the instinct cap
439
+ // because a real outside trigger arrived between turns.
440
+ while (queue.length > 0) {
441
+ const next = queue.shift();
442
+ if (next.reason === "habit" && next.habitName === "heartbeat" && shouldReuseHeartbeatOkRest(next.habitName)) {
443
+ finalizeCurrentHabitRun();
444
+ await reuseHeartbeatOkRest(next.habitName);
445
+ continue;
446
+ }
447
+ if (!(next.reason === "habit" && next.habitName === "heartbeat")) {
448
+ clearHeartbeatRestShield();
449
+ }
450
+ finalizeCurrentHabitRun();
451
+ nextReason = next.reason;
452
+ nextTaskId = next.taskId;
453
+ nextHabitName = next.habitName;
454
+ nextAwaitName = next.awaitName;
455
+ nextTrigger = next.trigger;
456
+ consecutiveInstinctTurns = nextReason === "instinct" ? consecutiveInstinctTurns + 1 : 0;
457
+ continue runLoop;
47
458
  }
48
- nextReason = rerunReason;
49
- nextTaskId = rerunTaskId;
50
- rerunReason = "instinct";
51
- rerunTaskId = undefined;
52
- } while (rerunRequested);
459
+ // Then check hasPendingWork fallback. This is the loop site: any
460
+ // tool that writes to the inner-dialog pending dir during a turn
461
+ // would cause hasPendingWork() to be true here, producing a
462
+ // self-sustaining "instinct" loop with no external input. Cap it.
463
+ if (hasPendingWork(currentHabitRun?.paths.pendingDir)) {
464
+ clearHeartbeatRestShield();
465
+ if (consecutiveInstinctTurns >= exports.MAX_CONSECUTIVE_INSTINCT_TURNS) {
466
+ (0, runtime_1.emitNervesEvent)({
467
+ level: "warn",
468
+ component: "senses",
469
+ event: "senses.inner_dialog_worker_instinct_loop_capped",
470
+ message: "inner dialog worker stopped chaining instinct turns; pending work remains for next external trigger",
471
+ meta: {
472
+ consecutiveInstinctTurns,
473
+ cap: exports.MAX_CONSECUTIVE_INSTINCT_TURNS,
474
+ lastReason: nextReason,
475
+ },
476
+ });
477
+ finalizeCurrentHabitRun();
478
+ break;
479
+ }
480
+ if (currentReason === "habit" && currentHabitName && currentHabitRun) {
481
+ consecutiveInstinctTurns += 1;
482
+ nextReason = "habit";
483
+ nextTaskId = undefined;
484
+ nextHabitName = currentHabitName;
485
+ nextAwaitName = undefined;
486
+ nextTrigger = currentTrigger;
487
+ nextHabitRun = currentHabitRun;
488
+ }
489
+ else {
490
+ finalizeCurrentHabitRun();
491
+ consecutiveInstinctTurns += 1;
492
+ nextReason = "instinct";
493
+ nextTaskId = undefined;
494
+ nextHabitName = undefined;
495
+ nextAwaitName = undefined;
496
+ nextTrigger = undefined;
497
+ }
498
+ continue;
499
+ }
500
+ finalizeCurrentHabitRun();
501
+ break;
502
+ } while (true);
53
503
  }
54
504
  finally {
55
505
  running = false;
@@ -59,16 +509,43 @@ function createInnerDialogWorker(runTurn = (options) => (0, inner_dialog_1.runIn
59
509
  if (!message || typeof message !== "object")
60
510
  return;
61
511
  const maybeMessage = message;
512
+ if (maybeMessage.type === "habit") {
513
+ /* v8 ignore next -- defensive fallback: live habit dispatch always sets habitName @preserve */
514
+ const habitName = maybeMessage.habitName ?? "(unnamed)";
515
+ if (shouldReuseHeartbeatOkRest(habitName)) {
516
+ await reuseHeartbeatOkRest(habitName);
517
+ return;
518
+ }
519
+ recordHabitFireForRecursion(habitName);
520
+ await run("habit", undefined, maybeMessage.habitName, undefined, maybeMessage.trigger ?? "overdue");
521
+ return;
522
+ }
523
+ if (maybeMessage.type === "await") {
524
+ clearHeartbeatRestShield();
525
+ /* v8 ignore next -- defensive fallback: live await dispatch always sets awaitName @preserve */
526
+ const awaitName = maybeMessage.awaitName ?? "(unnamed)";
527
+ recordHabitFireForRecursion(`await:${awaitName}`);
528
+ await run("await", undefined, undefined, maybeMessage.awaitName);
529
+ return;
530
+ }
62
531
  if (maybeMessage.type === "heartbeat") {
63
- await run("heartbeat");
532
+ // Backward compatibility: heartbeat -> habit/heartbeat
533
+ if (shouldReuseHeartbeatOkRest("heartbeat")) {
534
+ await reuseHeartbeatOkRest("heartbeat");
535
+ return;
536
+ }
537
+ recordHabitFireForRecursion("heartbeat");
538
+ await run("habit", undefined, "heartbeat", undefined, "overdue");
64
539
  return;
65
540
  }
66
541
  if (maybeMessage.type === "poke") {
542
+ clearHeartbeatRestShield();
67
543
  await run("instinct", maybeMessage.taskId);
68
544
  return;
69
545
  }
70
546
  if (maybeMessage.type === "chat" ||
71
547
  maybeMessage.type === "message") {
548
+ clearHeartbeatRestShield();
72
549
  await run("instinct");
73
550
  return;
74
551
  }