@openrig/cli 0.6.10 → 0.6.11

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 (352) hide show
  1. package/daemon/assets/plugins/openrig-core/skills/openrig-skills/SKILL.md +1 -1
  2. package/daemon/assets/plugins/openrig-core/skills/refocusing/scripts/trace-to-root.py +6 -1
  3. package/daemon/assets/skills/rigs/SKILL.md +1 -1
  4. package/daemon/context-packs/help/manifest.yaml +1 -1
  5. package/daemon/context-packs/onboarding-width/manifest.yaml +1 -1
  6. package/daemon/context-packs/onboarding-width/public-what-you-can-do.md +36 -11
  7. package/daemon/context-packs/reference/manifest.yaml +1 -1
  8. package/daemon/context-packs/reference/rig-spec.md +2 -2
  9. package/daemon/context-packs/reference/whats-new.md +135 -134
  10. package/daemon/context-packs/skills/agent-operated-software/manifest.yaml +1 -1
  11. package/daemon/context-packs/skills/agent-operated-workflows/manifest.yaml +1 -1
  12. package/daemon/context-packs/skills/applying-a-permission-policy/manifest.yaml +1 -1
  13. package/daemon/context-packs/skills/claude-compaction-restore/manifest.yaml +1 -1
  14. package/daemon/context-packs/skills/core/agent-starters/manifest.yaml +1 -1
  15. package/daemon/context-packs/skills/core/agent-startup-and-context-ingestion/manifest.yaml +1 -1
  16. package/daemon/context-packs/skills/core/cross-host-rig-commands/manifest.yaml +1 -1
  17. package/daemon/context-packs/skills/core/human-in-the-loop/manifest.yaml +1 -1
  18. package/daemon/context-packs/skills/core/messaging-the-human/manifest.yaml +1 -1
  19. package/daemon/context-packs/skills/core/openrig-architect/manifest.yaml +1 -1
  20. package/daemon/context-packs/skills/core/openrig-cmux/manifest.yaml +1 -1
  21. package/daemon/context-packs/skills/core/openrig-herdr/manifest.yaml +1 -1
  22. package/daemon/context-packs/skills/core/openrig-skills/SKILL.md +1 -1
  23. package/daemon/context-packs/skills/core/openrig-skills/manifest.yaml +3 -3
  24. package/daemon/context-packs/skills/core/openrig-software-factory/manifest.yaml +1 -1
  25. package/daemon/context-packs/skills/core/openrig-upgrade/manifest.yaml +1 -1
  26. package/daemon/context-packs/skills/core/rig-bundles-and-shareable-artifacts/manifest.yaml +1 -1
  27. package/daemon/context-packs/skills/core/rig-lifecycle/manifest.yaml +1 -1
  28. package/daemon/context-packs/skills/core/session-source-fork/manifest.yaml +1 -1
  29. package/daemon/context-packs/skills/core/specification-system/manifest.yaml +1 -1
  30. package/daemon/context-packs/skills/core/topology-mutation-and-seat-management/manifest.yaml +1 -1
  31. package/daemon/context-packs/skills/core/watchdog/manifest.yaml +1 -1
  32. package/daemon/context-packs/skills/delegating-work/manifest.yaml +1 -1
  33. package/daemon/context-packs/skills/forming-an-openrig-mental-model/manifest.yaml +1 -1
  34. package/daemon/context-packs/skills/loading-addressable-markdown/manifest.yaml +1 -1
  35. package/daemon/context-packs/skills/mission-slice-sop/manifest.yaml +1 -1
  36. package/daemon/context-packs/skills/openrig-operating-model/manifest.yaml +1 -1
  37. package/daemon/context-packs/skills/openrig-user/manifest.yaml +1 -1
  38. package/daemon/context-packs/skills/orienting-to-an-inherited-seat/manifest.yaml +1 -1
  39. package/daemon/context-packs/skills/pm/backlog-capture/manifest.yaml +1 -1
  40. package/daemon/context-packs/skills/pm/context-builder/manifest.yaml +1 -1
  41. package/daemon/context-packs/skills/pm/exec-summary/manifest.yaml +1 -1
  42. package/daemon/context-packs/skills/pm/office-hours/manifest.yaml +1 -1
  43. package/daemon/context-packs/skills/pm/plan-review/manifest.yaml +1 -1
  44. package/daemon/context-packs/skills/pm/requirements-writer/manifest.yaml +1 -1
  45. package/daemon/context-packs/skills/pm/ui-mockup/manifest.yaml +1 -1
  46. package/daemon/context-packs/skills/pods/development-team/manifest.yaml +1 -1
  47. package/daemon/context-packs/skills/pods/orchestration-team/manifest.yaml +1 -1
  48. package/daemon/context-packs/skills/pods/oversight-team/manifest.yaml +1 -1
  49. package/daemon/context-packs/skills/pods/review-team/manifest.yaml +1 -1
  50. package/daemon/context-packs/skills/process/agent-browser/manifest.yaml +1 -1
  51. package/daemon/context-packs/skills/process/context-engineering/manifest.yaml +1 -1
  52. package/daemon/context-packs/skills/process/dogfood/manifest.yaml +1 -1
  53. package/daemon/context-packs/skills/process/frontend-design/manifest.yaml +1 -1
  54. package/daemon/context-packs/skills/process/systematic-debugging/manifest.yaml +1 -1
  55. package/daemon/context-packs/skills/process/test-driven-development/manifest.yaml +1 -1
  56. package/daemon/context-packs/skills/process/verification-before-completion/manifest.yaml +1 -1
  57. package/daemon/context-packs/skills/queue-handoff/manifest.yaml +1 -1
  58. package/daemon/context-packs/skills/refocusing/manifest.yaml +1 -1
  59. package/daemon/context-packs/skills/refocusing/scripts/trace-to-root.py +6 -1
  60. package/daemon/context-packs/skills/retiring-and-inheriting-a-seat/manifest.yaml +1 -1
  61. package/daemon/context-packs/skills/seat-continuity-and-handover/manifest.yaml +1 -1
  62. package/daemon/context-packs/skills/session-compaction-and-restore/manifest.yaml +1 -1
  63. package/daemon/context-packs/skills/software-for-agents/manifest.yaml +1 -1
  64. package/daemon/context-packs/world-example/manifest.yaml +1 -1
  65. package/daemon/context-packs/world-public/manifest.yaml +1 -1
  66. package/daemon/dist/adapters/claude-code-adapter.d.ts +0 -14
  67. package/daemon/dist/adapters/claude-code-adapter.d.ts.map +1 -1
  68. package/daemon/dist/adapters/claude-code-adapter.js +27 -73
  69. package/daemon/dist/adapters/claude-code-adapter.js.map +1 -1
  70. package/daemon/dist/adapters/codex-runtime-adapter.d.ts +35 -0
  71. package/daemon/dist/adapters/codex-runtime-adapter.d.ts.map +1 -1
  72. package/daemon/dist/adapters/codex-runtime-adapter.js +94 -44
  73. package/daemon/dist/adapters/codex-runtime-adapter.js.map +1 -1
  74. package/daemon/dist/adapters/pi-runner.d.ts.map +1 -1
  75. package/daemon/dist/adapters/pi-runner.js +6 -3
  76. package/daemon/dist/adapters/pi-runner.js.map +1 -1
  77. package/daemon/dist/adapters/pi-runtime-adapter.js +1 -1
  78. package/daemon/dist/adapters/pi-runtime-adapter.js.map +1 -1
  79. package/daemon/dist/adapters/tmux.d.ts +23 -0
  80. package/daemon/dist/adapters/tmux.d.ts.map +1 -1
  81. package/daemon/dist/adapters/tmux.js +127 -6
  82. package/daemon/dist/adapters/tmux.js.map +1 -1
  83. package/daemon/dist/build-info.js +3 -3
  84. package/daemon/dist/db/all-migrations.d.ts.map +1 -1
  85. package/daemon/dist/db/all-migrations.js +2 -0
  86. package/daemon/dist/db/all-migrations.js.map +1 -1
  87. package/daemon/dist/db/migrations/103_session_stop_intent.d.ts +4 -0
  88. package/daemon/dist/db/migrations/103_session_stop_intent.d.ts.map +1 -0
  89. package/daemon/dist/db/migrations/103_session_stop_intent.js +9 -0
  90. package/daemon/dist/db/migrations/103_session_stop_intent.js.map +1 -0
  91. package/daemon/dist/domain/active-occupant.d.ts +14 -0
  92. package/daemon/dist/domain/active-occupant.d.ts.map +1 -1
  93. package/daemon/dist/domain/active-occupant.js +17 -0
  94. package/daemon/dist/domain/active-occupant.js.map +1 -1
  95. package/daemon/dist/domain/codex-network-default.d.ts +3 -0
  96. package/daemon/dist/domain/codex-network-default.d.ts.map +1 -1
  97. package/daemon/dist/domain/codex-network-default.js +1 -1
  98. package/daemon/dist/domain/codex-network-default.js.map +1 -1
  99. package/daemon/dist/domain/codex-pane-patterns.d.ts +2 -0
  100. package/daemon/dist/domain/codex-pane-patterns.d.ts.map +1 -0
  101. package/daemon/dist/domain/codex-pane-patterns.js +5 -0
  102. package/daemon/dist/domain/codex-pane-patterns.js.map +1 -0
  103. package/daemon/dist/domain/context-monitor.d.ts.map +1 -1
  104. package/daemon/dist/domain/context-monitor.js +46 -22
  105. package/daemon/dist/domain/context-monitor.js.map +1 -1
  106. package/daemon/dist/domain/cwd-resolution.d.ts +8 -0
  107. package/daemon/dist/domain/cwd-resolution.d.ts.map +1 -1
  108. package/daemon/dist/domain/cwd-resolution.js +24 -3
  109. package/daemon/dist/domain/cwd-resolution.js.map +1 -1
  110. package/daemon/dist/domain/gateway/slack/channel-recovery.d.ts.map +1 -1
  111. package/daemon/dist/domain/gateway/slack/channel-recovery.js +4 -3
  112. package/daemon/dist/domain/gateway/slack/channel-recovery.js.map +1 -1
  113. package/daemon/dist/domain/native-process-lineage.d.ts +5 -0
  114. package/daemon/dist/domain/native-process-lineage.d.ts.map +1 -1
  115. package/daemon/dist/domain/native-process-lineage.js +53 -15
  116. package/daemon/dist/domain/native-process-lineage.js.map +1 -1
  117. package/daemon/dist/domain/node-inventory.d.ts.map +1 -1
  118. package/daemon/dist/domain/node-inventory.js +15 -7
  119. package/daemon/dist/domain/node-inventory.js.map +1 -1
  120. package/daemon/dist/domain/node-launcher.d.ts.map +1 -1
  121. package/daemon/dist/domain/node-launcher.js +2 -1
  122. package/daemon/dist/domain/node-launcher.js.map +1 -1
  123. package/daemon/dist/domain/pane-cutover.d.ts +27 -0
  124. package/daemon/dist/domain/pane-cutover.d.ts.map +1 -0
  125. package/daemon/dist/domain/pane-cutover.js +37 -0
  126. package/daemon/dist/domain/pane-cutover.js.map +1 -0
  127. package/daemon/dist/domain/parent-session-env.d.ts +8 -0
  128. package/daemon/dist/domain/parent-session-env.d.ts.map +1 -0
  129. package/daemon/dist/domain/parent-session-env.js +37 -0
  130. package/daemon/dist/domain/parent-session-env.js.map +1 -0
  131. package/daemon/dist/domain/policies/parked-owner-consumer.d.ts +11 -0
  132. package/daemon/dist/domain/policies/parked-owner-consumer.d.ts.map +1 -1
  133. package/daemon/dist/domain/policies/parked-owner-consumer.js +81 -11
  134. package/daemon/dist/domain/policies/parked-owner-consumer.js.map +1 -1
  135. package/daemon/dist/domain/profile-resolver.d.ts.map +1 -1
  136. package/daemon/dist/domain/profile-resolver.js +2 -3
  137. package/daemon/dist/domain/profile-resolver.js.map +1 -1
  138. package/daemon/dist/domain/proof/judgments.d.ts +10 -5
  139. package/daemon/dist/domain/proof/judgments.d.ts.map +1 -1
  140. package/daemon/dist/domain/proof/judgments.js +27 -19
  141. package/daemon/dist/domain/proof/judgments.js.map +1 -1
  142. package/daemon/dist/domain/provider/codex-limit-banner.d.ts +2 -2
  143. package/daemon/dist/domain/provider/codex-limit-banner.d.ts.map +1 -1
  144. package/daemon/dist/domain/provider/codex-limit-banner.js +56 -9
  145. package/daemon/dist/domain/provider/codex-limit-banner.js.map +1 -1
  146. package/daemon/dist/domain/provider/codex-usage-reader.d.ts +31 -0
  147. package/daemon/dist/domain/provider/codex-usage-reader.d.ts.map +1 -0
  148. package/daemon/dist/domain/provider/codex-usage-reader.js +115 -0
  149. package/daemon/dist/domain/provider/codex-usage-reader.js.map +1 -0
  150. package/daemon/dist/domain/provider/codex-usage-windows.d.ts +78 -0
  151. package/daemon/dist/domain/provider/codex-usage-windows.d.ts.map +1 -0
  152. package/daemon/dist/domain/provider/codex-usage-windows.js +259 -0
  153. package/daemon/dist/domain/provider/codex-usage-windows.js.map +1 -0
  154. package/daemon/dist/domain/provider/provider-service-impl.d.ts +10 -0
  155. package/daemon/dist/domain/provider/provider-service-impl.d.ts.map +1 -1
  156. package/daemon/dist/domain/provider/provider-service-impl.js +27 -1
  157. package/daemon/dist/domain/provider/provider-service-impl.js.map +1 -1
  158. package/daemon/dist/domain/provider/provider-service.d.ts +5 -0
  159. package/daemon/dist/domain/provider/provider-service.d.ts.map +1 -1
  160. package/daemon/dist/domain/provider/provider-types.d.ts +65 -0
  161. package/daemon/dist/domain/provider/provider-types.d.ts.map +1 -1
  162. package/daemon/dist/domain/ps-projection.d.ts +5 -2
  163. package/daemon/dist/domain/ps-projection.d.ts.map +1 -1
  164. package/daemon/dist/domain/ps-projection.js +27 -25
  165. package/daemon/dist/domain/ps-projection.js.map +1 -1
  166. package/daemon/dist/domain/queue-repository.d.ts +2 -0
  167. package/daemon/dist/domain/queue-repository.d.ts.map +1 -1
  168. package/daemon/dist/domain/queue-repository.js +16 -3
  169. package/daemon/dist/domain/queue-repository.js.map +1 -1
  170. package/daemon/dist/domain/queue-stuck-sweep.d.ts.map +1 -1
  171. package/daemon/dist/domain/queue-stuck-sweep.js +21 -7
  172. package/daemon/dist/domain/queue-stuck-sweep.js.map +1 -1
  173. package/daemon/dist/domain/restore-check-service.d.ts +8 -0
  174. package/daemon/dist/domain/restore-check-service.d.ts.map +1 -1
  175. package/daemon/dist/domain/restore-check-service.js +12 -3
  176. package/daemon/dist/domain/restore-check-service.js.map +1 -1
  177. package/daemon/dist/domain/restore-orchestrator.d.ts +4 -0
  178. package/daemon/dist/domain/restore-orchestrator.d.ts.map +1 -1
  179. package/daemon/dist/domain/restore-orchestrator.js +34 -5
  180. package/daemon/dist/domain/restore-orchestrator.js.map +1 -1
  181. package/daemon/dist/domain/restore-plan-preview.d.ts +4 -0
  182. package/daemon/dist/domain/restore-plan-preview.d.ts.map +1 -1
  183. package/daemon/dist/domain/restore-plan-preview.js +14 -3
  184. package/daemon/dist/domain/restore-plan-preview.js.map +1 -1
  185. package/daemon/dist/domain/rigspec-preflight.d.ts.map +1 -1
  186. package/daemon/dist/domain/rigspec-preflight.js +7 -6
  187. package/daemon/dist/domain/rigspec-preflight.js.map +1 -1
  188. package/daemon/dist/domain/runtime-adapter.d.ts +1 -0
  189. package/daemon/dist/domain/runtime-adapter.d.ts.map +1 -1
  190. package/daemon/dist/domain/runtime-adapter.js.map +1 -1
  191. package/daemon/dist/domain/scope/scope-view-projection.d.ts +4 -2
  192. package/daemon/dist/domain/scope/scope-view-projection.d.ts.map +1 -1
  193. package/daemon/dist/domain/scope/scope-view-projection.js +6 -4
  194. package/daemon/dist/domain/scope/scope-view-projection.js.map +1 -1
  195. package/daemon/dist/domain/seat-lifecycle-service.d.ts +117 -2
  196. package/daemon/dist/domain/seat-lifecycle-service.d.ts.map +1 -1
  197. package/daemon/dist/domain/seat-lifecycle-service.js +335 -74
  198. package/daemon/dist/domain/seat-lifecycle-service.js.map +1 -1
  199. package/daemon/dist/domain/seat-restart-in-place.d.ts +292 -0
  200. package/daemon/dist/domain/seat-restart-in-place.d.ts.map +1 -0
  201. package/daemon/dist/domain/seat-restart-in-place.js +895 -0
  202. package/daemon/dist/domain/seat-restart-in-place.js.map +1 -0
  203. package/daemon/dist/domain/seat-structural-activity-service.d.ts +1 -1
  204. package/daemon/dist/domain/seat-structural-activity-service.d.ts.map +1 -1
  205. package/daemon/dist/domain/seat-structural-activity-service.js +5 -6
  206. package/daemon/dist/domain/seat-structural-activity-service.js.map +1 -1
  207. package/daemon/dist/domain/session-fingerprinter.d.ts.map +1 -1
  208. package/daemon/dist/domain/session-fingerprinter.js +9 -5
  209. package/daemon/dist/domain/session-fingerprinter.js.map +1 -1
  210. package/daemon/dist/domain/session-registry.d.ts +3 -0
  211. package/daemon/dist/domain/session-registry.d.ts.map +1 -1
  212. package/daemon/dist/domain/session-registry.js +6 -1
  213. package/daemon/dist/domain/session-registry.js.map +1 -1
  214. package/daemon/dist/domain/session-transport.d.ts +33 -3
  215. package/daemon/dist/domain/session-transport.d.ts.map +1 -1
  216. package/daemon/dist/domain/session-transport.js +391 -21
  217. package/daemon/dist/domain/session-transport.js.map +1 -1
  218. package/daemon/dist/domain/startup-orchestrator.d.ts +2 -0
  219. package/daemon/dist/domain/startup-orchestrator.d.ts.map +1 -1
  220. package/daemon/dist/domain/startup-orchestrator.js +4 -3
  221. package/daemon/dist/domain/startup-orchestrator.js.map +1 -1
  222. package/daemon/dist/domain/successor-session-launcher.d.ts +3 -7
  223. package/daemon/dist/domain/successor-session-launcher.d.ts.map +1 -1
  224. package/daemon/dist/domain/successor-session-launcher.js +6 -32
  225. package/daemon/dist/domain/successor-session-launcher.js.map +1 -1
  226. package/daemon/dist/domain/types.d.ts +29 -0
  227. package/daemon/dist/domain/types.d.ts.map +1 -1
  228. package/daemon/dist/domain/types.js.map +1 -1
  229. package/daemon/dist/domain/user-settings/settings-store.d.ts +1 -1
  230. package/daemon/dist/domain/user-settings/settings-store.d.ts.map +1 -1
  231. package/daemon/dist/domain/user-settings/settings-store.js +31 -0
  232. package/daemon/dist/domain/user-settings/settings-store.js.map +1 -1
  233. package/daemon/dist/domain/wake-resolver.js +2 -2
  234. package/daemon/dist/domain/wake-resolver.js.map +1 -1
  235. package/daemon/dist/domain/watchdog-jobs-repository.d.ts.map +1 -1
  236. package/daemon/dist/domain/watchdog-jobs-repository.js +19 -3
  237. package/daemon/dist/domain/watchdog-jobs-repository.js.map +1 -1
  238. package/daemon/dist/domain/whoami-service.d.ts +4 -1
  239. package/daemon/dist/domain/whoami-service.d.ts.map +1 -1
  240. package/daemon/dist/domain/whoami-service.js +25 -19
  241. package/daemon/dist/domain/whoami-service.js.map +1 -1
  242. package/daemon/dist/domain/workspace/project-read.d.ts +2 -0
  243. package/daemon/dist/domain/workspace/project-read.d.ts.map +1 -1
  244. package/daemon/dist/domain/workspace/project-read.js +19 -8
  245. package/daemon/dist/domain/workspace/project-read.js.map +1 -1
  246. package/daemon/dist/index.d.ts.map +1 -1
  247. package/daemon/dist/index.js +6 -0
  248. package/daemon/dist/index.js.map +1 -1
  249. package/daemon/dist/routes/chat.d.ts.map +1 -1
  250. package/daemon/dist/routes/chat.js +23 -2
  251. package/daemon/dist/routes/chat.js.map +1 -1
  252. package/daemon/dist/routes/proof.d.ts.map +1 -1
  253. package/daemon/dist/routes/proof.js +99 -10
  254. package/daemon/dist/routes/proof.js.map +1 -1
  255. package/daemon/dist/routes/provider.d.ts.map +1 -1
  256. package/daemon/dist/routes/provider.js +31 -0
  257. package/daemon/dist/routes/provider.js.map +1 -1
  258. package/daemon/dist/routes/queue.d.ts.map +1 -1
  259. package/daemon/dist/routes/queue.js +18 -6
  260. package/daemon/dist/routes/queue.js.map +1 -1
  261. package/daemon/dist/routes/rigs.js +5 -3
  262. package/daemon/dist/routes/rigs.js.map +1 -1
  263. package/daemon/dist/routes/scopes.d.ts.map +1 -1
  264. package/daemon/dist/routes/scopes.js +5 -3
  265. package/daemon/dist/routes/scopes.js.map +1 -1
  266. package/daemon/dist/routes/seat.d.ts.map +1 -1
  267. package/daemon/dist/routes/seat.js +32 -0
  268. package/daemon/dist/routes/seat.js.map +1 -1
  269. package/daemon/dist/startup.d.ts.map +1 -1
  270. package/daemon/dist/startup.js +12 -2
  271. package/daemon/dist/startup.js.map +1 -1
  272. package/daemon/docs/reference/agent-startup-guide.md +19 -0
  273. package/daemon/docs/reference/keeping-a-watch.md +156 -0
  274. package/daemon/docs/reference/rig-spec.md +2 -2
  275. package/daemon/docs/reference/sdlc-conventions.md +11 -1
  276. package/daemon/docs/reference/slack-app-setup.md +6 -4
  277. package/daemon/docs/reference/whats-new.md +135 -134
  278. package/daemon/specs/agents/shared/skills/core/openrig-skills/SKILL.md +1 -1
  279. package/dist/build-info.js +3 -3
  280. package/dist/commands/config.d.ts.map +1 -1
  281. package/dist/commands/config.js +2 -0
  282. package/dist/commands/config.js.map +1 -1
  283. package/dist/commands/daemon.d.ts.map +1 -1
  284. package/dist/commands/daemon.js +7 -0
  285. package/dist/commands/daemon.js.map +1 -1
  286. package/dist/commands/proof.d.ts.map +1 -1
  287. package/dist/commands/proof.js +11 -5
  288. package/dist/commands/proof.js.map +1 -1
  289. package/dist/commands/provider.d.ts.map +1 -1
  290. package/dist/commands/provider.js +72 -0
  291. package/dist/commands/provider.js.map +1 -1
  292. package/dist/commands/ps.d.ts +4 -0
  293. package/dist/commands/ps.d.ts.map +1 -1
  294. package/dist/commands/ps.js +13 -4
  295. package/dist/commands/ps.js.map +1 -1
  296. package/dist/commands/queue.d.ts +15 -5
  297. package/dist/commands/queue.d.ts.map +1 -1
  298. package/dist/commands/queue.js +113 -37
  299. package/dist/commands/queue.js.map +1 -1
  300. package/dist/commands/scope.d.ts.map +1 -1
  301. package/dist/commands/scope.js +57 -36
  302. package/dist/commands/scope.js.map +1 -1
  303. package/dist/commands/seat.d.ts.map +1 -1
  304. package/dist/commands/seat.js +161 -10
  305. package/dist/commands/seat.js.map +1 -1
  306. package/dist/commands/start.d.ts.map +1 -1
  307. package/dist/commands/start.js +4 -3
  308. package/dist/commands/start.js.map +1 -1
  309. package/dist/commands/up.d.ts.map +1 -1
  310. package/dist/commands/up.js +10 -0
  311. package/dist/commands/up.js.map +1 -1
  312. package/dist/config-store.d.ts +7 -1
  313. package/dist/config-store.d.ts.map +1 -1
  314. package/dist/config-store.js +43 -0
  315. package/dist/config-store.js.map +1 -1
  316. package/dist/lib/scope/mission-composition.d.ts +5 -1
  317. package/dist/lib/scope/mission-composition.d.ts.map +1 -1
  318. package/dist/lib/scope/mission-composition.js +61 -1
  319. package/dist/lib/scope/mission-composition.js.map +1 -1
  320. package/dist/lib/scope/scope-fs.d.ts +2 -1
  321. package/dist/lib/scope/scope-fs.d.ts.map +1 -1
  322. package/dist/lib/scope/scope-fs.js +4 -4
  323. package/dist/lib/scope/scope-fs.js.map +1 -1
  324. package/dist/lib/scope/slice-claims.d.ts +8 -0
  325. package/dist/lib/scope/slice-claims.d.ts.map +1 -0
  326. package/dist/lib/scope/slice-claims.js +88 -0
  327. package/dist/lib/scope/slice-claims.js.map +1 -0
  328. package/dist/queue-receipt.d.ts +41 -0
  329. package/dist/queue-receipt.d.ts.map +1 -0
  330. package/dist/queue-receipt.js +272 -0
  331. package/dist/queue-receipt.js.map +1 -0
  332. package/package.json +1 -1
  333. package/tui/dist/config/config-model.d.ts.map +1 -1
  334. package/tui/dist/config/config-model.js +2 -0
  335. package/tui/dist/config/config-model.js.map +1 -1
  336. package/tui/dist/hydrate.d.ts.map +1 -1
  337. package/tui/dist/hydrate.js +11 -4
  338. package/tui/dist/hydrate.js.map +1 -1
  339. package/tui/dist/pulse/pulse-model.d.ts +1 -0
  340. package/tui/dist/pulse/pulse-model.d.ts.map +1 -1
  341. package/tui/dist/pulse/pulse-model.js +7 -3
  342. package/tui/dist/pulse/pulse-model.js.map +1 -1
  343. package/tui/dist/pulse/render-pulse.d.ts.map +1 -1
  344. package/tui/dist/pulse/render-pulse.js +3 -1
  345. package/tui/dist/pulse/render-pulse.js.map +1 -1
  346. package/tui/dist/render.d.ts.map +1 -1
  347. package/tui/dist/render.js +26 -11
  348. package/tui/dist/render.js.map +1 -1
  349. package/tui/dist/types.d.ts +3 -0
  350. package/tui/dist/types.d.ts.map +1 -1
  351. package/ui/dist/assets/{index-D5n8EwkG.js → index-DhmxKuZf.js} +159 -159
  352. package/ui/dist/index.html +1 -1
@@ -7,6 +7,7 @@ import { observeSolePane } from "./pane-binding-observation.js";
7
7
  import { createHash } from "node:crypto";
8
8
  import { NativePermissionStore } from "./native-permission-store.js";
9
9
  import { validateNativePermissionSelection, unresolvedClaudePermissionModes } from "./native-permission-selection.js";
10
+ import { CodexInPlaceRestart, } from "./seat-restart-in-place.js";
10
11
  /**
11
12
  * S5 (OPR.0.5.4.7) — the seat-lifecycle verb surface: set-model, single-seat stop,
12
13
  * dead-session clean. One coherent design (KI-5.3-9):
@@ -36,6 +37,9 @@ export class SeatLifecycleService {
36
37
  runtimeAdapters;
37
38
  occupantInvalidator;
38
39
  activityOracle;
40
+ inPlaceRestartIo;
41
+ inPlaceRestartTiming;
42
+ inPlaceRestartDaemonStartedAt;
39
43
  constructor(deps) {
40
44
  if (deps.db !== deps.rigRepo.db)
41
45
  throw new Error("SeatLifecycleService: rigRepo must share the same db handle");
@@ -54,6 +58,9 @@ export class SeatLifecycleService {
54
58
  this.runtimeAdapters = deps.runtimeAdapters ?? {};
55
59
  this.occupantInvalidator = deps.occupantInvalidator ?? null;
56
60
  this.activityOracle = deps.activityOracle ?? null;
61
+ this.inPlaceRestartIo = deps.inPlaceRestartIo;
62
+ this.inPlaceRestartTiming = deps.inPlaceRestartTiming;
63
+ this.inPlaceRestartDaemonStartedAt = deps.inPlaceRestartDaemonStartedAt;
57
64
  }
58
65
  async setModel(input) {
59
66
  const required = this.requireReason(input.reason);
@@ -174,7 +181,7 @@ export class SeatLifecycleService {
174
181
  guidance: "A dead seat with stale records is returned to launchable with: rig seat clean",
175
182
  };
176
183
  }
177
- return this.stopManagedTmuxSeat(resolved, session, input.reason, input.operator);
184
+ return this.stopManagedTmuxSeat(resolved, session, input.reason, input.operator, true);
178
185
  }
179
186
  async cleanSeat(input) {
180
187
  const required = this.requireReason(input.reason);
@@ -309,30 +316,18 @@ export class SeatLifecycleService {
309
316
  });
310
317
  return { ...result, message: result.ok ? "Configured context delivered to the existing fresh conversation." : result.errors.join("; ") };
311
318
  }
312
- /** Deliberately replace exactly one managed seat with a blank native occupant. */
313
- async launchFresh(input) {
314
- const required = this.requireReason(input.reason);
315
- if (required)
316
- return required;
317
- if (input.fresh !== true) {
318
- return {
319
- ok: false,
320
- code: "fresh_required",
321
- message: "Explicit fresh launch requires fresh=true (--fresh); no continuity mode is inferred.",
322
- };
323
- }
324
- const resolved = this.resolveSeat(input.seatRef);
325
- if ("code" in resolved)
326
- return resolved;
327
- const guard = this.tmuxAdapter.deliveryGuard;
328
- if (guard && !guard.ownsLifecycle(resolved.nodeId)) {
329
- return guard.lifecycle([resolved.nodeId], () => this.launchFresh(input));
330
- }
319
+ /**
320
+ * Resolve a seat snapshot into current launch settings and persisted startup context.
321
+ * Return a refusal for stale seats, unavailable services, or runtime/context mismatch.
322
+ * Reads only: callers receive no reservation or launch guarantee. Execution repeats
323
+ * this resolution under its lifecycle lock rather than trusting an earlier plan.
324
+ */
325
+ resolveFreshLaunch(resolved, seatRef) {
331
326
  const seat = this.describe(resolved);
332
327
  const rig = this.rigRepo.getRig(seat.rigId);
333
328
  const node = rig?.nodes.find((candidate) => candidate.id === seat.nodeId);
334
329
  if (!rig || !node) {
335
- return { ok: false, code: "seat_not_found", message: `Seat "${input.seatRef}" no longer exists.`, guidance: SEAT_LOOKUP_GUIDANCE };
330
+ return { ok: false, code: "seat_not_found", message: `Seat "${seatRef}" no longer exists.`, guidance: SEAT_LOOKUP_GUIDANCE };
336
331
  }
337
332
  if (!this.nodeLauncher || !this.startupOrchestrator) {
338
333
  return { ok: false, code: "launch_unavailable", message: "Fresh-launch services are unavailable in this daemon." };
@@ -357,15 +352,197 @@ export class SeatLifecycleService {
357
352
  }
358
353
  const canonicalSessionName = deriveCanonicalFromEntry(resolved.entry)
359
354
  ?? deriveSessionName(seat.rigName, seat.logicalId);
360
- const retiringRows = this.nonTerminalSessions(node.id);
361
- if (retiringRows.some((row) => row.origin === "claimed")) {
355
+ return { ok: true, resolved, seat, rig, node, adapter, startup: startup.context, canonicalSessionName, nodeLauncher: this.nodeLauncher, startupOrchestrator: this.startupOrchestrator };
356
+ }
357
+ /**
358
+ * Validate an observed canonical collision against current managed rows and binding.
359
+ * `stop` authorizes only this matching occupant; it cannot authorize adopted or
360
+ * mismatched sessions. Return its session row or a refusal, including unknown pane
361
+ * observations, without stopping, repairing, or starting a tmux server.
362
+ */
363
+ async validateFreshCollision(resolved, canonicalSessionName, stop) {
364
+ const currentSession = this.latestSession(resolved.nodeId);
365
+ const currentBinding = this.sessionRegistry.getBindingForNode(resolved.nodeId);
366
+ const currentManaged = currentSession !== null
367
+ && !TERMINAL_SESSION_STATUSES.has(currentSession.status)
368
+ && currentSession.origin !== "claimed"
369
+ && currentSession.session_name === canonicalSessionName
370
+ && currentBinding?.tmuxSession === canonicalSessionName;
371
+ if (!currentManaged) {
362
372
  return {
363
373
  ok: false,
364
- code: "claimed_session",
365
- message: `Seat "${input.seatRef}" has an adopted/operator-owned occupant; fresh launch refuses even with --stop.`,
374
+ code: "unmanaged_session_collision",
375
+ message: `Canonical tmux session "${canonicalSessionName}" exists but is not owned by this seat's current managed rows; refusing to overwrite it.`,
376
+ };
377
+ }
378
+ if (!stop) {
379
+ return {
380
+ ok: false,
381
+ code: "session_live",
382
+ message: `Seat "${canonicalSessionName}" is live; fresh launch refuses without --stop.`,
383
+ guidance: "Re-run with --stop to end exactly this managed occupant, or use rig handover to carry context.",
384
+ };
385
+ }
386
+ const observedPane = await observeSolePane(this.tmuxAdapter, canonicalSessionName);
387
+ if (!observedPane.ok && observedPane.code === "tmux_unavailable") {
388
+ return {
389
+ ok: false,
390
+ code: "tmux_probe_failed",
391
+ message: `${observedPane.detail}; fresh launch refuses rather than kill without live occupant identity.`,
392
+ };
393
+ }
394
+ if (!observedPane.ok || observedPane.pane !== currentBinding?.tmuxPane) {
395
+ return {
396
+ ok: false,
397
+ code: "unmanaged_session_collision",
398
+ message: `Canonical tmux session "${canonicalSessionName}" is live, but its pane does not match this seat's current managed binding; refusing to stop it.`,
399
+ };
400
+ }
401
+ return currentSession;
402
+ }
403
+ /**
404
+ * Check historical rows/bindings that clean would touch, excluding the canonical name.
405
+ * Read-only tmux probes reject adopted, live, or unreadable historical occupants
406
+ * before any stop. Null means no historical blocker was observed; the caller must
407
+ * still validate the canonical occupant and recheck absence before launching.
408
+ */
409
+ async validateFreshHistory(nodeId, canonicalSessionName, seatRef) {
410
+ const rows = this.nonTerminalSessions(nodeId);
411
+ if (rows.some(row => row.origin === "claimed")) {
412
+ return {
413
+ ok: false, code: "claimed_session",
414
+ message: `Seat "${seatRef}" has an adopted/operator-owned occupant; fresh launch refuses even with --stop.`,
366
415
  guidance: "Stop the adopted process yourself, then run rig seat clean before launching fresh.",
367
416
  };
368
417
  }
418
+ const binding = this.sessionRegistry.getBindingForNode(nodeId);
419
+ const names = new Set([...rows.map(row => row.session_name), ...(binding?.tmuxSession ? [binding.tmuxSession] : [])]);
420
+ for (const name of names) {
421
+ if (name === canonicalSessionName)
422
+ continue;
423
+ const probe = await this.probeLiveness(name, "fresh launch refuses while historical occupant state is unknown");
424
+ if ("code" in probe)
425
+ return probe;
426
+ if (probe.state === "present")
427
+ return {
428
+ ok: false, code: "session_live",
429
+ message: `Historical session "${name}" is still live; fresh launch refuses to change this seat.`,
430
+ guidance: "rig seat stop targets the seat's latest session, not a selected historical session; it may stop the current occupant instead.",
431
+ };
432
+ }
433
+ return null;
434
+ }
435
+ /**
436
+ * Snapshot one seat's proposed fresh launch; `fresh` is mandatory and `stop` is intent.
437
+ * No lifecycle lock, repair, material projection, native launch or persistent write
438
+ * is entered. Siblings are listed as unchanged; no seat is reserved by the result.
439
+ * Known blockers set launchable=false; otherwise incomplete observations yield null.
440
+ * Unreadable tmux remains incomplete, never readiness. No launch command is built.
441
+ * Errors are reduced to safe codes;
442
+ * startup text, credentials and process output are not included in the response.
443
+ */
444
+ async planFresh(input) {
445
+ const refusal = (error) => ({
446
+ ...error, planOnly: true, complete: error.code !== "tmux_probe_failed", launchable: false,
447
+ // Parser/probe errors can embed persisted startup content or process output.
448
+ message: `Fresh launch preview refused: ${error.code}.`,
449
+ });
450
+ if (!input.fresh)
451
+ return refusal({ ok: false, code: "fresh_required", message: "--plan requires --fresh." });
452
+ const resolved = this.resolveSeat(input.seatRef);
453
+ if ("code" in resolved)
454
+ return refusal(resolved);
455
+ const prepared = this.resolveFreshLaunch(resolved, input.seatRef);
456
+ if ("code" in prepared)
457
+ return refusal(prepared);
458
+ const { seat, rig, node, startup, canonicalSessionName } = prepared;
459
+ const blockers = [];
460
+ const warnings = ["Snapshot only; execution resolves and validates again. Native readiness is not checked."];
461
+ let complete = true;
462
+ let tmuxUnknown = false;
463
+ const guard = this.tmuxAdapter.deliveryGuard?.preference(node.id);
464
+ if (guard?.effective || guard?.desired)
465
+ blockers.push({ code: "typing_guard_enabled", message: "Typing protection blocks lifecycle operations for this seat." });
466
+ const record = (error) => {
467
+ if (error.code === "tmux_probe_failed") {
468
+ complete = false;
469
+ tmuxUnknown = true;
470
+ warnings.push("tmux state is unknown; no server was started and no occupant was changed.");
471
+ }
472
+ else if (error.code === "claimed_session" || error.code === "session_live") {
473
+ blockers.push({ code: error.code, message: error.message, guidance: error.guidance });
474
+ }
475
+ else
476
+ blockers.push({ code: error.code, message: `Fresh launch would be refused: ${error.code}.` });
477
+ };
478
+ const history = await this.validateFreshHistory(node.id, canonicalSessionName, input.seatRef);
479
+ if (history)
480
+ record(history);
481
+ const probe = await this.probeLiveness(canonicalSessionName, "preview does not repair tmux");
482
+ const currentOccupant = "code" in probe ? "unknown" : probe.state;
483
+ let stopRequired = currentOccupant === "absent" ? false : null;
484
+ let owned = false;
485
+ if ("code" in probe)
486
+ record(probe);
487
+ else if (probe.state === "present") {
488
+ // Check ownership even without --stop; presence alone is not permission to stop.
489
+ const collision = await this.validateFreshCollision(resolved, canonicalSessionName, true);
490
+ if ("code" in collision)
491
+ record(collision);
492
+ else {
493
+ owned = true;
494
+ stopRequired = true;
495
+ if (!input.stop)
496
+ blockers.push({ code: "session_live", message: "A live managed occupant requires --stop." });
497
+ }
498
+ }
499
+ const launchable = blockers.length > 0 ? false : complete ? true : null;
500
+ const siblings = rig.nodes.filter(n => n.id !== node.id).map(n => ({
501
+ logicalId: n.logicalId, sessionName: n.binding?.tmuxSession ?? null, effect: "unchanged",
502
+ }));
503
+ return {
504
+ ok: true, planOnly: true, complete, launchable, seat,
505
+ sessionName: canonicalSessionName, currentOccupant,
506
+ stopRequired, wouldStop: blockers.length > 0 ? false : tmuxUnknown ? null : owned && input.stop === true,
507
+ blockers, warnings, siblings,
508
+ startup: { projectionCount: startup.plan.entries.length,
509
+ fileCount: startup.resolvedStartupFiles.filter(f => f.appliesOn.includes("fresh_start")).length,
510
+ actionCount: startup.startupActions.filter(a => a.appliesOn.includes("fresh_start")).length },
511
+ };
512
+ }
513
+ /**
514
+ * Execute a fresh replacement of exactly one seat, requiring fresh intent and reason.
515
+ * Resolve configuration again under the lifecycle lock, reject unsafe historical or
516
+ * canonical occupants, and require positive absence before creating a new occupant.
517
+ * Unlike planFresh this mutates lifecycle/startup state; an earlier preview grants
518
+ * no authority to skip validation. Sibling seats are never included in the operation.
519
+ */
520
+ async launchFresh(input) {
521
+ const required = this.requireReason(input.reason);
522
+ if (required)
523
+ return required;
524
+ if (input.fresh !== true) {
525
+ return {
526
+ ok: false,
527
+ code: "fresh_required",
528
+ message: "Explicit fresh launch requires fresh=true (--fresh); no continuity mode is inferred.",
529
+ };
530
+ }
531
+ const resolved = this.resolveSeat(input.seatRef);
532
+ if ("code" in resolved)
533
+ return resolved;
534
+ const guard = this.tmuxAdapter.deliveryGuard;
535
+ if (guard && !guard.ownsLifecycle(resolved.nodeId)) {
536
+ return guard.lifecycle([resolved.nodeId], () => this.launchFresh(input));
537
+ }
538
+ const prepared = this.resolveFreshLaunch(resolved, input.seatRef);
539
+ if ("code" in prepared)
540
+ return prepared;
541
+ const { seat, node, adapter, startup, canonicalSessionName, nodeLauncher, startupOrchestrator } = prepared;
542
+ const historyRefusal = await this.validateFreshHistory(resolved.nodeId, canonicalSessionName, input.seatRef);
543
+ if (historyRefusal)
544
+ return historyRefusal;
545
+ const retiringRows = this.nonTerminalSessions(node.id);
369
546
  // Detached is terminal for process cleanup, but remains a reboot candidate.
370
547
  // A deliberate fresh launch must retire that prior history as well.
371
548
  const supersededSessionIds = this.db.prepare("SELECT id FROM sessions WHERE node_id = ? AND status NOT IN ('superseded', 'exited')").all(node.id).map((row) => row.id);
@@ -403,44 +580,10 @@ export class SeatLifecycleService {
403
580
  if ("code" in canonicalProbe)
404
581
  return canonicalProbe;
405
582
  if (canonicalProbe.state === "present") {
406
- const currentSession = this.latestSession(node.id);
407
- const currentBinding = this.sessionRegistry.getBindingForNode(node.id);
408
- const currentManaged = currentSession !== null
409
- && !TERMINAL_SESSION_STATUSES.has(currentSession.status)
410
- && currentSession.origin !== "claimed"
411
- && currentSession.session_name === canonicalSessionName
412
- && currentBinding?.tmuxSession === canonicalSessionName;
413
- if (!currentManaged) {
414
- return {
415
- ok: false,
416
- code: "unmanaged_session_collision",
417
- message: `Canonical tmux session "${canonicalSessionName}" exists but is not owned by this seat's current managed rows; refusing to overwrite it.`,
418
- };
419
- }
420
- if (!input.stop) {
421
- return {
422
- ok: false,
423
- code: "session_live",
424
- message: `Seat "${input.seatRef}" is live; fresh launch refuses without --stop.`,
425
- guidance: "Re-run with --stop to end exactly this managed occupant, or use rig handover to carry context.",
426
- };
427
- }
428
- const observedPane = await observeSolePane(this.tmuxAdapter, canonicalSessionName);
429
- if (!observedPane.ok && observedPane.code === "tmux_unavailable") {
430
- return {
431
- ok: false,
432
- code: "tmux_probe_failed",
433
- message: `${observedPane.detail}; fresh launch refuses rather than kill without live occupant identity.`,
434
- };
435
- }
436
- if (!observedPane.ok || observedPane.pane !== currentBinding?.tmuxPane) {
437
- return {
438
- ok: false,
439
- code: "unmanaged_session_collision",
440
- message: `Canonical tmux session "${canonicalSessionName}" is live, but its pane does not match this seat's current managed binding; refusing to stop it.`,
441
- };
442
- }
443
- const stopped = await this.stopManagedTmuxSeat(resolved, currentSession, input.reason, input.operator);
583
+ const currentSession = await this.validateFreshCollision(resolved, canonicalSessionName, input.stop === true);
584
+ if ("code" in currentSession)
585
+ return currentSession;
586
+ const stopped = await this.stopManagedTmuxSeat(resolved, currentSession, input.reason, input.operator, false);
444
587
  if (!stopped.ok)
445
588
  return stopped;
446
589
  // Stopping the server's last session ends tmux's server, and every probe
@@ -481,7 +624,7 @@ export class SeatLifecycleService {
481
624
  successorSessionName: canonicalSessionName,
482
625
  ...(retiringGeneration ? { retiringGeneration } : {}),
483
626
  });
484
- const launch = await this.nodeLauncher.launchNode(seat.rigId, seat.logicalId, {
627
+ const launch = await nodeLauncher.launchNode(seat.rigId, seat.logicalId, {
485
628
  sessionName: canonicalSessionName,
486
629
  cwd: node.cwd ?? undefined,
487
630
  occupantKind: "fresh",
@@ -500,7 +643,7 @@ export class SeatLifecycleService {
500
643
  supersededSessionIds,
501
644
  retiringGeneration,
502
645
  newGeneration: null,
503
- startupPolicyHash: startup.context.hash,
646
+ startupPolicyHash: startup.hash,
504
647
  model: node.model,
505
648
  effort: node.effort ?? null,
506
649
  reason: input.reason,
@@ -515,7 +658,7 @@ export class SeatLifecycleService {
515
658
  const launchPosture = this.rigRepo.getNodePolicyProvenance(node.id)?.launchPosture
516
659
  ?? this.rigRepo.getRigPolicyProvenance(seat.rigId)?.launchPosture
517
660
  ?? "floor";
518
- const startupResult = await this.startupOrchestrator.startNode({
661
+ const startupResult = await startupOrchestrator.startNode({
519
662
  rigId: seat.rigId,
520
663
  nodeId: node.id,
521
664
  sessionId: launch.session.id,
@@ -528,9 +671,9 @@ export class SeatLifecycleService {
528
671
  launchPosture,
529
672
  },
530
673
  adapter,
531
- plan: startup.context.plan,
532
- resolvedStartupFiles: startup.context.resolvedStartupFiles,
533
- startupActions: startup.context.startupActions,
674
+ plan: startup.plan,
675
+ resolvedStartupFiles: startup.resolvedStartupFiles,
676
+ startupActions: startup.startupActions,
534
677
  isRestore: false,
535
678
  includeDurableObligations: true,
536
679
  sessionName: canonicalSessionName,
@@ -543,7 +686,7 @@ export class SeatLifecycleService {
543
686
  supersededSessionIds,
544
687
  retiringGeneration,
545
688
  newGeneration: generation,
546
- startupPolicyHash: startup.context.hash,
689
+ startupPolicyHash: startup.hash,
547
690
  model: node.model,
548
691
  effort: node.effort ?? null,
549
692
  reason: input.reason,
@@ -608,7 +751,7 @@ export class SeatLifecycleService {
608
751
  ...(nativeSessionId ? {} : { nativeSessionIdReason: "scrape_miss" }),
609
752
  model: node.model,
610
753
  effort: node.effort ?? null,
611
- startupPolicyHash: startup.context.hash,
754
+ startupPolicyHash: startup.hash,
612
755
  reason: input.reason.trim(),
613
756
  operator: input.operator ?? null,
614
757
  status: attentionRequired ? "attention_required" : "ready",
@@ -640,13 +783,125 @@ export class SeatLifecycleService {
640
783
  generation,
641
784
  model: node.model,
642
785
  effort: node.effort ?? undefined,
643
- startupPolicyHash: startup.context.hash,
786
+ startupPolicyHash: startup.hash,
644
787
  supersededSessionIds,
645
788
  warnings: startupResult.warnings,
646
789
  };
647
790
  }
791
+ /**
792
+ * OPR.0.7.0.5 — restart one Codex seat in place so it reads its home's current account: same conversation,
793
+ * same pane, the settings it is running with now. `plan` runs every gate read-only. Activity (mid-turn,
794
+ * needs input) and child processes are reported for the operator to judge, not refused. Identity, typing
795
+ * guard, adopted sessions, unreadable tmux and settings drift are named refusals before any signal.
796
+ */
797
+ async restartInPlace(input) {
798
+ if (!input.plan) {
799
+ const required = this.requireReason(input.reason ?? "");
800
+ if (required)
801
+ return required;
802
+ }
803
+ const resolved = this.resolveSeat(input.seatRef);
804
+ if ("code" in resolved)
805
+ return resolved;
806
+ const prepared = this.inPlaceRestarter();
807
+ if ("code" in prepared)
808
+ return prepared;
809
+ if (input.plan) {
810
+ const target = await this.inPlaceTarget(resolved, input.seatRef);
811
+ return "code" in target ? target : prepared.plan(target);
812
+ }
813
+ // Recorded before waiting for the lease: a restart that ran meanwhile refuses this one (no repeat
814
+ // on a slow reply).
815
+ const seenStartedSeq = prepared.latestStartedSeq(resolved.nodeId);
816
+ const run = async () => {
817
+ const target = await this.inPlaceTarget(resolved, input.seatRef);
818
+ if ("code" in target)
819
+ return target;
820
+ return prepared.execute(target, { reason: input.reason ?? "", operator: input.operator ?? null, seenStartedSeq });
821
+ };
822
+ const guard = this.tmuxAdapter.deliveryGuard;
823
+ return guard && !guard.ownsLifecycle(resolved.nodeId) ? guard.lifecycle([resolved.nodeId], run) : run();
824
+ }
825
+ /** `--verify`: report `moved` only with a completed tool turn since the restart and account-specific evidence. */
826
+ async verifyRestartInPlace(input) {
827
+ const resolved = this.resolveSeat(input.seatRef);
828
+ if ("code" in resolved)
829
+ return resolved;
830
+ const prepared = this.inPlaceRestarter();
831
+ if ("code" in prepared)
832
+ return prepared;
833
+ const target = await this.inPlaceTarget(resolved, input.seatRef);
834
+ return "code" in target ? target : prepared.verify(target, { expectAccount: input.expectAccount ?? null });
835
+ }
836
+ inPlaceRestarter() {
837
+ const adapter = this.runtimeAdapters["codex"];
838
+ if (!adapter?.buildResumeCommand || !adapter.verifyResumeInPane || !adapter.sendResumeCommand) {
839
+ return { ok: false, code: "runtime_adapter_missing", message: "The Codex runtime adapter with in-place resume is unavailable in this daemon." };
840
+ }
841
+ const activity = this.activityOracle?.getSeatState ? this.activityOracle : null;
842
+ return new CodexInPlaceRestart({
843
+ db: this.db, sessionRegistry: this.sessionRegistry, eventBus: this.eventBus, tmux: this.tmuxAdapter,
844
+ codex: adapter, activity, listProcesses: this.listProcesses,
845
+ io: this.inPlaceRestartIo, timing: this.inPlaceRestartTiming, daemonStartedAt: this.inPlaceRestartDaemonStartedAt,
846
+ });
847
+ }
848
+ /** The shared seat refusals, then the binding the relaunch is built from (the handover's posture rules). */
849
+ async inPlaceTarget(resolved, seatRef) {
850
+ const seat = this.describe(resolved);
851
+ const node = this.rigRepo.getRig(seat.rigId)?.nodes.find((candidate) => candidate.id === seat.nodeId);
852
+ if (!node)
853
+ return { ok: false, code: "seat_not_found", message: `Seat "${seatRef}" no longer exists.`, guidance: SEAT_LOOKUP_GUIDANCE };
854
+ if (node.runtime !== "codex") {
855
+ return { ok: false, code: "not_codex", message: `Seat "${seatRef}" runs ${node.runtime ?? "an unknown runtime"}; in-place restart supports Codex seats only.` };
856
+ }
857
+ const preference = this.tmuxAdapter.deliveryGuard?.preference(node.id);
858
+ if (preference?.effective || preference?.desired) {
859
+ return { ok: false, code: "typing_guard_enabled", message: "Typing protection blocks lifecycle operations for this seat; nothing was restarted." };
860
+ }
861
+ const session = this.latestSession(node.id);
862
+ if (!session || TERMINAL_SESSION_STATUSES.has(session.status)) {
863
+ return { ok: false, code: "no_session", message: `Seat "${seatRef}" has no live managed session to restart (checked: latest sessions row).` };
864
+ }
865
+ if (session.origin === "claimed") {
866
+ return { ok: false, code: "claimed_session", message: `Session "${session.session_name}" was adopted (origin=claimed), not launched by OpenRig; in-place restart refuses it.`,
867
+ guidance: "Release an adopted session with: rig unclaim" };
868
+ }
869
+ const probed = await this.probeLiveness(session.session_name, "in-place restart refuses rather than act on an unknown session");
870
+ if ("code" in probed)
871
+ return probed;
872
+ if (probed.state === "absent") {
873
+ return { ok: false, code: "session_not_live", message: `Session "${session.session_name}" is absent in tmux; there is nothing to restart in place.` };
874
+ }
875
+ const binding = this.sessionRegistry.getBindingForNode(node.id);
876
+ if (!binding?.tmuxSession || binding.tmuxSession !== session.session_name || !binding.tmuxPane) {
877
+ return { ok: false, code: "session_not_live", message: `Seat "${seatRef}" has no bound tmux pane for session "${session.session_name}".` };
878
+ }
879
+ let permissionOverride;
880
+ try {
881
+ permissionOverride = new NativePermissionStore(this.db).launchOverride(node.id, "codex");
882
+ }
883
+ catch (error) {
884
+ return { ok: false, code: "permission_selection_refused", message: `Permission selection: ${error.message}` };
885
+ }
886
+ const launchPosture = permissionOverride.launchPosture
887
+ ?? this.rigRepo.getNodePolicyProvenance(node.id)?.launchPosture
888
+ ?? this.rigRepo.getRigPolicyProvenance(seat.rigId)?.launchPosture
889
+ ?? "floor";
890
+ return {
891
+ seat, sessionId: session.id, sessionName: session.session_name,
892
+ saved: { model: node.model ?? null, effort: node.effort ?? null, codexConfigProfile: node.codexConfigProfile ?? null },
893
+ binding: {
894
+ ...binding, cwd: node.cwd ?? ".",
895
+ ...(node.model ? { model: node.model } : {}),
896
+ ...(node.effort ? { effort: node.effort } : {}),
897
+ ...(node.codexConfigProfile ? { codexConfigProfile: node.codexConfigProfile } : {}),
898
+ launchPosture, kernelAuthority: permissionOverride.kernelAuthority, teamPermissionDefault: permissionOverride.teamPermissionDefault,
899
+ nonInterruptive: this.rigRepo.getRigNonInterruptive(seat.rigId),
900
+ },
901
+ };
902
+ }
648
903
  // -- shared internals --
649
- async stopManagedTmuxSeat(resolved, session, reason, operator) {
904
+ async stopManagedTmuxSeat(resolved, session, reason, operator, recordStopIntent) {
650
905
  const seat = this.describe(resolved);
651
906
  const kill = await this.tmuxAdapter.killSession(session.session_name);
652
907
  if (kill && !kill.ok && kill.code !== "session_not_found") {
@@ -658,7 +913,13 @@ export class SeatLifecycleService {
658
913
  }
659
914
  let persisted = null;
660
915
  const tx = this.db.transaction(() => {
661
- this.sessionRegistry.updateStatus(session.id, "exited");
916
+ if (recordStopIntent && kill?.ok) {
917
+ this.sessionRegistry.markIntentionallyStopped(session.id);
918
+ }
919
+ else {
920
+ // An internal replacement stop or an unconfirmed kill must still affect health.
921
+ this.sessionRegistry.updateStatus(session.id, "exited");
922
+ }
662
923
  this.sessionRegistry.clearBinding(resolved.nodeId);
663
924
  persisted = this.eventBus.persistWithinTransaction({
664
925
  type: "session.stopped",