@ouro.bot/cli 0.1.0-alpha.48 → 0.1.0-alpha.481

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