@polderlabs/bizar-omp 0.6.1 → 0.6.3

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 (403) hide show
  1. package/README.md +59 -2
  2. package/dist/cli/agents-ink.d.ts.map +1 -1
  3. package/dist/cli/agents-ink.js +11 -10
  4. package/dist/cli/agents-ink.js.map +1 -1
  5. package/dist/cli/agents.d.ts +1 -0
  6. package/dist/cli/agents.d.ts.map +1 -1
  7. package/dist/cli/agents.js +11 -0
  8. package/dist/cli/agents.js.map +1 -1
  9. package/dist/cli/directory-selector.d.ts +36 -0
  10. package/dist/cli/directory-selector.d.ts.map +1 -1
  11. package/dist/cli/directory-selector.js +25 -0
  12. package/dist/cli/directory-selector.js.map +1 -1
  13. package/dist/cli/main.js +0 -0
  14. package/dist/cli/omb-commands.d.ts +30 -0
  15. package/dist/cli/omb-commands.d.ts.map +1 -0
  16. package/dist/cli/omb-commands.js +109 -0
  17. package/dist/cli/omb-commands.js.map +1 -0
  18. package/dist/cli/omb-daemon.d.ts +1 -0
  19. package/dist/cli/omb-daemon.d.ts.map +1 -1
  20. package/dist/cli/omb-daemon.js +15 -1
  21. package/dist/cli/omb-daemon.js.map +1 -1
  22. package/dist/cli/omb-dashboard.d.ts +1 -1
  23. package/dist/cli/omb-dashboard.d.ts.map +1 -1
  24. package/dist/cli/omb-dashboard.js +2 -1
  25. package/dist/cli/omb-dashboard.js.map +1 -1
  26. package/dist/cli/omb-runtime.d.ts +42 -0
  27. package/dist/cli/omb-runtime.d.ts.map +1 -0
  28. package/dist/cli/omb-runtime.js +507 -0
  29. package/dist/cli/omb-runtime.js.map +1 -0
  30. package/dist/cli/omb-tray.d.ts +3 -0
  31. package/dist/cli/omb-tray.d.ts.map +1 -0
  32. package/dist/cli/omb-tray.js +44 -0
  33. package/dist/cli/omb-tray.js.map +1 -0
  34. package/dist/cli/omb.js +8 -33
  35. package/dist/cli/omb.js.map +1 -1
  36. package/dist/extension.d.ts +2 -1
  37. package/dist/extension.d.ts.map +1 -1
  38. package/dist/extension.js +160 -33
  39. package/dist/extension.js.map +1 -1
  40. package/dist/omp/daemon-service.d.ts.map +1 -1
  41. package/dist/omp/daemon-service.js +6 -3
  42. package/dist/omp/daemon-service.js.map +1 -1
  43. package/dist/omp/daemon.d.ts +1 -0
  44. package/dist/omp/daemon.d.ts.map +1 -1
  45. package/dist/omp/daemon.js +1 -1
  46. package/dist/omp/daemon.js.map +1 -1
  47. package/dist/omp/dashboard-html.d.ts.map +1 -1
  48. package/dist/omp/dashboard-html.js +360 -38
  49. package/dist/omp/dashboard-html.js.map +1 -1
  50. package/dist/omp/model-role-assignment.d.ts +166 -1
  51. package/dist/omp/model-role-assignment.d.ts.map +1 -1
  52. package/dist/omp/model-role-assignment.js +393 -4
  53. package/dist/omp/model-role-assignment.js.map +1 -1
  54. package/dist/omp/omb-sessions.d.ts +44 -0
  55. package/dist/omp/omb-sessions.d.ts.map +1 -1
  56. package/dist/omp/omb-sessions.js +160 -52
  57. package/dist/omp/omb-sessions.js.map +1 -1
  58. package/dist/omp/omb-settings.d.ts +16 -0
  59. package/dist/omp/omb-settings.d.ts.map +1 -1
  60. package/dist/omp/omb-settings.js +55 -3
  61. package/dist/omp/omb-settings.js.map +1 -1
  62. package/dist/omp/run-log.d.ts +26 -0
  63. package/dist/omp/run-log.d.ts.map +1 -0
  64. package/dist/omp/run-log.js +24 -0
  65. package/dist/omp/run-log.js.map +1 -0
  66. package/dist/omp/tmux.d.ts +38 -2
  67. package/dist/omp/tmux.d.ts.map +1 -1
  68. package/dist/omp/tmux.js +231 -46
  69. package/dist/omp/tmux.js.map +1 -1
  70. package/dist/omp/tray.d.ts +2 -0
  71. package/dist/omp/tray.d.ts.map +1 -1
  72. package/dist/omp/tray.js +31 -5
  73. package/dist/omp/tray.js.map +1 -1
  74. package/dist/src/cli/agents-ink.d.ts +25 -0
  75. package/dist/src/cli/agents-ink.js +517 -0
  76. package/dist/src/cli/agents-ink.js.map +1 -0
  77. package/dist/src/cli/agents.d.ts +14 -0
  78. package/dist/src/cli/agents.js +197 -0
  79. package/dist/src/cli/agents.js.map +1 -0
  80. package/dist/src/cli/directory-selector.d.ts +60 -0
  81. package/dist/src/cli/directory-selector.js +208 -0
  82. package/dist/src/cli/directory-selector.js.map +1 -0
  83. package/dist/src/cli/doctor.d.ts +41 -0
  84. package/dist/src/cli/doctor.js +31 -0
  85. package/dist/src/cli/doctor.js.map +1 -0
  86. package/dist/src/cli/install.d.ts +129 -0
  87. package/dist/src/cli/install.js +164 -0
  88. package/dist/src/cli/install.js.map +1 -0
  89. package/dist/src/cli/main.d.ts +2 -0
  90. package/dist/src/cli/main.js +117 -0
  91. package/dist/src/cli/main.js.map +1 -0
  92. package/dist/src/cli/migrate.d.ts +18 -0
  93. package/dist/src/cli/migrate.js +14 -0
  94. package/dist/src/cli/migrate.js.map +1 -0
  95. package/dist/src/cli/omb-commands.d.ts +29 -0
  96. package/dist/src/cli/omb-commands.js +107 -0
  97. package/dist/src/cli/omb-commands.js.map +1 -0
  98. package/dist/src/cli/omb-daemon.d.ts +2 -0
  99. package/dist/src/cli/omb-daemon.js +135 -0
  100. package/dist/src/cli/omb-daemon.js.map +1 -0
  101. package/dist/src/cli/omb-dashboard.d.ts +12 -0
  102. package/dist/src/cli/omb-dashboard.js +113 -0
  103. package/dist/src/cli/omb-dashboard.js.map +1 -0
  104. package/dist/src/cli/omb-invocation.d.ts +8 -0
  105. package/dist/src/cli/omb-invocation.js +41 -0
  106. package/dist/src/cli/omb-invocation.js.map +1 -0
  107. package/dist/src/cli/omb-runtime.d.ts +41 -0
  108. package/dist/src/cli/omb-runtime.js +371 -0
  109. package/dist/src/cli/omb-runtime.js.map +1 -0
  110. package/dist/src/cli/omb-tray.d.ts +2 -0
  111. package/dist/src/cli/omb-tray.js +38 -0
  112. package/dist/src/cli/omb-tray.js.map +1 -0
  113. package/dist/src/cli/omb.d.ts +2 -0
  114. package/dist/src/cli/omb.js +31 -0
  115. package/dist/src/cli/omb.js.map +1 -0
  116. package/dist/src/cli/omp-theme.d.ts +17 -0
  117. package/dist/src/cli/omp-theme.js +22 -0
  118. package/dist/src/cli/omp-theme.js.map +1 -0
  119. package/dist/src/cli/process.d.ts +6 -0
  120. package/dist/src/cli/process.js +54 -0
  121. package/dist/src/cli/process.js.map +1 -0
  122. package/dist/src/cli/run.d.ts +2 -0
  123. package/dist/src/cli/run.js +5 -0
  124. package/dist/src/cli/run.js.map +1 -0
  125. package/dist/src/cli/setup-ui.d.ts +37 -0
  126. package/dist/src/cli/setup-ui.js +90 -0
  127. package/dist/src/cli/setup-ui.js.map +1 -0
  128. package/dist/src/core/acceptance.d.ts +32 -0
  129. package/dist/src/core/acceptance.js +87 -0
  130. package/dist/src/core/acceptance.js.map +1 -0
  131. package/dist/src/core/errors.d.ts +20 -0
  132. package/dist/src/core/errors.js +30 -0
  133. package/dist/src/core/errors.js.map +1 -0
  134. package/dist/src/core/evidence.d.ts +10 -0
  135. package/dist/src/core/evidence.js +35 -0
  136. package/dist/src/core/evidence.js.map +1 -0
  137. package/dist/src/core/policies.d.ts +10 -0
  138. package/dist/src/core/policies.js +60 -0
  139. package/dist/src/core/policies.js.map +1 -0
  140. package/dist/src/core/recovery.d.ts +6 -0
  141. package/dist/src/core/recovery.js +56 -0
  142. package/dist/src/core/recovery.js.map +1 -0
  143. package/dist/src/core/transitions.d.ts +13 -0
  144. package/dist/src/core/transitions.js +59 -0
  145. package/dist/src/core/transitions.js.map +1 -0
  146. package/dist/src/core/types.d.ts +256 -0
  147. package/dist/src/core/types.js +2 -0
  148. package/dist/src/core/types.js.map +1 -0
  149. package/dist/src/extension.d.ts +60 -0
  150. package/dist/src/extension.js +538 -0
  151. package/dist/src/extension.js.map +1 -0
  152. package/dist/src/index.d.ts +29 -0
  153. package/dist/src/index.js +30 -0
  154. package/dist/src/index.js.map +1 -0
  155. package/dist/src/omp/autonomous-settings.d.ts +14 -0
  156. package/dist/src/omp/autonomous-settings.js +65 -0
  157. package/dist/src/omp/autonomous-settings.js.map +1 -0
  158. package/dist/src/omp/capabilities.d.ts +23 -0
  159. package/dist/src/omp/capabilities.js +6 -0
  160. package/dist/src/omp/capabilities.js.map +1 -0
  161. package/dist/src/omp/compatibility.d.ts +30 -0
  162. package/dist/src/omp/compatibility.js +34 -0
  163. package/dist/src/omp/compatibility.js.map +1 -0
  164. package/dist/src/omp/completion.d.ts +7 -0
  165. package/dist/src/omp/completion.js +10 -0
  166. package/dist/src/omp/completion.js.map +1 -0
  167. package/dist/src/omp/config.d.ts +10 -0
  168. package/dist/src/omp/config.js +14 -0
  169. package/dist/src/omp/config.js.map +1 -0
  170. package/dist/src/omp/context.d.ts +15 -0
  171. package/dist/src/omp/context.js +3 -0
  172. package/dist/src/omp/context.js.map +1 -0
  173. package/dist/src/omp/daemon-service.d.ts +25 -0
  174. package/dist/src/omp/daemon-service.js +483 -0
  175. package/dist/src/omp/daemon-service.js.map +1 -0
  176. package/dist/src/omp/daemon.d.ts +48 -0
  177. package/dist/src/omp/daemon.js +194 -0
  178. package/dist/src/omp/daemon.js.map +1 -0
  179. package/dist/src/omp/dashboard-html.d.ts +3 -0
  180. package/dist/src/omp/dashboard-html.js +419 -0
  181. package/dist/src/omp/dashboard-html.js.map +1 -0
  182. package/dist/src/omp/dispatch-admission.d.ts +2 -0
  183. package/dist/src/omp/dispatch-admission.js +12 -0
  184. package/dist/src/omp/dispatch-admission.js.map +1 -0
  185. package/dist/src/omp/integration-recovery.d.ts +10 -0
  186. package/dist/src/omp/integration-recovery.js +18 -0
  187. package/dist/src/omp/integration-recovery.js.map +1 -0
  188. package/dist/src/omp/isolation-policy.d.ts +14 -0
  189. package/dist/src/omp/isolation-policy.js +9 -0
  190. package/dist/src/omp/isolation-policy.js.map +1 -0
  191. package/dist/src/omp/lifecycle.d.ts +14 -0
  192. package/dist/src/omp/lifecycle.js +14 -0
  193. package/dist/src/omp/lifecycle.js.map +1 -0
  194. package/dist/src/omp/memory.d.ts +16 -0
  195. package/dist/src/omp/memory.js +4 -0
  196. package/dist/src/omp/memory.js.map +1 -0
  197. package/dist/src/omp/model-role-assignment.d.ts +296 -0
  198. package/dist/src/omp/model-role-assignment.js +559 -0
  199. package/dist/src/omp/model-role-assignment.js.map +1 -0
  200. package/dist/src/omp/model-roles.d.ts +19 -0
  201. package/dist/src/omp/model-roles.js +6 -0
  202. package/dist/src/omp/model-roles.js.map +1 -0
  203. package/dist/src/omp/omb-sessions.d.ts +122 -0
  204. package/dist/src/omp/omb-sessions.js +512 -0
  205. package/dist/src/omp/omb-sessions.js.map +1 -0
  206. package/dist/src/omp/omb-settings.d.ts +35 -0
  207. package/dist/src/omp/omb-settings.js +104 -0
  208. package/dist/src/omp/omb-settings.js.map +1 -0
  209. package/dist/src/omp/result-reconciliation.d.ts +2 -0
  210. package/dist/src/omp/result-reconciliation.js +9 -0
  211. package/dist/src/omp/result-reconciliation.js.map +1 -0
  212. package/dist/src/omp/rpc.d.ts +67 -0
  213. package/dist/src/omp/rpc.js +4 -0
  214. package/dist/src/omp/rpc.js.map +1 -0
  215. package/dist/src/omp/run-log.d.ts +25 -0
  216. package/dist/src/omp/run-log.js +24 -0
  217. package/dist/src/omp/run-log.js.map +1 -0
  218. package/dist/src/omp/session-activity.d.ts +70 -0
  219. package/dist/src/omp/session-activity.js +361 -0
  220. package/dist/src/omp/session-activity.js.map +1 -0
  221. package/dist/src/omp/session-controls.d.ts +17 -0
  222. package/dist/src/omp/session-controls.js +14 -0
  223. package/dist/src/omp/session-controls.js.map +1 -0
  224. package/dist/src/omp/tmux.d.ts +89 -0
  225. package/dist/src/omp/tmux.js +445 -0
  226. package/dist/src/omp/tmux.js.map +1 -0
  227. package/dist/src/omp/tray-icons.d.ts +5 -0
  228. package/dist/src/omp/tray-icons.js +78 -0
  229. package/dist/src/omp/tray-icons.js.map +1 -0
  230. package/dist/src/omp/tray.d.ts +23 -0
  231. package/dist/src/omp/tray.js +167 -0
  232. package/dist/src/omp/tray.js.map +1 -0
  233. package/dist/src/services/budget.d.ts +19 -0
  234. package/dist/src/services/budget.js +10 -0
  235. package/dist/src/services/budget.js.map +1 -0
  236. package/dist/src/services/candidate-local.d.ts +13 -0
  237. package/dist/src/services/candidate-local.js +15 -0
  238. package/dist/src/services/candidate-local.js.map +1 -0
  239. package/dist/src/services/candidates.d.ts +20 -0
  240. package/dist/src/services/candidates.js +100 -0
  241. package/dist/src/services/candidates.js.map +1 -0
  242. package/dist/src/services/evidence-bundle.d.ts +17 -0
  243. package/dist/src/services/evidence-bundle.js +21 -0
  244. package/dist/src/services/evidence-bundle.js.map +1 -0
  245. package/dist/src/services/inspector.d.ts +11 -0
  246. package/dist/src/services/inspector.js +6 -0
  247. package/dist/src/services/inspector.js.map +1 -0
  248. package/dist/src/services/lessons.d.ts +13 -0
  249. package/dist/src/services/lessons.js +11 -0
  250. package/dist/src/services/lessons.js.map +1 -0
  251. package/dist/src/services/projection.d.ts +21 -0
  252. package/dist/src/services/projection.js +10 -0
  253. package/dist/src/services/projection.js.map +1 -0
  254. package/dist/src/services/readiness.d.ts +4 -0
  255. package/dist/src/services/readiness.js +35 -0
  256. package/dist/src/services/readiness.js.map +1 -0
  257. package/dist/src/services/recipes.d.ts +15 -0
  258. package/dist/src/services/recipes.js +42 -0
  259. package/dist/src/services/recipes.js.map +1 -0
  260. package/dist/src/services/recovery.d.ts +19 -0
  261. package/dist/src/services/recovery.js +9 -0
  262. package/dist/src/services/recovery.js.map +1 -0
  263. package/dist/src/services/review.d.ts +15 -0
  264. package/dist/src/services/review.js +9 -0
  265. package/dist/src/services/review.js.map +1 -0
  266. package/dist/src/storage/journal-recovery.d.ts +10 -0
  267. package/dist/src/storage/journal-recovery.js +33 -0
  268. package/dist/src/storage/journal-recovery.js.map +1 -0
  269. package/dist/src/storage/journal.d.ts +12 -0
  270. package/dist/src/storage/journal.js +82 -0
  271. package/dist/src/storage/journal.js.map +1 -0
  272. package/dist/src/storage/migrations.d.ts +22 -0
  273. package/dist/src/storage/migrations.js +107 -0
  274. package/dist/src/storage/migrations.js.map +1 -0
  275. package/dist/src/storage/repository-identity.d.ts +11 -0
  276. package/dist/src/storage/repository-identity.js +67 -0
  277. package/dist/src/storage/repository-identity.js.map +1 -0
  278. package/dist/src/storage/resources.d.ts +66 -0
  279. package/dist/src/storage/resources.js +148 -0
  280. package/dist/src/storage/resources.js.map +1 -0
  281. package/dist/src/tools/evidence.d.ts +8 -0
  282. package/dist/src/tools/evidence.js +9 -0
  283. package/dist/src/tools/evidence.js.map +1 -0
  284. package/dist/src/tools/integrate.d.ts +13 -0
  285. package/dist/src/tools/integrate.js +90 -0
  286. package/dist/src/tools/integrate.js.map +1 -0
  287. package/dist/src/tools/result.d.ts +9 -0
  288. package/dist/src/tools/result.js +2 -0
  289. package/dist/src/tools/result.js.map +1 -0
  290. package/dist/src/tools/verify.d.ts +13 -0
  291. package/dist/src/tools/verify.js +61 -0
  292. package/dist/src/tools/verify.js.map +1 -0
  293. package/dist/src/tools/workflow.d.ts +8 -0
  294. package/dist/src/tools/workflow.js +65 -0
  295. package/dist/src/tools/workflow.js.map +1 -0
  296. package/dist/src/workflows/direct.d.ts +9 -0
  297. package/dist/src/workflows/direct.js +2 -0
  298. package/dist/src/workflows/direct.js.map +1 -0
  299. package/dist/src/workflows/implement.d.ts +2 -0
  300. package/dist/src/workflows/implement.js +4 -0
  301. package/dist/src/workflows/implement.js.map +1 -0
  302. package/dist/src/workflows/plan.d.ts +17 -0
  303. package/dist/src/workflows/plan.js +6 -0
  304. package/dist/src/workflows/plan.js.map +1 -0
  305. package/dist/src/workflows/research.d.ts +15 -0
  306. package/dist/src/workflows/research.js +2 -0
  307. package/dist/src/workflows/research.js.map +1 -0
  308. package/dist/src/workflows/review.d.ts +15 -0
  309. package/dist/src/workflows/review.js +2 -0
  310. package/dist/src/workflows/review.js.map +1 -0
  311. package/dist/src/workflows/verify.d.ts +9 -0
  312. package/dist/src/workflows/verify.js +2 -0
  313. package/dist/src/workflows/verify.js.map +1 -0
  314. package/dist/tests/acceptance.test.d.ts +1 -0
  315. package/dist/tests/acceptance.test.js +27 -0
  316. package/dist/tests/acceptance.test.js.map +1 -0
  317. package/dist/tests/agents.test.d.ts +1 -0
  318. package/dist/tests/agents.test.js +369 -0
  319. package/dist/tests/agents.test.js.map +1 -0
  320. package/dist/tests/candidates.test.d.ts +1 -0
  321. package/dist/tests/candidates.test.js +60 -0
  322. package/dist/tests/candidates.test.js.map +1 -0
  323. package/dist/tests/core.test.d.ts +1 -0
  324. package/dist/tests/core.test.js +39 -0
  325. package/dist/tests/core.test.js.map +1 -0
  326. package/dist/tests/daemon.test.d.ts +1 -0
  327. package/dist/tests/daemon.test.js +157 -0
  328. package/dist/tests/daemon.test.js.map +1 -0
  329. package/dist/tests/dashboard.test.d.ts +1 -0
  330. package/dist/tests/dashboard.test.js +414 -0
  331. package/dist/tests/dashboard.test.js.map +1 -0
  332. package/dist/tests/directory-selector.test.d.ts +1 -0
  333. package/dist/tests/directory-selector.test.js +93 -0
  334. package/dist/tests/directory-selector.test.js.map +1 -0
  335. package/dist/tests/doctor.test.d.ts +1 -0
  336. package/dist/tests/doctor.test.js +32 -0
  337. package/dist/tests/doctor.test.js.map +1 -0
  338. package/dist/tests/install.test.d.ts +1 -0
  339. package/dist/tests/install.test.js +101 -0
  340. package/dist/tests/install.test.js.map +1 -0
  341. package/dist/tests/integration.test.d.ts +1 -0
  342. package/dist/tests/integration.test.js +49 -0
  343. package/dist/tests/integration.test.js.map +1 -0
  344. package/dist/tests/journal.test.d.ts +1 -0
  345. package/dist/tests/journal.test.js +50 -0
  346. package/dist/tests/journal.test.js.map +1 -0
  347. package/dist/tests/model-role-assignment.test.d.ts +1 -0
  348. package/dist/tests/model-role-assignment.test.js +294 -0
  349. package/dist/tests/model-role-assignment.test.js.map +1 -0
  350. package/dist/tests/omb-runtime.test.d.ts +1 -0
  351. package/dist/tests/omb-runtime.test.js +554 -0
  352. package/dist/tests/omb-runtime.test.js.map +1 -0
  353. package/dist/tests/omb-session-actions.test.d.ts +1 -0
  354. package/dist/tests/omb-session-actions.test.js +191 -0
  355. package/dist/tests/omb-session-actions.test.js.map +1 -0
  356. package/dist/tests/omb-settings.test.d.ts +1 -0
  357. package/dist/tests/omb-settings.test.js +82 -0
  358. package/dist/tests/omb-settings.test.js.map +1 -0
  359. package/dist/tests/omp-contract.test.d.ts +1 -0
  360. package/dist/tests/omp-contract.test.js +362 -0
  361. package/dist/tests/omp-contract.test.js.map +1 -0
  362. package/dist/tests/process.test.d.ts +1 -0
  363. package/dist/tests/process.test.js +12 -0
  364. package/dist/tests/process.test.js.map +1 -0
  365. package/dist/tests/psmux-windows.test.d.ts +1 -0
  366. package/dist/tests/psmux-windows.test.js +105 -0
  367. package/dist/tests/psmux-windows.test.js.map +1 -0
  368. package/dist/tests/recovery.test.d.ts +1 -0
  369. package/dist/tests/recovery.test.js +9 -0
  370. package/dist/tests/recovery.test.js.map +1 -0
  371. package/dist/tests/resources.test.d.ts +1 -0
  372. package/dist/tests/resources.test.js +55 -0
  373. package/dist/tests/resources.test.js.map +1 -0
  374. package/dist/tests/session-activity.test.d.ts +1 -0
  375. package/dist/tests/session-activity.test.js +159 -0
  376. package/dist/tests/session-activity.test.js.map +1 -0
  377. package/dist/tests/setup-ui.test.d.ts +1 -0
  378. package/dist/tests/setup-ui.test.js +37 -0
  379. package/dist/tests/setup-ui.test.js.map +1 -0
  380. package/dist/tests/storage-integrity.test.d.ts +1 -0
  381. package/dist/tests/storage-integrity.test.js +88 -0
  382. package/dist/tests/storage-integrity.test.js.map +1 -0
  383. package/dist/tests/tmux.test.d.ts +1 -0
  384. package/dist/tests/tmux.test.js +239 -0
  385. package/dist/tests/tmux.test.js.map +1 -0
  386. package/dist/tests/tray.test.d.ts +1 -0
  387. package/dist/tests/tray.test.js +37 -0
  388. package/dist/tests/tray.test.js.map +1 -0
  389. package/dist/tests/verification.test.d.ts +1 -0
  390. package/dist/tests/verification.test.js +61 -0
  391. package/dist/tests/verification.test.js.map +1 -0
  392. package/dist/tests/workflow-features.test.d.ts +1 -0
  393. package/dist/tests/workflow-features.test.js +82 -0
  394. package/dist/tests/workflow-features.test.js.map +1 -0
  395. package/dist/tests/workflow-safety.test.d.ts +1 -0
  396. package/dist/tests/workflow-safety.test.js +57 -0
  397. package/dist/tests/workflow-safety.test.js.map +1 -0
  398. package/docs/compatibility/baseline.json +1 -1
  399. package/docs/decisions/console-handoff.md +5 -0
  400. package/docs/releases/0.6.2.md +32 -0
  401. package/docs/releases/0.6.3.md +27 -0
  402. package/package.json +1 -1
  403. package/skills/bizar-omp/SKILL.md +2 -1
@@ -1,6 +1,7 @@
1
- import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
1
+ import { mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
2
2
  import { homedir } from "node:os";
3
3
  import { dirname, join } from "node:path";
4
+ import { parseCatalogSnapshot } from "./model-role-assignment.js";
4
5
  export const OMB_THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh", "max", "auto"];
5
6
  export const OMB_APPROVAL_MODES = ["always-ask", "write", "yolo"];
6
7
  export const DEFAULT_OMB_SETTINGS = {
@@ -29,7 +30,7 @@ function validChoice(value, choices, fallback) {
29
30
  export function loadOmbSettings(env = process.env) {
30
31
  try {
31
32
  const value = JSON.parse(readFileSync(ombSettingsPath(env), "utf8"));
32
- return {
33
+ const settings = {
33
34
  autoAttachLatest: validBoolean(value.autoAttachLatest, DEFAULT_OMB_SETTINGS.autoAttachLatest),
34
35
  mouseScrolling: validBoolean(value.mouseScrolling, DEFAULT_OMB_SETTINGS.mouseScrolling),
35
36
  showStoppedSessions: validBoolean(value.showStoppedSessions, DEFAULT_OMB_SETTINGS.showStoppedSessions),
@@ -39,6 +40,10 @@ export function loadOmbSettings(env = process.env) {
39
40
  defaultThinking: validChoice(value.defaultThinking, OMB_THINKING_LEVELS, DEFAULT_OMB_SETTINGS.defaultThinking),
40
41
  defaultApprovalMode: validChoice(value.defaultApprovalMode, OMB_APPROVAL_MODES, DEFAULT_OMB_SETTINGS.defaultApprovalMode),
41
42
  };
43
+ const catalog = parseCatalogSnapshot(value.modelCatalog);
44
+ if (catalog)
45
+ settings.modelCatalog = catalog;
46
+ return settings;
42
47
  }
43
48
  catch {
44
49
  return { ...DEFAULT_OMB_SETTINGS };
@@ -47,6 +52,53 @@ export function loadOmbSettings(env = process.env) {
47
52
  export function saveOmbSettings(settings, env = process.env) {
48
53
  const path = ombSettingsPath(env);
49
54
  mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
50
- writeFileSync(path, `${JSON.stringify(settings, null, 2)}\n`, { mode: 0o600 });
55
+ // Temp file plus rename: a reader or a crash never observes a half-written file.
56
+ const temporary = `${path}.${process.pid}.tmp`;
57
+ writeFileSync(temporary, `${JSON.stringify(settings, null, 2)}\n`, { mode: 0o600 });
58
+ renameSync(temporary, path);
59
+ }
60
+ /**
61
+ * Record the observed model catalog without ever replacing settings that could
62
+ * not be read. An existing but unparseable `omb.json` is left byte-for-byte
63
+ * untouched and reported, because that file may hold launcher preferences an
64
+ * interrupted write or a hand edit corrupted; rewriting it as defaults would
65
+ * silently discard the operator's configuration.
66
+ */
67
+ export function recordCatalogObservation(catalog, env = process.env) {
68
+ const path = ombSettingsPath(env);
69
+ let raw;
70
+ try {
71
+ raw = readFileSync(path, "utf8");
72
+ }
73
+ catch (error) {
74
+ if (error.code !== "ENOENT")
75
+ return { ok: false, reason: describeWriteError(error) };
76
+ }
77
+ let existing = {};
78
+ if (raw !== undefined) {
79
+ try {
80
+ const parsed = JSON.parse(raw);
81
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
82
+ throw new Error("settings root is not an object");
83
+ existing = parsed;
84
+ }
85
+ catch (error) {
86
+ return { ok: false, reason: `${path} is not readable JSON (${describeWriteError(error)}); left untouched` };
87
+ }
88
+ }
89
+ try {
90
+ const merged = { ...existing, modelCatalog: catalog };
91
+ mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
92
+ const temporary = `${path}.${process.pid}.tmp`;
93
+ writeFileSync(temporary, `${JSON.stringify(merged, null, 2)}\n`, { mode: 0o600 });
94
+ renameSync(temporary, path);
95
+ return { ok: true };
96
+ }
97
+ catch (error) {
98
+ return { ok: false, reason: describeWriteError(error) };
99
+ }
100
+ }
101
+ function describeWriteError(error) {
102
+ return error instanceof Error ? error.message : String(error);
51
103
  }
52
104
  //# sourceMappingURL=omb-settings.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"omb-settings.js","sourceRoot":"","sources":["../../src/omp/omb-settings.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"omb-settings.js","sourceRoot":"","sources":["../../src/omp/omb-settings.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Operator report that no longer fits OMP's status line.
3
+ *
4
+ * `ctx.ui.notify(message, "info")` renders through the host status line, which
5
+ * folds a single text component onto about two screen lines. A report longer
6
+ * than that arrives clipped, so the command that produced it writes the
7
+ * complete text here and points the operator at it. Only the notice is fitted;
8
+ * this log always holds the report verbatim.
9
+ */
10
+ export interface RunLogEntry {
11
+ /** Command or subsystem that produced the report. */
12
+ event: string;
13
+ /** Complete report text, exactly as the command returned it. */
14
+ detail: string;
15
+ /** Last session entry seen when the report was produced, when the host exposes one. */
16
+ sessionEntry?: string;
17
+ }
18
+ /** Run logs live beside the project journal, so a project keeps one directory. */
19
+ export declare function runLogPath(cwd: string): string;
20
+ /**
21
+ * Append one entry as a single JSON line. A run log is operator bookkeeping: a
22
+ * directory that cannot be created or written must never turn a completed
23
+ * command into a failed one, so the caller sees false instead of an exception.
24
+ */
25
+ export declare function appendRunLog(cwd: string, entry: RunLogEntry): boolean;
26
+ //# sourceMappingURL=run-log.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-log.d.ts","sourceRoot":"","sources":["../../src/omp/run-log.ts"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AACH,MAAM,WAAW,WAAW;IAC1B,qDAAqD;IACrD,KAAK,EAAE,MAAM,CAAC;IACd,gEAAgE;IAChE,MAAM,EAAE,MAAM,CAAC;IACf,uFAAuF;IACvF,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,kFAAkF;AAClF,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAUrE"}
@@ -0,0 +1,24 @@
1
+ import { appendFileSync, mkdirSync } from "node:fs";
2
+ import { dirname, join } from "node:path";
3
+ /** Run logs live beside the project journal, so a project keeps one directory. */
4
+ export function runLogPath(cwd) {
5
+ return join(cwd, ".bizar-omp", "run.log");
6
+ }
7
+ /**
8
+ * Append one entry as a single JSON line. A run log is operator bookkeeping: a
9
+ * directory that cannot be created or written must never turn a completed
10
+ * command into a failed one, so the caller sees false instead of an exception.
11
+ */
12
+ export function appendRunLog(cwd, entry) {
13
+ const line = `${JSON.stringify({ at: new Date().toISOString(), ...entry })}\n`;
14
+ try {
15
+ const path = runLogPath(cwd);
16
+ mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
17
+ appendFileSync(path, line, { mode: 0o600 });
18
+ return true;
19
+ }
20
+ catch {
21
+ return false;
22
+ }
23
+ }
24
+ //# sourceMappingURL=run-log.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-log.js","sourceRoot":"","sources":["../../src/omp/run-log.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAoB1C,kFAAkF;AAClF,MAAM,UAAU,UAAU,CAAC,GAAW;IACpC,OAAO,IAAI,CAAC,GAAG,EAAE,YAAY,EAAE,SAAS,CAAC,CAAC;AAC5C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,GAAW,EAAE,KAAkB;IAC1D,MAAM,IAAI,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,GAAG,KAAK,EAAE,CAAC,IAAI,CAAC;IAC/E,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;QAC7B,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAC3D,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAC5C,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
@@ -23,6 +23,22 @@ export interface OmbSessionConsole {
23
23
  code: number;
24
24
  text: string;
25
25
  }
26
+ /**
27
+ * Lines of history kept for the window an OMB session runs in.
28
+ *
29
+ * tmux defaults to 2000 lines, which a long OMP chat scrolls past in one
30
+ * sitting: the pane then drops the messages the operator needs to review and
31
+ * neither the wheel binding nor copy-mode can bring them back. `history-limit`
32
+ * is a window option, so it is set on the session's own window — every other
33
+ * tmux session keeps the limit its owner configured.
34
+ */
35
+ export declare const OMB_SESSION_HISTORY_LIMIT = 100000;
36
+ /**
37
+ * Raise one Bizar-owned session's window history limit. Idempotent, so attach
38
+ * paths run it too: a session created before the limit was raised must not stay
39
+ * capped at 2000 lines for the rest of its life.
40
+ */
41
+ export declare function raiseOmbSessionHistory(session: string, cwd?: string, env?: NodeJS.ProcessEnv): Promise<number>;
26
42
  /** Capture a bounded, plain-text view of one Bizar-owned session's active pane. */
27
43
  export declare function captureOmbSessionConsole(session: string, cwd?: string, env?: NodeJS.ProcessEnv, lines?: number): Promise<OmbSessionConsole>;
28
44
  /** Send literal composer text followed by Enter to one Bizar-owned session. */
@@ -31,15 +47,35 @@ export declare function sendOmbSessionInput(session: string, input: string, cwd?
31
47
  * Open one Bizar-owned session in a new terminal emulator window. The daemon
32
48
  * and hub run without a controlling TTY, so attaching means handing the attach
33
49
  * command to a terminal we spawn; when no emulator exists the caller still
34
- * receives the exact command to run by hand.
50
+ * receives the exact command to run by hand. Attaching is also where a session
51
+ * created before the history limit was raised is repaired, because an operator
52
+ * attaching to a long-running chat is the one who needs its scrollback.
35
53
  */
36
- export declare function openOmbSessionInTerminal(session: string, env?: NodeJS.ProcessEnv): OmbAttachLaunch;
54
+ export declare function openOmbSessionInTerminal(session: string, env?: NodeJS.ProcessEnv): Promise<OmbAttachLaunch>;
37
55
  /** Open a fixed Bizar CLI command in a new terminal emulator window. */
38
56
  export declare function openCommandInTerminal(command: string, env?: NodeJS.ProcessEnv): OmbAttachLaunch;
39
57
  /** Apply the launcher mouse preference to one exact Bizar-owned session. */
40
58
  export declare function setOmbSessionMouse(session: string, enabled: boolean, cwd?: string, env?: NodeJS.ProcessEnv): Promise<number>;
41
59
  /** Rename one exact Bizar-owned tmux session. */
42
60
  export declare function renameOmbSession(session: string, nextName: string, cwd?: string, env?: NodeJS.ProcessEnv): Promise<number>;
61
+ export interface TmuxSessionRecord {
62
+ name: string;
63
+ createdAt?: number;
64
+ lastAttachedAt?: number;
65
+ attached: boolean;
66
+ }
67
+ /** Parse one `list-sessions -F "#{session_name}\t#{session_created}\t#{session_last_attached}\t#{session_attached}"` result. */
68
+ export declare function parseTmuxSessionRecords(output: string): TmuxSessionRecord[];
69
+ /** Native records for the sessions the multiplexer currently hosts. */
70
+ export declare function listTmuxSessions(cwd?: string, env?: NodeJS.ProcessEnv): Promise<TmuxSessionRecord[]>;
71
+ /**
72
+ * Whether the multiplexer still hosts this exact session.
73
+ *
74
+ * `unknown` means the multiplexer could not be run at all, so a missing row
75
+ * must never be read as a session that is gone: a caller that reports a kill
76
+ * has to say which of the two it proved.
77
+ */
78
+ export declare function ombSessionLiveness(session: string, cwd?: string, env?: NodeJS.ProcessEnv): Promise<"live" | "gone" | "unknown">;
43
79
  /** Kill one exact Bizar-owned tmux session after the caller has confirmed it. */
44
80
  export declare function deleteOmbSession(session: string, cwd?: string, env?: NodeJS.ProcessEnv): Promise<number>;
45
81
  /** Hide an unhosted journal record that has no tmux session left to kill. */
@@ -1 +1 @@
1
- {"version":3,"file":"tmux.d.ts","sourceRoot":"","sources":["../../src/omp/tmux.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tmux.d.ts","sourceRoot":"","sources":["../../src/omp/tmux.ts"],"names":[],"mappings":"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"}
package/dist/omp/tmux.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { spawn } from "node:child_process";
3
- import { statSync } from "node:fs";
3
+ import { existsSync, statSync } from "node:fs";
4
4
  import { basename, join } from "node:path";
5
- import { clearOmbSessionDeleted, findLastOmbSession, markOmbSessionDeleted, ombSessionDir, resolveMultiplexerBin } from "./omb-sessions.js";
5
+ import { clearOmbSessionDeleted, findLastOmbSession, isOmbSessionName, markOmbSessionDeleted, ombSessionBoundNames, ombSessionDir, resolveMultiplexerBin } from "./omb-sessions.js";
6
6
  import { loadOmbSettings } from "./omb-settings.js";
7
7
  const NON_INTERACTIVE_FLAGS = new Set(["-p", "--print", "--export"]);
8
8
  const NON_INTERACTIVE_MODES = new Set(["json", "rpc", "rpc-ui", "acp"]);
@@ -54,21 +54,36 @@ function runTmux(command, args, cwd, env) {
54
54
  return closed.promise;
55
55
  }
56
56
  function readTmux(command, args, cwd, env) {
57
- const child = spawn(command, args, { cwd, env, stdio: ["ignore", "pipe", "ignore"] });
57
+ const child = spawn(command, args, { cwd, env, stdio: ["ignore", "pipe", "pipe"] });
58
58
  let output = "";
59
+ let error = "";
59
60
  child.stdout?.setEncoding("utf8");
60
61
  child.stdout?.on("data", chunk => { output += chunk; });
62
+ child.stderr?.setEncoding("utf8");
63
+ child.stderr?.on("data", chunk => { error += chunk; });
61
64
  const closed = Promise.withResolvers();
62
65
  child.once("error", closed.reject);
63
- child.once("close", (code, signal) => closed.resolve({ code: exitCode(code, signal), output }));
66
+ child.once("close", (code, signal) => closed.resolve({ code: exitCode(code, signal), output, error }));
64
67
  return closed.promise;
65
68
  }
69
+ /**
70
+ * Stop the parent's stdin read loop before handing the TTY to an inherit
71
+ * child. On Windows a flowing stdin with no data listener (the state an ink
72
+ * unmount can leave behind) consumes console input records, so a psmux
73
+ * attach sharing the console never sees keystrokes. Pausing only stops this
74
+ * process from reading; the inherit child keeps full access. The attached
75
+ * client restores terminal state itself, so nothing is restored here.
76
+ */
77
+ function quiesceStdinForHandoff() {
78
+ if (process.stdin.isTTY === true && !process.stdin.isPaused())
79
+ process.stdin.pause();
80
+ }
66
81
  /**
67
82
  * Apply the standard Bizar options to a Bizar-owned session: respawn dead
68
- * panes, remain-on-exit off, mouse preference, and the private root table so
69
- * Ctrl-D/C detach the client without sending exit or interrupt input into
70
- * OMP. The tmux host remains alive for background work, and the normal Ctrl-B
71
- * prefix still enters tmux's standard prefix table.
83
+ * panes, remain-on-exit off, window history limit, mouse preference, and the
84
+ * private root table so Ctrl-D/C detach the client without sending exit or
85
+ * interrupt input into OMP. The tmux host remains alive for background work,
86
+ * and the normal Ctrl-B prefix still enters tmux's standard prefix table.
72
87
  */
73
88
  async function prepareOmbSession(tmux, omp, session, cwd, childEnv, mouseScrolling) {
74
89
  // Keep the respawn opportunity below for stale sessions, but do not leave
@@ -87,31 +102,43 @@ async function prepareOmbSession(tmux, omp, session, cwd, childEnv, mouseScrolli
87
102
  const remainOnExitOff = await runTmux(tmux, ["set-option", "-t", session, "remain-on-exit", "off"], cwd, childEnv);
88
103
  if (remainOnExitOff !== 0)
89
104
  return remainOnExitOff;
105
+ // Keep the conversation reviewable: the pane's history is the only scrollback
106
+ // an OMP session has, and the tmux default holds minutes of a live chat.
107
+ const historyRaised = await runTmux(tmux, sessionHistoryArgs(session), cwd, childEnv);
108
+ if (historyRaised !== 0)
109
+ return historyRaised;
90
110
  // tmux must own wheel events so the terminal scrolls the pane instead of
91
111
  // translating them into up/down input for OMP's prompt-history editor.
92
112
  const mouseEnabled = await runTmux(tmux, ["set-option", "-t", session, "mouse", mouseScrolling ? "on" : "off"], cwd, childEnv);
93
113
  if (mouseEnabled !== 0)
94
114
  return mouseEnabled;
95
- const keyTable = `${session}-bizar-root`;
96
115
  // Keep pointer events inside the Bizar-owned key table. Without these
97
116
  // explicit bindings, tmux consumes wheel/click events while an OMP
98
117
  // alternate-screen overlay is active, so Advisor never receives them; when
99
118
  // the main OMP screen is active, the wheel should scroll tmux's pane.
100
- const bindWheelUp = await runTmux(tmux, ["bind-key", "-T", keyTable, "WheelUpPane", "if-shell", "-F", "#{alternate_on}", "send-keys -M", "copy-mode -e; send-keys -M"], cwd, childEnv);
101
- const bindWheelDown = await runTmux(tmux, ["bind-key", "-T", keyTable, "WheelDownPane", "if-shell", "-F", "#{alternate_on}", "send-keys -M", "send-keys -M"], cwd, childEnv);
102
- const bindMouseDown = await runTmux(tmux, ["bind-key", "-T", keyTable, "MouseDown1Pane", "if-shell", "-F", "#{alternate_on}", "send-keys -M", "select-pane"], cwd, childEnv);
103
- const bindMouseDrag = await runTmux(tmux, ["bind-key", "-T", keyTable, "MouseDrag1Pane", "if-shell", "-F", "#{alternate_on}", "send-keys -M", "copy-mode -e; send-keys -M"], cwd, childEnv);
104
- const bindMouseUp = await runTmux(tmux, ["bind-key", "-T", keyTable, "MouseUp1Pane", "if-shell", "-F", "#{alternate_on}", "send-keys -M", ""], cwd, childEnv);
105
- const bindDetach = await runTmux(tmux, ["bind-key", "-T", keyTable, "C-d", "detach-client"], cwd, childEnv);
106
- if (bindDetach !== 0)
107
- return bindDetach;
108
- const bindInterruptDetach = await runTmux(tmux, ["bind-key", "-T", keyTable, "C-c", "detach-client"], cwd, childEnv);
109
- if (bindInterruptDetach !== 0)
110
- return bindInterruptDetach;
111
- const bindPrefix = await runTmux(tmux, ["bind-key", "-T", keyTable, "C-b", "switch-client", "-T", "prefix"], cwd, childEnv);
112
- if (bindPrefix !== 0)
113
- return bindPrefix;
114
- return runTmux(tmux, ["set-option", "-t", session, "key-table", keyTable], cwd, childEnv);
119
+ // psmux ignores persistent key-table assignment (and its #583 `set-option`
120
+ // quirk eats dash-leading values), so skip the binds there; real tmux keeps
121
+ // them.
122
+ const psmuxMode = process.platform === "win32" && tmux === resolveMultiplexerBin();
123
+ if (!psmuxMode) {
124
+ const keyTable = `${session}-bizar-root`;
125
+ const bindWheelUp = await runTmux(tmux, ["bind-key", "-T", keyTable, "WheelUpPane", "if-shell", "-F", "#{alternate_on}", "send-keys -M", "copy-mode -e; send-keys -M"], cwd, childEnv);
126
+ const bindWheelDown = await runTmux(tmux, ["bind-key", "-T", keyTable, "WheelDownPane", "if-shell", "-F", "#{alternate_on}", "send-keys -M", "send-keys -M"], cwd, childEnv);
127
+ const bindMouseDown = await runTmux(tmux, ["bind-key", "-T", keyTable, "MouseDown1Pane", "if-shell", "-F", "#{alternate_on}", "send-keys -M", "select-pane"], cwd, childEnv);
128
+ const bindMouseDrag = await runTmux(tmux, ["bind-key", "-T", keyTable, "MouseDrag1Pane", "if-shell", "-F", "#{alternate_on}", "send-keys -M", "copy-mode -e; send-keys -M"], cwd, childEnv);
129
+ const bindMouseUp = await runTmux(tmux, ["bind-key", "-T", keyTable, "MouseUp1Pane", "if-shell", "-F", "#{alternate_on}", "send-keys -M", ""], cwd, childEnv);
130
+ const bindDetach = await runTmux(tmux, ["bind-key", "-T", keyTable, "C-d", "detach-client"], cwd, childEnv);
131
+ if (bindDetach !== 0)
132
+ return bindDetach;
133
+ const bindInterruptDetach = await runTmux(tmux, ["bind-key", "-T", keyTable, "C-c", "detach-client"], cwd, childEnv);
134
+ if (bindInterruptDetach !== 0)
135
+ return bindInterruptDetach;
136
+ const bindPrefix = await runTmux(tmux, ["bind-key", "-T", keyTable, "C-b", "switch-client", "-T", "prefix"], cwd, childEnv);
137
+ if (bindPrefix !== 0)
138
+ return bindPrefix;
139
+ return runTmux(tmux, ["set-option", "-t", session, "key-table", keyTable], cwd, childEnv);
140
+ }
141
+ return 0;
115
142
  }
116
143
  async function launchInTmux(tmux, omp, session, cwd, args, env, mouseScrolling, sessionDir) {
117
144
  const childEnv = { ...env, BIZAR_OMP_NO_TMUX: "1" };
@@ -129,15 +156,13 @@ async function launchInTmux(tmux, omp, session, cwd, args, env, mouseScrolling,
129
156
  const prepared = await prepareOmbSession(tmux, omp, session, cwd, childEnv, mouseScrolling);
130
157
  if (prepared !== 0)
131
158
  return prepared;
159
+ quiesceStdinForHandoff();
132
160
  const client = spawn(tmux, ["attach-session", "-t", session], { cwd, env: childEnv, stdio: "inherit" });
133
161
  const closed = Promise.withResolvers();
134
162
  client.once("error", closed.reject);
135
163
  client.once("close", (code, signal) => closed.resolve(exitCode(code, signal)));
136
164
  return closed.promise;
137
165
  }
138
- function ownedSession(session) {
139
- return /^bizar-[A-Za-z0-9_.-]+$/.test(session);
140
- }
141
166
  /**
142
167
  * Terminal emulators that can host an interactive attach, in preference order.
143
168
  * `$BIZAR_TERMINAL` overrides the list; `xfce4-terminal` takes the command as
@@ -179,6 +204,29 @@ export function findOnPath(bin, env = process.env) {
179
204
  const SESSION_CONSOLE_MAX_LINES = 1_000;
180
205
  const SESSION_CONSOLE_MAX_CHARS = 128 * 1024;
181
206
  const SESSION_INPUT_MAX_BYTES = 16 * 1024;
207
+ /**
208
+ * Lines of history kept for the window an OMB session runs in.
209
+ *
210
+ * tmux defaults to 2000 lines, which a long OMP chat scrolls past in one
211
+ * sitting: the pane then drops the messages the operator needs to review and
212
+ * neither the wheel binding nor copy-mode can bring them back. `history-limit`
213
+ * is a window option, so it is set on the session's own window — every other
214
+ * tmux session keeps the limit its owner configured.
215
+ */
216
+ export const OMB_SESSION_HISTORY_LIMIT = 100_000;
217
+ function sessionHistoryArgs(session) {
218
+ return ["set-option", "-w", "-t", `${session}:0`, "history-limit", String(OMB_SESSION_HISTORY_LIMIT)];
219
+ }
220
+ /**
221
+ * Raise one Bizar-owned session's window history limit. Idempotent, so attach
222
+ * paths run it too: a session created before the limit was raised must not stay
223
+ * capped at 2000 lines for the rest of its life.
224
+ */
225
+ export async function raiseOmbSessionHistory(session, cwd = process.cwd(), env = process.env) {
226
+ if (!isOmbSessionName(session))
227
+ return 2;
228
+ return runTmux(resolveMultiplexerBin(env), sessionHistoryArgs(session), cwd, { ...env, BIZAR_OMP_NO_TMUX: "1" });
229
+ }
182
230
  function cleanTerminalText(value) {
183
231
  return value
184
232
  .replace(/\u001B\][^\u0007]*(?:\u0007|\u001B\\)/g, "")
@@ -190,7 +238,7 @@ function cleanTerminalText(value) {
190
238
  }
191
239
  /** Capture a bounded, plain-text view of one Bizar-owned session's active pane. */
192
240
  export async function captureOmbSessionConsole(session, cwd = process.cwd(), env = process.env, lines = 500) {
193
- if (!ownedSession(session))
241
+ if (!isOmbSessionName(session))
194
242
  return { code: 2, text: "" };
195
243
  const requestedLines = Number.isFinite(lines) ? Math.floor(lines) : 500;
196
244
  const boundedLines = Math.max(1, Math.min(SESSION_CONSOLE_MAX_LINES, requestedLines));
@@ -200,7 +248,7 @@ export async function captureOmbSessionConsole(session, cwd = process.cwd(), env
200
248
  }
201
249
  /** Send literal composer text followed by Enter to one Bizar-owned session. */
202
250
  export async function sendOmbSessionInput(session, input, cwd = process.cwd(), env = process.env) {
203
- if (!ownedSession(session) || !input.trim() || input.includes("\u0000") || Buffer.byteLength(input) > SESSION_INPUT_MAX_BYTES)
251
+ if (!isOmbSessionName(session) || !input.trim() || input.includes("\u0000") || Buffer.byteLength(input) > SESSION_INPUT_MAX_BYTES)
204
252
  return 2;
205
253
  const tmux = resolveMultiplexerBin(env);
206
254
  const childEnv = { ...env, BIZAR_OMP_NO_TMUX: "1" };
@@ -213,13 +261,21 @@ export async function sendOmbSessionInput(session, input, cwd = process.cwd(), e
213
261
  * Open one Bizar-owned session in a new terminal emulator window. The daemon
214
262
  * and hub run without a controlling TTY, so attaching means handing the attach
215
263
  * command to a terminal we spawn; when no emulator exists the caller still
216
- * receives the exact command to run by hand.
264
+ * receives the exact command to run by hand. Attaching is also where a session
265
+ * created before the history limit was raised is repaired, because an operator
266
+ * attaching to a long-running chat is the one who needs its scrollback.
217
267
  */
218
- export function openOmbSessionInTerminal(session, env = process.env) {
268
+ export async function openOmbSessionInTerminal(session, env = process.env) {
219
269
  // Names come from tmux; keep the shell command single-quoted and refuse
220
270
  // anything outside the character set Bizar ever generates.
221
- if (!ownedSession(session) || !/^[A-Za-z0-9_.-]+$/.test(session))
271
+ if (!isOmbSessionName(session) || !/^[A-Za-z0-9_.-]+$/.test(session))
222
272
  return { spawned: false, command: "" };
273
+ // Best effort: a session that cannot take the option is attached to anyway so
274
+ // the operator still sees why the attach failed.
275
+ try {
276
+ await raiseOmbSessionHistory(session, process.cwd(), env);
277
+ }
278
+ catch { /* attach proceeds */ }
223
279
  const multiplexer = resolveMultiplexerBin(env).replace(/'/g, "'\\''");
224
280
  const command = `'${multiplexer}' attach-session -t '${session}'`;
225
281
  return openCommandInTerminal(command, env);
@@ -249,7 +305,7 @@ export function openCommandInTerminal(command, env = process.env) {
249
305
  }
250
306
  /** Apply the launcher mouse preference to one exact Bizar-owned session. */
251
307
  export function setOmbSessionMouse(session, enabled, cwd = process.cwd(), env = process.env) {
252
- if (!ownedSession(session))
308
+ if (!isOmbSessionName(session))
253
309
  return Promise.resolve(2);
254
310
  return runTmux(resolveMultiplexerBin(env), ["set-option", "-t", session, "mouse", enabled ? "on" : "off"], cwd, {
255
311
  ...env,
@@ -258,29 +314,156 @@ export function setOmbSessionMouse(session, enabled, cwd = process.cwd(), env =
258
314
  }
259
315
  /** Rename one exact Bizar-owned tmux session. */
260
316
  export function renameOmbSession(session, nextName, cwd = process.cwd(), env = process.env) {
261
- if (!ownedSession(session) || !ownedSession(nextName))
317
+ if (!isOmbSessionName(session) || !isOmbSessionName(nextName))
262
318
  return Promise.resolve(2);
263
319
  return runTmux(resolveMultiplexerBin(env), ["rename-session", "-t", session, nextName], cwd, {
264
320
  ...env,
265
321
  BIZAR_OMP_NO_TMUX: "1",
266
322
  });
267
323
  }
324
+ /**
325
+ * One `-F` record: `name\tcreated\tlast-attached\tattached`.
326
+ *
327
+ * The two timestamps are optional because the multiplexer prints an empty
328
+ * field, not a zero, for a session nothing has ever attached to; `attached`
329
+ * is the client *count*, so a session with two clients prints `2`. Treating
330
+ * either as a malformed record would drop a live session out of discovery and
331
+ * out of every "is it gone?" answer.
332
+ */
333
+ const SESSION_RECORD = /^([^\t]+)\t(\d*)\t(\d*)\t(\d+)$/;
334
+ /** A count tmux left empty means "nothing to count", never zero seconds. */
335
+ function optionalSeconds(field) {
336
+ if (!field)
337
+ return undefined;
338
+ const value = Number(field);
339
+ return Number.isFinite(value) ? value : undefined;
340
+ }
341
+ /** Parse one `list-sessions -F "#{session_name}\t#{session_created}\t#{session_last_attached}\t#{session_attached}"` result. */
342
+ export function parseTmuxSessionRecords(output) {
343
+ const records = [];
344
+ for (const line of output.split("\n")) {
345
+ if (!line)
346
+ continue;
347
+ const match = SESSION_RECORD.exec(line.trim());
348
+ if (!match)
349
+ continue;
350
+ records.push({
351
+ name: match[1],
352
+ createdAt: optionalSeconds(match[2]),
353
+ lastAttachedAt: optionalSeconds(match[3]),
354
+ attached: match[4] !== "0",
355
+ });
356
+ }
357
+ return records;
358
+ }
359
+ /**
360
+ * The socket a multiplexer command will use, when that can be derived.
361
+ *
362
+ * A client inside a session names its own server first (`TMUX` is
363
+ * `<socket>,<pid>,<session>`), and every other command goes to that same
364
+ * server. Without one, tmux uses `<TMUX_TMPDIR|/tmp>/tmux-<uid>/default`.
365
+ */
366
+ function multiplexerSocket(env) {
367
+ const current = env.TMUX?.split(",")[0];
368
+ if (current)
369
+ return current;
370
+ const uid = typeof process.getuid === "function" ? process.getuid() : undefined;
371
+ if (uid === undefined)
372
+ return undefined;
373
+ return join(env.TMUX_TMPDIR || "/tmp", `tmux-${uid}`, "default");
374
+ }
375
+ /**
376
+ * Whether a failed listing means "no server is running".
377
+ *
378
+ * This is the one failure that proves nothing is hosted: tmux answers a
379
+ * request it cannot serve with a nonzero exit, and only an absent socket (or
380
+ * tmux's own "no server running" wording) says the server itself is gone. A
381
+ * socket that exists but refuses — a permission error, a request the server
382
+ * rejected — answered nothing, so a caller that must prove a session is gone
383
+ * cannot read it as one.
384
+ */
385
+ function isNoServerFailure(env, error) {
386
+ if (/no server running/i.test(error))
387
+ return true;
388
+ const socket = multiplexerSocket(env);
389
+ return socket !== undefined && !existsSync(socket);
390
+ }
391
+ const SESSION_LIST_FORMAT = "#{session_name}\t#{session_created}\t#{session_last_attached}\t#{session_attached}";
392
+ /**
393
+ * One listing of the multiplexer, or `undefined` when it could not be read.
394
+ *
395
+ * `undefined` is not an empty listing: a caller that must prove a session is
396
+ * gone cannot do it with a multiplexer that never answered.
397
+ */
398
+ async function readSessionRecords(cwd, env) {
399
+ let result;
400
+ try {
401
+ result = await readTmux(resolveMultiplexerBin(env), ["list-sessions", "-F", SESSION_LIST_FORMAT], cwd, { ...env, BIZAR_OMP_NO_TMUX: "1" });
402
+ }
403
+ catch {
404
+ // The multiplexer could not be run at all, so nothing was ever asked.
405
+ return undefined;
406
+ }
407
+ if (result.code === 0)
408
+ return parseTmuxSessionRecords(result.output);
409
+ return isNoServerFailure(env, result.error) ? [] : undefined;
410
+ }
411
+ /** Native records for the sessions the multiplexer currently hosts. */
412
+ export async function listTmuxSessions(cwd = process.cwd(), env = process.env) {
413
+ return await readSessionRecords(cwd, env) ?? [];
414
+ }
415
+ /**
416
+ * Whether the multiplexer still hosts this exact session.
417
+ *
418
+ * `unknown` means the multiplexer could not be run at all, so a missing row
419
+ * must never be read as a session that is gone: a caller that reports a kill
420
+ * has to say which of the two it proved.
421
+ */
422
+ export async function ombSessionLiveness(session, cwd = process.cwd(), env = process.env) {
423
+ const records = await readSessionRecords(cwd, env);
424
+ if (!records)
425
+ return "unknown";
426
+ // The listing is parsed, never matched as raw text: a multiplexer may answer
427
+ // the format request with the records it has, and reading a name out of that
428
+ // text would call a hosted session gone.
429
+ return records.some(record => record.name === session) ? "live" : "gone";
430
+ }
268
431
  /** Kill one exact Bizar-owned tmux session after the caller has confirmed it. */
269
- export function deleteOmbSession(session, cwd = process.cwd(), env = process.env) {
270
- if (!ownedSession(session))
271
- return Promise.resolve(2);
272
- return runTmux(resolveMultiplexerBin(env), ["kill-session", "-t", session], cwd, {
273
- ...env,
274
- BIZAR_OMP_NO_TMUX: "1",
275
- }).then(code => {
276
- if (code !== 0)
277
- return code;
278
- return markOmbSessionDeleted(session, env) ? 0 : 1;
279
- });
432
+ export async function deleteOmbSession(session, cwd = process.cwd(), env = process.env) {
433
+ if (!isOmbSessionName(session))
434
+ return 2;
435
+ const childEnv = { ...env, BIZAR_OMP_NO_TMUX: "1" };
436
+ // A renamed session journals into the directory it was started with, so read
437
+ // the pane binding while the session still exists.
438
+ const bound = await ombSessionBoundNames(session, cwd, childEnv);
439
+ const code = await runTmux(resolveMultiplexerBin(env), ["kill-session", "-t", session], cwd, childEnv);
440
+ // One listing decides, whichever way the kill answered. A multiplexer can
441
+ // refuse a kill for a session a concurrent caller already removed - which is
442
+ // a success here - and it can report success while another session has
443
+ // already taken the name, which is not.
444
+ const liveness = await ombSessionLiveness(session, cwd, childEnv);
445
+ // A session the multiplexer still hosts is not deleted, and its journal must
446
+ // not be tombstoned: hiding a live session's journal would drop it from the
447
+ // hub while it keeps running, with no row left to open it again.
448
+ if (liveness === "live")
449
+ return code || 1;
450
+ // A kill the multiplexer accepted removed the session it was pointed at, so
451
+ // absence holds even when the listing cannot be taken again: the server may
452
+ // have exited with its last session. A kill it refused proves nothing on its
453
+ // own, and an unreadable listing proves nothing either, so neither may hide
454
+ // a journal. `omb forget` stays the explicit way to hide one by hand.
455
+ if (code !== 0 && liveness !== "gone")
456
+ return code || 1;
457
+ // Deletion outlives the tmux binding. The row the user removed came from one
458
+ // of these journals, so every directory behind this session is tombstoned:
459
+ // when tmux has already lost the session, its journal must not come back as a
460
+ // row that cannot be opened.
461
+ const tombstoned = [session, ...bound].every(name => markOmbSessionDeleted(name, env));
462
+ return tombstoned ? 0 : code || 1;
280
463
  }
281
464
  /** Hide an unhosted journal record that has no tmux session left to kill. */
282
465
  export function forgetOmbSession(session, env = process.env) {
283
- if (!ownedSession(session))
466
+ if (!isOmbSessionName(session))
284
467
  return 2;
285
468
  return markOmbSessionDeleted(session, env) ? 0 : 1;
286
469
  }
@@ -290,6 +473,7 @@ export function attachOmbSession(session, cwd = process.cwd(), env = process.env
290
473
  const args = env.TMUX || env.TMUX_PANE
291
474
  ? ["switch-client", "-t", session]
292
475
  : ["attach-session", "-t", session];
476
+ quiesceStdinForHandoff();
293
477
  const child = spawn(tmux, args, { cwd, env: { ...env, BIZAR_OMP_NO_TMUX: "1" }, stdio: "inherit" });
294
478
  return new Promise((resolve, reject) => {
295
479
  // A missing multiplexer degrades to a nonzero exit like a failed attach;
@@ -332,6 +516,7 @@ export async function launchOmb(cwd, args, env = process.env, sessionId) {
332
516
  throw error;
333
517
  }
334
518
  }
519
+ quiesceStdinForHandoff();
335
520
  const child = spawn(omp, args, { cwd, env, stdio: "inherit" });
336
521
  const closed = Promise.withResolvers();
337
522
  child.once("error", closed.reject);