@ouro.bot/cli 0.1.0-alpha.62 → 0.1.0-alpha.636

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 (430) 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 +4070 -13
  13. package/dist/arc/attention-types.js +8 -0
  14. package/dist/arc/cares.js +144 -0
  15. package/dist/arc/episodes.js +118 -0
  16. package/dist/arc/intentions.js +134 -0
  17. package/dist/arc/json-store.js +117 -0
  18. package/dist/arc/obligations.js +266 -0
  19. package/dist/arc/packets.js +194 -0
  20. package/dist/arc/presence.js +185 -0
  21. package/dist/arc/task-lifecycle.js +57 -0
  22. package/dist/heart/active-work.js +831 -43
  23. package/dist/heart/agent-entry.js +69 -3
  24. package/dist/heart/attachments/image-normalize.js +194 -0
  25. package/dist/heart/attachments/materialize.js +97 -0
  26. package/dist/heart/attachments/originals.js +88 -0
  27. package/dist/heart/attachments/render.js +29 -0
  28. package/dist/heart/attachments/sources/bluebubbles.js +156 -0
  29. package/dist/heart/attachments/sources/cli-local-file.js +78 -0
  30. package/dist/heart/attachments/sources/index.js +16 -0
  31. package/dist/heart/attachments/store.js +103 -0
  32. package/dist/heart/attachments/types.js +93 -0
  33. package/dist/heart/auth/auth-flow.js +479 -0
  34. package/dist/heart/awaiting/await-alert.js +146 -0
  35. package/dist/heart/awaiting/await-expiry.js +108 -0
  36. package/dist/heart/awaiting/await-loader.js +91 -0
  37. package/dist/heart/awaiting/await-parser.js +141 -0
  38. package/dist/heart/awaiting/await-runtime-state.js +100 -0
  39. package/dist/heart/awaiting/await-scheduler.js +377 -0
  40. package/dist/heart/background-operations.js +281 -0
  41. package/dist/heart/bridges/manager.js +137 -17
  42. package/dist/heart/bridges/store.js +14 -2
  43. package/dist/heart/bundle-state.js +168 -0
  44. package/dist/heart/commitments.js +135 -0
  45. package/dist/heart/config-registry.js +322 -0
  46. package/dist/heart/config.js +114 -119
  47. package/dist/heart/core.js +914 -248
  48. package/dist/heart/cross-chat-delivery.js +3 -18
  49. package/dist/heart/daemon/agent-config-check.js +419 -0
  50. package/dist/heart/daemon/agent-discovery.js +102 -3
  51. package/dist/heart/daemon/agent-service.js +522 -0
  52. package/dist/heart/daemon/agentic-repair.js +547 -0
  53. package/dist/heart/daemon/bluebubbles-health-diagnostics.js +122 -0
  54. package/dist/heart/daemon/boot-sync-probe.js +197 -0
  55. package/dist/heart/daemon/cadence.js +70 -0
  56. package/dist/heart/daemon/cli-defaults.js +776 -0
  57. package/dist/heart/daemon/cli-desk.js +322 -0
  58. package/dist/heart/daemon/cli-exec.js +7468 -0
  59. package/dist/heart/daemon/cli-help.js +505 -0
  60. package/dist/heart/daemon/cli-parse.js +1554 -0
  61. package/dist/heart/daemon/cli-render-doctor.js +57 -0
  62. package/dist/heart/daemon/cli-render.js +763 -0
  63. package/dist/heart/daemon/cli-types.js +8 -0
  64. package/dist/heart/daemon/connect-bay.js +323 -0
  65. package/dist/heart/daemon/daemon-cli.js +29 -1700
  66. package/dist/heart/daemon/daemon-entry.js +485 -2
  67. package/dist/heart/daemon/daemon-health.js +176 -0
  68. package/dist/heart/daemon/daemon-rollup.js +57 -0
  69. package/dist/heart/daemon/daemon-runtime-sync.js +88 -13
  70. package/dist/heart/daemon/daemon-tombstone.js +236 -0
  71. package/dist/heart/daemon/daemon.js +905 -71
  72. package/dist/heart/daemon/dns-workflow.js +394 -0
  73. package/dist/heart/daemon/doctor-types.js +8 -0
  74. package/dist/heart/daemon/doctor.js +873 -0
  75. package/dist/heart/daemon/health-monitor.js +122 -1
  76. package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
  77. package/dist/heart/daemon/hooks/bundle-meta.js +115 -1
  78. package/dist/heart/daemon/http-health-probe.js +80 -0
  79. package/dist/heart/daemon/human-command-screens.js +234 -0
  80. package/dist/heart/daemon/human-readiness.js +114 -0
  81. package/dist/heart/daemon/inner-status.js +89 -0
  82. package/dist/heart/daemon/interactive-repair.js +394 -0
  83. package/dist/heart/daemon/launchd.js +37 -8
  84. package/dist/heart/daemon/log-tailer.js +79 -10
  85. package/dist/heart/daemon/logs-prune.js +110 -0
  86. package/dist/heart/daemon/mcp-canary.js +297 -0
  87. package/dist/heart/daemon/migrate-to-desk.js +848 -0
  88. package/dist/heart/daemon/os-cron-deps.js +135 -0
  89. package/dist/heart/daemon/os-cron.js +14 -12
  90. package/dist/heart/daemon/ouro-bot-entry.js +4 -2
  91. package/dist/heart/daemon/ouro-entry.js +3 -1
  92. package/dist/heart/daemon/plugin-cli.js +432 -0
  93. package/dist/heart/daemon/process-manager.js +463 -34
  94. package/dist/heart/daemon/provider-discovery.js +137 -0
  95. package/dist/heart/daemon/provider-ping-progress.js +83 -0
  96. package/dist/heart/daemon/pulse.js +475 -0
  97. package/dist/heart/daemon/readiness-repair.js +365 -0
  98. package/dist/heart/daemon/run-hooks.js +2 -0
  99. package/dist/heart/daemon/runtime-logging.js +11 -3
  100. package/dist/heart/daemon/runtime-metadata.js +2 -30
  101. package/dist/heart/daemon/safe-mode.js +161 -0
  102. package/dist/heart/daemon/sense-manager.js +493 -38
  103. package/dist/heart/daemon/session-id-resolver.js +131 -0
  104. package/dist/heart/daemon/skill-management-installer.js +22 -9
  105. package/dist/heart/daemon/socket-client.js +158 -11
  106. package/dist/heart/daemon/stale-bundle-prune.js +96 -0
  107. package/dist/heart/daemon/startup-tui.js +330 -0
  108. package/dist/heart/daemon/task-scheduler.js +117 -39
  109. package/dist/heart/daemon/terminal-ui.js +499 -0
  110. package/dist/heart/daemon/thoughts.js +229 -17
  111. package/dist/heart/daemon/up-progress.js +366 -0
  112. package/dist/heart/daemon/vault-items.js +56 -0
  113. package/dist/heart/delegation.js +1 -4
  114. package/dist/heart/habits/habit-migration.js +189 -0
  115. package/dist/heart/habits/habit-parser.js +140 -0
  116. package/dist/heart/habits/habit-runtime-state.js +100 -0
  117. package/dist/heart/habits/habit-scheduler.js +372 -0
  118. package/dist/heart/{daemon → hatch}/hatch-flow.js +32 -56
  119. package/dist/heart/{daemon → hatch}/hatch-specialist.js +6 -8
  120. package/dist/heart/{daemon → hatch}/specialist-prompt.js +12 -9
  121. package/dist/heart/{daemon → hatch}/specialist-tools.js +37 -14
  122. package/dist/heart/identity.js +168 -57
  123. package/dist/heart/kept-notes.js +357 -0
  124. package/dist/heart/kicks.js +1 -1
  125. package/dist/heart/machine-identity.js +161 -0
  126. package/dist/heart/mail-import-discovery.js +353 -0
  127. package/dist/heart/mailbox/mailbox-http-hooks.js +66 -0
  128. package/dist/heart/mailbox/mailbox-http-response.js +7 -0
  129. package/dist/heart/mailbox/mailbox-http-routes.js +246 -0
  130. package/dist/heart/mailbox/mailbox-http-static.js +103 -0
  131. package/dist/heart/mailbox/mailbox-http-transport.js +116 -0
  132. package/dist/heart/mailbox/mailbox-http.js +99 -0
  133. package/dist/heart/mailbox/mailbox-read.js +31 -0
  134. package/dist/heart/mailbox/mailbox-types.js +27 -0
  135. package/dist/heart/mailbox/mailbox-view.js +197 -0
  136. package/dist/heart/mailbox/readers/agent-machine.js +418 -0
  137. package/dist/heart/mailbox/readers/continuity-readers.js +319 -0
  138. package/dist/heart/mailbox/readers/mail.js +375 -0
  139. package/dist/heart/mailbox/readers/runtime-readers.js +756 -0
  140. package/dist/heart/mailbox/readers/sessions.js +232 -0
  141. package/dist/heart/mailbox/readers/shared.js +111 -0
  142. package/dist/heart/mcp/mcp-server.js +656 -0
  143. package/dist/heart/migrate-config.js +100 -0
  144. package/dist/heart/model-capabilities.js +19 -0
  145. package/dist/heart/orientation-frame.js +217 -0
  146. package/dist/heart/platform.js +81 -0
  147. package/dist/heart/provider-attempt.js +134 -0
  148. package/dist/heart/provider-binding-resolver.js +272 -0
  149. package/dist/heart/provider-credentials.js +425 -0
  150. package/dist/heart/provider-failover.js +301 -0
  151. package/dist/heart/provider-models.js +81 -0
  152. package/dist/heart/provider-ping.js +262 -0
  153. package/dist/heart/provider-readiness-cache.js +40 -0
  154. package/dist/heart/provider-visibility.js +188 -0
  155. package/dist/heart/providers/anthropic-token.js +131 -0
  156. package/dist/heart/providers/anthropic.js +139 -52
  157. package/dist/heart/providers/azure.js +23 -11
  158. package/dist/heart/providers/error-classification.js +127 -0
  159. package/dist/heart/providers/github-copilot.js +145 -0
  160. package/dist/heart/providers/minimax-vlm.js +189 -0
  161. package/dist/heart/providers/minimax.js +26 -8
  162. package/dist/heart/providers/openai-codex.js +55 -40
  163. package/dist/heart/runtime-capability-check.js +170 -0
  164. package/dist/heart/runtime-credentials.js +367 -0
  165. package/dist/heart/runtime-cwd.js +87 -0
  166. package/dist/heart/sense-truth.js +13 -4
  167. package/dist/heart/session-activity.js +48 -24
  168. package/dist/heart/session-events.js +1163 -0
  169. package/dist/heart/session-playback-cli-main.js +5 -0
  170. package/dist/heart/session-playback-cli.js +36 -0
  171. package/dist/heart/session-playback.js +231 -0
  172. package/dist/heart/session-stats-cli-main.js +5 -0
  173. package/dist/heart/session-stats.js +182 -0
  174. package/dist/heart/session-transcript.js +133 -0
  175. package/dist/heart/start-of-turn-packet.js +345 -0
  176. package/dist/heart/streaming.js +44 -27
  177. package/dist/heart/structured-output.js +196 -0
  178. package/dist/heart/sync-classification.js +176 -0
  179. package/dist/heart/sync.js +449 -0
  180. package/dist/heart/target-resolution.js +9 -5
  181. package/dist/heart/tempo.js +93 -0
  182. package/dist/heart/temporal-view.js +41 -0
  183. package/dist/heart/timeouts.js +101 -0
  184. package/dist/heart/tool-activity-callbacks.js +59 -0
  185. package/dist/heart/tool-description.js +143 -0
  186. package/dist/heart/tool-friction.js +55 -0
  187. package/dist/heart/tool-loop.js +200 -0
  188. package/dist/heart/turn-context.js +389 -0
  189. package/dist/heart/{daemon → versioning}/ouro-bot-global-installer.js +6 -5
  190. package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
  191. package/dist/heart/versioning/ouro-path-installer.js +426 -0
  192. package/dist/heart/versioning/ouro-version-manager.js +295 -0
  193. package/dist/heart/{daemon → versioning}/staged-restart.js +40 -8
  194. package/dist/heart/{daemon → versioning}/update-checker.js +6 -1
  195. package/dist/heart/{daemon → versioning}/update-hooks.js +63 -59
  196. package/dist/mailbox-ui/assets/index-9-AxCxuB.js +61 -0
  197. package/dist/mailbox-ui/assets/index-CWzt267f.css +1 -0
  198. package/dist/mailbox-ui/index.html +15 -0
  199. package/dist/mailroom/attention.js +167 -0
  200. package/dist/mailroom/autonomy.js +209 -0
  201. package/dist/mailroom/blob-store.js +715 -0
  202. package/dist/mailroom/body-cache.js +61 -0
  203. package/dist/mailroom/core.js +788 -0
  204. package/dist/mailroom/entry.js +160 -0
  205. package/dist/mailroom/file-store.js +568 -0
  206. package/dist/mailroom/mbox-import.js +393 -0
  207. package/dist/mailroom/migration.js +164 -0
  208. package/dist/mailroom/outbound.js +380 -0
  209. package/dist/mailroom/policy.js +263 -0
  210. package/dist/mailroom/reader.js +233 -0
  211. package/dist/mailroom/search-cache.js +334 -0
  212. package/dist/mailroom/search-relevance.js +319 -0
  213. package/dist/mailroom/smtp-ingress.js +176 -0
  214. package/dist/mailroom/source-state.js +176 -0
  215. package/dist/mailroom/thread.js +109 -0
  216. package/dist/mailroom/travel-extract.js +89 -0
  217. package/dist/mind/bundle-manifest.js +14 -1
  218. package/dist/mind/context.js +251 -101
  219. package/dist/mind/desk-section.js +310 -0
  220. package/dist/mind/diary-integrity.js +60 -0
  221. package/dist/mind/{memory.js → diary.js} +68 -76
  222. package/dist/mind/embedding-provider.js +60 -0
  223. package/dist/mind/file-state.js +179 -0
  224. package/dist/mind/friends/channel.js +39 -0
  225. package/dist/mind/friends/resolver.js +54 -2
  226. package/dist/mind/friends/store-file.js +48 -4
  227. package/dist/mind/friends/types.js +2 -2
  228. package/dist/mind/journal-index.js +162 -0
  229. package/dist/mind/note-search.js +268 -0
  230. package/dist/mind/obligation-steering.js +221 -0
  231. package/dist/mind/pending.js +6 -1
  232. package/dist/mind/prompt-refresh.js +3 -2
  233. package/dist/mind/prompt.js +1058 -146
  234. package/dist/mind/provenance-trust.js +26 -0
  235. package/dist/mind/scrutiny.js +173 -0
  236. package/dist/nerves/cli-logging.js +7 -1
  237. package/dist/nerves/coverage/audit-rules.js +15 -6
  238. package/dist/nerves/coverage/audit.js +28 -2
  239. package/dist/nerves/coverage/cli.js +1 -1
  240. package/dist/nerves/coverage/contract.js +5 -5
  241. package/dist/nerves/coverage/file-completeness.js +139 -5
  242. package/dist/nerves/event-buffer.js +111 -0
  243. package/dist/nerves/index.js +224 -4
  244. package/dist/nerves/observation.js +20 -0
  245. package/dist/nerves/redact.js +79 -0
  246. package/dist/nerves/review/cli-main.js +5 -0
  247. package/dist/nerves/review/cli.js +156 -0
  248. package/dist/nerves/review/core.js +152 -0
  249. package/dist/nerves/runtime.js +5 -1
  250. package/dist/repertoire/ado-client.js +15 -56
  251. package/dist/repertoire/ado-semantic.js +16 -10
  252. package/dist/repertoire/api-client.js +97 -0
  253. package/dist/repertoire/bitwarden-store.js +997 -0
  254. package/dist/repertoire/bundle-templates.js +72 -0
  255. package/dist/repertoire/bw-installer.js +180 -0
  256. package/dist/repertoire/coding/codex-jsonl.js +64 -0
  257. package/dist/repertoire/coding/context-pack.js +331 -0
  258. package/dist/repertoire/coding/feedback.js +197 -30
  259. package/dist/repertoire/coding/manager.js +163 -10
  260. package/dist/repertoire/coding/spawner.js +55 -9
  261. package/dist/repertoire/coding/tools.js +177 -7
  262. package/dist/repertoire/commerce-errors.js +109 -0
  263. package/dist/repertoire/commerce-self-test.js +156 -0
  264. package/dist/repertoire/credential-access.js +178 -0
  265. package/dist/repertoire/desk/classifier.js +362 -0
  266. package/dist/repertoire/duffel-client.js +185 -0
  267. package/dist/repertoire/github-client.js +14 -55
  268. package/dist/repertoire/graph-client.js +11 -52
  269. package/dist/repertoire/guardrails.js +385 -0
  270. package/dist/repertoire/mcp-client.js +295 -0
  271. package/dist/repertoire/mcp-manager.js +403 -0
  272. package/dist/repertoire/mcp-tools.js +83 -0
  273. package/dist/repertoire/plugin-mcp.js +175 -0
  274. package/dist/repertoire/plugins.js +253 -0
  275. package/dist/repertoire/shell-sessions.js +133 -0
  276. package/dist/repertoire/skills.js +48 -4
  277. package/dist/repertoire/stripe-client.js +131 -0
  278. package/dist/repertoire/tool-results.js +29 -0
  279. package/dist/repertoire/tools-attachments.js +317 -0
  280. package/dist/repertoire/tools-awaiting.js +372 -0
  281. package/dist/repertoire/tools-base.js +57 -1082
  282. package/dist/repertoire/tools-bluebubbles.js +2 -0
  283. package/dist/repertoire/tools-bridge.js +144 -0
  284. package/dist/repertoire/tools-bundle.js +993 -0
  285. package/dist/repertoire/tools-config.js +186 -0
  286. package/dist/repertoire/tools-continuity.js +252 -0
  287. package/dist/repertoire/tools-credential.js +383 -0
  288. package/dist/repertoire/tools-files.js +344 -0
  289. package/dist/repertoire/tools-flight.js +227 -0
  290. package/dist/repertoire/tools-flow.js +119 -0
  291. package/dist/repertoire/tools-github.js +3 -8
  292. package/dist/repertoire/tools-mail.js +1975 -0
  293. package/dist/repertoire/tools-notes.js +438 -0
  294. package/dist/repertoire/tools-obligations.js +143 -0
  295. package/dist/repertoire/tools-orientation.js +31 -0
  296. package/dist/repertoire/tools-record.js +464 -0
  297. package/dist/repertoire/tools-runtime.js +150 -0
  298. package/dist/repertoire/tools-session.js +756 -0
  299. package/dist/repertoire/tools-shell.js +120 -0
  300. package/dist/repertoire/tools-stripe.js +182 -0
  301. package/dist/repertoire/tools-surface.js +316 -0
  302. package/dist/repertoire/tools-teams.js +12 -39
  303. package/dist/repertoire/tools-travel.js +125 -0
  304. package/dist/repertoire/tools-trip.js +982 -0
  305. package/dist/repertoire/tools-user-profile.js +146 -0
  306. package/dist/repertoire/tools-vault.js +40 -0
  307. package/dist/repertoire/tools-voice.js +145 -0
  308. package/dist/repertoire/tools.js +215 -103
  309. package/dist/repertoire/travel-api-client.js +360 -0
  310. package/dist/repertoire/user-profile.js +131 -0
  311. package/dist/repertoire/vault-setup.js +246 -0
  312. package/dist/repertoire/vault-unlock.js +594 -0
  313. package/dist/scripts/claude-code-hook.js +41 -0
  314. package/dist/scripts/claude-code-stop-hook.js +47 -0
  315. package/dist/senses/attention-queue.js +116 -0
  316. package/dist/senses/await-turn-message.js +58 -0
  317. package/dist/senses/bluebubbles/active-turns.js +216 -0
  318. package/dist/senses/bluebubbles/attachment-cache.js +53 -0
  319. package/dist/senses/bluebubbles/attachment-download.js +137 -0
  320. package/dist/senses/{bluebubbles-client.js → bluebubbles/client.js} +219 -18
  321. package/dist/senses/bluebubbles/entry.js +77 -0
  322. package/dist/senses/{bluebubbles-inbound-log.js → bluebubbles/inbound-log.js} +20 -3
  323. package/dist/senses/bluebubbles/index.js +2599 -0
  324. package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +121 -71
  325. package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +33 -12
  326. package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +3 -3
  327. package/dist/senses/bluebubbles/processed-log.js +133 -0
  328. package/dist/senses/bluebubbles/replay.js +137 -0
  329. package/dist/senses/{bluebubbles-runtime-state.js → bluebubbles/runtime-state.js} +30 -2
  330. package/dist/senses/{bluebubbles-session-cleanup.js → bluebubbles/session-cleanup.js} +1 -1
  331. package/dist/senses/bluebubbles-meta-guard.js +40 -0
  332. package/dist/senses/cli/bracketed-paste.js +82 -0
  333. package/dist/senses/cli/image-paste.js +287 -0
  334. package/dist/senses/cli/image-ref-navigation.js +75 -0
  335. package/dist/senses/cli/ink-app.js +156 -0
  336. package/dist/senses/cli/inline-diff.js +64 -0
  337. package/dist/senses/cli/input-keys.js +174 -0
  338. package/dist/senses/cli/kill-ring.js +86 -0
  339. package/dist/senses/cli/message-list.js +51 -0
  340. package/dist/senses/cli/ouro-tui.js +607 -0
  341. package/dist/senses/cli/spinner-imperative.js +135 -0
  342. package/dist/senses/cli/spinner.js +101 -0
  343. package/dist/senses/cli/status-line.js +60 -0
  344. package/dist/senses/cli/streaming-markdown.js +526 -0
  345. package/dist/senses/cli/tool-display.js +85 -0
  346. package/dist/senses/cli/tool-render.js +85 -0
  347. package/dist/senses/cli/tui-store.js +240 -0
  348. package/dist/senses/cli/virtual-list.js +35 -0
  349. package/dist/senses/cli-entry.js +60 -8
  350. package/dist/senses/cli-layout.js +100 -0
  351. package/dist/senses/cli.js +517 -204
  352. package/dist/senses/commands.js +66 -3
  353. package/dist/senses/habit-turn-message.js +108 -0
  354. package/dist/senses/inner-dialog-worker.js +254 -22
  355. package/dist/senses/inner-dialog.js +488 -39
  356. package/dist/senses/mail-entry.js +66 -0
  357. package/dist/senses/mail.js +379 -0
  358. package/dist/senses/pipeline.js +666 -181
  359. package/dist/senses/proactive-content-guard.js +51 -0
  360. package/dist/senses/shared-turn.js +393 -0
  361. package/dist/senses/surface-tool.js +70 -0
  362. package/dist/senses/teams-entry.js +60 -8
  363. package/dist/senses/teams.js +388 -98
  364. package/dist/senses/trust-gate.js +100 -5
  365. package/dist/senses/voice/audio-playback.js +237 -0
  366. package/dist/senses/voice/audio-routing.js +119 -0
  367. package/dist/senses/voice/elevenlabs.js +202 -0
  368. package/dist/senses/voice/floor-control.js +431 -0
  369. package/dist/senses/voice/floor-controller.js +115 -0
  370. package/dist/senses/voice/golden-path.js +116 -0
  371. package/dist/senses/voice/index.js +29 -0
  372. package/dist/senses/voice/meeting.js +113 -0
  373. package/dist/senses/voice/outbound.js +190 -0
  374. package/dist/senses/voice/phone.js +33 -0
  375. package/dist/senses/voice/playback.js +139 -0
  376. package/dist/senses/voice/realtime-eval.js +496 -0
  377. package/dist/senses/voice/realtime-trace.js +531 -0
  378. package/dist/senses/voice/transcript.js +70 -0
  379. package/dist/senses/voice/turn.js +191 -0
  380. package/dist/senses/voice/twilio-phone-runtime.js +807 -0
  381. package/dist/senses/voice/twilio-phone.js +5079 -0
  382. package/dist/senses/voice/types.js +2 -0
  383. package/dist/senses/voice/whisper.js +161 -0
  384. package/dist/senses/voice-entry.js +81 -0
  385. package/dist/senses/voice-realtime-eval-command.js +99 -0
  386. package/dist/senses/voice-realtime-eval-entry.js +21 -0
  387. package/dist/senses/voice-twilio-entry.js +87 -0
  388. package/dist/trips/core.js +138 -0
  389. package/dist/trips/store.js +265 -0
  390. package/dist/util/frontmatter.js +53 -0
  391. package/package.json +42 -8
  392. package/skills/agent-commerce.md +106 -0
  393. package/skills/browser-navigation.md +117 -0
  394. package/skills/commerce-setup-guide.md +116 -0
  395. package/skills/commerce-setup.md +84 -0
  396. package/skills/configure-dev-tools.md +99 -0
  397. package/skills/travel-planning.md +138 -0
  398. package/dist/heart/daemon/auth-flow.js +0 -351
  399. package/dist/heart/daemon/ouro-path-installer.js +0 -178
  400. package/dist/heart/safe-workspace.js +0 -228
  401. package/dist/heart/session-recall.js +0 -116
  402. package/dist/mind/associative-recall.js +0 -209
  403. package/dist/repertoire/tasks/board.js +0 -134
  404. package/dist/repertoire/tasks/index.js +0 -224
  405. package/dist/repertoire/tasks/lifecycle.js +0 -80
  406. package/dist/repertoire/tasks/middleware.js +0 -65
  407. package/dist/repertoire/tasks/parser.js +0 -173
  408. package/dist/repertoire/tasks/scanner.js +0 -132
  409. package/dist/repertoire/tasks/transitions.js +0 -144
  410. package/dist/senses/bluebubbles-entry.js +0 -13
  411. package/dist/senses/bluebubbles.js +0 -1177
  412. package/dist/senses/debug-activity.js +0 -148
  413. package/subagents/README.md +0 -7
  414. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
  415. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
  416. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
  417. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
  418. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
  419. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +0 -0
  420. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
  421. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
  422. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
  423. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
  424. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
  425. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
  426. /package/dist/{repertoire/tasks/types.js → heart/attachments/sources/adapter.js} +0 -0
  427. /package/dist/heart/{daemon → hatch}/hatch-animation.js +0 -0
  428. /package/dist/heart/{daemon → hatch}/specialist-orchestrator.js +0 -0
  429. /package/dist/heart/{daemon → versioning}/ouro-uti.js +0 -0
  430. /package/dist/heart/{daemon → versioning}/wrapper-publish-guard.js +0 -0
@@ -1,11 +1,19 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.formatOtherActiveSessionSummaries = formatOtherActiveSessionSummaries;
3
4
  exports.suggestBridgeForActiveWork = suggestBridgeForActiveWork;
4
5
  exports.buildActiveWorkFrame = buildActiveWorkFrame;
5
6
  exports.formatActiveWorkFrame = formatActiveWorkFrame;
7
+ exports.formatLiveWorldStateCheckpoint = formatLiveWorldStateCheckpoint;
8
+ exports.snapshotActiveWork = snapshotActiveWork;
9
+ exports.detectActiveWorkChanges = detectActiveWorkChanges;
10
+ exports.formatActiveWorkChanges = formatActiveWorkChanges;
6
11
  const runtime_1 = require("../nerves/runtime");
7
12
  const state_machine_1 = require("./bridges/state-machine");
13
+ const obligations_1 = require("../arc/obligations");
8
14
  const target_resolution_1 = require("./target-resolution");
15
+ const config_1 = require("./config");
16
+ const RECENT_ACTIVE_OBLIGATION_WINDOW_MS = 60 * 60 * 1000;
9
17
  function activityPriority(source) {
10
18
  return source === "friend-facing" ? 0 : 1;
11
19
  }
@@ -15,21 +23,487 @@ function compareActivity(a, b) {
15
23
  return sourceDiff;
16
24
  return b.lastActivityMs - a.lastActivityMs;
17
25
  }
18
- function summarizeLiveTasks(taskBoard) {
19
- const live = [
20
- ...taskBoard.byStatus.processing,
21
- ...taskBoard.byStatus.validating,
22
- ...taskBoard.byStatus.collaborating,
23
- ];
24
- return [...new Set(live)];
25
- }
26
26
  function isActiveBridge(bridge) {
27
27
  return bridge.lifecycle === "active";
28
28
  }
29
29
  function hasSharedObligationPressure(input) {
30
- return (typeof input.currentObligation === "string"
31
- && input.currentObligation.trim().length > 0) || input.mustResolveBeforeHandoff
32
- || summarizeLiveTasks(input.taskBoard).length > 0;
30
+ return input.mustResolveBeforeHandoff
31
+ || activeObligationCount(input.pendingObligations) > 0;
32
+ }
33
+ function formatCodingLaneLabel(session) {
34
+ return `${session.runner} ${session.id}`;
35
+ }
36
+ function compactCodingCheckpoint(session) {
37
+ const checkpoint = session.checkpoint?.replace(/\s+/g, " ").trim();
38
+ if (!checkpoint)
39
+ return "";
40
+ return checkpoint.length <= 80 ? checkpoint : `${checkpoint.slice(0, 77)}...`;
41
+ }
42
+ function describeCodingSessionScope(session, currentSession) {
43
+ if (!session.originSession)
44
+ return "";
45
+ if (currentSession
46
+ && session.originSession.friendId === currentSession.friendId
47
+ && session.originSession.channel === currentSession.channel
48
+ && session.originSession.key === currentSession.key) {
49
+ return " for this thread";
50
+ }
51
+ return ` for ${session.originSession.channel}/${session.originSession.key}`;
52
+ }
53
+ function activeObligationCount(obligations) {
54
+ return (obligations ?? []).filter((ob) => (0, obligations_1.isOpenObligationStatus)(ob.status)).length;
55
+ }
56
+ function obligationOriginKey(obligation) {
57
+ return `${obligation.origin.friendId}/${obligation.origin.channel}/${(0, config_1.sanitizeKey)(obligation.origin.key)}`;
58
+ }
59
+ function buildLiveCodingLabelSet(codingSessions, otherCodingSessions) {
60
+ return new Set([
61
+ ...codingSessions.map(formatCodingLaneLabel),
62
+ ...otherCodingSessions.map(formatCodingLaneLabel),
63
+ ]);
64
+ }
65
+ function isMaterialActiveObligation(obligation, liveCodingLabels, nowMs) {
66
+ if (obligation.currentArtifact?.trim())
67
+ return true;
68
+ if (obligation.status === "waiting_for_merge" || obligation.status === "updating_runtime")
69
+ return true;
70
+ const surface = obligation.currentSurface;
71
+ if (surface?.kind === "merge" || surface?.kind === "runtime")
72
+ return true;
73
+ const recentlyTouched = (nowMs - obligationTimestampMs(obligation)) <= RECENT_ACTIVE_OBLIGATION_WINDOW_MS;
74
+ if (surface?.kind === "coding") {
75
+ const liveLabel = surface.label.trim();
76
+ return (liveLabel.length > 0 && liveCodingLabels.has(liveLabel)) || recentlyTouched;
77
+ }
78
+ return recentlyTouched;
79
+ }
80
+ function normalizePendingObligations(obligations, codingSessions, otherCodingSessions) {
81
+ const openObligations = (obligations ?? []).filter((obligation) => (0, obligations_1.isOpenObligationStatus)(obligation.status));
82
+ if (openObligations.length === 0)
83
+ return [];
84
+ const liveCodingLabels = buildLiveCodingLabelSet(codingSessions, otherCodingSessions);
85
+ const nowMs = Date.now();
86
+ const normalized = [];
87
+ const seenOrigins = new Set();
88
+ for (const obligation of [...openObligations].sort(newestObligationFirst)) {
89
+ if (!isMaterialActiveObligation(obligation, liveCodingLabels, nowMs))
90
+ continue;
91
+ const originKey = obligationOriginKey(obligation);
92
+ if (seenOrigins.has(originKey))
93
+ continue;
94
+ seenOrigins.add(originKey);
95
+ normalized.push(obligation);
96
+ }
97
+ return normalized;
98
+ }
99
+ function formatObligationSurface(obligation) {
100
+ if (!obligation.currentSurface?.label)
101
+ return "";
102
+ switch (obligation.status) {
103
+ case "investigating":
104
+ return ` (working in ${obligation.currentSurface.label})`;
105
+ case "waiting_for_merge":
106
+ return ` (waiting at ${obligation.currentSurface.label})`;
107
+ case "updating_runtime":
108
+ return ` (updating via ${obligation.currentSurface.label})`;
109
+ default:
110
+ return ` (${obligation.currentSurface.label})`;
111
+ }
112
+ }
113
+ function mergeArtifactFallback(obligation) {
114
+ const trimmed = obligation.content.trim();
115
+ if (!trimmed)
116
+ return "the fix";
117
+ const stripped = trimmed.replace(/^merge(?:\s+|$)/i, "").trim();
118
+ return stripped || "the fix";
119
+ }
120
+ function formatMergeArtifact(obligation) {
121
+ const currentArtifact = obligation.currentArtifact?.trim();
122
+ if (currentArtifact)
123
+ return currentArtifact;
124
+ if (obligation.currentSurface?.kind === "merge") {
125
+ const surfaceLabel = obligation.currentSurface.label.trim();
126
+ if (surfaceLabel)
127
+ return surfaceLabel;
128
+ }
129
+ return mergeArtifactFallback(obligation);
130
+ }
131
+ /* v8 ignore start -- Epic 1: obligation selection, resume handles, change detection @preserve */
132
+ function obligationStatusPriority(status) {
133
+ switch (status) {
134
+ case "investigating": return 0;
135
+ case "waiting_for_merge": return 1;
136
+ case "updating_runtime": return 2;
137
+ case "pending": return 3;
138
+ case "fulfilled": return 4;
139
+ }
140
+ }
141
+ function selectPrimaryObligation(obligations, currentSession) {
142
+ const open = obligations.filter(obligations_1.isOpenObligation);
143
+ if (open.length === 0)
144
+ return null;
145
+ // Prefer current-session match among advanced (non-pending) obligations
146
+ const sessionMatch = currentSession
147
+ ? open.find((ob) => ob.status !== "pending"
148
+ && ob.origin.friendId === currentSession.friendId
149
+ && ob.origin.channel === currentSession.channel
150
+ && (0, config_1.sanitizeKey)(ob.origin.key) === (0, config_1.sanitizeKey)(currentSession.key))
151
+ : null;
152
+ if (sessionMatch)
153
+ return sessionMatch;
154
+ // Then any advanced obligation, sorted by status priority then freshness
155
+ const sorted = [...open].sort((a, b) => {
156
+ const statusDiff = obligationStatusPriority(a.status) - obligationStatusPriority(b.status);
157
+ if (statusDiff !== 0)
158
+ return statusDiff;
159
+ return obligationTimestampMs(b) - obligationTimestampMs(a);
160
+ });
161
+ return sorted[0] ?? null;
162
+ }
163
+ function findPrimaryOpenObligation(frame) {
164
+ return frame.primaryObligation ?? selectPrimaryObligation(frame.pendingObligations ?? [], frame.currentSession);
165
+ }
166
+ function matchesCurrentSession(frame, obligation) {
167
+ return Boolean(frame.currentSession
168
+ && obligation.origin.friendId === frame.currentSession.friendId
169
+ && obligation.origin.channel === frame.currentSession.channel
170
+ && (0, config_1.sanitizeKey)(obligation.origin.key) === (0, config_1.sanitizeKey)(frame.currentSession.key));
171
+ }
172
+ function findCurrentSessionOpenObligation(frame) {
173
+ return (frame.pendingObligations ?? []).find((obligation) => (0, obligations_1.isOpenObligationStatus)(obligation.status) && matchesCurrentSession(frame, obligation))
174
+ ?? null;
175
+ }
176
+ function formatActiveLane(frame, obligation) {
177
+ const liveCodingSession = frame.codingSessions?.[0];
178
+ if (liveCodingSession) {
179
+ return `${formatCodingLaneLabel(liveCodingSession)}${describeCodingSessionScope(liveCodingSession, frame.currentSession)}`;
180
+ }
181
+ if (obligation?.currentSurface?.label) {
182
+ return obligation.currentSurface.label;
183
+ }
184
+ if (obligation && matchesCurrentSession(frame, obligation) && frame.currentSession) {
185
+ return "this same thread";
186
+ }
187
+ if (frame.inner?.job?.status === "running") {
188
+ return "inner dialog";
189
+ }
190
+ return null;
191
+ }
192
+ function formatCodingArtifact(session) {
193
+ const artifactPath = session?.artifactPath?.trim();
194
+ if (artifactPath)
195
+ return artifactPath;
196
+ return session ? "no PR or merge artifact yet" : null;
197
+ }
198
+ function formatCurrentArtifact(frame, obligation) {
199
+ // Live coding session artifact takes precedence (fresher evidence)
200
+ const liveCodingSession = frame.codingSessions?.[0];
201
+ if (liveCodingSession?.artifactPath?.trim()) {
202
+ return liveCodingSession.artifactPath.trim();
203
+ }
204
+ if (obligation?.currentArtifact?.trim()) {
205
+ return obligation.currentArtifact.trim();
206
+ }
207
+ if (obligation?.currentSurface?.kind === "merge" && obligation.currentSurface.label.trim()) {
208
+ return obligation.currentSurface.label.trim();
209
+ }
210
+ const liveCodingArtifact = formatCodingArtifact(liveCodingSession);
211
+ if (liveCodingArtifact) {
212
+ return liveCodingArtifact;
213
+ }
214
+ if (obligation) {
215
+ return "no artifact yet";
216
+ }
217
+ return null;
218
+ }
219
+ function formatObligationContentNextAction(obligation) {
220
+ const content = obligation?.content?.trim();
221
+ if (!content)
222
+ return null;
223
+ return `work on "${content}" and bring back a concrete artifact`;
224
+ }
225
+ function backgroundOperationPriority(operation) {
226
+ switch (operation.status) {
227
+ case "failed": return 0;
228
+ case "queued": return 1;
229
+ case "running": return 2;
230
+ case "succeeded": return 3;
231
+ }
232
+ }
233
+ function backgroundOperationSpecText(spec, key) {
234
+ const value = spec?.[key];
235
+ return typeof value === "string" ? value.trim() : "";
236
+ }
237
+ function selectPrimaryBackgroundOperation(frame) {
238
+ const operations = frame.backgroundOperations ?? [];
239
+ if (operations.length === 0)
240
+ return null;
241
+ return [...operations].sort((left, right) => {
242
+ const priorityDiff = backgroundOperationPriority(left) - backgroundOperationPriority(right);
243
+ if (priorityDiff !== 0)
244
+ return priorityDiff;
245
+ return Date.parse(right.updatedAt) - Date.parse(left.updatedAt);
246
+ })[0] ?? null;
247
+ }
248
+ function formatBackgroundOperationNextAction(operation) {
249
+ if (operation.kind === "mail.import-discovered") {
250
+ return "inspect the import-ready archive and start the matching mail import";
251
+ }
252
+ if (operation.kind === "mail.import-mbox") {
253
+ switch (operation.status) {
254
+ case "failed":
255
+ switch (operation.failure?.class?.trim()) {
256
+ case "transient-storage-read":
257
+ return "retry-safe once the transient storage/network issue clears";
258
+ case "mailroom-auth":
259
+ case "mailroom-config":
260
+ return "repair mail auth/config access, then retry";
261
+ case "source-grant-missing":
262
+ case "source-grant-ambiguous":
263
+ return "repair the delegated owner/source lane, then retry";
264
+ case "archive-discovery":
265
+ case "archive-ambiguity":
266
+ case "archive-missing":
267
+ case "archive-access":
268
+ return "materialize or point at the correct local archive, then retry";
269
+ }
270
+ if (operation.failure?.retryDisposition === "retry-safe") {
271
+ return "retry the failed mail import once the transient issue clears or the dependency answers again";
272
+ }
273
+ if (operation.failure?.retryDisposition === "investigate-first") {
274
+ return "inspect the failed mail import carefully, confirm the root cause, and then decide whether to retry";
275
+ }
276
+ return "inspect the failed mail import, fix the issue, and retry it";
277
+ case "queued":
278
+ return "queued — no action unless it stalls or i need live status";
279
+ case "running":
280
+ return "in flight — no action unless it stalls or i need live status";
281
+ case "succeeded":
282
+ return "caught up — no rerun needed unless a newer archive appears";
283
+ }
284
+ }
285
+ switch (operation.status) {
286
+ case "failed": return `repair the failed ${operation.title} operation and retry it`;
287
+ case "queued": return `let the queued ${operation.title} operation start, then re-check progress`;
288
+ case "running": return `monitor the ${operation.title} operation and react when it changes`;
289
+ case "succeeded": return `review the completed ${operation.title} operation and continue`;
290
+ }
291
+ }
292
+ function formatMailImportRecoveryUniverse(operation) {
293
+ const failureClass = operation.failure?.class?.trim();
294
+ if (!failureClass)
295
+ return null;
296
+ switch (failureClass) {
297
+ case "transient-storage-read":
298
+ return "transient dependency/read issue — safe to retry once storage/network answers again";
299
+ case "mailroom-auth":
300
+ case "mailroom-config":
301
+ return "mail auth/config issue — repair mail access or runtime config before retrying";
302
+ case "source-grant-missing":
303
+ case "source-grant-ambiguous":
304
+ return "delegated lane/registry issue — inspect owner/source linking before retrying";
305
+ case "archive-discovery":
306
+ case "archive-ambiguity":
307
+ case "archive-missing":
308
+ case "archive-access":
309
+ return "local archive/file issue — materialize or point at the right archive before retrying";
310
+ default:
311
+ return "unclassified import issue — inspect the recorded error before retrying";
312
+ }
313
+ }
314
+ function formatBackgroundOperationMeta(operation) {
315
+ const lines = [`operation: ${operation.id}`];
316
+ const filePath = backgroundOperationSpecText(operation.spec, "filePath")
317
+ || backgroundOperationSpecText(operation.spec, "newestCandidatePath");
318
+ if (filePath)
319
+ lines.push(`file: ${filePath}`);
320
+ const originLabel = backgroundOperationSpecText(operation.spec, "fileOriginLabel")
321
+ || backgroundOperationSpecText(operation.spec, "newestCandidateOriginLabel");
322
+ if (originLabel)
323
+ lines.push(`origin: ${originLabel}`);
324
+ const ownerEmail = backgroundOperationSpecText(operation.spec, "ownerEmail");
325
+ const source = backgroundOperationSpecText(operation.spec, "source");
326
+ if (ownerEmail || source) {
327
+ lines.push(`owner/source: ${ownerEmail || "unknown"} / ${source || "unknown"}`);
328
+ }
329
+ if (operation.failure?.class?.trim())
330
+ lines.push(`failure class: ${operation.failure.class}`);
331
+ if (operation.failure?.retryDisposition?.trim())
332
+ lines.push(`retry: ${operation.failure.retryDisposition}`);
333
+ if (operation.failure?.hint?.trim())
334
+ lines.push(`recovery: ${operation.failure.hint}`);
335
+ const recoveryUniverse = operation.kind === "mail.import-mbox" ? formatMailImportRecoveryUniverse(operation) : null;
336
+ if (recoveryUniverse)
337
+ lines.push(`recovery universe: ${recoveryUniverse}`);
338
+ if (operation.startedAt?.trim())
339
+ lines.push(`started: ${operation.startedAt}`);
340
+ if (operation.finishedAt?.trim())
341
+ lines.push(`finished: ${operation.finishedAt}`);
342
+ else if (operation.updatedAt?.trim())
343
+ lines.push(`updated: ${operation.updatedAt}`);
344
+ const nextAction = formatBackgroundOperationNextAction(operation);
345
+ if (nextAction.trim().length > 0)
346
+ lines.push(`next: ${nextAction}`);
347
+ if (operation.remediation?.length) {
348
+ lines.push(...operation.remediation.map((step) => `remediation: ${step}`));
349
+ }
350
+ return lines;
351
+ }
352
+ function formatNextAction(frame, obligation) {
353
+ const obligationHasConcreteArtifact = Boolean(obligation?.currentArtifact?.trim())
354
+ || obligation?.currentSurface?.kind === "merge";
355
+ if (obligation?.status === "waiting_for_merge") {
356
+ return obligation.nextAction?.trim() || `wait for checks, merge ${formatMergeArtifact(obligation)}, then update runtime`;
357
+ }
358
+ if (obligation?.status === "updating_runtime") {
359
+ return obligation.nextAction?.trim() || "update runtime, verify version/changelog, then re-observe";
360
+ }
361
+ if (obligationHasConcreteArtifact && obligation?.nextAction?.trim()) {
362
+ return obligation.nextAction.trim();
363
+ }
364
+ const liveCodingSession = frame.codingSessions?.[0];
365
+ if (liveCodingSession?.status === "waiting_input") {
366
+ return `answer ${formatCodingLaneLabel(liveCodingSession)} and continue`;
367
+ }
368
+ if (liveCodingSession?.status === "stalled") {
369
+ return `unstick ${formatCodingLaneLabel(liveCodingSession)} and continue`;
370
+ }
371
+ if (liveCodingSession) {
372
+ return "finish the coding pass and bring the result back here";
373
+ }
374
+ if (obligation?.nextAction?.trim())
375
+ return obligation.nextAction.trim();
376
+ if (obligation) {
377
+ return formatObligationContentNextAction(obligation) || "continue the active loop and bring the result back here";
378
+ }
379
+ const backgroundOperation = selectPrimaryBackgroundOperation(frame);
380
+ if (backgroundOperation) {
381
+ return formatBackgroundOperationNextAction(backgroundOperation);
382
+ }
383
+ if (frame.mustResolveBeforeHandoff) {
384
+ return "finish what i started here before moving on";
385
+ }
386
+ return null;
387
+ }
388
+ const RECENT_OTHER_LIVE_SESSION_WINDOW_MS = 60 * 60 * 1000;
389
+ function sessionOriginKey(origin) {
390
+ return `${origin.friendId}/${origin.channel}/${(0, config_1.sanitizeKey)(origin.key)}`;
391
+ }
392
+ function codingSessionTimestampMs(session) {
393
+ return Date.parse(session.lastActivityAt ?? session.startedAt);
394
+ }
395
+ function obligationTimestampMs(obligation) {
396
+ const value = Date.parse(obligation.updatedAt ?? obligation.createdAt);
397
+ return Number.isFinite(value) ? value : 0;
398
+ }
399
+ function newestObligationFirst(left, right) {
400
+ return obligationTimestampMs(right) - obligationTimestampMs(left);
401
+ }
402
+ function formatOtherSessionArtifact(obligation, codingSession) {
403
+ if (obligation?.currentArtifact?.trim())
404
+ return obligation.currentArtifact.trim();
405
+ if (obligation?.currentSurface?.kind === "merge" && obligation.currentSurface.label.trim()) {
406
+ return obligation.currentSurface.label.trim();
407
+ }
408
+ const codingArtifact = formatCodingArtifact(codingSession);
409
+ if (codingArtifact)
410
+ return codingArtifact;
411
+ return obligation ? "no artifact yet" : "no explicit artifact yet";
412
+ }
413
+ function formatOtherSessionNextAction(obligation, codingSession) {
414
+ if (obligation?.nextAction?.trim())
415
+ return obligation.nextAction.trim();
416
+ if (obligation?.status === "waiting_for_merge") {
417
+ return `wait for checks, merge ${formatMergeArtifact(obligation)}, then update runtime`;
418
+ }
419
+ if (obligation?.status === "updating_runtime") {
420
+ return "update runtime, verify version/changelog, then re-observe";
421
+ }
422
+ if (codingSession?.status === "waiting_input") {
423
+ return `answer ${formatCodingLaneLabel(codingSession)} and continue`;
424
+ }
425
+ if (codingSession?.status === "stalled") {
426
+ return `unstick ${formatCodingLaneLabel(codingSession)} and continue`;
427
+ }
428
+ if (codingSession) {
429
+ return "finish the coding pass and bring the result back there";
430
+ }
431
+ if (obligation) {
432
+ return formatObligationContentNextAction(obligation) || "continue the active loop and bring the result back there";
433
+ }
434
+ return "check this session and bring back the latest concrete state";
435
+ }
436
+ function formatOtherSessionLine(label, status, activeLane, artifact, nextAction) {
437
+ return `- ${label}: [${status}] ${activeLane}; artifact ${artifact}; next ${nextAction}`;
438
+ }
439
+ function formatOtherActiveSessionSummaries(frame, nowMs = Date.now()) {
440
+ const originMap = new Map();
441
+ for (const session of frame.friendActivity?.allOtherLiveSessions ?? []) {
442
+ if (session.friendId === "self" || session.channel === "inner")
443
+ continue;
444
+ originMap.set(sessionOriginKey(session), {
445
+ friendId: session.friendId,
446
+ channel: session.channel,
447
+ key: session.key,
448
+ });
449
+ }
450
+ const orphanCodingSummaries = (frame.otherCodingSessions ?? [])
451
+ .filter((session) => !session.originSession)
452
+ .sort((left, right) => codingSessionTimestampMs(right) - codingSessionTimestampMs(left))
453
+ .map((session) => ({
454
+ timestampMs: codingSessionTimestampMs(session),
455
+ line: formatOtherSessionLine("another session", session.status, formatCodingLaneLabel(session), formatCodingArtifact(session), formatOtherSessionNextAction(null, session)),
456
+ }));
457
+ for (const session of frame.otherCodingSessions ?? []) {
458
+ if (!session.originSession)
459
+ continue;
460
+ if (frame.currentSession
461
+ && session.originSession.friendId === frame.currentSession.friendId
462
+ && session.originSession.channel === frame.currentSession.channel
463
+ && (0, config_1.sanitizeKey)(session.originSession.key) === (0, config_1.sanitizeKey)(frame.currentSession.key)) {
464
+ continue;
465
+ }
466
+ originMap.set(sessionOriginKey(session.originSession), session.originSession);
467
+ }
468
+ for (const obligation of frame.pendingObligations ?? []) {
469
+ if (obligation.status === "fulfilled" || matchesCurrentSession(frame, obligation))
470
+ continue;
471
+ originMap.set(sessionOriginKey(obligation.origin), obligation.origin);
472
+ }
473
+ const summaries = [...originMap.values()].map((origin) => {
474
+ const originKey = sessionOriginKey(origin);
475
+ const obligation = [...(frame.pendingObligations ?? [])]
476
+ .filter((candidate) => candidate.status !== "fulfilled" && sessionOriginKey(candidate.origin) === originKey)
477
+ .sort(newestObligationFirst)[0] ?? null;
478
+ const codingSession = [...(frame.otherCodingSessions ?? [])]
479
+ .filter((candidate) => candidate.originSession && sessionOriginKey(candidate.originSession) === originKey)
480
+ .sort((left, right) => codingSessionTimestampMs(right) - codingSessionTimestampMs(left))[0] ?? null;
481
+ const liveSession = (frame.friendActivity?.allOtherLiveSessions ?? []).find((candidate) => sessionOriginKey(candidate) === originKey) ?? null;
482
+ const hasMaterialLiveSession = liveSession
483
+ ? ((nowMs - liveSession.lastActivityMs) <= RECENT_OTHER_LIVE_SESSION_WINDOW_MS
484
+ || (frame.currentSession != null
485
+ && liveSession.friendId === frame.currentSession.friendId
486
+ && liveSession.channel !== frame.currentSession.channel))
487
+ : false;
488
+ if (!obligation && !codingSession && !hasMaterialLiveSession) {
489
+ return null;
490
+ }
491
+ const timestampMs = Math.max(liveSession?.lastActivityMs ?? 0, codingSession ? codingSessionTimestampMs(codingSession) : 0, obligation ? obligationTimestampMs(obligation) : 0);
492
+ const activeLane = codingSession
493
+ ? formatCodingLaneLabel(codingSession)
494
+ : obligation?.currentSurface?.label?.trim() || "this live thread";
495
+ const artifact = formatOtherSessionArtifact(obligation, codingSession);
496
+ const nextAction = formatOtherSessionNextAction(obligation, codingSession);
497
+ const status = obligation?.status ?? codingSession?.status ?? "active";
498
+ const label = liveSession?.friendName ?? origin.friendId;
499
+ return {
500
+ timestampMs,
501
+ line: formatOtherSessionLine(`${label}/${origin.channel}/${origin.key}`, status, activeLane, artifact, nextAction),
502
+ };
503
+ }).filter((entry) => entry !== null)
504
+ .sort((left, right) => right.timestampMs - left.timestampMs);
505
+ const lines = summaries.map((entry) => entry.line);
506
+ return [...lines, ...orphanCodingSummaries.map((entry) => entry.line)];
33
507
  }
34
508
  function suggestBridgeForActiveWork(input) {
35
509
  const targetCandidates = (input.targetCandidates ?? [])
@@ -50,10 +524,16 @@ function suggestBridgeForActiveWork(input) {
50
524
  .sort((a, b) => {
51
525
  return b.lastActivityMs - a.lastActivityMs;
52
526
  });
53
- if (!hasSharedObligationPressure(input) || targetCandidates.length !== 1) {
527
+ if (!hasSharedObligationPressure({
528
+ mustResolveBeforeHandoff: input.mustResolveBeforeHandoff,
529
+ pendingObligations: input.pendingObligations,
530
+ }) || targetCandidates.length === 0) {
54
531
  return null;
55
532
  }
56
533
  const targetSession = targetCandidates[0];
534
+ const objectiveHint = [...(input.pendingObligations ?? [])]
535
+ .find((obligation) => (0, obligations_1.isOpenObligationStatus)(obligation.status))
536
+ ?.content?.trim() || "keep this shared work aligned";
57
537
  const activeBridge = input.bridges.find(isActiveBridge) ?? null;
58
538
  if (activeBridge) {
59
539
  const alreadyAttached = activeBridge.attachedSessions.some((session) => session.friendId === targetSession.friendId
@@ -72,26 +552,69 @@ function suggestBridgeForActiveWork(input) {
72
552
  return {
73
553
  kind: "begin-new",
74
554
  targetSession,
75
- objectiveHint: input.currentObligation?.trim() || "keep this shared work aligned",
555
+ objectiveHint,
76
556
  reason: "shared-work-candidate",
77
557
  };
78
558
  }
79
559
  function formatSessionLabel(session) {
80
560
  return `${session.channel}/${session.key}`;
81
561
  }
562
+ function deriveResumeHandleConfidence(primaryObligation, codingSession) {
563
+ if (primaryObligation?.currentArtifact?.trim() && primaryObligation.nextAction?.trim())
564
+ return "high";
565
+ if (codingSession?.checkpoint?.trim())
566
+ return "medium";
567
+ if (primaryObligation)
568
+ return "low";
569
+ return "low";
570
+ }
571
+ function buildResumeHandle(currentSession, primaryObligation, codingSessions) {
572
+ const sessionLabel = currentSession ? formatSessionLabel(currentSession) : null;
573
+ if (!sessionLabel)
574
+ return null;
575
+ const liveCoding = codingSessions[0] ?? null;
576
+ const lane = liveCoding
577
+ ? `${formatCodingLaneLabel(liveCoding)}${describeCodingSessionScope(liveCoding, currentSession)}`
578
+ : (primaryObligation?.currentSurface?.label?.trim() || null);
579
+ const artifact = primaryObligation?.currentArtifact?.trim()
580
+ || (liveCoding?.artifactPath?.trim() || null);
581
+ const blockerOrWaitingOn = primaryObligation?.meaning?.waitingOn?.detail?.trim() || null;
582
+ const nextAction = primaryObligation?.nextAction?.trim()
583
+ || (primaryObligation?.content?.trim() ? `work on "${primaryObligation.content.trim()}" and bring back a concrete artifact` : null);
584
+ const lastVerifiedCheckpoint = liveCoding?.checkpoint?.trim() || null;
585
+ const codingIdentity = liveCoding
586
+ ? { sessionId: liveCoding.id, runner: liveCoding.runner, status: liveCoding.status }
587
+ : null;
588
+ return {
589
+ sessionLabel,
590
+ lane,
591
+ artifact,
592
+ blockerOrWaitingOn,
593
+ nextAction,
594
+ lastVerifiedCheckpoint,
595
+ confidence: deriveResumeHandleConfidence(primaryObligation, liveCoding),
596
+ codingIdentity,
597
+ };
598
+ }
82
599
  function buildActiveWorkFrame(input) {
83
600
  const friendSessions = input.currentSession
84
601
  ? input.friendActivity
85
602
  .filter((entry) => entry.friendId === input.currentSession?.friendId)
86
603
  .sort(compareActivity)
87
604
  : [];
88
- const liveTaskNames = summarizeLiveTasks(input.taskBoard);
89
605
  const activeBridgePresent = input.bridges.some(isActiveBridge);
606
+ const liveCodingSessions = input.codingSessions ?? [];
607
+ const allOtherLiveSessions = [...input.friendActivity].sort(compareActivity);
608
+ const otherCodingSessions = input.otherCodingSessions ?? [];
609
+ const pendingObligations = normalizePendingObligations(input.pendingObligations, liveCodingSessions, otherCodingSessions);
610
+ const openObligations = activeObligationCount(pendingObligations);
90
611
  const centerOfGravity = activeBridgePresent
91
612
  ? "shared-work"
92
- : (input.inner.status === "running" || input.inner.hasPending || input.mustResolveBeforeHandoff)
613
+ : (input.inner.status === "running" || input.inner.hasPending || input.mustResolveBeforeHandoff || openObligations > 0 || liveCodingSessions.length > 0)
93
614
  ? "inward-work"
94
615
  : "local-turn";
616
+ const primaryObligation = selectPrimaryObligation(pendingObligations, input.currentSession ?? null);
617
+ const resumeHandle = buildResumeHandle(input.currentSession ?? null, primaryObligation, liveCodingSessions);
95
618
  const frame = {
96
619
  currentSession: input.currentSession ?? null,
97
620
  currentObligation: input.currentObligation?.trim() || null,
@@ -99,24 +622,27 @@ function buildActiveWorkFrame(input) {
99
622
  centerOfGravity,
100
623
  inner: input.inner,
101
624
  bridges: input.bridges,
102
- taskPressure: {
103
- compactBoard: input.taskBoard.compact,
104
- liveTaskNames,
105
- activeBridges: input.taskBoard.activeBridges,
106
- },
107
625
  friendActivity: {
108
626
  freshestForCurrentFriend: friendSessions[0] ?? null,
109
627
  otherLiveSessionsForCurrentFriend: friendSessions,
628
+ allOtherLiveSessions,
110
629
  },
630
+ codingSessions: liveCodingSessions,
631
+ backgroundOperations: input.backgroundOperations ?? [],
632
+ otherCodingSessions,
633
+ pendingObligations,
111
634
  targetCandidates: input.targetCandidates ?? [],
635
+ innerReturnObligations: input.innerReturnObligations ?? [],
112
636
  bridgeSuggestion: suggestBridgeForActiveWork({
113
637
  currentSession: input.currentSession,
114
638
  currentObligation: input.currentObligation,
115
639
  mustResolveBeforeHandoff: input.mustResolveBeforeHandoff,
116
640
  bridges: input.bridges,
117
- taskBoard: input.taskBoard,
641
+ pendingObligations,
118
642
  targetCandidates: input.targetCandidates,
119
643
  }),
644
+ primaryObligation,
645
+ resumeHandle,
120
646
  };
121
647
  (0, runtime_1.emitNervesEvent)({
122
648
  component: "engine",
@@ -126,38 +652,145 @@ function buildActiveWorkFrame(input) {
126
652
  centerOfGravity: frame.centerOfGravity,
127
653
  friendId: frame.currentSession?.friendId ?? null,
128
654
  bridges: frame.bridges.length,
129
- liveTasks: frame.taskPressure.liveTaskNames.length,
130
655
  liveSessions: frame.friendActivity.otherLiveSessionsForCurrentFriend.length,
656
+ codingSessions: frame.codingSessions.length,
657
+ otherLiveSessions: allOtherLiveSessions.length,
658
+ otherCodingSessions: otherCodingSessions.length,
659
+ pendingObligations: openObligations,
131
660
  hasBridgeSuggestion: frame.bridgeSuggestion !== null,
132
661
  },
133
662
  });
134
663
  return frame;
135
664
  }
136
- function formatActiveWorkFrame(frame) {
137
- const lines = ["## active work"];
665
+ function formatActiveWorkFrame(frame, options) {
666
+ const lines = ["## what i'm holding"];
667
+ lines.push("this is my top-level live world-state right now. inner work, coding lanes, other sessions, and return obligations all belong inside this picture.");
668
+ lines.push("if older checkpoints elsewhere in the transcript disagree with this picture, this picture wins.");
669
+ const primaryObligation = findPrimaryOpenObligation(frame);
670
+ const currentSessionObligation = findCurrentSessionOpenObligation(frame);
671
+ const activeLane = formatActiveLane(frame, primaryObligation);
672
+ const currentArtifact = formatCurrentArtifact(frame, primaryObligation);
673
+ const nextAction = formatNextAction(frame, primaryObligation);
674
+ const otherActiveSessions = formatOtherActiveSessionSummaries(frame);
675
+ // Session line
138
676
  if (frame.currentSession) {
139
- lines.push(`current session: ${formatSessionLabel(frame.currentSession)}`);
677
+ let sessionLine = `i'm in a conversation on ${formatSessionLabel(frame.currentSession)}.`;
678
+ if (currentSessionObligation?.content?.trim()) {
679
+ sessionLine += ` i still owe them: ${currentSessionObligation.content.trim()}.`;
680
+ }
681
+ else if (frame.mustResolveBeforeHandoff) {
682
+ sessionLine += " i need to finish what i started here before moving on.";
683
+ }
684
+ lines.push("");
685
+ lines.push(sessionLine);
140
686
  }
141
- lines.push(`center: ${frame.centerOfGravity}`);
142
- if (typeof frame.currentObligation === "string" && frame.currentObligation.trim().length > 0) {
143
- lines.push(`obligation: ${frame.currentObligation.trim()}`);
687
+ else {
688
+ lines.push("");
689
+ lines.push("i'm not in a conversation right now.");
144
690
  }
145
- if (frame.mustResolveBeforeHandoff) {
146
- lines.push("handoff pressure: must resolve before handoff");
691
+ if (activeLane || currentArtifact || nextAction) {
692
+ lines.push("");
693
+ lines.push("## current concrete state");
694
+ if (frame.currentSession) {
695
+ lines.push(`- live conversation: ${formatSessionLabel(frame.currentSession)}`);
696
+ }
697
+ if (activeLane) {
698
+ lines.push(`- active lane: ${activeLane}`);
699
+ }
700
+ if (currentArtifact) {
701
+ lines.push(`- current artifact: ${currentArtifact}`);
702
+ }
703
+ if (nextAction) {
704
+ lines.push(`- next action: ${nextAction}`);
705
+ }
706
+ if (frame.resumeHandle?.lastVerifiedCheckpoint) {
707
+ lines.push(`- last checkpoint: ${frame.resumeHandle.lastVerifiedCheckpoint}`);
708
+ }
709
+ }
710
+ // Inner status block
711
+ const job = frame.inner?.job;
712
+ if (job) {
713
+ if (job.status === "queued") {
714
+ let queuedLine = "i have a thought queued up for private attention.";
715
+ if (frame.inner?.contentSnippet) {
716
+ queuedLine += `\nit's about: "${frame.inner.contentSnippet}"`;
717
+ }
718
+ lines.push("");
719
+ lines.push(queuedLine);
720
+ }
721
+ else if (job.status === "running") {
722
+ const originName = job.origin?.friendName ?? job.origin?.friendId;
723
+ let runningLine = originName
724
+ ? `i'm thinking through something privately right now. ${originName} asked about something and i wanted to give it real thought.`
725
+ : "i'm thinking through something privately right now.";
726
+ if (frame.inner?.obligationPending) {
727
+ runningLine += "\ni still owe them an answer.";
728
+ }
729
+ lines.push("");
730
+ lines.push(runningLine);
731
+ }
732
+ else if (job.status === "surfaced") {
733
+ let surfacedLine = "i finished thinking about something privately. i should bring my answer back.";
734
+ if (job.surfacedResult) {
735
+ const truncated = job.surfacedResult.length > 120 ? job.surfacedResult.slice(0, 117) + "..." : job.surfacedResult;
736
+ surfacedLine += `\nwhat i came to: ${truncated}`;
737
+ }
738
+ lines.push("");
739
+ lines.push(surfacedLine);
740
+ }
741
+ // idle, returned, abandoned: omitted
742
+ }
743
+ if ((frame.codingSessions ?? []).length > 0) {
744
+ lines.push("");
745
+ lines.push("## live coding work");
746
+ for (const session of frame.codingSessions) {
747
+ const checkpoint = compactCodingCheckpoint(session);
748
+ lines.push(`- [${session.status}] ${formatCodingLaneLabel(session)}${describeCodingSessionScope(session, frame.currentSession)}${checkpoint ? `: ${checkpoint}` : ""}`);
749
+ /* v8 ignore start -- coding identity display: tested in identity-packet.test.ts @preserve */
750
+ if (session.codingIdentity) {
751
+ const id = session.codingIdentity;
752
+ lines.push(` branch: ${id.branch ?? "unknown"} commit: ${id.commit ?? "unknown"} ${id.dirty ? "dirty" : "clean"} verification: ${id.verificationStatus}`);
753
+ }
754
+ /* v8 ignore stop */
755
+ }
756
+ }
757
+ const backgroundOperations = frame.backgroundOperations ?? [];
758
+ if (backgroundOperations.length > 0) {
759
+ lines.push("");
760
+ lines.push("## background operations");
761
+ for (const operation of backgroundOperations) {
762
+ let line = `- [${operation.status}] ${operation.title}`;
763
+ if (operation.summary.trim().length > 0) {
764
+ line += `: ${operation.summary}`;
765
+ }
766
+ line += `\n ${formatBackgroundOperationMeta(operation).join("\n ")}`;
767
+ if (operation.detail?.trim()) {
768
+ line += `\n ${operation.detail.trim()}`;
769
+ }
770
+ if (operation.progress) {
771
+ const current = typeof operation.progress.current === "number" ? String(operation.progress.current) : "?";
772
+ const total = typeof operation.progress.total === "number" ? String(operation.progress.total) : null;
773
+ const unit = operation.progress.unit?.trim() ? ` ${operation.progress.unit.trim()}` : "";
774
+ line += `\n progress: ${total ? `${current}/${total}` : current}${unit}`;
775
+ }
776
+ if (operation.error?.message?.trim()) {
777
+ line += `\n error: ${operation.error.message.trim()}`;
778
+ }
779
+ lines.push(line);
780
+ }
147
781
  }
148
- const innerStatus = frame.inner?.status ?? "idle";
149
- const innerHasPending = frame.inner?.hasPending === true;
150
- lines.push(`inner status: ${innerStatus}${innerHasPending ? " (pending queued)" : ""}`);
151
- if ((frame.taskPressure?.liveTaskNames ?? []).length > 0) {
152
- lines.push(`live tasks: ${frame.taskPressure.liveTaskNames.join(", ")}`);
782
+ if (otherActiveSessions.length > 0) {
783
+ lines.push("");
784
+ lines.push("## other active sessions");
785
+ lines.push(...otherActiveSessions);
153
786
  }
787
+ // Bridges
154
788
  if ((frame.bridges ?? []).length > 0) {
155
789
  const bridgeLabels = frame.bridges.map((bridge) => `${bridge.id} [${(0, state_machine_1.bridgeStateLabel)(bridge)}]`);
156
- lines.push(`bridges: ${bridgeLabels.join(", ")}`);
157
- }
158
- if (frame.friendActivity?.freshestForCurrentFriend) {
159
- lines.push(`freshest friend-facing session: ${formatSessionLabel(frame.friendActivity.freshestForCurrentFriend)}`);
790
+ lines.push("");
791
+ lines.push(`i have shared work spanning sessions: ${bridgeLabels.join(", ")}.`);
160
792
  }
793
+ // Target candidates (keep factual format)
161
794
  const targetCandidatesBlock = frame.targetCandidates && frame.targetCandidates.length > 0
162
795
  ? (0, target_resolution_1.formatTargetSessionCandidates)(frame.targetCandidates)
163
796
  : "";
@@ -165,14 +798,169 @@ function formatActiveWorkFrame(frame) {
165
798
  lines.push("");
166
799
  lines.push(targetCandidatesBlock);
167
800
  }
801
+ if ((frame.pendingObligations ?? []).length > 0) {
802
+ const openCount = frame.pendingObligations.filter((ob) => (0, obligations_1.isOpenObligationStatus)(ob.status)).length;
803
+ if (options?.obligationDetailsRenderedElsewhere && openCount > 0) {
804
+ // Enriched obligation data (with resumeHint, stalenessClass, waitingOn) is rendered elsewhere.
805
+ // Avoid duplicating the full list — just anchor the count here.
806
+ lines.push("");
807
+ lines.push(`return obligations: ${openCount} active (canonical details in **Owed** section of start-of-turn packet)`);
808
+ }
809
+ else if (openCount > 0) {
810
+ lines.push("");
811
+ lines.push("## return obligations");
812
+ for (const obligation of frame.pendingObligations) {
813
+ if (!(0, obligations_1.isOpenObligationStatus)(obligation.status))
814
+ continue;
815
+ let obligationLine = `- [${obligation.status}] ${obligation.origin.friendId}/${obligation.origin.channel}/${obligation.origin.key}: ${obligation.content}${formatObligationSurface(obligation)}`;
816
+ if (obligation.latestNote?.trim()) {
817
+ obligationLine += `\n latest: ${obligation.latestNote.trim()}`;
818
+ }
819
+ lines.push(obligationLine);
820
+ }
821
+ }
822
+ }
823
+ if (frame.innerReturnObligations && frame.innerReturnObligations.length > 0) {
824
+ lines.push("");
825
+ lines.push("## inner return obligations");
826
+ for (const ob of frame.innerReturnObligations) {
827
+ const preview = ob.delegatedContent.length > 60
828
+ ? `${ob.delegatedContent.slice(0, 57)}...`
829
+ : ob.delegatedContent;
830
+ lines.push(`- [${ob.status}] ${ob.origin.friendId}/${ob.origin.channel}/${ob.origin.key}: ${preview}`);
831
+ }
832
+ }
833
+ // Bridge suggestion
168
834
  if (frame.bridgeSuggestion) {
169
- if (frame.bridgeSuggestion.kind === "attach-existing") {
170
- lines.push(`suggested bridge: attach ${frame.bridgeSuggestion.bridgeId} -> ${formatSessionLabel(frame.bridgeSuggestion.targetSession)}`);
835
+ lines.push("");
836
+ if (frame.bridgeSuggestion.kind === "begin-new") {
837
+ lines.push(`this work touches my conversation on ${formatSessionLabel(frame.bridgeSuggestion.targetSession)} too -- i should connect these threads.`);
171
838
  }
172
839
  else {
173
- lines.push(`suggested bridge: begin -> ${formatSessionLabel(frame.bridgeSuggestion.targetSession)}`);
174
- lines.push(`bridge objective hint: ${frame.bridgeSuggestion.objectiveHint}`);
840
+ lines.push(`this work relates to bridge ${frame.bridgeSuggestion.bridgeId} -- i should connect ${formatSessionLabel(frame.bridgeSuggestion.targetSession)} to it.`);
175
841
  }
176
842
  }
177
843
  return lines.join("\n");
178
844
  }
845
+ function formatLiveWorldStateCheckpoint(frame) {
846
+ const primaryObligation = findPrimaryOpenObligation(frame);
847
+ const activeLane = formatActiveLane(frame, primaryObligation) ?? "no explicit live lane";
848
+ const currentArtifact = formatCurrentArtifact(frame, primaryObligation) ?? "no artifact yet";
849
+ const nextAction = formatNextAction(frame, primaryObligation) ?? "continue from the live world-state";
850
+ const otherActiveSessions = formatOtherActiveSessionSummaries(frame);
851
+ const lines = [
852
+ "## live world-state",
853
+ "This is the freshest state for this turn. If older transcript history conflicts with it, this state wins.",
854
+ `- live conversation: ${frame.currentSession ? formatSessionLabel(frame.currentSession) : "not in a live conversation"}`,
855
+ `- active lane: ${activeLane}`,
856
+ `- current artifact: ${currentArtifact}`,
857
+ `- next action: ${nextAction}`,
858
+ ];
859
+ if (frame.resumeHandle?.lastVerifiedCheckpoint) {
860
+ lines.push(`- last checkpoint: ${frame.resumeHandle.lastVerifiedCheckpoint}`);
861
+ }
862
+ if (otherActiveSessions.length > 0) {
863
+ lines.push("other active sessions:");
864
+ lines.push(...otherActiveSessions);
865
+ }
866
+ return lines.join("\n");
867
+ }
868
+ function snapshotActiveWork(frame) {
869
+ return {
870
+ obligationSnapshots: (frame.pendingObligations ?? []).map((ob) => ({
871
+ id: ob.id,
872
+ status: ob.status,
873
+ artifact: ob.currentArtifact?.trim() || null,
874
+ nextAction: ob.nextAction?.trim() || null,
875
+ })),
876
+ codingSnapshots: (frame.codingSessions ?? []).map((cs) => ({
877
+ id: cs.id,
878
+ status: cs.status,
879
+ artifact: cs.artifactPath?.trim() || null,
880
+ checkpoint: cs.checkpoint?.trim() || null,
881
+ })),
882
+ timestamp: new Date().toISOString(),
883
+ };
884
+ }
885
+ function detectActiveWorkChanges(previous, current) {
886
+ const changes = [];
887
+ const prevObMap = new Map(previous.obligationSnapshots.map((ob) => [ob.id, ob]));
888
+ const currObMap = new Map(current.obligationSnapshots.map((ob) => [ob.id, ob]));
889
+ // Detect new and changed obligations
890
+ for (const [id, curr] of currObMap) {
891
+ const prev = prevObMap.get(id);
892
+ if (!prev) {
893
+ changes.push({
894
+ kind: "obligation_appeared",
895
+ id,
896
+ from: null,
897
+ to: curr.status,
898
+ summary: `new obligation: ${curr.status}`,
899
+ });
900
+ continue;
901
+ }
902
+ if (prev.status !== curr.status) {
903
+ changes.push({
904
+ kind: "obligation_status_changed",
905
+ id,
906
+ from: prev.status,
907
+ to: curr.status,
908
+ summary: `obligation ${prev.status} -> ${curr.status}`,
909
+ });
910
+ }
911
+ if (prev.artifact !== curr.artifact) {
912
+ changes.push({
913
+ kind: "obligation_artifact_changed",
914
+ id,
915
+ from: prev.artifact,
916
+ to: curr.artifact,
917
+ summary: curr.artifact ? `artifact updated: ${curr.artifact}` : "artifact cleared",
918
+ });
919
+ }
920
+ }
921
+ const prevCodingMap = new Map(previous.codingSnapshots.map((cs) => [cs.id, cs]));
922
+ const currCodingMap = new Map(current.codingSnapshots.map((cs) => [cs.id, cs]));
923
+ for (const [id, curr] of currCodingMap) {
924
+ const prev = prevCodingMap.get(id);
925
+ if (!prev)
926
+ continue;
927
+ if (prev.status !== curr.status) {
928
+ changes.push({
929
+ kind: "coding_status_changed",
930
+ id,
931
+ from: prev.status,
932
+ to: curr.status,
933
+ summary: `coding ${prev.status} -> ${curr.status}`,
934
+ });
935
+ }
936
+ if (prev.artifact !== curr.artifact) {
937
+ changes.push({
938
+ kind: "coding_artifact_changed",
939
+ id,
940
+ from: prev.artifact,
941
+ to: curr.artifact,
942
+ summary: curr.artifact ? `artifact updated: ${curr.artifact}` : "artifact cleared",
943
+ });
944
+ }
945
+ if (prev.checkpoint !== curr.checkpoint) {
946
+ changes.push({
947
+ kind: "coding_checkpoint_changed",
948
+ id,
949
+ from: prev.checkpoint,
950
+ to: curr.checkpoint,
951
+ summary: curr.checkpoint ? `checkpoint: ${curr.checkpoint}` : "checkpoint cleared",
952
+ });
953
+ }
954
+ }
955
+ return changes;
956
+ }
957
+ function formatActiveWorkChanges(changes) {
958
+ if (changes.length === 0)
959
+ return "";
960
+ const lines = ["## what changed since last looked"];
961
+ for (const change of changes) {
962
+ lines.push(`- ${change.summary}`);
963
+ }
964
+ return lines.join("\n");
965
+ }
966
+ /* v8 ignore stop */