@openrig/cli 0.6.8 → 0.6.10

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 (480) hide show
  1. package/README.md +2 -2
  2. package/daemon/assets/onboarding/02-self-and-competent-action.md +4 -3
  3. package/daemon/assets/plugins/openrig-core/.claude-plugin/plugin.json +1 -1
  4. package/daemon/assets/plugins/openrig-core/.codex-plugin/plugin.json +1 -1
  5. package/daemon/assets/plugins/openrig-core/hooks/scripts/activity-relay.cjs +42 -2
  6. package/daemon/assets/plugins/openrig-core/hooks/scripts/refocus.cjs +41 -2
  7. package/daemon/assets/plugins/openrig-core/skills/messaging-the-human/SKILL.md +12 -4
  8. package/daemon/assets/plugins/openrig-core/skills/openrig-user/SKILL.md +7 -1
  9. package/daemon/assets/plugins/openrig-core/skills/refocusing/scripts/trace-to-root.py +218 -7
  10. package/daemon/assets/skills/rigs/SKILL.md +6 -4
  11. package/daemon/context-packs/help/manifest.yaml +1 -1
  12. package/daemon/context-packs/onboarding-width/manifest.yaml +1 -1
  13. package/daemon/context-packs/onboarding-width/public-what-you-can-do.md +51 -16
  14. package/daemon/context-packs/reference/getting-started.md +10 -6
  15. package/daemon/context-packs/reference/manifest.yaml +1 -1
  16. package/daemon/context-packs/reference/whats-new.md +145 -74
  17. package/daemon/context-packs/skills/agent-operated-software/manifest.yaml +1 -1
  18. package/daemon/context-packs/skills/agent-operated-workflows/manifest.yaml +1 -1
  19. package/daemon/context-packs/skills/applying-a-permission-policy/manifest.yaml +1 -1
  20. package/daemon/context-packs/skills/claude-compaction-restore/manifest.yaml +1 -1
  21. package/daemon/context-packs/skills/core/agent-starters/manifest.yaml +1 -1
  22. package/daemon/context-packs/skills/core/agent-startup-and-context-ingestion/manifest.yaml +1 -1
  23. package/daemon/context-packs/skills/core/cross-host-rig-commands/SKILL.md +1 -0
  24. package/daemon/context-packs/skills/core/cross-host-rig-commands/manifest.yaml +1 -1
  25. package/daemon/context-packs/skills/core/human-in-the-loop/manifest.yaml +1 -1
  26. package/daemon/context-packs/skills/core/messaging-the-human/SKILL.md +12 -4
  27. package/daemon/context-packs/skills/core/messaging-the-human/manifest.yaml +1 -1
  28. package/daemon/context-packs/skills/core/openrig-architect/manifest.yaml +1 -1
  29. package/daemon/context-packs/skills/core/openrig-cmux/manifest.yaml +1 -1
  30. package/daemon/context-packs/skills/core/openrig-herdr/manifest.yaml +1 -1
  31. package/daemon/context-packs/skills/core/openrig-skills/manifest.yaml +1 -1
  32. package/daemon/context-packs/skills/core/openrig-software-factory/manifest.yaml +1 -1
  33. package/daemon/context-packs/skills/core/openrig-upgrade/manifest.yaml +1 -1
  34. package/daemon/context-packs/skills/core/rig-bundles-and-shareable-artifacts/manifest.yaml +1 -1
  35. package/daemon/context-packs/skills/core/rig-lifecycle/manifest.yaml +1 -1
  36. package/daemon/context-packs/skills/core/session-source-fork/manifest.yaml +1 -1
  37. package/daemon/context-packs/skills/core/specification-system/manifest.yaml +1 -1
  38. package/daemon/context-packs/skills/core/topology-mutation-and-seat-management/SKILL.md +2 -2
  39. package/daemon/context-packs/skills/core/topology-mutation-and-seat-management/manifest.yaml +1 -1
  40. package/daemon/context-packs/skills/core/watchdog/manifest.yaml +1 -1
  41. package/daemon/context-packs/skills/delegating-work/manifest.yaml +1 -1
  42. package/daemon/context-packs/skills/forming-an-openrig-mental-model/manifest.yaml +1 -1
  43. package/daemon/context-packs/skills/loading-addressable-markdown/manifest.yaml +1 -1
  44. package/daemon/context-packs/skills/mission-slice-sop/manifest.yaml +1 -1
  45. package/daemon/context-packs/skills/openrig-operating-model/manifest.yaml +1 -1
  46. package/daemon/context-packs/skills/openrig-user/SKILL.md +7 -1
  47. package/daemon/context-packs/skills/openrig-user/manifest.yaml +1 -1
  48. package/daemon/context-packs/skills/orienting-to-an-inherited-seat/manifest.yaml +1 -1
  49. package/daemon/context-packs/skills/pm/backlog-capture/manifest.yaml +1 -1
  50. package/daemon/context-packs/skills/pm/context-builder/manifest.yaml +1 -1
  51. package/daemon/context-packs/skills/pm/exec-summary/manifest.yaml +1 -1
  52. package/daemon/context-packs/skills/pm/office-hours/manifest.yaml +1 -1
  53. package/daemon/context-packs/skills/pm/plan-review/manifest.yaml +1 -1
  54. package/daemon/context-packs/skills/pm/requirements-writer/manifest.yaml +1 -1
  55. package/daemon/context-packs/skills/pm/ui-mockup/manifest.yaml +1 -1
  56. package/daemon/context-packs/skills/pods/development-team/manifest.yaml +1 -1
  57. package/daemon/context-packs/skills/pods/orchestration-team/manifest.yaml +1 -1
  58. package/daemon/context-packs/skills/pods/oversight-team/manifest.yaml +1 -1
  59. package/daemon/context-packs/skills/pods/review-team/manifest.yaml +1 -1
  60. package/daemon/context-packs/skills/process/agent-browser/manifest.yaml +1 -1
  61. package/daemon/context-packs/skills/process/context-engineering/manifest.yaml +1 -1
  62. package/daemon/context-packs/skills/process/dogfood/manifest.yaml +1 -1
  63. package/daemon/context-packs/skills/process/frontend-design/manifest.yaml +1 -1
  64. package/daemon/context-packs/skills/process/systematic-debugging/manifest.yaml +1 -1
  65. package/daemon/context-packs/skills/process/test-driven-development/manifest.yaml +1 -1
  66. package/daemon/context-packs/skills/process/verification-before-completion/manifest.yaml +1 -1
  67. package/daemon/context-packs/skills/queue-handoff/manifest.yaml +1 -1
  68. package/daemon/context-packs/skills/refocusing/manifest.yaml +1 -1
  69. package/daemon/context-packs/skills/refocusing/scripts/trace-to-root.py +218 -7
  70. package/daemon/context-packs/skills/retiring-and-inheriting-a-seat/manifest.yaml +1 -1
  71. package/daemon/context-packs/skills/seat-continuity-and-handover/manifest.yaml +1 -1
  72. package/daemon/context-packs/skills/session-compaction-and-restore/manifest.yaml +1 -1
  73. package/daemon/context-packs/skills/software-for-agents/manifest.yaml +1 -1
  74. package/daemon/context-packs/world-example/manifest.yaml +1 -1
  75. package/daemon/context-packs/world-public/manifest.yaml +1 -1
  76. package/daemon/dist/adapters/claude-code-adapter.d.ts.map +1 -1
  77. package/daemon/dist/adapters/claude-code-adapter.js +16 -7
  78. package/daemon/dist/adapters/claude-code-adapter.js.map +1 -1
  79. package/daemon/dist/adapters/claude-resume-launch.d.ts +4 -0
  80. package/daemon/dist/adapters/claude-resume-launch.d.ts.map +1 -0
  81. package/daemon/dist/adapters/claude-resume-launch.js +13 -0
  82. package/daemon/dist/adapters/claude-resume-launch.js.map +1 -0
  83. package/daemon/dist/adapters/claude-resume.d.ts +2 -1
  84. package/daemon/dist/adapters/claude-resume.d.ts.map +1 -1
  85. package/daemon/dist/adapters/claude-resume.js +9 -4
  86. package/daemon/dist/adapters/claude-resume.js.map +1 -1
  87. package/daemon/dist/adapters/tmux-server.d.ts +15 -0
  88. package/daemon/dist/adapters/tmux-server.d.ts.map +1 -0
  89. package/daemon/dist/adapters/tmux-server.js +58 -0
  90. package/daemon/dist/adapters/tmux-server.js.map +1 -0
  91. package/daemon/dist/adapters/tmux.d.ts +3 -1
  92. package/daemon/dist/adapters/tmux.d.ts.map +1 -1
  93. package/daemon/dist/adapters/tmux.js +4 -2
  94. package/daemon/dist/adapters/tmux.js.map +1 -1
  95. package/daemon/dist/build-info.js +3 -3
  96. package/daemon/dist/db/all-migrations.d.ts.map +1 -1
  97. package/daemon/dist/db/all-migrations.js +6 -0
  98. package/daemon/dist/db/all-migrations.js.map +1 -1
  99. package/daemon/dist/db/migrations/098_queue_transitions_qitem_id_order.d.ts +3 -0
  100. package/daemon/dist/db/migrations/098_queue_transitions_qitem_id_order.d.ts.map +1 -0
  101. package/daemon/dist/db/migrations/098_queue_transitions_qitem_id_order.js +12 -0
  102. package/daemon/dist/db/migrations/098_queue_transitions_qitem_id_order.js.map +1 -0
  103. package/daemon/dist/db/migrations/099_queue_items_recovery_tags.d.ts +3 -0
  104. package/daemon/dist/db/migrations/099_queue_items_recovery_tags.d.ts.map +1 -0
  105. package/daemon/dist/db/migrations/099_queue_items_recovery_tags.js +19 -0
  106. package/daemon/dist/db/migrations/099_queue_items_recovery_tags.js.map +1 -0
  107. package/daemon/dist/db/migrations/101_claude_resume_rotation.d.ts +3 -0
  108. package/daemon/dist/db/migrations/101_claude_resume_rotation.d.ts.map +1 -0
  109. package/daemon/dist/db/migrations/101_claude_resume_rotation.js +19 -0
  110. package/daemon/dist/db/migrations/101_claude_resume_rotation.js.map +1 -0
  111. package/daemon/dist/domain/agent-activity-store.js +3 -0
  112. package/daemon/dist/domain/agent-activity-store.js.map +1 -1
  113. package/daemon/dist/domain/bootstrap-repository.js +1 -1
  114. package/daemon/dist/domain/bootstrap-repository.js.map +1 -1
  115. package/daemon/dist/domain/chat-repository.d.ts +3 -0
  116. package/daemon/dist/domain/chat-repository.d.ts.map +1 -1
  117. package/daemon/dist/domain/chat-repository.js +15 -4
  118. package/daemon/dist/domain/chat-repository.js.map +1 -1
  119. package/daemon/dist/domain/claude-managed-launch.d.ts +1 -1
  120. package/daemon/dist/domain/claude-managed-launch.d.ts.map +1 -1
  121. package/daemon/dist/domain/claude-managed-launch.js +3 -2
  122. package/daemon/dist/domain/claude-managed-launch.js.map +1 -1
  123. package/daemon/dist/domain/cmux-layout-service.d.ts.map +1 -1
  124. package/daemon/dist/domain/cmux-layout-service.js +2 -1
  125. package/daemon/dist/domain/cmux-layout-service.js.map +1 -1
  126. package/daemon/dist/domain/codex-git-add-dirs.js +1 -1
  127. package/daemon/dist/domain/codex-git-add-dirs.js.map +1 -1
  128. package/daemon/dist/domain/context-usage-store.d.ts.map +1 -1
  129. package/daemon/dist/domain/context-usage-store.js +6 -1
  130. package/daemon/dist/domain/context-usage-store.js.map +1 -1
  131. package/daemon/dist/domain/crash-cart-conductor.d.ts.map +1 -1
  132. package/daemon/dist/domain/crash-cart-conductor.js +3 -1
  133. package/daemon/dist/domain/crash-cart-conductor.js.map +1 -1
  134. package/daemon/dist/domain/current-work.d.ts +74 -0
  135. package/daemon/dist/domain/current-work.d.ts.map +1 -1
  136. package/daemon/dist/domain/current-work.js +165 -0
  137. package/daemon/dist/domain/current-work.js.map +1 -1
  138. package/daemon/dist/domain/files/file-read.d.ts.map +1 -1
  139. package/daemon/dist/domain/files/file-read.js +11 -3
  140. package/daemon/dist/domain/files/file-read.js.map +1 -1
  141. package/daemon/dist/domain/gateway/connections-projection.d.ts +3 -1
  142. package/daemon/dist/domain/gateway/connections-projection.d.ts.map +1 -1
  143. package/daemon/dist/domain/gateway/connections-projection.js +3 -1
  144. package/daemon/dist/domain/gateway/connections-projection.js.map +1 -1
  145. package/daemon/dist/domain/gateway/gateway-subsystem.d.ts +3 -1
  146. package/daemon/dist/domain/gateway/gateway-subsystem.d.ts.map +1 -1
  147. package/daemon/dist/domain/gateway/gateway-subsystem.js +3 -1
  148. package/daemon/dist/domain/gateway/gateway-subsystem.js.map +1 -1
  149. package/daemon/dist/domain/gateway/slack/inbound.d.ts +21 -2
  150. package/daemon/dist/domain/gateway/slack/inbound.d.ts.map +1 -1
  151. package/daemon/dist/domain/gateway/slack/inbound.js +70 -11
  152. package/daemon/dist/domain/gateway/slack/inbound.js.map +1 -1
  153. package/daemon/dist/domain/gateway/slack/queue-access.d.ts +3 -0
  154. package/daemon/dist/domain/gateway/slack/queue-access.d.ts.map +1 -1
  155. package/daemon/dist/domain/gateway/slack/queue-access.js +5 -1
  156. package/daemon/dist/domain/gateway/slack/queue-access.js.map +1 -1
  157. package/daemon/dist/domain/gateway/slack/slack-delivery.d.ts +4 -0
  158. package/daemon/dist/domain/gateway/slack/slack-delivery.d.ts.map +1 -1
  159. package/daemon/dist/domain/gateway/slack/slack-delivery.js +1 -1
  160. package/daemon/dist/domain/gateway/slack/slack-delivery.js.map +1 -1
  161. package/daemon/dist/domain/gateway/slack/slack-subsystem.d.ts.map +1 -1
  162. package/daemon/dist/domain/gateway/slack/slack-subsystem.js +81 -23
  163. package/daemon/dist/domain/gateway/slack/slack-subsystem.js.map +1 -1
  164. package/daemon/dist/domain/gateway/slack/socket-inbound.d.ts +37 -0
  165. package/daemon/dist/domain/gateway/slack/socket-inbound.d.ts.map +1 -1
  166. package/daemon/dist/domain/gateway/slack/socket-inbound.js +281 -38
  167. package/daemon/dist/domain/gateway/slack/socket-inbound.js.map +1 -1
  168. package/daemon/dist/domain/gateway/slack/state-store.d.ts +14 -1
  169. package/daemon/dist/domain/gateway/slack/state-store.d.ts.map +1 -1
  170. package/daemon/dist/domain/gateway/slack/state-store.js +16 -0
  171. package/daemon/dist/domain/gateway/slack/state-store.js.map +1 -1
  172. package/daemon/dist/domain/history-query.d.ts.map +1 -1
  173. package/daemon/dist/domain/history-query.js +8 -6
  174. package/daemon/dist/domain/history-query.js.map +1 -1
  175. package/daemon/dist/domain/human-questions.d.ts +16 -4
  176. package/daemon/dist/domain/human-questions.d.ts.map +1 -1
  177. package/daemon/dist/domain/human-questions.js +10 -5
  178. package/daemon/dist/domain/human-questions.js.map +1 -1
  179. package/daemon/dist/domain/install-engine.js +2 -2
  180. package/daemon/dist/domain/install-engine.js.map +1 -1
  181. package/daemon/dist/domain/kernel-boot-tracker.d.ts +20 -1
  182. package/daemon/dist/domain/kernel-boot-tracker.d.ts.map +1 -1
  183. package/daemon/dist/domain/kernel-boot-tracker.js +66 -14
  184. package/daemon/dist/domain/kernel-boot-tracker.js.map +1 -1
  185. package/daemon/dist/domain/kernel-boot.d.ts +4 -0
  186. package/daemon/dist/domain/kernel-boot.d.ts.map +1 -1
  187. package/daemon/dist/domain/kernel-boot.js +26 -1
  188. package/daemon/dist/domain/kernel-boot.js.map +1 -1
  189. package/daemon/dist/domain/native-process-lineage.d.ts +52 -4
  190. package/daemon/dist/domain/native-process-lineage.d.ts.map +1 -1
  191. package/daemon/dist/domain/native-process-lineage.js +254 -34
  192. package/daemon/dist/domain/native-process-lineage.js.map +1 -1
  193. package/daemon/dist/domain/node-cmux-service.d.ts.map +1 -1
  194. package/daemon/dist/domain/node-cmux-service.js +2 -1
  195. package/daemon/dist/domain/node-cmux-service.js.map +1 -1
  196. package/daemon/dist/domain/node-inventory.d.ts.map +1 -1
  197. package/daemon/dist/domain/node-inventory.js +58 -13
  198. package/daemon/dist/domain/node-inventory.js.map +1 -1
  199. package/daemon/dist/domain/progress/progress-indexer.d.ts.map +1 -1
  200. package/daemon/dist/domain/progress/progress-indexer.js +19 -0
  201. package/daemon/dist/domain/progress/progress-indexer.js.map +1 -1
  202. package/daemon/dist/domain/provider/codex-limit-banner.d.ts +40 -0
  203. package/daemon/dist/domain/provider/codex-limit-banner.d.ts.map +1 -0
  204. package/daemon/dist/domain/provider/codex-limit-banner.js +121 -0
  205. package/daemon/dist/domain/provider/codex-limit-banner.js.map +1 -0
  206. package/daemon/dist/domain/ps-projection.d.ts.map +1 -1
  207. package/daemon/dist/domain/ps-projection.js +3 -2
  208. package/daemon/dist/domain/ps-projection.js.map +1 -1
  209. package/daemon/dist/domain/queue-recovery.d.ts.map +1 -1
  210. package/daemon/dist/domain/queue-recovery.js +10 -3
  211. package/daemon/dist/domain/queue-recovery.js.map +1 -1
  212. package/daemon/dist/domain/queue-repository.d.ts +78 -13
  213. package/daemon/dist/domain/queue-repository.d.ts.map +1 -1
  214. package/daemon/dist/domain/queue-repository.js +103 -41
  215. package/daemon/dist/domain/queue-repository.js.map +1 -1
  216. package/daemon/dist/domain/queue-stuck-sweep.d.ts.map +1 -1
  217. package/daemon/dist/domain/queue-stuck-sweep.js +5 -2
  218. package/daemon/dist/domain/queue-stuck-sweep.js.map +1 -1
  219. package/daemon/dist/domain/queue-transition-log.d.ts +12 -4
  220. package/daemon/dist/domain/queue-transition-log.d.ts.map +1 -1
  221. package/daemon/dist/domain/queue-transition-log.js +24 -0
  222. package/daemon/dist/domain/queue-transition-log.js.map +1 -1
  223. package/daemon/dist/domain/queue-wake-ladder.d.ts +17 -0
  224. package/daemon/dist/domain/queue-wake-ladder.d.ts.map +1 -1
  225. package/daemon/dist/domain/queue-wake-ladder.js +49 -3
  226. package/daemon/dist/domain/queue-wake-ladder.js.map +1 -1
  227. package/daemon/dist/domain/restore-guidance.d.ts +39 -0
  228. package/daemon/dist/domain/restore-guidance.d.ts.map +1 -0
  229. package/daemon/dist/domain/restore-guidance.js +163 -0
  230. package/daemon/dist/domain/restore-guidance.js.map +1 -0
  231. package/daemon/dist/domain/restore-orchestrator.d.ts +6 -1
  232. package/daemon/dist/domain/restore-orchestrator.d.ts.map +1 -1
  233. package/daemon/dist/domain/restore-orchestrator.js +160 -6
  234. package/daemon/dist/domain/restore-orchestrator.js.map +1 -1
  235. package/daemon/dist/domain/runtime-adapter.d.ts +2 -0
  236. package/daemon/dist/domain/runtime-adapter.d.ts.map +1 -1
  237. package/daemon/dist/domain/runtime-adapter.js.map +1 -1
  238. package/daemon/dist/domain/scope/scope-approve.d.ts +21 -0
  239. package/daemon/dist/domain/scope/scope-approve.d.ts.map +1 -1
  240. package/daemon/dist/domain/scope/scope-approve.js +48 -4
  241. package/daemon/dist/domain/scope/scope-approve.js.map +1 -1
  242. package/daemon/dist/domain/scope/scope-view-projection.d.ts.map +1 -1
  243. package/daemon/dist/domain/scope/scope-view-projection.js +5 -7
  244. package/daemon/dist/domain/scope/scope-view-projection.js.map +1 -1
  245. package/daemon/dist/domain/seat-attention-reconciler.d.ts +5 -2
  246. package/daemon/dist/domain/seat-attention-reconciler.d.ts.map +1 -1
  247. package/daemon/dist/domain/seat-attention-reconciler.js +18 -4
  248. package/daemon/dist/domain/seat-attention-reconciler.js.map +1 -1
  249. package/daemon/dist/domain/seat-identity-reconciler.d.ts.map +1 -1
  250. package/daemon/dist/domain/seat-identity-reconciler.js +7 -2
  251. package/daemon/dist/domain/seat-identity-reconciler.js.map +1 -1
  252. package/daemon/dist/domain/seat-lifecycle-service.d.ts.map +1 -1
  253. package/daemon/dist/domain/seat-status-service.d.ts +2 -1
  254. package/daemon/dist/domain/seat-status-service.d.ts.map +1 -1
  255. package/daemon/dist/domain/seat-status-service.js +1 -0
  256. package/daemon/dist/domain/seat-status-service.js.map +1 -1
  257. package/daemon/dist/domain/seat-structural-activity-service.d.ts +9 -1
  258. package/daemon/dist/domain/seat-structural-activity-service.d.ts.map +1 -1
  259. package/daemon/dist/domain/seat-structural-activity-service.js +28 -4
  260. package/daemon/dist/domain/seat-structural-activity-service.js.map +1 -1
  261. package/daemon/dist/domain/seat-switch-client-service.d.ts.map +1 -1
  262. package/daemon/dist/domain/seat-switch-client-service.js +2 -1
  263. package/daemon/dist/domain/seat-switch-client-service.js.map +1 -1
  264. package/daemon/dist/domain/session-registry.d.ts +46 -0
  265. package/daemon/dist/domain/session-registry.d.ts.map +1 -1
  266. package/daemon/dist/domain/session-registry.js +86 -4
  267. package/daemon/dist/domain/session-registry.js.map +1 -1
  268. package/daemon/dist/domain/session-transport.d.ts +13 -1
  269. package/daemon/dist/domain/session-transport.d.ts.map +1 -1
  270. package/daemon/dist/domain/session-transport.js +101 -5
  271. package/daemon/dist/domain/session-transport.js.map +1 -1
  272. package/daemon/dist/domain/startup-orchestrator.d.ts +8 -0
  273. package/daemon/dist/domain/startup-orchestrator.d.ts.map +1 -1
  274. package/daemon/dist/domain/startup-orchestrator.js +37 -1
  275. package/daemon/dist/domain/startup-orchestrator.js.map +1 -1
  276. package/daemon/dist/domain/terminal/terminal-service.d.ts +5 -1
  277. package/daemon/dist/domain/terminal/terminal-service.d.ts.map +1 -1
  278. package/daemon/dist/domain/terminal/terminal-service.js +30 -4
  279. package/daemon/dist/domain/terminal/terminal-service.js.map +1 -1
  280. package/daemon/dist/domain/terminal/view-composer.d.ts +6 -0
  281. package/daemon/dist/domain/terminal/view-composer.d.ts.map +1 -1
  282. package/daemon/dist/domain/terminal/view-composer.js +2 -1
  283. package/daemon/dist/domain/terminal/view-composer.js.map +1 -1
  284. package/daemon/dist/domain/transcript-store.js +1 -1
  285. package/daemon/dist/domain/transcript-store.js.map +1 -1
  286. package/daemon/dist/domain/types.d.ts +9 -0
  287. package/daemon/dist/domain/types.d.ts.map +1 -1
  288. package/daemon/dist/domain/types.js +5 -0
  289. package/daemon/dist/domain/types.js.map +1 -1
  290. package/daemon/dist/domain/usage-series.d.ts.map +1 -1
  291. package/daemon/dist/domain/usage-series.js +9 -4
  292. package/daemon/dist/domain/usage-series.js.map +1 -1
  293. package/daemon/dist/domain/user-settings/settings-store.d.ts +1 -1
  294. package/daemon/dist/domain/user-settings/settings-store.d.ts.map +1 -1
  295. package/daemon/dist/domain/user-settings/settings-store.js +13 -0
  296. package/daemon/dist/domain/user-settings/settings-store.js.map +1 -1
  297. package/daemon/dist/domain/view-projector.d.ts +4 -0
  298. package/daemon/dist/domain/view-projector.d.ts.map +1 -1
  299. package/daemon/dist/domain/view-projector.js +19 -4
  300. package/daemon/dist/domain/view-projector.js.map +1 -1
  301. package/daemon/dist/domain/workflow-runtime.d.ts +1 -1
  302. package/daemon/dist/routes/activity.d.ts.map +1 -1
  303. package/daemon/dist/routes/activity.js +33 -1
  304. package/daemon/dist/routes/activity.js.map +1 -1
  305. package/daemon/dist/routes/chat.d.ts.map +1 -1
  306. package/daemon/dist/routes/chat.js +6 -2
  307. package/daemon/dist/routes/chat.js.map +1 -1
  308. package/daemon/dist/routes/gateway.d.ts.map +1 -1
  309. package/daemon/dist/routes/gateway.js +2 -0
  310. package/daemon/dist/routes/gateway.js.map +1 -1
  311. package/daemon/dist/routes/kernel-status.js +3 -1
  312. package/daemon/dist/routes/kernel-status.js.map +1 -1
  313. package/daemon/dist/routes/projects.d.ts.map +1 -1
  314. package/daemon/dist/routes/projects.js +5 -1
  315. package/daemon/dist/routes/projects.js.map +1 -1
  316. package/daemon/dist/routes/query-limit.d.ts +19 -0
  317. package/daemon/dist/routes/query-limit.d.ts.map +1 -0
  318. package/daemon/dist/routes/query-limit.js +24 -0
  319. package/daemon/dist/routes/query-limit.js.map +1 -0
  320. package/daemon/dist/routes/queue.d.ts.map +1 -1
  321. package/daemon/dist/routes/queue.js +35 -9
  322. package/daemon/dist/routes/queue.js.map +1 -1
  323. package/daemon/dist/routes/rig-cmux.js +8 -10
  324. package/daemon/dist/routes/rig-cmux.js.map +1 -1
  325. package/daemon/dist/routes/rigs.d.ts.map +1 -1
  326. package/daemon/dist/routes/rigs.js +6 -4
  327. package/daemon/dist/routes/rigs.js.map +1 -1
  328. package/daemon/dist/routes/scope-approve.d.ts.map +1 -1
  329. package/daemon/dist/routes/scope-approve.js +3 -0
  330. package/daemon/dist/routes/scope-approve.js.map +1 -1
  331. package/daemon/dist/routes/stream.d.ts.map +1 -1
  332. package/daemon/dist/routes/stream.js +5 -1
  333. package/daemon/dist/routes/stream.js.map +1 -1
  334. package/daemon/dist/routes/up.d.ts.map +1 -1
  335. package/daemon/dist/routes/up.js +2 -1
  336. package/daemon/dist/routes/up.js.map +1 -1
  337. package/daemon/dist/routes/views.d.ts.map +1 -1
  338. package/daemon/dist/routes/views.js +7 -1
  339. package/daemon/dist/routes/views.js.map +1 -1
  340. package/daemon/dist/startup.d.ts.map +1 -1
  341. package/daemon/dist/startup.js +19 -0
  342. package/daemon/dist/startup.js.map +1 -1
  343. package/daemon/docs/reference/getting-started.md +10 -6
  344. package/daemon/docs/reference/refocus-channel.md +33 -0
  345. package/daemon/docs/reference/slack-app-setup.md +19 -0
  346. package/daemon/docs/reference/whats-new.md +145 -74
  347. package/daemon/specs/agents/development/qa/guidance/role.md +9 -0
  348. package/daemon/specs/agents/shared/skills/core/cross-host-rig-commands/SKILL.md +1 -0
  349. package/daemon/specs/agents/shared/skills/core/messaging-the-human/SKILL.md +12 -4
  350. package/daemon/specs/agents/shared/skills/core/topology-mutation-and-seat-management/SKILL.md +2 -2
  351. package/daemon/specs/rigs/launch/factory/CULTURE.md +13 -0
  352. package/daemon/specs/rigs/launch/factory/guidance/lead-first-move.md +18 -5
  353. package/daemon/specs/rigs/launch/kernel/agents/operator/agent/guidance/role.md +20 -1
  354. package/daemon/specs/rigs/launch/starter/CULTURE.md +13 -0
  355. package/daemon/specs/rigs/launch/starter/guidance/lead-first-move.md +18 -5
  356. package/dist/build-info.js +3 -3
  357. package/dist/cli-error.d.ts.map +1 -1
  358. package/dist/cli-error.js +2 -0
  359. package/dist/cli-error.js.map +1 -1
  360. package/dist/commands/add.d.ts.map +1 -1
  361. package/dist/commands/add.js +55 -4
  362. package/dist/commands/add.js.map +1 -1
  363. package/dist/commands/capture.d.ts +9 -0
  364. package/dist/commands/capture.d.ts.map +1 -1
  365. package/dist/commands/capture.js +93 -41
  366. package/dist/commands/capture.js.map +1 -1
  367. package/dist/commands/chatroom.d.ts.map +1 -1
  368. package/dist/commands/chatroom.js +25 -5
  369. package/dist/commands/chatroom.js.map +1 -1
  370. package/dist/commands/config.d.ts.map +1 -1
  371. package/dist/commands/config.js +4 -1
  372. package/dist/commands/config.js.map +1 -1
  373. package/dist/commands/daemon.d.ts.map +1 -1
  374. package/dist/commands/daemon.js +37 -3
  375. package/dist/commands/daemon.js.map +1 -1
  376. package/dist/commands/down.d.ts.map +1 -1
  377. package/dist/commands/down.js +1 -50
  378. package/dist/commands/down.js.map +1 -1
  379. package/dist/commands/env.d.ts.map +1 -1
  380. package/dist/commands/env.js +6 -0
  381. package/dist/commands/env.js.map +1 -1
  382. package/dist/commands/heartbeat.js +2 -2
  383. package/dist/commands/heartbeat.js.map +1 -1
  384. package/dist/commands/ps.d.ts +3 -0
  385. package/dist/commands/ps.d.ts.map +1 -1
  386. package/dist/commands/ps.js +8 -3
  387. package/dist/commands/ps.js.map +1 -1
  388. package/dist/commands/queue.d.ts +39 -6
  389. package/dist/commands/queue.d.ts.map +1 -1
  390. package/dist/commands/queue.js +130 -33
  391. package/dist/commands/queue.js.map +1 -1
  392. package/dist/commands/scope.d.ts.map +1 -1
  393. package/dist/commands/scope.js +10 -1
  394. package/dist/commands/scope.js.map +1 -1
  395. package/dist/commands/seat.d.ts.map +1 -1
  396. package/dist/commands/seat.js +6 -0
  397. package/dist/commands/seat.js.map +1 -1
  398. package/dist/commands/send.d.ts.map +1 -1
  399. package/dist/commands/send.js +23 -5
  400. package/dist/commands/send.js.map +1 -1
  401. package/dist/commands/setup.d.ts +6 -0
  402. package/dist/commands/setup.d.ts.map +1 -1
  403. package/dist/commands/setup.js +100 -44
  404. package/dist/commands/setup.js.map +1 -1
  405. package/dist/commands/slack.d.ts +17 -0
  406. package/dist/commands/slack.d.ts.map +1 -1
  407. package/dist/commands/slack.js +41 -0
  408. package/dist/commands/slack.js.map +1 -1
  409. package/dist/commands/start.d.ts.map +1 -1
  410. package/dist/commands/start.js +5 -1
  411. package/dist/commands/start.js.map +1 -1
  412. package/dist/commands/status.d.ts.map +1 -1
  413. package/dist/commands/status.js +5 -0
  414. package/dist/commands/status.js.map +1 -1
  415. package/dist/commands/usage.d.ts.map +1 -1
  416. package/dist/commands/usage.js +10 -5
  417. package/dist/commands/usage.js.map +1 -1
  418. package/dist/commands/workflow.d.ts.map +1 -1
  419. package/dist/commands/workflow.js +8 -8
  420. package/dist/commands/workflow.js.map +1 -1
  421. package/dist/config-store.d.ts +2 -1
  422. package/dist/config-store.d.ts.map +1 -1
  423. package/dist/config-store.js +14 -0
  424. package/dist/config-store.js.map +1 -1
  425. package/dist/cross-host-types.d.ts +1 -1
  426. package/dist/cross-host-types.d.ts.map +1 -1
  427. package/dist/daemon-lifecycle.d.ts +4 -0
  428. package/dist/daemon-lifecycle.d.ts.map +1 -1
  429. package/dist/daemon-lifecycle.js +16 -4
  430. package/dist/daemon-lifecycle.js.map +1 -1
  431. package/dist/lib/scope/capability-delta.d.ts.map +1 -1
  432. package/dist/lib/scope/capability-delta.js +8 -0
  433. package/dist/lib/scope/capability-delta.js.map +1 -1
  434. package/dist/lib/scope/progress-edit.js +1 -1
  435. package/dist/lib/scope/progress-edit.js.map +1 -1
  436. package/dist/lib/scope/scope-fs.d.ts +13 -0
  437. package/dist/lib/scope/scope-fs.d.ts.map +1 -1
  438. package/dist/lib/scope/scope-fs.js +31 -7
  439. package/dist/lib/scope/scope-fs.js.map +1 -1
  440. package/dist/remote-host-ops.d.ts +4 -0
  441. package/dist/remote-host-ops.d.ts.map +1 -1
  442. package/dist/remote-host-ops.js +20 -2
  443. package/dist/remote-host-ops.js.map +1 -1
  444. package/dist/rig-handle.d.ts +45 -0
  445. package/dist/rig-handle.d.ts.map +1 -0
  446. package/dist/rig-handle.js +51 -0
  447. package/dist/rig-handle.js.map +1 -0
  448. package/dist/system-preflight.d.ts +5 -0
  449. package/dist/system-preflight.d.ts.map +1 -1
  450. package/dist/system-preflight.js +8 -0
  451. package/dist/system-preflight.js.map +1 -1
  452. package/dist/terminal-window.d.ts.map +1 -1
  453. package/dist/terminal-window.js +3 -1
  454. package/dist/terminal-window.js.map +1 -1
  455. package/package.json +1 -1
  456. package/tui/dist/config/config-model.d.ts.map +1 -1
  457. package/tui/dist/config/config-model.js +1 -0
  458. package/tui/dist/config/config-model.js.map +1 -1
  459. package/tui/dist/connections/connections-model.d.ts +5 -0
  460. package/tui/dist/connections/connections-model.d.ts.map +1 -1
  461. package/tui/dist/connections/connections-model.js +16 -1
  462. package/tui/dist/connections/connections-model.js.map +1 -1
  463. package/tui/dist/daemon-client.d.ts +3 -0
  464. package/tui/dist/daemon-client.d.ts.map +1 -1
  465. package/tui/dist/daemon-client.js +4 -1
  466. package/tui/dist/daemon-client.js.map +1 -1
  467. package/tui/dist/detail.d.ts.map +1 -1
  468. package/tui/dist/detail.js +6 -1
  469. package/tui/dist/detail.js.map +1 -1
  470. package/tui/dist/hydrate.d.ts.map +1 -1
  471. package/tui/dist/hydrate.js +19 -17
  472. package/tui/dist/hydrate.js.map +1 -1
  473. package/tui/dist/input.d.ts.map +1 -1
  474. package/tui/dist/input.js +15 -4
  475. package/tui/dist/input.js.map +1 -1
  476. package/tui/dist/local-reading.js +2 -2
  477. package/tui/dist/local-reading.js.map +1 -1
  478. package/tui/dist/reading.d.ts.map +1 -1
  479. package/tui/dist/reading.js +14 -3
  480. package/tui/dist/reading.js.map +1 -1
package/README.md CHANGED
@@ -42,7 +42,7 @@ To install with Bun instead, run `bun add -g @openrig/cli`. OpenRig still runs o
42
42
 
43
43
  npm 11 and later can skip that postinstall script and print `npm warn install-scripts` naming `@openrig/cli`. That's expected: the CLI still works, and only the Node.js and SQLite check was skipped. To run it yourself, use `node "$(npm root -g)/@openrig/cli/scripts/check-abi.mjs"`; `rig doctor` checks the Node.js version only.
44
44
 
45
- Choose the working account you already have: **Claude Code, Codex, or both**. Reuse an explicit choice; no second subscription is required. `rig setup --dry-run` previews the broader setup; applying `rig setup` checks both harnesses and installs a missing one, plus Herdr unless declined with `--no-herdr`. On macOS, the installing agent offers Ghostty once. Setup leaves an existing cmux installation alone. It is optional for the [selected-provider path](docs/reference/getting-started.md#choose-your-providers).
45
+ Choose the working account you already have: **Claude Code, Codex, or both**. Reuse an explicit choice; no second subscription is required. `rig setup --dry-run` previews the broader setup; applying `rig setup` checks both harnesses and installs a missing one, plus Herdr unless declined with `--no-herdr`. Pass the choice with `--providers claude` or `--providers codex` so the other reads not selected instead of failed. The one-command install above doesn't know the choice, so it installs and checks both; for one provider, go step by step and run `rig setup --providers <choice>`. On macOS, the installing agent offers Ghostty once. Setup leaves an existing cmux installation alone. It is optional for the [selected-provider path](docs/reference/getting-started.md#choose-your-providers).
46
46
 
47
47
  A team seat with no permission policy, per-seat choice or (for Codex) named profile launches with OpenRig's [team default](docs/reference/rig-spec.md#team-launch-defaults): Claude runs ordinary `rig` commands, project reads and common tests without prompting, while lifecycle commands such as `rig up` and `rig down` still ask; Codex also gets the OpenRig workspace and its pod's state directory as writable directories. Before launching, your agent recommends keeping that default, and offers to remember selected OpenRig commands in your native settings only if you want that, at personal project scope unless you explicitly choose user-wide sessions. It is not global YOLO or permission to invent work. On Yes, the agent [adds and verifies native rules](docs/reference/getting-started.md#have-your-agent-configure-permissions); No or no answer keeps the team default and leaves settings unchanged. An existing explicit choice is reused. Say “Undo the OpenRig command allowances added by this setup” to remove only its additions.
48
48
 
@@ -447,7 +447,7 @@ Before setup or managed launch, review [what OpenRig changes on your machine](#w
447
447
 
448
448
  Already-running adopted sessions may need restart before they pick up newly written runtime config.
449
449
 
450
- **For agents:** First ask which available provider(s) the user wants, reusing an explicit choice. Recommend the working account they already have and follow the selected-provider guide above. Offer core setup (`rig setup`) or the fuller workstation path (`rig setup --full`) only when they want those additional tools. Inspect the result with `--json` and use `rig doctor` to finish any remaining machine-specific issues. Then start the daemon if it is stopped, open the OpenRig TUI and operator for them (say so, then run `rig terminal open saved:kernel --window --json`; no commands for the person to copy), and hand the person's goal and project folder to the kernel operator ([installing-agent handoff](docs/reference/getting-started.md#installing-agent-handoff)). Installation is finished when the person is talking to the operator; don't implement the project yourself. When OpenRig itself misbehaves, read [docs/reference/help.md](docs/reference/help.md) (installed agents can run `rig context get help`; the same text is at [openrig.dev/help/agents](https://www.openrig.dev/help/agents)): it covers the next step, known problems, and how to reach the team if you're still stuck.
450
+ **For agents:** First ask which available provider(s) the user wants, reusing an explicit choice, and pass it to setup (`rig setup --providers claude`, `codex` or `both`). Recommend the working account they already have and follow the selected-provider guide above. Offer core setup (`rig setup`) or the fuller workstation path (`rig setup --full`) only when they want those additional tools. Inspect the result with `--json` and use `rig doctor` to finish any remaining machine-specific issues. Starting OpenRig and opening its view are the last steps of installing, not extras, so do them without stopping to ask whether to go on: start the daemon if it is stopped, open the OpenRig TUI and operator for them (say so, then run `rig terminal open saved:kernel --window --json`; no commands for the person to copy), and hand the person's goal and project folder to the kernel operator ([installing-agent handoff](docs/reference/getting-started.md#installing-agent-handoff)). Installation is finished when the person is talking to the operator; don't implement the project yourself. When OpenRig itself misbehaves, read [docs/reference/help.md](docs/reference/help.md) (installed agents can run `rig context get help`; the same text is at [openrig.dev/help/agents](https://www.openrig.dev/help/agents)): it covers the next step, known problems, and how to reach the team if you're still stuck.
451
451
 
452
452
  ## Comparison with Claude Managed Agents
453
453
 
@@ -67,9 +67,10 @@ conversation. Explain the failure and help with the chosen fallback; do not atta
67
67
  Over headless SSH, explain that no visible terminal opened; tell the person to open a new terminal window or
68
68
  tab and give one complete connection and attachment command using the current Herdr endpoint, as in the guide.
69
69
  No, SSH and headless use are valid background outcomes. If the person chooses a manual operator attachment after
70
- a failure, find the `operator.agent` row with `rig ps --nodes --rig kernel --json`. Give the exact
71
- `env -u TMUX tmux attach-session -t '=<canonicalSessionName>'` with the observed name filled in for a new terminal
72
- on the same host and user (over SSH, connect there first). Ctrl-b, then d detaches without stopping it.
70
+ a failure, find the `operator.agent` row with
71
+ `rig ps --nodes --rig kernel --json --fields logicalId,canonicalSessionName,tmuxAttachCommand`. Give `env -u TMUX` followed by
72
+ that row's `tmuxAttachCommand`, exactly as listed (it names the daemon's tmux server when that isn't the default
73
+ one), for a new terminal on the same host and user (over SSH, connect there first). Ctrl-b, then d detaches without stopping it.
73
74
  Ask the person's goal and project folder, then hand them to the ready operator; do not implement the project yourself.
74
75
  Find the `operator.agent` row with `rig ps --nodes --rig kernel --json` and use its `canonicalSessionName` with
75
76
  `rig send <canonicalSessionName> 'This is the agent that installed OpenRig. The person will answer in your pane. Goal: <goal>. Project folder: <absolute path>.'`,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openrig-core",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "OpenRig canonical skills and hooks for cross-runtime agent topology coordination, continuity, and operating discipline.",
5
5
  "author": {
6
6
  "name": "Mike Schwarz",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openrig-core",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "OpenRig canonical skills and hooks for cross-runtime agent topology coordination, continuity, and operating discipline.",
5
5
  "author": {
6
6
  "name": "Mike Schwarz",
@@ -1,6 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
3
 
4
+ const crypto = require("node:crypto");
5
+ const fs = require("node:fs");
6
+ const os = require("node:os");
7
+ const path = require("node:path");
8
+
4
9
  // OpenRig activity-relay hook script.
5
10
  // Reads a hook event payload from stdin, normalizes it, and POSTs to the
6
11
  // OpenRig daemon's /api/activity/hooks endpoint for real-time UI seat-status.
@@ -154,6 +159,13 @@ function buildSessionIdentityPayload(providerPayload, env = process.env, now = (
154
159
  const sessionName = firstString(env.OPENRIG_SESSION_NAME, env.RIGGED_SESSION_NAME);
155
160
  const nodeId = firstString(env.OPENRIG_NODE_ID, env.RIGGED_NODE_ID);
156
161
  const runtime = firstString(env.OPENRIG_RUNTIME, env.RIGGED_RUNTIME);
162
+ const generation = firstString(env.OPENRIG_OCCUPANT_GENERATION, env.RIGGED_OCCUPANT_GENERATION);
163
+ // How this session began (startup, resume, clear or compact). The daemon tells a resumed
164
+ // conversation's new id from a /clear by it; it is absent from runtimes that do not report it.
165
+ const source = firstString(providerPayload.source);
166
+ // Set only on the command OpenRig sends to resume this seat, so the daemon can tell the process
167
+ // it launched from another Claude sharing the seat's environment.
168
+ const resumeLaunch = firstString(env.OPENRIG_RESUME_LAUNCH);
157
169
 
158
170
  if ((!sessionName && !nodeId) || !runtime) return null;
159
171
 
@@ -162,18 +174,45 @@ function buildSessionIdentityPayload(providerPayload, env = process.env, now = (
162
174
  sessionName,
163
175
  nodeId,
164
176
  runtime,
177
+ generation,
165
178
  hookEvent,
179
+ source,
180
+ resumeLaunch,
181
+ // The daemon finds the Claude that ran this hook from its parent chain.
182
+ hookPid: process.pid,
166
183
  sessionId,
167
184
  occurredAt: now().toISOString(),
168
185
  };
169
186
  }
170
187
 
188
+ // #1077 — whether this is the first SessionStart of the launch OpenRig armed (OPENRIG_RESUME_LAUNCH
189
+ // for this occupant generation). Recorded on local disk before anything is posted, so a first hook
190
+ // whose post never reaches the daemon still makes every later one (an in-process /resume, a child
191
+ // sharing the environment) report false. Any error reports false.
192
+ function claimFirstLaunchHook(resumeLaunch, generation, dir = path.join(os.tmpdir(), `openrig-resume-launch-${uid()}`)) {
193
+ if (!resumeLaunch || !generation) return false;
194
+ try {
195
+ fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
196
+ const key = crypto.createHash("sha256").update(`${generation}\0${resumeLaunch}`).digest("hex");
197
+ fs.closeSync(fs.openSync(path.join(dir, key), "wx", 0o600));
198
+ return true;
199
+ } catch {
200
+ return false;
201
+ }
202
+ }
203
+
204
+ function uid() {
205
+ try { return typeof process.getuid === "function" ? String(process.getuid()) : "user"; } catch { return "user"; }
206
+ }
207
+
171
208
  async function main() {
172
209
  const providerPayload = parseJson(await readStdin());
173
210
  const payload = buildOpenRigPayload(providerPayload);
174
- await postHookPayload(payload);
175
-
176
211
  const identityPayload = buildSessionIdentityPayload(providerPayload, process.env);
212
+ if (identityPayload && identityPayload.resumeLaunch) {
213
+ identityPayload.resumeLaunchFirst = claimFirstLaunchHook(identityPayload.resumeLaunch, identityPayload.generation);
214
+ }
215
+ await postHookPayload(payload);
177
216
  if (identityPayload) {
178
217
  await postHookPayload(identityPayload);
179
218
  }
@@ -185,6 +224,7 @@ if (require.main === module) {
185
224
 
186
225
  module.exports = {
187
226
  buildOpenRigPayload,
227
+ claimFirstLaunchHook,
188
228
  buildSessionIdentityPayload,
189
229
  parseJson,
190
230
  postHookPayload,
@@ -102,10 +102,29 @@ function readConfiguredContent(home) {
102
102
  // current work, its basis travels to the trace script, which alone decides how to render it;
103
103
  // a failed or unreadable answer is passed as UNKNOWN. Never guess a work node here: a guess
104
104
  // would silently re-point the whole trace.
105
+ // OPR.0.7.0.12 — the work packet, switched off by default: the trace receives the daemon's
106
+ // labelled work candidates and carries duties and notes as text. With it off, every path below
107
+ // is unchanged.
108
+ function workPacketEnabled() {
109
+ return enabled(process.env.OPENRIG_REFOCUS_WORK_PACKET, false);
110
+ }
111
+
105
112
  function readQueueWhoami(timeout = 2_000) {
106
- const result = spawnSync("rig", ["queue", "whoami", "--json"], {
113
+ const args = ["queue", "whoami", "--json", ...(workPacketEnabled() ? ["--work-candidates"] : [])];
114
+ let result = spawnSync("rig", args, {
107
115
  encoding: "utf8", env: process.env, timeout, maxBuffer: 16 * 1024 * 1024,
108
116
  });
117
+ // A rig CLI older than this hook rejects the flag. Ask again without it, inside what is left of
118
+ // the budget, so the role and the strict answer still arrive (just without candidates).
119
+ if (args.includes("--work-candidates") && !result.error && result.status !== 0
120
+ && /unknown option/i.test(`${result.stderr || ""}${result.stdout || ""}`)) {
121
+ const remaining = remainingLookupBudget();
122
+ if (remaining > 250) {
123
+ result = spawnSync("rig", ["queue", "whoami", "--json"], {
124
+ encoding: "utf8", env: process.env, timeout: remaining, maxBuffer: 16 * 1024 * 1024,
125
+ });
126
+ }
127
+ }
109
128
  if (result.error) return { unknown: `queue whoami failed: ${result.error.message}` };
110
129
  if (result.status !== 0 || !result.stdout || !result.stdout.trim()) {
111
130
  return { unknown: `queue whoami exited ${result.status ?? "without a status"} with no answer` };
@@ -208,11 +227,31 @@ function renderTrace() {
208
227
  }
209
228
  role = renderRole(whoami);
210
229
  }
211
- if (work.start) args.push("--work-start", work.start);
230
+ const packet = workPacketEnabled();
231
+ let evidence = null;
232
+ if (packet) {
233
+ args.push("--packet");
234
+ if (trees !== "topology") {
235
+ if (!whoami) {
236
+ const timeout = remainingLookupBudget();
237
+ whoami = timeout > 250 ? readQueueWhoami(timeout) : { unknown: "no budget left" };
238
+ }
239
+ const candidates = whoami.answer?.workCandidates;
240
+ if (candidates && typeof candidates === "object") evidence = JSON.stringify(candidates);
241
+ }
242
+ }
243
+ // An explicit start always wins. Otherwise the candidates replace the strict answer: the
244
+ // strict node ignores mission-only rows, so it could hide a second mission in flight.
245
+ const explicitStart = Boolean(process.env.OPENRIG_REFOCUS_WORK_NODE);
246
+ if (work.start && (explicitStart || !evidence)) args.push("--work-start", work.start);
247
+ else if (evidence) args.push("--work-candidates", "-");
212
248
  else if (work.basis) args.push("--work-basis", work.basis);
213
249
  else if (work.unknown) args.push("--work-unknown", work.unknown);
250
+ // With an explicit start, the evidence supplies only held and next work.
251
+ if (explicitStart && evidence) args.push("--work-candidates", "-");
214
252
  const result = spawnSync(process.env.PYTHON || "python3", args, {
215
253
  encoding: "utf8",
254
+ ...(evidence ? { input: evidence } : {}),
216
255
  env: traceEnv(trees),
217
256
  timeout: 2_000,
218
257
  maxBuffer: 16 * 1024 * 1024,
@@ -104,10 +104,18 @@ a JSON array of 1–4 questions, each
104
104
  options (labels up to 75 characters, at most one recommended). Slack shows each
105
105
  question as a row of buttons. Each click records that answer on the item, and
106
106
  the decision resolves once every question has one. You then receive one reply
107
- row listing the answers, and the item's `humanAnswers` holds the option ids. The
108
- human may instead type a reply in the thread; that resolves the decision as
109
- usual, so read the reply rather than assuming an option was picked. Keep the
110
- brief complete: the questions add buttons, they do not replace the explanation.
107
+ row listing the answers. In `humanAnswers`, clicked answers are option-id strings.
108
+ A whole typed reply is an object:
109
+ `{kind: "typed-reply", text: "…", placement: "first-unanswered", unansweredCount: N}`.
110
+ It is placed automatically under the first unanswered question; the person did
111
+ not select that question. `N` counts the other question slots still empty in
112
+ `humanAnswers` after that placement.
113
+ Earlier button answers stay intact. Read `text` as the person's words, never as
114
+ an option id even if the strings match. The typed reply still closes the decision
115
+ with the other questions unanswered; `done` is not approval. If every button
116
+ answer was already recorded, that final answer set stays intact and the typed
117
+ reply remains in its correlated reply row. Keep the brief complete: the questions
118
+ add buttons, they do not replace the explanation.
111
119
 
112
120
  If an existing agent-owned row must wait for a **decision**, block it on the **new live qitem ID**
113
121
  (`rig queue block <work-id> --on <human-qitem-id> ...`), not on the human address.
@@ -1302,7 +1302,7 @@ Node-granular managed partial restore (v0.3.4+):
1302
1302
  ### Add a member to an existing pod — v0.3.3+
1303
1303
 
1304
1304
  ```bash
1305
- rig add <rig-id> <pod-namespace> <member-fragment-path> [--json]
1305
+ rig add <rig> <pod-namespace> <member-fragment-path> [--json]
1306
1306
  ```
1307
1307
 
1308
1308
  `rig add` is the top-level verb for the `add_member` converge op. It adds a
@@ -1310,6 +1310,12 @@ single member to an existing pod from a YAML/JSON member fragment file. The
1310
1310
  daemon resolves the named pod, validates the member, runs preflight, and
1311
1311
  launches the member in place.
1312
1312
 
1313
+ `<rig>` is the rig id or its exact name (the `rigName` that `rig whoami --json`
1314
+ reports). A name shared by more than one rig is refused before anything is
1315
+ added, with the matching ids listed (`rig_ambiguous` under `--json`). `rig add`
1316
+ always targets the local daemon: while a remote host is selected it refuses to
1317
+ resolve a name (`remote_host_selected`); an exact local id still works.
1318
+
1313
1319
  HTTP outcomes:
1314
1320
  - `201` — member added; per-node launch state included in the response.
1315
1321
  - `400` — `validation_failed` or `preflight_failed` (the fragment or its launch posture is rejected before any state change).
@@ -2,10 +2,12 @@
2
2
  """Render topology and work context by ascending directory paths only."""
3
3
 
4
4
  import argparse
5
+ import datetime
5
6
  import json
6
7
  import os
7
8
  import re
8
9
  import subprocess
10
+ import sys
9
11
  from pathlib import Path
10
12
 
11
13
  SHELVES = {"rigs", "pods", "seats", "missions", "slices"}
@@ -148,7 +150,82 @@ def light_learned(text):
148
150
  return body[:boundary if boundary > 0 else 800].rstrip() + "\n[… use --depth full for the rest]"
149
151
 
150
152
 
151
- def render_topology(start, root, depth, failures):
153
+ # OPR.0.7.0.12 — the refocus packet (--packet). Duties and notes are carried as text by
154
+ # conventional section, with an honest "not found" and a bounded excerpt otherwise; nobody is
155
+ # asked to add headings. Old files are named with their measured age as a cue, not a verdict.
156
+ DUTY_HEADINGS = ("my job here", "standing duties")
157
+ NOTES_STATE_HEADINGS = ("current state",)
158
+ HEADING = re.compile(r"^(#{1,6})\s+(.*?)\s*#*\s*$")
159
+ DEFAULT_NOTES_MAX_AGE_DAYS = 14
160
+
161
+
162
+ def heading_sections(text, wanted):
163
+ """[(title, body)] for each Markdown heading whose title starts with a wanted phrase."""
164
+ lines = re.sub(r"^---\s*\n.*?\n---\s*\n", "", text or "", count=1, flags=re.S).splitlines()
165
+ found = []
166
+ for index, line in enumerate(lines):
167
+ match = HEADING.match(line)
168
+ if not match or not match.group(2).strip().lower().startswith(wanted):
169
+ continue
170
+ level = len(match.group(1))
171
+ body = []
172
+ for later in lines[index + 1:]:
173
+ heading = HEADING.match(later)
174
+ if heading and len(heading.group(1)) <= level:
175
+ break
176
+ body.append(later)
177
+ found.append((match.group(2).strip(), "\n".join(body).strip()))
178
+ return found
179
+
180
+
181
+ def by_section(text, wanted, path):
182
+ found = heading_sections(text, wanted)
183
+ shown = "\n\n".join(f"{title}\n{body}" if body else title for title, body in found)
184
+ missing = [phrase for phrase in wanted if not any(title.lower().startswith(phrase) for title, _ in found)]
185
+ if not missing:
186
+ return shown
187
+ if not found:
188
+ names = " or ".join(f'"{phrase.upper()}"' for phrase in wanted)
189
+ return f"SECTION NOT FOUND — no {names} heading in {path}; bounded excerpt follows\n{light_learned(text)}"
190
+ # Some sections matched: name each one that did not, with the same bounded excerpt, so text
191
+ # kept under another heading is not silently dropped.
192
+ names = ", ".join(f'"{phrase.upper()}"' for phrase in missing)
193
+ return f"{shown}\n\nSECTION NOT FOUND — no {names} heading in {path}; bounded excerpt follows\n{light_learned(text)}"
194
+
195
+
196
+ def notes_max_age_days():
197
+ try:
198
+ value = float(os.environ.get("OPENRIG_REFOCUS_NOTES_MAX_AGE_DAYS", DEFAULT_NOTES_MAX_AGE_DAYS))
199
+ except ValueError:
200
+ return DEFAULT_NOTES_MAX_AGE_DAYS
201
+ return value if value > 0 else DEFAULT_NOTES_MAX_AGE_DAYS
202
+
203
+
204
+ def age_cue(path, text):
205
+ """An OLD NOTES line when the file is past the threshold, measured from `updated:` or mtime."""
206
+ threshold = notes_max_age_days()
207
+ updated, source = None, "mtime"
208
+ match = re.match(r"^---\s*\n(.*?)\n---", text or "", re.S)
209
+ if match:
210
+ found = re.search(r"^updated:\s*[\"']?(\d{4}-\d{2}-\d{2})", match.group(1), re.M)
211
+ if found:
212
+ try:
213
+ updated = datetime.datetime.strptime(found.group(1), "%Y-%m-%d").replace(tzinfo=datetime.timezone.utc)
214
+ source = "updated"
215
+ except ValueError:
216
+ updated = None
217
+ if updated is None:
218
+ try:
219
+ updated = datetime.datetime.fromtimestamp(path.stat().st_mtime, datetime.timezone.utc)
220
+ except OSError:
221
+ return None
222
+ age = (datetime.datetime.now(datetime.timezone.utc) - updated).total_seconds() / 86400
223
+ if age <= threshold:
224
+ return None
225
+ return f"OLD NOTES — {path}, {age:.0f} days old, source {source}, threshold {threshold:g} days"
226
+
227
+
228
+ def render_topology(start, root, depth, failures, packet=False):
152
229
  output = ["## TOPOLOGY TRACE", f"root: {root}", f"start: {start}"]
153
230
  nodes, error = ascent(start, root)
154
231
  if error:
@@ -161,12 +238,21 @@ def render_topology(start, root, depth, failures):
161
238
  if text is None:
162
239
  output.append(f"\n### {label}\nMISSING LINK — {chain_file}")
163
240
  continue
164
- body = text.strip() if depth == "full" else light_learned(text)
241
+ if depth == "full":
242
+ body = text.strip()
243
+ elif packet and node == nodes[-1]:
244
+ # The seat's own file: its job and standing duties as text.
245
+ body = by_section(text, DUTY_HEADINGS, chain_file)
246
+ else:
247
+ body = light_learned(text)
165
248
  output.append(f"\n### {label} · LEARNED.md\n{body}")
249
+ cue = age_cue(chain_file, text) if packet else None
250
+ if cue:
251
+ output.append(cue)
166
252
  return "\n".join(output)
167
253
 
168
254
 
169
- def render_work(start, root, depth, failures, fallback=None):
255
+ def render_work(start, root, depth, failures, fallback=None, packet=False):
170
256
  output = ["## WORK TRACE", f"root: {root}", f"start: {start}"]
171
257
  if fallback:
172
258
  output.append(f"FALLBACK — {fallback}")
@@ -201,6 +287,19 @@ def render_work(start, root, depth, failures, fallback=None):
201
287
  output.append(f"NOTES RESOLUTION GAP — resolved {notes_name} became unreadable at {notes_path}")
202
288
  else:
203
289
  output.append(f"\nNOTES · {notes_name}\n{notes_text.strip()}")
290
+ cue = age_cue(notes_path, notes_text) if packet else None
291
+ if cue:
292
+ output.append(cue)
293
+ elif packet:
294
+ notes_text = read(notes_path)
295
+ if notes_text is None:
296
+ failures.append(f"unreadable notes: {notes_path}")
297
+ output.append(f"NOTES RESOLUTION GAP — resolved {notes_name} became unreadable at {notes_path}")
298
+ else:
299
+ output.append(f"\nNOTES · {notes_name}\n{by_section(notes_text, NOTES_STATE_HEADINGS, notes_path)}")
300
+ cue = age_cue(notes_path, notes_text)
301
+ if cue:
302
+ output.append(cue)
204
303
  else:
205
304
  try:
206
305
  size = notes_path.stat().st_size
@@ -211,9 +310,107 @@ def render_work(start, root, depth, failures, fallback=None):
211
310
  output.append(f"NOTES · {notes_name} · {size} bytes · {notes_path}")
212
311
  else:
213
312
  output.append(f"NOTES GAP — no readable mission notes at {node}")
313
+
314
+ # The SDLC convention keeps a node's current delivery state in PROGRESS.md; carry it
315
+ # as text when present. Its absence is not a gap: many nodes have no PROGRESS.md.
316
+ progress_path = node / "PROGRESS.md"
317
+ progress_text = read(progress_path) if packet else None
318
+ if progress_text is not None:
319
+ progress_body = progress_text.strip() if depth == "full" else by_section(progress_text, NOTES_STATE_HEADINGS, progress_path)
320
+ output.append(f"\nPROGRESS · PROGRESS.md\n{progress_body}")
321
+ cue = age_cue(progress_path, progress_text)
322
+ if cue:
323
+ output.append(cue)
324
+ return "\n".join(output)
325
+
326
+
327
+ def candidate_line(candidate):
328
+ name = candidate.get("mission") or "?"
329
+ if candidate.get("slice"):
330
+ name += f" / {candidate['slice']}"
331
+ intent_text = candidate.get("intent") or "no readable intent"
332
+ line = f"- {name} — {intent_text} — source: {candidate.get('source') or 'unknown'}"
333
+ if candidate.get("unresolved"):
334
+ line += f" — UNRESOLVED ON THIS HOST: {candidate['unresolved']}"
335
+ return line
336
+
337
+
338
+ def render_held_and_next(evidence):
339
+ output = []
340
+ held = evidence.get("held") or []
341
+ if held:
342
+ output.append("HELD WORK (blocked; this is not next):")
343
+ for row in held:
344
+ output.append(f"- {row.get('qitemId') or 'a row'} — {row.get('summary') or 'no summary'} — "
345
+ f"blocked on {row.get('blockedOn') or 'unknown'} — "
346
+ f"continuation: {row.get('continuation') or 'none recorded'}")
347
+ following = evidence.get("next") or []
348
+ if following:
349
+ output.append("POSSIBLE NEXT WORK (pending; no order implied):")
350
+ for row in following:
351
+ missions = ", ".join(row.get("missions") or [])
352
+ output.append(f"- {row.get('qitemId') or 'a row'} — {row.get('summary') or 'no summary'}"
353
+ + (f" [mission: {missions}]" if missions else ""))
354
+ if evidence.get("heldAndNextTruncated"):
355
+ output.append("(held and next lists were cut; `rig queue list` has the rest)")
214
356
  return "\n".join(output)
215
357
 
216
358
 
359
+ def render_candidates(evidence, root, depth, failures):
360
+ """The work section from labelled queue evidence. One direct, resolved tag is shown as the
361
+ work with its source; anything less certain lists every candidate and asks the agent."""
362
+ candidates = evidence.get("candidates") or []
363
+ unknown = evidence.get("unknown") or []
364
+ if (len(candidates) == 1 and not unknown and candidates[0].get("kind") == "tag"
365
+ and candidates[0].get("workNodePath") and not candidates[0].get("unresolved")):
366
+ only = candidates[0]
367
+ notes = [f"WORK FROM QUEUE EVIDENCE — {only.get('source')}. If this is stale, say what you are actually doing."]
368
+ if not only.get("slice"):
369
+ notes.append("no slice named")
370
+ traced = render_work(Path(only["workNodePath"]), root, depth, failures, packet=True)
371
+ head, _, rest = traced.partition("\n")
372
+ return "\n".join([head, *notes, rest])
373
+
374
+ missions_root = evidence.get("missionsRoot") or str(root / "missions")
375
+ output = ["## WORK — name it"]
376
+ if not candidates and not unknown:
377
+ output.append("No in-progress queue row names your work. If you are working from messages, "
378
+ "name the mission they belong to; if you have no current work, say so.")
379
+ elif len(candidates) > 1:
380
+ output.append(f"{len(candidates)} candidates are in flight. Say which mission you are actually working on.")
381
+ else:
382
+ output.append("The queue evidence does not settle your work. Confirm a candidate or name your mission.")
383
+ if candidates:
384
+ output.append("Candidates (evidence, not a verdict; none is adopted for you):")
385
+ output.extend(candidate_line(candidate) for candidate in candidates)
386
+ if unknown:
387
+ output.append("In-progress rows the queue cannot place:")
388
+ output.extend(f"- {row.get('qitemId') or 'a row'} — {row.get('summary') or 'no summary'}: {row.get('reason')}"
389
+ for row in unknown)
390
+ if not candidates:
391
+ names = evidence.get("missionsOnHost") or []
392
+ if names:
393
+ listing = ", ".join(names) + (", …" if evidence.get("missionsOnHostTruncated") else "")
394
+ output.append(f"Missions on this host: {listing}")
395
+ output.append("Then read that mission's current intent as text:")
396
+ output.append(f" python3 {Path(__file__).resolve()} --trees work --packet --work-start {missions_root}/<mission>")
397
+ orientation = render_work(root, root, "light", failures, packet=True)
398
+ _, _, rest = orientation.partition("\n")
399
+ output.append("\n## ORIENTATION — the project-level chain, not your work\n" + rest.lstrip("\n"))
400
+ return "\n".join(output)
401
+
402
+
403
+ def read_candidates(source):
404
+ try:
405
+ raw = sys.stdin.read() if source == "-" else Path(source).read_text(encoding="utf8")
406
+ evidence = json.loads(raw)
407
+ except (OSError, json.JSONDecodeError) as error:
408
+ return None, f"work candidates unreadable: {error}"
409
+ if not isinstance(evidence, dict) or not isinstance(evidence.get("candidates", []), list):
410
+ return None, "work candidates have an invalid shape"
411
+ return evidence, None
412
+
413
+
217
414
  def canonical_seat(session):
218
415
  """(member, rig) for a canonical session name, else None so the caller asks `rig whoami`.
219
416
 
@@ -279,6 +476,8 @@ def main():
279
476
  parser.add_argument("--work-basis", help="the daemon's reason no current work node was named")
280
477
  parser.add_argument("--work-unknown", help="why the current work node could not be read")
281
478
  parser.add_argument("--check", action="store_true", help="exit nonzero on trace or notes resolution failure; rendered text is unchanged")
479
+ parser.add_argument("--packet", action="store_true", help="carry duties and notes as text by section, with old-notes cues")
480
+ parser.add_argument("--work-candidates", help="labelled work evidence as JSON (a path, or - for stdin), from `rig queue whoami --work-candidates`")
282
481
  args = parser.parse_args()
283
482
 
284
483
  sections = []
@@ -293,7 +492,7 @@ def main():
293
492
  sections.append(gap("## TOPOLOGY TRACE\nTRACE GAP — topology.root is unresolved"))
294
493
  else:
295
494
  start = Path(args.topology_start) if args.topology_start else derive_topology_start(root)
296
- sections.append(render_topology(start, root, args.depth, failures) if start else
495
+ sections.append(render_topology(start, root, args.depth, failures, packet=args.packet) if start else
297
496
  gap("## TOPOLOGY TRACE\nTRACE GAP — current topology node is unresolved; pass --topology-start with a literal absolute path (or configure OPENRIG_REFOCUS_TOPOLOGY_NODE separately)"))
298
497
 
299
498
  if args.trees in {"work", "both"}:
@@ -304,10 +503,19 @@ def main():
304
503
  # Precedence: an explicit start wins; then the hook's daemon answer (basis or unknown);
305
504
  # only a standalone run with neither falls back to inferring from the working directory.
306
505
  explicit = args.work_start or os.environ.get("OPENRIG_REFOCUS_WORK_NODE")
506
+ evidence = None
507
+ if args.work_candidates:
508
+ evidence, error = read_candidates(args.work_candidates)
509
+ if error:
510
+ sections.append(gap(f"## WORK TRACE\nTRACE GAP — {error}"))
307
511
  if explicit:
308
- sections.append(render_work(Path(explicit), root, args.depth, failures))
512
+ sections.append(render_work(Path(explicit), root, args.depth, failures, packet=args.packet))
513
+ elif evidence is not None:
514
+ sections.append(render_candidates(evidence, root, args.depth, failures))
515
+ elif args.work_candidates:
516
+ pass # the unreadable-evidence gap above is the answer; never fall back to the root
309
517
  elif args.work_basis == NO_CURRENT_BATON_BASIS:
310
- sections.append(render_work(root, root, args.depth, failures, fallback=(
518
+ sections.append(render_work(root, root, args.depth, failures, packet=args.packet, fallback=(
311
519
  f"no current typed baton ({args.work_basis}). Showing the project-level chain from the work root: "
312
520
  "a broad orientation, not evidence of a current mission")))
313
521
  elif args.work_basis:
@@ -316,8 +524,11 @@ def main():
316
524
  sections.append(gap(f"## WORK TRACE\nTRACE GAP — current work node UNKNOWN: {args.work_unknown}"))
317
525
  else:
318
526
  start = derive_work_start(root)
319
- sections.append(render_work(start, root, args.depth, failures) if start else
527
+ sections.append(render_work(start, root, args.depth, failures, packet=args.packet) if start else
320
528
  gap("## WORK TRACE\nTRACE GAP — current work node is unresolved; pass --work-start with a literal absolute path (or configure OPENRIG_REFOCUS_WORK_NODE separately)"))
529
+ held_and_next = render_held_and_next(evidence) if evidence else ""
530
+ if held_and_next:
531
+ sections.append(held_and_next)
321
532
 
322
533
  print("\n\n".join(sections))
323
534
  return 1 if args.check and failures else 0
@@ -68,9 +68,10 @@ guidance in `AGENTS.md` or `CLAUDE.md` plus the team's skills and plugins. Say s
68
68
  and ends with `run:` and a command (the `error` field with `--json`). That command already names the installed
69
69
  herdr binary and the daemon's socket, or the conversation to attach. Relay it exactly rather than composing one.
70
70
  If a note asks you to place the view once Herdr starts, run that `rig terminal open` yourself after they start it.
71
- - **If it printed no command:** find `operator.agent` in `rig ps --nodes --rig kernel --json`, take its
72
- `canonicalSessionName` (never a guessed name) and give
73
- `env -u TMUX tmux attach-session -t '=<canonicalSessionName>'` for the operator's conversation.
71
+ - **If it printed no command:** find `operator.agent` in
72
+ `rig ps --nodes --rig kernel --json --fields logicalId,canonicalSessionName,tmuxAttachCommand` and give
73
+ `env -u TMUX` followed by its `tmuxAttachCommand`, exactly as listed (never a guessed name), for the operator's
74
+ conversation. That command names the daemon's tmux server when it isn't the default one.
74
75
 
75
76
  For any other failure, the table under "What can interrupt installation and the OpenRig view" in
76
77
  `rig context get reference/getting-started.md#open-the-kernel-conversations` says why and what to do next.
@@ -80,7 +81,8 @@ guidance in `AGENTS.md` or `CLAUDE.md` plus the team's skills and plugins. Say s
80
81
  `rig send <canonicalSessionName> 'This is the agent that installed OpenRig. The person will answer in your pane. Goal: <goal>. Project folder: <absolute path>. Branch: <branch>.'`
81
82
  Or the person types the goal and folder in the operator's pane. If they give you a goal later, forward it the same
82
83
  way. The operator helps them pick a team that fits their logins, starts it on their yes and gives the goal to the
83
- team's lead. Show them where the operator answers, and don't build the project yourself.
84
+ team's lead. Before that yes, it says what launching into their folder changes for their own agent there; relay
85
+ that with the question. Show them where the operator answers, and don't build the project yourself.
84
86
  - **Relay the operator's questions:** the operator asks in its own pane, and the person may not be looking there.
85
87
  After each step you hand it, read its screen with `rig capture <canonicalSessionName>`. When it asks the person
86
88
  something (start this team? which folder? which option?), ask them here in the operator's words and send their
@@ -1,6 +1,6 @@
1
1
  # Agent help: the single troubleshooting and escalation guide (docs/reference/help.md).
2
2
  name: help
3
- version: "0.6.8"
3
+ version: "0.6.10"
4
4
  taxonomy: world
5
5
  purpose: "What an agent does when its user says OpenRig isn't working: diagnose, fix within permissions, verify, and escalate to OpenRig support."
6
6
  files:
@@ -1,6 +1,6 @@
1
1
  # Public capability and source-map width for the default onboarding walk.
2
2
  name: onboarding-width
3
- version: "0.6.8"
3
+ version: "0.6.10"
4
4
  taxonomy: world
5
5
  purpose: "The public capability map and source map referenced by the default onboarding walk."
6
6
  files: