@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
@@ -1,3 +1,4 @@
1
+ import { CODEX_TURN_STATUS_PATTERN } from "./codex-pane-patterns.js";
1
2
  import { randomUUID } from "node:crypto";
2
3
  import { inspectStartupStagedText, startupSubmissionEvidence } from "./startup-submission-evidence.js";
3
4
  export { inspectStartupStagedText } from "./startup-submission-evidence.js";
@@ -37,10 +38,6 @@ const MID_WORK_PATTERNS = [
37
38
  // placeholder counts as idle only through MID_WORK_PATTERNS here, and classifySendReadiness
38
39
  // never lets a placeholder-only verdict override a display-fresh running/needs_input hook.
39
40
  const CODEX_EMPTY_COMPOSER_PATTERN = /^›\s+Ask Codex to do anything\s*$/;
40
- // Codex's live turn-status row: a bullet, a header ("Working", or the reasoning summary Codex shows in its place),
41
- // then the elapsed time and "esc to interrupt" in parentheses, e.g. "• Working (1h 09m 39s • esc to interrupt)".
42
- // Completed output that merely says "Working directory: …" or "Working tree is clean." never matches.
43
- const CODEX_TURN_STATUS_PATTERN = /^[•◦]\s+\S.*\((?:\d+[hms]\s*)+•\s*esc to interrupt\)/;
44
41
  const IDLE_PROMPT_PATTERNS = [
45
42
  /^[❯›]\s*$/, // prompt char + optional whitespace + end-of-line only
46
43
  CODEX_EMPTY_COMPOSER_PATTERN,
@@ -48,11 +45,19 @@ const IDLE_PROMPT_PATTERNS = [
48
45
  const PROMPT_DRAFT_PATTERNS = [
49
46
  /^[❯›]\s+\S/,
50
47
  ];
48
+ // Claude's permission-mode footers: default, accept edits, bypass, auto and plan, optionally after a
49
+ // vim-mode marker such as "-- INSERT --" (#808). A suffix such as "· 1 shell" can follow the mode.
50
+ const CLAUDE_MODE_FOOTER = /^(?:-- [A-Z]+ -- )?(?:⏵⏵ (?:accept edits|bypass permissions|auto mode) on\b|⏸ plan mode on\b|\? for shortcuts\b)/;
51
+ // Sibling pattern identical to CLAUDE_MODE_FOOTER except that it ends in \? for shortcuts$,
52
+ // keeping unframed-composer and selectionLines checks anchored on the default footer (#808).
53
+ const CLAUDE_ANCHORED_MODE_FOOTER = /^(?:-- [A-Z]+ -- )?(?:⏵⏵ (?:accept edits|bypass permissions|auto mode) on\b|⏸ plan mode on\b|\? for shortcuts$)/;
54
+ // Permission mode status footers specifically (excluding shortcuts hint that appears in Codex footers).
55
+ const CLAUDE_PERMISSION_MODE_FOOTER = /(?:-- [A-Z]+ -- )?(?:⏵⏵ (?:accept edits|bypass permissions|auto mode) on\b|⏸ plan mode on\b)/;
51
56
  // Footer hints, not proof of inactivity: Claude also renders its mode bar
52
57
  // during a turn. Current live-status evidence must take precedence below.
53
58
  const IDLE_STATUS_BAR_PATTERNS = [
54
59
  /gpt-\d[\d.]* .+ · Context \[/, // Codex model/context footer
55
- /⏵⏵ accept edits/, // Claude Code edit-accept bar
60
+ CLAUDE_PERMISSION_MODE_FOOTER, // Claude Code mode footers (#808)
56
61
  ];
57
62
  const IDLE_TERMINAL_COMMANDS = new Set(["zsh", "bash", "sh", "fish", "nu", "tmux"]);
58
63
  // OPR.0.4.1.10 — permission / confirmation question signatures. The numbered-selector pattern
@@ -119,9 +124,6 @@ const CLAUDE_STATUS_WARNINGS = [
119
124
  /^tmux focus-events off · add 'set -g focus-events on' to ~\/\.tmux\.conf and re…$/,
120
125
  /^You've used (?:\d|[1-9]\d)% of your weekly limit · resets \d{1,2}(?::\d{2})?(?:am|pm) \(UTC\)$/,
121
126
  ];
122
- // Claude's permission-mode footers: default, accept edits, bypass, auto and plan, optionally after a
123
- // vim-mode marker such as "-- INSERT --" (#808). A suffix such as "· 1 shell" can follow the mode.
124
- const CLAUDE_MODE_FOOTER = /^(?:-- [A-Z]+ -- )?(?:⏵⏵ (?:accept edits|bypass permissions|auto mode) on\b|⏸ plan mode on\b|\? for shortcuts\b)/;
125
127
  // Current Claude status rows need not end in "thinking)" or show "esc to interrupt".
126
128
  // Completed summaries such as "✻ Crunched for 2s" lack the live ellipsis/timer shape.
127
129
  // While a hook runs, the timer follows its label: "(running PostToolUse hook · 3m 12s · …)".
@@ -149,7 +151,7 @@ function findClaudeComposer(paneContent, options = {}) {
149
151
  if (indent === undefined) {
150
152
  // The unframed Claude prompt has the same current status/task block.
151
153
  // Keep Codex footers and a bare prompt with no visible block on their old path.
152
- if (bar < 2 || !/^(?:⏵⏵ (?:accept edits|bypass permissions) on\b|⏸ plan mode on\b|\? for shortcuts$)/.test(lines[bar].trim()))
154
+ if (bar < 2 || !CLAUDE_ANCHORED_MODE_FOOTER.test(lines[bar].trim()))
153
155
  return null;
154
156
  prompt = lines[bar - 1] ?? "";
155
157
  indent = /^([ \t]*)❯\s*$/.exec(prompt)?.[1];
@@ -300,7 +302,7 @@ export function classifyPaneActivity(paneContent, options = {}) {
300
302
  // A complete later empty composer with a recognized Claude bar makes the preceding question history.
301
303
  // Keep draft handling and selectors without this dialog boundary unchanged.
302
304
  const selectionLines = claudeComposer?.framed &&
303
- /^(?:⏵⏵ (?:accept edits|bypass permissions|auto mode) on\b|⏸ plan mode on\b|\? for shortcuts$)/.test(claudeComposer.bar) &&
305
+ CLAUDE_ANCHORED_MODE_FOOTER.test(claudeComposer.bar) &&
304
306
  IDLE_PROMPT_PATTERNS.some(pattern => pattern.test(claudeComposer.text)) &&
305
307
  oldQuestionEnd >= 0 && oldQuestionEnd < promptScanLines.length - 1
306
308
  ? promptScanLines.slice(oldQuestionEnd + 1) : promptScanLines;
@@ -354,7 +356,8 @@ export function classifyPaneActivity(paneContent, options = {}) {
354
356
  CLAUDE_LIVE_STATUS_PATTERN,
355
357
  ...(options.timerlessStatusIsLive ? [CLAUDE_TIMERLESS_STATUS_PATTERN] : []),
356
358
  ]);
357
- if (idleStatusBarLine && (!idleStatusBarLine.includes("⏵⏵ accept edits") || !midWorkEvidence)) {
359
+ const isClaudeStatusBar = CLAUDE_PERMISSION_MODE_FOOTER.test(idleStatusBarLine ?? "");
360
+ if (idleStatusBarLine && (!isClaudeStatusBar || !midWorkEvidence)) {
358
361
  return {
359
362
  state: "agent_idle",
360
363
  reason: "idle_status_bar",
@@ -604,6 +607,98 @@ function countOccurrences(haystack, needle) {
604
607
  }
605
608
  return count;
606
609
  }
610
+ /**
611
+ * Claude indents continuation lines in submitted prompts. Compare the same
612
+ * line content in the sent text and both captures, retaining line breaks and
613
+ * within-line spacing rather than allowing unrelated words to match.
614
+ */
615
+ function normalizeVerificationText(text) {
616
+ return text.replace(/\r?\n[ \t]*/g, "\n");
617
+ }
618
+ /** Match the full envelope with whitespace collapsed, including body and recipient.
619
+ * Raw sends retain their normalized 40-character prefix and spacing. */
620
+ function verificationSnippet(text) {
621
+ const normalized = normalizeVerificationText(text);
622
+ const header = /^From: [^\n]+\nTo: [^\n]+\n(?:Sent: [^\n]+\n)?---\n/.exec(normalized);
623
+ return { snippet: header ? normalized.replace(/\s+/g, " ").trim() : normalized.slice(0, 40), envelope: !!header };
624
+ }
625
+ /** Count whole visible envelope blocks, not prefixes of longer messages.
626
+ * A new envelope, prompt or same-column output ends an indented user block.
627
+ * Whitespace is compared only after retaining boundaries and quote indentation. */
628
+ function countEnvelopeOccurrences(transcript, expected) {
629
+ const lines = transcript.split("\n");
630
+ let count = 0;
631
+ let block = null;
632
+ let blockIndent = 0;
633
+ let blockPrompted = false;
634
+ let inAgentOutput = false;
635
+ const finish = () => {
636
+ if (block?.join("\n").replace(/\s+/g, " ").trim() === expected)
637
+ count++;
638
+ block = null;
639
+ };
640
+ for (let i = 0; i < lines.length; i++) {
641
+ const line = lines[i];
642
+ const indent = /^[ \t]*/.exec(line)[0].length;
643
+ const prompted = /^[❯›]\s+/.test(line.slice(indent));
644
+ const header = line.slice(indent).replace(/^[❯›]\s+/, "");
645
+ const atBoundary = (!block && !inAgentOutput) || indent <= blockIndent;
646
+ const candidate = normalizeVerificationText([header, ...lines.slice(i + 1, i + 5)].join("\n"));
647
+ const envelopeHeader = /^From: [^\n]+\nTo: [^\n]+\n(?:Sent: [^\n]+\n)?---\n/.test(candidate);
648
+ if (atBoundary && envelopeHeader && (!inAgentOutput || prompted)) {
649
+ finish();
650
+ block = [header];
651
+ blockIndent = indent;
652
+ // Flat historical captures have no role columns; retain whole-block
653
+ // equality there instead of treating their own header/body as output.
654
+ blockPrompted = prompted && /^[ \t]*/.exec(lines[i + 1] ?? "")[0].length > indent;
655
+ inAgentOutput = false;
656
+ }
657
+ else if (atBoundary && blockPrompted && line.trim().length > 0) {
658
+ // Any nonblank boundary line is outside an indented user block. Deeper
659
+ // quotes stay in the body, and blank separators do not change its text.
660
+ finish();
661
+ inAgentOutput = true;
662
+ }
663
+ else if (atBoundary && /^[❯›](?:\s|$)/.test(line.slice(indent))) {
664
+ finish();
665
+ }
666
+ else if (block) {
667
+ block.push(line);
668
+ }
669
+ }
670
+ finish();
671
+ return count;
672
+ }
673
+ /** The last prompt marker owns the current input region. Never count it or its
674
+ * continuation lines as submitted transcript, in either capture. If a capture
675
+ * ends at a historical prompt with no later input marker, leave it unconfirmed. */
676
+ function verificationTranscript(content) {
677
+ const lines = (content ?? "").replace(/\r\n/g, "\n").split("\n");
678
+ let inputAt = lastPromptLine(lines);
679
+ if (inputAt >= 0) {
680
+ let indent = /^[ \t]*/.exec(lines[inputAt])[0].length;
681
+ // Claude indents draft continuation lines. A quoted prompt on one of them
682
+ // belongs to the enclosing input, not a new transcript/composer boundary.
683
+ for (let i = inputAt - 1; i >= 0; i--) {
684
+ const prompt = /^([ \t]*)[❯›]/.exec(lines[i]);
685
+ if (prompt && prompt[1].length < indent) {
686
+ inputAt = i;
687
+ indent = prompt[1].length;
688
+ }
689
+ }
690
+ }
691
+ // A visible framed composer starts at its upper rule, not its prompt.
692
+ // Keep quoted/indented rules in the message; require a matching lower frame.
693
+ if (inputAt > 0) {
694
+ const indent = /^[ \t]*/.exec(lines[inputAt])[0];
695
+ const frame = (line) => line.startsWith(indent) &&
696
+ /^─{3,}(?: .+ ─+)?$/.test(line.slice(indent.length).trimEnd());
697
+ if (frame(lines[inputAt - 1]) && lines.slice(inputAt + 1).some(frame))
698
+ inputAt--;
699
+ }
700
+ return (inputAt < 0 ? lines : lines.slice(0, inputAt)).join("\n");
701
+ }
607
702
  /** Map a resolved fan-out target + its recipient list → the EnvelopeScope (ruling 03c35295). The
608
703
  * transport knows the target shape + resolved seats, so it builds the honest scale daemon-side:
609
704
  * DM / multi (full list) / rig- or pod-scoped broadcast (with seat count) / topology. */
@@ -1037,6 +1132,9 @@ export class SessionTransport {
1037
1132
  const pref = guard.preference(target.nodeId);
1038
1133
  return pref.desired || pref.effective ? target : null;
1039
1134
  }
1135
+ /** Deliver text and Enter to the resolved recipient under the send guards.
1136
+ * With verification requested, compare rendered message counts, excluding
1137
+ * agent input; a confirmed render does not prove agent consumption. */
1040
1138
  async send(sessionName, text, opts) {
1041
1139
  const guard = this.tmuxAdapter.deliveryGuard;
1042
1140
  if (!guard)
@@ -1069,7 +1167,44 @@ export class SessionTransport {
1069
1167
  return retainedResult();
1070
1168
  }
1071
1169
  }
1072
- return await guard.operation(sessionName, () => this.sendUnguarded(sessionName, text, opts), async (target) => {
1170
+ // #1084 — the idle wait must not occupy the seat's serial lease: a long
1171
+ // --wait-for-idle inside guard.operation holds up other sends and queue
1172
+ // creates to this seat for the whole wait. The lease-free wait, main's
1173
+ // quick refusals ahead of it, and the occupant binding all live in
1174
+ // preWaitForIdle; the lease is entered only for the idle re-check +
1175
+ // write. A null return means go through guard.operation exactly as on
1176
+ // main (guard held, target unresolvable, or a quick refusal).
1177
+ let sendOpts = opts;
1178
+ if (opts?.waitForIdleMs !== undefined && !opts.submitOnly && !opts.preWaitedIdle) {
1179
+ const pre = await this.preWaitForIdle(sessionName, opts, guard);
1180
+ if (pre === null) {
1181
+ // Fall through with today's path (in-lease wait / retain / throw).
1182
+ }
1183
+ else if (!pre.ok) {
1184
+ return pre.failure;
1185
+ }
1186
+ else {
1187
+ // Occupant check (review round 3): the lease starts only after the
1188
+ // pre-wait, so refuse here when the seat changed hands meanwhile —
1189
+ // exactly as main refuses with guard_target_changed. Retention must
1190
+ // not adopt the new occupant either, so this runs before operation.
1191
+ const current = guard.target(sessionName);
1192
+ if (JSON.stringify(pre.bound) !== JSON.stringify(current)) {
1193
+ return {
1194
+ ok: false,
1195
+ sessionName,
1196
+ sent: false,
1197
+ reason: "guard_target_changed",
1198
+ error: "Input target/occupant changed; no input written.",
1199
+ activity: pre.evidence.activity,
1200
+ waitedMs: pre.evidence.waitedMs,
1201
+ attempts: pre.evidence.attempts,
1202
+ };
1203
+ }
1204
+ sendOpts = { ...opts, preWaitedIdle: pre.evidence, preWaitBound: pre.bound };
1205
+ }
1206
+ }
1207
+ return await guard.operation(sessionName, () => this.sendUnguarded(sessionName, text, sendOpts), async (target) => {
1073
1208
  if (opts?.submitOnly)
1074
1209
  return { ok: false, sessionName, sent: false, reason: "typing_guard_enabled", error: "Typing guard prevents submit-only; no Enter was sent." };
1075
1210
  this.db.transaction(() => {
@@ -1104,6 +1239,131 @@ export class SessionTransport {
1104
1239
  return { ok: false, sessionName, sent: false, reason: error.code ?? "guard_unavailable", error: error.message };
1105
1240
  }
1106
1241
  }
1242
+ /**
1243
+ * #1084/#1103: lease-free idle wait before the serial lease, so a long
1244
+ * --wait-for-idle holds up no other send or queue create to this seat.
1245
+ * Returns the wait evidence plus the occupant bound before the wait (both
1246
+ * threaded into the leased send), a failure result using main's exact
1247
+ * reasons, or null when the send must go through guard.operation exactly
1248
+ * as on main. Order matters: typing-guard decision first, then main's
1249
+ * quick refusals (runtime identity, wait validations, session probe),
1250
+ * then the wait. Only the lookups sit inside try: a late throw surfaces
1251
+ * instead of silently running a second full wait inside the lease.
1252
+ */
1253
+ async preWaitForIdle(sessionName, opts, guard) {
1254
+ const timeoutMs = opts.waitForIdleMs;
1255
+ if (timeoutMs === undefined)
1256
+ return null;
1257
+ let meta;
1258
+ let bound;
1259
+ try {
1260
+ const preTarget = guard.maybeTarget(sessionName);
1261
+ if (!preTarget)
1262
+ return null;
1263
+ const prePref = guard.preference(preTarget.nodeId);
1264
+ if (prePref.effective || prePref.desired)
1265
+ return null;
1266
+ meta = this.getSessionMeta(sessionName);
1267
+ bound = guard.target(sessionName);
1268
+ }
1269
+ catch {
1270
+ return null;
1271
+ }
1272
+ // External CLI seats never wait: main refuses them before anything else,
1273
+ // and a probe or wait would only delay that refusal (or mistake it for
1274
+ // an absent session).
1275
+ if (meta.attachmentType === "external_cli") {
1276
+ return { ok: false, failure: {
1277
+ ok: false,
1278
+ sessionName,
1279
+ reason: "transport_unavailable",
1280
+ error: `Session '${sessionName}' is attached as an external CLI node. Inbound tmux transport is unavailable for this target.`,
1281
+ } };
1282
+ }
1283
+ const runtime = meta.runtime;
1284
+ if (runtime && runtime !== "terminal" && runtime !== "claude-code") {
1285
+ const unverified = await this.unverifiedShellForeground(sessionName, runtime, meta.pane, meta.resumeToken);
1286
+ if (unverified) {
1287
+ return { ok: false, failure: {
1288
+ ok: false,
1289
+ sessionName,
1290
+ sent: false,
1291
+ reason: "target_runtime_unverified",
1292
+ error: `Refused: '${sessionName}' reports ${unverified} as the foreground command, but OpenRig could not verify its expected ${runtime} agent in the bound pane. The agent may still be running behind a wrapper. No text was sent.`,
1293
+ } };
1294
+ }
1295
+ }
1296
+ if (opts.force) {
1297
+ return { ok: false, failure: {
1298
+ ok: false,
1299
+ sessionName,
1300
+ reason: "invalid_wait_for_idle",
1301
+ error: "--wait-for-idle cannot be combined with force. No text was sent.",
1302
+ sent: false,
1303
+ } };
1304
+ }
1305
+ if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
1306
+ return { ok: false, failure: {
1307
+ ok: false,
1308
+ sessionName,
1309
+ reason: "invalid_wait_for_idle",
1310
+ error: "waitForIdleMs must be a positive number. No text was sent.",
1311
+ sent: false,
1312
+ } };
1313
+ }
1314
+ try {
1315
+ const target = this.absenceProbeTarget(sessionName);
1316
+ const observedAt = this.now().toISOString();
1317
+ const probe = await this.tmuxAdapter.probeSession(sessionName);
1318
+ if (probe.state === "absent") {
1319
+ this.recordSessionMissingVerdict(target, observedAt);
1320
+ return { ok: false, failure: {
1321
+ ok: false,
1322
+ sessionName,
1323
+ reason: "session_missing",
1324
+ error: `Session '${sessionName}' not found: tmux reports no session with this name. No text was sent. Check available sessions with: rig ps --nodes`,
1325
+ } };
1326
+ }
1327
+ if (probe.state === "transport_unavailable") {
1328
+ return { ok: false, failure: {
1329
+ ok: false,
1330
+ sessionName,
1331
+ reason: "tmux_unavailable",
1332
+ error: `The tmux server could not be reached (${probe.cause}). Whether session '${sessionName}' exists was not determined. No text was sent.`,
1333
+ } };
1334
+ }
1335
+ }
1336
+ catch (err) {
1337
+ return { ok: false, failure: {
1338
+ ok: false,
1339
+ sessionName,
1340
+ reason: "tmux_unavailable",
1341
+ error: `The tmux session probe failed unexpectedly (${err instanceof Error ? err.message : String(err)}). Whether session '${sessionName}' exists was not determined. No text was sent.`,
1342
+ } };
1343
+ }
1344
+ const deadlineAt = Date.now() + timeoutMs;
1345
+ const preWait = await this.waitForIdle({
1346
+ sessionName,
1347
+ runtime: meta.runtime,
1348
+ attachmentType: meta.attachmentType,
1349
+ timeoutMs,
1350
+ binding: { sessionName, nodeId: meta.nodeId, occupant: meta.occupant, pane: meta.pane },
1351
+ readinessFromPaneOnly: opts.readinessFromPaneOnly === true,
1352
+ });
1353
+ if (!preWait.ok) {
1354
+ return { ok: false, failure: {
1355
+ ok: false,
1356
+ sessionName,
1357
+ reason: preWait.reason,
1358
+ error: preWait.error,
1359
+ sent: false,
1360
+ activity: preWait.activity,
1361
+ waitedMs: preWait.waitedMs,
1362
+ attempts: preWait.attempts,
1363
+ } };
1364
+ }
1365
+ return { ok: true, evidence: { activity: preWait.activity, waitedMs: preWait.waitedMs, attempts: preWait.attempts, deadlineAt }, bound };
1366
+ }
1107
1367
  async sendUnguarded(sessionName, text, opts) {
1108
1368
  let preVerifyContent = null;
1109
1369
  const sessionMeta = this.getSessionMeta(sessionName);
@@ -1282,7 +1542,10 @@ export class SessionTransport {
1282
1542
  }
1283
1543
  return observe({ ok: true, sessionName, outcome: "rendered-unconfirmed", submitOnly: true });
1284
1544
  }
1285
- if (waitForIdleMs !== undefined) {
1545
+ // #1084: when send() already waited lease-free (preWaitedIdle), the wait
1546
+ // below is skipped; otherwise wait here, exactly as before
1547
+ // (typing-guard flip and unresolvable-target races keep today's behavior).
1548
+ if (waitForIdleMs !== undefined && !opts?.preWaitedIdle) {
1286
1549
  const waitResult = await this.waitForIdle({
1287
1550
  sessionName,
1288
1551
  runtime,
@@ -1307,6 +1570,104 @@ export class SessionTransport {
1307
1570
  };
1308
1571
  }
1309
1572
  }
1573
+ else if (opts?.preWaitedIdle && waitForIdleMs !== undefined) {
1574
+ // Occupant check (review round 3): the lease started only after the
1575
+ // pre-wait, so refuse when the seat changed hands meanwhile, exactly
1576
+ // as main refuses with guard_target_changed. No new refusal.
1577
+ const preGuard = this.tmuxAdapter.deliveryGuard;
1578
+ if (preGuard && opts.preWaitBound) {
1579
+ const current = preGuard.target(sessionName);
1580
+ if (JSON.stringify(opts.preWaitBound) !== JSON.stringify(current)) {
1581
+ return {
1582
+ ok: false,
1583
+ sessionName,
1584
+ sent: false,
1585
+ reason: "guard_target_changed",
1586
+ error: "Input target/occupant changed; no input written.",
1587
+ activity: opts.preWaitedIdle.activity,
1588
+ waitedMs: opts.preWaitedIdle.waitedMs,
1589
+ attempts: opts.preWaitedIdle.attempts,
1590
+ };
1591
+ }
1592
+ }
1593
+ // Idle re-check (review round 1 + bot round 2): the wait-mode contract
1594
+ // holds at type time too — only idle types. The budget is measured
1595
+ // from the ORIGINAL deadline (lease-queue time counts too), so the
1596
+ // total wait never exceeds what the caller asked for. Below one poll
1597
+ // interval, waiting buys nothing: one unraced observation decides, so
1598
+ // an idle seat at a dead budget still sends instead of losing a race
1599
+ // against a zero timer.
1600
+ const preEvidence = opts.preWaitedIdle;
1601
+ const deadlineRemainingMs = preEvidence.deadlineAt - Date.now();
1602
+ if (deadlineRemainingMs > this.waitForIdlePollMs) {
1603
+ const rewait = await this.waitForIdle({
1604
+ sessionName,
1605
+ runtime,
1606
+ attachmentType: sessionMeta.attachmentType,
1607
+ timeoutMs: deadlineRemainingMs,
1608
+ // Message-only: the re-wait runs on the leftover budget, but the
1609
+ // timeout names the configured --wait-for-idle value.
1610
+ timeoutLabelMs: waitForIdleMs,
1611
+ binding: observed?.binding,
1612
+ readinessFromPaneOnly: opts.readinessFromPaneOnly === true,
1613
+ });
1614
+ waitEvidence = {
1615
+ activity: rewait.activity,
1616
+ waitedMs: preEvidence.waitedMs + rewait.waitedMs,
1617
+ attempts: preEvidence.attempts + rewait.attempts,
1618
+ };
1619
+ if (!rewait.ok) {
1620
+ return {
1621
+ ok: false,
1622
+ sessionName,
1623
+ reason: rewait.reason,
1624
+ error: rewait.error,
1625
+ sent: false,
1626
+ ...waitEvidence,
1627
+ };
1628
+ }
1629
+ }
1630
+ else {
1631
+ const recheck = await this.classifySendReadiness({
1632
+ sessionName,
1633
+ runtime,
1634
+ attachmentType: sessionMeta.attachmentType,
1635
+ binding: observed?.binding,
1636
+ readinessFromPaneOnly: opts.readinessFromPaneOnly === true,
1637
+ });
1638
+ if (recheck.state !== "idle") {
1639
+ const late = recheck.state === "needs_input"
1640
+ ? {
1641
+ reason: "target_needs_input",
1642
+ error: `Refused: '${sessionName}' is at an interactive prompt (${recheck.reason}). A message must not select or approve it. To deliberately drive the prompt: rig send ${sessionName} "<text>" --dangerously-interact --reason "<why>". No text was sent.`,
1643
+ }
1644
+ : recheck.state === "unknown"
1645
+ ? {
1646
+ reason: "target_activity_unknown",
1647
+ error: `Target activity could not be determined (${recheck.reason}) when the ${waitForIdleMs}ms wait ended. No text was sent.`,
1648
+ }
1649
+ : {
1650
+ reason: "wait_for_idle_timeout",
1651
+ error: `Target was still busy (${recheck.reason}) when the ${waitForIdleMs}ms wait ended. No text was sent.`,
1652
+ };
1653
+ return {
1654
+ ok: false,
1655
+ sessionName,
1656
+ sent: false,
1657
+ reason: late.reason,
1658
+ error: late.error,
1659
+ activity: recheck,
1660
+ waitedMs: preEvidence.waitedMs,
1661
+ attempts: preEvidence.attempts + 1,
1662
+ };
1663
+ }
1664
+ waitEvidence = {
1665
+ activity: recheck,
1666
+ waitedMs: preEvidence.waitedMs,
1667
+ attempts: preEvidence.attempts + 1,
1668
+ };
1669
+ }
1670
+ }
1310
1671
  // 2. OPR.0.4.1.10 — robust prompt/permission + mid-work guard on the DEFAULT path.
1311
1672
  // Runs the same detector previously reachable only via --wait-for-idle: fresh runtime-hook primary
1312
1673
  // (within the send-readiness window) + hardened capture-pane fallback. This closes the rig-send
@@ -1397,7 +1758,8 @@ export class SessionTransport {
1397
1758
  if (opts?.verify) {
1398
1759
  const captureSeq = observed ? nextCaptureSeq++ : 0;
1399
1760
  try {
1400
- preVerifyContent = await this.runStage("session_transport.pre_capture", () => this.tmuxAdapter.capturePaneContent(sessionName, 30));
1761
+ preVerifyContent = await this.runStage("session_transport.pre_capture", () => runtime === "terminal" || !verificationSnippet(text).envelope ? this.tmuxAdapter.capturePaneContent(sessionName, 30)
1762
+ : this.tmuxAdapter.capturePaneContent(sessionName, 30, { joinWrappedLines: true }));
1401
1763
  if (observed)
1402
1764
  observed.pre = captureSlot(preVerifyContent, this.now().toISOString(), captureSeq);
1403
1765
  }
@@ -1472,12 +1834,19 @@ export class SessionTransport {
1472
1834
  await this.sleep(500);
1473
1835
  const captureSeq = observed ? nextCaptureSeq++ : 0;
1474
1836
  try {
1475
- const content = await this.runStage("session_transport.post_capture", () => this.tmuxAdapter.capturePaneContent(sessionName, 30));
1837
+ const content = await this.runStage("session_transport.post_capture", () => runtime === "terminal" || !verificationSnippet(text).envelope ? this.tmuxAdapter.capturePaneContent(sessionName, 30)
1838
+ : this.tmuxAdapter.capturePaneContent(sessionName, 30, { joinWrappedLines: true }));
1476
1839
  if (observed)
1477
1840
  observed.post = captureSlot(content, this.now().toISOString(), captureSeq);
1478
- const snippet = text.substring(0, Math.min(text.length, 40));
1479
- const preCount = countOccurrences(preVerifyContent ?? "", snippet);
1480
- const postCount = countOccurrences(content ?? "", snippet);
1841
+ // A terminal prompt is command history, not an agent composer. Preserve
1842
+ // its original prefix-count verification even while a command is running.
1843
+ const terminal = runtime === "terminal";
1844
+ const { snippet, envelope } = terminal ? { snippet: text.slice(0, 40), envelope: false } : verificationSnippet(text);
1845
+ const transcript = terminal ? (pane) => pane ?? ""
1846
+ : envelope ? verificationTranscript : (pane) => normalizeVerificationText(verificationTranscript(pane));
1847
+ const count = envelope ? countEnvelopeOccurrences : countOccurrences;
1848
+ const preCount = count(transcript(preVerifyContent), snippet);
1849
+ const postCount = count(transcript(content), snippet);
1481
1850
  const verified = postCount > preCount;
1482
1851
  return observe({ ok: true, sessionName, ...interaction, verified, outcome: verified ? "delivered" : "rendered-unconfirmed", ...(sendAdvisory ? { warning: sendAdvisory } : {}), ...(waitMode ? { sent: true, ...waitEvidence } : {}) });
1483
1852
  }
@@ -1510,6 +1879,7 @@ export class SessionTransport {
1510
1879
  const deadline = Date.now() + input.timeoutMs;
1511
1880
  let attempts = 0;
1512
1881
  let last = null;
1882
+ const labelMs = input.timeoutLabelMs ?? input.timeoutMs;
1513
1883
  const expire = () => {
1514
1884
  const count = `${attempts} observation${attempts === 1 ? "" : "s"}`;
1515
1885
  const activity = last ?? {
@@ -1521,14 +1891,14 @@ export class SessionTransport {
1521
1891
  ok: false,
1522
1892
  reason: "target_activity_unknown",
1523
1893
  error: last
1524
- ? `Target activity could not be determined (${activity.reason}) when the ${input.timeoutMs}ms wait ended (${count}). No text was sent.`
1525
- : `Target activity could not be determined: no observation completed within the ${input.timeoutMs}ms wait. No text was sent.`,
1894
+ ? `Target activity could not be determined (${activity.reason}) when the ${labelMs}ms wait ended (${count}). No text was sent.`
1895
+ : `Target activity could not be determined: no observation completed within the ${labelMs}ms wait. No text was sent.`,
1526
1896
  activity, waitedMs: input.timeoutMs, attempts,
1527
1897
  }
1528
1898
  : {
1529
1899
  ok: false,
1530
1900
  reason: "wait_for_idle_timeout",
1531
- error: `Target was still busy (${activity.reason}) when the ${input.timeoutMs}ms wait ended (${count}). No text was sent.`,
1901
+ error: `Target was still busy (${activity.reason}) when the ${labelMs}ms wait ended (${count}). No text was sent.`,
1532
1902
  activity, waitedMs: input.timeoutMs, attempts,
1533
1903
  };
1534
1904
  };